1219 Commits
Author SHA1 Message Date
Catherine Reprobate be0293f555 update Readme links 2026-05-25 23:55:29 -07:00
fgsfds 54d35b47a0 Merge pull request #716 from jonaeru/port-net-disablemenu
[port-net] Disable all menus in Perfect Menu except Network Game and Change Agent
2026-05-02 12:20:13 +02:00
Jonaeru 04a518840f Add "Player Setup" menu to "Join Game" menu
Add `MENUDIALOGFLAG_STARTSELECTS` to the "Network Game" menu
Remove `MENUDIALOGFLAG_IGNOREBACK` from the "Join Network Game" menu
2026-04-26 20:59:32 +09:00
Jonaeru 68df5343ba Disable all menus in Perfect Menu except Network Game and Change Agent 2026-04-25 00:53:00 +09:00
fgsfds aead1bc4c4 port-net: kick ci 2026-04-11 22:13:44 +02:00
fgsfds b86cc88991 port-net: update netplay.md
doing this mostly to kick CI
2025-12-31 21:10:42 +01:00
fgsfds d946e332ae port: net: don't transfer projectile/embedded flags in damage event 2025-09-28 10:26:50 +02:00
fgsfds 57041735cb port: net: fix build on newer mingw versions 2025-08-03 14:15:10 +02:00
fgsfds f3ce20fb6e port: net: fix laptop gun altfire on clients; better autogun sync 2025-04-27 19:52:28 +02:00
fgsfds 75d1886da1 port: net: load mpsetups from mpsetups.bin when entering host menu 2025-04-27 17:36:03 +02:00
fgsfds a582068c21 port: net: sync prop damage 2025-04-27 16:41:33 +02:00
fgsfds 4c1e9ece94 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2025-04-27 16:01:37 +02:00
fgsfds 4b8e1d52b5 port: move menuAlt functions to menu.c and make them global 2025-04-27 15:54:39 +02:00
fgsfds a9ccc61f96 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2025-04-27 15:45:45 +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 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 110876b036 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2025-03-16 09:18:31 +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 ae7b21cf56 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2025-03-02 13:38:12 +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 e8a57d7f6f Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2025-02-22 11:28:12 +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 2362444efd Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2025-02-11 20:06:26 +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 f5251fa1b9 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2025-01-05 15:46:00 +01:00
fgsfds 4f7817a0ca port: forgot the constant 2025-01-05 15:45:42 +01:00
fgsfds da4e5e4832 what the fuck git 2025-01-05 15:44:14 +01:00
fgsfds 5ebce756ed Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2025-01-05 15:43:52 +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 839ef7cc44 thank you git very cool 2025-01-05 12:44:51 +01:00
fgsfds c597915466 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2025-01-05 12:33:15 +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 5db911a58b Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-11-29 09:58:04 +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 5425c21c83 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-11-23 20:40:38 +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 abe04c0dda Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-11-19 18:33:29 +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 7721297dc8 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-11-17 11:09:06 +01: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 44c5a4c213 port-net: note that switch is not supported 2024-11-16 15:39:13 +01:00
fgsfds 7677b40b06 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-11-16 15:38:27 +01:00
fgsfds d747588323 ci: only build the port branch for nswitch 2024-11-16 15:37:43 +01:00
fgsfds f948fc06f2 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-11-16 15:30:34 +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 26c24d62aa Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-11-16 12:56:01 +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 9a484c1aea Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-11-15 19:14:04 +01:00
fgsfds 08afb2d90a readme: fix formatting 2024-11-15 19:13:53 +01:00
fgsfds 3f45d41de6 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-11-15 19:13:07 +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 6ddebf8aa6 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-11-15 01:36:54 +01: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 6d20ed25fb Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-11-14 18:46:15 +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 112f6da972 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-11-13 09:09:47 +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 80cd44d8e2 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-11-13 08:55:19 +01:00
fgsfds 5d9fe034ea tools: fix assetmgr on python <= 3.8 2024-11-13 08:55:04 +01:00
fgsfds 3ff2f9e0ec Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-11-13 08:51:43 +01:00
fgsfds 1d7c381ce2 port: cmake: fix stdc++ linking on windows; restore the icon 2024-11-13 08:50:35 +01:00
fgsfds 8b8eedcdfc port-net: fix artifact links 2024-11-12 23:20:22 +01:00
fgsfds 1398f5d0f5 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-11-12 23:18:53 +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 4d96fab71f Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-11-12 14:46:26 +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 796241d443 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-09-02 11:03:24 +02: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 3455708e38 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-09-02 10:07:04 +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 ae0ba57c24 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-08-06 16:54:36 +02: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 f7435e0ead Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-08-05 11:42:49 +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 fceacee0e2 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-08-04 11:09:30 +02: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. 55ab679a81 port: give Cloaking Device at respawn if cheat is active 2024-05-19 23:51:40 -07:00
fgsfds a5a2970b67 Merge branch 'port' into port-net 2024-05-19 19:45:37 +02: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 0d6a5f2d0f Merge branch 'port' into port-net 2024-05-18 19:33:21 +02:00
fgsfds dce96a4a3d port: add separate extra buttons for accept/cancel 2024-05-18 19:32:34 +02:00
fgsfds c5ab7d20df Merge branch 'port' into port-net 2024-05-18 19:18:36 +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 d53dd8c48f Merge branch 'port' into port-net 2024-05-18 19:02:30 +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 edced1d0e2 Merge branch 'port' into port-net 2024-05-15 14:11:30 +02:00
fgsfds e8e513fecb port: possible fix for #401 2024-05-15 14:11:24 +02:00
fgsfds 7cc389bc69 Merge branch 'port' into port-net 2024-05-15 13:39:19 +02:00
fgsfds 4601a9c318 port: only respect friendly fire setting in team games 2024-05-15 13:39:12 +02:00
fgsfds 5e03342562 Merge branch 'port' into port-net 2024-05-15 12:29:45 +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 30e987eb50 Merge branch 'port' into port-net 2024-05-15 12:13:43 +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 e5f142b110 Merge branch 'port' into port-net 2024-05-14 23:16:48 +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 95bf97a2c1 Merge branch 'port' into port-net 2024-05-14 22:56:54 +02:00
fgsfds 9530924c21 port: add mouse navigation toggle to options 2024-05-14 22:56:47 +02:00
fgsfds f52fa8f759 Merge branch 'port' into port-net 2024-05-14 22:53:08 +02:00
fgsfds 2ba192d411 port: make menu mouse flag global 2024-05-14 22:53:02 +02:00
fgsfds ff4321673b port: net: add note about regions 2024-05-14 22:24:10 +02:00
fgsfds 7590f0bdc3 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-05-14 22:23:00 +02:00
fgsfds bf8192ee84 Update README.md 2024-05-14 22:21:14 +02:00
fgsfds 70882d8a32 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-05-14 22:17:09 +02:00
fgsfds 45ec35172d ci: fix executable names on linux 2024-05-14 22:04:27 +02:00
fgsfds 045d5d2e46 Merge branch 'port-net' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-05-14 22:00:44 +02:00
fgsfds 926e4dce28 ci: autobuild pal and jpn and include them in release 2024-05-14 21:59:44 +02:00
fgsfds 7fabc68e95 Merge branch 'port' into port-net 2024-05-14 21:06:26 +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 948a3e0c51 Merge branch 'port' into port-net 2024-05-14 20:33:50 +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 7ffc1d393b Update README.md 2024-05-14 12:10:52 +02:00
fgsfds aba98349ae Merge branch 'port' into port-net 2024-05-14 12:07:19 +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
fgsfds 9625cd7d28 Merge branch 'port' into port-net 2024-05-14 11:37:47 +02:00
fgsfds 32c5d2c742 Merge pull request #411 from jonaeru/port-friendly-fire
port: add friendly fire mp option
2024-05-14 11:35:08 +02:00
fgsfds 3199f99fbd Merge branch 'port' into port-friendly-fire 2024-05-14 11:32:21 +02:00
fgsfds 0e2de3b746 Merge branch 'port' into port-net 2024-05-14 11:29:28 +02:00
fgsfds 51d842f516 Merge pull request #412 from jonaeru/port-autorandom
port: add auto random mp weapon option
2024-05-14 11:21:22 +02:00
fgsfds 4e7e61c207 Merge branch 'port' into port-autorandom 2024-05-14 11:20:29 +02:00
fgsfds 32417c164c Merge branch 'port' into port-net 2024-05-14 11:12:56 +02:00
fgsfds 70b02da163 port: fix long option names and whitespace 2024-05-14 11:12:49 +02:00
fgsfds 1a3f36f626 Merge pull request #420 from throwaway29292/port
Add an option in Combat Simulator to disable the blur effect from melee damage
2024-05-14 11:02:28 +02:00
fgsfds 1db33f278b Merge branch 'port' into port-net 2024-05-14 10:56:58 +02:00
fgsfds d8a26fa221 port: clean up whitespace 2024-05-14 10:56:50 +02:00
fgsfds 28d6c5b827 Merge pull request #426 from throwaway29292/dualwieldallguns
Add a cheat to allow dual-wielding all weapons
2024-05-14 10:35:57 +02:00
fgsfds abc6612641 Merge branch 'port' into port-net 2024-05-14 10:35:06 +02:00
fgsfds fef8985b6b port: fix whitespace and scope in bgunConsiderToggleGunFunction 2024-05-14 10:34:16 +02:00
fgsfds fd8718f7b1 Merge pull request #416 from NeonNyan/fix-rcp120alt
fix for rcp120 alt button behavior
2024-05-14 10:25:21 +02:00
fgsfds 57b1e37397 Merge branch 'port' into port-net 2024-05-14 10:15:19 +02:00
fgsfds 197208b951 port: add detail textures toggle 2024-05-14 10:13:50 +02:00
fgsfds 3f3c091289 Merge branch 'port' into port-net 2024-05-13 22:23:16 +02:00
fgsfds 4bd314f60b port: add exclusive fullscreen and hidpi settings
for now config only

exclusive fullscreen uses DefaultWidth/DefaultHeight for resolution

hidpi defaults to off
2024-05-13 22:23:04 +02:00
fgsfds 41ddcc7822 Merge branch 'port' into port-net 2024-05-13 18:49:16 +02:00
fgsfds 95b43b3f7b port: remove sprintf redeclaration 2024-05-13 18:48:35 +02:00
fgsfds 6708bf2aa6 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-05-13 15:27:06 +02:00
fgsfds 62a55a3d6e port: don't force libc++, fix system.c on clang16+ 2024-05-13 15:24:45 +02:00
fgsfds 12cf9df01b port: allow overriding CC and CXX 2024-05-13 12:55:29 +02:00
fgsfds c16aa70a66 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-05-13 12:20:12 +02:00
fgsfds c5c1ef1d4e port: ask for high performance GPU on windows 2024-05-13 12:19:34 +02:00
fgsfds f3c1242858 port: more detail texture adjustment 2024-05-13 12:15:42 +02:00
fgsfds 60c30e9b67 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-05-13 01:15:50 +02:00
fgsfds ef3d53b9f7 port: make detail textures less intense 2024-05-13 01:15:30 +02:00
fgsfds bc01ff558f Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-05-13 00:30:42 +02:00
fgsfds 1d040b1ccc port: hackfix detail textures
this might have broken something else
2024-05-13 00:30:21 +02:00
fgsfds 9755f3ab41 port: even more gfx_pc cleanup 2024-05-13 00:28:19 +02:00
fgsfds f86746364f port: no need to explicitly disable player collision when tracing light glares 2024-05-12 17:12:37 +02:00
fgsfds 536c766793 port: more gfx_pc cleanup 2024-05-12 17:09:50 +02:00
fgsfds dca1e1752b port: remove remnants of masked/blended texture support 2024-05-12 16:48:33 +02:00
fgsfds 8c844874e7 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-05-12 16:32:16 +02:00
fgsfds ce6424117e port: re-disable glare calculation in multiplayer
they don't render anyway
2024-05-12 16:31:45 +02:00
fgsfds 15c0327592 port: better light glare hit detection 2024-05-12 16:22:34 +02:00
fgsfds 2e18ffdad9 update branch name in build instructions 2024-05-11 15:58:56 +02:00
fgsfds b2ea9aa5f2 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-05-11 15:57:20 +02:00
fgsfds 13003121ea Update README.md 2024-05-11 15:54:52 +02:00
fgsfds ba56947457 clarify build instructions a bit 2024-05-11 15:53:34 +02:00
fgsfds b9a51e4a62 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-05-11 14:14:15 +02:00
fgsfds 27faaecda2 gcc14 fixes 2024-05-11 14:13:51 +02:00
Not actually throwaway 798fbf7b90 Add a cheat to allow dual-wielding all guns. The cheat's name is "Gameplay/(Two-Handed)" 2024-05-01 17:55:22 +02:00
fgsfds a0f8550034 Merge pull request #422 from PaulGrandperrin/patch-1
Makefile.port: fix dependencies for parallel compilation
2024-04-25 17:33:29 +02:00
Paul Grandperrin 73dc52cfd6 Makefile.port: fix dependencies for parallel compilation 2024-04-25 12:49:36 +02:00
Not actually throwaway 5b1d03cbbb Add an option in Combat Simulator to disable the blur effect from melee damage
This effect might be annoyning or eye straining for some people so i believe it's a good idea to implement this option. There is still some free space in the MP Options bitfield for future expansion.
2024-04-24 22:54:15 +02:00
Catherine Reprobate 68aee1d2f2 fix for rcp120 alt button behavior 2024-04-14 14:49:32 -07:00
Jonaeru 7580ebcaf9 port: rename constants 2024-03-26 23:45:55 +09:00
Jonaeru c9a14f090b port: add constants 2024-03-26 23:41:57 +09:00
Jonaeru 2483d4fc35 port: add auto random mp weapon option 2024-03-26 00:53:57 +09:00
Jonaeru 501ab95b00 port: fix texts 2024-03-20 11:19:06 +09:00
Jonaeru 0b61ec9641 port: add friendly fire mp option 2024-03-20 01:53:50 +09:00
fgsfds b4f7f467c0 Merge pull request #406 from jonaeru/port-perfectdarkness
Give Night Vision at respawn in Perfect Darkness Combat
2024-03-17 13:38:42 +01:00
fgsfds 894ccfabf3 Merge pull request #408 from jonaeru/port-fix-xrayscanner
Fix X-Ray Scanner model in Combat Simulator
2024-03-17 13:38:01 +01:00
Jonaeru ec8310e4a1 port: fix X-Ray Scanner model in Combat Simulator 2024-03-17 15:42:53 +09:00
Jonaeru 80faefbaf6 port: give Night Vision at respawn in Perfect Darkness Combat 2024-03-17 15:12:26 +09:00
fgsfds b72d7f54e1 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-03-09 22:38:35 +01:00
fgsfds c9f880e427 port: fix #224, allow combat knife in jpn 2024-03-09 22:38:11 +01:00
fgsfds d8b21f78e0 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-03-09 17:45:41 +01:00
fgsfds 92a9ac43fc port: fix linux build 2024-03-09 17:45:27 +01:00
fgsfds 0d0de5b0d4 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-03-09 17:43:11 +01:00
fgsfds 4baae8de0b port: add extra sleep calls to busy loops; separate sleep into system.c 2024-03-09 17:39:41 +01:00
fgsfds d11b5705a2 port: add missing configRegisterUInt decl 2024-03-09 17:03:06 +01:00
fgsfds 7667d37ff0 Merge pull request #388 from iamgreaser/gm/net/counterop-4player
port-net: Extend counter-op mode to 4 players
2024-03-09 16:58:31 +01:00
fgsfds cf7c4d4239 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-02-13 01:17:45 +01:00
fgsfds 839143550f port: fix potential crash in handInflictMeleeDamage
pointers can be little endian, so there might be a problem
2024-02-13 01:16:57 +01:00
GreaseMonkey adcf56ed34 Handle cases for Counter-Op where certain local players can be missing; Don't support 2.x controls for Counter-Op
I'm not sure if this happens in practice in the port itself, but with a bit of temporary hackery one can force certain players to be absent.
This handles that case cleanly.
2024-02-11 13:25:35 +13:00
fgsfds 5e65e84210 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-02-11 00:59:18 +01:00
fgsfds fe0d9b3cfd port: fix blur shader on some older cards 2024-02-10 16:56:54 +01:00
fgsfds 935cd1faa9 port: gl: dump shader source when compilation fails 2024-02-10 14:07:20 +01:00
GreaseMonkey 63a9a26908 set_chr_team(CHR_ANTI, *) now sets all counter-op player teams
The easiest-to-test effect of this is that counter-op players will no longer attempt to auto-aim against one another (p2 vs any other).

Maps where this was necessary: Villa, Chicago, Rescue, Air Base, Air Force One
(Other maps stick to the default of `TEAM_ENEMY`, and so this doesn't really affect it.)
2024-02-10 14:17:22 +13:00
GreaseMonkey f4530633d6 Replace "Counter-Operative" player selection with "Main Player" + extend to 4 entries 2024-02-10 11:20:01 +13:00
GreaseMonkey 94e244a236 Report correct ending success/failure when any counter-op player aborts 2024-02-09 16:15:09 +13:00
GreaseMonkey 92d3a9f564 Add macros for counter-op player determination; Handle some missing checks 2024-02-09 13:44:04 +13:00
GreaseMonkey 44a67e60e8 net: Use LOCALPLAYERCOUNT() for UI size determination 2024-02-09 09:10:33 +13:00
GreaseMonkey 634eecb35d Use vertical-split versions of menus in 3+-player main missions
These work fine in the 2x2 split arrangement.
2024-02-09 08:40:02 +13:00
GreaseMonkey a0db91a0c9 Preliminary 4-player counter-op mode
Here's some things that will be needed off the top of my head:

- Handling the half-screen-width case for the pause menus
- Changing the player select menu to select the not-counter-op player instead, then extending that to 4 players
- Thorough testing of each level for any weird counter-op-specific features
2024-02-09 08:40:02 +13:00
fgsfds 6b105d0be0 Merge pull request #381 from iamgreaser/gm/net/broadcast-queries-001
query.py: Allow broadcast queries and wait for all replies
2024-02-06 10:49:58 +01:00
GreaseMonkey 11febd7ace port-net: query.py: Print reply source addresses 2024-02-06 12:16:05 +13:00
GreaseMonkey dface4696c port-net: query.py: List all server query replies
This is for when one provides a broadcast address to query.
2024-02-06 12:14:20 +13:00
GreaseMonkey 0669ce5668 port-net: query.py: Allow querying broadcast
This waits for the first reply and then exits.
2024-02-06 12:05:17 +13:00
fgsfds 6d3ea5b0fd Update README.md 2024-01-29 22:14:06 +01:00
fgsfds 36f8494ebf Update README.md 2024-01-29 22:11:34 +01:00
fgsfds fcb1dbb298 Merge pull request #375 from abgrac/readme-links-netplay
Add port-net/netplay build links to default README
2024-01-29 22:10:14 +01:00
fgsfds 409e955883 Merge pull request #376 from abgrac/readme-links-titles
Updated title & links titles for consistency with Master
2024-01-29 22:10:06 +01:00
Adriano Bini f006f9ba7b Updated title/link titles for consistency with MST
Some people are not being able to properly download/play because of Github's always defaulting to master's README.MD. This includes netplay links in the master branchg README as well.
2024-01-29 17:16:07 -03:00
Adriano Bini 815c75c6a8 Add port-net/netplay build links to default README
Some people are not being able to properly download/play because of Github's always defaulting to master's README.MD. This includes netplay links in the master branchg README as well.
2024-01-29 17:08:27 -03:00
fgsfds 6a03e8d9cf port: net: unify console and join address input routines 2024-01-28 19:28:51 +01:00
fgsfds a1af5b655a Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-01-28 18:46:13 +01:00
fgsfds 33cc89e8fd Merge pull request #371 from Calinou/add-crosshair-health-option
Add an option to color crosshair according to player health + shield
2024-01-28 18:39:05 +01:00
fgsfds cc6df47eed Merge pull request #372 from Calinou/crosshair-hide-when-dead
Always hide crosshair when dead
2024-01-28 18:37:50 +01:00
Hugo Locurcio 02d7efb87f Add an option to color crosshair according to player health + shield
Shield is taken into account and is added to health for the calculation,
as the vast majority of damage types are fully blocked by a shield.

3 modes are available:

- Off (default)
- On (Green): Goes through a red-yellow-green-cyan gradient,
  closer to vanilla.
- On (White): Goes through a red-yellow-white-green gradient,
  closer to games like Xonotic.

When set to either of the On modes, the crosshair color setting
is ignored but the crosshair alpha setting is still used.
2024-01-27 19:21:05 +01:00
Hugo Locurcio 1f4d9c8cdc Always hide crosshair when dead
Previously, the crosshair would show up during the death animation
if Always Show Target is enabled or if aiming just before dying.
2024-01-27 19:19:06 +01:00
fgsfds edeafa596d Merge pull request #373 from abgrac/port-net
Changed server footer color to more readable green
2024-01-27 14:51:30 +01:00
Raf 63c456a233 port-64: first changes, able to build 2024-01-27 18:25:55 +08:00
Adriano Bini b954e3ce80 Changed server footer color to more readable green 2024-01-27 02:17:48 -03:00
fgsfds bfa4035642 port: net: bump protocol version 2024-01-16 01:59:01 +01:00
fgsfds 35be4d589e Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-01-16 01:57:15 +01:00
fgsfds 474a6df3d4 port: add spawn with weapon mp option
unfortunately it does not fit in the save buffer and won't save
2024-01-16 01:56:30 +01:00
fgsfds 884a30f970 port: net: bump protocol version 2024-01-16 01:27:22 +01:00
fgsfds 7288947390 port: net: handle UCMD_ACTIVATE as a press 2024-01-16 01:27:03 +01:00
fgsfds c444e76ecb port: net: skip intro cutscene if netgame requested on command line 2024-01-15 13:10:57 +01:00
fgsfds c4b1a8d4a2 port: net: fix --maxclients 2024-01-15 13:01:13 +01:00
fgsfds 7c8b1176c7 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-01-15 12:58:35 +01:00
fgsfds 9cde121b52 port: don't call rumble function if rumble strength is 0 2024-01-15 12:58:00 +01:00
fgsfds c5a088e7b8 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-01-15 11:40:30 +01:00
fgsfds e53f26f3eb port: fix #347
patch submitted by Ryan Dwyer

The patch allows all humans/bots to be selected regardless of team. It also adds a check to make sure a bot is not given a command to attack itself.
2024-01-15 09:47:52 +01:00
fgsfds 81313f0c4e port: ifdef around sight scale changes 2024-01-14 21:21:19 +01:00
fgsfds cf5588478b Merge pull request #332 from Calinou/add-crosshair-size-option
Add a crosshair size option
2024-01-14 21:21:03 +01:00
fgsfds d9cb850848 Merge pull request #333 from AXDOOMER/port
Always use high detail weapon models
2024-01-14 21:20:36 +01:00
fgsfds 8e443d4830 port: ifdef around sight scale changes 2024-01-14 21:13:31 +01:00
fgsfds 2cb52b749c Merge pull request #332 from Calinou/add-crosshair-size-option
Add a crosshair size option
2024-01-14 21:11:58 +01:00
fgsfds de14f90daf Merge branch 'port-net' into add-crosshair-size-option 2024-01-14 21:11:44 +01:00
fgsfds 9afc7e113e Merge pull request #333 from AXDOOMER/port
Always use high detail weapon models
2024-01-14 20:49:20 +01:00
fgsfds fbfe4b4564 port: net: allow up to 120fps in netgames 2024-01-14 20:48:22 +01:00
fgsfds 4cb99506cb port: net: replace useless checksum with slightly more useful crc16 2024-01-14 20:36:03 +01:00
fgsfds 562e763fbd tools: add server query client example 2024-01-14 20:03:16 +01:00
fgsfds 952de6e82b port: net: allow connectionless server info queries 2024-01-14 19:59:00 +01:00
fgsfds 7ec54e6d0b port: net: fix team/handicap menus with 5+ players 2024-01-14 17:54:16 +01:00
fgsfds e6df6014c7 port: net: bump protocol version 2024-01-14 17:40:02 +01:00
fgsfds e688a1c6e6 port: net: do not assume contiguous player slots 2024-01-14 17:36:19 +01:00
fgsfds e44298d0c2 port: net: fix player options not working in SP 2024-01-14 17:15:43 +01:00
fgsfds 31cd8fc28a port: net: fix #328 2024-01-14 15:49:18 +01:00
fgsfds a46ce32ad4 port: net: don't crash if there aren't any player props
although I still don't know what actually leads to this situation
2024-01-14 15:38:05 +01:00
fgsfds 31d8aae704 port: net: move the rest of the IP logging to log only 2024-01-08 12:31:42 +01:00
fgsfds 4b30f52b32 port: net: cap --maxclients 2024-01-07 22:20:46 +01:00
fgsfds c8d42bbf20 port: net: if going into netgame from command line, skip intro and default to profile 0 2024-01-07 22:14:59 +01:00
fgsfds 511d6ca299 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-01-07 22:06:47 +01:00
fgsfds b9db86f89b port: add command line parameter to select player file 2024-01-07 22:05:31 +01:00
fgsfds 33f6d643be port: net: add command line arguments for quick hosting and joining 2024-01-07 22:01:20 +01:00
fgsfds c2d09135f7 port: net: probably fix ipv6 address parsing 2024-01-07 21:17:59 +01:00
fgsfds 9f6b21e870 port: net: fix main menu lockup after playing a 5+ player game 2024-01-07 20:52:31 +01:00
fgsfds 4eca4a1f07 port: net: fix a bunch of access violations 2024-01-07 19:54:27 +01:00
fgsfds 4439fdf411 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-01-07 19:10:21 +01:00
fgsfds 6bd3597ff6 port: fix optionsmenu.c warnings 2024-01-07 18:40:32 +01:00
fgsfds 6ac8a1a0f6 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-01-07 17:08:44 +01:00
fgsfds 8645d0a82a port: don't use the existing log system in crashlog in case it crashes 2024-01-07 17:07:12 +01:00
fgsfds ba52580e0c port: display module offsets in the windows crashlog 2024-01-07 16:43:20 +01:00
fgsfds d1d288b96a port: don't use cv2pdb by default if it exists 2024-01-07 16:43:02 +01:00
fgsfds 06f2283180 port: use cv2pdb on windows executables if present 2024-01-07 16:09:04 +01:00
fgsfds b1b17e21c1 port: write crash info to log file even without --log 2024-01-07 15:40:30 +01:00
Alexandre-Xavier Labonté-Lamoureux f4ec781b8e port: always use high detail weapon models 2024-01-06 02:58:54 -05:00
Hugo Locurcio 5e256ea406 Add a crosshair size option
5 sizes are available (from 0 to 4), with 2 being the default vanilla-like
value.

Size 0 is a dot with alpha adjusted to match the crosshair color
settings.
2024-01-05 20:21:44 +01:00
fgsfds 5abb0e484e port: net: fix maxplayers cap 2024-01-05 00:33:51 +01:00
fgsfds 16c247a24e port: net: change default LerpTicks to 3 2024-01-04 19:27:14 +01:00
fgsfds 0737c688d7 port: net: don't explode in menu code with > 4 players 2024-01-04 00:00:14 +01:00
fgsfds 9de245eab6 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2024-01-03 21:56:28 +01:00
fgsfds c487e423b1 port: fix blur-related crash on Intel GPUs 2024-01-03 21:55:07 +01:00
fgsfds a3cc54d33a port: net: bump protocol version 2024-01-02 19:03:11 +01:00
fgsfds a261246e64 port: net: move clsettings to a separate message; add join notifications 2024-01-02 19:02:23 +01:00
fgsfds 2e195fe21a port: net: bump protocol version 2024-01-02 00:44:40 +01:00
fgsfds 36a692991f port: net: transmit more player options; allow headroll death in netgames 2024-01-02 00:44:08 +01:00
fgsfds ca0e3c3060 port: net: disable headroll in netgames 2024-01-01 21:25:36 +01:00
fgsfds 39474e97a7 port: net: bump protocol version 2024-01-01 20:26:52 +01:00
fgsfds b74cd095a1 port: net: better gun and crosshair position sync; fix zooming guns 2024-01-01 20:18:32 +01:00
fgsfds 96e1c57f61 port: net: carry some of the client inputs over to server-sent moves 2023-12-31 21:00:54 +01:00
fgsfds f6ee8bbf71 port: net: don't die when there's a % in a chat message 2023-12-31 20:31:37 +01:00
fgsfds 188faeecf6 port: net: update netplay.md 2023-12-31 19:51:13 +01:00
fgsfds 2c0a0a1337 port: net: don't play death music, pain and pickup sounds from other players 2023-12-30 14:32:35 +01:00
fgsfds 7f92551d5a port: net: don't create hudmsgs for other players 2023-12-30 13:21:36 +01:00
fgsfds f54dbb596e Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2023-12-30 12:20:03 +01:00
fgsfds 49f607dd79 port: fix pal and jpn builds 2023-12-30 12:19:36 +01:00
fgsfds aa3c5a85b7 port: net: make team sync slightly less insane 2023-12-29 11:56:54 +01:00
fgsfds f46e112c3d port: net: fix dualwielding, probably; bump protocol version 2023-12-29 02:06:12 +01:00
fgsfds bcb5b3f5c1 port: net: fix uninitialized tickop in SVC_PROP_USE 2023-12-28 22:49:39 +01:00
fgsfds 65589e2fd2 port: net: sort of sync lifts; bump protocol version 2023-12-28 22:43:27 +01:00
fgsfds 787758c038 port: log branch name 2023-12-28 21:48:05 +01:00
fgsfds 54fbd8ba54 port: net: log protocol name 2023-12-28 21:41:27 +01:00
fgsfds 49129dd3e7 port: log branch name 2023-12-28 21:41:20 +01:00
fgsfds 7bfa2b9425 port: net: bump protocol number 2023-12-28 21:38:33 +01:00
fgsfds 53fbbb8a10 port: net: fix teams in netgames 2023-12-28 21:38:17 +01:00
fgsfds 7bee9cdcfc port: net: sync instant environmental death 2023-12-28 12:45:18 +01:00
fgsfds 928544ae5f port: net: bump protocol version just in case 2023-12-28 12:11:43 +01:00
fgsfds 312c752205 port: net: set client rng at the same time the server sends it 2023-12-28 12:10:43 +01:00
fgsfds a5d1c25fea port: net: set g_NumReasonsToEndMatch when server ends the match
just in case
2023-12-28 12:00:21 +01:00
fgsfds 7abebe7405 port: net: don't end match locally on the client 2023-12-28 11:58:38 +01:00
fgsfds ebc126f837 port: net: disable pause in netgames 2023-12-27 19:30:29 +01:00
fgsfds 67bc9c4858 port: net: ignore handicap in netgames 2023-12-27 16:08:49 +01:00
fgsfds c4a3c18208 port: net: clarify chrslots 2023-12-27 16:08:41 +01:00
fgsfds cf1b87a833 port: net: discard game-related messages on client if not in CLSTATE_GAME 2023-12-27 01:51:44 +01:00
fgsfds fb123603ca port: net: put SVC_STAGE_START/END back in the default channel 2023-12-27 01:40:05 +01:00
fgsfds b3ab58da3b Update netplay.md 2023-12-27 01:15:23 +01:00
fgsfds 6374fc834c Update README.md 2023-12-27 01:03:04 +01:00
fgsfds 6df31649f5 Update README.md 2023-12-27 00:38:05 +01:00
fgsfds 9de6b580ba port: net: document netplay status 2023-12-27 00:37:19 +01:00
fgsfds 8eb6880694 port: net: fix linux builds probably 2023-12-26 23:15:05 +01:00
fgsfds fe4d86fae1 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2023-12-26 22:58:20 +01:00
fgsfds 3c62a967a2 port: display branch name in legal screen 2023-12-26 22:58:08 +01:00
fgsfds 8492670bad ci: build port-net branch 2023-12-26 22:49:18 +01:00
fgsfds 04f95ed1d1 port: net: experimental 8 player support 2023-12-26 22:48:28 +01:00
fgsfds ee037c10ce port: net: ignore UpdateFrames when reliable move is required 2023-12-26 22:40:33 +01:00
fgsfds cbf65e53b9 port: net: only send player moves when needed; add stuff to net debug 2023-12-26 22:33:57 +01:00
fgsfds 8c2b15d649 port: on-screen messages include all rows of the message 2023-12-26 16:55:39 +01:00
fgsfds 2134571b9a port: net: check clients for matching mods; bump protocol version 2023-12-26 16:51:55 +01:00
fgsfds a541c79eda port: net: add movement update rate to ini 2023-12-26 16:21:07 +01:00
fgsfds 454086be6b port: net: separate control msgs into another channel; add bandwidth settings 2023-12-26 16:18:20 +01:00
fgsfds 6bd5997059 port: net: don't draw console or net debug when the font is unloaded 2023-12-25 18:25:07 +01:00
fgsfds 99911b2290 port: net: domain names can in fact start with a digit 2023-12-25 13:10:07 +01:00
fgsfds 95d8b0692f port: net: add some config vars 2023-12-24 17:31:57 +01:00
fgsfds e85cc3b309 port: net: hardcap fps to 60 if in network game 2023-12-24 17:14:19 +01:00
fgsfds 2a01d562c3 Update README.md 2023-12-24 17:07:24 +01:00
fgsfds 51daf45c19 Update README.md 2023-12-24 17:06:29 +01:00
fgsfds c9bd2bfd54 port: net: clarify what this is 2023-12-24 17:01:40 +01:00
fgsfds 6225f62412 port: net: partially fix rockets 2023-12-24 16:56:05 +01:00
fgsfds d2ffd73dea port: net: add net debug info, add copypaste support to IP input 2023-12-24 00:39:36 +01:00
fgsfds 02329b64a1 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2023-12-23 22:09:43 +01:00
fgsfds aae0f70dd3 port: net: sync some projectiles, doors, parts of bgun, etc 2023-12-23 22:09:37 +01:00
fgsfds 41d9cb4578 port: add console for chat and log messages 2023-12-23 22:09:02 +01: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
fgsfds f2a2458795 port: fix typo 2023-12-22 12:33:34 +01:00
fgsfds a7ab358b43 port: simplify sight color code a bit 2023-12-22 12:32:13 +01:00
fgsfds a82ac025da Merge pull request #300 from Bobbar/port_crosshair_alpha
Crosshair Alpha Proof of Concept
2023-12-22 12:25:36 +01:00
fgsfds 461bf8d49b Merge pull request #314 from kronflux/port
port: add "Skedar Leader" track to Soundtrack menu
2023-12-22 12:24:46 +01:00
fgsfds 370047b1b0 Merge branch 'port' of https://github.com/fgsfdsfgs/perfect_dark into port-net 2023-12-18 16:34:58 +01:00
Richard M db1d00a9b0 port: add "Skedar Leader" track
Add the "Skedar Leader" track to the Combat Simulator Soundtrack selection menu as "Skedar Warrior" as we do not currently have the ability to use the official track name
2023-12-17 11:50:16 -07:00
fgsfds 6fc99e4c23 port: net: basic networking with barely working position sync 2023-12-17 12:54:48 +01:00
fgsfds 92c66c93dc port: correct HUD aspect in horizontal 2-player splitscreen too 2023-12-17 12:52:11 +01:00
fgsfds 94df3fc58c Merge pull request #309 from djdv/feat/win-max
port: add maximize window option to extended menu
2023-12-17 12:30:25 +01:00
fgsfds f2545b4e53 port: fix GE muzzleflashes on single-shot guns 2023-12-17 12:28:47 +01:00
Dominic Della Valle 0221839699 port: add maximize window option to extended menu 2023-12-16 11:56:39 -05:00
Bobby Lovell 1698f53728 Update main.c to use new UInt config for crosshair color 2023-12-16 10:20:32 -05:00
Bobby Lovell 7ac734fc81 Merge branch 'fgsfdsfgs:port' into port_crosshair_alpha 2023-12-16 10:18:34 -05:00
fgsfds 28218b26c2 port: add setting for GE muzzle flashes and disable it by default 2023-12-16 15:22:23 +01:00
fgsfds 4233e5e066 Merge pull request #293 from Nyxem64/muzzleflash
GE Muzzle flash addition
2023-12-16 15:08:22 +01:00
fgsfds cdd7d6edac port: use strto* when parsing config instead of ato*
allows hex values
2023-12-16 15:08:14 +01:00
fgsfds 581c63fc27 Merge pull request #308 from djdv/feat/win-max
port: add start window maximized flag to config
2023-12-16 15:03:04 +01:00
fgsfds dee7ab7b54 Merge pull request #306 from Bobbar/port_u32_config_support
Add config support for unsigned integers.
2023-12-16 15:02:37 +01:00
Dominic Della Valle 8c509db888 port: add start window maximized flag to config 2023-12-16 07:04:52 -05:00
Bobby Lovell 5aa799718a Add support for unsigned integers. 2023-12-15 10:17:15 -05:00
Bobby Lovell 880a7a0971 Add back line inadvertently removed in 342e186f79 2023-12-15 08:10:31 -05:00
Bobby Lovell e84d83e404 Add missing ndef. 2023-12-14 16:08:53 -05:00
Bobby Lovell 79fb976bcf Implement a simple colored box menu item type and use that for the preview. 2023-12-14 16:03:29 -05:00
Bobby Lovell 519bd95a75 Center preview text. 2023-12-14 14:49:13 -05:00
Bobby Lovell 8421140e3f Remove comment. 2023-12-14 10:31:47 -05:00
Bobby Lovell 894ea53b29 Spell out colors... 2023-12-14 10:18:43 -05:00
Bobby Lovell fb05725c34 - Implement RGBA.
- Add preview label.
2023-12-14 10:13:27 -05:00
Bobby Lovell 2a6625278a - Fix RGB defines
- Just store the colour and parse RGBA values when modifying.
2023-12-13 13:48:06 -05:00
Bobby Lovell 342e186f79 Add option to change crosshair alpha, and could provide fully custom colors. Proof of concept. 2023-12-13 13:06:48 -05:00
J cabd40f898 GE Muzzle flash addition 2023-12-11 00:49:09 +00:00
fgsfds 0a7faf2409 port: add file patching system; add patch for #286
patch submitted by Ryan Dwyer
2023-12-07 17:20:34 +01:00
fgsfds 03324c0823 port: use correct aspect instead of 4:3 when scaling crosshair 2023-12-07 16:46:32 +01:00
fgsfds aeb6851606 port: change FPS hard cap to 240 on NTSC, 200 on PAL 2023-12-06 17:16:34 +01:00
fgsfds 26da2aa5e6 Update README.md 2023-12-06 17:12:13 +01:00
fgsfds 7647062619 port: hard cap FPS to 200 for now 2023-12-06 17:11:21 +01:00
fgsfds 3a313287bb port: fix config ints not clamping properly 2023-12-06 17:10:48 +01:00
fgsfds 42af4d4604 port: approximately normalize eyespy bob 2023-12-06 16:53:46 +01:00
fgsfds 3118d01921 port: don't render garbage in the first blur frame (fixes #287) 2023-12-06 14:57:21 +01:00
fgsfds f46359b307 Update README.md 2023-12-05 16:27:09 +01:00
fgsfds 00297f6d0d Merge pull request #276 from hyh19962008/port
Add the minimal required gcc and sdl2 version in README.md
2023-12-05 16:23:47 +01:00
Demon 39d5b57ccb Update README.md, change minimal SDL2 version to 2.0.12 2023-12-05 23:00:56 +08:00
fgsfds d1be171939 port: only use SDL_CONTROLLER_TYPE_VIRTUAL when available 2023-12-04 18:22:37 +01:00
fgsfds 6f206345a1 Merge pull request #282 from JAMoreno-Larios/port
Changed 'codeclean' so that it doesn't try to delete inexistent directories.
2023-12-03 23:08:25 +01:00
José Agustín Moreno Larios 13b23de6d3 Simplified the 'codeclean' rule to find all *.o files and delete them 2023-12-03 16:38:18 -05:00
José Agustín Moreno Larios d897356029 Changed 'codeclean' so that it doesn't try to delete inexistent directories. 2023-12-03 16:28:02 -05:00
fgsfds f96e7da00f port: use proper aspect for 2D elements
this means that now scaling at most 4:3 resolutions will be a bit mangled, since the real base resolution is 320x220
2023-12-03 21:10:41 +01:00
Demon 1fb16b3bfd Update README.md, add the minimal required gcc and sdl2 version 2023-12-03 13:18:27 +08:00
fgsfds 2c20a0487e port: better menu blur
TODO: make it render the blurred texture to the fb once instead of rendering it blurred every frame
2023-12-02 19:18:47 +01:00
fgsfds aef2463361 port: alternative fix for the classic sight 2023-12-02 14:04:33 +01:00
fgsfds 2b8d5d4f75 port: fix crosshair aspect and make sights centered 4:3 2023-12-02 13:48:24 +01:00
fgsfds ef83f23200 port: fix sun aspect ratio 2023-12-01 19:35:04 +01:00
fgsfds 75133acbbd port: alternate squished aspect fix
by just changing the actual aspect instead of fucking around with the resolution
2023-12-01 17:31:42 +01:00
fgsfds 1aea68b89a Revert "port: unsquish the aspect ratio"
This reverts commit af34015562.

I'll have to come up with a better way to do this
2023-12-01 17:21:27 +01:00
fgsfds af34015562 port: unsquish the aspect ratio
this might break something but I haven't noticed anything bad yet
2023-11-30 10:51:21 +01:00
fgsfds 7cd3dafaa4 port: add wide HUD centering option for ultrawide displays 2023-11-27 11:52:53 +01:00
fgsfds e0249067b9 port: reset the controller LEDs on unassign 2023-11-27 01:26:45 +01:00
fgsfds 31ad9351f5 port: load gamecontrollerdb if available 2023-11-27 01:20:09 +01:00
fgsfds 116dc7e8b6 port: allow assigning controllers manually 2023-11-27 00:57:52 +01:00
fgsfds aced07f356 Merge pull request #253 from NeonNyan/fix-camspy
fixup: PC controls camspy instant abort
2023-11-26 23:59:35 +01:00
Catherine Reprobate 8d99ac92a0 fixup: PC controls camspy instant abort
only consider first controller for camspy input
2023-11-26 14:54:12 -08:00
fgsfds 4a3c3a29b7 port: measure nbomb age based on timestamps
makes them last the same amount of time regardless of fps
2023-11-26 21:15:47 +01:00
fgsfds 523e6ba9d9 port: don't randomly close radial menu at 240fps 2023-11-26 20:45:54 +01:00
fgsfds c6a36633f5 port: untie radial menu open delay from framerate 2023-11-26 20:43:31 +01:00
fgsfds 626b5937ce port: possibly fix reloading and some altmodes in N64 schemes 2023-11-26 20:32:46 +01:00
fgsfds 228851f867 port: add c-buttons to bind menu 2023-11-26 20:27:22 +01:00
fgsfds 1c72b3022e port: prevent extended options from cutting off 2023-11-26 19:46:06 +01:00
fgsfds 5d7b7adb57 port: expose FirstGamepadNum as checkbox in ext options menu 2023-11-26 19:26:07 +01:00
fgsfds 2d3e3d1aaf port: add option to disable death music in MP 2023-11-26 19:10:19 +01:00
fgsfds 94e8e1b5e7 port: don't nuke all binds when resetting one player 2023-11-26 19:05:13 +01:00
fgsfds d3a2ed216a port: add a second set of default bindings for N64 controls 2023-11-26 18:40:06 +01:00
fgsfds 600dae58e2 port: allow using N64 control schemes
change from Ext to another control scheme to activate

note that this will require rebinding keys, as the default config is for the Ext scheme
2023-11-26 18:07:35 +01:00
fgsfds 3a1d08509b port: unlock all challenges properly 2023-11-26 13:40:15 +01:00
fgsfds 45a44cd37e port: move unlock everything option to cheats 2023-11-24 22:40:02 +01:00
fgsfds 5a68daf18c Merge pull request #243 from Bobbar/unlock_everything_gamesave
Option to unlock everything.
2023-11-24 22:31:40 +01:00
fgsfds e43d29f357 port: add hold crouch 2023-11-24 22:30:52 +01:00
fgsfds 3328e147eb port: hackfix some more RGBA32 textures 2023-11-22 22:19:54 +01:00
fgsfds 7e929c2432 Update README.md 2023-11-18 12:05:21 +01:00
fgsfds b88690e8df port: add easier ways to skip the intro
--skip-intro on command line or Game.SkipIntro in the config
2023-11-18 11:56:19 +01:00
fgsfds 305e64a263 port: restore glReadBuffer value after changing it
this might fix reshade
2023-11-18 00:43:22 +01:00
fgsfds b618c99abd Merge pull request #245 from Bobbar/port_add_VS_ignore
Update gitignore for Visual Studio.
2023-11-17 20:48:47 +01:00
Bobby Lovell 58d815f1ec Update gitignore for Visual Studio. 2023-11-17 12:20:35 -05:00
Bobby Lovell 99da0586ea Add menu and confirmation prompt. 2023-11-17 09:28:43 -05:00
Bobby Lovell 27e36ca24e Add prototype. 2023-11-17 09:23:00 -05:00
Bobby Lovell 9dfd0ec905 Add the main unlock hacks 2023-11-16 21:11:31 -05:00
fgsfds 6f55843f30 port: backport better SDL framepacing from LUS 2023-11-15 13:53:18 +01:00
fgsfds 4a16f27abd port: don't slow down the mouse at exactly 240 fps 2023-11-15 12:13:13 +01:00
fgsfds 11e318b70f port: mouselook speed now independent of framerate 2023-11-15 10:32:54 +01:00
fgsfds 5bb4f1d193 port: fix (?) slomo at high framerates 2023-11-15 00:25:10 +01:00
fgsfds f394f209b2 port: fix npc footsteps at high framerates 2023-11-15 00:25:01 +01:00
fgsfds 9c7f348652 port: use the 240hz timer in activemenu 2023-11-15 00:24:38 +01:00
fgsfds 32b2e9c28e port: fix sliding doors exploding at non-60fps framerates 2023-11-14 23:58:40 +01:00
fgsfds 72e9e2af95 port: very experimental uncapped framerate support
set Game.TickRateDivisor in pd.ini to 0

this still has many issues, such as combat boost not working
2023-11-14 23:29:44 +01:00
fgsfds 8a348ab1b5 port: fix bullet casings going behind the world 2023-11-13 21:07:53 +01:00
fgsfds 28b172f5c7 port: make autoguns fire only on even frames at 60+ fps 2023-11-12 16:09:58 +01:00
fgsfds ef511d5889 port: fix #231 2023-11-12 15:48:41 +01:00
fgsfds 83a155fa49 port: fix #210
by using a separate fullscreen fb for blur effects
2023-11-12 15:05:21 +01:00
fgsfds eecee9d940 port: fix #55
patch submitted by Ryan Dwyer
2023-11-12 13:56:50 +01:00
fgsfds cd19c07810 port: fix player model flinching at the start of a cutscene
patch contributed by Ryan Dwyer
2023-11-11 17:42:39 +01:00
fgsfds f1edc91fd8 port: fix whitespace 2023-11-11 17:41:19 +01:00
fgsfds 5df6d2fdfb port: slightly simpler fix for bgTestHitOnObj 2023-11-11 17:41:10 +01:00
fgsfds 83c5b4980b Merge pull request #230 from NeonNyan/port
Remote mine fixes
2023-11-11 17:31:52 +01:00
Catherine Reprobate 0e043f24b5 Remote mine fixes
- N64 fix: fixes issue where selecting the remote mine from the active menu
  or the inventory menu when Jo already has a remote mine equipped
  causes the player to unequip the detonator

Confirmed this issue presents on ntsc-final on 1964GEPD.

- port fix: fixes issue with remote mine input handler where the
  previous active menu slotnum would be activeated. The slotnum is
  unconditionally set to 4 (the "resting no-op" slotnum) to prevent this
2023-11-06 22:09:48 -08:00
fgsfds 828776e272 port: account for non-segmented addresses in bgTestHitOnObj 2023-11-05 23:08:34 +01:00
fgsfds 407d4724a7 port: use mpindex to index player specific settings 2023-11-04 02:39:16 +01:00
fgsfds d75adeb0c8 port: per-player settings
NOTE: this will reset big parts of your config
2023-11-04 02:08:45 +01:00
fgsfds dc6e6a507c port: slightly more helpful rom error messages 2023-11-04 02:08:44 +01:00
fgsfds fbae610a3b port: rework config system a bit 2023-11-04 02:08:44 +01:00
fgsfds 479c0335f3 Update README.md 2023-11-02 00:24:49 +01:00
fgsfds d021e95d70 port: add exe region to legal screen 2023-11-02 00:20:35 +01:00
fgsfds 3ac194f9ee port: pal: fix (?) audio stutter 2023-11-02 00:20:18 +01:00
fgsfds fea0a1e4ca port: pal: swap all the characters in extended fonts 2023-11-01 23:46:39 +01:00
fgsfds a802d2db06 port: allow pressing DEL to delete the binding 2023-11-01 17:46:24 +01:00
fgsfds 4a0296d1a4 port: fix radial menu bind in extended options 2023-11-01 16:36:07 +01:00
fgsfds c040c17b49 port: fix whitespace 2023-11-01 16:35:48 +01:00
fgsfds 4eaaae91a6 Merge pull request #215 from SilentException/feat-grab-mouse-default
Allow mouse input by default
2023-11-01 16:30:25 +01:00
SilentException 83d22c3b70 Allow mouse input by default 2023-11-01 04:23:34 +01:00
fgsfds 4914aa335b fix README typo 2023-10-30 19:01:52 +01:00
fgsfds afb91ab9e9 port: add radial menu sensitivity slider 2023-10-30 19:00:26 +01:00
fgsfds ed65f7971a Merge pull request #206 from NeonNyan/port
Input fixups for quick-detonate and radial menu navigation
2023-10-30 11:14:33 +01:00
Catherine Reprobate 3feddd8c64 port: fixes #205 radial movement issue 2023-10-29 16:13:04 -07:00
Catherine Reprobate 9b65199d3d fix: port: xbla-style quick detonate fix
- adds A + X to list of quick-detonate keybinds: correct xbla behavior for quick detonating per the xbox
implementation
2023-10-29 15:48:50 -07:00
fgsfds 50b74e4280 port: fix #204; allow players 2-4 to use lstick in radial menu 2023-10-29 18:28:04 +01:00
fgsfds c8db5fa106 port: add keybind menu 2023-10-28 18:17:35 +02:00
fgsfds cea9527936 port: add controller axis settings
also make sliders look nicer and save some input settings on quit
2023-10-28 14:36:00 +02:00
fgsfds 2813ecedeb port: fix some sliders in extended options 2023-10-28 13:45:12 +02:00
fgsfds 015817f204 port: add extended options menu
as well as support for string literals in the menu system
2023-10-28 05:33:09 +02:00
fgsfds da7e1493a5 port: extend sky slightly beyond screen
to push glitchy corners out of view
2023-10-25 12:54:47 +02:00
fgsfds 368021201b Update README.md 2023-10-24 15:55:04 +02:00
fgsfds 30b8400d86 port: fix drug blur not resetting on respawn
fix taken from Graslu's decomp fork
2023-10-24 11:14:33 +02:00
fgsfds 77fcac4912 port: remove static decls from bondmove.h 2023-10-23 20:34:51 +02:00
fgsfds 790d44afb0 Merge pull request #203 from NeonNyan/port
fixup: quick detonate
2023-10-23 20:33:23 +02:00
Catherine Reprobate 0ea3bea096 port: put instant detonate flow in own function 2023-10-22 16:35:30 -07:00
Catherine Reprobate 05c108a950 fixup: quick detonate 2023-10-22 16:23:25 -07:00
fgsfds 6957c1540d port: fix digital grab movement 2023-10-22 18:49:48 +02:00
fgsfds be689a0495 port: add forgotten DPAD_RIGHT setting 2023-10-22 15:29:36 +02:00
fgsfds 0b9f99a084 port: only allow crouch cycling when crouching is allowed 2023-10-22 15:22:01 +02:00
fgsfds 4c1076080d port: allow user to go back to the original crouch controls
set Game.ClassicCrouch=1
2023-10-22 15:17:47 +02:00
fgsfds 8347900d33 port: expand config size 2023-10-22 15:07:47 +02:00
fgsfds f638d49693 port: fit the CK_ enum back into 32 bits 2023-10-22 14:45:58 +02:00
fgsfds d1817aaea6 port: cleanup; camspy and slayer respect invert pitch option
note: dual analog mode now only works if you set StickCButtons=0 in pd.ini
2023-10-22 14:38:44 +02:00
fgsfds e2b1cdce86 Merge pull request #196 from NeonNyan/1.2_analog
1.2 + 1 Analog Controls
2023-10-22 13:29:42 +02:00
fgsfds 81a5e971ef port: finish drawing before copying the backbuffer 2023-10-21 14:24:36 +02:00
fgsfds 6f0cb752aa port: gl: allow user to override context version 2023-10-19 13:36:40 +02:00
fgsfds abf5703036 port: only disable crash handlers if they were installed 2023-10-19 12:32:57 +02:00
fgsfds b8e6e19ef5 port: allow running without a crash handler
--no-crash-handler
2023-10-19 12:30:50 +02:00
fgsfds ba51e9d5d1 port: don't autoturn when looking too far to the side in horizon scanner mode 2023-10-18 16:17:26 +02:00
fgsfds 8bf14c4044 port: implement horizon scan effect 2023-10-18 16:12:25 +02:00
Catherine Reprobate b650c820e0 Readme update 2023-10-17 18:28:18 -07:00
Catherine Reprobate 80d787caf9 Support for two-sticks, one controller
port: implements analog movement for pc controllers

port: Implement menu movement with the C stick

port: Implement analog leaning

port: Implement 1.2 + 1 analog zooming

port: pd input lib now handles 32 buttons

port: modern crouch implementation

port: implement analog slayer airbraking

port: xbla farsight strafing

Map crouch buttons

- map cycle crouch to L3
- sensible 1964-style crouch bindings
2023-10-17 18:28:18 -07:00
fgsfds 1eb1e9686a port: allow user to disable framebuffer use 2023-10-16 23:19:18 +02:00
fgsfds dbebe7e626 port: fix new fb effects when MSAA is on 2023-10-16 23:06:00 +02:00
fgsfds 79f8a35c33 port: implement fisheye 2023-10-16 22:38:44 +02:00
fgsfds b78a5ee064 port: implement motion blur and zoom blur 2023-10-16 22:07:41 +02:00
fgsfds ed3bd97dd7 port: when loading GL try 3.0 and 3.2 core as well 2023-10-05 18:20:37 +02:00
fgsfds d3d313c9e8 Merge pull request #194 from rafccq/port
bug fix: incorrect RGBA values for some embedded textures
2023-10-04 10:53:40 +02:00
Raf 8bb847508f Merge remote-tracking branch 'base/port' into port 2023-10-03 21:14:48 +08:00
fgsfds 63b38e48ba port: actually use RumbleScale 2023-10-03 11:03:27 +02:00
Raf e8cb7e4136 Merge remote-tracking branch 'base/port' into port 2023-10-02 01:48:49 +08:00
fgsfds 8a71ff651a port: correct aspect ratio of combat scenario-specific timers 2023-10-01 17:33:37 +02:00
Raf 4c201ef3ff Merge remote-tracking branch 'base/port' into port 2023-10-01 23:05:07 +08:00
fgsfds 0278458a28 port: fix #193 2023-10-01 16:22:51 +02:00
Raf 3b4600d0af bug fix: incorrect RGBA values for some embedded textures
fixes blue muzzle flash from Investigation and Crash Site drone guns
2023-10-01 21:58:27 +08:00
fgsfds 50e3393951 Update README.md 2023-09-30 19:09:12 +02:00
fgsfds 72fa10634f Merge pull request #191 from TwitchBronBron/patch-1
Improve windows build instructions
2023-09-30 19:08:13 +02:00
Bronley Plumb e6a852ea8b Update README.md
fix numbers in list
2023-09-30 12:37:41 -04:00
Bronley Plumb 603a879bdf Update README.md
Add a note.
Remove lots of stuff that wasn't actually necessary.
2023-09-30 12:36:55 -04:00
Bronley Plumb 94221e2c62 Improve windows build instructions 2023-09-30 12:13:49 -04:00
fgsfds 28837dd034 port: different fix for chrAlertOthersOfInjury crash 2023-09-30 14:17:47 +02:00
fgsfds 9a7e9c9ee3 port: small fixes for previous commit 2023-09-30 14:05:53 +02:00
fgsfds 608b02d363 Merge pull request #188 from NeonNyan/ammenu-abs
hack: cp `inputMouseGetScaled -> inputMouseGetScaledDeltaAbsSens` for intuitive amenu UX while using aim inversion
2023-09-30 12:41:49 +02:00
Catherine Reprobate 940ba8c4c0 fixup: Use the float abs function 2023-09-29 17:29:08 -07:00
Catherine Reprobate b0c6e79329 hack: cp inputMouseGetScaledDeltaAbsSens for ammenu 2023-09-28 23:00:07 -07:00
fgsfds 86ed199054 port: fix external seg loading 2023-09-28 09:05:11 +02:00
fgsfds 466c77362e port: mod: add support for sequence replacements 2023-09-28 00:55:14 +02:00
fgsfds 8a342a0698 port: mod: add a dumb replacement system for individual textures and animations 2023-09-27 23:42:47 +02:00
fgsfds 75b0d2dd29 port: modconfig: allow defining the alarm sound and extra gunmem size 2023-09-27 20:19:09 +02:00
fgsfds 704015deac port: modconfig: add user defined extended weather config
includes a way to specify weatherproof rooms and other hardcoded stuff

this might break something, as it removes some hardcoded checks
2023-09-27 19:44:51 +02:00
fgsfds d98575d77b port: add basic mod directory support with config files for custom stages
select mod directory with --moddir whatever

these should contain a modconfig.txt that can specify replacements for some stage table fields, etc
2023-09-26 23:05:07 +02:00
fgsfds 9b17aaf258 port: gl: add ARB_vertex_array_object
for those #ifdef APPLE parts
2023-09-26 15:29:59 +02:00
fgsfds 4638af52e2 port: gl: don't die without fbo support 2023-09-26 15:28:43 +02:00
fgsfds 8aa1e6b9c9 port: gl: check for GL_MIRROR_CLAMP_TO_EDGE; cleanup 2023-09-26 15:01:49 +02:00
fgsfds c4e0e4f868 port: more GL error checking 2023-09-26 14:49:14 +02:00
fgsfds 85b2ba5f77 port: cap pad size
this is required for some custom levels that have pads with wrong flags
2023-09-25 01:39:01 +02:00
fgsfds ef090a2b8f port: properly get size from external files 2023-09-25 01:39:01 +02:00
fgsfds d1d11b9362 port: fix alreadySwapped
how the fuck did this work fine before?
2023-09-25 01:39:00 +02:00
fgsfds ee4434eb6c Merge pull request #181 from jonaeru/enable-combatknife-jp
Add the combat knife in jpn-final
2023-09-24 19:40:10 +02:00
Jonaeru 9d2957c419 Add the combat knife in jpn-final, fix conditions 2023-09-24 22:07:53 +09:00
Jonaeru e606a58515 Add the combat knife in jpn-final, fix #if 2023-09-24 21:58:08 +09:00
fgsfds d303971c2d Revert "port: use system trig functions"
apparently this only causes issues, though it might be possible to use SOME trig functions from libc
2023-09-24 11:47:14 +02:00
fgsfds bd113a5b44 port: nicer GL debug output
now only enabled if you pass --debug-gl
2023-09-24 00:41:57 +02:00
Jonaeru 99337e8157 Add the combat knife in jpn-final 2023-09-24 01:30:11 +09:00
fgsfds dad5b3c074 port: use system trig functions
this might cause different behavior from the N64 version or it might fix some issues, who knows
2023-09-23 13:18:51 +02:00
fgsfds 7d5f33d033 port: fix surfacetypes in g_Textures 2023-09-22 21:26:02 +02:00
fgsfds 54842f50db port: another UB fix in bg.c 2023-09-22 21:06:32 +02:00
fgsfds 5ae29afdeb port: fix some pointer ub in bg.c 2023-09-22 20:52:31 +02:00
fgsfds 8a62b884cc port: make crosshair sway resolution independent
this might suck
2023-09-22 20:37:52 +02:00
fgsfds ca8851789a port: add centered HUD mode
set Game.CenterHUD=1 in pd.ini to enable
2023-09-22 20:26:32 +02:00
fgsfds 205032c626 Merge pull request #176 from rafccq/port
bug fix: hoverbike jittering
2023-09-22 20:13:59 +02:00
Raf f0842337e1 Merge remote-tracking branch 'base/port' into port 2023-09-20 18:37:36 +08:00
fgsfds b2cb5c1737 tools: assetmgr: move --raw-out into a separate function 2023-09-20 11:19:36 +02:00
fgsfds eef42a1e3e tools: assetmgr: allow writing raw binary instead of ELF; fix zip() on windows
use --raw-out filename to get the raw output (zipped if applicable)
2023-09-20 10:58:19 +02:00
fgsfds 53ff42836c tools: rarezip: use system gzip on non-linux 2023-09-20 10:36:21 +02:00
Raf e92f556cf9 bug fix: hoverbike jittering - also remove redundant condition from hovUpdateGround() 2023-09-19 04:07:28 +08:00
Raf 13a6cc1c28 bug fix: hoverbike jittering - revert changes to frametimeCalculate() 2023-09-19 03:12:30 +08:00
Raf 89a3377456 bug fix: hoverbike jittering - forgot to remove a term from the expression 2023-09-19 01:13:29 +08:00
Raf 053d6172e5 bug fix: hoverbike jittering 2023-09-19 00:59:09 +08:00
fgsfds 31bb7c62ad port: add scanline effects for NV and IR goggles and slayer 2023-09-17 23:53:12 +02:00
fgsfds c3f572f016 port: recreate infiltration camera effects
using newly added modulation blending and noise
2023-09-17 23:34:02 +02:00
fgsfds 309aff78fe Merge pull request #171 from Phnod/enhancement/auto-switch-classic-weapons
Add classic weapons to auto-switch list
2023-09-16 12:41:44 +02:00
fgsfds 8553c788ab port: disable reverse pitch and lookahead by default 2023-09-15 21:08:04 +02:00
fgsfds d567f707cb port: fix #170 2023-09-15 20:59:48 +02:00
fgsfds 6686221029 port: fix #169 2023-09-15 20:53:06 +02:00
fgsfds 3ee473d909 Revert "port: fall back to copy if a zipped file is not zipped"
This reverts commit 233f4b7514.
2023-09-15 20:38:58 +02:00
fgsfds 2010d31f6b Revert "port: fix error message in previous commit"
This reverts commit ae2d463d7e.
2023-09-15 20:38:37 +02:00
fgsfds ae2d463d7e port: fix error message in previous commit 2023-09-15 20:32:31 +02:00
fgsfds 233f4b7514 port: fall back to copy if a zipped file is not zipped 2023-09-15 20:31:24 +02:00
fgsfds 6a1b0a474c port: allow specifying path to eeprom file
--eeprom-file file.bin
2023-09-14 21:35:05 +02:00
fgsfds 78ff5683ce port: make the reverse pitch option affect mouselook 2023-09-14 20:41:19 +02:00
fgsfds 53e881b75e port: support loading/saving from/to a directory in HOME or APPDATA
~/.local/share/perfectdark on Linux

AppData/Roaming/perfectdark on Windows

on Windows if the game has write access to the working directory it will save there by default, otherwise it will save to AppData

on Linux the game will save to the working directory if there is already a config there, otherwise it will save to ~

additionally the ROM/data files will be loaded from wherever they're found, working directory taking priority
2023-09-13 20:36:42 +02:00
fgsfds fff2fcae21 port: don't increment module refcount when getting base address 2023-09-12 23:28:30 +02:00
fgsfds a68a23d1cb port: print module base in crash message 2023-09-12 23:24:23 +02:00
fgsfds cb1e1e5dca port: fix #163 2023-09-12 17:34:34 +02:00
Phnod 3b09cb3fae Add classic weapons to auto-switch list 2023-09-11 18:45:33 -04:00
fgsfds c10050a14c port: jpn-final: possibly fix japanese characters 2023-09-11 18:32:09 +02:00
fgsfds f8ef6939b0 port: roll back to old variant of #76 2023-09-08 22:28:19 +02:00
fgsfds 52854b6502 port: fix #139 2023-09-08 15:47:24 +02:00
fgsfds fe5d1dd152 port: fix #158 2023-09-08 15:09:05 +02:00
fgsfds 180e62d597 port: cosmetics 2023-09-08 14:37:44 +02:00
fgsfds 4870641d38 Merge pull request #126 from Phnod/zoom-hud-fov
Zoom HUD fov fix and zoom fov config option
2023-09-08 13:00:14 +02:00
fgsfds 33e2f15f49 Merge pull request #121 from rafccq/port
Bug fix: double reload
2023-09-08 12:59:32 +02:00
fgsfds cf51f09826 Merge pull request #160 from tmyqlfpir/port
Fix random five scenario using classic weapons for last slot
2023-09-08 12:59:21 +02:00
tmyqlfpir 8a75774506 Fix comment typo
Introduced in commit 920c0eada5
2023-09-08 20:40:58 +10:00
tmyqlfpir 7e8c57ee4d Fix random five scenario using classic weapons for last slot 2023-09-08 20:25:30 +10:00
Raf 84331c4d08 Bug fix: double reload, new approach
Reverted the previous changes, no longer necessary
2023-09-05 22:27:24 +08:00
Raf ceac1be026 Merge remote-tracking branch 'base/port' into port 2023-09-05 21:44:26 +08:00
fgsfds 892d50ba7c port: revert #134 for now
there must be a different solution for that problem
2023-09-05 11:45:12 +02:00
Raf c08d8b6bcb Merge remote-tracking branch 'base/port' into port 2023-09-05 04:40:45 +08:00
fgsfds dde656c4c3 port: fix typo 2023-09-04 21:47:42 +02:00
fgsfds 2d628e2b5a Merge pull request #134 from Phnod/fix/guard-line-of-sight
fix: return false in chrHasLosToPosWasteful if outside FOV check
2023-09-04 21:46:52 +02:00
fgsfds d7652a6db6 port: remove stray field in TextureCacheKey 2023-09-04 21:10:20 +02:00
fgsfds 491d3521f7 port: different names for pal and jpn EXEs 2023-09-04 21:06:49 +02:00
fgsfds d6854c412c port: allow building with pal-final and jpn-final
this will produce a separate executable that will load pd.pal-final.z64 or pd.jpn-final.z64, respectively

japanese characters are broken in jpn and pal crashes when you try to select language, so no autobuilds yet
2023-09-04 21:06:10 +02:00
fgsfds 110386a3dd tools: mklang: explicitly specify utf-8 2023-09-04 21:02:50 +02:00
Phnod 7d96cd8fbd Merge branch 'port' of https://github.com/Phnod/perfect_dark into zoom-hud-fov
# Conflicts:
#	port/src/main.c
#	src/include/data.h
2023-09-03 15:39:46 -04:00
fgsfds 840a2e73a5 port: implement screen shake 2023-09-03 19:12:29 +02:00
Phnod d033a7fa02 Merge branch 'port' of https://github.com/Phnod/perfect_dark into zoom-hud-fov
# Conflicts:
#	src/include/data.h
2023-09-02 19:05:12 -04:00
fgsfds 07c3a513ef port: generalize the texture font filter a bit
now called TextureFilter2D; although for now I couldn't find anything other than fonts to use it on
2023-09-03 00:36:27 +02:00
fgsfds 18b467a4d8 Merge pull request #127 from Phnod/font-filtering
port: add a config option to disable texture filtering on fonts
2023-09-03 00:22:06 +02:00
fgsfds ff8505c013 Merge pull request #130 from Phnod/rotated-text-cutoff-fix
fix: remove height trim on rotated text
2023-09-03 00:19:06 +02:00
fgsfds 7207bb6293 Merge pull request #137 from NeonNyan/pc-ab
Use XBox / PC Menu A/B semantics
2023-09-02 23:21:30 +02:00
Catherine Reprobate 0d6a62ada0 Use XBox / PC Menu A/B semantics
Fixes #110
2023-09-02 13:28:21 -07:00
fgsfds 721c27c329 port: add exit option to 4mb menu 2023-09-02 22:05:33 +02:00
Raf 488198b7da Merge remote-tracking branch 'base/port' into port 2023-09-03 02:45:19 +08:00
fgsfds 702db43590 port: workarounds for some sky issues 2023-09-02 19:35:04 +02:00
Raf d8c5960c80 Merge remote-tracking branch 'base/port' into port 2023-09-02 23:13:48 +08:00
fgsfds 0942f61aff port: possibly fix skyboxes
by just rendering them with normal triangles
2023-09-02 16:18:06 +02:00
Phnod b83604a677 fix: return false in chrHasLosToPosWasteful if outside FOV check 2023-09-02 02:45:40 -04:00
fgsfds 56df5b4054 port: ignore invert pitch setting when mouse aiming 2023-09-01 23:08:52 +02:00
fgsfds cc079e842b port: small crashhandler fix 2 2023-09-01 22:58:45 +02:00
fgsfds 37907dccfc port: small crashhandler fix 2023-09-01 22:49:45 +02:00
fgsfds 701193e71a port: add crash handler
you probably won't get symbol names, but you can still use addr2line
2023-09-01 22:42:44 +02:00
Phnod eff475c498 fix: nudge menu left side text a pixel to the left to counteract extra pixel column 2023-09-01 14:38:17 -04:00
Phnod 5235581e33 fix: remove height trim on rotated text 2023-09-01 13:49:50 -04:00
Raf ec6b6b25a4 Merge remote-tracking branch 'base/port' into port 2023-09-02 00:20:29 +08:00
fgsfds e5e685902c port: don't use G_RM_NOOP2 with non-noop 1cyc modes
this ALMOST fixes sparks and blood splatter
2023-09-01 17:56:00 +02:00
fgsfds b0d97bde89 port: possibly fixed a bunch of textures
at the cost of about 22kb extra memory, how horrifying
2023-09-01 17:55:07 +02:00
Phnod 810db26bf4 fix: undo regression with previous cleanup, horizon scanner previously showed the wrong zoom level relative to FOV change 2023-09-01 10:07:15 -04:00
Phnod 5033c096a2 cleanup: move PLATFORM_N64 preprocessor checks for fov zoom into a separate macro to reduce clutter 2023-09-01 09:48:53 -04:00
Raf 83cfaa5e77 Merge remote-tracking branch 'base/port' into port 2023-09-01 20:44:50 +08:00
fgsfds 29dae044cc port: also disable hi-res and aspect options in 2p pause menu 2023-09-01 12:45:05 +02:00
Raf 7e83207444 Merge remote-tracking branch 'base/port' into port 2023-09-01 15:59:51 +08:00
fgsfds 9744b2266f port: dummy out hi-res and screen ratio options 2023-09-01 09:22:09 +02:00
Phnod 9eb3ffcc30 port: add a config option to disable texture filtering on fonts 2023-09-01 00:02:47 -04:00
Phnod 917209cb65 fix: remove +1 from horizon scanner's displayed zoom level to show the accurate zoom level
Previously the display would instantly jump from 1.00x to 2.01x, and show 31.00x instead of 30.00 at the max zoom level
2023-08-31 21:31:31 -04:00
Phnod 0bf57ddd48 fix: apply FovAffectsZoom to horizon scanner zoom 2023-08-31 21:26:00 -04:00
Phnod fb009ae52f fix: allow dynamic zoom weapons to fully zoom out to 1x zoom 2023-08-31 20:58:33 -04:00
Phnod 2a5160c519 cleanup: move repetitive zoom fov logic to single multiplier value 2023-08-31 20:39:30 -04:00
Phnod 349b502149 port: apply FovAffectsZoom to Farsight's secondary fire mode 2023-08-31 20:39:30 -04:00
Phnod 1c1164d9e8 port: apply FovAffectsZoom changes to max zoom level for sniper, farsight and horizon scanner 2023-08-31 20:39:29 -04:00
Phnod 35386bbd2c port: modify default zoom level for dynamic zoom weapons if fovzoom ini option is enabled
This affects the Sniper Rifle, Farsight, and Horizon Scanner
2023-08-31 20:39:29 -04:00
Phnod 96bd8e05aa port: add ini config parameter to control whether ini FOV change should affect the max zoom of weapons 2023-08-31 20:39:29 -04:00
Phnod 85c1adb258 port: adjust max zoom range by FOV ini value 2023-08-31 20:39:29 -04:00
Phnod e540a42c9c port: modify zoom range hud to use player FOV 2023-08-31 20:39:29 -04:00
Raf 93ff313237 Merge remote-tracking branch 'base/port' into port 2023-09-01 01:05:42 +08:00
fgsfds 60e2118001 Merge pull request #114 from iamgreaser/gm/ubfix-0001
Fix a few cases of UB incl. OoB
2023-08-31 18:29:38 +02:00
Raf 49963c2e47 Merge remote-tracking branch 'base/port' into port 2023-08-31 20:07:43 +08:00
fgsfds e883144a76 port: fix texformat errors 2023-08-31 13:00:04 +02:00
fgsfds b6a3aef345 port: add logging and some command line args
--log: logs messages to pd.log

--boot-stage N: sets initial stage number to N (MP stages will crash or hang if booted like this)

--no-sound: disable sound

--rom-file S: set ROM filename
2023-08-31 12:54:18 +02:00
Raf b49cc250e0 Merge remote-tracking branch 'base/port' into port 2023-08-31 17:53:17 +08:00
fgsfds 2e49ba10dd port: aspect correct radial menu 2023-08-31 10:36:21 +02:00
Raf 4042fb3a62 Bug fix: double reload 2023-08-31 14:29:29 +08:00
fgsfds 24ced381de port: add separate mouse aim sensitivity
Game.MouseAimSpeedX and Game.MouseAimSpeedY
2023-08-31 01:21:33 +02:00
fgsfds e265482cb4 port: more widescreen HUD hacks 2023-08-31 00:55:17 +02:00
fgsfds ba8346edb7 port: experimental hack for proper 16:9 HUD
might or might not be more convenient than editing all offsets
2023-08-31 00:45:18 +02:00
fgsfds 600f261dcb port: don't crash silently on GL errors 2023-08-30 18:19:54 +02:00
fgsfds 14efaee388 port: add wide rect commands; fix crosshair spazzing out on screen borders
if you're building manually, this change requires a clean rebuild
2023-08-30 17:21:13 +02:00
fgsfds 687682cab0 port: fix gamepad aiming with MOUSEAIM_CLASSIC
also uninvert Y when moving the camera with it
2023-08-30 16:10:42 +02:00
fgsfds c3b4d59168 port: add 1964GEPD-like mouse aim mode
you can switch to the old variant by setting Game.MouseAimMode to 1 in pd.ini
2023-08-30 15:28:33 +02:00
fgsfds 970e13773d port: remove unused fileSlots array 2023-08-30 12:45:39 +02:00
fgsfds af1422a1de port: move CrosshairSway and FovY to the [Game] ini section
fov doesn't really belong in the video functions either
2023-08-30 12:31:27 +02:00
fgsfds 4947350230 Merge pull request #70 from squiddingme/crosshair
Config option to control crosshair/gun sway
2023-08-30 12:15:57 +02:00
fgsfds e29e20e779 port: small cleanup; decrease bigfont height to 26
this avoids scrolling in the main menu; will probably also help with the extended options later
2023-08-30 12:14:18 +02:00
fgsfds 3490f1d7ae Merge pull request #104 from kronflux/port
Add an exit option to main menu
2023-08-30 12:03:20 +02:00
fgsfds d39d7fb1f5 port: small cleanup 2023-08-30 12:02:24 +02:00
fgsfds 8b3b684675 Merge pull request #108 from rafccq/port
enable using mouse on the radial menu
2023-08-30 12:00:27 +02:00
Richard M 630b236ac0 Merge branch 'fgsfdsfgs:port' into port 2023-08-30 01:10:15 -06:00
Raf 5bb7cb47aa Merge remote-tracking branch 'base/port' into port 2023-08-29 20:07:59 +08:00
fgsfds 7d152b37ad Merge branch 'master' of https://github.com/n64decomp/perfect_dark into port 2023-08-29 14:00:48 +02:00
Ryan Dwyer 0235a971d6 Fix bot name array overflow 2023-08-29 21:36:58 +10:00
Raf bb9bb83202 Merge remote-tracking branch 'base/port' into port 2023-08-29 19:33:51 +08:00
Raf 1a7458a290 fix whitespace issues 2023-08-29 16:26:33 +08:00
fgsfds 00decf3347 port: wrap previous change in #ifdef AVOID_UB 2023-08-29 10:16:51 +02:00
fgsfds 6e1df743d0 Merge pull request #116 from AXDOOMER/port
Fix buffer overflow in creditsResetSlides
2023-08-29 10:15:02 +02:00
fgsfds c54a768b19 port: fix #117 and other related OOB writes 2023-08-29 10:09:46 +02:00
Richard M 250e9b1805 Merge branch 'fgsfdsfgs:port' into port 2023-08-29 00:44:46 -06:00
GreaseMonkey 43a91b2b4b Fix "mpindex=4" UB cases for various view gadgets 2023-08-29 13:15:42 +12:00
Alexandre-Xavier e4742bcafb Fix array out of bound in decoder.c 2023-08-29 01:07:44 +00:00
Alexandre-Xavier Labonté-Lamoureux 21f3dee554 Fix buffer overflow in creditsResetSlides 2023-08-28 19:45:50 -04:00
GreaseMonkey 889ae950fe Fix a few cases of UB incl. OoB
Behaviour should be mostly the same but there are some OoB accesses in the menu code where I've had to assume things.

Tests for each OoB case:

- Accessing of layer -1: Select a game file in the "Choose Your Reality" screen.
- Accessing of menu for the 5th player: Die in a mission.
2023-08-29 10:23:14 +12:00
Raf 272b28b6a9 attempt to fix whitespace issues 2023-08-29 02:53:17 +08:00
Raf 9a259acefa enable using mouse on the radial menu: removed unused constants 2023-08-29 02:41:11 +08:00
Raf 92392da6fe enable using mouse on the radial menu: reworked
mouse+kb and other input devices are no longer exclusive when using the radial menu
2023-08-29 02:39:16 +08:00
Raf 0f6920a3f1 Merge branch 'base-port' into port 2023-08-28 23:55:15 +08:00
fgsfds d2574c4b49 port: fix RGB555 textures in Grid
fix submitted by Ryan
2023-08-28 16:02:37 +02:00
fgsfds 0e5b4bde62 Merge branch 'master' of https://github.com/n64decomp/perfect_dark into port 2023-08-28 15:55:54 +02:00
fgsfds 916d147619 port: skip detail textures
this fixes the carpet in Defection and maybe other places, but means that detail textures are broken for now
2023-08-28 15:03:51 +02:00
Ryan Dwyer 4f56cd4c09 Set names for symbols relating to the gfx C0 command 2023-08-28 22:18:05 +10:00
Raf ab17a995a4 enable using mouse on the radial menu 2023-08-28 04:50:26 +08:00
squiddingme 3f562c3009 Add config option to control crosshair/gun sway 2023-08-28 02:40:50 +08:00
fgsfds 66443dd2c2 port: don't explode when EEPROM can't be saved or loaded 2023-08-27 17:49:27 +02:00
fgsfds 89849bc805 port: read keybinds from config file 2023-08-27 17:26:57 +02:00
fgsfds 4fef14f9fc port: rework config system
it is no longer required to specify all possible config keys in config.c, you can just use configGet/Set
2023-08-27 17:26:46 +02:00
fgsfds dce1f5492f Update README.md 2023-08-27 13:33:41 +02:00
Ryan Dwyer 0b1aabf345 Set names for a heap of shotdata symbols 2023-08-27 21:27:53 +10:00
fgsfds 57b6247a65 Update README.md 2023-08-27 13:22:59 +02:00
fgsfds 9529a991ef Merge pull request #68 from NeonNyan/controller-buttons
Multiple input updates
2023-08-27 13:06:16 +02:00
fgsfds 1f49665c05 Merge pull request #103 from iamgreaser/gm/fix-choppy-audio-at-non-60fps
Fix choppy audio at sub-60fps framerates
2023-08-27 12:49:54 +02:00
Richard M 0f73ab889f port: add an exit option to main menu
In Fullscreen there is currently no way to close the game without using Alt+F4. This adds an option "Exit" to the Main Menu, which asks to confirm before performing exit.
2023-08-27 04:16:51 -06:00
Catherine Reprobate aa8e08e4d0 Update readme 2023-08-26 18:35:07 -07:00
Catherine Reprobate 2a78f6902d handle b button differently if N64 platform 2023-08-26 17:56:36 -07:00
fgsfds 558875c91c port: fix the RGBA4/8 hack
this fixes the door hinge thing textures in CI
2023-08-27 02:17:30 +02:00
Catherine Reprobate 8ec0feb49b fix: grabbable 2023-08-26 17:16:41 -07:00
GreaseMonkey 5b0874daef Fix choppy audio at sub-60fps framerates 2023-08-27 12:12:21 +12:00
Catherine Reprobate df8c1139a1 fix: sniper crouching 2023-08-26 16:27:41 -07:00
Catherine Reprobate 0d7bd746ac move abstracted n64 buttons to contants.h 2023-08-26 16:17:54 -07:00
Catherine Reprobate e95c7f144e fixes AB remote detonation 2023-08-26 16:14:43 -07:00
Catherine Reprobate 10844e7a52 fixup controller use buttons 2023-08-26 16:14:43 -07:00
Catherine Reprobate 077a091f7d fixup camspy bindings 2023-08-26 16:14:43 -07:00
Catherine Reprobate f88493870a Address multiple extended input nits
- Q for radial menu
- mapped remaining xbla buttons, but the menus follow switch controller handfeel
- based on @Phnod's switch-weapons PR: https://github.com/fgsfdsfgs/perfect_dark/pull/57
2023-08-26 16:14:43 -07:00
Catherine Reprobate 3f6f0b3f9c map sensible xbox inputs
xbox A is mapped to n64 B for using items
n64 A is unmapped for controller.

When radial / weapon switching is mapped way from n64 A n64 A can be
remapped as a cancel button .
Trigger will need to be used for the menus until
2023-08-26 16:14:43 -07:00
Phnod 5a0580005f Added scrollwheel weapon swapping 2023-08-26 16:14:43 -07:00
fgsfds 1439f8bbeb Merge pull request #76 from tmyqlfpir/mp-classic-weapons
Allow classic weapons to be used in multiplayer
2023-08-26 20:49:44 +02:00
fgsfds bf8277fb2c port: re-disable GBI_FLOATS
some more matrices need fixing I guess
2023-08-26 15:59:43 +02:00
fgsfds d9c974fc00 port: set default optimization level to -Og 2023-08-26 14:49:37 +02:00
fgsfds 23dfc05511 port: enable GBI_FLOATS by default
seems like it works fine
2023-08-26 14:49:07 +02:00
fgsfds 4d9a41bc76 port: (possibly) make the laser scale better with the bigger distance 2023-08-26 14:23:22 +02:00
fgsfds db0059e0f0 port: infinitely shooting guard fix from 1964GEPD 2023-08-26 14:08:20 +02:00
fgsfds 2b27c2dc6a port: make matrices work with GBI_FLOATS
add GBI_FLOATS=1 to DEFINES to enable it

not enabling by default yet because not sure if it'll break anything
2023-08-26 13:49:23 +02:00
fgsfds 85e914c129 Merge pull request #94 from MaikelChan/credits_texts
Fixed credits texts with wrong UVs.
2023-08-26 13:31:20 +02:00
MaikelChan 5710b2a7dd Fixed credits texts with wrong UVs. 2023-08-26 13:24:42 +02:00
fgsfds 844139b339 port: restart currently playing MP3 when needed
there's probably a way to determine reset condition without adding an extra field to g_Mp3Vars, but I can't be arsed to figure it out
2023-08-26 10:34:35 +02:00
Ryan Dwyer 79a94b29ce Name some texture symbols, mostly relating to LODs 2023-08-26 12:20:04 +10:00
tmyqlfpir d03617d682 Add classic weapons to multiplayer 2023-08-26 11:09:58 +10:00
fgsfds 8494e29075 Merge pull request #90 from Phnod/laser-sight-distance
Increase Falcon laser fade out distance
2023-08-25 20:59:20 +02:00
fgsfds d229ba2405 port: somewhat fix the health display at different FOVs 2023-08-25 20:56:17 +02:00
fgsfds 4ab1e08129 port: make sun and light glares use LOS checks
this partially fixes them, but there are still problems to iron out
2023-08-25 17:18:02 +02:00
Phnod 4255867f29 Increase laser fade out distance 2023-08-25 00:39:20 -04:00
fgsfds 87529f37c8 port: use gettimeofday() as timing source; use smaller tick multiplier to avoid overflows 2023-08-24 18:11:14 +02:00
fgsfds caaf82385b port: disable color modulation effects when none are active 2023-08-24 17:53:13 +02:00
fgsfds ffdcdeee9f port: increase slayer sensitivity a bit more 2023-08-23 23:02:56 +02:00
fgsfds 0db9e84b58 port: cap slayer rocket sensitivity and make it a bit bigger 2023-08-23 22:47:06 +02:00
fgsfds 82f647299c port: link with -ldl on linux regardless of arch 2023-08-23 22:36:47 +02:00
fgsfds a85a18774f port: implement NVG/IRG color modulation using the grayscale command
still missing the funky overlays
2023-08-22 23:21:55 +02:00
fgsfds 143d2a107a port: save config on exit 2023-08-22 20:37:18 +02:00
fgsfds 47258ebd7f Merge pull request #53 from tmyqlfpir/fix-footsteps-slomo
Fix spamming footsteps for slow mode
2023-08-22 20:30:55 +02:00
fgsfds 095b7540d5 port: fix aspect on menu models 2023-08-22 20:22:25 +02:00
fgsfds e871156301 port: reduce or eliminate portal seams
by slightly extending the portal scissor boxes
2023-08-22 20:09:14 +02:00
fgsfds 35da8e2e67 port: fix animated textures in Attack Ship
patch submitted by Ryan
2023-08-22 19:48:22 +02:00
fgsfds 5d4606d0f6 port: fix #73
patch submitted by Ryan
2023-08-22 19:47:50 +02:00
fgsfds 2533a844a7 port: fix use-after-free when invalidating texcache 2023-08-22 01:35:13 +02:00
fgsfds 62ea74f332 port: turns out rodata comes after texture data 2023-08-22 00:57:27 +02:00
Ryan Dwyer 38345c1672 Set names for menumodel symbols 2023-08-22 08:48:32 +10:00
fgsfds 3a10d47903 port: fix normals 2023-08-22 00:42:36 +02:00
fgsfds 12eeb97e71 port: don't go out of bounds when unswizzling textures
this might still break though, god knows what else is there in the texconfigs
2023-08-22 00:30:41 +02:00
fgsfds 4b1dc93792 Merge pull request #69 from tmyqlfpir/fov-speed-adjustment
Adjust FOV zoom speed when using non-default FOV
2023-08-21 17:11:54 +02:00
tmyqlfpir 5aa8474d2b Adjust FOV zoom speed when using non-default FOV 2023-08-21 18:23:40 +10:00
fgsfds 58e13db613 Update README.md 2023-08-21 01:14:45 +02:00
fgsfds 9e3dd9b6d4 Merge pull request #61 from tmyqlfpir/eyespy-clamp
Limit eyespy range to 75 degrees
2023-08-21 01:12:52 +02:00
fgsfds 81902e1b96 Merge pull request #63 from tmyqlfpir/tweak-pickup-threshold-degrees
Adjust pickup degrees threshold
2023-08-21 00:55:52 +02:00
fgsfds 2670db7ca1 port: add rstick fields to OSContPad 2023-08-21 00:29:51 +02:00
tmyqlfpir bf43f32946 Adjust pickup degrees threshold 2023-08-21 07:45:38 +10:00
tmyqlfpir 4455cfcde1 Limit eyespy range to 75 degrees
Needed due to lack of lookahead
2023-08-21 07:26:01 +10:00
tmyqlfpir 682c0c83a1 Expose LV_SLOMO_TICK_CAP macro in lv.h
Needed for slomo footsteps fix
2023-08-21 06:24:08 +10:00
fgsfds b9944e8669 port: don't crash when swapping empty rooms 2023-08-20 22:20:12 +02:00
fgsfds b4207b3fd9 port: allow theoretical ARM builds
this requires your device to support desktop GL3+ and might require manual setting of the TOOLCHAIN variable
2023-08-20 21:41:04 +02:00
fgsfds 2b6b205a78 port: min supported SDL version should now be 2.0.12 2023-08-20 21:25:06 +02:00
fgsfds 8c6d6df5fc port: be a bit more standard compliant 2023-08-20 19:59:07 +02:00
tmyqlfpir 18ae54f656 Fix footsteps with combat boost 2023-08-21 02:33:11 +10:00
tmyqlfpir f6fb534035 Fix spamming footsteps for slow mode 2023-08-21 01:49:59 +10:00
fgsfds 4b0f2ea439 port: unswizzle pre-swizzled textures 2023-08-20 17:26:11 +02:00
fgsfds 45a81e92f4 Update README.md 2023-08-20 16:51:21 +02:00
fgsfds e0ced73d8a port: fix model lighting 2023-08-20 16:26:21 +02:00
fgsfds f1186a35d8 port: forgot this 2023-08-20 15:48:46 +02:00
fgsfds 933ba8a708 port: swap all portal vertex batches
actually fixes #43

credit to Ryan for the patch
2023-08-20 15:44:01 +02:00
fgsfds bd5d613a24 port: whitespace cleanup 2023-08-20 15:42:40 +02:00
fgsfds 3da1fd4372 Merge pull request #28 from NeonNyan/port
Implement some dedicated buttons for mouse+kb / gamepad
2023-08-20 15:30:39 +02:00
fgsfds d007550adb Merge branch 'port' into port 2023-08-20 15:30:19 +02:00
fgsfds 170f2646e1 Merge pull request #48 from tmyqlfpir/fix-ai-menu-mp
Fix menu crash when issuing order to all bots
2023-08-20 15:28:14 +02:00
fgsfds 207f97a0eb Update README.md 2023-08-20 15:27:34 +02:00
fgsfds 577de9683b Update README.md 2023-08-20 15:26:31 +02:00
tmyqlfpir ec09d4a6ca Use already existing JPN fix 2023-08-20 23:19:59 +10:00
fgsfds 1b04dd8032 Merge pull request #45 from tmyqlfpir/port
Adjust spark scale depending on output resolution
2023-08-20 15:15:43 +02:00
fgsfds 24bfac89ae Merge pull request #46 from tmyqlfpir/force-anim-lerp
Always interpolate character animations
2023-08-20 15:15:00 +02:00
fgsfds 2a5594d7d5 Merge pull request #47 from tmyqlfpir/no-lods
Don't draw LODs for port
2023-08-20 15:14:33 +02:00
fgsfds 44c8b024b0 Merge pull request #49 from tmyqlfpir/skedar-door-rate-limit
Rate limit stuckage RNG for skedar doors
2023-08-20 15:13:40 +02:00
fgsfds 9acd05f16c port: allocate room data from system heap
props to Ryan for the patch
2023-08-20 15:12:09 +02:00
fgsfds 7e71450a76 port: wrap malloc & co
in case we'll need allocation stats or something later
2023-08-20 14:56:07 +02:00
fgsfds 6fbb7e39ec Merge branch 'master' of https://github.com/n64decomp/perfect_dark into port 2023-08-20 14:41:57 +02:00
tmyqlfpir 920c0eada5 Rate limit stuckage RNG for skedar doors
Limits calculation to 15 times per second, close to that to how fast this would execute on original hardware
2023-08-20 21:38:38 +10:00
tmyqlfpir 97c1b13370 Decrease spark scale
Uses hires resolution as multiplication factor
2023-08-20 20:58:16 +10:00
tmyqlfpir 47d4e4f659 Fix menu crash when issuing order to all bots 2023-08-20 20:33:52 +10:00
tmyqlfpir 97258542be Don't draw LODs for port 2023-08-20 20:08:19 +10:00
tmyqlfpir 908aa3556e Always interpolate chr animation
Ignores distance check for pc port
2023-08-20 17:33:17 +10:00
Catherine Reprobate 93679e62e8 tested with xbox one controller
map implemented buttons to xbla positions

map radial menu to middle the mouse button
2023-08-20 00:00:00 -07:00
Ryan Dwyer 09edfb8545 Fix some global data placement issues 2023-08-20 16:48:35 +10:00
Ryan Dwyer d7926f12ad Fix incorrect rounding in C version of sinf 2023-08-20 16:34:38 +10:00
Ryan Dwyer e18167d8ae Fix C version of portalConvertCoordinates 2023-08-20 12:49:21 +10:00
Catherine Reprobate c3dc838acb F to crouch w/ sniper
F to crouch with sniper
F + Z to crouch with sniper
2023-08-19 14:47:43 -07:00
fgsfds 7e26e6eac0 port: disable zbufClear to prevent white flashing in splitscreen 2023-08-19 18:24:33 +02:00
fgsfds 0c80abf5b9 port: ignore scissor test in resolve_msaa_color_buffer 2023-08-19 18:02:24 +02:00
fgsfds a7692fe4ef port: add MSAA setting 2023-08-19 17:50:31 +02:00
fgsfds 05233ef853 port: fix slomo
for different framerates hopefully we'll just have to redefine TICKS
2023-08-19 16:13:02 +02:00
fgsfds 8232d4a3f2 port: fix #23
credit to Ryan for figuring this out
2023-08-19 15:45:16 +02:00
fgsfds e6a4b9f2fe port: small clean up in gfx_pc 2023-08-19 15:38:16 +02:00
fgsfds 67c4531771 port: add stick scale config setting; better (?) deadzone 2023-08-19 15:18:15 +02:00
fgsfds 6f3f48d1e9 port: disable camspy lookahead 2023-08-19 14:21:33 +02:00
fgsfds b7f77498b3 port: disable height-based sensitivity multipliers 2023-08-19 14:17:53 +02:00
fgsfds 8d26944642 port: three-point does not need GL_LINEAR 2023-08-19 13:57:44 +02:00
fgsfds 2f54ceb96e port: add texture filter setting 2023-08-19 13:56:15 +02:00
fgsfds 63a5701906 port: fix mouse sensitivity at different FOVs/in zoom 2023-08-19 13:36:58 +02:00
fgsfds 41cdef055e port: allow keyboard to act as a separate controller
also add a way to fake controller connection status for testing
2023-08-19 12:13:23 +02:00
fgsfds 420053178e Merge branch 'master' of https://github.com/n64decomp/perfect_dark into port 2023-08-19 11:45:17 +02:00
fgsfds 412dcd7736 port: fix blur in hires mode 2023-08-19 11:43:18 +02:00
Ryan Dwyer d7c94b4d04 Fix UB in modelasm chrinfo handler 2023-08-19 19:14:10 +10:00
Ryan Dwyer 032c5166f4 Fix improper casting of model rwdata 2023-08-19 19:01:00 +10:00
fgsfds 4e42e3ef82 port: mouse wheel binds; handle adding and removing controllers 2023-08-19 02:16:58 +02:00
Catherine Reprobate a71c7cbba2 Merge branch 'fgsfdsfgs:port' into port 2023-08-18 16:39:44 -07:00
Catherine Reprobate 781fbcddd4 fixup bindings:
F and G will switch modes and bringup the radial menu
2023-08-18 16:37:41 -07:00
fgsfds 1d151f2864 port: implement some framebuffer effects
cloaking and menu blur

in a likely extremely slow way
2023-08-19 00:48:09 +02:00
Catherine Reprobate ffae4540f9 dedicated radial menu mapped to D_JPAD 2023-08-18 14:34:58 -07:00
Catherine Reprobate 25b5f66e6b map L_TRIG to alt button
- switches immediately when releases L
- or whenevever L+Z is pressed. Will switch back when L is released.
2023-08-18 14:32:08 -07:00
Catherine Reprobate 68c00af44e Mapped reload to X_BUTTON.
Introduce `JO_ACTION*` constants to use `player.bondreloadoractivate` as a bit
field.

Deviation from vanilla Mouse Injector behavior: hard seperation between
reload and activate. `B` will not reload just as `ALT1` will not
activate.
2023-08-18 14:09:45 -07:00
Catherine Reprobate 12571746d7 Unmap L_TRIG and *_JPAD 2023-08-18 13:59:13 -07:00
fgsfds d90504675f port: this is not necessary at all 2023-08-18 17:24:18 +02:00
fgsfds 249041764b port: add adjustable fov 2023-08-18 17:18:56 +02:00
fgsfds 554fde7a9d port: fix rumble 2023-08-18 15:34:13 +02:00
fgsfds a49bfd00a4 port: add mouse controls to eyespy and slayer 2023-08-18 14:47:08 +02:00
fgsfds bc4c08fe2f port: only player 1 gets mouselook and only when aiming is allowed 2023-08-18 13:58:33 +02:00
fgsfds b906f77b37 port: added rumble scale and support for 2 extra buttons
also fixed some warnings
2023-08-18 12:26:55 +02:00
fgsfds e1f6e167fb Update README.md 2023-08-16 15:43:19 +02:00
fgsfds 034ff984cc port: fix s32 pointer in bgRenderRoomPass 2023-08-16 14:52:25 +02:00
fgsfds fedcbb8917 Merge branch 'master' of https://github.com/n64decomp/perfect_dark into port 2023-08-16 10:53:02 +02:00
Ryan Dwyer fb5b505bab Untangle menuitemdata structs 2023-08-16 18:34:08 +10:00
Ryan Dwyer f020543599 Use sizeof for setup prop sizes instead of literals 2023-08-16 14:36:34 +10:00
fgsfds 7a4edd6ef7 port: fix SHADE_ALPHA with fog again 2023-08-16 02:15:04 +02:00
fgsfds 2b5e136cc0 port: fix #15 and menu sliders in general 2023-08-16 02:13:58 +02:00
fgsfds ab4d595904 port: fix #14
patch courtesy of Ryan
2023-08-16 00:28:20 +02:00
fgsfds b1247b5eac port: purge texcache when gunmem is released as well 2023-08-16 00:19:53 +02:00
fgsfds bed505fd91 port: get rid of __builtin_trap 2023-08-15 23:33:55 +02:00
fgsfds ffea7cd65a port: reset texcache on level change 2023-08-15 23:33:25 +02:00
fgsfds 8600aead20 port: close config after reading it 2023-08-15 22:00:39 +02:00
fgsfds f48879653a port: forgot this 2023-08-15 21:57:34 +02:00
fgsfds 0c01ab76cf port: add simple config file
includes an option to disable vsync and enable cpu-side frame limiter
2023-08-15 21:45:23 +02:00
fgsfds 1eb30b28e1 port: don't shove headers into the link command line 2023-08-15 21:35:09 +02:00
fgsfds 6a749bdae5 port: temporary fix for explosion texture colors 2023-08-15 17:49:09 +02:00
fgsfds 9aa15c6fbb Merge pull request #12 from MaikelChan/menu_rendering
Fixed flipped texts and menu elements that were beyond the near clip plane
2023-08-15 16:43:31 +02:00
fgsfds 8aa8d61bb8 Merge branch 'master' of https://github.com/n64decomp/perfect_dark into port
this fixes collision bugs related to moving objects and rotation of a lot of stuff
2023-08-15 16:16:18 +02:00
Ryan Dwyer 24657743ff Fix mtx3Copy in C translation 2023-08-15 22:28:11 +10:00
MaikelChan 6f35e00c16 Fixed flipped texts and menu elements that were beyond the near clip plane. 2023-08-15 05:05:53 +02:00
fgsfds 20fd3a8f67 port: make alt-enter go into fullscreen 2023-08-15 01:06:14 +02:00
fgsfds 7666ccf2c7 port: fix muzzle flashes on some guns 2023-08-15 00:49:35 +02:00
fgsfds 0cc29d2c99 port: fix healthbar rendering 2023-08-15 00:16:25 +02:00
fgsfds 1b1222494e port: move game viewport init to gfx_init() 2023-08-14 22:07:36 +02:00
fgsfds 94c3dfe51e port: fixup aspect ratio on the 3d parts of the title sequence 2023-08-14 22:07:16 +02:00
fgsfds 58d93cb083 port: hackfix psychosis gun crash 2023-08-14 19:43:05 +02:00
fgsfds f5bcc25e10 port: fix textureconfig-related texture corruption
explosions are still miscolored, but no longer garbage
2023-08-14 18:30:02 +02:00
fgsfds a31e2209c5 port: fix firing range
props to Ryan again
2023-08-14 17:53:08 +02:00
fgsfds 4d52a8e476 port: scale gun swivel only when mouse aiming 2023-08-14 17:42:48 +02:00
fgsfds c3fb50c358 port; refactor widescreen PR a bit
abstract aspect into a video* function

re-add gun swivel, but make it slower on hi res
2023-08-14 17:39:02 +02:00
fgsfds 65115089af Merge pull request #4 from MaikelChan/aspect_ratio
Sort of implemented arbitrary aspect ratio and mouse movement improvements
2023-08-14 17:24:57 +02:00
fgsfds 48bac90a7b Merge pull request #5 from babbygremlin/port
Fix default control scheme for combat sim
2023-08-14 17:18:35 +02:00
babbygremlin 93a38649f3 Fix default control scheme for combat sim
the default control scheme for new profiles in combat simulations was being set to 1.1 instead of 1.2 this just changes the number, its very tiny
2023-08-14 00:30:30 -07:00
MaikelChan 89c5cfb46b Sort of implemented arbitrary aspect ratio and mouse movement improvements. 2023-08-14 07:20:05 +02:00
fgsfds 51808cd1f8 port: fix a bunch of controller-related bugs
don't completely override kb+m input when a controller is connected (fixes #3)

handle controller disconnection

add adequate default controller binds

add deadzone
2023-08-13 23:18:24 +02:00
fgsfds 758eb77578 port: fix credits crash
campaign is now more or less completable, other than the pushbox collision bug
2023-08-13 22:49:00 +02:00
fgsfds 358f788b61 port: read gbi command id correctly in gfxReplaceGbiCommands 2023-08-13 21:09:04 +02:00
fgsfds e0d4bf44b8 port: read command ids correctly when rendering in xray mode 2023-08-13 21:04:00 +02:00
fgsfds 7ec10febae port: swap intro commands properly 2023-08-13 20:30:28 +02:00
fgsfds 8acd495e91 port: revert the loaded_texture changes
they broke more than they fixed
2023-08-13 20:05:26 +02:00
fgsfds 5f11dd48a2 Revert "port: make the tmem_index allocation a little bit more sane"
This reverts commit 0f0e674f71.
2023-08-13 20:02:33 +02:00
fgsfds 38343bfbf1 Revert "port: change the loaded_texture system yet again; fix a couple crashes"
This reverts commit 6750bd9422.
2023-08-13 20:02:16 +02:00
fgsfds 76ed7f180e port: padoffsets are actually u16 2023-08-13 19:42:51 +02:00
fgsfds 6750bd9422 port: change the loaded_texture system yet again; fix a couple crashes
in combat sim once in a million years, in G5 and Villa
2023-08-13 18:52:15 +02:00
fgsfds d51a7bc9d6 port: rename some math functions to avoid conflicts with libc 2023-08-13 17:13:08 +02:00
fgsfds 6cb545aaf0 port: swap more cctv and linkliftdoorobj fields
props to Ryan for noticing
2023-08-13 16:48:21 +02:00
fgsfds 4b8c4a5bcd port: saner bg portal swapping 2023-08-13 15:52:43 +02:00
fgsfds 0a9a191f27 Update README.md 2023-08-13 12:05:59 +02:00
fgsfds 83c1bd3ffd ci: bundle DLL hell with windows builds 2023-08-13 11:56:54 +02:00
fgsfds 23c57ad033 ci: add placeholder file to data directory so it gets packaged 2023-08-13 11:45:42 +02:00
fgsfds cf1594bcbb ci: forgot to --add-architecture 2023-08-13 11:39:05 +02:00
fgsfds 10caa91099 ci: add even more missing deps 2023-08-13 11:37:19 +02:00
fgsfds 6f209d26d8 ci: add missing deps 2023-08-13 11:29:16 +02:00
fgsfds 6d777fb18f ci: start setting up CI 2023-08-13 11:24:24 +02:00
fgsfds c007bee536 port: don't use s32s for texture pointers 2023-08-13 01:13:03 +02:00
fgsfds 0f0e674f71 port: make the tmem_index allocation a little bit more sane 2023-08-12 22:42:38 +02:00
fgsfds 56ab86cddc port: support linear texgen without lookat set; set default values for lookat 2023-08-12 21:41:28 +02:00
fgsfds 8c9c0abee6 port: use uname -m instead of -p for machine arch 2023-08-11 23:43:31 +02:00
fgsfds ae01850ce1 Update README.md
clarify what 32-bit platforms means
2023-08-11 22:23:18 +02:00
fgsfds 319aaaa81d Update README.md 2023-08-11 22:13:20 +02:00
fgsfds 4f4280de58 port: on linux, default to host gcc with -m32
as suggested in #1

also do not abort clean on unsupported target arch
2023-08-11 22:06:39 +02:00
fgsfds dbd2da4923 port: LoadTLUT should probably mark textures for reload as well 2023-08-11 20:55:38 +02:00
fgsfds 16fcca7a2f port: hackfix incorrect size for RGBA textures; mark all textures as changed on load
this fixes the menu font, but it's probably a better idea to fix the whole loaded_texture system
2023-08-11 20:44:24 +02:00
fgsfds a803d5a4ec port: stub out G_RDPHALF_ commands
this will temporarily prevent crashing in combat sim but will result in black skies on maps that use this
2023-08-11 18:18:16 +02:00
fgsfds d888e82de6 port: fix vertex count in G_VTX 2023-08-11 15:19:17 +02:00
fgsfds 07adda3fa6 port: more reasonable mouse sensitivity
what the fuck was I trying to do here?
2023-08-11 00:03:37 +02:00
fgsfds 3416e0632d port: fix byteswapping the waypoint data 2023-08-11 00:03:16 +02:00
fgsfds 6396b38a6f port: fix (?) crash related to knocking out the secretary in defection 2023-08-11 00:02:59 +02:00
fgsfds 25d9e4a195 Update README.md 2023-08-09 23:02:24 +02:00
fgsfds b109d866dd port: fix linux build 2023-08-09 23:00:57 +02:00
fgsfds 075b7f9bd7 port: make the legal screen display the commit hash and platform 2023-08-09 22:54:42 +02:00
fgsfds fc16dc1330 port: nuke unused env var 2023-08-09 22:33:25 +02:00
fgsfds 28282f1c35 port: auto-generate headers like the decomp does
this does not require the ROM
2023-08-09 22:32:26 +02:00
fgsfds 67492e744d Update README.md 2023-08-09 22:09:53 +02:00
fgsfds 288b37a1b3 port: fix aEnvMixer; fix some misc warnings
hopefully that was the last of the big audio issues
2023-08-09 21:18:36 +02:00
fgsfds 60e64e1a1d port: don't doubleswap envelope data
this fixes music running out of free channels
2023-08-09 19:08:48 +02:00
fgsfds 18bab30c59 port: more UB/bug fixes 2023-08-09 13:07:02 +02:00
fgsfds a37441b221 port: hackfix a bunch of UB and seg-related issues
game now runs with -O2
2023-08-08 16:38:45 +02:00
fgsfds 245d5095b5 port: remove hacks from makefile 2023-08-08 14:31:30 +02:00
fgsfds 62f3007d2a port: halfassed solution for segmented addresses; fix some dyntex related stuff 2023-08-08 14:30:59 +02:00
fgsfds f9b27d7d01 port: match rendering resolution to window resolution, but keep 4:3 for now
16:9 requires some work
2023-08-06 22:04:22 +02:00
fgsfds 885bfeaf38 port: disable indefinite wait in aiIfMusicEventQueueIsEmpty for now
might have to actually run audio in a different thread
2023-08-06 21:38:07 +02:00
fgsfds 2d6e6c887e port: add mp3 decoding via lieff/minimp3 2023-08-06 21:24:38 +02:00
fgsfds afae1a3aae port: fix chraction crash
bug?
2023-08-06 21:24:04 +02:00
fgsfds 9081421eba port: add stupid hack to avoid double-swapping audio data 2023-08-06 21:23:47 +02:00
fgsfds eb8c4e9ee9 Merge branch 'master' of https://github.com/n64decomp/perfect_dark into port 2023-08-06 18:52:09 +02:00
fgsfds 81c1c206d4 port: make audio run at 60hz again but with smaller frames
this is required to tick music events correctly
2023-08-06 18:20:37 +02:00
fgsfds 063df3243d port: make audio tick at 30hz, add hack to prevent popping
this is a shit solution, but it'll do for now
2023-08-06 18:08:21 +02:00
fgsfds af3e235348 port: reenable SSE/NEON checks in mixer 2023-08-06 15:52:54 +02:00
fgsfds ffb5ca4b5b port: begin implementing audio
mixer taken from sm64-port and modified to fit PD's naudio thing

MP3 playback not supported yet

audio buffering sucks
2023-08-06 15:51:07 +02:00
fgsfds 866be01860 port: swap ADPCM books and loop states 2023-08-06 15:50:07 +02:00
fgsfds 32c05e6a3d port: swap sequence headers 2023-08-06 01:18:07 +02:00
Ryan Dwyer f1e1e6b204 Set names for headanim symbols 2023-08-05 18:16:16 +10:00
fgsfds e1b892e8b4 port: hack in mouselook 2023-08-05 03:13:56 +02:00
fgsfds da9046f745 port: swap RGBA color literals 2023-08-05 01:57:26 +02:00
fgsfds 51a27cba75 port: disable windows imagebase hack
that makes windows put the heap at a lower address instead
2023-08-05 01:13:40 +02:00
fgsfds 0e931b0be0 port: add gSPPerspNormalize support
this fixes the viewmodel
2023-08-05 01:12:47 +02:00
fgsfds ea8e49c870 port: linux support; horrible hack to avoid segmented address funny moments
linux support only tested a little bit in a VM
2023-08-04 23:44:20 +02:00
fgsfds 172f943891 port: remove GetModuleHandleA call 2023-08-04 21:49:22 +02:00
fgsfds e6965580a0 port: mostly unfuck texture loader 2023-08-04 21:47:54 +02:00
fgsfds a9b772ef99 port: fix hitscans and other uses of Gtri 2023-08-04 16:46:05 +02:00
fgsfds c2d1d9b4bf port: don't crash when reading briefing in the mission screen 2023-08-04 01:25:18 +02:00
fgsfds d6ee4f49d2 port: flesh out the input system a bit 2023-08-04 01:11:50 +02:00
fgsfds 05889b54cb port: partially unfuck menus 2023-08-04 01:11:19 +02:00
fgsfds 952d23de08 port: fix gun file swapping 2023-08-03 21:54:34 +02:00
fgsfds c8e3641bbc port: fix colors when both fog and SHADE_ALPHA are enabled 2023-08-03 18:26:59 +02:00
fgsfds a12d756d79 port: detect fog alpha usage 2023-08-03 16:58:52 +02:00
fgsfds 406900e253 port: detect fog color usage 2023-08-03 16:50:24 +02:00
fgsfds ff9030f5fb port: swap light bboxes properly 2023-08-03 16:50:14 +02:00
fgsfds 316516422b port: fix lookat loading; allow for multiple mipped textures 2023-08-03 16:17:31 +02:00
fgsfds 58120e299e port: fix (?) texture alignment, ignore LOD levels > 0 for now 2023-08-03 16:01:12 +02:00
fgsfds 46a9888647 port: hackfix modeswitching 2023-08-02 20:32:21 +02:00
fgsfds a542e93fe7 port: temporarily disable sleep timer 2023-08-02 19:45:49 +02:00
fgsfds 03ea57dab8 port: disable zbufDrawArtifactsOffscreen for now 2023-08-02 19:45:11 +02:00
fgsfds 9d1e40c5f7 port: unfuck font palettes 2023-08-02 19:44:41 +02:00
fgsfds a3c3f8df72 port: fix LOD textures exploding, fix palette loading 2023-08-02 19:44:13 +02:00
fgsfds 4fa7deed5a port: swap more modeldef nodes 2023-08-02 02:30:02 +02:00
fgsfds c0e73091f5 port: check GL attrib and uniform indices before using them 2023-08-02 02:29:38 +02:00
fgsfds c449a687cf port: fix vertex color indexing 2023-08-02 01:04:15 +02:00
fgsfds 23f5b72943 port: swap room verts 2023-08-02 00:11:51 +02:00
fgsfds 9ec6fa06f8 port: oops, forgot Makefile this whole time 2023-08-01 23:39:14 +02:00
fgsfds 9433dc7769 port: make it not crash on the intro sequence and render SOME geometry 2023-08-01 23:38:06 +02:00
fgsfds 9508b136ff port: replace old fast3d with libultraship-fast3d 2023-08-01 23:37:49 +02:00
fgsfds 157d46b73a port: fix tahoma 2023-08-01 01:28:08 +02:00
fgsfds a37bb4c3be port: fix REORDER model node byteswapping and gundl.numvertices 2023-07-31 22:36:26 +02:00
fgsfds 5c9a502657 port: fix Gfx being 16 bytes 2023-07-31 22:34:54 +02:00
fgsfds 2331b0911d port: always report at least one controller connected 2023-07-30 21:25:01 +02:00
fgsfds f91401cb95 port: make the legal screen render correctly
also, total errno death in the same commit because I am dumb
2023-07-30 21:24:39 +02:00
fgsfds da94644c38 port: make it link and load
nothing happens after loading though
2023-07-29 23:21:35 +02:00
Ryan Dwyer aeca25d984 Fix arguments for if_chr_same_floor_distance_to_pad_lt 2023-07-21 00:03:01 +10:00
Ryan Dwyer cef885db72 Replace a heap of literals, mostly in sound code 2023-07-07 22:10:48 +10:00
Ryan Dwyer a780b5f179 Identify hov and hovtype properties 2023-06-28 23:37:39 +10:00
Ryan Dwyer 3b4451a2d1 Name more pak symbols 2023-06-25 22:33:57 +10:00
Ryan Dwyer 83e8265d5b Introduce RoomNum typedef 2023-06-20 19:14:13 +10:00
373 changed files with 52347 additions and 7120 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
+330
View File
@@ -0,0 +1,330 @@
name: C/C++ CI
on:
push:
branches: [ "port", "port-net" ]
pull_request:
branches: [ "port" ]
workflow_dispatch:
jobs:
build-i686-windows:
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- name: Install MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: MINGW32
update: true
install: >-
git
make
mingw-w64-i686-toolchain
mingw-w64-i686-SDL2
mingw-w64-i686-zlib
mingw-w64-i686-cmake
- name: Checkout repository
uses: actions/checkout@v4
- name: Build pd.i686.exe
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
run: |
mkdir -p bin/data
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/
touch bin/data/put_your_rom_here.txt
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: pd-i686-windows
path: bin/
retention-days: 0
build-i686-linux:
runs-on: ubuntu-22.04
steps:
- name: Install dependencies
run: |
sudo dpkg --add-architecture i386
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 cmake
- name: Checkout repository
uses: actions/checkout@v4
- name: Build pd.i686
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
run: |
mkdir -p bin/data
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
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: pd-i686-linux
path: bin/
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: bilelmoussaoui/flatpak-github-actions:freedesktop-23.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.fgsfdsfgs.perfect_dark.flatpak
manifest-path: dist/linux/io.github.fgsfdsfgs.perfect_dark.yaml
cache-key: flatpak-builder-${{ github.sha }}
upload-artifact: false
# - name: Build Flatpak bundle
# run: |
# cd dist/linux/
# flatpak-builder build --force-clean io.github.fgsfdsfgs.perfect_dark.yaml
# flatpak build-export export build
# flatpak build-bundle export io.github.fgsfdsfgs.perfect_dark.flatpak io.github.fgsfdsfgs.perfect_dark
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: io.github.fgsfdsfgs.perfect_dark.flatpak
path: io.github.fgsfdsfgs.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.fgsfdsfgs.perfect_dark.flatpak/io.github.fgsfdsfgs.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/*
+7
View File
@@ -1,7 +1,10 @@
*.o
*.pyc
*.dll
*.exe
pd.*.z64
build
.flatpak-builder
extracted
src/assets/*/*.bin
src/assets/*/*.ctl
@@ -19,3 +22,7 @@ src/assets/*/sequences/*.seq
src/assets/*/textures/*.bin
src/generated
tools/mkrom/mkrom
/.vs
CppProperties.json
.idea
cmake-build-debug
+358
View File
@@ -0,0 +1,358 @@
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)
# 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
)
# 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 ws2_32 winmm 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()
-808
View File
@@ -1,808 +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)
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/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)
CFLAGS := $(C_DEFINES) -DAVOID_UB=1 $(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
+202 -37
View File
@@ -1,62 +1,227 @@
# Perfect Dark Decompilation
# Perfect Dark port (`port-net`)
This repository contains a complete decompilation of Perfect Dark for the Nintendo 64.
## Experimental netplay branch
The project aims to be a matching decompilation. When a matching decompilation is compiled with the same compiler that the original developers used, the output will be exactly the same as the retail game, byte for byte.
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.**
To build the project, you must already have a Perfect Dark ROM. The project can build the exact same ROM from decomp's source code combined with assets that it extracts from your base ROM.
See [this file](https://github.com/perfect-dark-pc-port/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.
To run the port, you must already have a Perfect Dark ROM, specifically one of the following:
* `ntsc-final`/`US V1.1`/`US Rev 1` (md5 `e03b088b6ac9e0080440efed07c1e40f`).
**This is the recommended version to use**.
Called `NTSC version 8.7 final` on the boot screen.
* `ntsc-1.0`/`US V1.0` (md5 `7f4171b0c8d17815be37913f535e4e93`).
Technically supported, but not recommended.
Called `NTSC version 8.7 final` on the boot screen as well.
* `jpn-final` (md5 `538d2b75945eae069b29c46193e74790`).
Technically supported, but requires a separate custom-built executable.
Called `JPN version 8.9 final` on the boot screen.
* `pal-final` (md5 `d9b5cd305d228424891ce38e71bc9213`).
Technically supported, but requires a separate custom-built executable.
Called `PAL 8.7 final` on the boot screen.
## Status
See the [Perfect Dark Decompilation Status Page](https://ryandwyer.gitlab.io/pdstatus/).
The game is in a mostly functional state, with both singleplayer and split-screen multiplayer modes fully working.
There are minor graphics- and gameplay-related issues, and possibly occasional crashes.
All versions of the game are fully decompiled but a small handful of functions are not yet byte-matching even though they are functionally the same. The status page doesn't show these as 100% because it counts matching functions only.
**The following extra features are implemented:**
* mouselook;
* dual analog controller support;
* widescreen resolution support;
* configurable field of view;
* 60 FPS support, including fixes for some framerate-related issues;
* fixes for a couple original bugs and crashes;
* basic mod support, currently enough to load a few custom levels;
* slightly expanded memory heap size;
* experimental high framerate support (up to 240 FPS):
* 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.
* emulate the Transfer Pak functionality the game has on the Nintendo 64 to unlock some cheats automatically.
## Installation Requirements
**The following platforms are officially supported and tested:**
* Windows 7+: i686, x86_64
* Linux: i686, x86_64
* MacOS: x86_64 (OS 10.9+), arm64 (OS 11.0+)
* Nintendo Switch: arm64
For Arch Linux:
## Download
* Install these packages: `binutils fakeroot gcc make python vim`
* Install from AUR: `armips`
* Install from AUR: a MIPS binutils package of your choice (eg. `mips-elf-binutils`)
* Install from AUR: a MIPS gcc package of your choice (eg. `mips-elf-gcc`)
Latest [automatic builds](https://github.com/perfect-dark-pc-port/perfect_dark/actions) of the netplay branch for supported platforms:
* [x86_64-windows (`port-net`)](https://nightly.link/perfect-dark-pc-port/perfect_dark/workflows/c-cpp/port-net/pd-x86_64-windows.zip)
* [i686-windows (`port-net`)](https://nightly.link/perfect-dark-pc-port/perfect_dark/workflows/c-cpp/port-net/pd-i686-windows.zip)
* [x86_64-linux (`port-net`)](https://nightly.link/perfect-dark-pc-port/perfect_dark/workflows/c-cpp/port-net/pd-x86_64-linux.zip)
* [i686-linux (`port-net`)](https://nightly.link/perfect-dark-pc-port/perfect_dark/workflows/c-cpp/port-net/pd-i686-linux.zip)
For Debian and Ubuntu:
If you are looking for regular builds (the `port` branch), see [this link](https://github.com/perfect-dark-pc-port/perfect_dark/blob/port/README.md#download).
* Install these packages: `binutils-mips-linux-gnu build-essential gcc-mips-linux-gnu libc6-dev-i386 libcapstone-dev make`
* Compile and install `armips`
## Running
## ROM Versions
You must already have a Perfect Dark ROM to run the game, as specified above.
Perfect Dark has six known versions:
This assumes that you're using an x86_64 build. If you aren't, replace `x86_64` below with your arch (e.g. `i686`).
| ROM ID | Description | MD5 Checksum |
|------------|---------------------------------------------|----------------------------------|
| ntsc-beta | NTSC 6.4 beta | aa93f4df16fceada399a749f5ad2f273 |
| ntsc-1.0 | NTSC 8.7 final (the initial, buggy release) | 7f4171b0c8d17815be37913f535e4e93 |
| ntsc-final | NTSC 8.7 final | e03b088b6ac9e0080440efed07c1e40f |
| pal-beta | PAL 28.7 beta | ad2de210a3455ba5ec541f0c78d91444 |
| pal-final | PAL 8.7 final | d9b5cd305d228424891ce38e71bc9213 |
| jpn-final | JPN 8.9 final | 538d2b75945eae069b29c46193e74790 |
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.
The project uses the `$ROMID` environment variable to know which version to work with. If not set, it defaults to `ntsc-final`. You can change it by running something like `export ROMID=ntsc-1.0`.
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`.
## Extracting the base ROM
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.
1. Save your existing ROM file into the root of the repository with the name `pd.ntsc-final.z64`. It should not be byteswapped (the first four bytes should be `0x80371240`).
2. Run `make extract`.
Optionally, you can move the data folder to `~/.local/share/perfectdark` on Linux or `~/Library/Application Support/perfectdark` on MacOS.
This will extract assets to `src/assets`. If any asset already exists then it will not be overwritten. This means you can modify assets as desired, and your changes will not be overwritten if you run the extract command again.
Note that users with different ROMs can't play netgames with each other.
The extract command will also create an `extracted/ntsc-final` directory. This directory contains some compiled code segments from the ROM and is only used for comparison purposes.
Additional information can be found in the [wiki](https://github.com/perfect-dark-pc-port/perfect_dark/wiki).
## Compiling
A GPU supporting OpenGL 3.0/ES3.0 or above is required to run the port.
* Run `git submodule update --init --recursive`. You only have to do this once.
* Run `make -j` to build the ROM. The ROM will be written to `build/ntsc-final/pd.z64`.
### Installing the Nintendo Switch version
## How do I know the built files are matching?
The Nintendo Switch build ZIP comes with all 3 regions in different folders: `perfectdark`, `perfectdark_pal` and `perfectdark_jpn`.
Run `make` followed by `make test`. If `make test` produces no output then the compiled project is matching.
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.
You can also md5sum your base ROM with the built ROM and check they have the same hash: `md5sum pd.ntsc-final.z64 build/ntsc-final/pd.z64`.
`port-net` currently does not work on the Switch.
## Controls
1964GEPD-style and Xbox-style bindings are implemented.
N64 pad buttons X and Y (or `X_BUTTON`, `Y_BUTTON` in the code) refer to the reserved buttons `0x40` and `0x80`, which are also leveraged by 1964GEPD.
Support for one controller, two-stick configurations are enabled for 1.2.
Note that the mouse only controls player 1.
Controls can be rebound in `pd.ini`. Default control scheme is as follows:
| Action | Keyboard and mouse | Xbox pad | N64 pad |
| - | - | - | - |
| Fire / Accept | LMB/Space | RT | Z Trigger |
| Aim mode | RMB/Z | LT | R Trigger |
| Use / Cancel | E | N/A | B |
| Use / Accept | N/A | A | A |
| Crouch cycle | N/A | L3 | `0x80000000` (Extra) |
| Half-Crouch | Shift | N/A | `0x40000000` (Extra) |
| Full-Crouch | Control | N/A | `0x20000000` (Extra) |
| Reload | R | X | X `(0x40)` |
| Previous weapon | Mousewheel forward | B | D-Left |
| Next weapon | Mousewheel back | Y | Y `(0x80)` |
| Radial menu | Q | LB | D-Down |
| Alt fire mode | F | RB | L Trigger |
| Alt-fire oneshot | `F + LMB` or `E + LMB` | `A + RT` or `RB + RT` | `A + Z` or `L + Z` |
| Quick-detonate | `E + Q` or `E + R` | `A + B` or `A + X` | `A + D-Left`or `A + X` |
## Building
### Windows
1. Install [MSYS2](https://www.msys2.org).
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:
`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:
`git clone -b port-net --recursive https://github.com/perfect-dark-pc-port/perfect_dark.git && cd perfect_dark`
5. Run `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.\
6. Run `cmake --build build -j4 -- -O`.
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
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.
* 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:
`git clone -b port-net --recursive https://github.com/perfect-dark-pc-port/perfect_dark.git && cd perfect_dark`
3. Run the following command:
* ```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.
* 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. Run `cmake --build build -j4`.
5. The resulting executable will be at `build/pd.<arch>` (for example `build/pd.x86_64`).
### MacOS
1. Set up Homebrew.
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/perfect-dark-pc-port/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.
### 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/perfect-dark-pc-port/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
* 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;
* [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;
* lieff for [minimp3](https://github.com/lieff/minimp3);
* 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;
* 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.fgsfdsfgs.perfect_dark.sh
Icon=io.github.fgsfdsfgs.perfect_dark
Terminal=false
Type=Application
Categories=Game;ActionGame;
StartupNotify=false
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>io.github.fgsfdsfgs.perfect_dark</id>
<name>Perfect Dark</name>
<developer id="io.github.fgsfdsfgs.perfect_dark">
<name>Perfect Dark Contributors</name>
<url>https://github.com/fgsfdsfgs/perfect_dark/graphs/contributors</url>
</developer>
<launchable type="desktop-id">io.github.fgsfdsfgs.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">https://gitlab.com/fpiesche/dxx-rebirth-assets/-/raw/c6e7e79eebe92905f84f07a635ffab5122a94bd1/d1x/screenshots/retromode.png</image>
<caption>"Retro mode": the default graphics setup, like the original game but in high resolution</caption>
<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

+39
View File
@@ -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
+41
View File
@@ -0,0 +1,41 @@
app-id: io.github.fgsfdsfgs.perfect_dark
runtime: org.freedesktop.Platform
runtime-version: "23.08"
sdk: org.freedesktop.Sdk
command: io.github.fgsfdsfgs.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.fgsfdsfgs.perfect_dark.sh
- type: file
path: io.github.fgsfdsfgs.perfect_dark.png
- type: file
path: io.github.fgsfdsfgs.perfect_dark.metainfo.xml
- type: file
path: io.github.fgsfdsfgs.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
@@ -0,0 +1,47 @@
## 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 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.
+21
View File
@@ -22,6 +22,7 @@
#define __R4300_H__
#include <PR/ultratypes.h>
#include "platform.h"
/*
* Segment base addresses and sizes
@@ -60,6 +61,8 @@
#else /* _LANGUAGE_C */
#ifdef PLATFORM_N64
#define K0_TO_K1(x) ((u32)(x)|0xA0000000) /* kseg0 to kseg1 */
#define K1_TO_K0(x) ((u32)(x)&0x9FFFFFFF) /* kseg1 to kseg0 */
#define K0_TO_PHYS(x) ((u32)(x)&0x1FFFFFFF) /* kseg0 to physical */
@@ -68,6 +71,24 @@
#define PHYS_TO_K0(x) ((u32)(x)|0x80000000) /* physical to kseg0 */
#define PHYS_TO_K1(x) ((u32)(x)|0xA0000000) /* physical to kseg1 */
#else /* PLATFORM_N64 */
#ifdef PLATFORM_64BIT
typedef u64 k_ptr_t;
#else
typedef u32 k_ptr_t;
#endif
#define K0_TO_K1(x) ((k_ptr_t)(x)) /* kseg0 to kseg1 */
#define K1_TO_K0(x) ((k_ptr_t)(x)) /* kseg1 to kseg0 */
#define K0_TO_PHYS(x) ((k_ptr_t)(x)) /* kseg0 to physical */
#define K1_TO_PHYS(x) ((k_ptr_t)(x)) /* kseg1 to physical */
#define KDM_TO_PHYS(x) ((k_ptr_t)(x)) /* direct mapped to physical */
#define PHYS_TO_K0(x) ((k_ptr_t)(x)) /* physical to kseg0 */
#define PHYS_TO_K1(x) ((k_ptr_t)(x)) /* physical to kseg1 */
#endif /* PLATFORM_N64 */
#endif /* _LANGUAGE_ASSEMBLY */
/*
+8
View File
@@ -265,6 +265,8 @@ typedef short RESAMPLE_STATE[16];
*/
typedef short ENVMIX_STATE[40];
#ifdef PLATFORM_N64
/*
* Macros to assemble the audio command list
*/
@@ -402,6 +404,12 @@ typedef short ENVMIX_STATE[40];
_a->words.w1 = (unsigned int) d; \
}
#else // PLATFORM_N64
#include "mixer.h"
#endif
#endif /* _LANGUAGE_C */
#endif /* !_ABI_H_ */
+159 -31
View File
@@ -22,6 +22,12 @@
#include <PR/ultratypes.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.
@@ -594,10 +600,10 @@
#define G_BL_0 3
#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) \
(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) \
AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \
@@ -1029,16 +1035,32 @@ typedef union {
* Triangle face
*/
typedef struct {
#ifdef PLATFORM_BIG_ENDIAN
unsigned char flag;
unsigned char v[3];
#else
unsigned char v[3]; // reverse order
unsigned char flag;
#endif
} Tri;
#ifdef PLATFORM_BIG_ENDIAN
#define GFX_TRI_VTX(i) (i)
#else
#define GFX_TRI_VTX(i) (2 - i)
#endif
/*
* 4x4 matrix, fixed point s15.16 format.
* First 8 words are integer portion of the 4x4 matrix
* Last 8 words are the fraction portion of the 4x4 matrix
*/
typedef long Mtx_t[4][4];
#ifdef GBI_FLOATS
// 4x4 float matrix
typedef float Mtx_t[4][4];
#else
typedef int32_t Mtx_t[4][4];
#endif
typedef union {
Mtx_t m;
@@ -1290,23 +1312,45 @@ typedef union {
/*
* 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 {
#ifdef PLATFORM_BIG_ENDIAN
int cmd:8;
unsigned int par:8;
unsigned int len:16;
unsigned int addr;
#else // NOTE: changing signedness mid int will break up the bitfield on normal platforms, even BE
int len:16;
int par:8;
int cmd:8;
unsigned int addr;
#endif
} Gdma;
#endif
/*
* Graphics Immediate Mode Packet types
*/
typedef struct {
#ifdef PLATFORM_BIG_ENDIAN
int cmd:8;
int pad:24;
#else
int pad:24;
int cmd:8;
#endif
Tri tri;
} Gtri;
typedef struct {
#ifdef PLATFORM_BIG_ENDIAN
unsigned char cmd:8;
unsigned char pad:8;
unsigned char z4:4;
@@ -1321,6 +1365,28 @@ typedef struct {
unsigned char x2:4;
unsigned char y1:4;
unsigned char x1:4;
#else
unsigned char z1:4;
unsigned char z2:4;
unsigned char z3:4;
unsigned char z4:4;
unsigned char pad:8;
unsigned char cmd:8;
#ifdef PLATFORM_64BIT
unsigned char pad2[4];
#endif
unsigned char x1:4;
unsigned char y1:4;
unsigned char x2:4;
unsigned char y2:4;
unsigned char x3:4;
unsigned char y3:4;
unsigned char x4:4;
unsigned char y4:4;
#ifdef PLATFORM_64BIT
unsigned char pad3[4];
#endif
#endif
} Gtri4;
typedef struct {
@@ -1356,12 +1422,21 @@ typedef struct {
} GsetothermodeH;
typedef struct {
#ifdef PLATFORM_BIG_ENDIAN
unsigned char cmd;
unsigned char lodscale;
unsigned char tile;
unsigned char on;
unsigned short s;
unsigned short t;
#else
unsigned char on;
unsigned char tile;
unsigned char lodscale;
unsigned char cmd;
unsigned short t;
unsigned short s;
#endif
} Gtexture;
typedef struct {
@@ -1484,13 +1559,14 @@ typedef struct {
* Generic Gfx Packet
*/
typedef struct {
unsigned int w0;
unsigned int w1;
uintptr_t w0;
uintptr_t w1;
} Gwords;
// xxxxxxxx 11223344 44555566 66666777
// 88888888 99999999 9999aaaa aaaaaaaa
typedef struct {
#ifdef PLATFORM_BIG_ENDIAN
unsigned int cmd:8;
unsigned int unk08:2;
unsigned int unk0a:2;
@@ -1502,15 +1578,37 @@ typedef struct {
unsigned int unk20:8;
unsigned int tile1:12;
unsigned int tile2:12;
#else
unsigned int subcmd:3;
unsigned int flags:7;
unsigned int unk12:4;
unsigned int unk0e:4;
unsigned int unk0c:2;
unsigned int unk0a:2;
unsigned int unk08:2;
unsigned int cmd:8;
unsigned int tile2:12;
unsigned int tile1:12;
unsigned int unk20:8;
#endif
} GunkC0;
typedef struct {
#ifdef PLATFORM_BIG_ENDIAN
unsigned int cmd:8;
unsigned int unk08:4;
unsigned int unk0c:4;
unsigned int unk10:16;
unsigned int seg:8;
unsigned int offset:24;
#else
unsigned int unk10:16;
unsigned int unk0c:4;
unsigned int unk08:4;
unsigned int cmd:8;
unsigned int offset:24;
unsigned int seg:8;
#endif
} Gvtx;
/*
@@ -1519,17 +1617,22 @@ typedef struct {
*/
typedef union {
Gwords words;
#ifdef PLATFORM_64BIT
u8 bytes[16];
#else
u8 bytes[8];
#endif
Gdma dma;
Gvtx vtx;
Gtri tri;
Gtri4 tri4;
Gline3D line;
Gtexture texture;
#ifdef PLATFORM_N64 /* the rest is not needed on other platforms and some of em screw up the size */
Gpopmtx popmtx;
Gsegment segment;
GsetothermodeH setothermodeH;
GsetothermodeL setothermodeL;
Gtexture texture;
Gperspnorm perspnorm;
Gsetimg setimg;
Gsetcombine setcombine;
@@ -1539,10 +1642,26 @@ typedef union {
Gloadtile loadtile; /* use for loadblock also, th is dxt */
Gsettilesize settilesize;
Gloadtlut loadtlut;
#endif
GunkC0 unkc0;
#ifdef PLATFORM_64BIT
long long int force_structure_alignment[2];
#else
long long int force_structure_alignment;
#endif
} Gfx;
#ifdef PLATFORM_BIG_ENDIAN
#define GFX_W0_BYTE(i) (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
#define GFX_W0_BYTE(i) (3 - (i))
#define GFX_W1_BYTE(i) (7 - (i))
#endif
/*
* Macros to assemble the graphics display list
*/
@@ -1555,12 +1674,12 @@ typedef union {
Gfx *_g = (Gfx *)(pkt); \
\
_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) \
{ \
_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) \
@@ -1569,14 +1688,14 @@ typedef union {
\
_g->words.w0 = (_SHIFTL((c), 24, 8) | _SHIFTL((p), 16, 8) | \
_SHIFTL((l), 0, 16)); \
_g->words.w1 = (unsigned int)(s); \
_g->words.w1 = (uintptr_t)(s); \
}
#define gsDma1p(c, s, l, p) \
{ \
(_SHIFTL((c), 24, 8) | _SHIFTL((p), 16, 8) | \
_SHIFTL((l), 0, 16)), \
(unsigned int)(s) \
(uintptr_t)(s) \
}
#define gDma2p(pkt, c, adrs, len, idx, ofs) \
@@ -1584,14 +1703,14 @@ typedef union {
Gfx *_g = (Gfx *)(pkt); \
_g->words.w0 = (_SHIFTL((c),24,8)|_SHIFTL(((len)-1)/8,19,5)| \
_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) \
{ \
(_SHIFTL((c),24,8)|_SHIFTL(((len)-1)/8,19,5)| \
_SHIFTL((ofs)/8,8,8)|_SHIFTL((idx),0,8)), \
(unsigned int)(adrs) \
(uintptr_t)(adrs) \
}
#define gSPNoOp(pkt) gDma0p(pkt, G_SPNOOP, 0, 0)
@@ -1640,12 +1759,12 @@ typedef union {
Gfx *_g = (Gfx *)(pkt); \
\
_g->words.w0 = _SHIFTL((c), 24, 8); \
_g->words.w1 = (unsigned int)(p0); \
_g->words.w1 = (uintptr_t)(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) \
@@ -1682,13 +1801,13 @@ typedef union {
\
_g->words.w0 = (_SHIFTL((c), 24, 8) | _SHIFTL((p0), 8, 16) | \
_SHIFTL((p1), 0, 8)); \
_g->words.w1 = (unsigned int) (dat); \
_g->words.w1 = (uintptr_t) (dat); \
}
#define gsImmp21(c, p0, p1, dat) \
{ \
_SHIFTL((c), 24, 8) | _SHIFTL((p0), 8, 16) | _SHIFTL((p1), 0, 8), \
(unsigned int) (dat) \
(uintptr_t) (dat) \
}
#define gMoveWd(pkt, index, offset, data) \
@@ -1831,7 +1950,7 @@ typedef union {
\
_g->words.w0 = _SHIFTL(G_CULLDL, 24, 8) | \
((0x0f & (vstart))*40); \
_g->words.w1 = (unsigned int)((0x0f & ((vend)+1))*40); \
_g->words.w1 = (uintptr_t)((0x0f & ((vend)+1))*40); \
}
// Removed in PD
@@ -1847,6 +1966,15 @@ typedef union {
#define gsSPSegment(segment, base) \
gsMoveWd(G_MW_SEGMENT, (segment)*4, base)
#ifdef PLATFORM_N64
#define SEGADDR(x) x
#define UNSEGADDR(x) x
#else
// we mark all segmented addresses so that it'll be easier to recognize them later
#define SEGADDR(x) ((void *)((uintptr_t)(x) | 1))
#define UNSEGADDR(x) ((uintptr_t)(x) & ~1)
#endif
/*
* Clipping Macros
*/
@@ -2143,12 +2271,12 @@ typedef union {
Gfx *_g = (Gfx *)(pkt); \
\
_g->words.w0 = _SHIFTL(G_SETGEOMETRYMODE, 24, 8); \
_g->words.w1 = (unsigned int)(word); \
_g->words.w1 = (uintptr_t)(word); \
}
#define gsSPSetGeometryMode(word) \
{ \
_SHIFTL(G_SETGEOMETRYMODE, 24, 8), (unsigned int)(word) \
_SHIFTL(G_SETGEOMETRYMODE, 24, 8), (uintptr_t)(word) \
}
#define gSPClearGeometryMode(pkt, word) \
@@ -2156,12 +2284,12 @@ typedef union {
Gfx *_g = (Gfx *)(pkt); \
\
_g->words.w0 = _SHIFTL(G_CLEARGEOMETRYMODE, 24, 8); \
_g->words.w1 = (unsigned int)(word); \
_g->words.w1 = (uintptr_t)(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) \
@@ -2170,13 +2298,13 @@ typedef union {
\
_g->words.w0 = (_SHIFTL(cmd, 24, 8) | _SHIFTL(sft, 8, 8) | \
_SHIFTL(len, 0, 8)); \
_g->words.w1 = (unsigned int)(data); \
_g->words.w1 = (uintptr_t)(data); \
}
#define gsSPSetOtherMode(cmd, sft, len, data) \
{ \
_SHIFTL(cmd, 24, 8) | _SHIFTL(sft, 8, 8) | _SHIFTL(len, 0, 8), \
(unsigned int)(data) \
(uintptr_t)(data) \
}
/*
@@ -2227,14 +2355,14 @@ typedef union {
\
_g->words.w0 = _SHIFTL(cmd, 24, 8) | _SHIFTL(fmt, 21, 3) | \
_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) \
{ \
_SHIFTL(cmd, 24, 8) | _SHIFTL(fmt, 21, 3) | \
_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)
@@ -2260,13 +2388,13 @@ typedef union {
Gfx *_g = (Gfx *)(pkt); \
\
_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) \
{ \
_SHIFTL(G_SETCOMBINE, 24, 8) | _SHIFTL(muxs0, 0, 24), \
(unsigned int)(muxs1) \
(uintptr_t)(muxs1) \
}
#define GCCc0w0(saRGB0, mRGB0, saA0, mA0) \
@@ -2339,12 +2467,12 @@ typedef union {
Gfx *_g = (Gfx *)(pkt); \
\
_g->words.w0 = _SHIFTL(c, 24, 8); \
_g->words.w1 = (unsigned int)(d); \
_g->words.w1 = (uintptr_t)(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) \
@@ -2425,13 +2553,13 @@ typedef union {
Gfx *_g = (Gfx *)(pkt); \
\
_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) \
{ \
_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 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 FTOFRAC8(x) ((int) MIN(((x) * (128.0f)), 127.0f) & 0xff)
+4
View File
@@ -120,7 +120,11 @@ typedef struct ALLink_s {
void alUnlink(ALLink *element);
void alLink(ALLink *element, ALLink *after);
#ifdef PLATFORM_N64
typedef s32 (*ALDMAproc)(s32 addr, s32 len, void *state);
#else
typedef uintptr_t (*ALDMAproc)(uintptr_t addr, s32 len, void *state);
#endif
typedef ALDMAproc (*ALDMANew)(void *state);
void alCopy(void *src, void *dest, s32 len);
+14 -3
View File
@@ -28,6 +28,7 @@ extern "C" {
#include <PR/ultratypes.h>
#include <PR/mbi.h>
#include "platform.h"
struct var8009c340 {
u8 surround;
@@ -71,7 +72,7 @@ typedef struct {
s32 maxAuxBusses;
s32 outputRate;
s32 maxOutSamples;
s32 sv_dramout;
uintptr_t sv_dramout;
s32 sv_first;
} N_ALSynth;
@@ -208,7 +209,7 @@ struct fx {
s16 unk00;
s16 unk02;
s32 unk04;
s16 unk08[8];
s16 unk08[16];
};
typedef struct N_ALVoiceState_s {
@@ -256,7 +257,7 @@ typedef struct {
ALOscStop stopOsc;
ALSeqMarker *loopStart;
ALSeqMarker *loopEnd;
s32 loopCount; /* -1 = loop forever, 0 = no loop */
intptr_t loopCount; /* -1 = loop forever, 0 = no loop */
u8 unk88;
u8 unk89;
} N_ALSeqPlayer;
@@ -284,9 +285,19 @@ typedef struct {
ALOscInit initOsc;
ALOscUpdate updateOsc;
ALOscStop stopOsc;
#ifdef PLATFORM_64BIT
s32 _pad1_;
f32 unk7c;
s32 _pad2_;
f32 unk80;
#else
f32 unk7c;
f32 unk80;
#endif
void *queue;
u8 unk88;
u8 unk89;
} N_ALCSPlayer;
+42 -18
View File
@@ -53,14 +53,18 @@ extern "C" {
typedef struct {
u16 type; /* Controller Type */
u8 status; /* Controller status */
u8 errno;
u8 errnum;
}OSContStatus;
typedef struct {
u16 button;
u32 button;
s8 stick_x; /* -80 <= stick_x <= 80 */
s8 stick_y; /* -80 <= stick_y <= 80 */
u8 errno;
u8 errnum;
#ifndef PLATFORM_N64
s8 rstick_x;
s8 rstick_y;
#endif
} OSContPad;
typedef struct {
@@ -68,7 +72,7 @@ typedef struct {
u8 databuffer[32]; /* address of the data buffer */
u8 addressCrc; /* CRC code for address */
u8 dataCrc; /* CRC code for data */
u8 errno;
u8 errnum;
} OSContRamIo;
@@ -118,21 +122,39 @@ typedef struct {
#define CONT_EEPROM_BUSY 0x80
/* Buttons */
#define CONT_8000 0x80000000
#define CONT_4000 0x40000000
#define CONT_2000 0x20000000
#define CONT_1000 0x10000000
#define CONT_0800 0x08000000
#define CONT_0400 0x04000000
#define CONT_0200 0x02000000
#define CONT_0100 0x01000000
#define CONT_0080 0x00800000
#define CONT_0040 0x00400000
#define CONT_0020 0x00200000
#define CONT_0010 0x00100000
#define CONT_0008 0x00080000
#define CONT_0004 0x00040000
#define CONT_0002 0x00020000
#define CONT_0001 0x00010000
#define CONT_A 0x8000
#define CONT_B 0x4000
#define CONT_G 0x2000
#define CONT_START 0x1000
#define CONT_UP 0x0800
#define CONT_DOWN 0x0400
#define CONT_LEFT 0x0200
#define CONT_RIGHT 0x0100
#define CONT_L 0x0020
#define CONT_R 0x0010
#define CONT_E 0x0008
#define CONT_D 0x0004
#define CONT_C 0x0002
#define CONT_F 0x0001
#define CONT_A 0x00008000
#define CONT_B 0x00004000
#define CONT_G 0x00002000
#define CONT_START 0x00001000
#define CONT_UP 0x00000800
#define CONT_DOWN 0x00000400
#define CONT_LEFT 0x00000200
#define CONT_RIGHT 0x00000100
#define CONT_EXTRA1 0x00000080
#define CONT_EXTRA0 0x00000040
#define CONT_L 0x00000020
#define CONT_R 0x00000010
#define CONT_E 0x00000008
#define CONT_D 0x00000004
#define CONT_C 0x00000002
#define CONT_F 0x00000001
/* Nintendo's official button names */
@@ -150,6 +172,8 @@ typedef struct {
#define L_CBUTTONS CONT_C
#define R_CBUTTONS CONT_F
#define D_CBUTTONS CONT_D
#define X_BUTTON CONT_EXTRA0
#define Y_BUTTON CONT_EXTRA1
/* Controller error number */
+15 -3
View File
@@ -35,6 +35,9 @@ extern "C" {
#endif
#include <PR/ultratypes.h>
#ifndef PLATFORM_N64
#include <stdint.h>
#endif
#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS)
@@ -70,12 +73,17 @@ extern "C" {
#define OS_CYCLES_TO_NSEC(c) (((u64)(c)*(1000000000LL/15625000LL))/(OS_CPU_COUNTER/15625000LL))
#define OS_CYCLES_TO_USEC(c) (((u64)(c)*(1000000LL/15625LL))/(OS_CPU_COUNTER/15625LL))
#ifdef PLATFORM_N64
#define OS_K0_TO_PHYSICAL(x) (u32)(((char *)(x)-0x80000000))
#define OS_K1_TO_PHYSICAL(x) (u32)(((char *)(x)-0xa0000000))
#define OS_PHYSICAL_TO_K0(x) (void *)(((u32)(x)+0x80000000))
#define OS_PHYSICAL_TO_K1(x) (void *)(((u32)(x)+0xa0000000))
#else
#define OS_K0_TO_PHYSICAL(x) (uintptr_t)(x)
#define OS_K1_TO_PHYSICAL(x) (uintptr_t)(x)
#define OS_PHYSICAL_TO_K0(x) (void *)(x)
#define OS_PHYSICAL_TO_K1(x) (void *)(x)
#endif
/**************************************************************************
*
@@ -92,9 +100,13 @@ extern "C" {
/* Address translation routines and macros */
#ifdef PLATFORM_N64
extern u32 osVirtualToPhysical(void *);
extern void * osPhysicalToVirtual(u32);
#else
extern uintptr_t osVirtualToPhysical(void *);
extern void * osPhysicalToVirtual(uintptr_t);
#endif
#endif /* defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) */
+15 -3
View File
@@ -31,6 +31,14 @@
#define _OS_LIBC_H_
#include "os_pfs.h"
#include "platform.h"
#ifndef PLATFORM_N64
#include <stdio.h>
#endif
#ifdef PLATFORM_OSX
#include <strings.h>
#endif
#ifdef _LANGUAGE_C_PLUS_PLUS
extern "C" {
@@ -80,13 +88,17 @@ extern "C" {
/* byte string operations */
extern void bcopy(const void *, void *, int);
extern int bcmp(const void *, const void *, int);
extern void bzero(void *, int);
#ifndef PLATFORM_OSX
extern void bcopy(const void *, void *, size_t);
extern int bcmp(const void *, const void *, size_t);
extern void bzero(void *, size_t);
#endif
/* Printf */
#ifdef PLATFORM_N64
extern int sprintf(char *s, const char *fmt, ...);
#endif
extern void osSyncPrintf(const char *fmt, ...);
+2 -2
View File
@@ -37,7 +37,7 @@ extern "C" {
#include <PR/ultratypes.h>
#include "os_thread.h"
#include "os_message.h"
#include <stdint.h>
#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS)
@@ -198,7 +198,7 @@ extern u32 osPiGetStatus(void);
extern s32 osPiGetDeviceType(void);
extern s32 osPiWriteIo(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 *);
extern void osCreatePiManager(OSPri, OSMesgQueue *, OSMesg *, s32);
File renamed without changes.
+8
View File
@@ -57,6 +57,8 @@ typedef volatile long long vs64; /* signed 64-bit */
typedef float f32; /* single prec floating point */
typedef double f64; /* double prec floating point */
#ifdef PLATFORM_N64
#if !defined(_SIZE_T) && !defined(_SIZE_T_) && !defined(_SIZE_T_DEF)
#define _SIZE_T
#define _SIZE_T_DEF /* exeGCC size_t define label */
@@ -68,6 +70,12 @@ typedef unsigned long size_t;
#endif
#endif
#else
#include <stddef.h>
#endif
#endif /* _LANGUAGE_C */
+10
View File
@@ -0,0 +1,10 @@
#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
@@ -0,0 +1,2 @@
#define MINIMP3_IMPLEMENTATION
#include "external/minimp3.h"
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Emill, MaikelChan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+56
View File
@@ -0,0 +1,56 @@
#ifndef GFX_API_H
#define GFX_API_H
#ifndef __cplusplus
#include <stdint.h>
#include <stdbool.h>
#endif
#include "gfx_rendering_api.h"
#include "gfx_window_manager_api.h"
struct XYWidthHeight {
int16_t x, y;
uint32_t width, height;
};
struct GfxDimensions {
float internal_mul;
uint32_t width, height;
float aspect_ratio;
};
struct GfxInitSettings {
struct GfxWindowManagerAPI *wapi;
struct GfxRenderingAPI *rapi;
struct GfxWindowInitSettings window_settings;
};
extern struct GfxDimensions gfx_current_window_dimensions; // The dimensions of the window
extern struct GfxDimensions
gfx_current_dimensions; // The dimensions of the draw area the game draws to, before scaling (if applicable)
extern struct XYWidthHeight
gfx_current_game_window_viewport; // The area of the window the game is drawn to, (0, 0) is top-left corner
extern uint32_t gfx_msaa_level;
extern struct XYWidthHeight gfx_current_native_viewport; // The internal/native video mode of the game
extern float gfx_current_native_aspect; // The aspect ratio of the above mode
extern bool gfx_framebuffers_enabled;
extern bool gfx_detail_textures_enabled;
void gfx_init(const struct GfxInitSettings *settings);
void gfx_destroy(void);
struct GfxRenderingAPI* gfx_get_current_rendering_api(void);
void gfx_start_frame(void);
void gfx_run(Gfx* commands);
void gfx_end_frame(void);
void gfx_set_target_fps(int);
void gfx_set_texture_filter(enum FilteringMode mode);
void gfx_texture_cache_clear(void);
void gfx_texture_cache_delete(const uint8_t *orig_addr);
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_set_framebuffer(int fb, float noise_scale) ;
void gfx_reset_framebuffer(void);
void gfx_copy_framebuffer(int fb_dst, int fb_src, int left, int top, int use_back);
#endif
+59
View File
@@ -0,0 +1,59 @@
#include "gfx_cc.h"
void gfx_cc_get_features(uint64_t shader_id0, uint32_t shader_id1, struct CCFeatures* cc_features) {
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
for (int k = 0; k < 4; k++) {
cc_features->c[i][j][k] = (shader_id0 >> (i * 32 + j * 16 + k * 4)) & 0xf;
}
}
}
cc_features->opt_alpha = (shader_id1 & SHADER_OPT_ALPHA) != 0;
cc_features->opt_fog = (shader_id1 & SHADER_OPT_FOG) != 0;
cc_features->opt_texture_edge = (shader_id1 & SHADER_OPT_TEXTURE_EDGE) != 0;
cc_features->opt_noise = (shader_id1 & SHADER_OPT_NOISE) != 0;
cc_features->opt_2cyc = (shader_id1 & SHADER_OPT_2CYC) != 0;
cc_features->opt_alpha_threshold = (shader_id1 & SHADER_OPT_ALPHA_THRESHOLD) != 0;
cc_features->opt_invisible = (shader_id1 & SHADER_OPT_INVISIBLE) != 0;
cc_features->opt_grayscale = (shader_id1 & SHADER_OPT_GRAYSCALE) != 0;
cc_features->opt_blur = (shader_id1 & SHADER_OPT_BLUR) != 0;
cc_features->clamp[0][0] = (shader_id1 & SHADER_OPT_TEXEL0_CLAMP_S);
cc_features->clamp[0][1] = (shader_id1 & SHADER_OPT_TEXEL0_CLAMP_T);
cc_features->clamp[1][0] = (shader_id1 & SHADER_OPT_TEXEL1_CLAMP_S);
cc_features->clamp[1][1] = (shader_id1 & SHADER_OPT_TEXEL1_CLAMP_T);
cc_features->used_textures[0] = false;
cc_features->used_textures[1] = false;
cc_features->num_inputs = 0;
for (int c = 0; c < 2; c++) {
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 4; j++) {
if (cc_features->c[c][i][j] >= SHADER_INPUT_1 && cc_features->c[c][i][j] <= SHADER_INPUT_7) {
if (cc_features->c[c][i][j] > cc_features->num_inputs) {
cc_features->num_inputs = cc_features->c[c][i][j];
}
}
if (cc_features->c[c][i][j] == SHADER_TEXEL0 || cc_features->c[c][i][j] == SHADER_TEXEL0A) {
cc_features->used_textures[0] = true;
}
if (cc_features->c[c][i][j] == SHADER_TEXEL1 || cc_features->c[c][i][j] == SHADER_TEXEL1A) {
cc_features->used_textures[1] = true;
}
}
}
}
for (int c = 0; c < 2; c++) {
cc_features->do_single[c][0] = cc_features->c[c][0][2] == SHADER_0;
cc_features->do_single[c][1] = cc_features->c[c][1][2] == SHADER_0;
cc_features->do_multiply[c][0] = cc_features->c[c][0][1] == SHADER_0 && cc_features->c[c][0][3] == SHADER_0;
cc_features->do_multiply[c][1] = cc_features->c[c][1][1] == SHADER_0 && cc_features->c[c][1][3] == SHADER_0;
cc_features->do_mix[c][0] = cc_features->c[c][0][1] == cc_features->c[c][0][3];
cc_features->do_mix[c][1] = cc_features->c[c][1][1] == cc_features->c[c][1][3];
cc_features->color_alpha_same[c] =
((shader_id0 >> c * 32) & 0xffff) == ((shader_id0 >> (c * 32 + 16)) & 0xffff);
}
}
+75
View File
@@ -0,0 +1,75 @@
#ifndef GFX_CC_H
#define GFX_CC_H
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
#include <compare>
#endif
enum {
SHADER_0,
SHADER_INPUT_1,
SHADER_INPUT_2,
SHADER_INPUT_3,
SHADER_INPUT_4,
SHADER_INPUT_5,
SHADER_INPUT_6,
SHADER_INPUT_7,
SHADER_TEXEL0,
SHADER_TEXEL0A,
SHADER_TEXEL1,
SHADER_TEXEL1A,
SHADER_1,
SHADER_COMBINED,
SHADER_NOISE,
SHADER_LOD_FRAC,
};
#define SHADER_OPT_ALPHA (1 << 0)
#define SHADER_OPT_FOG (1 << 1)
#define SHADER_OPT_TEXTURE_EDGE (1 << 2)
#define SHADER_OPT_NOISE (1 << 3)
#define SHADER_OPT_2CYC (1 << 4)
#define SHADER_OPT_ALPHA_THRESHOLD (1 << 5)
#define SHADER_OPT_INVISIBLE (1 << 6)
#define SHADER_OPT_GRAYSCALE (1 << 7)
#define SHADER_OPT_TEXEL0_CLAMP_S (1 << 8)
#define SHADER_OPT_TEXEL0_CLAMP_T (1 << 9)
#define SHADER_OPT_TEXEL1_CLAMP_S (1 << 10)
#define SHADER_OPT_TEXEL1_CLAMP_T (1 << 11)
#define SHADER_OPT_BLUR (1 << 12)
struct ColorCombinerKey {
uint64_t combine_mode;
uint64_t options;
auto operator<=>(const ColorCombinerKey&) const = default;
};
#define SHADER_MAX_TEXTURES 2
#define SHADER_FIRST_TEXTURE 0
struct CCFeatures {
uint8_t c[2][2][4];
bool opt_alpha;
bool opt_fog;
bool opt_texture_edge;
bool opt_noise;
bool opt_2cyc;
bool opt_alpha_threshold;
bool opt_invisible;
bool opt_grayscale;
bool opt_blur;
bool used_textures[2];
bool clamp[2][2];
int num_inputs;
bool do_single[2][2];
bool do_multiply[2][2];
bool do_mix[2][2];
bool color_alpha_same[2];
};
void gfx_cc_get_features(uint64_t shader_id0, uint32_t shader_id1, struct CCFeatures* cc_features);
#endif
File diff suppressed because it is too large. Load diff
+8
View File
@@ -0,0 +1,8 @@
#ifndef GFX_OPENGL_H
#define GFX_OPENGL_H
#include "gfx_rendering_api.h"
extern struct GfxRenderingAPI gfx_opengl_api;
#endif
File diff suppressed because it is too large. Load diff
+60
View File
@@ -0,0 +1,60 @@
#ifndef GFX_PC_H
#define GFX_PC_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <unordered_map>
#include <list>
#include <cstddef>
#include <PR/gbi.h>
#include "system.h"
#define SCREEN_WIDTH ((int32_t)gfx_current_native_viewport.width)
#define SCREEN_HEIGHT ((int32_t)gfx_current_native_viewport.height)
extern uintptr_t gfxFramebuffer;
struct GfxRenderingAPI;
struct GfxWindowManagerAPI;
struct TextureCacheKey {
const uint8_t* texture_addr;
const uint8_t* palette_addrs[2];
uint8_t fmt, siz;
uint8_t palette_index;
bool operator==(const TextureCacheKey&) const noexcept = default;
struct Hasher {
size_t operator()(const TextureCacheKey& key) const noexcept {
uintptr_t addr = (uintptr_t)key.texture_addr;
return (size_t)(addr ^ (addr >> 5));
}
};
};
typedef std::unordered_map<TextureCacheKey, struct TextureCacheValue, TextureCacheKey::Hasher> TextureCacheMap;
typedef std::pair<const TextureCacheKey, struct TextureCacheValue> TextureCacheNode;
struct TextureCacheValue {
uint32_t texture_id;
uint8_t cms, cmt;
bool linear_filter;
std::list<struct TextureCacheMapIter>::iterator lru_location;
};
struct TextureCacheMapIter {
TextureCacheMap::iterator it;
};
extern "C" {
#include "gfx_api.h"
}
#endif
+57
View File
@@ -0,0 +1,57 @@
#ifndef GFX_RENDERING_API_H
#define GFX_RENDERING_API_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
struct ShaderProgram;
struct GfxClipParameters {
bool z_is_from_0_to_1;
bool invert_y;
};
enum FilteringMode { FILTER_NONE, FILTER_LINEAR, FILTER_THREE_POINT };
struct GfxRenderingAPI {
const char* (*get_name)(void);
int (*get_max_texture_size)(void);
struct GfxClipParameters (*get_clip_parameters)(void);
void (*unload_shader)(struct ShaderProgram* old_prg);
void (*load_shader)(struct ShaderProgram* new_prg);
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);
void (*shader_get_info)(struct ShaderProgram* prg, uint8_t* num_inputs, bool used_textures[2]);
void (*clear_shaders)(void);
uint32_t (*new_texture)(void);
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 (*set_sampler_parameters)(int sampler, bool linear_filter, uint32_t cms, uint32_t cmt);
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_viewport)(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 (*draw_triangles)(float buf_vbo[], size_t buf_vbo_len, size_t buf_vbo_num_tris);
void (*init)(void);
void (*on_resize)(void);
void (*start_frame)(void);
void (*end_frame)(void);
void (*finish_render)(void);
int (*create_framebuffer)();
void (*update_framebuffer_parameters)(int fb_id, uint32_t width, uint32_t height, uint32_t msaa_level,
bool opengl_invert_y, bool render_target, bool has_depth_buffer,
bool can_extract_depth);
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 (*clear_framebuffer)(bool clear_color, bool clear_depth);
void (*resolve_msaa_color_buffer)(int fb_id_target, int fb_id_source);
void* (*get_framebuffer_texture_id)(int fb_id);
void (*select_texture_fb)(int fb_id);
void (*delete_texture)(uint32_t texID);
void (*set_texture_filter)(enum FilteringMode mode);
enum FilteringMode (*get_texture_filter)(void);
};
#endif
+7
View File
@@ -0,0 +1,7 @@
#ifndef GFX_SCREEN_CONFIG_H
#define GFX_SCREEN_CONFIG_H
#define DESIRED_SCREEN_WIDTH 640
#define DESIRED_SCREEN_HEIGHT 480
#endif
+8
View File
@@ -0,0 +1,8 @@
#ifndef GFX_SDL_H
#define GFX_SDL_H
#include "gfx_window_manager_api.h"
extern struct GfxWindowManagerAPI gfx_sdl;
#endif
+463
View File
@@ -0,0 +1,463 @@
#include <stdio.h>
#include <SDL.h>
#include <unistd.h>
#include <time.h>
#include "platform.h"
#include "system.h"
#include "gfx_window_manager_api.h"
#include "gfx_screen_config.h"
static SDL_Window* wnd;
static SDL_GLContext ctx;
static SDL_Renderer* renderer;
static int sdl_to_lus_table[512];
static bool vsync_enabled = true;
// OTRTODO: These are redundant. Info can be queried from SDL.
static int window_width = DESIRED_SCREEN_WIDTH;
static int window_height = DESIRED_SCREEN_HEIGHT;
static uint32_t fullscreen_flag = SDL_WINDOW_FULLSCREEN_DESKTOP;
static bool fullscreen_state;
static bool maximized_state;
static bool is_running = true;
static void (*on_fullscreen_changed_callback)(bool is_now_fullscreen);
static int target_fps = 120; // above 60 since vsync is enabled by default
static uint64_t previous_time;
static uint64_t qpc_freq;
#define FRAME_INTERVAL_US_NUMERATOR 1000000
#define FRAME_INTERVAL_US_DENOMINATOR (target_fps)
static int32_t gfx_sdl_get_maximized_state(void) {
return (int32_t)maximized_state;
}
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;
SDL_SetWindowFullscreen(wnd, on ? fullscreen_flag : 0);
if (call_callback && on_fullscreen_changed_callback) {
on_fullscreen_changed_callback(on);
}
}
static void set_maximize_window(bool on) {
maximized_state = on;
if (on) {
SDL_MaximizeWindow(wnd);
} else {
SDL_RestoreWindow (wnd);
}
}
static void gfx_sdl_get_active_window_refresh_rate(uint32_t* refresh_rate) {
int display_in_use = SDL_GetWindowDisplayIndex(wnd);
SDL_DisplayMode mode;
SDL_GetCurrentDisplayMode(display_in_use, &mode);
*refresh_rate = mode.refresh_rate;
}
static void gfx_sdl_init(const struct GfxWindowInitSettings *set) {
window_width = set->width;
window_height = set->height;
#ifdef SDL_HINT_VIDEO_HIGHDPI_DISABLED
if (!set->allow_hidpi) {
// HiDPI control, if available
SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "1");
#if defined(PLATFORM_WIN32) && defined(SDL_HINT_WINDOWS_DPI_AWARENESS)
// if HiDPI is disabled, declare ourselves DPI aware to get 1:1 window size on Windows
SDL_SetHint(SDL_HINT_WINDOWS_DPI_AWARENESS, "permonitor");
#endif
}
#endif
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
sysFatalError("Could not init SDL:\n%s", SDL_GetError());
}
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
if (sysArgCheck("--debug-gl")) {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
}
int posX = set->x;
int posY = set->y;
int display_in_use = SDL_GetWindowDisplayIndex(wnd);
if (display_in_use < 0) { // Fallback to default if out of bounds
posX = 100;
posY = 100;
}
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) {
fullscreen_flag = SDL_WINDOW_FULLSCREEN;
}
// 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 (set->fullscreen) {
flags |= fullscreen_flag;
fullscreen_state = true;
}
if (set->maximized) {
flags |= SDL_WINDOW_MAXIMIZED;
maximized_state = true;
}
#ifdef SDL_WINDOW_ALLOW_HIGHDPI
if (set->allow_hidpi) {
flags |= SDL_WINDOW_ALLOW_HIGHDPI;
}
#endif
// 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
static u32 glver[][3] = {
{ 0, 0, 0 }, // for command line override
{ 3, 0, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY }, // 3.0: default, has all the features required
{ 4, 1, SDL_GL_CONTEXT_PROFILE_CORE }, // 4.1core: macs only have core profile and this is the latest
{ 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 verstart = 1;
const u32 verend = sizeof(glver) / sizeof(*glver);
const char *verstr = sysArgGetString("--gl-version");
if (verstr && *verstr) {
// user override
glver[0][2] = strstr(verstr, "core") ? SDL_GL_CONTEXT_PROFILE_CORE :
(strstr(verstr, "es") ? SDL_GL_CONTEXT_PROFILE_ES :
SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
sscanf(verstr, "%d.%d", &glver[0][0], &glver[0][1]);
if (glver[0][0] >= 1 && glver[0][0] <= 4 && glver[0][1] < 9) {
verstart = 0;
}
}
ctx = NULL;
u32 vmin = 0, vmaj = 0, vprof = SDL_GL_CONTEXT_PROFILE_COMPATIBILITY;
const char *vprofstr = "";
for (u32 i = verstart; i < verend && !ctx; ++i) {
vmaj = glver[i][0];
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_MINOR_VERSION, vmin);
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);
if (!ctx) {
sysLogPrintf(LOG_WARNING, "SDL: could not create GL%d.%d%s context: %s", vmaj, vmin, vprofstr, SDL_GetError());
SDL_DestroyWindow(wnd);
wnd = nullptr;
}
}
if (!wnd || !ctx) {
sysFatalError("Could not open SDL window with an OpenGL context of any supported version:\n%s", SDL_GetError());
} else {
sysLogPrintf(LOG_NOTE, "SDL: created GL%d.%d%s context", vmaj, vmin, vprofstr);
}
SDL_GL_MakeCurrent(wnd, ctx);
SDL_GL_SetSwapInterval(1);
SDL_ShowWindow(wnd);
qpc_freq = SDL_GetPerformanceFrequency();
}
static void gfx_sdl_close(void) {
is_running = false;
}
static void gfx_sdl_set_fullscreen_changed_callback(void (*on_fullscreen_changed)(bool is_now_fullscreen)) {
on_fullscreen_changed_callback = on_fullscreen_changed;
}
static void gfx_sdl_set_fullscreen(bool enable) {
set_fullscreen(enable, true);
}
static void gfx_sdl_set_fullscreen_exclusive(bool enable) {
const uint32_t newflag = enable ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP;
if (fullscreen_flag != newflag) {
fullscreen_flag = newflag;
// reset fullscreen to take new value into account if it already is in fullscreen
if (fullscreen_state) {
fullscreen_state = false;
set_fullscreen(enable, true);
}
}
}
static void gfx_sdl_set_maximize_window(bool enable) {
set_maximize_window(enable);
}
static void gfx_sdl_set_cursor_visibility(bool visible) {
if (visible) {
SDL_ShowCursor(SDL_ENABLE);
} else {
SDL_ShowCursor(SDL_DISABLE);
}
}
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) {
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));
}
static void gfx_sdl_handle_events(void) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN:
if (event.key.keysym.sym == SDLK_RETURN && (event.key.keysym.mod & KMOD_ALT)) {
// alt-enter received, switch fullscreen state
set_fullscreen(!fullscreen_state, true);
}
break;
case SDL_WINDOWEVENT:
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
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 &&
event.window.windowID == SDL_GetWindowID(wnd)) {
// We listen specifically for main window close because closing main window
// on macOS does not trigger SDL_Quit.
exit(0);
}
break;
case SDL_QUIT:
exit(0);
break;
}
}
}
static bool gfx_sdl_start_frame(void) {
return true;
}
static uint64_t qpc_to_100ns(uint64_t qpc) {
return qpc / qpc_freq * 10000000 + qpc % qpc_freq * 10000000 / qpc_freq;
}
static inline void sync_framerate_with_timer(void) {
uint64_t t;
t = qpc_to_100ns(SDL_GetPerformanceCounter());
const int64_t next = previous_time + 10 * FRAME_INTERVAL_US_NUMERATOR / FRAME_INTERVAL_US_DENOMINATOR;
int64_t left = next - t;
// We want to exit a bit early, so we can busy-wait the rest to never miss the deadline
left -= 15000UL;
if (left > 0) {
sysSleep(left);
}
do {
sysCpuRelax();
t = qpc_to_100ns(SDL_GetPerformanceCounter());
} while ((int64_t)t < next);
t = qpc_to_100ns(SDL_GetPerformanceCounter());
if (left > 0 && t - next < 10000) {
// In case it takes some time for the application to wake up after sleep,
// or inaccurate timer,
// don't let that slow down the framerate.
t = next;
}
previous_time = t;
}
static void gfx_sdl_swap_buffers_begin(void) {
if (target_fps) {
sync_framerate_with_timer();
}
SDL_GL_SwapWindow(wnd);
}
static void gfx_sdl_swap_buffers_end(void) {
}
static double gfx_sdl_get_time(void) {
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) {
target_fps = fps;
}
static bool gfx_sdl_can_disable_vsync(void) {
return true;
}
static void *gfx_sdl_get_window_handle(void) {
return (void *)wnd;
}
static void gfx_sdl_set_window_title(const char *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) {
const bool success = SDL_GL_SetSwapInterval(interval) >= 0;
vsync_enabled = success && (interval != 0);
if (!success) {
sysLogPrintf(LOG_WARNING, "SDL: failed to set vsync %d: %s", interval, SDL_GetError());
}
return success;
}
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_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,
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_get_active_window_refresh_rate,
gfx_sdl_set_cursor_visibility,
gfx_sdl_set_closest_resolution,
gfx_sdl_set_dimensions,
gfx_sdl_get_dimensions,
gfx_sdl_get_centered_positions,
gfx_sdl_handle_events,
gfx_sdl_start_frame,
gfx_sdl_swap_buffers_begin,
gfx_sdl_swap_buffers_end,
gfx_sdl_get_time,
gfx_sdl_get_target_fps,
gfx_sdl_set_target_fps,
gfx_sdl_can_disable_vsync,
gfx_sdl_get_window_handle,
gfx_sdl_set_window_title,
gfx_sdl_get_swap_interval,
gfx_sdl_set_swap_interval,
};
+54
View File
@@ -0,0 +1,54 @@
#ifndef GFX_WINDOW_MANAGER_API_H
#define GFX_WINDOW_MANAGER_API_H
#include <stdint.h>
#include <stdbool.h>
struct GfxWindowInitSettings {
const char *title;
uint32_t width;
uint32_t height;
int32_t x;
int32_t y;
bool fullscreen;
bool fullscreen_is_exclusive;
bool maximized;
bool centered;
bool allow_hidpi;
};
struct GfxWindowManagerAPI {
void (*init)(const struct GfxWindowInitSettings *settings);
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)(bool enable);
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 (*get_active_window_refresh_rate)(uint32_t* refresh_rate);
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_centered_positions)(int32_t width, int32_t height, int32_t *posX, int32_t *posY);
void (*handle_events)(void);
bool (*start_frame)(void);
void (*swap_buffers_begin)(void);
void (*swap_buffers_end)(void);
double (*get_time)(void); // For debug
int32_t (*get_target_fps)(void);
void (*set_target_fps)(int fps);
bool (*can_disable_vsync)(void);
void *(*get_window_handle)(void);
void (*set_window_title)(const char *);
int (*get_swap_interval)(void);
bool (*set_swap_interval)(int);
};
#endif
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+311
View File
@@ -0,0 +1,311 @@
#ifndef __khrplatform_h_
#define __khrplatform_h_
/*
** Copyright (c) 2008-2018 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be included
** in all copies or substantial portions of the Materials.
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
/* Khronos platform-specific types and definitions.
*
* The master copy of khrplatform.h is maintained in the Khronos EGL
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
* The last semantic modification to khrplatform.h was at commit ID:
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
*
* Adopters may modify this file to suit their platform. Adopters are
* encouraged to submit platform specific modifications to the Khronos
* group so that they can be included in future versions of this file.
* Please submit changes by filing pull requests or issues on
* the EGL Registry repository linked above.
*
*
* See the Implementer's Guidelines for information about where this file
* should be located on your system and for more details of its use:
* http://www.khronos.org/registry/implementers_guide.pdf
*
* This file should be included as
* #include <KHR/khrplatform.h>
* by Khronos client API header files that use its types and defines.
*
* The types in khrplatform.h should only be used to define API-specific types.
*
* Types defined in khrplatform.h:
* khronos_int8_t signed 8 bit
* khronos_uint8_t unsigned 8 bit
* khronos_int16_t signed 16 bit
* khronos_uint16_t unsigned 16 bit
* khronos_int32_t signed 32 bit
* khronos_uint32_t unsigned 32 bit
* khronos_int64_t signed 64 bit
* khronos_uint64_t unsigned 64 bit
* khronos_intptr_t signed same number of bits as a pointer
* khronos_uintptr_t unsigned same number of bits as a pointer
* khronos_ssize_t signed size
* khronos_usize_t unsigned size
* khronos_float_t signed 32 bit floating point
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
* nanoseconds
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
* khronos_boolean_enum_t enumerated boolean type. This should
* only be used as a base type when a client API's boolean type is
* an enum. Client APIs which use an integer or other type for
* booleans cannot use this as the base type for their boolean.
*
* Tokens defined in khrplatform.h:
*
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
*
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
*
* Calling convention macros defined in this file:
* KHRONOS_APICALL
* KHRONOS_APIENTRY
* KHRONOS_APIATTRIBUTES
*
* These may be used in function prototypes as:
*
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
* int arg1,
* int arg2) KHRONOS_APIATTRIBUTES;
*/
#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
# define KHRONOS_STATIC 1
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APICALL
*-------------------------------------------------------------------------
* This precedes the return type of the function in the function prototype.
*/
#if defined(KHRONOS_STATIC)
/* If the preprocessor constant KHRONOS_STATIC is defined, make the
* header compatible with static linking. */
# define KHRONOS_APICALL
#elif defined(_WIN32)
# define KHRONOS_APICALL __declspec(dllimport)
#elif defined (__SYMBIAN32__)
# define KHRONOS_APICALL IMPORT_C
#elif defined(__ANDROID__)
# define KHRONOS_APICALL __attribute__((visibility("default")))
#else
# define KHRONOS_APICALL
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIENTRY
*-------------------------------------------------------------------------
* This follows the return type of the function and precedes the function
* name in the function prototype.
*/
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
/* Win32 but not WinCE */
# define KHRONOS_APIENTRY __stdcall
#else
# define KHRONOS_APIENTRY
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIATTRIBUTES
*-------------------------------------------------------------------------
* This follows the closing parenthesis of the function prototype arguments.
*/
#if defined (__ARMCC_2__)
#define KHRONOS_APIATTRIBUTES __softfp
#else
#define KHRONOS_APIATTRIBUTES
#endif
/*-------------------------------------------------------------------------
* basic type definitions
*-----------------------------------------------------------------------*/
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
/*
* Using <stdint.h>
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
/*
* To support platform where unsigned long cannot be used interchangeably with
* inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
* Ideally, we could just use (u)intptr_t everywhere, but this could result in
* ABI breakage if khronos_uintptr_t is changed from unsigned long to
* unsigned long long or similar (this results in different C++ name mangling).
* To avoid changes for existing platforms, we restrict usage of intptr_t to
* platforms where the size of a pointer is larger than the size of long.
*/
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
#define KHRONOS_USE_INTPTR_T
#endif
#endif
#elif defined(__VMS ) || defined(__sgi)
/*
* Using <inttypes.h>
*/
#include <inttypes.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
/*
* Win32
*/
typedef __int32 khronos_int32_t;
typedef unsigned __int32 khronos_uint32_t;
typedef __int64 khronos_int64_t;
typedef unsigned __int64 khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(__sun__) || defined(__digital__)
/*
* Sun or Digital
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#if defined(__arch64__) || defined(_LP64)
typedef long int khronos_int64_t;
typedef unsigned long int khronos_uint64_t;
#else
typedef long long int khronos_int64_t;
typedef unsigned long long int khronos_uint64_t;
#endif /* __arch64__ */
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif 0
/*
* Hypothetical platform with no float or int64 support
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#define KHRONOS_SUPPORT_INT64 0
#define KHRONOS_SUPPORT_FLOAT 0
#else
/*
* Generic fallback
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#endif
/*
* Types that are (so far) the same on all platforms
*/
typedef signed char khronos_int8_t;
typedef unsigned char khronos_uint8_t;
typedef signed short int khronos_int16_t;
typedef unsigned short int khronos_uint16_t;
/*
* Types that differ between LLP64 and LP64 architectures - in LLP64,
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
* to be the only LLP64 architecture in current use.
*/
#ifdef KHRONOS_USE_INTPTR_T
typedef intptr_t khronos_intptr_t;
typedef uintptr_t khronos_uintptr_t;
#elif defined(_WIN64)
typedef signed long long int khronos_intptr_t;
typedef unsigned long long int khronos_uintptr_t;
#else
typedef signed long int khronos_intptr_t;
typedef unsigned long int khronos_uintptr_t;
#endif
#if defined(_WIN64)
typedef signed long long int khronos_ssize_t;
typedef unsigned long long int khronos_usize_t;
#else
typedef signed long int khronos_ssize_t;
typedef unsigned long int khronos_usize_t;
#endif
#if KHRONOS_SUPPORT_FLOAT
/*
* Float type
*/
typedef float khronos_float_t;
#endif
#if KHRONOS_SUPPORT_INT64
/* Time types
*
* These types can be used to represent a time interval in nanoseconds or
* an absolute Unadjusted System Time. Unadjusted System Time is the number
* of nanoseconds since some arbitrary system event (e.g. since the last
* time the system booted). The Unadjusted System Time is an unsigned
* 64 bit value that wraps back to 0 every 584 years. Time intervals
* may be either signed or unsigned.
*/
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
typedef khronos_int64_t khronos_stime_nanoseconds_t;
#endif
/*
* Dummy value used to pad enum types to 32 bits.
*/
#ifndef KHRONOS_MAX_ENUM
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
#endif
/*
* Enumerated boolean type
*
* Values other than zero should be considered to be true. Therefore
* comparisons should not be made against KHRONOS_TRUE.
*/
typedef enum {
KHRONOS_FALSE = 0,
KHRONOS_TRUE = 1,
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
} khronos_boolean_enum_t;
#endif /* __khrplatform_h_ */
+12
View File
@@ -0,0 +1,12 @@
#ifndef _IN_AUDIO_H
#define _IN_AUDIO_H
#include <PR/ultratypes.h>
s32 audioInit(void);
s32 audioGetBytesBuffered(void);
s32 audioGetSamplesBuffered(void);
void audioSetNextBuffer(const s16 *buf, u32 len);
void audioEndFrame(void);
#endif
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include <PR/ultratypes.h>
#define CONFIG_FNAME "pd.ini"
#define CONFIG_PATH "$S/" CONFIG_FNAME
void configInit(void);
// loads config from file (path extensions such as ! apply)
s32 configLoad(const char *fname);
// saves config to file (path extensions such as ! apply)
s32 configSave(const char *fname);
// registers a variable in the config file
// this should be done before configInit() is called, preferably in a module constructor
void configRegisterInt(const char *key, s32 *var, s32 min, s32 max);
void configRegisterUInt(const char* key, u32* var, u32 min, u32 max);
void configRegisterFloat(const char *key, f32 *var, f32 min, f32 max);
void configRegisterString(const char *key, char *var, u32 maxstr);
+15
View File
@@ -0,0 +1,15 @@
#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);
s32 conIsOpen(void);
#endif
+5100
View File
File diff suppressed because it is too large. Load diff
+1865
View File
File diff suppressed because it is too large. Load diff
+27
View File
@@ -0,0 +1,27 @@
#ifndef _IN_FS_H
#define _IN_FS_H
#include <stdio.h>
#include <PR/ultratypes.h>
#define FS_MAXPATH 1024
s32 fsInit(void);
const char *fsFullPath(const char *relPath);
s32 fsPathIsAbsolute(const char *path);
s32 fsPathIsCwdRelative(const char *path);
void *fsFileLoad(const char *name, u32 *outSize);
s32 fsFileLoadTo(const char *name, void *dst, u32 dstSize);
s32 fsFileSize(const char *name);
FILE *fsFileOpenWrite(const char *name);
FILE *fsFileOpenRead(const char *name);
void fsFileFree(FILE *f);
const char *fsGetModDir(void);
s32 fsCreateDir(const char *path);
#endif
+273
View File
@@ -0,0 +1,273 @@
#ifndef _IN_INPUT_H
#define _IN_INPUT_H
#include <PR/ultratypes.h>
#include <PR/os_cont.h>
#define INPUT_MAX_CONTROLLERS MAXCONTROLLERS
#define INPUT_MAX_CONNECTED_CONTROLLERS 8
#define INPUT_MAX_CONTROLLER_BUTTONS 32
#define INPUT_MAX_BINDS 4
#define CONT_STICK_XNEG 0x10000
#define CONT_STICK_XPOS 0x20000
#define CONT_STICK_YNEG 0x40000
#define CONT_STICK_YPOS 0x80000
#define CONT_NUM_BUTTONS 32 // not including the stick axes
enum virtkey {
/* same order as SDL scancodes */
VK_KEYBOARD_BEGIN = 0,
VK_A = 4,
VK_Z = 29,
VK_1 = 30,
VK_9 = 38,
VK_0 = 39,
VK_RETURN = 40,
VK_ESCAPE = 41,
VK_BACKSPACE = 42,
VK_SPACE = 44,
VK_MINUS = 45,
VK_LEFTBRACKET = 47,
VK_RIGHTBRACKET = 48,
VK_SEMICOLON = 51,
VK_GRAVE = 53,
VK_COMMA = 54,
VK_PERIOD = 55,
VK_F1 = 58,
VK_F9 = 66,
VK_DELETE = 76,
VK_LCTRL = 224,
VK_LSHIFT = 225,
VK_LALT = 226,
VK_RCTRL = 228,
VK_RSHIFT = 229,
/* same order as SDL mouse buttons */
VK_MOUSE_BEGIN = 512,
VK_MOUSE_LEFT = VK_MOUSE_BEGIN,
VK_MOUSE_MIDDLE,
VK_MOUSE_RIGHT,
VK_MOUSE_X1,
VK_MOUSE_X2,
VK_MOUSE_WHEEL_UP,
VK_MOUSE_WHEEL_DN,
/* same order as SDL gamecontroller buttons plus two buttons for triggers */
VK_JOY_BEGIN,
VK_JOY1_BEGIN = VK_JOY_BEGIN,
VK_JOY1_LSHOULDER = VK_JOY1_BEGIN + 9,
VK_JOY1_RSHOULDER = VK_JOY1_BEGIN + 10,
VK_JOY1_LTRIG = VK_JOY1_BEGIN + 30,
VK_JOY1_RTRIG = VK_JOY1_BEGIN + 31,
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,
};
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 {
CK_C_R,
CK_C_L,
CK_C_D,
CK_C_U,
CK_RTRIG,
CK_LTRIG,
CK_X, // gap in CONT_
CK_Y, // gap in CONT_
CK_DPAD_R,
CK_DPAD_L,
CK_DPAD_D,
CK_DPAD_U,
CK_START,
CK_ZTRIG,
CK_B,
CK_A,
CK_STICK_XNEG,
CK_STICK_XPOS,
CK_STICK_YNEG,
CK_STICK_YPOS,
CK_ACCEPT,
CK_CANCEL,
CK_0040,
CK_0080,
CK_0100,
CK_0200,
CK_0400,
CK_0800,
CK_1000,
CK_2000,
CK_4000,
CK_8000,
CK_TOTAL_COUNT
};
enum mouselockmode {
MLOCK_OFF = 0,
MLOCK_ON = 1,
MLOCK_AUTO = 2
};
// returns bitmask of connected controllers or -1 if failed
s32 inputInit(void);
// read the specified player's inputs into the N64 pad struct
// returns 0 if read, non-0 if failed
s32 inputReadController(s32 idx, OSContPad *npad);
// returns 1 if rumble is supported for specified player's controller
s32 inputRumbleSupported(s32 idx);
// returns 1 if specified player has a live controller assigned
s32 inputControllerConnected(s32 idx);
// returns bitmask of players with assigned controllers
s32 inputControllerMask(void);
// get/set Input.Player%d.SwapSticks
s32 inputControllerGetSticksSwapped(s32 cidx);
void inputControllerSetSticksSwapped(s32 cidx, s32 swapped);
// get/set Input.Player%d.StickCButtons (DualAnalog is 1 if StickCButtons is 0)
s32 inputControllerGetDualAnalog(s32 cidx);
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
f32 inputControllerGetAxisScale(s32 cidx, s32 stick, s32 axis);
void inputControllerSetAxisScale(s32 cidx, s32 stick, s32 axis, f32 value);
// get/set deadzone for a given player
f32 inputControllerGetAxisDeadzone(s32 cidx, s32 stick, s32 axis);
void inputControllerSetAxisDeadzone(s32 cidx, s32 stick, s32 axis, f32 value);
// writes array of up to INPUT_MAX_CONNECTED_CONTROLLERS controller IDs
// for all the controllers available on this machine into out if it's not NULL
// returns number of IDs that would've been written (or were written if out is not NULL)
s32 inputGetConnectedControllers(s32 *out);
// get name of connected controller id
// returns "Invalid" on failure
const char *inputGetConnectedControllerName(s32 id);
// get id of the controller currently assigned to player cidx or -1 if none
s32 inputGetAssignedControllerId(s32 cidx);
// assign connected controller id to player cidx
// if id is -1, unassigns controller from player, if any
// returns true on success, false on failure
s32 inputAssignController(s32 cidx, s32 id);
// vk is a value from the virtkey enum above
s32 inputKeyPressed(u32 vk);
s32 inputKeyJustPressed(u32 vk);
// idx is controller index, contbtn is one of the CONT_ constants
s32 inputButtonPressed(s32 idx, u32 contbtn);
// bind virtkey vk to n64 pad #idx's button/axis ck as represented by its contkey value
// if bind is -1, picks a bind slot automatically
void inputKeyBind(s32 idx, u32 ck, s32 bind, u32 vk);
const u32 *inputKeyGetBinds(s32 idx, u32 ck);
// get VK_ value from human-readable name
s32 inputGetKeyByName(const char *name);
// get human-readable name from VK_ value
const char *inputGetKeyName(s32 vk);
// get CK_ value from human-readable name
s32 inputGetContKeyByName(const char *name);
// get human-readable name from CK_ value
const char *inputGetContKeyName(u32 ck);
// strength is 0 .. 1; 0 strength turns it off
void inputRumble(s32 idx, f32 strength, f32 time);
f32 inputRumbleGetStrength(s32 cidx);
void inputRumbleSetStrength(s32 cidx, f32 val);
// locks the mouse cursor in the window and makes it invisible if argument is true
void inputLockMouse(s32 lock);
// returns the current state of the above
s32 inputMouseIsLocked(void);
// sets x, y to mouse position in native viewport coordinates (ie, 320x240 most of the time)
// 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
void inputMouseGetRawDelta(s32 *dx, s32 *dy);
// returns changes in mouse position since last frame, scaled by sensitivity
// returns 0, 0 when the mouse is not locked into the window
void inputMouseGetScaledDelta(f32 *dx, f32 *dy);
// returns changes in mouse position since last frame, scaled by absolute sensitivity
// returns 0, 0 when the mouse is not locked into the window
void inputMouseGetAbsScaledDelta(f32 *dx, f32 *dy);
void inputMouseGetSpeed(f32 *x, f32 *y);
void inputMouseSetSpeed(f32 x, f32 y);
s32 inputMouseIsEnabled(void);
void inputMouseEnable(s32 enabled);
// call this every frame
void inputUpdate(void);
// call this before configSave()
void inputSaveBinds(void);
// reset given player's binds to either PC or N64 defaults
void inputSetDefaultKeyBinds(s32 cidx, s32 n64mode);
// clear or get the last pressed button
void inputClearLastKey(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 inputStopTextInput(void);
s32 inputIsTextInputActive(void);
void inputClearLastTextChar(void);
char inputGetLastTextChar(void);
s32 inputTextHandler(char *out, const u32 outSize, s32 *curCol, s32 oskCharsOnly);
void inputClearClipboard(void);
const char *inputGetClipboard(void);
// returns keymod values
u32 inputGetKeyModState(void);
#endif
+55
View File
@@ -0,0 +1,55 @@
#ifndef MIXER_H
#define MIXER_H
#include <stdint.h>
#include <ultra64.h>
#undef aSegment
#undef aClearBuffer
#undef aSetBuffer
#undef aLoadBuffer
#undef aSaveBuffer
#undef aDMEMMove
#undef aMix
#undef aEnvMixer
#undef aResample
#undef aInterleave
#undef aSetVolume
#undef aSetVolume32
#undef aSetLoop
#undef aLoadADPCM
#undef aADPCMdec
void aClearBufferImpl(uint16_t addr, int nbytes);
void aLoadADPCMImpl(int num_entries_times_16, const int16_t *book_source_addr);
void aDMEMMoveImpl(uint16_t in_addr, uint16_t out_addr, int nbytes);
void aSetLoopImpl(ADPCM_STATE *adpcm_loop_state);
void aADPCMdecImpl(uint8_t flags, ADPCM_STATE state, int nbytes, uint16_t inofs, uint16_t outofs);
void aResampleImpl(uint8_t flags, uint16_t pitch, RESAMPLE_STATE state, uint16_t inofs, uint8_t outflag);
void aLoadBufferImpl(const void *source_addr, uint16_t dest_addr, uint16_t nbytes);
void aSaveBufferImpl(uint16_t source_addr, int16_t *dest_addr, uint16_t nbytes);
void aInterleaveImpl(void);
void aMixImpl(uint8_t flags, int16_t gain, uint16_t in_addr, uint16_t out_addr);
void aEnvMixerImpl(uint8_t flags, ENVMIX_STATE state, int16_t some_vol);
void aSetVolumeImpl(uint8_t flags, int16_t v, int16_t t, int16_t r);
void aPoleFilterImpl(uint8_t flags, int16_t gain, uint32_t t, uint32_t addr);
void aDisableImpl(uint16_t outp, uint32_t b, uint32_t c);
void aPlayMP3Impl(const void *mp3file, u32 mp3size, void *out, int reset);
#define aDisable(pkt, o, b, c) aDisableImpl(o, b, c)
#define aClearBuffer(pkt, d, c) aClearBufferImpl(d, c)
#define aLoadBuffer(pkt, c, d, s) aLoadBufferImpl((void *)(s), d, c)
#define aSaveBuffer(pkt, c, s, d) aSaveBufferImpl(s, (int16_t *)(d), c)
#define aLoadADPCM(pkt, c, d) aLoadADPCMImpl(c, (int16_t *)(d))
#define aDMEMMove(pkt, i, o, c) aDMEMMoveImpl(i, o, c)
#define aSetLoop(pkt, a) aSetLoopImpl((void *)(a))
#define aADPCMdec(pkt, s, f, c, i, o) aADPCMdecImpl(f, (void *)(s), c, i, o)
#define aResample(pkt, s, f, p, i, o) aResampleImpl(f, p, (void *)(s), i, o)
#define aInterleave(pkt) aInterleaveImpl()
#define aMix(pkt, f, g, i, o) aMixImpl(f, g, i, o)
#define aEnvMixer(pkt, f, t, s) aEnvMixerImpl(f, (void *)(s), t)
#define aSetVolume(pkt, f, v, t, r) aSetVolumeImpl(f, v, t, r)
#define aPoleFilter(pkt, f, g, t, s) aPoleFilterImpl(f, g, t, s)
#define aPlayMP3(pkt, a, b, c, r) aPlayMP3Impl((void *)(a), b, (void *)(c), r)
#endif
+19
View File
@@ -0,0 +1,19 @@
#ifndef _IN_MOD_H
#define _IN_MOD_H
#include <PR/ultratypes.h>
#define MOD_CONFIG_FNAME "modconfig.txt"
struct animtableentry;
s32 modConfigLoad(const char *path);
s32 modTextureLoad(u16 num, void *dst, u32 dstSize);
s32 modAnimationLoadDescriptor(u16 num, struct animtableentry *anim);
void *modAnimationLoadData(u16 num);
void *modSequenceLoad(u16 num, u32 *outSize);
#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
@@ -0,0 +1,163 @@
#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
@@ -0,0 +1,50 @@
#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
@@ -0,0 +1,10 @@
#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
@@ -0,0 +1,74 @@
#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
+32
View File
@@ -0,0 +1,32 @@
#ifndef _IN_PREPROCESS_H
#define _IN_PREPROCESS_H
#include <PR/ultratypes.h>
typedef u8 *(*preprocessfunc)(u8 *data, u32 size, u32 *outSize);
u8* preprocessAnimations(u8 *data, u32 size, u32 *outSize);
u8* preprocessMpConfigs(u8 *data, u32 size, u32 *outSize);
u8* preprocessFont(u8 *data, u32 size, u32 *outSize);
u8* preprocessJpnFont(u8 *data, u32 size, u32 *outSize);
u8* preprocessALBankFile(u8 *data, u32 size, u32 *outSize);
u8 *preprocessALCMidiHdr(u8 *data, u32 size, u32 *outSize);
u8* preprocessSequences(u8 *data, u32 size, u32 *outSize);
u8* preprocessTexturesList(u8 *data, u32 size, u32 *outSize);
void preprocessBgSection1(u8* data, u32 size, u32 ofs);
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);
u32 preprocessBgRoom(u8* data, u32 size, u32 room_ofs);
u8 *preprocessLangFile(u8 *data, u32 size, u32 *outSize);
u8 *preprocessPadsFile(u8 *data, u32 size, u32 *outSize);
u8 *preprocessTilesFile(u8 *data, u32 size, u32 *outSize);
u8 *preprocessSetupFile(u8 *data, u32 size, u32 *outSize);
u8 *preprocessModelFile(u8 *data, u32 size, u32 *outSize);
u8 *preprocessGunFile(u8 *data, u32 size, u32 *outSize);
#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
+29
View File
@@ -0,0 +1,29 @@
#ifndef _IN_ROMDATA_H
#define _IN_ROMDATA_H
#include <PR/ultratypes.h>
extern u8 *g_RomFile;
extern u32 g_RomFileSize;
extern const char *g_RomName;
s32 romdataInit(void);
u8 *romdataFileLoad(s32 fileNum, u32 *outSize);
void romdataFilePreprocess(s32 fileNum, s32 loadType, u8 *data, u32 size, u32 *outSize);
void romdataFileFree(s32 fileNum);
const char *romdataFileGetName(s32 fileNum);
u8 *romdataFileGetData(s32 fileNum);
s32 romdataFileGetSize(s32 fileNum);
s32 romdataFileGetNumForName(const char *name);
u8 *romdataSegGetData(const char *segName);
u8 *romdataSegGetDataEnd(const char *segName);
u32 romdataSegGetSize(const char *segName);
u32 romdataFileGetEstimatedSize(const u32 size, const u32 loadtype);
s32 romdataCheckGbcRom(void);
#endif
+56
View File
@@ -0,0 +1,56 @@
#ifndef _IN_SYSTEM_H
#define _IN_SYSTEM_H
#ifdef __cplusplus
extern "C" {
#endif
#include <PR/ultratypes.h>
#define LOGFLAG_NOCON (1 << 6)
#define LOGFLAG_SHOWMSG (1 << 7)
enum loglevel {
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 sysInit(void);
s32 sysArgCheck(const char *arg);
const char *sysArgGetString(const char *arg);
s32 sysArgGetInt(const char *arg, s32 defval);
u64 sysGetMicroseconds(void);
f32 sysGetSeconds(void);
void sysFatalError(const char *fmt, ...) __attribute__((noreturn));
s32 sysLogIsOpen(void);
void sysLogPrintf(s32 level, const char *fmt, ...);
void sysGetExecutablePath(char *outPath, const u32 outLen);
void sysGetHomePath(char *outPath, const u32 outLen);
void *sysMemAlloc(const u32 size);
void *sysMemZeroAlloc(const u32 size);
void *sysMemRealloc(void *ptr, const u32 newSize);
void sysMemFree(void *ptr);
// hns is specified in 100ns units
void sysSleep(const s64 hns);
// yield CPU if supported (e.g. during a busy loop)
void sysCpuRelax(void);
void crashInit(void);
void crashShutdown(void);
#ifdef __cplusplus
}
#endif
#endif
+29
View File
@@ -0,0 +1,29 @@
#ifndef _IN_UTILS_H
#define _IN_UTILS_H
#define UTIL_MAX_TOKEN 1024
#include <PR/ultratypes.h>
char *strRightTrim(char *str);
char *strTrim(char *str);
char *strUnquote(char *str);
char *strParseToken(char *str, char *out, s32 *outCount);
char *strFmt(const char *fmt, ...);
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
+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
+80
View File
@@ -0,0 +1,80 @@
#ifndef _IN_VIDEO_H
#define _IN_VIDEO_H
#include <PR/ultratypes.h>
#include <PR/gbi.h>
// maximum framerate; if the game runs faster than this, things will break
#if PAL
#define VIDEO_MAX_FPS 200
#else
#define VIDEO_MAX_FPS 240
#endif
typedef struct {
s32 width;
s32 height;
} displaymode;
s32 videoInit(void);
void videoStartFrame(void);
void videoSubmitCommands(Gfx *cmds);
void videoClearScreen(void);
void videoEndFrame(void);
void *videoGetWindowHandle(void);
void videoUpdateNativeResolution(s32 w, s32 h);
s32 videoGetNativeWidth(void);
s32 videoGetNativeHeight(void);
s32 videoGetWidth(void);
s32 videoGetHeight(void);
f32 videoGetAspect(void);
s32 videoGetFullscreen(void);
s32 videoGetFullscreenMode(void);
s32 videoGetMaximizeWindow(void);
void videoSetMaximizeWindow(s32 fs);
s32 videoGetCenterWindow(void);
void videoSetCenterWindow(s32 center);
u32 videoGetTextureFilter(void);
s32 videoGetTextureFilter2D(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 videoGetAverageFPS(void);
f64 videoGetLastRenderTime(void);
void videoCapFramerate(s32 limit);
void videoSetWindowOffset(s32 x, s32 y);
void videoSetFullscreen(s32 fs);
void videoSetFullscreenMode(s32 mode);
void videoSetTextureFilter(u32 filter);
void videoSetTextureFilter2D(s32 filter);
void videoSetDetailTextures(s32 detail);
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);
s32 videoCreateFramebuffer(u32 w, u32 h, s32 upscale, s32 autoresize);
void videoSetFramebuffer(s32 target);
void videoResetFramebuffer(void);
void videoCopyFramebuffer(s32 dst, s32 src, s32 left, s32 top);
void videoResizeFramebuffer(s32 target, u32 w, u32 h, s32 upscale, s32 autoresize);
s32 videoFramebuffersSupported(void);
void videoResetTextureCache(void);
void videoFreeCachedTexture(const void *texptr);
void videoShutdown(void);
#endif
+75
View File
@@ -0,0 +1,75 @@
#include <PR/ultratypes.h>
#include <stdio.h>
#include <SDL.h>
#include "platform.h"
#include "config.h"
#include "audio.h"
#include "system.h"
static SDL_AudioDeviceID dev;
static const s16 *nextBuf;
static u32 nextSize = 0;
static s32 bufferSize = 512;
static s32 queueLimit = 8192;
s32 audioInit(void)
{
if (SDL_InitSubSystem(SDL_INIT_AUDIO) != 0) {
sysLogPrintf(LOG_ERROR, "SDL audio init error: %s", SDL_GetError());
return -1;
}
SDL_AudioSpec want, have;
SDL_zero(want);
want.freq = 22020; // TODO: this might cause trouble for some platforms
want.format = AUDIO_S16SYS;
want.channels = 2;
want.samples = bufferSize;
want.callback = NULL;
nextBuf = NULL;
dev = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0);
if (dev == 0) {
sysLogPrintf(LOG_ERROR, "SDL_OpenAudio error: %s", SDL_GetError());
return -1;
}
SDL_PauseAudioDevice(dev, 0);
return 0;
}
s32 audioGetBytesBuffered(void)
{
return SDL_GetQueuedAudioSize(dev);
}
s32 audioGetSamplesBuffered(void)
{
return audioGetBytesBuffered() / 4;
}
void audioSetNextBuffer(const s16 *buf, u32 len)
{
nextBuf = buf;
nextSize = len;
}
void audioEndFrame(void)
{
if (nextBuf && nextSize) {
if (audioGetSamplesBuffered() < queueLimit) {
SDL_QueueAudio(dev, nextBuf, nextSize);
}
nextBuf = NULL;
nextSize = 0;
}
}
PD_CONSTRUCTOR static void audioConfigInit(void)
{
configRegisterInt("Audio.BufferSize", &bufferSize, 0, 1 * 1024 * 1024);
configRegisterInt("Audio.QueueLimit", &queueLimit, 0, 1 * 1024 * 1024);
}
+300
View File
@@ -0,0 +1,300 @@
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#include <PR/ultratypes.h>
#include "fs.h"
#include "config.h"
#include "system.h"
#include "utils.h"
#define CONFIG_MAX_SECNAME 128
#define CONFIG_MAX_KEYNAME 256
#define CONFIG_MAX_SETTINGS 300
typedef enum {
CFG_NONE,
CFG_S32,
CFG_F32,
CFG_U32,
CFG_STR
} configtype;
struct configentry {
char key[CONFIG_MAX_KEYNAME + 1];
s32 seclen;
configtype type;
void *ptr;
union {
struct { f32 min_f32, max_f32; };
struct { s32 min_s32, max_s32; };
struct { u32 min_u32, max_u32; };
u32 max_str;
};
} settings[CONFIG_MAX_SETTINGS];
static s32 numSettings = 0;
static u8 configMaxWarningLogged = 0;
static inline s32 configClampInt(s32 val, s32 min, s32 max)
{
return (val < min) ? min : ((val > max) ? max : val);
}
static inline u32 configClampUInt(u32 val, u32 min, u32 max)
{
return (val < min) ? min : ((val > max) ? max : val);
}
static inline f32 configClampFloat(f32 val, f32 min, f32 max)
{
return (val < min) ? min : ((val > max) ? max : val);
}
static inline struct configentry *configFindEntry(const char *key)
{
for (s32 i = 0; i < numSettings; ++i) {
if (!strncasecmp(settings[i].key, key, CONFIG_MAX_KEYNAME)) {
return &settings[i];
}
}
return NULL;
}
static inline struct configentry *configAddEntry(const char *key)
{
if (numSettings < CONFIG_MAX_SETTINGS) {
struct configentry *cfg = &settings[numSettings++];
snprintf(cfg->key, CONFIG_MAX_KEYNAME, "%s", key);
const char *delim = strrchr(cfg->key, '.');
cfg->seclen = delim ? (delim - cfg->key) : 0;
return cfg;
}
if (!configMaxWarningLogged) {
sysLogPrintf(LOG_WARNING, "Maximum number of configuration entries exceeded: %d", CONFIG_MAX_SETTINGS);
configMaxWarningLogged = 1;
}
return NULL;
}
static inline struct configentry *configFindOrAddEntry(const char *key)
{
for (s32 i = 0; i < numSettings; ++i) {
if (!strncasecmp(settings[i].key, key, CONFIG_MAX_KEYNAME)) {
return &settings[i];
}
}
return configAddEntry(key);
}
static inline const char *configGetSection(char *sec, const struct configentry *cfg)
{
if (!cfg->seclen || cfg->seclen > CONFIG_MAX_SECNAME) {
strncpy(sec, cfg->key, CONFIG_MAX_SECNAME);
sec[CONFIG_MAX_SECNAME] = '\0';
return sec;
}
memcpy(sec, cfg->key, cfg->seclen);
sec[cfg->seclen] = '\0';
return sec;
}
void configRegisterInt(const char *key, s32 *var, s32 min, s32 max)
{
struct configentry *cfg = configFindOrAddEntry(key);
if (cfg) {
cfg->type = CFG_S32;
cfg->ptr = var;
cfg->min_s32 = min;
cfg->max_s32 = max;
}
}
void configRegisterUInt(const char* key, u32* var, u32 min, u32 max)
{
struct configentry* cfg = configFindOrAddEntry(key);
if (cfg) {
cfg->type = CFG_U32;
cfg->ptr = var;
cfg->min_u32 = min;
cfg->max_u32 = max;
}
}
void configRegisterFloat(const char *key, f32 *var, f32 min, f32 max)
{
struct configentry *cfg = configFindOrAddEntry(key);
if (cfg) {
cfg->type = CFG_F32;
cfg->ptr = var;
cfg->min_f32 = min;
cfg->max_f32 = max;
}
}
void configRegisterString(const char *key, char *var, u32 maxstr)
{
struct configentry *cfg = configFindOrAddEntry(key);
if (cfg) {
cfg->type = CFG_STR;
cfg->ptr = var;
cfg->max_str = maxstr;
}
}
static void configSetFromString(const char *key, const char *val)
{
struct configentry *cfg = configFindEntry(key);
if (!cfg) return;
s32 tmp_s32;
f32 tmp_f32;
u32 tmp_u32;
switch (cfg->type) {
case CFG_S32:
tmp_s32 = strtol(val, NULL, 0);
if (cfg->min_s32 < cfg->max_s32) {
tmp_s32 = configClampInt(tmp_s32, cfg->min_s32, cfg->max_s32);
}
*(s32 *)cfg->ptr = tmp_s32;
break;
case CFG_F32:
tmp_f32 = strtof(val, NULL);
if (cfg->min_f32 < cfg->max_f32) {
tmp_f32 = configClampFloat(tmp_f32, cfg->min_f32, cfg->max_f32);
}
*(f32 *)cfg->ptr = tmp_f32;
break;
case CFG_U32:
tmp_u32 = strtoul(val, NULL, 0);
if (cfg->min_u32 < cfg->max_u32) {
tmp_u32 = configClampUInt(tmp_u32, cfg->min_u32, cfg->max_u32);
}
*(u32*)cfg->ptr = tmp_u32;
break;
case CFG_STR:
strncpy(cfg->ptr, val, cfg->max_str ? cfg->max_str - 1 : 4096);
break;
default:
break;
}
}
static void configSaveEntry(struct configentry *cfg, FILE *f)
{
switch (cfg->type) {
case CFG_S32:
if (cfg->min_s32 < cfg->max_s32) {
*(s32 *)cfg->ptr = configClampInt(*(s32 *)cfg->ptr, cfg->min_s32, cfg->max_s32);
}
fprintf(f, "%s=%d\n", cfg->key + cfg->seclen + 1, *(s32 *)cfg->ptr);
break;
case CFG_F32:
if (cfg->min_f32 < cfg->max_f32) {
*(f32 *)cfg->ptr = configClampFloat(*(f32 *)cfg->ptr, cfg->min_f32, cfg->max_f32);
}
fprintf(f, "%s=%f\n", cfg->key + cfg->seclen + 1, *(f32 *)cfg->ptr);
break;
case CFG_U32:
if (cfg->min_u32 < cfg->max_u32) {
*(u32*)cfg->ptr = configClampUInt(*(u32*)cfg->ptr, cfg->min_u32, cfg->max_u32);
}
fprintf(f, "%s=%u\n", cfg->key + cfg->seclen + 1, *(u32 *)cfg->ptr);
break;
case CFG_STR:
fprintf(f, "%s=%s\n", cfg->key + cfg->seclen + 1, (char *)cfg->ptr);
break;
default:
break;
}
}
s32 configSave(const char *fname)
{
FILE *f = fsFileOpenWrite(fname);
if (!f) {
return 0;
}
char tmpSec[CONFIG_MAX_SECNAME + 1] = { 0 };
char curSec[CONFIG_MAX_SECNAME + 1] = { 0 };
configGetSection(curSec, &settings[0]);
fprintf(f, "[%s]\n", curSec);
for (s32 i = 0; i < numSettings; ++i) {
struct configentry *cfg = &settings[i];
configGetSection(tmpSec, cfg);
if (strncmp(curSec, tmpSec, CONFIG_MAX_SECNAME) != 0) {
fprintf(f, "\n[%s]\n", tmpSec);
strncpy(curSec, tmpSec, CONFIG_MAX_SECNAME);
}
configSaveEntry(cfg, f);
}
fsFileFree(f);
return 1;
}
s32 configLoad(const char *fname)
{
FILE *f = fsFileOpenRead(fname);
if (!f) {
return 0;
}
char curSec[CONFIG_MAX_SECNAME + 1] = { 0 };
char keyBuf[CONFIG_MAX_SECNAME * 2 + 2] = { 0 }; // SECTION + . + KEY + \0
char token[UTIL_MAX_TOKEN + 1] = { 0 };
char lineBuf[2048] = { 0 };
char *line = lineBuf;
s32 lineLen = 0;
while (fgets(lineBuf, sizeof(lineBuf), f)) {
line = lineBuf;
line = strParseToken(line, token, NULL);
if (token[0] == '[' && token[1] == '\0') {
// section; get name
line = strParseToken(line, token, NULL);
if (!token[0]) {
sysLogPrintf(LOG_ERROR, "configLoad: malformed section line: %s", lineBuf);
continue;
}
strncpy(curSec, token, CONFIG_MAX_SECNAME);
// eat ]
line = strParseToken(line, token, NULL);
if (token[0] != ']' || token[1] != '\0') {
sysLogPrintf(LOG_ERROR, "configLoad: malformed section line: %s", lineBuf);
}
} else if (token[0]) {
// probably a key=value pair; append key name to section name
snprintf(keyBuf, sizeof(keyBuf) - 1, "%s.%s", curSec, token);
// eat =
line = strParseToken(line, token, NULL);
if (token[0] != '=' || token[1] != '\0') {
sysLogPrintf(LOG_ERROR, "configLoad: malformed keyvalue line: %s", lineBuf);
continue;
}
// the rest of the line is the value
line = strTrim(line);
if (line[0] == '"') {
line = strUnquote(line);
}
configSetFromString(keyBuf, line);
}
}
fsFileFree(f);
return 1;
}
void configInit(void)
{
if (fsFileSize(CONFIG_PATH) > 0) {
configLoad(CONFIG_PATH);
}
}
+220
View File
@@ -0,0 +1,220 @@
#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;
g_MenuKeyboardPlayer = -1;
if (conOpen) {
inputClearLastTextChar();
inputStartTextInput();
} else {
inputStopTextInput();
}
}
conButton = button;
if (conOpen) {
if (inputTextHandler(conInput, CON_COLS, &conInputCol, false)) {
if (g_NetMode) {
netChat(NULL, conInput);
}
conInput[0] = '\0';
conInputCol = 0;
}
}
}
s32 conIsOpen(void)
{
return conOpen;
}
+361
View File
@@ -0,0 +1,361 @@
#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <SDL.h>
#include <PR/ultratypes.h>
#include "system.h"
#include "platform.h"
#define CRASH_LOG_FNAME "pd.crash.log"
#define CRASH_MAX_MSG 8192
#define CRASH_MAX_SYM 256
#define CRASH_MAX_FRAMES 32
#define CRASH_MSG(...) \
if (msglen < CRASH_MAX_MSG) msglen += snprintf(msg + msglen, CRASH_MAX_MSG - msglen, __VA_ARGS__)
#if defined(PLATFORM_WIN32)
#include <windows.h>
#include <dbghelp.h>
#include <inttypes.h>
#include <excpt.h>
// NOTE: game builds with gcc, which means we have no PDBs for the windows version
// this means that you generally won't get any symbol names in the main executable
static LPTOP_LEVEL_EXCEPTION_FILTER prevExFilter;
static void *crashGetModuleBase(const void *addr)
{
HMODULE h = NULL;
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, addr, &h);
return (void *)h;
}
static void crashStackTrace(char *msg, PEXCEPTION_POINTERS exinfo)
{
CONTEXT context = *exinfo->ContextRecord;
HANDLE process = GetCurrentProcess();
HANDLE thread = GetCurrentThread();
SymSetOptions(SymGetOptions() | SYMOPT_DEBUG | SYMOPT_LOAD_LINES);
SymInitialize(process, NULL, TRUE);
STACKFRAME64 stackframe;
memset(&stackframe, 0, sizeof(stackframe));
DWORD image;
#ifdef PLATFORM_X86
image = IMAGE_FILE_MACHINE_I386;
stackframe.AddrPC.Offset = context.Eip;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.Ebp;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.Esp;
stackframe.AddrStack.Mode = AddrModeFlat;
#elif defined(PLATFORM_X86_64)
image = IMAGE_FILE_MACHINE_AMD64;
stackframe.AddrPC.Offset = context.Rip;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.Rsp;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.Rsp;
stackframe.AddrStack.Mode = AddrModeFlat;
#else
snprintf(msg, CRASH_MAX_MSG, "no stack trace available on this arch\n");
return;
#endif
DWORD disp = 0;
DWORD64 disp64 = 0;
IMAGEHLP_LINE64 line;
DWORD msglen = 0;
CRASH_MSG("EXCEPTION: 0x%08lx\n", exinfo->ExceptionRecord->ExceptionCode);
CRASH_MSG("PC: %p", exinfo->ExceptionRecord->ExceptionAddress);
if (SymGetLineFromAddr64(process, (uintptr_t)exinfo->ExceptionRecord->ExceptionAddress, &disp, &line)) {
CRASH_MSG(": %s:%lu+%lu", line.FileName, line.LineNumber, disp);
}
CRASH_MSG("\nMODULE: [%p]\n", crashGetModuleBase(exinfo->ExceptionRecord->ExceptionAddress));
CRASH_MSG("MAIN MODULE: [%p]\n", crashGetModuleBase(crashInit));
CRASH_MSG("\nBACKTRACE:\n");
char symbuf[sizeof(SYMBOL_INFO) + CRASH_MAX_SYM * sizeof(TCHAR)];
PSYMBOL_INFO sym = (PSYMBOL_INFO)symbuf;
sym->SizeOfStruct = sizeof(*sym);
sym->MaxNameLen = CRASH_MAX_SYM;
s32 i;
for (i = 0; i < CRASH_MAX_FRAMES; ++i) {
const BOOL res = StackWalk64(image, process, thread, &stackframe, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL);
if (!res) {
break;
}
CRASH_MSG("#%02d: %p", i, (void *)(uintptr_t)stackframe.AddrPC.Offset);
if (SymFromAddr(process, stackframe.AddrPC.Offset, &disp64, sym)) {
CRASH_MSG(": %s+%llu", sym->Name, disp64);
} else if (process, stackframe.AddrPC.Offset) {
const uintptr_t modbase = (uintptr_t)crashGetModuleBase((void *)(uintptr_t)stackframe.AddrPC.Offset);
const uintptr_t modofs = (uintptr_t)stackframe.AddrPC.Offset - modbase;
CRASH_MSG(": [%p]+%p", (void *)modbase, (void *)modofs);
}
if(SymGetLineFromAddr64(process, stackframe.AddrPC.Offset, &disp, &line)) {
CRASH_MSG(" (%s:%lu+%lu)", line.FileName, line.LineNumber, disp);
}
CRASH_MSG("\n");
}
if (i <= 1) {
CRASH_MSG("no information\n");
} else if (i == CRASH_MAX_FRAMES) {
CRASH_MSG("...\n");
}
SymCleanup(process);
}
static long __stdcall crashHandler(PEXCEPTION_POINTERS exinfo)
{
char msg[CRASH_MAX_MSG + 1] = { 0 };
if (IsDebuggerPresent()) {
if (prevExFilter) {
return prevExFilter(exinfo);
}
return EXCEPTION_CONTINUE_EXECUTION;
}
sysLogPrintf(LOG_ERROR, "FATAL: Crashed: PC=%p CODE=0x%08lx", exinfo->ExceptionRecord->ExceptionAddress, exinfo->ExceptionRecord->ExceptionCode);
fflush(stderr);
fflush(stdout);
crashStackTrace(msg, exinfo);
// open log file for the crash dump if one hasn't been opened yet
if (!sysLogIsOpen()) {
FILE *f = fopen(CRASH_LOG_FNAME, "wb");
if (f) {
fprintf(f, "Crash!\n\n%s", msg);
fclose(f);
}
}
sysFatalError("Crash!\n\n%s", msg);
return EXCEPTION_CONTINUE_EXECUTION;
}
#elif defined(PLATFORM_LINUX)
#include <ucontext.h>
#include <signal.h>
#include <execinfo.h>
#include <unistd.h>
#include <ctype.h>
#include <dlfcn.h>
#include <sys/fcntl.h>
static struct sigaction prevSigAction;
static s32 crashIsDebuggerPresent(void)
{
static s32 result = -1;
if (result >= 0) {
return result;
}
char buf[4096] = { 0 };
int fd = open("/proc/self/status", O_RDONLY);
if (fd < 0) {
result = 0;
return 0;
}
int rx = read(fd, buf, sizeof(buf) - 1);
close(fd);
if (rx <= 0) {
result = 0;
return 0;
}
buf[rx] = 0;
char *str = strstr(buf, "TracerPid:");
if (!str) {
result = 0;
return 0;
}
str += 10;
while (*str && !isdigit(*str)) {
if (*str == '\n') {
result = 0;
return 0;
}
++str;
}
result = (atoi(str) != 0);
return result;
}
static void *crashGetModuleBase(const void *addr)
{
Dl_info info;
if (dladdr(addr, &info)) {
return info.dli_fbase;
}
return NULL;
}
static void crashStackTrace(char *msg, s32 sig, void *pc)
{
u32 msglen = 0;
void *frames[CRASH_MAX_FRAMES] = { NULL };
const s32 nframes = backtrace(frames, CRASH_MAX_FRAMES);
if (nframes <= 0) {
CRASH_MSG("no information\n");
return;
}
char **strings = backtrace_symbols(frames, nframes);
CRASH_MSG("SIGNAL: %d\n", sig);
CRASH_MSG("PC: ");
if (pc) {
CRASH_MSG("%p\n", pc);
} else if (strings) {
CRASH_MSG("%s\n", strings[0]);
} else {
CRASH_MSG("%p\n", frames[0]);
}
CRASH_MSG("MODULE: %p\n", crashGetModuleBase(frames[0]));
CRASH_MSG("MAIN MODULE: %p\n", crashGetModuleBase(crashInit));
CRASH_MSG("\nBACKTRACE:\n");
s32 i;
for (i = 0; i < nframes; ++i) {
CRASH_MSG("#%02d: ", i);
if (strings && strings[i]) {
CRASH_MSG("%s\n", strings[i]);
} else {
CRASH_MSG("%p\n", frames[i]);
}
}
if (i == CRASH_MAX_FRAMES) {
CRASH_MSG("...\n");
} else if (i <= 1) {
CRASH_MSG("no information\n");
}
free(strings);
}
static void crashHandler(s32 sig, siginfo_t *siginfo, void *ctx)
{
char msg[CRASH_MAX_MSG + 1] = { 0 };
if (crashIsDebuggerPresent()) {
return;
}
void *pc = NULL;
if (ctx) {
ucontext_t *ucontext = (ucontext_t *)ctx;
#ifdef PLATFORM_X86
pc = (void *)ucontext->uc_mcontext.gregs[REG_EIP];
#elif defined(PLATFORM_X86_64)
pc = (void *)ucontext->uc_mcontext.gregs[REG_RIP];
#elif defined(PLATFORM_ARM) && defined(PLATFORM_64BIT)
pc = (void *)ucontext->uc_mcontext.pc;
#elif defined(PLATFORM_ARM)
pc = (void *)ucontext->uc_mcontext.arm_pc;
#endif
}
sysLogPrintf(LOG_ERROR, "FATAL: Crashed: PC=%p SIGNAL=%d", pc, sig);
fflush(stderr);
fflush(stdout);
crashStackTrace(msg, sig, pc);
sysFatalError("Crash!\n\n%s", msg);
}
#endif
s32 g_CrashEnabled = 0;
static char crashMsg[1024];
void crashInit(void)
{
#ifdef PLATFORM_WIN32
SetErrorMode(SEM_FAILCRITICALERRORS);
prevExFilter = SetUnhandledExceptionFilter(crashHandler);
g_CrashEnabled = 1;
#elif defined(PLATFORM_LINUX)
struct sigaction sigact = { 0 };
sigact.sa_flags = SA_SIGINFO | SA_ONSTACK;
sigact.sa_sigaction = crashHandler;
sigaction(SIGSEGV, &sigact, &prevSigAction);
sigaction(SIGABRT, &sigact, &prevSigAction);
sigaction(SIGBUS, &sigact, &prevSigAction);
sigaction(SIGILL, &sigact, &prevSigAction);
g_CrashEnabled = 1;
#endif
}
void crashShutdown(void)
{
if (!g_CrashEnabled) {
return;
}
#ifdef PLATFORM_WIN32
if (prevExFilter) {
SetUnhandledExceptionFilter(prevExFilter);
}
#elif defined(PLATFORM_LINUX)
sigaction(SIGSEGV, &prevSigAction, NULL);
sigaction(SIGABRT, &prevSigAction, NULL);
sigaction(SIGBUS, &prevSigAction, NULL);
sigaction(SIGILL, &prevSigAction, NULL);
#endif
g_CrashEnabled = 0;
}
void crashCreateThread(void)
{
}
void crashSetMessage(char *string)
{
}
void crashReset(void)
{
}
void crashAppendChar(char c)
{
}
+294
View File
@@ -0,0 +1,294 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/stat.h>
#include <PR/ultratypes.h>
#include "config.h"
#include "system.h"
#include "platform.h"
#include "utils.h"
#include "fs.h"
#ifdef PLATFORM_WIN32
#include <direct.h>
#endif
#define DEFAULT_BASEDIR_NAME "data"
static char baseDir[FS_MAXPATH + 1]; // replaces $B
static char modDir[FS_MAXPATH + 1]; // replaces $M
static char saveDir[FS_MAXPATH + 1]; // replaces $S
static char homeDir[FS_MAXPATH + 1]; // replaces $H
static char exeDir[FS_MAXPATH + 1]; // replaces $E
static s32 fsPathIsWritable(const char *path)
{
#ifdef PLATFORM_WIN32
// on windows access() on directories will only check if the directory exists, so
char tmp[FS_MAXPATH + 1] = { 0 };
snprintf(tmp, sizeof(tmp), "%s/.tmp", path);
FILE *f = fopen(tmp, "wb");
if (f) {
fclose(f);
remove(tmp);
return 1;
}
return 0;
#else
return (access(path, W_OK) == 0);
#endif
}
s32 fsPathIsAbsolute(const char *path)
{
return (path[0] == '/' || (isalpha(path[0]) && path[1] == ':'));
}
s32 fsPathIsCwdRelative(const char *path)
{
// ., .., ./, ../
return (path[0] == '.' && (path[1] == '.' || path[1] == '/' || path[1] == '\\' || path[1] == '\0'));
}
const char *fsFullPath(const char *relPath)
{
static char pathBuf[FS_MAXPATH + 1];
if (relPath[0] == '$') {
// expandable placeholder $X; will be replaced with the corresponding path, if any
const char *expStr = NULL;
switch (relPath[1]) {
case 'E': expStr = exeDir; break;
case 'H': expStr = homeDir; break;
case 'M': expStr = modDir; break;
case 'B': expStr = baseDir; break;
case 'S': expStr = saveDir; break;
default: break;
}
if (expStr) {
const u32 len = strlen(expStr);
if (len > 0) {
memcpy(pathBuf, expStr, len);
strncpy(pathBuf + len, relPath + 2, FS_MAXPATH - len);
return pathBuf;
}
}
// couldn't expand anything, return as is
return relPath;
} else if (!baseDir[0] || fsPathIsAbsolute(relPath) || fsPathIsCwdRelative(relPath)) {
// user explicitly wants working directory or this is an absolute path or we have no baseDir set up yet
return relPath;
}
// path relative to mod or base dir; this will be a read request, so check where the file actually is
if (modDir[0]) {
snprintf(pathBuf, FS_MAXPATH, "%s/%s", modDir, relPath);
if (fsFileSize(pathBuf) >= 0) {
return pathBuf;
}
}
// fall back to basedir
snprintf(pathBuf, FS_MAXPATH, "%s/%s", baseDir, relPath);
return pathBuf;
}
s32 fsInit(void)
{
sysGetExecutablePath(exeDir, FS_MAXPATH);
// if this is set, default to exe path for everything
const s32 portable = sysArgCheck("--portable");
if (portable) {
strcpy(homeDir, exeDir);
} else {
sysGetHomePath(homeDir, FS_MAXPATH);
}
// get path to base dir and expand it if needed
const char *path = sysArgGetString("--basedir");
if (!path) {
// check if there's a `data` directory in working directory or homeDir, otherwise default to exe directory
path = "$E/" DEFAULT_BASEDIR_NAME;
if (!portable) {
if (fsFileSize("./" DEFAULT_BASEDIR_NAME) >= 0) {
path = "./" DEFAULT_BASEDIR_NAME;
} else if (fsFileSize("$H/" DEFAULT_BASEDIR_NAME)) {
path = "$H/" DEFAULT_BASEDIR_NAME;
}
}
}
strncpy(baseDir, fsFullPath(path), FS_MAXPATH);
// get path to mod dir and expand it if needed
// mod directory is overlaid on top of base directory
path = sysArgGetString("--moddir");
if (path) {
if (fsPathIsAbsolute(path) || fsPathIsCwdRelative(path) || path[0] == '$') {
// path is explicit; check as-is
if (fsFileSize(path) >= 0) {
strncpy(modDir, fsFullPath(path), FS_MAXPATH);
}
} else {
// path is relative to workdir; try to find it
const char *priority[] = { ".", "$E", "$H" };
for (s32 i = 0; i < 2 + (portable != 0); ++i) {
char *tmp = strFmt("%s/%s", priority[i], path);
if (fsFileSize(tmp) >= 0) {
strncpy(modDir, fsFullPath(tmp), FS_MAXPATH);
break;
}
}
}
if (!modDir[0]) {
sysLogPrintf(LOG_WARNING, "could not find specified moddir `%s`", path);
}
}
// get path to save dir and expand it if needed
path = sysArgGetString("--savedir");
if (!path) {
if (portable) {
path = "$E";
} else {
#if defined(PLATFORM_LINUX) || defined(PLATFORM_OSX)
// check if there's a config in the working directory, otherwise default to homeDir
if (fsFileSize("./" CONFIG_FNAME) >= 0) {
path = ".";
} else {
path = "$H";
}
#else
// check if working directory is writable, otherwise default to homeDir
if (fsPathIsWritable("./")) {
path = ".";
} else {
sysLogPrintf(LOG_WARNING, "cannot write to working directory, will use %s for saves instead", homeDir);
path = "$H";
}
#endif
}
}
strncpy(saveDir, fsFullPath(path), FS_MAXPATH);
if (modDir[0]) {
sysLogPrintf(LOG_NOTE, " mod dir: %s", modDir);
}
sysLogPrintf(LOG_NOTE, "base dir: %s", baseDir);
sysLogPrintf(LOG_NOTE, "save dir: %s", saveDir);
return 0;
}
const char *fsGetModDir(void)
{
return modDir[0] ? modDir : NULL;
}
s32 fsFileLoadTo(const char *name, void *dst, u32 dstSize)
{
const char *fullName = fsFullPath(name);
FILE *f = fopen(fullName, "rb");
if (!f) {
return -1;
}
fseek(f, 0, SEEK_END);
const s32 size = ftell(f);
fseek(f, 0, SEEK_SET);
if (size < 0) {
sysLogPrintf(LOG_ERROR, "fsFileLoadTo: empty file or invalid size (%d): %s", size, fullName);
fclose(f);
return -1;
}
if ((u32)size > dstSize) {
sysLogPrintf(LOG_ERROR, "fsFileLoadTo: file too big for buffer (%u > %u): %s", size, dstSize, fullName);
fclose(f);
return -1;
}
fread(dst, 1, size, f);
fclose(f);
return size;
}
void *fsFileLoad(const char *name, u32 *outSize)
{
const char *fullName = fsFullPath(name);
FILE *f = fopen(fullName, "rb");
if (!f) {
sysLogPrintf(LOG_ERROR, "fsFileLoad: could not find file: %s", fullName);
return NULL;
}
fseek(f, 0, SEEK_END);
const s32 size = ftell(f);
fseek(f, 0, SEEK_SET);
if (size < 0) {
sysLogPrintf(LOG_ERROR, "fsFileLoad: empty file or invalid size (%d): %s", size, fullName);
fclose(f);
return NULL;
}
void *buf = NULL;
if (size) {
buf = sysMemZeroAlloc(size + 1); // sick hack for a free null terminator
if (!buf) {
sysLogPrintf(LOG_ERROR, "fsFileLoad: could not alloc %d bytes for file: %s", size, fullName);
fclose(f);
return NULL;
}
fread(buf, 1, size, f);
}
fclose(f);
if (outSize) {
*outSize = size;
}
return buf;
}
s32 fsFileSize(const char *name)
{
const char *fullName = fsFullPath(name);
struct stat st;
if (stat(fullName, &st) < 0) {
return -1;
} else {
return st.st_size;
}
}
FILE *fsFileOpenWrite(const char *name)
{
return fopen(fsFullPath(name), "wb");
}
FILE *fsFileOpenRead(const char *name)
{
return fopen(fsFullPath(name), "rb");
}
void fsFileFree(FILE *f)
{
fclose(f);
}
s32 fsCreateDir(const char *path)
{
#ifdef PLATFORM_WIN32
return _mkdir(fsFullPath(path));
#else
return mkdir(fsFullPath(path), 0777);
#endif
}
+1543
View File
File diff suppressed because it is too large. Load diff
+487
View File
@@ -0,0 +1,487 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <PR/os_internal.h>
#include <PR/rcp.h>
#include "platform.h"
#include "system.h"
#include "input.h"
#include "video.h"
#include "audio.h"
#include "fs.h"
#define EEPROM_SIZE (EEP16K_MAXBLOCKS * 8)
#define EEPROM_FNAME "eeprom.bin"
#define EEPROM_PATH "$S/" EEPROM_FNAME
#define OS_COUNTER_RATE 46875000ULL
#define OS_COUNTER_NUM (OS_COUNTER_RATE / 1000ULL)
#define OS_COUNTER_DEN (1000000ULL / 1000ULL)
u64 osClockRate = OS_CLOCK_RATE;
u32 osMemSize = 16 * 1024 * 1024; /* expansion pak installed plus some extra */
s32 osTvType = OS_TV_NTSC; /* 0 = PAL, 1 = NTSC, 2 = MPAL */
s32 osResetType = 0; /* 0 = cold reset */
s32 osViClock = VI_NTSC_CLOCK;
static u8 eeprom[EEPROM_SIZE];
static char eepromPath[FS_MAXPATH + 1];
static s32 eepromLoaded = 0;
/* Time */
OSTime osGetTime(void)
{
// u64 should be enough to last a while
return (sysGetMicroseconds() * OS_COUNTER_NUM) / OS_COUNTER_DEN;
}
u32 osGetCount(void)
{
return (u32)osGetTime();
}
/* Thread */
void osCreateThread(OSThread *thrd, OSId id, void (*entry)(void *), void *arg, void *sp, OSPri p)
{
thrd->id = id;
thrd->state = OS_STATE_STOPPED;
}
void osDestroyThread(OSThread *thrd)
{
thrd->id = 0;
thrd->state = 0;
}
void osYieldThread(void)
{
}
void osStartThread(OSThread *thrd)
{
thrd->state = OS_STATE_RUNNING;
}
void osStopThread(OSThread *thrd)
{
thrd->state = OS_STATE_STOPPED;
}
OSPri osGetThreadPri(OSThread *thrd)
{
return 0;
}
void osSetThreadPri(OSThread *thrd, OSPri pri)
{
}
/* Mesg */
void osCreateMesgQueue(OSMesgQueue *mq, OSMesg *msgBuf, s32 count)
{
mq->validCount = 0;
mq->first = 0;
mq->msgCount = count;
mq->msg = msgBuf;
}
void osSetEventMesg(OSEvent e, OSMesgQueue *mq, OSMesg msg)
{
}
s32 osSendMesg(OSMesgQueue *mq, OSMesg msg, s32 flag)
{
return 0;
}
s32 osRecvMesg(OSMesgQueue *mq, OSMesg *msg, s32 flag)
{
return 0;
}
/* Vi */
void osCreateViManager(OSPri pri)
{
}
void osViSetMode(OSViMode *mode)
{
}
void osViSetEvent(OSMesgQueue *mq, OSMesg msg, u32 retraceCount)
{
}
void osViBlack(u8 active)
{
if (active) {
videoClearScreen();
}
}
void osViSetSpecialFeatures(u32 func)
{
}
void osViSwapBuffer(void *vaddr)
{
}
void osViSetXScale(f32 value)
{
}
void osViSetYScale(f32 value)
{
}
/* Ai */
s32 osAiSetFrequency(u32 frequency)
{
// we can allow for any freq
return (s32)frequency;
}
u32 osAiGetLength(void)
{
return audioGetBytesBuffered();
}
s32 osAiSetNextBuffer(void *bufPtr, u32 size)
{
audioSetNextBuffer(bufPtr, size);
return 0;
}
/* Cont */
s32 osContInit(OSMesgQueue *mesgq, u8 *bitpattern, OSContStatus *data)
{
if (bitpattern) {
*bitpattern = inputControllerMask();
}
if (data) {
osContGetQuery(data);
}
return 0;
}
s32 osContStartReadData(OSMesgQueue *mesgq)
{
osSendMesg(mesgq, (OSMesg)0, OS_MESG_NOBLOCK);
return 0;
}
void osContGetReadData(OSContPad *pad)
{
// game always passes in an array of 4 OSContPads
for (s32 i = 0; i < MAXCONTROLLERS; ++i, ++pad) {
pad->button = 0;
pad->stick_x = 0;
pad->stick_y = 0;
pad->rstick_x = 0;
pad->rstick_y = 0;
if (inputReadController(i, pad) < 0) {
pad->errnum = CONT_NO_RESPONSE_ERROR;
} else {
pad->errnum = 0;
}
}
}
s32 osContStartQuery(OSMesgQueue *mq)
{
return 0;
}
void osContGetQuery(OSContStatus *status)
{
// also always 4 status structs here
for (s32 i = 0; i < MAXCONTROLLERS; ++i, ++status) {
if (inputControllerConnected(i)) {
status->errnum = 0;
status->type = CONT_ABSOLUTE;
status->status = CONT_CARD_ON;
} else {
status->errnum = CONT_NO_RESPONSE_ERROR;
status->type = 0;
status->status = 0;
}
}
}
/* Motor */
s32 osMotorProbe(OSMesgQueue *ctrlrqueue, OSPfs* pfs, s32 channel)
{
if (pfs && inputRumbleSupported(channel)) {
pfs->queue = ctrlrqueue;
pfs->channel = channel;
pfs->activebank = 0xff;
pfs->status = PFS_MOTOR_INITIALIZED;
return 0;
}
return PFS_ERR_NOPACK;
}
s32 __osMotorAccess(OSPfs *pfs, s32 cmd)
{
if (!pfs || pfs->channel < 0 || pfs->channel >= INPUT_MAX_CONTROLLERS) {
return PFS_ERR_NOPACK;
}
const f32 strength = (f32)(cmd == MOTOR_START);
inputRumble(pfs->channel, strength, 5.f); // hope someone turns it off in those 5 seconds
return 0;
}
/* Eeprom */
static inline void osEepromSetPath(void)
{
const char *extPath = sysArgGetString("--eeprom-file");
if (extPath && extPath[0]) {
if (extPath[0] == '$' || fsPathIsAbsolute(extPath) || fsPathIsCwdRelative(extPath)) {
strncpy(eepromPath, extPath, FS_MAXPATH);
} else {
// just a filename, look for it in the save dir
snprintf(eepromPath, FS_MAXPATH, "$S/%s", extPath);
}
} else {
strncpy(eepromPath, EEPROM_PATH, FS_MAXPATH);
}
}
static inline void osEeepromLoad(const char *fname)
{
if (!eepromLoaded) {
eepromLoaded = 1;
FILE *fp = fsFileOpenRead(fname);
if (fp) {
fread(eeprom, 1, EEPROM_SIZE, fp);
fsFileFree(fp);
} else {
sysLogPrintf(LOG_NOTE, "could not read EEPROM from `%s`: %s", fsFullPath(fname), strerror(errno));
}
}
}
static inline void osEeepromSave(const char *fname)
{
FILE* fp = fsFileOpenWrite(fname);
if (fp) {
fwrite(eeprom, 1, EEPROM_SIZE, fp);
fsFileFree(fp);
} else {
sysLogPrintf(LOG_ERROR, "could not save EEPROM to `%s`: %s", fsFullPath(fname), strerror(errno));
}
}
s32 osEepromProbe(OSMesgQueue *mq)
{
return EEPROM_TYPE_16K;
}
s32 osEepromLongRead(OSMesgQueue *mq, u8 address, u8 *buffer, int nbytes)
{
if (!eepromPath[0]) {
osEepromSetPath();
}
osEeepromLoad(eepromPath);
memcpy(buffer, eeprom + address * 8, nbytes);
return 0;
}
s32 osEepromLongWrite(OSMesgQueue *mq, u8 address, u8 *buffer, int nbytes)
{
if (!eepromPath[0]) {
osEepromSetPath();
}
osEeepromLoad(eepromPath);
memcpy(eeprom + address * 8, buffer, nbytes);
osEeepromSave(eepromPath);
return 0;
}
/* Pfs */
s32 osPfsIsPlug(OSMesgQueue *queue, u8 *pattern)
{
if (pattern) {
*pattern = 0;
for (s32 i = 0; i < MAXCONTROLLERS; ++i) {
if (inputRumbleSupported(i)) {
*pattern |= 1 << i;
}
}
}
return 0;
}
s32 osPfsInitPak(OSMesgQueue *queue, OSPfs *pfs, s32 channel, s32 *arg3)
{
// if rumble is supported, indicate that we have a rumble pak instead
return inputRumbleSupported(channel) ? PFS_ERR_DEVICE : PFS_ERR_NOPACK;
}
s32 osPfsChecker(OSPfs *pfs)
{
return PFS_ERR_NOPACK;
}
s32 osPfsFreeBlocks(OSPfs *pfs, s32 *remaining)
{
return PFS_ERR_NOPACK;
}
s32 osPfsNumFiles(OSPfs *pfs, s32 *max_files, s32 *files_used)
{
return PFS_ERR_NOPACK;
}
s32 osPfsAllocateFile(OSPfs *pfs, u16 company_code, u32 game_code, u8 *game_name, u8 *ext_name, int num_bytes, s32 *file_no)
{
return PFS_ERR_NOPACK;
}
s32 osPfsFindFile(OSPfs *pfs, u16 company_code, u32 game_code, u8 *game_name, u8 *ext_name, s32 *file_no)
{
return PFS_ERR_NOPACK;
}
s32 osPfsDeleteFile(OSPfs *pfs, u16 company_code, u32 game_code, u8 *game_name, u8 *ext_name)
{
return PFS_ERR_NOPACK;
}
s32 osPfsReSizeFile(OSPfs *pfs, u16 company_code, u32 game_code, u8 *game_name, u8 *ext_name, int length)
{
return PFS_ERR_NOPACK;
}
s32 osPfsFileState(OSPfs *pfs, s32 fileNo, OSPfsState *state)
{
return PFS_ERR_NOPACK;
}
s32 osPfsReadWriteFile(OSPfs* pfs, s32 fileNo, u8 flag, int offset, int size, u8* data)
{
return PFS_ERR_NOPACK;
}
/* Gbpak */
s32 osGbpakInit(OSMesgQueue *queue, OSPfs *pfs, s32 ch)
{
return PFS_ERR_NOPACK;
}
s32 osGbpakPower(OSPfs *pfs, s32 flag)
{
return PFS_ERR_NOPACK;
}
s32 osGbpakReadWrite(OSPfs *pfs, u16 flag, u16 addr, u8 *buf, u16 size)
{
return PFS_ERR_NOPACK;
}
s32 osGbpakReadId(OSPfs *pfs, OSGbpakId *id, u8 *status)
{
return PFS_ERR_NOPACK;
}
/* Misc */
void osWritebackDCacheAll(void)
{
}
void osWritebackDCache(void *a, s32 b)
{
}
void osInvalDCache(void *a, s32 b)
{
}
s32 osPiStartDma(OSIoMesg *mb, s32 priority, s32 direction, uintptr_t devAddr, void *vAddr, u32 nbytes, OSMesgQueue *mq)
{
memcpy(vAddr, (const void *)devAddr, nbytes);
return 0;
}
s32 osPiReadIo(u32 devaddr, u32 *data)
{
return 0;
}
uintptr_t osVirtualToPhysical(void *addr)
{
return (uintptr_t)addr;
}
u32 osGetMemSize(void)
{
return osMemSize;
}
OSIntMask osGetIntMask(void)
{
return 0;
}
OSIntMask osSetIntMask(OSIntMask mask)
{
return 0;
}
/* libc compatibility wrappers */
#ifndef PLATFORM_OSX
void bzero(void *ptr, size_t size)
{
memset(ptr, 0, size);
}
void bcopy(const void *src, void *dst, size_t n)
{
memcpy(dst, src, n);
}
s32 bcmp(const void *s1, const void *s2, size_t n)
{
return memcmp(s1, s2, n);
}
#endif
+203
View File
@@ -0,0 +1,203 @@
#include <stdlib.h>
#include <stdio.h>
#include <PR/ultratypes.h>
#include <PR/ultrasched.h>
#include <PR/os_message.h>
#include "lib/main.h"
#include "bss.h"
#include "data.h"
#include "video.h"
#include "audio.h"
#include "input.h"
#include "fs.h"
#include "romdata.h"
#include "config.h"
#include "mod.h"
#include "system.h"
#include "console.h"
#include "utils.h"
#include "net/net.h"
u32 g_OsMemSize = 0;
s32 g_OsMemSizeMb = 16;
u8 g_Is4Mb = 0;
s8 g_Resetting = false;
OSSched g_Sched;
OSMesgQueue g_MainMesgQueue;
OSMesg g_MainMesgBuf[32];
u8 *g_MempHeap = NULL;
u32 g_MempHeapSize = 0;
u32 g_VmNumTlbMisses = 0;
u32 g_VmNumPageMisses = 0;
u32 g_VmNumPageReplaces = 0;
u8 g_VmShowStats = 0;
s32 g_TickRateDiv = 1;
s32 g_TickExtraSleep = true;
s32 g_SkipIntro = false;
s32 g_FileAutoSelect = -1;
extern s32 g_StageNum;
s32 bootGetMemSize(void)
{
return (s32)g_OsMemSize;
}
void *bootAllocateStack(s32 threadid, s32 size)
{
static u8 bruh[0x1000];
return bruh;
}
void bootCreateSched(void)
{
osCreateMesgQueue(&g_MainMesgQueue, g_MainMesgBuf, ARRAYCOUNT(g_MainMesgBuf));
if (osTvType == OS_TV_MPAL) {
osCreateScheduler(&g_Sched, NULL, OS_VI_MPAL_LAN1, 1);
} else {
osCreateScheduler(&g_Sched, NULL, OS_VI_NTSC_LAN1, 1);
}
}
static void gameInit(void)
{
osMemSize = g_OsMemSizeMb * 1024 * 1024;
for (s32 i = 0; i < MAX_LOCAL_PLAYERS; ++i) {
struct extplayerconfig *cfg = g_PlayerExtCfg + i;
cfg->fovzoommult = cfg->fovzoom ? cfg->fovy / 60.0f : 1.0f;
}
if (g_HudCenter == HUDCENTER_NORMAL) {
g_HudAlignModeL = G_ASPECT_CENTER_EXT;
g_HudAlignModeR = G_ASPECT_CENTER_EXT;
} else if (g_HudCenter == HUDCENTER_WIDE) {
g_HudAlignModeL = G_ASPECT_LEFT_EXT | G_ASPECT_WIDE_EXT;
g_HudAlignModeR = G_ASPECT_RIGHT_EXT | G_ASPECT_WIDE_EXT;
}
}
static void cleanup(void)
{
sysLogPrintf(LOG_NOTE, "shutdown");
netDisconnect();
inputSaveBinds();
configSave(CONFIG_PATH);
videoShutdown();
crashShutdown();
// TODO: actually shut down all subsystems
}
int main(int argc, const char **argv)
{
sysInitArgs(argc, argv);
if (!sysArgCheck("--no-crash-handler")) {
crashInit();
}
conInit();
sysInit();
fsInit();
configInit();
videoInit();
inputInit();
audioInit();
romdataInit();
netInit();
g_ValidGbcRomFound = romdataCheckGbcRom();
gameInit();
if (fsGetModDir()) {
modConfigLoad(MOD_CONFIG_FNAME);
}
atexit(cleanup);
bootCreateSched();
g_OsMemSize = osGetMemSize();
g_MempHeapSize = g_OsMemSize;
g_MempHeap = sysMemZeroAlloc(g_MempHeapSize);
if (!g_MempHeap) {
sysFatalError("Could not alloc %u bytes for memp heap.", g_MempHeapSize);
}
sysLogPrintf(LOG_NOTE, "memp heap at %p - %p", g_MempHeap, g_MempHeap + g_MempHeapSize);
sysLogPrintf(LOG_NOTE, "rom file at %p - %p", g_RomFile, g_RomFile + g_RomFileSize);
g_SndDisabled = sysArgCheck("--no-sound");
g_StageNum = sysArgGetInt("--boot-stage", STAGE_TITLE);
g_FileAutoSelect = sysArgGetInt("--profile", -1);
if (g_StageNum == STAGE_TITLE && (sysArgCheck("--skip-intro") || g_SkipIntro)) {
// shorthand for --boot-stage 0x26
g_StageNum = STAGE_CITRAINING;
} else if (g_StageNum < 0x01 || g_StageNum > 0x5d) {
// stage num out of range
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) {
sysLogPrintf(LOG_NOTE, "boot stage set to 0x%02x", g_StageNum);
}
if (g_FileAutoSelect >= 0) {
sysLogPrintf(LOG_NOTE, "player profile set to %d", g_FileAutoSelect);
}
mainProc();
return 0;
}
PD_CONSTRUCTOR static void gameConfigInit(void)
{
configRegisterInt("Game.MemorySize", &g_OsMemSizeMb, 4, 2048);
configRegisterInt("Game.CenterHUD", &g_HudCenter, 0, 2);
configRegisterInt("Game.MenuMouseControl", &g_MenuMouseControl, 0, 1);
configRegisterFloat("Game.ScreenShakeIntensity", &g_ViShakeIntensityMult, 0.f, 10.f);
configRegisterInt("Game.TickRateDivisor", &g_TickRateDiv, 0, 10);
configRegisterInt("Game.ExtraSleep", &g_TickExtraSleep, 0, 1);
configRegisterInt("Game.SkipIntro", &g_SkipIntro, 0, 1);
configRegisterInt("Game.DisableMpDeathMusic", &g_MusicDisableMpDeath, 0, 1);
configRegisterInt("Game.GEMuzzleFlashes", &g_BgunGeMuzzleFlashes, 0, 1);
for (s32 j = 0; j < MAX_LOCAL_PLAYERS; ++j) {
const s32 i = j + 1;
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.MouseAimMode", i), &g_PlayerExtCfg[j].mouseaimmode, 0, 1);
configRegisterFloat(strFmt("Game.Player%d.MouseAimSpeedX", i), &g_PlayerExtCfg[j].mouseaimspeedx, 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.CrosshairSway", i), &g_PlayerExtCfg[j].crosshairsway, 0.f, 10.f);
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);
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);
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);
}
}
+721
View File
@@ -0,0 +1,721 @@
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <ultra64.h>
#include "mixer.h"
#include "platform.h"
#include "external/minimp3.h"
#ifdef __SSE4_1__
#include <immintrin.h>
#define HAS_SSE41 1
#define HAS_NEON 0
#elif __ARM_NEON
#include <arm_neon.h>
#define HAS_SSE41 0
#define HAS_NEON 1
#else
#define HAS_SSE41 0
#define HAS_NEON 0
#endif
#pragma GCC optimize ("unroll-loops")
#if HAS_SSE41
#define LOADLH(l, h) _mm_castpd_si128(_mm_loadh_pd(_mm_load_sd((const double *)(l)), (const double *)(h)))
#endif
#define ROUND_UP_64(v) (((v) + 63) & ~63)
#define ROUND_UP_32(v) (((v) + 31) & ~31)
#define ROUND_UP_16(v) (((v) + 15) & ~15)
#define ROUND_UP_8(v) (((v) + 7) & ~7)
#define ROUND_DOWN_16(v) ((v) & ~0xf)
#define BUF_SIZE 3072 // 2720 + slack
#define BUF_U8(a) (rspa.buf.as_u8 + (a))
#define BUF_S16(a) (rspa.buf.as_s16 + (a) / sizeof(int16_t))
#define NUM_SAMPLES 0xB8
#define NUM_BYTES 0x170
#define OFS_BASE 0
#define OFS_TEMP1 0x170
#define OFS_MAIN_L 0x4E0
#define OFS_MAIN_R 0x650
#define OFS_AUX_L 0x7C0
#define OFS_AUX_R 0x930
static struct {
int16_t vol[2];
int16_t target[2];
int32_t rate[2];
int16_t vol_dry;
int16_t vol_wet;
ADPCM_STATE *adpcm_loop_state;
int16_t adpcm_table[8][2][8];
union {
int16_t as_s16[BUF_SIZE / sizeof(int16_t)];
uint8_t as_u8[BUF_SIZE];
} buf;
} rspa;
static int16_t resample_table[64][4] = {
{0x0c39, 0x66ad, 0x0d46, 0xffdf}, {0x0b39, 0x6696, 0x0e5f, 0xffd8},
{0x0a44, 0x6669, 0x0f83, 0xffd0}, {0x095a, 0x6626, 0x10b4, 0xffc8},
{0x087d, 0x65cd, 0x11f0, 0xffbf}, {0x07ab, 0x655e, 0x1338, 0xffb6},
{0x06e4, 0x64d9, 0x148c, 0xffac}, {0x0628, 0x643f, 0x15eb, 0xffa1},
{0x0577, 0x638f, 0x1756, 0xff96}, {0x04d1, 0x62cb, 0x18cb, 0xff8a},
{0x0435, 0x61f3, 0x1a4c, 0xff7e}, {0x03a4, 0x6106, 0x1bd7, 0xff71},
{0x031c, 0x6007, 0x1d6c, 0xff64}, {0x029f, 0x5ef5, 0x1f0b, 0xff56},
{0x022a, 0x5dd0, 0x20b3, 0xff48}, {0x01be, 0x5c9a, 0x2264, 0xff3a},
{0x015b, 0x5b53, 0x241e, 0xff2c}, {0x0101, 0x59fc, 0x25e0, 0xff1e},
{0x00ae, 0x5896, 0x27a9, 0xff10}, {0x0063, 0x5720, 0x297a, 0xff02},
{0x001f, 0x559d, 0x2b50, 0xfef4}, {0xffe2, 0x540d, 0x2d2c, 0xfee8},
{0xffac, 0x5270, 0x2f0d, 0xfedb}, {0xff7c, 0x50c7, 0x30f3, 0xfed0},
{0xff53, 0x4f14, 0x32dc, 0xfec6}, {0xff2e, 0x4d57, 0x34c8, 0xfebd},
{0xff0f, 0x4b91, 0x36b6, 0xfeb6}, {0xfef5, 0x49c2, 0x38a5, 0xfeb0},
{0xfedf, 0x47ed, 0x3a95, 0xfeac}, {0xfece, 0x4611, 0x3c85, 0xfeab},
{0xfec0, 0x4430, 0x3e74, 0xfeac}, {0xfeb6, 0x424a, 0x4060, 0xfeaf},
{0xfeaf, 0x4060, 0x424a, 0xfeb6}, {0xfeac, 0x3e74, 0x4430, 0xfec0},
{0xfeab, 0x3c85, 0x4611, 0xfece}, {0xfeac, 0x3a95, 0x47ed, 0xfedf},
{0xfeb0, 0x38a5, 0x49c2, 0xfef5}, {0xfeb6, 0x36b6, 0x4b91, 0xff0f},
{0xfebd, 0x34c8, 0x4d57, 0xff2e}, {0xfec6, 0x32dc, 0x4f14, 0xff53},
{0xfed0, 0x30f3, 0x50c7, 0xff7c}, {0xfedb, 0x2f0d, 0x5270, 0xffac},
{0xfee8, 0x2d2c, 0x540d, 0xffe2}, {0xfef4, 0x2b50, 0x559d, 0x001f},
{0xff02, 0x297a, 0x5720, 0x0063}, {0xff10, 0x27a9, 0x5896, 0x00ae},
{0xff1e, 0x25e0, 0x59fc, 0x0101}, {0xff2c, 0x241e, 0x5b53, 0x015b},
{0xff3a, 0x2264, 0x5c9a, 0x01be}, {0xff48, 0x20b3, 0x5dd0, 0x022a},
{0xff56, 0x1f0b, 0x5ef5, 0x029f}, {0xff64, 0x1d6c, 0x6007, 0x031c},
{0xff71, 0x1bd7, 0x6106, 0x03a4}, {0xff7e, 0x1a4c, 0x61f3, 0x0435},
{0xff8a, 0x18cb, 0x62cb, 0x04d1}, {0xff96, 0x1756, 0x638f, 0x0577},
{0xffa1, 0x15eb, 0x643f, 0x0628}, {0xffac, 0x148c, 0x64d9, 0x06e4},
{0xffb6, 0x1338, 0x655e, 0x07ab}, {0xffbf, 0x11f0, 0x65cd, 0x087d},
{0xffc8, 0x10b4, 0x6626, 0x095a}, {0xffd0, 0x0f83, 0x6669, 0x0a44},
{0xffd8, 0x0e5f, 0x6696, 0x0b39}, {0xffdf, 0x0d46, 0x66ad, 0x0c39}
};
static inline int16_t clamp16(int32_t v) {
if (v < -0x8000) {
return -0x8000;
} else if (v > 0x7fff) {
return 0x7fff;
}
return (int16_t)v;
}
static inline int32_t clamp32(int64_t v) {
if (v < -0x7fffffff - 1) {
return -0x7fffffff - 1;
} else if (v > 0x7fffffff) {
return 0x7fffffff;
}
return (int32_t)v;
}
void aClearBufferImpl(uint16_t addr, int nbytes) {
nbytes = ROUND_UP_16(nbytes);
memset(BUF_U8(addr), 0, nbytes);
}
void aLoadBufferImpl(const void *source_addr, uint16_t dest_addr, uint16_t nbytes) {
memcpy(BUF_U8(dest_addr), source_addr, ROUND_UP_8(nbytes));
}
void aSaveBufferImpl(uint16_t source_addr, int16_t *dest_addr, uint16_t nbytes) {
memcpy(dest_addr, BUF_S16(source_addr), ROUND_UP_8(nbytes));
}
void aLoadADPCMImpl(int num_entries_times_16, const int16_t *book_source_addr) {
memcpy(rspa.adpcm_table, book_source_addr, num_entries_times_16);
}
void aInterleaveImpl(void) {
const int16_t *l = BUF_S16(OFS_MAIN_L);
const int16_t *r = BUF_S16(OFS_MAIN_R);
int count = ROUND_UP_16(NUM_SAMPLES) / 8;
int16_t *d = BUF_S16(OFS_BASE);
while (count > 0) {
int16_t l0 = *l++;
int16_t l1 = *l++;
int16_t l2 = *l++;
int16_t l3 = *l++;
int16_t l4 = *l++;
int16_t l5 = *l++;
int16_t l6 = *l++;
int16_t l7 = *l++;
int16_t r0 = *r++;
int16_t r1 = *r++;
int16_t r2 = *r++;
int16_t r3 = *r++;
int16_t r4 = *r++;
int16_t r5 = *r++;
int16_t r6 = *r++;
int16_t r7 = *r++;
*d++ = l0;
*d++ = r0;
*d++ = l1;
*d++ = r1;
*d++ = l2;
*d++ = r2;
*d++ = l3;
*d++ = r3;
*d++ = l4;
*d++ = r4;
*d++ = l5;
*d++ = r5;
*d++ = l6;
*d++ = r6;
*d++ = l7;
*d++ = r7;
--count;
}
}
void aDMEMMoveImpl(uint16_t in_addr, uint16_t out_addr, int nbytes) {
memmove(BUF_U8(out_addr), BUF_U8(in_addr), ROUND_UP_16(nbytes));
}
void aSetLoopImpl(ADPCM_STATE *adpcm_loop_state) {
rspa.adpcm_loop_state = adpcm_loop_state;
}
void aADPCMdecImpl(uint8_t flags, ADPCM_STATE state, int nbytes, uint16_t inofs, uint16_t outofs) {
#if HAS_SSE41
const __m128i tblrev = _mm_setr_epi8(12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1, -1, -1);
const __m128i pos0 = _mm_set_epi8(3, -1, 3, -1, 2, -1, 2, -1, 1, -1, 1, -1, 0, -1, 0, -1);
const __m128i pos1 = _mm_set_epi8(7, -1, 7, -1, 6, -1, 6, -1, 5, -1, 5, -1, 4, -1, 4, -1);
const __m128i mult = _mm_set_epi16(0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01);
const __m128i mask = _mm_set1_epi16((int16_t)0xf000);
#elif HAS_NEON
static const int8_t pos0_data[] = {-1, 0, -1, 0, -1, 1, -1, 1, -1, 2, -1, 2, -1, 3, -1, 3};
static const int8_t pos1_data[] = {-1, 4, -1, 4, -1, 5, -1, 5, -1, 6, -1, 6, -1, 7, -1, 7};
static const int16_t mult_data[] = {0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10};
static const int16_t table_prefix_data[] = {0, 0, 0, 0, 0, 0, 0, 1 << 11};
const int8x16_t pos0 = vld1q_s8(pos0_data);
const int8x16_t pos1 = vld1q_s8(pos1_data);
const int16x8_t mult = vld1q_s16(mult_data);
const int16x8_t mask = vdupq_n_s16((int16_t)0xf000);
const int16x8_t table_prefix = vld1q_s16(table_prefix_data);
#endif
uint8_t *in = BUF_U8(inofs);
int16_t *out = BUF_S16(outofs);
nbytes = ROUND_UP_32(nbytes);
if (flags & A_INIT) {
memset(out, 0, 16 * sizeof(int16_t));
} else if (flags & A_LOOP) {
memcpy(out, rspa.adpcm_loop_state, 16 * sizeof(int16_t));
} else {
memcpy(out, state, 16 * sizeof(int16_t));
}
out += 16;
#if HAS_SSE41
__m128i prev_interleaved = _mm_set1_epi32((uint16_t)out[-2] | ((uint16_t)out[-1] << 16));
//__m128i prev_interleaved = _mm_shuffle_epi32(_mm_loadu_si32(out - 2), 0); // GCC misses this?
#elif HAS_NEON
int16x8_t result = vld1q_s16(out - 8);
#endif
while (nbytes > 0) {
int shift = *in >> 4; // should be in 0..12
int table_index = *in++ & 0xf; // should be in 0..7
int16_t (*tbl)[8] = rspa.adpcm_table[table_index];
int i;
#if HAS_SSE41
// The _mm_loadu_si64 instruction was added in GCC 9, and results in the same
// asm as the following instructions, so better be compatible with old GCC.
//__m128i inv = _mm_loadu_si64(in);
uint64_t v; memcpy(&v, in, 8);
__m128i inv = _mm_set_epi64x(0, v);
__m128i invec[2] = {_mm_shuffle_epi8(inv, pos0), _mm_shuffle_epi8(inv, pos1)};
__m128i tblvec0 = _mm_loadu_si128((const __m128i *)tbl[0]);
__m128i tblvec1 = _mm_loadu_si128((const __m128i *)(tbl[1]));
__m128i tbllo = _mm_unpacklo_epi16(tblvec0, tblvec1);
__m128i tblhi = _mm_unpackhi_epi16(tblvec0, tblvec1);
__m128i shiftcount = _mm_set_epi64x(0, 12 - shift); // _mm_cvtsi64_si128 does not exist on 32-bit x86
__m128i tblvec1_rev[8];
tblvec1_rev[0] = _mm_insert_epi16(_mm_shuffle_epi8(tblvec1, tblrev), 1 << 11, 7);
tblvec1_rev[1] = _mm_bsrli_si128(tblvec1_rev[0], 2);
tblvec1_rev[2] = _mm_bsrli_si128(tblvec1_rev[0], 4);
tblvec1_rev[3] = _mm_bsrli_si128(tblvec1_rev[0], 6);
tblvec1_rev[4] = _mm_bsrli_si128(tblvec1_rev[0], 8);
tblvec1_rev[5] = _mm_bsrli_si128(tblvec1_rev[0], 10);
tblvec1_rev[6] = _mm_bsrli_si128(tblvec1_rev[0], 12);
tblvec1_rev[7] = _mm_bsrli_si128(tblvec1_rev[0], 14);
in += 8;
for (i = 0; i < 2; i++) {
__m128i acc0 = _mm_madd_epi16(prev_interleaved, tbllo);
__m128i acc1 = _mm_madd_epi16(prev_interleaved, tblhi);
__m128i muls[8];
__m128i result;
invec[i] = _mm_sra_epi16(_mm_and_si128(_mm_mullo_epi16(invec[i], mult), mask), shiftcount);
muls[7] = _mm_madd_epi16(tblvec1_rev[0], invec[i]);
muls[6] = _mm_madd_epi16(tblvec1_rev[1], invec[i]);
muls[5] = _mm_madd_epi16(tblvec1_rev[2], invec[i]);
muls[4] = _mm_madd_epi16(tblvec1_rev[3], invec[i]);
muls[3] = _mm_madd_epi16(tblvec1_rev[4], invec[i]);
muls[2] = _mm_madd_epi16(tblvec1_rev[5], invec[i]);
muls[1] = _mm_madd_epi16(tblvec1_rev[6], invec[i]);
muls[0] = _mm_madd_epi16(tblvec1_rev[7], invec[i]);
acc0 = _mm_add_epi32(acc0, _mm_hadd_epi32(_mm_hadd_epi32(muls[0], muls[1]), _mm_hadd_epi32(muls[2], muls[3])));
acc1 = _mm_add_epi32(acc1, _mm_hadd_epi32(_mm_hadd_epi32(muls[4], muls[5]), _mm_hadd_epi32(muls[6], muls[7])));
acc0 = _mm_srai_epi32(acc0, 11);
acc1 = _mm_srai_epi32(acc1, 11);
result = _mm_packs_epi32(acc0, acc1);
_mm_storeu_si128((__m128i *)out, result);
out += 8;
prev_interleaved = _mm_shuffle_epi32(result, _MM_SHUFFLE(3, 3, 3, 3));
}
#elif HAS_NEON
int8x8_t inv = vld1_s8((int8_t *)in);
int16x8_t tblvec[2] = {vld1q_s16(tbl[0]), vld1q_s16(tbl[1])};
int16x8_t invec[2] = {vreinterpretq_s16_s8(vcombine_s8(vtbl1_s8(inv, vget_low_s8(pos0)),
vtbl1_s8(inv, vget_high_s8(pos0)))),
vreinterpretq_s16_s8(vcombine_s8(vtbl1_s8(inv, vget_low_s8(pos1)),
vtbl1_s8(inv, vget_high_s8(pos1))))};
int16x8_t shiftcount = vdupq_n_s16(shift - 12); // negative means right shift
int16x8_t tblvec1[8];
in += 8;
tblvec1[0] = vextq_s16(table_prefix, tblvec[1], 7);
invec[0] = vmulq_s16(invec[0], mult);
tblvec1[1] = vextq_s16(table_prefix, tblvec[1], 6);
invec[1] = vmulq_s16(invec[1], mult);
tblvec1[2] = vextq_s16(table_prefix, tblvec[1], 5);
tblvec1[3] = vextq_s16(table_prefix, tblvec[1], 4);
invec[0] = vandq_s16(invec[0], mask);
tblvec1[4] = vextq_s16(table_prefix, tblvec[1], 3);
invec[1] = vandq_s16(invec[1], mask);
tblvec1[5] = vextq_s16(table_prefix, tblvec[1], 2);
tblvec1[6] = vextq_s16(table_prefix, tblvec[1], 1);
invec[0] = vqshlq_s16(invec[0], shiftcount);
invec[1] = vqshlq_s16(invec[1], shiftcount);
tblvec1[7] = table_prefix;
for (i = 0; i < 2; i++) {
int32x4_t acc0;
int32x4_t acc1;
acc1 = vmull_lane_s16(vget_high_s16(tblvec[0]), vget_high_s16(result), 2);
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec[1]), vget_high_s16(result), 3);
acc0 = vmull_lane_s16(vget_low_s16(tblvec[0]), vget_high_s16(result), 2);
acc0 = vmlal_lane_s16(acc0, vget_low_s16(tblvec[1]), vget_high_s16(result), 3);
acc0 = vmlal_lane_s16(acc0, vget_low_s16(tblvec1[0]), vget_low_s16(invec[i]), 0);
acc0 = vmlal_lane_s16(acc0, vget_low_s16(tblvec1[1]), vget_low_s16(invec[i]), 1);
acc0 = vmlal_lane_s16(acc0, vget_low_s16(tblvec1[2]), vget_low_s16(invec[i]), 2);
acc0 = vmlal_lane_s16(acc0, vget_low_s16(tblvec1[3]), vget_low_s16(invec[i]), 3);
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec1[0]), vget_low_s16(invec[i]), 0);
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec1[1]), vget_low_s16(invec[i]), 1);
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec1[2]), vget_low_s16(invec[i]), 2);
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec1[3]), vget_low_s16(invec[i]), 3);
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec1[4]), vget_high_s16(invec[i]), 0);
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec1[5]), vget_high_s16(invec[i]), 1);
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec1[6]), vget_high_s16(invec[i]), 2);
acc1 = vmlal_lane_s16(acc1, vget_high_s16(tblvec1[7]), vget_high_s16(invec[i]), 3);
result = vcombine_s16(vqshrn_n_s32(acc0, 11), vqshrn_n_s32(acc1, 11));
vst1q_s16(out, result);
out += 8;
}
#else
for (i = 0; i < 2; i++) {
int16_t ins[8];
int16_t prev1 = out[-1];
int16_t prev2 = out[-2];
int j, k;
for (j = 0; j < 4; j++) {
ins[j * 2] = (((*in >> 4) << 28) >> 28) << shift;
ins[j * 2 + 1] = (((*in++ & 0xf) << 28) >> 28) << shift;
}
for (j = 0; j < 8; j++) {
int32_t acc = tbl[0][j] * prev2 + tbl[1][j] * prev1 + (ins[j] << 11);
for (k = 0; k < j; k++) {
acc += tbl[1][((j - k) - 1)] * ins[k];
}
acc >>= 11;
*out++ = clamp16(acc);
}
}
#endif
nbytes -= 16 * sizeof(int16_t);
}
memcpy(state, out - 16, 16 * sizeof(int16_t));
}
void aResampleImpl(uint8_t flags, uint16_t pitch, RESAMPLE_STATE state, uint16_t inofs, uint8_t outflag) {
int16_t tmp[16];
int16_t *in_initial = BUF_S16(inofs);
int16_t *in = in_initial;
int16_t *out = BUF_S16(OFS_BASE + ((outflag & 3) != 0) * NUM_BYTES);
int nbytes = ROUND_UP_16(NUM_BYTES);
uint32_t pitch_accumulator;
int i;
#if !HAS_SSE41 && !HAS_NEON
int16_t *tbl;
int32_t sample;
#endif
if (flags & A_INIT) {
memset(tmp, 0, 5 * sizeof(int16_t));
} else {
memcpy(tmp, state, 16 * sizeof(int16_t));
}
if (flags & 2) {
memcpy(in - 8, tmp + 8, 8 * sizeof(int16_t));
in -= tmp[5] / sizeof(int16_t);
}
in -= 4;
pitch_accumulator = (uint16_t)tmp[4];
memcpy(in, tmp, 4 * sizeof(int16_t));
#if HAS_SSE41
__m128i multiples = _mm_setr_epi16(0, 2, 4, 6, 8, 10, 12, 14);
__m128i pitchvec = _mm_set1_epi16((int16_t)pitch);
__m128i pitchvec_8_steps = _mm_set1_epi32((pitch << 1) * 8);
__m128i pitchacclo_vec = _mm_set1_epi32((uint16_t)pitch_accumulator);
__m128i pl = _mm_mullo_epi16(multiples, pitchvec);
__m128i ph = _mm_mulhi_epu16(multiples, pitchvec);
__m128i acc_a = _mm_add_epi32(_mm_unpacklo_epi16(pl, ph), pitchacclo_vec);
__m128i acc_b = _mm_add_epi32(_mm_unpackhi_epi16(pl, ph), pitchacclo_vec);
do {
__m128i tbl_positions = _mm_srli_epi16(_mm_packus_epi32(
_mm_and_si128(acc_a, _mm_set1_epi32(0xffff)),
_mm_and_si128(acc_b, _mm_set1_epi32(0xffff))), 10);
__m128i in_positions = _mm_packus_epi32(_mm_srli_epi32(acc_a, 16), _mm_srli_epi32(acc_b, 16));
__m128i tbl_entries[4];
__m128i samples[4];
/*for (i = 0; i < 4; i++) {
tbl_entries[i] = _mm_castpd_si128(_mm_loadh_pd(_mm_load_sd(
(const double *)resample_table[_mm_extract_epi16(tbl_positions, 2 * i)]),
(const double *)resample_table[_mm_extract_epi16(tbl_positions, 2 * i + 1)]));
samples[i] = _mm_castpd_si128(_mm_loadh_pd(_mm_load_sd(
(const double *)&in[_mm_extract_epi16(in_positions, 2 * i)]),
(const double *)&in[_mm_extract_epi16(in_positions, 2 * i + 1)]));
samples[i] = _mm_mulhrs_epi16(samples[i], tbl_entries[i]);
}*/
tbl_entries[0] = LOADLH(resample_table[_mm_extract_epi16(tbl_positions, 0)], resample_table[_mm_extract_epi16(tbl_positions, 1)]);
tbl_entries[1] = LOADLH(resample_table[_mm_extract_epi16(tbl_positions, 2)], resample_table[_mm_extract_epi16(tbl_positions, 3)]);
tbl_entries[2] = LOADLH(resample_table[_mm_extract_epi16(tbl_positions, 4)], resample_table[_mm_extract_epi16(tbl_positions, 5)]);
tbl_entries[3] = LOADLH(resample_table[_mm_extract_epi16(tbl_positions, 6)], resample_table[_mm_extract_epi16(tbl_positions, 7)]);
samples[0] = LOADLH(&in[_mm_extract_epi16(in_positions, 0)], &in[_mm_extract_epi16(in_positions, 1)]);
samples[1] = LOADLH(&in[_mm_extract_epi16(in_positions, 2)], &in[_mm_extract_epi16(in_positions, 3)]);
samples[2] = LOADLH(&in[_mm_extract_epi16(in_positions, 4)], &in[_mm_extract_epi16(in_positions, 5)]);
samples[3] = LOADLH(&in[_mm_extract_epi16(in_positions, 6)], &in[_mm_extract_epi16(in_positions, 7)]);
samples[0] = _mm_mulhrs_epi16(samples[0], tbl_entries[0]);
samples[1] = _mm_mulhrs_epi16(samples[1], tbl_entries[1]);
samples[2] = _mm_mulhrs_epi16(samples[2], tbl_entries[2]);
samples[3] = _mm_mulhrs_epi16(samples[3], tbl_entries[3]);
_mm_storeu_si128((__m128i *)out, _mm_hadds_epi16(_mm_hadds_epi16(samples[0], samples[1]), _mm_hadds_epi16(samples[2], samples[3])));
acc_a = _mm_add_epi32(acc_a, pitchvec_8_steps);
acc_b = _mm_add_epi32(acc_b, pitchvec_8_steps);
out += 8;
nbytes -= 8 * sizeof(int16_t);
} while (nbytes > 0);
in += (uint16_t)_mm_extract_epi16(acc_a, 1);
pitch_accumulator = (uint16_t)_mm_extract_epi16(acc_a, 0);
#elif HAS_NEON
static const uint16_t multiples_data[8] = {0, 2, 4, 6, 8, 10, 12, 14};
uint16x8_t multiples = vld1q_u16(multiples_data);
uint32x4_t pitchvec_8_steps = vdupq_n_u32((pitch << 1) * 8);
uint32x4_t pitchacclo_vec = vdupq_n_u32((uint16_t)pitch_accumulator);
uint32x4_t acc_a = vmlal_n_u16(pitchacclo_vec, vget_low_u16(multiples), pitch);
uint32x4_t acc_b = vmlal_n_u16(pitchacclo_vec, vget_high_u16(multiples), pitch);
do {
uint16x8x2_t unzipped = vuzpq_u16(vreinterpretq_u16_u32(acc_a), vreinterpretq_u16_u32(acc_b));
uint16x8_t tbl_positions = vshrq_n_u16(unzipped.val[0], 10);
uint16x8_t in_positions = unzipped.val[1];
int16x8_t tbl_entries[4];
int16x8_t samples[4];
int16x8x2_t unzipped1;
int16x8x2_t unzipped2;
tbl_entries[0] = vcombine_s16(vld1_s16(resample_table[vgetq_lane_u16(tbl_positions, 0)]), vld1_s16(resample_table[vgetq_lane_u16(tbl_positions, 1)]));
tbl_entries[1] = vcombine_s16(vld1_s16(resample_table[vgetq_lane_u16(tbl_positions, 2)]), vld1_s16(resample_table[vgetq_lane_u16(tbl_positions, 3)]));
tbl_entries[2] = vcombine_s16(vld1_s16(resample_table[vgetq_lane_u16(tbl_positions, 4)]), vld1_s16(resample_table[vgetq_lane_u16(tbl_positions, 5)]));
tbl_entries[3] = vcombine_s16(vld1_s16(resample_table[vgetq_lane_u16(tbl_positions, 6)]), vld1_s16(resample_table[vgetq_lane_u16(tbl_positions, 7)]));
samples[0] = vcombine_s16(vld1_s16(&in[vgetq_lane_u16(in_positions, 0)]), vld1_s16(&in[vgetq_lane_u16(in_positions, 1)]));
samples[1] = vcombine_s16(vld1_s16(&in[vgetq_lane_u16(in_positions, 2)]), vld1_s16(&in[vgetq_lane_u16(in_positions, 3)]));
samples[2] = vcombine_s16(vld1_s16(&in[vgetq_lane_u16(in_positions, 4)]), vld1_s16(&in[vgetq_lane_u16(in_positions, 5)]));
samples[3] = vcombine_s16(vld1_s16(&in[vgetq_lane_u16(in_positions, 6)]), vld1_s16(&in[vgetq_lane_u16(in_positions, 7)]));
samples[0] = vqrdmulhq_s16(samples[0], tbl_entries[0]);
samples[1] = vqrdmulhq_s16(samples[1], tbl_entries[1]);
samples[2] = vqrdmulhq_s16(samples[2], tbl_entries[2]);
samples[3] = vqrdmulhq_s16(samples[3], tbl_entries[3]);
unzipped1 = vuzpq_s16(samples[0], samples[1]);
unzipped2 = vuzpq_s16(samples[2], samples[3]);
samples[0] = vqaddq_s16(unzipped1.val[0], unzipped1.val[1]);
samples[1] = vqaddq_s16(unzipped2.val[0], unzipped2.val[1]);
unzipped1 = vuzpq_s16(samples[0], samples[1]);
samples[0] = vqaddq_s16(unzipped1.val[0], unzipped1.val[1]);
vst1q_s16(out, samples[0]);
acc_a = vaddq_u32(acc_a, pitchvec_8_steps);
acc_b = vaddq_u32(acc_b, pitchvec_8_steps);
out += 8;
nbytes -= 8 * sizeof(int16_t);
} while (nbytes > 0);
in += vgetq_lane_u16(vreinterpretq_u16_u32(acc_a), 1);
pitch_accumulator = vgetq_lane_u16(vreinterpretq_u16_u32(acc_a), 0);
#else
do {
for (i = 0; i < 8; i++) {
tbl = resample_table[pitch_accumulator * 64 >> 16];
sample = ((in[0] * tbl[0] + 0x4000) >> 15) +
((in[1] * tbl[1] + 0x4000) >> 15) +
((in[2] * tbl[2] + 0x4000) >> 15) +
((in[3] * tbl[3] + 0x4000) >> 15);
*out++ = clamp16(sample);
pitch_accumulator += (pitch << 1);
in += pitch_accumulator >> 16;
pitch_accumulator %= 0x10000;
}
nbytes -= 8 * sizeof(int16_t);
} while (nbytes > 0);
#endif
state[4] = (int16_t)pitch_accumulator;
memcpy(state, in, 4 * sizeof(int16_t));
i = (in - in_initial + 4) & 7;
in -= i;
if (i != 0) {
i = -8 - i;
}
state[5] = i;
memcpy(state + 8, in, 8 * sizeof(int16_t));
}
void aEnvMixerImpl(uint8_t flags, ENVMIX_STATE state, int16_t rvol) {
int16_t *in = BUF_S16(OFS_BASE);
int16_t *dry[2] = {BUF_S16(OFS_MAIN_L), BUF_S16(OFS_MAIN_R)};
int16_t *wet[2] = {BUF_S16(OFS_AUX_L), BUF_S16(OFS_AUX_R)};
int nsamples = NUM_SAMPLES;
struct {
int32_t t[2];
int32_t rate[2];
int16_t tgt[2];
int16_t voldry;
int16_t volwet;
} *savedstate = (void *)state;
rspa.vol[1] = rvol; // why the fuck is this here?
// naudio uses a linear envelope
// TODO: sse/neon
int32_t t[2], tgt[2], rate[2];
int16_t voldry, volwet;
if (flags & A_INIT) {
for (int i = 0; i < 2; ++i) {
t[i] = rspa.vol[i] << 16;
rate[i] = rspa.rate[i] >> 3;
tgt[i] = rspa.target[i] << 16;
}
voldry = rspa.vol_dry;
volwet = rspa.vol_wet;
} else {
for (int i = 0; i < 2; ++i) {
t[i] = savedstate->t[i];
rate[i] = savedstate->rate[i];
tgt[i] = savedstate->tgt[i] << 16;
}
voldry = savedstate->voldry;
volwet = savedstate->volwet;
}
#ifdef PLATFORM_BIG_ENDIAN
#define XOR 0
#else
#define XOR 1
#endif
for (int i = 0; i < nsamples; ++i) {
int16_t gain[4];
int16_t vol[2];
int16_t *outptr[4];
for (int j = 0; j < 2; ++j) {
t[j] += rate[j];
if ((rate[j] <= 0 && t[j] <= tgt[j]) || (rate[j] > 0 && t[j] >= tgt[j])) {
t[j] = tgt[j];
rate[j] = 0;
}
vol[j] = t[j] >> 16;
}
outptr[0] = dry[0] + (i^XOR);
outptr[1] = dry[1] + (i^XOR);
outptr[2] = wet[0] + (i^XOR);
outptr[3] = wet[1] + (i^XOR);
gain[0] = clamp16((vol[0] * voldry + 0x4000) >> 15);
gain[1] = clamp16((vol[1] * voldry + 0x4000) >> 15);
gain[2] = clamp16((vol[0] * volwet + 0x4000) >> 15);
gain[3] = clamp16((vol[1] * volwet + 0x4000) >> 15);
const int16_t insamp = in[i^XOR];
for (int j = 0; j < 4; ++j) {
*outptr[j] = clamp16(*outptr[j] + ((insamp * gain[j]) >> 15));
}
}
#undef XOR
for (int i = 0; i < 2; ++i) {
savedstate->t[i] = t[i];
savedstate->rate[i] = rate[i];
savedstate->tgt[i] = tgt[i] >> 16;
}
savedstate->voldry = voldry;
savedstate->volwet = volwet;
}
// flags is always 0 in PD
void aMixImpl(uint8_t flags, int16_t gain, uint16_t in_addr, uint16_t out_addr) {
int nbytes = ROUND_UP_16(NUM_BYTES); // can't round up to 32 here because 0x170 ain't gonna do that
int16_t *in = BUF_S16(in_addr);
int16_t *out = BUF_S16(out_addr);
#if HAS_SSE41
__m128i gain_vec = _mm_set1_epi16(gain);
#elif !HAS_NEON
int i;
int32_t sample;
#endif
#if !HAS_NEON
if (gain == -0x8000) {
while (nbytes > 0) {
#if HAS_SSE41
__m128i out1, in1;
out1 = _mm_loadu_si128((const __m128i *)out);
in1 = _mm_loadu_si128((const __m128i *)in);
out1 = _mm_subs_epi16(out1, in1);
_mm_storeu_si128((__m128i *)out, out1);
out += 8;
in += 8;
#else
for (i = 0; i < 8; i++) {
sample = *out - *in++;
*out++ = clamp16(sample);
}
#endif
nbytes -= 8 * sizeof(int16_t);
}
}
#endif
while (nbytes > 0) {
#if HAS_SSE41
__m128i out1, in1;
out1 = _mm_loadu_si128((const __m128i *)out);
in1 = _mm_loadu_si128((const __m128i *)in);
out1 = _mm_adds_epi16(out1, _mm_mulhrs_epi16(in1, gain_vec));
_mm_storeu_si128((__m128i *)out, out1);
out += 8;
in += 8;
#elif HAS_NEON
int16x8_t out1, in1;
out1 = vld1q_s16(out);
in1 = vld1q_s16(in);
out1 = vqaddq_s16(out1, vqrdmulhq_n_s16(in1, gain));
vst1q_s16(out, out1);
out += 8;
in += 8;
#else
for (i = 0; i < 8; i++) {
sample = ((*out * 0x7fff + *in++ * gain) + 0x4000) >> 15;
*out++ = clamp16(sample);
}
#endif
nbytes -= 8 * sizeof(int16_t);
}
}
void aSetVolumeImpl(uint8_t flags, int16_t v, int16_t t, int16_t r) {
// the flags are not really very intuitive here
if (flags & A_VOL) {
if (flags & A_LEFT) {
rspa.vol[0] = v;
rspa.vol_dry = t;
rspa.vol_wet = r;
} else {
rspa.target[1] = v;
rspa.rate[1] = (int32_t)((uint16_t)t << 16 | ((uint16_t)r));
}
} else /* A_RATE */ {
rspa.target[0] = v;
rspa.rate[0] = (int32_t)((uint16_t)t << 16 | ((uint16_t)r));
}
}
void aPlayMP3Impl(const void *mp3file, u32 mp3size, void *out, int reset) {
static mp3dec_t mp3d;
static const u8 *curdata = NULL; // pointer to the mp3 we're currently processing
static s32 dataptr = 0; // byte index into curdata
if (mp3file != curdata || reset) {
// new mp3, reinit decoder
mp3dec_init(&mp3d);
curdata = mp3file;
dataptr = 0;
}
// this command is supposed to write one full frame to out
// but which frame? we'll just decode sequentially, it'll probably work
if (dataptr < mp3size) {
// FIXME: decoding straight to out might bite us in the ass because it's only 1160 bytes
mp3dec_frame_info_t info;
const s32 samples = mp3dec_decode_frame(&mp3d, curdata + dataptr, mp3size - dataptr, out, &info);
// fill in the rest of the buffer if frame is smaller
const s32 diff = 580 - samples;
if (diff > 0) {
memset((s16 *)out + samples, 0, diff * 2);
} else {
assert(diff == 0);
}
dataptr += info.frame_bytes;
} else {
// empty frame
memset(out, 0, 580 * 2);
}
}
void aPoleFilterImpl(uint8_t flags, int16_t gain, uint32_t t, uint32_t addr) {
// this never gets called?
}
void aDisableImpl(uint16_t outp, uint32_t b, uint32_t c) {
// this never gets called?
}
+533
View File
@@ -0,0 +1,533 @@
#include <stdlib.h>
#include <string.h>
#include <PR/ultratypes.h>
#include "platform.h"
#include "system.h"
#include "fs.h"
#include "utils.h"
#include "romdata.h"
#include "mod.h"
#include "data.h"
#include "game/stagetable.h"
#define MOD_TEXTURES_DIR "textures"
#define MOD_ANIMATIONS_DIR "animations"
#define MOD_SEQUENCES_DIR "sequences"
extern struct stagemusic g_StageTracks[];
extern struct stageallocation g_StageAllocations8Mb[];
#define PARSE_STAGE_FLOAT(sec, name, v, min, max) \
p = modConfigParseFloatValue(p, token, &v); \
if (!p || v < (min) || v > (max)) { \
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: " sec " invalid " name " value: %s", stagenum, token); \
return NULL; \
}
#define PARSE_STAGE_INT(sec, name, v, min, max) \
p = modConfigParseIntValue(p, token, &v); \
if (!p || v < (min) || v > (max)) { \
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: " sec " invalid " name " value: %s", stagenum, token); \
return NULL; \
}
#define PARSE_STAGE_FILENAME(sec, name, v) \
p = modConfigParseFileValue(p, token, &v); \
if (!p) { \
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: " sec " invalid " name " value: %s", stagenum, token); \
return NULL; \
}
#define PARSE_STAGE_STRING(sec, name, v) \
p = strParseToken(p, token, NULL); \
if (!p) { \
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: " sec " invalid " name " value: %s", stagenum, token); \
return NULL; \
} \
v = strUnquote(token);
#define PARSE_INT(sec, name, v, min, max, ret) \
p = modConfigParseIntValue(p, token, &v); \
if (!p || v < (min) || v > (max)) { \
sysLogPrintf(LOG_ERROR, "mod: %s: invalid " name " value: %s", sec, token); \
return ret; \
}
static inline char *modConfigParseFileValue(char *p, char *token, s32 *filenum)
{
p = strParseToken(p, token, NULL);
if (!token[0]) {
return NULL; // empty
}
// check if it is a number already
s32 num = strtol(token, NULL, 0);
if (num > 0 && romdataFileGetName(num)) {
*filenum = num;
return p;
}
// it's a filename
num = romdataFileGetNumForName(strUnquote(token));
if (num >= 0) {
*filenum = num;
return p;
}
// the filename was invalid
return NULL;
}
static inline char *modConfigParseIntValue(char *p, char *token, s32 *out)
{
p = strParseToken(p, token, NULL);
if (!token[0]) {
return NULL; // empty
}
char *endp = token;
const s32 num = strtol(token, &endp, 0);
if (num == 0 && (endp == token || *endp != '\0')) {
return NULL;
}
*out = num;
return p;
}
static inline char *modConfigParseFloatValue(char *p, char *token, f32 *out)
{
p = strParseToken(p, token, NULL);
if (!token[0]) {
return NULL; // empty
}
char *endp = token;
const f32 num = strtof(token, &endp);
if (num == 0.f && (endp == token || *endp != '\0')) {
return NULL;
}
*out = num;
return p;
}
static char *modConfigParseStageMusic(char *p, char *token, s32 stagenum)
{
struct stagemusic *smus = NULL;
for (struct stagemusic *p = g_StageTracks; p->stagenum; ++p) {
if (p->stagenum == stagenum) {
smus = p;
break;
}
}
if (!smus) {
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: music can't be changed for this stage", stagenum);
return NULL;
}
// eat opening bracket
p = strParseToken(p, token, NULL);
if (token[0] != '{' || token[1] != '\0') {
return NULL;
}
// parse keyvalues until } is reached
s32 tmp = 0;
p = strParseToken(p, token, NULL);
while (p && token[0] && strcmp(token, "}") != 0) {
if (!strcmp(token, "primarytrack")) {
PARSE_STAGE_INT("music:", "primarytrack", tmp, 0, 128);
smus->primarytrack = tmp;
} else if (!strcmp(token, "ambienttrack")) {
PARSE_STAGE_INT("music:", "ambienttrack", tmp, 0, 128);
smus->ambienttrack = tmp;
} else if (!strcmp(token, "xtrack")) {
PARSE_STAGE_INT("music:", "xtrack", tmp, 0, 128);
smus->xtrack = tmp;
} else {
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: music: invalid key: %s", stagenum, token);
return NULL;
}
p = strParseToken(p, token, NULL);
}
if (token[0] != '}') {
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: unterminated music block", stagenum);
return NULL;
}
return p;
}
static char *modConfigParseStageWeatherRooms(char *p, char *token, s32 stagenum, struct weathercfg *wcfg)
{
// determine where we can start adding rooms
s32 idx;
for (idx = 0; idx < WEATHERCFG_MAX_SKIPROOMS && wcfg->skiprooms[idx]; ++idx);
// eat opening bracket
p = strParseToken(p, token, NULL);
if (token[0] != '{' || token[1] != '\0') {
return NULL;
}
// check if user wants to clear the whole list
p = strParseToken(p, token, NULL);
if (!strcmp(token, "clear")) {
memset(wcfg->skiprooms, 0, sizeof(wcfg->skiprooms));
idx = 0;
p = strParseToken(p, token, NULL);
}
s32 tmp = 0;
while (p && token[0] && strcmp(token, "}") != 0) {
if (token[0] == ',' && !token[1]) {
p = strParseToken(p, token, NULL);
continue;
}
tmp = strtol(token, NULL, 0);
if (tmp <= 0 || tmp > 32767) {
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: weather: rooms: invalid room %s", stagenum, token);
return NULL;
}
if (idx < WEATHERCFG_MAX_SKIPROOMS) {
wcfg->skiprooms[idx++] = tmp;
}
p = strParseToken(p, token, NULL);
}
if (token[0] != '}') {
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: weather: unterminated rooms block", stagenum);
return NULL;
}
return p;
}
static char *modConfigParseStageWeather(char *p, char *token, s32 stagenum)
{
s32 wi;
struct weathercfg *wcfg = NULL;
for (wi = 0; wi < ARRAYCOUNT(g_WeatherConfig) && g_WeatherConfig[wi].stagenum; ++wi) {
if (g_WeatherConfig[wi].stagenum == stagenum) {
break;
}
}
if (wi >= WEATHERCFG_MAX_STAGES) {
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: no more space for weather config", stagenum);
return NULL;
}
wcfg = &g_WeatherConfig[wi];
if (!wcfg->stagenum) {
// new weather config; initialize with defaults
*wcfg = g_DefaultWeatherConfig;
wcfg->stagenum = stagenum;
} else {
// flags have to be re-specified
wcfg->flags = 0;
}
// eat opening bracket
p = strParseToken(p, token, NULL);
if (token[0] != '{' || token[1] != '\0') {
return NULL;
}
// parse keyvalues until } is reached
s32 tmpi = 0;
f32 tmpf = 0.f;
p = strParseToken(p, token, NULL);
while (p && token[0] && strcmp(token, "}") != 0) {
if (!strcmp(token, "include_rooms") || !strcmp(token, "exclude_rooms")) {
// include_rooms | exclude_rooms { ROOM_NUMBERS... }
const s32 include = (token[0] == 'i');
p = modConfigParseStageWeatherRooms(p, token, stagenum, wcfg);
if (!p) {
return NULL;
}
if (wcfg->skiprooms[0] && include) {
wcfg->flags |= WEATHERFLAG_INCLUDE;
}
} else if (!strcmp(token, "cutscene_only")) {
wcfg->flags |= WEATHERFLAG_CUTSCENE_ONLY;
} else if (!strcmp(token, "constant_wind")) {
PARSE_STAGE_FLOAT("weather:", "constant_wind (0)", wcfg->windanglerad, -M_TAU, M_TAU);
PARSE_STAGE_FLOAT("weather:", "constant_wind (1)", wcfg->windspeedx, -1024.f, 1024.f);
PARSE_STAGE_FLOAT("weather:", "constant_wind (2)", wcfg->windspeedz, -1024.f, 1024.f);
wcfg->flags |= WEATHERFLAG_FORCE_WINDDIR;
} else if (!strcmp(token, "windspeed")) {
PARSE_STAGE_FLOAT("weather:", "windspeed", tmpf, -1024.f, 1024.f);
wcfg->windspeed = tmpf;
} else if (!strcmp(token, "ymin")) {
PARSE_STAGE_FLOAT("weather:", "ymin", tmpf, -65536.f, 65536.f);
wcfg->ymin = tmpf;
} else if (!strcmp(token, "ymax")) {
PARSE_STAGE_FLOAT("weather:", "ymax", tmpf, -65536.f, 65536.f);
wcfg->ymax = tmpf;
} else if (!strcmp(token, "zmax")) {
PARSE_STAGE_FLOAT("weather:", "zmax", tmpf, -65536.f, 65536.f);
wcfg->zmax = tmpf;
} else {
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: weather: invalid key: %s", stagenum, token);
return NULL;
}
p = strParseToken(p, token, NULL);
}
if (token[0] != '}') {
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: unterminated weather block", stagenum);
return NULL;
}
return p;
}
static char *modConfigParseStage(char *p, char *token)
{
// stage number
p = strParseToken(p, token, NULL);
const s32 stagenum = strtol(token, NULL, 0);
if (stagenum <= 0x01 || stagenum > 0x50) {
return NULL;
}
// eat opening bracket
p = strParseToken(p, token, NULL);
if (token[0] != '{' || token[1] != '\0') {
return NULL;
}
// find the stage table pointers this corresponds to
struct stagetableentry *stab = NULL;
struct stageallocation *salloc = NULL;
const s32 sidx = stageGetIndex(stagenum);
if (sidx >= 0) {
stab = &g_Stages[sidx];
} else {
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: unknown stage number", stagenum);
return NULL;
}
for (struct stageallocation *p = g_StageAllocations8Mb; p->stagenum; ++p) {
if (p->stagenum == stagenum) {
salloc = p;
break;
}
}
// parse keyvalues until } is reached
s32 tmp = 0;
char *tmps = NULL;
p = strParseToken(p, token, NULL);
while (p && token[0] && strcmp(token, "}") != 0) {
if (!strcmp(token, "bgfile")) {
// bg FILE_NAME_OR_NUM
PARSE_STAGE_FILENAME("", "bgfile", tmp);
stab->bgfileid = tmp;
} else if (!strcmp(token, "tilesfile")) {
// tilesfile FILE_NAME_OR_NUM
PARSE_STAGE_FILENAME("", "tilesfile", tmp);
stab->tilefileid = tmp;
} else if (!strcmp(token, "padsfile")) {
// padsfile FILE_NAME_OR_NUM
PARSE_STAGE_FILENAME("", "padsfile", tmp);
stab->padsfileid = tmp;
} else if (!strcmp(token, "setupfile")) {
// setupfile FILE_NAME_OR_NUM
PARSE_STAGE_FILENAME("", "setupfile", tmp);
stab->setupfileid = tmp;
} else if (!strcmp(token, "mpsetupfile")) {
// mpsetupfile FILE_NAME_OR_NUM
PARSE_STAGE_FILENAME("", "mpsetupfile", tmp);
stab->mpsetupfileid = tmp;
} else if (!strcmp(token, "alarm")) {
PARSE_STAGE_INT("", "alarm", tmp, 1, 0xFFFF);
stab->alarm = tmp;
} else if (!strcmp(token, "extragunmem")) {
PARSE_STAGE_INT("", "extragunmem", tmp, 0, 0xFFFF);
stab->extragunmem = tmp;
} else if (!strcmp(token, "allocation")) {
// allocation "ALLOCSTRING"
PARSE_STAGE_STRING("", "allocation", tmps);
// FIXME: this leaks
tmps = strDuplicate(tmps);
if (tmps) {
salloc->string = tmps;
}
} else if (!strcmp(token, "music")) {
// music { KEYVALUES... }
p = modConfigParseStageMusic(p, token, stagenum);
if (!p) {
return NULL;
}
} else if (!strcmp(token, "weather")) {
// weather { KEYVALUES... }
p = modConfigParseStageWeather(p, token, stagenum);
if (!p) {
return NULL;
}
} else {
sysLogPrintf(LOG_ERROR, "modconfig: stage 0x%02x: invalid key: %s", stagenum, token);
return NULL;
}
p = strParseToken(p, token, NULL);
}
if (token[0] != '}') {
sysLogPrintf(LOG_ERROR, "modconfig: unterminated stage 0x%02x block", stagenum);
return NULL;
}
return p;
}
s32 modConfigLoad(const char *fname)
{
u32 dataLen = 0;
char *data = fsFileLoad(fname, &dataLen);
if (!data) {
return false;
}
s32 success = true;
char token[UTIL_MAX_TOKEN + 1] = { 0 };
char *end = data + dataLen;
char *p = strParseToken(data, token, NULL);
while (p && token[0]) {
if (!strcmp(token, "stage")) {
// stage NUMBER { KEYVALUES... }
char *prev = p;
p = modConfigParseStage(p, token);
if (!p) {
sysLogPrintf(LOG_ERROR, "modconfig: malformed stage block at offset %d", prev - data);
success = false;
break;
}
} else {
// garbage
sysLogPrintf(LOG_ERROR, "modconfig: unexpected %s at offset %d", token[0] ? token : "end of file", p - data);
success = false;
break;
}
p = strParseToken(p, token, NULL);
}
sysMemFree(data);
return success;
}
s32 modTextureLoad(u16 num, void *dst, u32 dstSize)
{
static s32 dirExists = -1;
if (dirExists < 0) {
dirExists = (fsFileSize(MOD_TEXTURES_DIR "/") >= 0);
}
if (!dirExists) {
return -1;
}
char path[FS_MAXPATH + 1];
snprintf(path, sizeof(path), MOD_TEXTURES_DIR "/%04x.bin", num);
const s32 ret = fsFileLoadTo(path, dst, dstSize);
if (ret > 0) {
sysLogPrintf(LOG_NOTE, "mod: loaded external texture %04x", num);
}
return ret;
}
void *modSequenceLoad(u16 num, u32 *outSize)
{
static s32 dirExists = -1;
if (dirExists < 0) {
dirExists = (fsFileSize(MOD_SEQUENCES_DIR "/") >= 0);
}
if (!dirExists) {
return NULL;
}
char path[FS_MAXPATH + 1];
snprintf(path, sizeof(path), MOD_SEQUENCES_DIR "/%04x.bin", num);
if (fsFileSize(path) > 0) {
void *ret = fsFileLoad(path, outSize);
if (ret) {
sysLogPrintf(LOG_NOTE, "mod: loaded external sequence %04x", num);
return ret;
}
}
return NULL;
}
void *modAnimationLoadData(u16 num)
{
char path[FS_MAXPATH + 1];
// load the animation data
snprintf(path, sizeof(path), MOD_ANIMATIONS_DIR "/%04x.bin", num);
void *data = fsFileLoad(path, NULL);
if (!data) {
sysFatalError("External animation %04x has no data file.\nEnsure that it is placed at %s or delete the descriptor.", num, path);
}
return data;
}
s32 modAnimationLoadDescriptor(u16 num, struct animtableentry *anim)
{
static s32 dirExists = -1;
if (dirExists < 0) {
dirExists = (fsFileSize(MOD_ANIMATIONS_DIR "/") >= 0);
}
if (!dirExists) {
return false;
}
char path[FS_MAXPATH + 1];
// load the descriptor, if any
snprintf(path, sizeof(path), MOD_ANIMATIONS_DIR "/%04x.txt", num);
if (fsFileSize(path) <= 0) {
return false;
}
char *desc = fsFileLoad(path, NULL);
if (!desc) {
return false;
}
// parse the descriptor
char token[UTIL_MAX_TOKEN + 1] = { 0 };
char *p = strParseToken(desc, token, NULL);
s32 tmp = 0;
while (p && token[0]) {
if (!strcmp(token, "numframes")) {
PARSE_INT(path, "numframes", tmp, 0, 0xFFFF, false);
anim->numframes = tmp;
} else if (!strcmp(token, "bytesperframe")) {
PARSE_INT(path, "bytesperframe", tmp, 0, 0xFFFF, false);
anim->bytesperframe = tmp;
} else if (!strcmp(token, "headerlen")) {
PARSE_INT(path, "headerlen", tmp, 0, 0xFFFF, false);
anim->headerlen = tmp;
} else if (!strcmp(token, "framelen")) {
PARSE_INT(path, "framelen", tmp, 0, 0xFF, false);
anim->framelen = tmp;
} else if (!strcmp(token, "flags")) {
PARSE_INT(path, "flags", tmp, 0, 0xFF, false);
anim->flags = tmp;
} else {
sysLogPrintf(LOG_ERROR, "mod: %s: invalid key: %s", path, token);
return false;
}
p = strParseToken(p, token, NULL);
}
sysMemFree(desc);
sysLogPrintf(LOG_NOTE, "mod: loaded external animation %04x", num);
return true;
}
+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 = -1;
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
@@ -0,0 +1,305 @@
#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));
}
+422
View File
@@ -0,0 +1,422 @@
#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 "game/filelist.h"
#include "video.h"
#include "input.h"
#include "config.h"
#include "mpsetups.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);
extern struct menuitem g_MpPlayerSetup234MenuItems[];
extern struct menudialogdef g_NetJoinPlayerSetupMenuDialog;
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) {
// load the setup file when entering the Combat Simulator
mpsetupCopyAllFromPak();
mpsetupLoadCurrentFile();
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 | MENUDIALOGFLAG_STARTSELECTS,
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, false) < 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;
}
static MenuItemHandlerResult menuhandlerJoinPlayerSetup(s32 operation, struct menuitem *item, union handlerdata *data)
{
if (operation == MENUOP_SET) {
// load MP player file
filelistCreate(0, FILETYPE_MPPLAYER);
filelistsTick();
menuPushDialog(&g_NetJoinPlayerSetupMenuDialog);
}
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_028, // "Player Setup"
0,
menuhandlerJoinPlayerSetup,
},
{
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,
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 | MENUDIALOGFLAG_STARTSELECTS,
NULL,
};
struct menudialogdef g_NetJoinPlayerSetupMenuDialog = {
MENUDIALOGTYPE_DEFAULT,
L_MPMENU_028, // "Player Setup"
g_MpPlayerSetup234MenuItems,
NULL,
MENUDIALOGFLAG_DROPOUTONCLOSE | MENUDIALOGFLAG_STARTSELECTS,
NULL,
};
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+653
View File
@@ -0,0 +1,653 @@
#include <stdlib.h>
#include <ultra64.h>
#include <PR/ultrasched.h>
#include "lib/sched.h"
#include "lib/vars.h"
#include "constants.h"
#include "game/camdraw.h"
#include "game/cheats.h"
#include "game/debug.h"
#include "game/file.h"
#include "game/lang.h"
#include "game/race.h"
#include "game/body.h"
#include "game/stubs/game_000840.h"
#include "game/stubs/game_000850.h"
#include "game/stubs/game_000860.h"
#include "game/stubs/game_000870.h"
#include "game/smoke.h"
#include "game/stubs/game_0008e0.h"
#include "game/stubs/game_0008f0.h"
#include "game/stubs/game_000900.h"
#include "game/stubs/game_000910.h"
#include "game/tex.h"
#include "game/stubs/game_00b180.h"
#include "game/stubs/game_00b200.h"
#include "game/challenge.h"
#include "game/title.h"
#include "game/pdmode.h"
#include "game/objectives.h"
#include "game/endscreen.h"
#include "game/playermgr.h"
#include "game/game_1531a0.h"
#include "game/gfxmemory.h"
#include "game/lang.h"
#include "game/lv.h"
#include "game/timing.h"
#include "game/music.h"
#include "game/stubs/game_175f50.h"
#include "game/game_175f90.h"
#include "game/zbuf.h"
#include "game/game_1a78b0.h"
#include "game/mplayer/mplayer.h"
#include "game/pak.h"
#include "game/splat.h"
#include "game/utils.h"
#include "bss.h"
#include "lib/audiomgr.h"
#include "lib/args.h"
#include "lib/boot.h"
#include "lib/vm.h"
#include "lib/rzip.h"
#include "lib/vi.h"
#include "lib/fault.h"
#include "lib/crash.h"
#include "lib/dma.h"
#include "lib/joy.h"
#include "lib/main.h"
#include "lib/snd.h"
#include "lib/memp.h"
#include "lib/mema.h"
#include "lib/model.h"
#include "lib/profile.h"
#include "lib/videbug.h"
#include "lib/debughud.h"
#include "lib/anim.h"
#include "lib/rdp.h"
#include "lib/lib_34d0.h"
#include "lib/lib_2f490.h"
#include "lib/rmon.h"
#include "lib/rng.h"
#include "lib/str.h"
#include "data.h"
#include "types.h"
#include "system.h"
#include "console.h"
#include "net/net.h"
#include "net/netmsg.h"
extern u8 *g_MempHeap;
extern u32 g_MempHeapSize;
void rngSetSeed(u32 seed);
bool var8005d9b0 = false;
s32 g_StageNum = STAGE_TITLE;
u32 g_MainMemaHeapSize = 1024 * 300;
bool var8005d9bc = false;
s32 var8005d9c0 = 0;
s32 var8005d9c4 = 0;
bool g_MainGameLogicEnabled = true;
u32 g_MainNumGfxTasks = 0;
bool g_MainIsEndscreen = false;
s32 g_DoBootPakMenu = 0;
u32 var8005dd3c = 0x00000000;
u32 var8005dd40 = 0x00000000;
u32 var8005dd44 = 0x00000000;
u32 var8005dd48 = 0x00000000;
u32 var8005dd4c = 0x00000000;
u32 var8005dd50 = 0x00000000;
s32 g_MainChangeToStageNum = -1;
bool g_MainIsDebugMenuOpen = false;
struct stageallocation g_StageAllocations8Mb[] = {
{ STAGE_CITRAINING, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
{ STAGE_DEFECTION, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_INVESTIGATION, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_EXTRACTION, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_CHICAGO, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_G5BUILDING, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_VILLA, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma600" },
{ STAGE_INFILTRATION, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma500" },
{ STAGE_RESCUE, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma500" },
{ STAGE_ESCAPE, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma500" },
{ STAGE_AIRBASE, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_AIRFORCEONE, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_CRASHSITE, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_PELAGIC, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_DEEPSEA, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_DEFENSE, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_ATTACKSHIP, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_SKEDARRUINS, "-ml0 -me0 -mgfx110 -mgfxtra80 -mvtx100 -ma700" },
{ STAGE_MP_SKEDAR, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_RAVINE, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_PIPES, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_G5BUILDING, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_SEWERS, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_WAREHOUSE, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_BASE, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_COMPLEX, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_TEMPLE, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_FELICITY, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_AREA52, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_GRID, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_CARPARK, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_RUINS, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_FORTRESS, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_MP_VILLA, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_RUN, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_MP2, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_MP6, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_MP7, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_MP8, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_MP14, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_MP16, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_MP17, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_MP18, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_MP19, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_MP20, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_ASH, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
{ STAGE_28, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
{ STAGE_MBR, "-ml0 -me0 -mgfx120 -mvtx100 -ma700" },
{ STAGE_TEST_SILO, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_24, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
{ STAGE_MAIANSOS, "-ml0 -me0 -mgfx120 -mvtx100 -ma500" },
{ STAGE_RETAKING, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
{ STAGE_TEST_DEST, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
{ STAGE_2B, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
{ STAGE_WAR, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
{ STAGE_TEST_UFF, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
{ STAGE_TEST_OLD, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
{ STAGE_DUEL, "-ml0 -me0 -mgfx120 -mvtx100 -ma700" },
{ STAGE_TEST_LAM, "-ml0 -me0 -mgfx120 -mvtx98 -ma400" },
{ STAGE_TEST_ARCH, "-ml0 -me0 -mgfx200 -mvtx200 -ma400" },
{ STAGE_TEST_LEN, "-ml0 -me0 -mgfx120 -mvtx98 -ma300" },
{ STAGE_TITLE, "-ml0 -me0 -mgfx80 -mvtx20 -ma001" },
{ 0, "-ml0 -me0 -mgfx120 -mvtx98 -ma300" },
};
struct stageallocation g_StageAllocations4Mb[] = {
{ STAGE_MP_SKEDAR, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_PIPES, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_AREA52, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_RAVINE, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_G5BUILDING, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_SEWERS, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_WAREHOUSE, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_BASE, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_COMPLEX, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_TEMPLE, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_FELICITY, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_GRID, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_TEST_RUN, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_CARPARK, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_RUINS, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_MP_FORTRESS, "-ml0 -me0 -mgfx96 -mvtx96 -ma130" },
{ STAGE_MP_VILLA, "-ml0 -me0 -mgfx96 -mvtx96 -ma140" },
{ STAGE_TEST_MP2, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
{ STAGE_TEST_MP6, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
{ STAGE_TEST_MP7, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
{ STAGE_TEST_MP8, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
{ STAGE_TEST_MP14, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
{ STAGE_TEST_MP16, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
{ STAGE_TEST_MP17, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
{ STAGE_TEST_MP18, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
{ STAGE_TEST_MP19, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
{ STAGE_TEST_MP20, "-ml0 -me0 -mgfx96 -mvtx96 -ma115" },
{ STAGE_TEST_LEN, "-ml0 -me0 -mgfx100 -mvtx96 -ma120" },
{ STAGE_4MBMENU, "-mgfx100 -mvtx50 -ma50" },
{ STAGE_TITLE, "-ml0 -me0 -mgfx80 -mvtx20 -ma001" },
{ 0, "-ml0 -me0 -mgfx100 -mvtx96 -ma300" },
};
Gfx var8005dcc8[] = {
gsSPSegment(0x00, 0x00000000),
gsSPDisplayList(&var800613a0),
gsSPDisplayList(&var80061380),
gsDPFullSync(),
gsSPEndDisplayList(),
};
s32 g_MainIsBooting = 1;
void mainInit(void)
{
s32 x;
s32 i;
s32 j;
u32 addr;
faultInit();
dmaInit();
amgrInit();
varsInit();
mempInit();
memaInit();
joyInit();
joyReset();
var8005d9b0 = rmonIsDisabled();
g_Is4Mb = (osGetMemSize() <= 0x400000);
g_VmShowStats = 0;
// no copyright screen
viSetMode(VIMODE_HI);
viConfigureForLegal();
viBlack(true);
viUpdateMode();
filesInit();
if (var8005d9b0) {
argSetString(" -ml0 -me0 -mgfx100 -mvtx50 -mt700 -ma400");
}
mempSetHeap(g_MempHeap, g_MempHeapSize);
mempResetPool(MEMPOOL_8);
mempResetPool(MEMPOOL_PERMANENT);
crashReset();
challengesInit();
utilsInit();
texInit();
langInit();
lvInit();
cheatsInit();
textInit();
dhudInit();
playermgrInit();
frametimeInit();
profileInit();
smokesInit();
mpInit(true);
pheadInit();
paksInit();
pheadInit2();
animsInit();
racesInit();
bodiesInit();
titleInit();
modelSetDistanceChecksDisabled(true); // don't use LODs
g_MainIsBooting = 0;
}
void mainProc(void)
{
mainInit();
rdpInit();
sndInit();
while (true) {
mainLoop();
}
}
/**
* It's suspected that this function would have allowed developers to override
* the value of variables while the game is running in order to view their
* effects immediately rather than having to recompile the game each time.
*
* The developers would have used rmon to create a table of name/value pairs,
* then this function would have looked up the given variable name in the table
* and written the new value to the variable's address.
*/
void mainOverrideVariable(char *name, void *value)
{
// empty
}
/**
* This function enters an infinite loop which iterates once per stage load.
* Within this loop is an inner loop which runs very frequently and decides
* whether to run mainTick on each iteration.
*
* NTSC beta checks two shorts at an offset 64MB into the development board
* and refuses to continue if they are not any of the allowed values.
* Decomp patches these reads in its build system so it can be played
* without the development board.
*/
void mainLoop(void)
{
s32 ending = false;
s32 index;
s32 numplayers;
u32 stack;
func0f175f98();
var8005d9c4 = 0;
argGetLevel(&g_StageNum);
if (g_DoBootPakMenu) {
g_Vars.pakstocheck = 0xfd;
g_StageNum = STAGE_BOOTPAKMENU;
}
if (g_StageNum != STAGE_TITLE) {
titleSetNextStage(g_StageNum);
if (g_StageNum < STAGE_TITLE) {
func0f01b148(0);
if (argFindByPrefix(1, "-hard")) {
lvSetDifficulty(argFindByPrefix(1, "-hard")[0] - '0');
}
}
}
if (g_StageNum == STAGE_CITRAINING && IS4MB()) {
g_StageNum = STAGE_4MBMENU;
}
rngSetSeed(osGetCount());
// Outer loop - this is infinite because ending is never changed
while (!ending) {
g_MainNumGfxTasks = 0;
g_MainGameLogicEnabled = true;
g_MainIsEndscreen = false;
if (var8005d9b0 && var8005d9c4 == 0) {
index = -1;
if (IS4MB()) {
if (g_StageNum < STAGE_TITLE && getNumPlayers() >= 2) {
index = 0; \
while (g_StageAllocations4Mb[index].stagenum) { \
if (g_StageAllocations4Mb[index].stagenum == g_StageNum + 400) { \
break; \
} \
index++;
}
if (g_StageAllocations4Mb[index].stagenum == 0) {
index = -1;
}
}
if (index);
if (index < 0) {
index = 0;
while (g_StageAllocations4Mb[index].stagenum) {
if (g_StageNum == g_StageAllocations4Mb[index].stagenum) {
break;
}
index++;
}
}
argSetString(g_StageAllocations4Mb[index].string);
} else {
// 8MB
if (g_StageNum < STAGE_TITLE && getNumPlayers() >= 2) {
index = 0; \
while (g_StageAllocations8Mb[index].stagenum) { \
if (g_StageNum + 400 == g_StageAllocations8Mb[index].stagenum) { \
break; \
} \
index++;
}
if (g_StageAllocations8Mb[index].stagenum == 0) {
index = -1;
}
}
if (index < 0) {
index = 0;
while (g_StageAllocations8Mb[index].stagenum) {
if (g_StageNum == g_StageAllocations8Mb[index].stagenum) {
break;
}
index++;
}
}
argSetString(g_StageAllocations8Mb[index].string);
}
}
var8005d9c4 = 0;
mempResetPool(MEMPOOL_7);
mempResetPool(MEMPOOL_STAGE);
filesStop(4);
if (argFindByPrefix(1, "-ma")) {
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);
langReset(g_StageNum);
playermgrReset();
if (g_StageNum >= STAGE_TITLE) {
numplayers = 0;
} else {
if (argFindByPrefix(1, "-play")) {
numplayers = strtol(argFindByPrefix(1, "-play"), NULL, 0);
} else {
numplayers = 1;
}
if (getNumPlayers() >= 2) {
numplayers = getNumPlayers();
}
}
if (numplayers < 2) {
g_Vars.bondplayernum = 0;
g_Vars.coopplayernum = -1;
g_Vars.antiplayernum = -1;
} else if (argFindByPrefix(1, "-coop")) {
g_Vars.bondplayernum = 0;
g_Vars.coopplayernum = 1;
g_Vars.antiplayernum = -1;
} else if (argFindByPrefix(1, "-anti")) {
g_Vars.bondplayernum = 0;
g_Vars.coopplayernum = -1;
g_Vars.antiplayernum = 1;
}
playermgrAllocatePlayers(numplayers);
if (argFindByPrefix(1, "-mpbots")) {
g_Vars.lvmpbotlevel = 1;
}
if (g_Vars.coopplayernum >= 0 || g_Vars.antiplayernum >= 0) {
#ifdef PLATFORM_N64
g_MpSetup.chrslots = 0x03;
#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
mpReset();
} else if (g_Vars.perfectbuddynum) {
mpReset();
} else if (g_Vars.mplayerisrunning == false
&& (numplayers >= 2 || g_Vars.lvmpbotlevel || argFindByPrefix(1, "-play"))) {
g_MpSetup.chrslots = 1;
for (s32 i = 1; i < numplayers; ++i) {
g_MpSetup.chrslots |= 1 << i;
}
g_MpSetup.stagenum = g_StageNum;
mpReset();
}
gfxReset();
joyReset();
dhudReset();
zbufReset(g_StageNum);
lvReset(g_StageNum);
viReset(g_StageNum);
frametimeCalculate();
profileReset();
while (g_MainChangeToStageNum < 0) {
const s32 cycles = osGetCount() - g_Vars.thisframestartt;
if (!g_Vars.mininc60 || (cycles >= g_Vars.mininc60 * CYCLES_PER_FRAME - CYCLES_PER_FRAME / 2)) {
schedStartFrame(&g_Sched);
mainTick();
schedEndFrame(&g_Sched);
}
if (g_TickExtraSleep) {
sysSleep(EXTRA_SLEEP_TIME);
}
}
lvStop();
mempDisablePool(MEMPOOL_STAGE);
mempDisablePool(MEMPOOL_7);
filesStop(4);
viBlack(true);
pak0f116994();
g_StageNum = g_MainChangeToStageNum;
g_MainChangeToStageNum = -1;
}
}
void mainTick(void)
{
Gfx *gdl = NULL;
Gfx *gdlstart = NULL;
OSScMsg msg = {OS_SC_DONE_MSG};
s32 i;
if (g_MainChangeToStageNum < 0) {
frametimeCalculate();
profileReset();
profileSetMarker(PROFILE_MAINTICK_START);
joyDebugJoy();
schedSetCrashEnable2(false);
if (g_MainGameLogicEnabled) {
gdl = gdlstart = gfxGetMasterDisplayList();
gDPSetTile(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_16b, 0, 0x0000, G_TX_LOADTILE, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD);
gDPSetTile(gdl++, G_IM_FMT_RGBA, G_IM_SIZ_4b, 0, 0x0100, 6, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOLOD);
lvTick();
playermgrShuffle();
if (g_StageNum < STAGE_TITLE) {
for (i = 0; i < PLAYERCOUNT(); i++) {
setCurrentPlayerNum(playermgrGetPlayerAtOrder(i));
if (g_StageNum != STAGE_TEST_OLD || !titleIsKeepingMode()) {
viSetViewPosition(g_Vars.currentplayer->viewleft, g_Vars.currentplayer->viewtop);
viSetFovAspectAndSize(
g_Vars.currentplayer->fovy, g_Vars.currentplayer->aspect,
g_Vars.currentplayer->viewwidth, g_Vars.currentplayer->viewheight);
}
lvTickPlayer();
}
}
gdl = lvRender(gdl);
if (debugGetProfileMode() >= 2) {
gdl = profileRender(gdl);
}
gdl = conRender(gdl);
gdl = netDebugRender(gdl);
gDPFullSync(gdl++);
gSPEndDisplayList(gdl++);
}
if (g_MainGameLogicEnabled) {
gfxSwapBuffers();
viUpdateMode();
}
rdpCreateTask(gdlstart, gdl, 0, (uintptr_t) &msg);
memaPrint();
profileSetMarker(PROFILE_MAINTICK_END);
}
}
void mainEndStage(void)
{
sndStopNosedive();
if (!g_MainIsEndscreen) {
pak0f11c6d0();
joyDisableTemporarily();
if (g_Vars.coopplayernum >= 0) {
s32 prevplayernum = g_Vars.currentplayernum;
s32 i;
for (i = 0; i < LOCALPLAYERCOUNT(); i++) {
setCurrentPlayerNum(i);
endscreenPushCoop();
}
setCurrentPlayerNum(prevplayernum);
musicStartMenu();
} else if (g_Vars.antiplayernum >= 0) {
s32 prevplayernum = g_Vars.currentplayernum;
s32 i;
for (i = 0; i < LOCALPLAYERCOUNT(); i++) {
setCurrentPlayerNum(i);
endscreenPushAnti();
}
setCurrentPlayerNum(prevplayernum);
musicStartMenu();
} else if (g_Vars.normmplayerisrunning) {
mpEndMatch();
} else {
endscreenPrepare();
musicStartMenu();
}
netServerStageEnd();
}
g_MainIsEndscreen = true;
}
/**
* Change to the given stage at the end of the current frame.
*/
void mainChangeToStage(s32 stagenum)
{
pak0f11c6d0();
g_MainChangeToStageNum = stagenum;
}
s32 mainGetStageNum(void)
{
return g_StageNum;
}
void func0000e990(void)
{
objectivesCheckAll();
objectivesDisableChecking();
mainEndStage();
}
+428
View File
@@ -0,0 +1,428 @@
#include <PR/ultratypes.h>
#include <PR/ultrasched.h>
#include "lib/boot.h"
#include "lib/sched.h"
#include "constants.h"
#include "game/menugfx.h"
#include "bss.h"
#include "lib/args.h"
#include "lib/audiomgr.h"
#include "lib/reset.h"
#include "lib/rzip.h"
#include "lib/crash.h"
#include "lib/main.h"
#include "lib/snd.h"
#include "lib/pimgr.h"
#include "lib/profile.h"
#include "lib/rmon.h"
#include "lib/lib_48150.h"
#include "lib/vi.h"
#include "lib/joy.h"
#include "data.h"
#include "types.h"
#include "video.h"
#include "audio.h"
#include "input.h"
#include "console.h"
#include "mixer.h"
#include "net/net.h"
/*
* private typedefs and defines
*/
#define VIDEO_MSG 666
#define RSP_DONE_MSG 667
#define RDP_DONE_MSG 668
#define PRE_NMI_MSG 669
/*
* OSScTask state
*/
#define OS_SC_DP 0x0001 /* set if still needs dp */
#define OS_SC_SP 0x0002 /* set if still needs sp */
#define OS_SC_YIELD 0x0010 /* set if yield requested */
#define OS_SC_YIELDED 0x0020 /* set if yield completed */
/*
* OSScTask->flags type identifier
*/
#define OS_SC_XBUS (OS_SC_SP | OS_SC_DP)
#define OS_SC_DRAM (OS_SC_SP | OS_SC_DP | OS_SC_DRAM_DLIST)
#define OS_SC_DP_XBUS (OS_SC_SP)
#define OS_SC_DP_DRAM (OS_SC_SP | OS_SC_DRAM_DLIST)
#define OS_SC_SP_XBUS (OS_SC_DP)
#define OS_SC_SP_DRAM (OS_SC_DP | OS_SC_DRAM_DLIST)
/*
* private functions
*/
void __scMain(void *arg);
void __scHandleTasks(OSSched *s);
void __scHandleRSP(OSSched *s);
void __scHandleRDP(OSSched *s);
void __scAppendList(OSSched *s, OSScTask *t);
OSScTask *__scTaskReady(OSScTask *t);
s32 __scTaskComplete(OSSched *s,OSScTask *t);
void __scExec(OSSched *sc, OSScTask *sp, OSScTask *dp);
void __scYield(OSSched *s);
s32 __scSchedule(OSSched *sc, OSScTask **sp, OSScTask **dp, s32 availRCP);
OSViMode var8008dcc0[NUM_GFXTASKS];
OSViMode *var8008dd60[NUM_GFXTASKS];
OSViMode var8008dd68[NUM_GFXTASKS];
s32 var8008de08;
s32 g_ViCurVStart0;
s32 g_ViCurVStart1;
u32 var8008de14;
OSTimer g_SchedRspTimer;
u32 g_SchedDpCounters[4];
struct artifact g_ArtifactLists[3][120];
u8 g_SchedSpecialArtifactIndexes[3];
s32 g_SchedWriteArtifactsIndex;
s32 g_SchedFrontArtifactsIndex;
s32 g_SchedPendingArtifactsIndex;
bool g_SchedCrashedUnexpectedly = false;
bool g_SchedCrashEnable1 = false;
bool g_SchedCrashEnable2 = false;
u32 g_SchedCrashRenderInterval = 45000000;
u32 g_SchedCrashLastRendered = 0;
s32 var8005ce74 = 0;
f32 g_ViXScalesBySlot[NUM_GFXTASKS] = {1, 1};
f32 g_ViYScalesBySlot[NUM_GFXTASKS] = {1, 1};
bool g_SchedViModesPending[NUM_GFXTASKS] = {false, false};
s32 g_ViUnblackTimer = NUM_FRAMEBUFFERS + 1;
s32 g_ViShakeDirection = 1;
s32 g_ViShakeIntensity = 0;
f32 g_ViShakeIntensityMult = 1.f;
s32 g_ViShakeTimer = 0;
u32 var8005cea0 = 0;
u32 var8005cea4 = 0;
OSScMsg g_SchedRspMsg = {OS_SC_RSP_MSG};
bool g_SchedIsFirstTask = true;
s32 g_PrevFrameFb = -1;
s32 g_BlurFb = -1;
s32 g_BlurFbCapTimer = -1;
bool g_BlurFbDirty = true;
void schedSetCrashEnable1(bool enable)
{
g_SchedCrashEnable1 = enable;
}
void schedSetCrashedUnexpectedly(bool enable)
{
g_SchedCrashedUnexpectedly = enable;
}
void schedSetCrashEnable2(bool enable)
{
g_SchedCrashEnable2 = enable;
}
void schedSetCrashRenderInterval(u32 cycles)
{
g_SchedCrashRenderInterval = cycles;
}
void schedRenderCrashOnBuffer(void *framebuffer)
{
if ((g_SchedCrashEnable2 && g_SchedCrashEnable1) || g_SchedCrashedUnexpectedly) {
// crashRenderFrame(framebuffer);
g_SchedCrashLastRendered = osGetCount();
}
}
void schedRenderCrashPeriodically(u32 framecount)
{
if ((framecount & 0xf) == 0 && ((g_SchedCrashEnable2 && g_SchedCrashEnable1) || g_SchedCrashedUnexpectedly)) {
if (osGetCount() - g_SchedCrashLastRendered > g_SchedCrashRenderInterval) {
// crashRenderFrame(g_FrameBuffers[0]);
// crashRenderFrame(g_FrameBuffers[1]);
}
}
}
void schedInitCrashLastRendered(void)
{
g_SchedCrashLastRendered = osGetCount();
}
void osCreateScheduler(OSSched *sc, OSThread *thread, u8 mode, u32 numFields)
{
sc->curRSPTask = 0;
sc->curRDPTask = 0;
sc->clientList = 0;
sc->frameCount = 0;
sc->audioListHead = 0;
sc->gfxListHead = 0;
sc->audioListTail = 0;
sc->gfxListTail = 0;
sc->retraceMsg.type = OS_SC_RETRACE_MSG;
sc->prenmiMsg.type = OS_SC_PRE_NMI_MSG;
sc->thread = thread;
osCreateMesgQueue(&sc->interruptQ, sc->intBuf, OS_SC_MAX_MESGS);
osCreateMesgQueue(&sc->cmdQ, sc->cmdMsgBuf, OS_SC_MAX_MESGS);
osCreateViManager(OS_PRIORITY_VIMGR);
var8008de08 = osViModeTable[mode].comRegs.hStart;
g_ViCurVStart0 = osViModeTable[mode].fldRegs[0].vStart;
g_ViCurVStart1 = osViModeTable[mode].fldRegs[1].vStart;
var8008dd60[0] = &var8008dd68[0];
var8008dd60[1] = &var8008dd68[1];
var8008dd68[0] = osViModeTable[mode];
var8008dd68[1] = osViModeTable[mode];
osViSetEvent(&sc->interruptQ, (OSMesg)VIDEO_MSG, numFields);
schedInitCrashLastRendered();
g_PrevFrameFb = videoCreateFramebuffer(0, 0, false, true);
g_BlurFb = videoCreateFramebuffer(0, 0, false, true);
}
void osScAddClient(OSSched *sc, OSScClient *c, OSMesgQueue *msgQ, bool is30fps)
{
c->msgQ = msgQ;
c->is30fps = is30fps;
c->next = sc->clientList;
sc->clientList = c;
}
OSMesgQueue *osScGetCmdQ(OSSched *sc)
{
return &sc->cmdQ;
}
void __scUpdateViMode(void)
{
if (g_SchedIsFirstTask) {
osViBlack(false);
g_SchedIsFirstTask = false;
}
var8005ce74 = (var8005ce74 + 1) % 2;
if (g_SchedViModesPending[1 - var8005ce74]) {
// TODO: make this a little less awkward
extern struct rend_vidat *g_ViBackData;
videoUpdateNativeResolution(g_ViBackData->bufx, g_ViBackData->bufy);
g_SchedViModesPending[1 - var8005ce74] = false;
}
if (g_ViUnblackTimer != 0 && g_ViUnblackTimer <= NUM_FRAMEBUFFERS) {
g_ViUnblackTimer--;
}
}
/**
* Nintendo's sheduler accepts tasks on a "command" message queue.
* This isn't used here.
*
* In PD, the main and audio threads submit tasks by calling this function
* instead. It temporarily increases the calling thread's priority above the
* scheduler, adds the task to the linked list directly and attempts to execute
* it. This is faster than the queue method because it avoids switching threads.
*/
void schedSubmitTask(OSSched *sc, OSScTask *t)
{
if (sc->doAudio && t->list.t.type == M_AUDTASK) {
// send this into the mixer
} else if (t->list.t.type == M_GFXTASK) {
videoSubmitCommands((Gfx *)t->list.t.data_ptr);
}
}
void schedStartFrame(OSSched *sc)
{
videoStartFrame();
if (g_Vars.diffframe60) {
if (g_NetMode) {
videoCapFramerate(120);
netStartFrame();
} else {
videoCapFramerate(0);
}
}
}
void schedAudioFrame(OSSched *sc)
{
s32 i;
if (!g_SndDisabled) {
for (i = 0; i < g_Vars.diffframe60; i++) {
amgrFrame();
audioEndFrame();
}
}
}
/**
* Handle a retrace (vsync) event.
*
* Audio tasks are scheduled based on retrace + a timer (approximately 6ms).
* On NTSC, this is done on every second frame if 8MB, or every second frame
* if 4MB. I guess less memory means the audio queue has to be kept smaller
* and processed more frequently. On PAL, it's every second frame regardless.
*
* Controller input is polled here.
*
* Lastly, if there's crash information available then it will be checked and
* rendered periodically (once every 16 retraces). I guess this makes it render
* if the RDP has hung.
*/
void schedEndFrame(OSSched *sc)
{
static bool netDebugKey = false;
sc->frameCount++;
#if PAL
if (!g_Resetting && (sc->frameCount & 1)) {
// osStopTimer(&g_SchedRspTimer);
// osSetTimer(&g_SchedRspTimer, 280000, 0, amgrGetFrameMesgQueue(), &g_SchedRspMsg);
}
#else
if (!g_Resetting && ((sc->frameCount & 1) || IS4MB())) {
// osStopTimer(&g_SchedRspTimer);
// osSetTimer(&g_SchedRspTimer, 280000, 0, amgrGetFrameMesgQueue(), &g_SchedRspMsg);
}
#endif
if (!g_Resetting) {
viHandleRetrace();
}
inputUpdate();
conTick();
const bool newKey = inputKeyPressed(VK_F9);
if (!netDebugKey && newKey) {
g_NetDebugDraw = !g_NetDebugDraw;
}
netDebugKey = newKey;
joyStartReadData(&g_PiMesgQueue);
joyReadData();
joy00014238();
if (g_Vars.diffframe60) {
netEndFrame();
}
sndHandleRetrace();
schedAudioFrame(sc);
schedRenderCrashPeriodically(sc->frameCount);
videoEndFrame();
if (g_MainIsBooting == 0) {
schedConsiderScreenshot();
}
// check for vid mode changes
__scUpdateViMode();
}
void schedInitArtifacts(void)
{
s32 i;
s32 j;
for (i = 0; i < 3; i++) {
for (j = 0; j < MAX_ARTIFACTS; j++) {
g_ArtifactLists[i][j].type = ARTIFACTTYPE_FREE;
}
g_SchedSpecialArtifactIndexes[i] = 0;
}
}
/**
* The write list is an artifact list that is not currently being displayed on
* the screen. Update logic can write here to put artifacts on the next frame.
*/
struct artifact *schedGetWriteArtifacts(void)
{
return g_ArtifactLists[g_SchedWriteArtifactsIndex];
}
/**
* The front list is the artifact list that is currently being displayed on the
* screen. Rendering logic reads this list. The list may be re-used for multiple
* frames in a row during lag.
*/
struct artifact *schedGetFrontArtifacts(void)
{
return g_ArtifactLists[g_SchedFrontArtifactsIndex];
}
/**
* The pending list is possibly misnamed. I'm not sure how this list works.
*
* @TODO: Investigate.
*/
struct artifact *schedGetPendingArtifacts(void)
{
return g_ArtifactLists[g_SchedPendingArtifactsIndex];
}
void schedIncrementWriteArtifacts(void)
{
g_SchedWriteArtifactsIndex = (g_SchedWriteArtifactsIndex + 1) % 3;
}
void schedIncrementFrontArtifacts(void)
{
g_SchedFrontArtifactsIndex = (g_SchedFrontArtifactsIndex + 1) % 3;
}
void schedIncrementPendingArtifacts(void)
{
g_SchedPendingArtifactsIndex = (g_SchedPendingArtifactsIndex + 1) % 3;
}
void schedResetArtifacts(void)
{
g_SchedWriteArtifactsIndex = 0;
g_SchedFrontArtifactsIndex = 1;
g_SchedPendingArtifactsIndex = 0;
}
void schedUpdatePendingArtifacts(void)
{
g_SchedSpecialArtifactIndexes[g_SchedPendingArtifactsIndex] = 0;
schedIncrementPendingArtifacts();
}
void schedConsiderScreenshot(void)
{
if (g_MenuData.screenshottimer == 1) {
if (IS8MB()) {
menugfxCreateBlur();
}
g_MenuData.screenshottimer = 0;
}
if (g_BlurFbCapTimer == 0) {
videoCopyFramebuffer(g_BlurFb, 0, -1, -1);
g_BlurFbCapTimer = -1;
g_BlurFbDirty = false;
} else if (g_BlurFbCapTimer > 0) {
--g_BlurFbCapTimer;
} else if (g_BlurFbCapTimer < 0) {
// no blur requested this frame, mark blur fb dirty
g_BlurFbDirty = true;
}
if (g_MenuData.screenshottimer >= 2) {
g_MenuData.screenshottimer--;
}
}
+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;
}
+107
View File
@@ -0,0 +1,107 @@
#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);
#if MAX_PLAYERS > 4
// make space for the extra players
cfg->setup.chrslots = (cfg->setup.chrslots & 0x000f) | ((cfg->setup.chrslots & 0x0ff0) << 4);
#endif
// 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;
}
Loaded 100 of 373 files, more files were not shown because too many files have changed in this diff. Show more