Compare commits

..
Author SHA1 Message Date
Goober5000 17b01fa8eb Merge pull request #1906 from plieblang/LabShipMenuImprovement
Show ship directly when clicking on it in the F3 lab
2018-10-23 22:41:16 -04:00
Goober5000 45ea62a9a2 Merge pull request #1907 from plieblang/ShipInvisibleAutoTargeting
ship-invisible doesn't turn off autotargeting
2018-10-23 22:41:02 -04:00
plieblang 979a4b0924 Flip default param value 2018-10-22 14:42:42 -05:00
Goober5000 e1db71fb69 Merge pull request #1910 from wookieejedi/FixOnShipDepart
Fix to "On Ship Depart" to incorporate Goober's feedback
2018-10-22 14:27:03 -04:00
niffiwan c33d406942 Merge pull request #1909 from asarium/build/travis_windows
Test Windows compilation with Travis CI
2018-10-22 22:03:25 +10:00
plieblang 30baac39a9 Combine cease_targeting functions 2018-10-21 13:13:08 -05:00
wookieejedi 50dbbc4687 Incorporates Goober's feedback
Moved new "On Ship Depart" hook exectuion to ship_cleanup.
2018-10-21 01:11:16 -04:00
niffiwan e19a6f9e01 Merge pull request #1905 from wookieejedi/OnDepartHook
Add '$On Ship Depart' Conditional Hook
2018-10-21 08:52:53 +10:00
niffiwan d9184545f7 Merge pull request #1902 from plieblang/BriefingVoiceUnpause
Play simulated speech if mission is launched while briefing is paused
2018-10-21 08:52:18 +10:00
asarium 5c07d181ad Test Windows compilation with Travis CI
Travis CI recently added support for running builds in Windows. This
adds support for testing compilation on Windows using that feature.

The newer version of Visual Studio and MinGW required some code changes
and an update of Google Test which is included in this commit.
2018-10-20 23:44:10 +02:00
wookieejedi 140fed2812 Added "Method" hook variable to "On Ship Depart" 2018-10-20 16:41:59 -04:00
plieblang dd2fd3ee5c Address feedback 2018-10-20 10:45:51 -05:00
plieblang dd7c36e43d ship-invisible doesn't turn off autotargeting 2018-10-19 18:49:53 -05:00
plieblang 409c7da2d7 Clicking on a ship in the lab shows it directly 2018-10-19 15:00:07 -05:00
wookieejedi 791e22bc1d Add On Ship Depart Conditional Hook 2018-10-18 17:50:22 -04:00
plieblang 6a93715c9b Clarify fsspeech_pause call 2018-10-18 11:28:45 -05:00
Goober5000 8fee9804df Merge pull request #1903 from plieblang/LabUpdatePOFName
Update displayed POF name in the F3 lab when new ship is selected
2018-10-17 23:32:53 -04:00
plieblang 2dc6d64c37 Update POF name when new ship is selected 2018-10-17 19:31:37 -05:00
plieblang a8142b8f80 Solution that actually compiles 2018-10-17 15:56:12 -05:00
plieblang 53f98cda99 Play simulated speech if mission is launched while briefing is paused 2018-10-17 01:03:39 -05:00
m!m 115d06a051 Merge pull request #1899 from Artyrm/Fix_missing_HUD
Fix missing HUD bug
2018-10-14 19:22:37 +02:00
m!m 485af1bad3 Merge pull request #1895 from Artyrm/Adapt_barracks_interface
Barracks stats adaptation for longer Unicode strings.
2018-10-14 19:22:27 +02:00
Goober5000 0ca5ade5ef Merge pull request #1894 from Artyrm/master
More friendly assert if used font misses a glyph.
2018-10-14 13:22:05 -04:00
Artyrm ff601db6fc Switched to hud_config_as_player() 2018-10-14 18:15:18 +03:00
Artyrm 686bc35cff Moved variables, gave mean. names and descr. 2018-10-14 16:07:59 +03:00
Artyrm ffe9a085b6 Improved readability. 2018-10-14 15:39:48 +03:00
Artyrm 33df766edf #ifdefed debug parts. 2018-10-14 15:25:17 +03:00
Artyrm 9a6227e7b0 Fixed grammar. 2018-10-14 14:58:53 +03:00
m!m c664eac1ee Merge pull request #1898 from ngld/enhance/betterBmErrors
If an icon can't be loaded, display an error instead of asserting.
2018-10-14 12:31:03 +02:00
Artyrm a7a9514fd1 Little cleanups. 2018-10-13 19:37:17 +03:00
Artyrm b402d9158c Use .is_observer flag. Add HUD restore in DEBRIEF state. 2018-10-13 18:56:21 +03:00
Artyrm c1b055a685 Start using hud_config_restore(). 2018-10-13 16:58:17 +03:00
ngld 412197d3e9 Gracefully handle missing briefing icons. 2018-10-13 06:16:16 +02:00
Artyrm 98f1d690f6 Fix Clang warnings. 2018-10-12 19:18:24 +03:00
Goober5000 842dbb1b75 Merge pull request #1888 from plieblang/AIProfileABFlag
Add "$free afterburner use" flag to ai_profiles.tbl
2018-10-12 12:12:26 -04:00
Artyrm df8e85f22e String width adapts, orig. behaviour is intact. 2018-10-12 17:57:44 +03:00
Goober5000 73482a6d62 Merge pull request #1896 from wookieejedi/FixOnArriveforDockWings
Fixes missing "On Ship Arrive" with Docked Wings
2018-10-11 22:38:04 -04:00
wookieejedi afa7976018 Removed redundant syntax 2018-10-11 18:36:05 -04:00
wookieejedi 0d355982d4 Update code/mission/missionparse.cpp 2018-10-11 11:43:40 -04:00
wookieejedi 7f9021cbdb Fixed missing "=" 2018-10-11 11:41:53 -04:00
wookieejedi 1450c71e2e Improve dock check with bool
Uses boolean value to determine if wing is docked, incoroprates that bool into if block for setting On Ship Arrive hook.
2018-10-11 11:39:16 -04:00
wookieejedi d80e6d0f71 Fixed missing "_" 2018-10-10 18:05:48 -04:00
wookieejedi f6dd3b09ab Remove incorrect placement 2018-10-10 17:05:22 -04:00
wookieejedi bc5ef0b28d Fixed anchor call and null bug 2018-10-10 13:12:18 -04:00
wookieejedi 8e618ffaec Add HV to Docked Wings
Fixs bug by adding the conditional hook call "On Ship Arrive" to docked wings that arrive.
2018-10-10 12:24:30 -04:00
Artyrm 889474688c Barracks stats adaptation for longer Unicode strings. 2018-10-10 18:01:06 +03:00
Artyrm d56cb8fc62 Even mor specific, gcc syntax. 2018-10-09 19:29:00 +03:00
Artyrm 98f196ee48 Compiler-specific fallthrough. 2018-10-09 19:13:36 +03:00
Artyrm 9f4ad9d1eb #ifdefed print for Release. Tried the strictest fallthrough comment 2018-10-09 18:29:00 +03:00
Artyrm a69e1d7308 Proper args handling. Extern C is also back. 2018-10-09 17:48:42 +03:00
Artyrm 34d1bf03f9 Got rid of unnes. #ifded. 2018-10-09 17:28:03 +03:00
wookieejedi 9fcd96ff97 Adds Accept Mission Outcome as new Conditional Hook (#1893)
* Adds Accept Mission Outcome Event to Game Events

Adds Accept Mission Outcome Event to Game Events, so scritps and other things can be called only when a campaign mission is accepted.

* Fixed double entry

* Define CHA_CMISSIONACCEPT

Adds line to define new conditional hook, CHA_CMISSIONACCEPT

* Add flag_def_list for On Campaign Mission Accept

Adds the proper flag_def_list for "On Campaign Mission Accept" CHA_CMISSIONACCEPT

* Runs New Conditional Hook

Runs the new conditional hook for "On Campaign Mission Accept"

* Reverts event changes

* Reverts state changese

* Reverts post_event change
2018-10-08 18:13:02 +02:00
Artyrm 2b77721c79 Tweaked function type a little for compilers. 2018-10-08 12:45:14 +03:00
Artyrm 95fafa50c4 Changed printf function. Explicit fallthrough. 2018-10-08 12:01:55 +03:00
Artyrm cac07391ca More user-friendly assert on missed glyph in font. 2018-10-07 23:44:27 +03:00
Goober5000 9daeb7f417 Merge pull request #1891 from Artyrm/master
Switch communication messages to use SCP_string
2018-10-07 11:11:06 -04:00
Artyrm f0ba0265fd New version of stb_truetype.h, just in case. 2018-10-07 15:35:12 +03:00
Artyrm 5b77cad5ac Merge branch 'ComMsg_Unicode_fix' 2018-10-07 14:57:16 +03:00
Artyrm 3f024cb324 And FRED fix as well. 2018-10-07 14:56:50 +03:00
m!m 1d60d25cf5 Merge pull request #1890 from wookieejedi/HyperspaceSounds
Fix missing Warpin sounds from Hyperspace Warpin Effect
2018-10-07 09:36:16 +02:00
Artyrm be5c98c7e2 Merge branch 'ComMsg_Unicode_fix' 2018-10-06 19:57:36 +03:00
Artyrm 6212ad29f1 One dependency in qtfred. Fixed. 2018-10-06 19:57:06 +03:00
wookieejedi 5ec30bdaee Update code/ship/shipfx.cpp 2018-10-06 11:37:50 -04:00
wookieejedi b9b74a3201 Fixed sound variable error
Pos variable not used, so removed it.
2018-10-06 09:45:36 -04:00
wookieejedi 09c24313d7 Added sounds to WE Hyperspace
Allows warpin enter and exit sounds to be properly used with the Hyperspace warpin effect.
2018-10-06 08:35:28 -04:00
Artyrm afdaa3a3ee Merge branch 'ComMsg_Unicode_fix' 2018-10-06 13:32:20 +03:00
Artyrm 68dcef639d Clean-up commented variants. 2018-10-06 13:31:21 +03:00
wookieejedi 91f351b990 Update code/ship/shipfx.cpp 2018-10-06 01:35:52 -04:00
wookieejedi dd1def4f4c Update code/ship/shipfx.cpp 2018-10-06 00:36:23 -04:00
wookieejedi 8b770792fb Update code/ship/shipfx.cpp 2018-10-05 22:17:30 -04:00
plieblang 23f9cfc815 Add free-afterburner-use flag to ai_profiles.tbl 2018-10-02 14:10:27 -05:00
niffiwan 11f9175425 Merge pull request #1887 from TRBlount/feature/mod_play_warp_settings
Make player warpout settings customizable
2018-10-01 11:08:14 +10:00
Artyrm 4fb9c27e71 Comm_orders assign fix. MsgItems to SCP_string too. 2018-09-30 23:51:47 +03:00
TRBlount 4c7b7a0fef Make player warpout settings customizable 2018-09-30 11:31:41 -06:00
Artyrm 3dc1689936 Switched to SCP_string in HUDSquadMsg 2018-09-30 17:23:23 +03:00
niffiwan 94df2777e0 Merge pull request #1884 from niffiwan/fix/setetsvalues_doco
Fix set-ets-values sexp documentation bug
2018-09-30 12:52:38 +10:00
niffiwan c9ebc33d98 apply similar to get-ets-values 2018-09-30 10:12:18 +10:00
niffiwan 9bd459d549 further enhance doco (per feedback) 2018-09-30 09:27:10 +10:00
m!m d9db8bdb71 Merge pull request #1883 from asarium/fix/linuxRelease
Fix linux release building
2018-09-29 16:30:46 +02:00
niffiwan f3cdfcc229 Fix set-ets-values sexp documentation bug
Found by Asteroth - thanks!
2018-09-29 19:16:06 +10:00
asarium 44e3f1f9b5 Fix linux release building
I removed too much code when disabling qtFRED deployment...
2018-09-29 10:30:15 +02:00
niffiwan da5e7f1510 Merge pull request #1882 from asarium/build/disableLinuxQtFred
Disable Linux qtFRED building again
2018-09-29 10:51:55 +10:00
asarium d830a01381 Disable Linux qtFRED building again
There are still some unresolved issues and the file size is pretty large
due to some issues with how the AppImage is built.
2018-09-28 23:13:20 +02:00
m!m d24d536731 Merge pull request #1862 from asarium/feature/libRocket
Add scripting features for barracks libRocket UI
2018-09-28 10:27:01 +02:00
Goober5000 6d0e166dea Merge pull request #1875 from asarium/opengl/shadowFboFix
Remove duplicate shadow FBO creation
2018-09-27 16:34:33 -04:00
m!m e0301da596 Merge pull request #1879 from Goober5000/fred_choose_dock_leader
always choose a dock leader in FRED
2018-09-27 11:46:55 +02:00
asarium a815c0247c Add scripting features for barracks libRocket UI
This mostly adds the scripting features required for accessing the
various internal variables required for the barracks screen.
2018-09-27 11:45:09 +02:00
m!m f42eaf9637 Merge pull request #1817 from asarium/cleanup/luaVarargs
Convert scripting interaction function to variadic templates
2018-09-27 11:44:22 +02:00
Goober5000 01fb2c1243 Merge pull request #1878 from Goober5000/fireball_warp_type
allow custom fireballs to be used as ship warp effects
2018-09-26 17:21:29 -04:00
Goober5000 408f259368 always choose a dock leader in FRED
In FRED, if all docked ships had their arrival cue set to false, none of them would be loaded
in the mission because there was no dock leader to bring in the entire group.  This PR fixes that
by choosing an arbitrary ship (the biggest ship according to ship_class_compare) to be the
dock leader.  This consequently fixes issue #1877 because the wing is able to find its ship.
2018-09-26 15:35:23 -04:00
Goober5000 a9b8e5c043 address clang-tidy complaints 2018-09-26 14:17:39 -04:00
asarium cfb9540e2c Fix issues with ignoring parameters 2018-09-26 19:15:42 +02:00
asarium 88115c7703 Fix clang-tidy issues 2018-09-26 19:15:42 +02:00
asarium 8dba6770ae Convert ade argument setting to variadic templates
Same as with argument getting, this preserves the type information and
makes the system generally much safer.
2018-09-26 19:15:42 +02:00
asarium 8f4d51b14a Convert ade_get_args to variadic template based solution
This maintains the type information which can be used for enforce
const-correctness and also for implementing more advanced ways of
handling the type information.
2018-09-26 19:15:42 +02:00
asarium 185aece470 Remove duplicate shadow FBO creation
This appears to be a leftover from the development of the shadow
rendering code. The shadow FBO was allocated twice but only one was
used. This removed the unused code and also ports the improved error
handling of that code over to the actual shadow FBO creation code.
2018-09-26 14:10:35 +02:00
m!m 0e962e269b Merge pull request #1876 from plieblang/MemUsageFlagRemoval
Don't show nonexistent memory usage flag
2018-09-26 09:02:20 +02:00
Goober5000 095a2efc56 allow custom fireballs to be used as ship warp effects
This allows the WE_Default warp type to be used with any warp fireball in fireball.tbl.  The fireball can be used by specifying its unique ID for the existing $Warpin type and $Warpout type options in ships.tbl.  The warp type is managed by bitwise-OR'ing a flag to the fireball's index.
2018-09-26 00:19:17 -04:00
plieblang 944a254551 Don't show nonexistent memory usage flag 2018-09-25 16:37:21 -05:00
Goober5000 f628999ef9 Merge pull request #1872 from asarium/fix/libRocketTTF
Disable libRocket unless unicode mode is active
2018-09-24 12:02:33 -04:00
Goober5000 e2fb4d84d7 Merge pull request #1871 from asarium/fix/linuxBuildTransferSh
Remove release build uploading to transfer.sh
2018-09-23 19:59:38 -04:00
asarium ff952298a2 Disable libRocket unless unicode mode is active
Since libRocket requires unicode mode this doesn't change anything but
it fixes an error when a mod uses TrueType fonts without unicode mode.
2018-09-23 14:18:35 +02:00
m!m 66b3fdfed8 Merge pull request #1870 from Goober5000/issue_1869
fix issue #1869
2018-09-23 12:19:41 +02:00
asarium 451c03f76a Remove release build uploading to transfer.sh
I think I used that for debugging some things but now it's causing
issues.
2018-09-23 12:16:12 +02:00
Goober5000 da30c5a38e fix issue 1869 2018-09-22 18:33:00 -04:00
m!m 5206aaabdf Merge pull request #1866 from Goober5000/custom_warpglow
Custom warp glows, balls, and models
2018-09-20 23:20:34 +02:00
Goober5000 f6ed93f7a9 address Travis complaint 2018-09-20 15:29:05 -04:00
Goober5000 4f0e2ae9f1 additional small fixes 2018-09-20 00:25:42 -04:00
Goober5000 c3f595ba0e tweaks 2018-09-19 22:51:57 -04:00
Goober5000 d02d98681a apply new warp attributes for remodularized fireball.tbl 2018-09-19 20:08:19 -04:00
Goober5000 98e37b2570 Merge pull request #1865 from Goober5000/remodularize_fireball_tbl
Remodularize fireball.tbl
2018-09-19 19:50:18 -04:00
Goober5000 3c8b87c958 address PR feedback 2018-09-19 13:00:05 -04:00
niffiwan 8d44946b2b Merge pull request #1863 from asarium/fix/jsonPilotModConversion
Use the correct location flags for enumerating pilots
2018-09-19 21:24:08 +10:00
Goober5000 98b9d5c899 a few more corrections 2018-09-18 19:43:11 -04:00
Goober5000 2f5079fcd1 populate the fireball entry IDs when fred2 starts up
fix various issues with both strings and positive numbers being accepted as sexp arguments
2018-09-18 17:33:45 -04:00
asarium 59a8a347a1 Use the correct location flags for enumerating pilots
This was an oversight in the JSON changes since those were made long
before the CFile location flags were a thing. This uses the correct
location flags for enumerating pilots for conversion.
2018-09-18 22:33:51 +02:00
niffiwan e04f1b4ca4 Merge pull request #1861 from Artyrm/master
Training messages fix.
2018-09-18 20:08:19 +10:00
Fabian Woltermann 7da41c32e3 Merge pull request #1267 from asarium/feature/jsonPilotReading
Add JSON pilot reading implementation
2018-09-18 10:26:07 +02:00
Goober5000 73770845b6 use enhanced fireball.tbl to create OPF_FIREBALL for use in explosion-effect and warp-effect 2018-09-18 00:56:38 -04:00
Goober5000 5828d7f634 generate a unique ID for each fireball, if one isn't specified 2018-09-17 23:06:04 -04:00
Goober5000 45f6cdc687 make fireball modular tables simpler, without using the confusing lod_checker logic, and also add an optional unique id 2018-09-17 22:49:23 -04:00
Artyrm 13fe34a3c7 Merge branch 'training_messages_fix' 2018-09-17 22:26:33 +03:00
asarium da64f285bc Fix issue with file location flags 2018-09-17 20:12:38 +02:00
asarium 45f9ea2ea4 Suppress false-positives in valgrind tests 2018-09-17 19:47:40 +02:00
asarium eb73328c14 Add std::ostream operator to ID class
This will print the internal valie to the stream which can be useful for
debugging.
2018-09-17 19:24:20 +02:00
asarium 380ca12b0d Fix clang-tidy issues 2018-09-17 19:24:11 +02:00
asarium c7e66e26fb Delete old pilot files as well when deleting a pilot 2018-09-17 19:23:18 +02:00
asarium ff911e666d More fixes
This finally fixes the seemingly non-deterministic failure of the
unit-tests (among other things).
2018-09-17 19:23:12 +02:00
asarium c8619ddd0d Fix uninitialized variable error detected by valgrind 2018-09-17 19:23:05 +02:00
asarium 721b2da37b Fix copy-paste error
This caused the continuous conversion of old binary pilots to the JSON
format which reset all the changes made to the JSON data.
2018-09-17 19:22:59 +02:00
asarium e9f4c1618e Add unit tests for validating pilot loading 2018-09-17 19:22:50 +02:00
asarium 4eef54c10b Add JSON reading implementation
This changes the pilot reading code to always use JSON files for storing
the pilot data. Old pilots are converted to the new format when FSO
starts and after that point only JSON pilots will be used.
2018-09-17 19:22:43 +02:00
Artyrm f5ba1e470c Training messages fix. Their delay could be too small with voices volume ste to 0. 2018-09-17 20:12:58 +03:00
asarium 94a00ca6ee Add reading code to FileHandler
Currently only implemented for the BinaryFileHandler
2018-09-17 19:06:50 +02:00
Goober5000 3a8c10bec5 Merge pull request #1858 from Goober5000/enhanced_warp_effect
add additional parameters to warp-effect
2018-09-17 13:00:28 -04:00
niffiwan e92cc5161e Merge pull request #1859 from asarium/feature/loopingParticles
Add support for looping particles
2018-09-17 19:47:26 +10:00
asarium ea73ea33ca Add support for looping particles
This introduces support for keeping particles around forever and letting
them be controlled by a Lua script.
2018-09-17 09:26:20 +02:00
Goober5000 8fe7dc4a1b Merge pull request #1860 from Goober5000/friendlier_warning
rewrite the mod warning dialog a bit
2018-09-16 19:33:58 -04:00
Goober5000 f5bbb21199 rewrite the mod warning dialog a bit 2018-09-16 14:16:57 -04:00
Goober5000 c2761a6142 address clang-tidy complaints 2018-09-16 13:44:38 -04:00
Fabian Woltermann 88b0dba208 Merge pull request #1466 from asarium/feature/libRocket
Add new libRocket UI system
2018-09-16 15:20:34 +02:00
asarium 7173299ca7 Add new libRocket UI system
This new system allows to create a user interface that goes beyond the
existing UI system.
2018-09-16 13:55:29 +02:00
Fabian Woltermann e35fc10530 Merge pull request #1856 from Goober5000/sexp_reset_post_effects
add reset-post-effects sexp
2018-09-16 10:43:39 +02:00
Goober5000 46e8e735b6 more complaining by clang-tidy 2018-09-16 00:31:58 -04:00
Goober5000 e3e40ee576 fix build warning 2018-09-15 23:42:29 -04:00
Goober5000 f0b99e24ff add additional parameters to warp-effect
The warp-effect SEXP can now specify other animations from fireball.tbl that are not necessarily the standard or Knossos animations.  Additionally, the SEXP can now specify the duration for the opening and closing of the warp effect.
2018-09-15 23:30:17 -04:00
Goober5000 e0f76e0cfa tweak sexp documentation as well 2018-09-14 21:59:05 -04:00
Goober5000 5303440dfb add reset-post-effects sexp
Nobody ever thought to add a reset-post-effects SEXP to complement set-post-effects, so this remedies that.  Also, a few minor edits were made to the scripting documentation.
2018-09-14 21:54:35 -04:00
Fabian Woltermann 138a1d01d4 Merge pull request #1854 from TRBlount/fix/share_fire_dir
Fix share_fire_direction logic
2018-09-11 08:04:40 +02:00
TRBlount 0814bf0ae1 Fix share_fire_direction logic 2018-09-10 16:40:36 -06:00
niffiwan 39a0cfecbb Merge pull request #1853 from asarium/feature/sdlVersionDebugLog
Write SDL version to debug log
2018-09-10 23:31:03 +10:00
asarium b78d940136 Write SDL version to debug log
This adds the runtime and compile version of the used SDL library to the
start of the debug log. This was requested by ngld and should make
diagnosing some errors easier.
2018-09-10 09:36:24 +02:00
Goober5000 bc03442a3c Merge pull request #1850 from asarium/fix/1722
Handle DIRECTIVE_WING_ZERO in is-destroyed SEXPs correctly
2018-09-07 12:33:43 -04:00
asarium 8ce1a6f490 Handle DIRECTIVE_WING_ZERO in is-destroyed SEXPs correctly
The special value DIRECTIVE_WING_ZERO (defined to be -999) is used to
signify to the directives system that an is-destroyed SEXP was found
which specified an empty wing. However, if a second is-destroyed-delay
SEXP is present in the same directive then the count of the parameters
is added to -999 which makes means that the directives system then
displays it on the HUD as a negative number.

This fixes that by resetting the counter to 0 if a second SEXP
encounters the special value which fixes the issue in the supplied test
mission. There are probably other edge cases when using multiple
is-destroyed SEXPs in a directive so I added a warning to the SEXP help
which lets the mission designer know that it is preferable to specify
multiple parameters instead of using multiple is-destroyed SEXPs.

This fixes #1722.
2018-09-07 13:38:10 +02:00
Fabian Woltermann 18d2ef8580 Merge pull request #1849 from asarium/fix/1655
Apply clipping offsets when using the line draw list
2018-09-06 12:29:17 +02:00
asarium 4a86b70a69 Apply clipping offsets when using the line draw list
This should make the line draw list class behave identically to the old
line rendering functions. This caused a few issues where the lines were
drawn outside the scissor area which made them invisible.

This fixes #1655.
2018-09-04 15:04:57 +02:00
m!m f717c41083 Merge pull request #1846 from asarium/fix/nebulaBackground
Fix nebula background rendering
2018-09-02 22:59:59 +02:00
asarium 92aacc8479 Fix nebula background rendering
This makes the deferred fog rendering code use the nebula background
instead of the single fog color for the background.

This is not an ideal solution since objects fade to the fog color
instead of the color of the background but it's better than rendering no
background.
2018-09-02 19:07:48 +02:00
Fabian Woltermann 2ae7990c61 Merge pull request #1845 from asarium/fix/1828
Disable movie looping for MVE cutscenes
2018-09-02 15:53:38 +02:00
asarium 4e8ebedfa0 Disable movie looping for MVE cutscenes
This changes the FFmpeg code to not use av_seek_frame anymore if looping
is not required. This fixes an issue when playing MVE movies since that
format does not support seeking.

This fixes #1828.
2018-08-30 23:10:22 +02:00
m!m 01f418f2fb Merge pull request #1844 from The-E/fix/hdr_spec_maps
HDR color space conversion for spec maps is not applied correctly
2018-08-30 15:52:03 +02:00
Fabian Woltermann 0ed47de357 Update main-f.sdr 2018-08-30 13:53:20 +02:00
Fabian Woltermann f5f1c97c0f HDR color space conversion for spec maps only happened in one code path, not all of them. This fixes that. 2018-08-29 21:19:48 +02:00
Goober5000 b0d3957df7 Merge pull request #1841 from niffiwan/feature/per_ship_scan_range
add per-ship-class scanning range feature
2018-08-28 12:59:07 -04:00
niffiwan 332bd01f0f address feedback
remove static keyword & add comment for new constant variable
switch to using #define values for the default scan ranges
2018-08-28 21:51:06 +10:00
niffiwan eb8717f051 add per-ship-class scanning range feature
Requested for FotG - allow dedicated scanning ship options
e.g. Y-wing Longprobe & TIE/rc
2018-08-28 21:13:50 +10:00
m!m af8ae03d9e Merge pull request #1839 from Goober5000/ignore_multiplayer_campaigns
ignore multiplayer as well as singleplayer campaigns
2018-08-24 18:41:53 +02:00
Goober5000 0ca7299bbc ignore multiplayer as well as singleplayer campaigns 2018-08-24 10:58:11 -04:00
Fabian Woltermann 98234c3bc2 Merge pull request #1834 from The-E/fix/team_color_srgb
The team color process is only valid for srgb color space
2018-08-23 18:53:36 +02:00
niffiwan 50691c41da Merge pull request #1837 from niffiwan/feature/autoaim_frame
add feature: change reticle when autoaim is active
2018-08-22 08:42:08 +10:00
m!m 4a66cb190a Merge pull request #1824 from The-E/fix/vm_vec_random_cone_params
vm_vec_random_cone needs to be called with the smaller angle first.
2018-08-21 15:04:39 +02:00
niffiwan 9ba3a0ccf9 clang-tidy: remove FALSE & NULL 2018-08-21 22:53:31 +10:00
niffiwan b625f51645 add feature: change reticle when autoaim is active
Optionally play a sound when autoaim becomes active, and another sound
when autoaim becomes inactive
Credit to zookeeper - I'm just pushing this into master!
2018-08-21 20:56:58 +10:00
Fabian Woltermann c2c8acbf13 REdo properly 2018-08-20 17:12:38 +02:00
Fabian Woltermann ac58950ac5 Revert "vm_vec_random_cone needs to be called with the smaller angle first."
This reverts commit 5b01036723.
2018-08-20 17:10:31 +02:00
Fabian Woltermann 8a84fffe12 Small copy/paste error fix 2018-08-19 20:18:31 +02:00
Fabian Woltermann 0c216ede98 The team color process is only valid for srgb color space, so we need to convert everything into it when we do the thing 2018-08-19 20:14:15 +02:00
m!m 3e543729fc Merge pull request #1832 from Goober5000/ignored_missions
add game_settings feature to ignore single missions
2018-08-19 16:39:49 +02:00
Goober5000 6385bf73be we should not only match without regard to file extension but also without regard to letter case -- and do this for campaigns as well 2018-08-18 15:20:04 -04:00
Goober5000 b7a32329db Merge pull request #1831 from Goober5000/make_getmissionfilename_consistent
make sure getMissionFilename never has a .fs2 extension
2018-08-18 15:05:06 -04:00
m!m b363bda60d Merge pull request #1833 from Goober5000/fix_insufficient_loadout_crash
fix bug introduced in pr #1736
2018-08-18 09:08:23 +02:00
Goober5000 0b547d971e make sure getMissionFilename never has a .fs2 extension 2018-08-18 01:52:48 -04:00
Goober5000 9ac04b9349 fix bug introduced in pr #1736 2018-08-18 01:35:16 -04:00
Goober5000 453b1ca619 address clang-tidy complaint 2018-08-17 23:16:48 -04:00
Goober5000 e6f1332980 add game_settings feature to ignore single missions 2018-08-17 18:32:58 -04:00
Goober5000 5840ca84d6 make sure getMissionFilename has a .fs2 extension 2018-08-17 16:47:51 -04:00
m!m aa0e1c755f Merge pull request #1825 from niffiwan/feature/qtfred_asteroid
qtfred asteroid editor
2018-08-17 13:37:26 +02:00
niffiwan 97469d65ef Merge pull request #1820 from asarium/build/updatedFFmpeg
Update prebuilt FFmpeg libraries to version 3.4.4
2018-08-17 19:24:11 +10:00
niffiwan 5834c01ca9 use UNREACHABLE macro in switch default:
addresses review feedback from m!m
2018-08-14 19:50:08 +10:00
niffiwan 13076364d6 Merge pull request #1714 from asarium/qtfred2_/linuxqtdeploy
Enable qtFRED for all deployments
2018-08-13 23:38:07 +10:00
niffiwan e2905e76ca fix clang-tidy (3): const auto & (!) ;) 2018-08-13 19:09:47 +10:00
niffiwan accea7bb4d fix clang-tidy warnings (2): const auto 2018-08-12 22:39:52 +10:00
niffiwan 733b67ada3 fix clang-tidy warnings
change CLAMP macro to use boolean rather than implicit conversion int
2018-08-12 21:42:11 +10:00
niffiwan de06d1e36f fix clang-tidy warnings (1)
add override to functions
convert to range based for loops
set default dtor
2018-08-12 21:40:47 +10:00
niffiwan 7e6eb25492 triple braces clang? really? 2018-08-11 22:37:57 +10:00
niffiwan 9de5d8d011 add asteroid editor to qtfred 2018-08-11 20:49:55 +10:00
Fabian Woltermann 62d178d896 Merge pull request #1818 from asarium/feature/loopingMovies
Add support for looping movies
2018-08-10 20:46:36 +02:00
Fabian Woltermann f8b210b659 Merge pull request #1819 from asarium/feature/vec3dOperators
Add C++ operators for vector math operations
2018-08-10 20:45:45 +02:00
Fabian Woltermann d3e6ee81e1 Merge pull request #1822 from asarium/fix/fredFlags
Terminate FRED/qtFRED when command line demands it
2018-08-10 20:44:56 +02:00
Fabian Woltermann 5b01036723 vm_vec_random_cone needs to be called with the smaller angle first.
This also adds a check to that function to swap the values around should that not be the case
2018-08-10 17:26:42 +02:00
asarium 66f95312ae Terminate FRED/qtFRED when command line demands it
This was reported by ngld who experienced issues with Knossos since FRED
did not terminate properly when asked to provide the command line flags.
This should fix that.
2018-08-01 09:20:18 +02:00
asarium a737c7a373 Update prebuilt FFmpeg libraries to version 3.4.4
This should fix an issue with the playback speed of APNG files which is
present in the current builds. This does not include the Mac libraries
since I cannot compile the libraries for that platform.
2018-07-31 15:43:52 +02:00
asarium ead93f3175 Add C++ operators for vector math operations
This makes it a bit easier to use the vector types since they are now
usable with the standard C++ operators.
2018-07-30 23:38:51 +02:00
asarium 48b1e3f289 Add support for looping movies
This adds a playback property for making the movie loop to the start
when the end is reached. The way this is done is by simply keeping the
decoder running even if the end of the movie is reached. Then the movie
is reset to the beginning and decoding continues. The player detects
this reset by examining the frame times which keeps the playback
constant.

This also includes support for this in the movie scripting API.
2018-07-30 18:10:48 +02:00
Fabian Woltermann 8a2641181f Merge pull request #1816 from asarium/fix/1815
Don't reset mission file name on mission end
2018-07-28 18:47:17 +02:00
m!m 36e8c3b623 Merge pull request #1814 from TRBlount/fix/random_cone
Fix vm_vec_random_cone/sphere functions
2018-07-28 18:44:58 +02:00
TRBlount 1c2a136ef7 Fix vm_vec_random_cone/sphere functions 2018-07-28 09:11:59 -06:00
asarium 72272cb8cf Don't reset mission file name on mission end
This was needed by the restart dialog action and got removed since the
Discord changes needed to know if a mission was active or not.

I removed the code which changed the mission file name and replaced it
with some internal handling in the discord code which should now handle
mission restarts better.

This fixes #1815.
2018-07-28 16:12:26 +02:00
m!m 4062f59128 Merge pull request #1813 from asarium/fix/stupidIfTypos
Fix crash when launching FSO without a mod option
2018-07-28 09:38:29 +02:00
asarium 24ab091671 Fix crash when launching FSO without a mod option 2018-07-27 18:17:18 +02:00
Fabian Woltermann 7cd17205b5 Merge pull request #1785 from asarium/feature/soundHandleIds
Use strongly typed handles for sound handles
2018-07-27 15:04:02 +02:00
Fabian Woltermann d58bd7db69 Merge pull request #1811 from asarium/fix/1754
Properly handle invalid UTF-8 sequences in NanoVG
2018-07-26 08:22:37 +02:00
m!m ce11936e56 Merge pull request #1810 from asarium/fix/discordLinkingIssue
Fix MSVC linking issue in new Discord Code
2018-07-25 23:18:00 +02:00
asarium feda97c148 Properly handle invalid UTF-8 sequences in NanoVG
The original issue was reported by Novachen in #1754 where a significant
slowdown was encountered in the controls menu (Ship and Misc tabs). I
traced the cause of the slowdown to repeated uploads of the NanoVG font
atlas texture even though no changes were necessary.

The root cause of the issue was that NanoVG did not handle invalid UTF-8
sequences at the end of a string properly. The UTF-8 decoder returned a
success code even though no code point was decoded which lead the rest
of the code to believe that the font atlas needed to be recreated.

This fixes #1754 by properly handling that case.

This also fixed an assertion failure if NanoVG was asked to render
2D elements without any vertices.
2018-07-25 14:17:06 +02:00
asarium a0e85e7ef5 Fix MSVC linking issue in new Discord Code
The CMake file did not contain the required target_link_libraries which
made the build fail when compiling it for the FastDebug configuration.
2018-07-25 13:31:33 +02:00
m!m 6939403262 Merge pull request #1808 from plieblang/MissionInfoParsing
Improve parsing of mission info text fields
2018-07-25 09:02:24 +02:00
Fabian Woltermann 33e8703555 Merge pull request #1788 from asarium/feature/discord
Add discord Rich Presence support
2018-07-25 08:21:23 +02:00
Fabian Woltermann 8a87d20415 Merge pull request #1801 from asarium/feature/shaderCacheLocation
Add CFile API for specifying the file location
2018-07-25 08:20:16 +02:00
Fabian Woltermann b324d2892c Merge pull request #1809 from EatThePath/master
Corrected faulty lifetime randomization for weapons in weapons.cpp
2018-07-25 08:16:46 +02:00
David Gibson 54bd7e3963 Corrected faulty lifetime randomization for weapons in weapons.cpp 2018-07-24 19:38:44 -05:00
plieblang b2230f723b Undo reformatting 2018-07-24 11:59:13 -07:00
m!m f75dafde4a Merge pull request #1746 from asarium/feature/objectDisplayString
Add ship display name feature
2018-07-24 15:49:11 +02:00
m!m d70f92e782 Merge pull request #1807 from asarium/fix/luaCallbackCrash
Fix crash on game shutdown if Lua object callbacks are used
2018-07-24 09:02:59 +02:00
plieblang d7e042b38a Dumb copy/paste mistake 2018-07-23 17:52:37 -07:00
plieblang 941a0c3c8a PR feedback and make methods static 2018-07-23 17:47:42 -07:00
plieblang edc6b94f7f Namespace resolution and size_type vs int mismatch 2018-07-23 13:38:34 -07:00
plieblang 1182a485ac Strip quotes from text and improve mission notes handling 2018-07-23 12:18:07 -07:00
asarium 3cd2c40331 Clear objects on game close 2018-07-23 19:21:16 +02:00
asarium c13cb44df4 Add ship display name feature
This adds a mission file option for ships which allows specifying a
different string which should be used for displaying the name of the
ship to the user. This name will not be used in SEXPs or other ship
lookup functions so it can be freely translated and two ships can also
have the same display name.

The new feature can be used by adding $Display name: <string> after $Name
for a ship in a mission file. I think I added proper support for FRED
(and qtFRED) so that this new value is properly saved but it would be
great if someone could test that.

This implements one of the features requested in #1730.
2018-07-22 23:16:00 +02:00
m!m aede65107b Merge pull request #1805 from asarium/feature/scriptingParsingApi
Add scripting API for accessing parsing system
2018-07-22 22:15:48 +02:00
asarium 197767ce94 Fix clang-tidy warnings 2018-07-22 11:47:33 +02:00
asarium 7924c66d37 Add function for listing files from CFile
This is basically a wrapper around cf_get_file_list which returns the
results in a table.
2018-07-22 11:47:33 +02:00
asarium 3106191cea Rename Mission_text to something better
The variable is now used by a lot of other things so it makes sense to
rename it to something that better describes what it is used for.
2018-07-22 11:47:33 +02:00
asarium 8c4ec9b91c Add scripting API for accessing parsing system
This allows scripts to use the same parsing functions which are also
used by the engine for parsing tables.
2018-07-22 11:47:33 +02:00
m!m 5bfcd1d063 Merge pull request #1804 from PeterMitsis/aicode-api-updates
Unused parameter removal from aicode.cpp module
2018-07-20 14:11:40 +02:00
Peter Mitsis 923265988c Fix warnings found by clang_tidy.sh
Signed-off-by: Peter Mitsis <[email protected]>
2018-07-19 19:24:23 -04:00
Peter Mitsis c485ed8199 aicode: Update maybe_cheat_fire_synaptic() API
Removes an unused parameter from the routine's API.

Signed-off-by: Peter Mitsis <[email protected]>
2018-07-19 13:09:35 -04:00
m!m 4353d4d47f Merge pull request #1803 from plieblang/MissionNoteSemicolonCrash
Write newline after mission notes
2018-07-19 17:06:11 +02:00
plieblang da65a66932 Semicolon fix for qtFRED as well 2018-07-18 13:57:29 -07:00
plieblang 7df8313b8b Force newline after mission notes 2018-07-18 13:33:27 -07:00
Peter Mitsis 187affe004 aicode: Update cheat_fire_synaptic() API
1. Removes unused parameter
2. Applies 'static' keyword to the routine.

Together, these two changes should help the compiler generate
more efficient code.

Signed-off-by: Peter Mitsis <[email protected]>
2018-07-17 16:24:17 -04:00
Peter Mitsis f29cc2ef86 aicode: Update ai_ship_destroy() API
Removes unused parameters from the routine.

Signed-off-by: Peter Mitsis <[email protected]>
2018-07-17 16:24:17 -04:00
Peter Mitsis 97e15ca135 aicode: Update ai_ship_hit() API
Removes two unused parameters from ai_ship_hit(). Instances where this
routine are called are also updated.

This should result in slightly more efficient code.

Signed-off-by: Peter Mitsis <[email protected]>
2018-07-17 16:24:17 -04:00
Peter Mitsis 868418c100 aicode: Update big_ship_collide_recover_start() API
Removes the unused parameter from the routine. This has a small
ripple effect such that it results in an unused parameter in one
of the routines from which it is called.

Signed-off-by: Peter Mitsis <[email protected]>
2018-07-17 16:24:17 -04:00
Peter Mitsis e413b10ce1 aicode: Update ai_control_info_check() API
1. Removes unused parameter
2. Applies the 'static' keyword to the routine.

Together, these two changes should help the compiler generate slightly
more efficient code.

Signed-off-by: Peter Mitsis <[email protected]>
2018-07-17 16:24:17 -04:00
Peter Mitsis bdd740eabd aicode: Update ai_find_shockwave_ship() API
1. Removes unused parameter
2. Applies 'static' keyword to the routine

Together, these two changes should help the compiler generate slightly
more efficient code.

Signed-off-by: Peter Mitsis <[email protected]>
2018-07-17 16:24:17 -04:00
Peter Mitsis d24e3c9295 aicode: Update ai_find_shockwave_weapon() API
1. Removes an unused parameter.
2. Applies the 'static' keyword to the routine.
3. Applies the 'const' keyword to the remaining parameter.

Together these changes should help the compiler generate slightly more
efficient code.

Signed-off-by: Peter Mitsis <[email protected]>
2018-07-17 16:24:13 -04:00
Peter Mitsis 13be144495 aicode: Update ai_preprocess_ignore_objnum() API
Applies the 'static' keyword to the routine as it is only used in the
module in which it is defined.

Removes an unused parameter.

Together, these two changes should help the compiler generate slightly
more efficient code.

Signed-off-by: Peter Mitsis <[email protected]>
2018-07-17 15:27:35 -04:00
Peter Mitsis 8857c4561a aicode: Update gwlr_object_1() API
Adds the 'static' keyword and removes unused parameters.

Signed-off-by: Peter Mitsis <[email protected]>
2018-07-17 15:25:22 -04:00
Peter Mitsis af4a2555db aicode: Update get_behind_ship() API
Adds the 'static' keyword to the routine as it is only used in the
module in which it is defined.

Removes its  unused parameter (and updates location where it is called).

Signed-off-by: Peter Mitsis <[email protected]>
2018-07-17 15:25:22 -04:00
Peter Mitsis ae2c4ef098 aicode: Update ai_chase_eb() API
Removes the unused parameter from the routine and adds the 'static'
keyword to the routine as it is only used in the module in which it
is defined.

Signed-off-by: Peter Mitsis <[email protected]>
2018-07-17 15:25:22 -04:00
Peter Mitsis 6e509868d2 aicode: Update ai_fire_secondary_weapon() API
Removes unused parameters from the routine.

Signed-off-by: Peter Mitsis <[email protected]>
2018-07-17 15:25:22 -04:00
Peter Mitsis d0bc3cf91d aicode: Update ai_select_primary_weapon_OLD() API
This routine is only used in the module in which it is defined, so the
'static' keyword has been applied to it.

One of its three parameters was unused, so it has been removed.

Finally, the 'const' keyword has been applied to appropriate arguments.

These changes should help the compiler generate slightly more efficient
code.

Signed-off-by: Peter Mitsis <[email protected]>
2018-07-17 15:25:22 -04:00
Peter Mitsis 10079c88cd aicode: Remove fds_aux()
The routine fds_aux() is not used anywhere.

Signed-off-by: Peter Mitsis <[email protected]>
2018-07-17 15:25:22 -04:00
Peter Mitsis 3aacb6cb42 aicode: Update ai_turn_towards_vector() API
The routine ai_turn_towards_vector() had an unused parameter (frametime)
and it has been removed.

Each of the instances where this routine is called have also been updated
to reflect the parameter removal. As this resulted in the routine
swarm_update_direction() suddenly having an unused parameter, that routine
and the places where it is called have also been updated (remove
unused parameter).

Signed-off-by: Peter Mitsis <[email protected]>
2018-07-17 15:25:22 -04:00
asarium b434776d53 Fix clang-tidy issues 2018-07-17 17:20:55 +02:00
asarium 20925f23cc Use new cfile location feature for pilot files
This was previously hard-coded but it is now possible to solve this
using the new location API.
2018-07-17 17:20:55 +02:00
asarium 64a9e3d03a Use location API for specifying shader cache location
The files are now exclusively stored in the top level user directory to
make the shader cache not dependent on the current mod. This also adds
some code which removes all old shader cache files which may be stored
in the old (per-mod) location.
2018-07-17 17:20:55 +02:00
asarium fe01372f46 Add CFile API for specifying location
This adds the capability for specifying a bit field for certain API
functions which will limit where they search for files.
2018-07-17 17:20:55 +02:00
asarium 7134e22322 Convert cfile find_location functions to return structs
The amount of output parameters is becoming quite large which makes it
harder to add new input parameters. For that reason I converted the
existing output parameters to a struct which cleans up the function
signature a lot.
2018-07-17 17:20:55 +02:00
m!m fac618c7f0 Merge pull request #1800 from PeterMitsis/remove-unused-parameters
Remove unused parameters
2018-07-16 22:33:22 +02:00
Fabian Woltermann b333104f45 Merge pull request #1799 from NovachenFS2/strings-translation-fix
Strings.tbl translation adjustments AddOn
2018-07-16 22:28:25 +02:00
Jenna Trassa c0401c24e5 Ballistic Weapon Energy Gauge 2018-07-16 10:46:02 +02:00
asarium 2ded9aa35d Format changes with clang-format 2018-07-16 10:21:52 +02:00
asarium ad54f588bb Use strongly typed handles for sound handles
This is similar to the other changes I already posted. Here the sound
instance handles are converted to their own handle type which will make
it easier to use the sound API.
2018-07-16 10:21:52 +02:00
Peter Mitsis a64ebca805 aibig: Update ai_big_maybe_enter_strafe_mode() API
Removes the unused parameter from ai_big_maybe_enter_strafe_mode().
Each place where this routine is called has been corrected to reflect
the updated API.

The 'const' keyword has been applied to remaining parameters as
necessary.

Signed-off-by: Peter Mitsis <[email protected]>
2018-07-15 22:27:43 -04:00
Peter Mitsis 69781cec25 aibig: Update ai_big_strafe_maybe_attack_turret() API
Adds the 'const' keyword to the parameters in the routine
ai_big_strafe_maybe_attack_turret() as they are unchanged
by the routine.

Signed-off-by: Peter Mitsis <[email protected]>
2018-07-15 22:19:56 -04:00
Peter Mitsis 137457e570 aibig: Update ai_big_strafe_maybe_retreat() API
The routine ai_big_strafe_maybe_retreat() is only used in the module in
which it is defined. Consequently it now sports the 'static' keyword, and
no longer uses the 'extern' keyword in its forward declaration (which has
been moved to be colocated with other forward declarations).

Secondly, since it was only using one of its two parameters, the unused
parameter has been removed.

Thirdly, since its only remaining parameter is not modified by the routine,
the 'const' keyword has been applied to it.

Signed-off-by: Peter Mitsis <[email protected]>
2018-07-15 22:02:35 -04:00
Peter Mitsis b7f3ba3660 aibig: Remove routine ai_big_ship()
The routine ai_big_ship() is empty, and appears to have been since it
was initially added many years ago. Removing it helps eliminate some
unused code.

Signed-off-by: Peter Mitsis <[email protected]>
2018-07-15 21:44:49 -04:00
Peter Mitsis bf6cfe61d7 aibig: Update ai_big_maybe_fire_weapons() API
The routine ai_big_maybe_fire_weapons() is only used in the file in
which it is defined and is thus a good candidate for being declared
'static'.

Furthermore, as it was only using two of the five parameters, the
three unused parameters have been removed and all instances where the
routine is called have been updated.

Signed-off-by: Peter Mitsis <[email protected]>
2018-07-15 21:44:08 -04:00
m!m 990838051a Merge pull request #1137 from asarium/lua/defaultScripts2
Add a lua loader that uses the CFile system
2018-07-15 22:57:40 +02:00
m!m 597104c479 Merge pull request #1798 from asarium/fix/debrisObjectsAssert
Convert debris object count Assert to Error
2018-07-15 22:57:25 +02:00
asarium 2ee5d21a10 Add discord Rich Presence support
This uses the Discord Rich Presence API for improving the integration of
FSO into Discord. At the moment this includes state notifications for
being in the main hall, the command and mission briefing and in-mission.
When in-mission it also includes the elapsed time of the mission with
support for time compression.

The details part of the notification includes the campaign name and
mission name if possible.
2018-07-15 19:37:24 +02:00
asarium 8c1d3492eb Convert debris object count Assert to Error
This will make the error message clearer instead of just showing a
cryptic Assert message. This cannot be handled by a simple warning since
capping num_debris_objects to MAX_DEBRIS_OBJECTS would then cause issues
when reading the rest of the header.
2018-07-15 18:34:44 +02:00
asarium ba5fcb971a Format changes with clang-format 2018-07-15 18:10:40 +02:00
asarium 5359b12b4f Only run valgrind on debug builds
In release builds there are a lot of false-positives probably due to the
optimizations of the compiler.
2018-07-15 18:10:40 +02:00
asarium 0fb7345617 Fix clang-tidy issues in gtest
Some of those are fixed in the newest version from their git repository
but I don't want to do a full update just for that.

modernize-make-unique was disabled since clang-tidy apparently doesn't
respect the language setting and make_unique is only present in C++14.
2018-07-15 18:10:40 +02:00
asarium a34ca578ba Add a lua loader that uses the CFile system
This allows to use the built-in lua "require" function with our file
system. This will help organize complicated scripts and it will also
allow to use libraries which were designed for this system.

To enable this change, this includes a new mechanism which allows to
load scripts from the default file system so that the files don't need
to be included in every mod. The default files can be overridden by a
mod if a special mod-table option has been set, similar to how external
shaders are handled right now.
2018-07-15 18:10:40 +02:00
m!m 7f03ac31ae Merge pull request #1797 from asarium/fix/particleEffectHandles
Use type-safe handles for particle effects
2018-07-15 16:37:31 +02:00
Fabian Woltermann 25b396f6a0 Merge pull request #1795 from NovachenFS2/strings-translation
Strings.tbl translation adjustments
2018-07-15 15:35:21 +02:00
asarium c6e2f94d0b Use type-safe handles for particle effects
Nightmare discovered an off-by-one error when checking the validity of a
particle effect handle. Since the new ID system makes that much easier
and less error-prone I decided to go ahead and convert all handles to
an ID typedef which also fixes the reported bug.
2018-07-15 14:50:32 +02:00
Jenna Trassa 9de8d45f19 Review changes for barracks.cpp 2018-07-15 09:25:17 +02:00
m!m 7f5168e9d6 Merge pull request #1796 from asarium/fix/movieBufferOffset
Use byte offset into immediate buffer for movie rendering
2018-07-14 23:47:34 +02:00
Jenna Trassa 490c5d8357 Review Changes in the hud.cpp 2018-07-14 22:28:18 +02:00
Fabian Woltermann 011ca4bb85 Merge pull request #1772 from asarium/build/betterSourceGroupFunction
CMake: Unify how source files are added to CMake
2018-07-14 21:50:00 +02:00
Fabian Woltermann a4f499ce8c Merge pull request #1789 from asarium/fix/shipCleanupMode
Fix assert in ship_cleanup
2018-07-14 21:48:47 +02:00
asarium 5578588894 Use byte offset into immediate buffer for movie rendering
This was causing issues when using the new scripting API in JAD where
there were a lot of 2D operations which filled up the immediate mode
buffer. The reason was that GL_ARB_vertex_attrib_binding the relative
offset is limited and the movie code adds the immediate buffer offset to
the vertex layout which then hit the offset limit set by OpenGL.

This fixes that by using the normal byte offset method which is already
used by the render_primitives functions.
2018-07-14 20:57:29 +02:00
Jenna Trassa dbee42bdec strings.tbl translation adjustments
Previously untranslateable strings can now translated, because they got an unique ID in the strings.tbl.
2018-07-14 14:43:05 +02:00
Jenna Trassa 783e4b5ab2 strings.tbl translation adjustments
Another duplicate that now uses a unique ID.
2018-07-14 14:39:24 +02:00
Jenna Trassa cea27244dc strings.tbl translation adjustments
A duplicate string that had an unique ID even there was an ID for this string. This one uses the initial ID for this string.
2018-07-14 14:36:03 +02:00
Jenna Trassa 09084395a5 strings.tbl translation adjustments
This string, that is used for the Docking precedure of the Support ship was untranslateable before. Now there is a given ID for the strings.tbl
2018-07-14 14:34:26 +02:00
Jenna Trassa 886b14e595 strings.tbl translation adjustments
A previously untranslateable string got an unique ID, that is translateable through the strings.tbl
2018-07-14 14:32:10 +02:00
Jenna Trassa 2fca5fd965 strings.tbl translation adjustments
The strings that got no ID got one. Aswell the duplicate string uses the id that is already predefined.
2018-07-14 14:30:24 +02:00
Jenna Trassa 69cb4f0136 strings.tbl translation adjustments
The string is getting an ID from the strings.tbl that is translateable.
2018-07-14 14:27:56 +02:00
Jenna Trassa 76d36b1c5f strings.tbl translation adjustments
A fix so that the duplicate string is using the id for the first string.
2018-07-14 14:26:48 +02:00
Jenna Trassa bf37a36e89 strings.tbl translation adjustments 2018-07-14 14:18:52 +02:00
Fabian Woltermann 6750f0a4cc Merge pull request #1794 from asarium/feature/scriptingMovies
Add scripting API for displaying movie files
2018-07-14 09:14:15 +02:00
asarium 06a21a0f9b Add scripting API for displaying movie files
This adds an API for the scripting system which allows it to load and
display movie files using the standard movie player code which includes
multi-threaded frame decoding.
2018-07-13 21:54:41 +02:00
m!m 3d653bd770 Merge pull request #1793 from asarium/feature/rgbMovies
Add support for movies with RGB(A) pixel format
2018-07-13 21:50:12 +02:00
asarium db3d92732f Add support for movies with RGB(A) pixel format
This allows to directly display RGB(A) movies without transcoding them
to YUV first. This allows the movie player to support APNG files (which
are supported natively by FFmpeg) with an alpha channel and without
converting them to YUV first.
2018-07-13 19:28:53 +02:00
MageKing17 4fbc0d02fa Merge pull request #1792 from fjelliott/shockwaves-check-huge-supercap-flags
Shockwaves caused by weapons respect big ship flags while calculating damage
2018-07-12 20:25:40 -07:00
Frans Elliott c6f75e7d14 Moved SUPERCAP_DAMAGE_SCALE macro from weapons.cpp to weapon.h so it can be used in shiphit.cpp. 2018-07-12 19:56:44 -05:00
Frans Elliott 8f4d2a27db Added a mod_table option that can enable/disable whether weapon shockwaves will respect the huge and supercap ship flags. The option is disabled by default to mirror retail behavior. 2018-07-12 19:17:31 -05:00
Frans Elliott c4bb136d80 Shockwaves caused by weapons will no longer deal lethal damage to big ships if the weapon that caused the shockwave isn't flagged as being able to deal lethal damage to that ship. For example, helios warheads now cannot kill a Sathanas, and small missiles that cause shockwaves (such as the EMP Adv.) cannot be used to kill corvettes. 2018-07-12 18:17:28 -05:00
m!m ea2656e75f Merge pull request #1790 from MageKing17/bugfix/inverted-sound-validity-check
Fix inverted validity check in snd_time_remaining().
2018-07-11 17:27:38 +02:00
MageKing17 d70672d7bc Fix inverted validity check in snd_time_remaining().
Overlooked mistake from PR #1777.
2018-07-10 17:17:38 -07:00
m!m ccc727a148 Merge pull request #1631 from Karajorma/Feature/EternalVariables
Feature/eternal variables
2018-07-10 15:15:29 +02:00
asarium 87ac2ca6a3 CMake: Unify how source files are added to CMake
This unifies how our CMake system handles adding source files to the
project so that all subprojects use the same mechanism. This also makes
it easier to add a new source folder to the code project since you don't
need to editor three places at the same time anymore.
2018-07-10 15:13:18 +02:00
Karajorma e8bd6b3929 Looks like I missed one. 2018-07-10 18:07:42 +08:00
Karajorma 4e7756d29f Fix errors in clang-tidy 2018-07-10 17:02:47 +08:00
asarium fd96dd287d Fix assert in ship_cleanup
The Assert did no cover all possible input values which caused some
isues for me. This fixes that.
2018-07-10 10:58:31 +02:00
m!m dea5fd9f30 Merge pull request #1784 from MageKing17/bugfix/target-priority-parsing
Make parse_weapon_targeting_priorities() work when weapon missing.
2018-07-10 10:46:18 +02:00
MageKing17 5ebf48b9b0 Adjustment in response to feedback/CI warning.
Warning() replaced with error_display(0), and a line changed to get rid of a clang-tidy warning about repeated types.
2018-07-09 12:07:42 -07:00
MageKing17 2dc2c0643f Merge pull request #1786 from asarium/fix/luaShipClassesIndex
Fix bounds check and string->int conversion in lua ship classes API
2018-07-09 03:14:47 -07:00
asarium e761d8a8e9 Fix bounds check and string->int conversion in lua ship classes API
The bounds check was not correct for 1-based indices. I moved the
Lua->C++ index conversion before the bounds check so that it makes
more sense.
Also, atoi isn't a reliable way for converting a string to an integer.
2018-07-09 10:32:08 +02:00
MageKing17 36b97487c6 Merge pull request #1787 from asarium/fix/invalidCampaignFile
Don't make invalid data in campaign file fatal
2018-07-08 19:20:22 -07:00
asarium 367825b1e0 Don't make invalid data in campaign file fatal
The previous code simply set a boolean flag to indicate that the data is
"invalid" which failed the campaign loading operation. With these
changes, those entries will simply be skipped. That can happen if a mod
added or removed a ship or weapon class or if two campaigns share the
same campaign name.
2018-07-08 10:29:59 +02:00
MageKing17 8f5a364345 Make parse_weapon_targeting_priorities() work when weapon missing.
Previously, if parse_weapon_targeting_priorities() couldn't find a weapon matching the name, it wouldn't parse the "+Target Priority:" line, so it would cause a parsing error when the parser failed to find "$Name:" or "#End" there. Now, the "match not found" codepath still parses it so that no mismatch occurs. Also, I reordered the function so that the parsing wasn't happening in the middle of a loop through the list of weapon types, because it made me cringe.
2018-07-07 10:48:23 -07:00
Fabian Woltermann 07a15286b4 Merge pull request #1777 from asarium/feature/soundIds
Use strongly-typed handles for sound entries
2018-07-07 14:21:44 +02:00
m!m 8e4deb0454 Merge pull request #1783 from MageKing17/bugfix/scripting-createship-safety
Lua's createShip() function now checks for a valid ship class.
2018-07-07 10:50:35 +02:00
MageKing17 aed44067df Lua's createShip() function now checks for a valid ship class.
Ideally it wouldn't be an optional argument at all, but that would break backwards-compatibility, so instead it'll just return an invalid ship handle instead of calling ship_create() with a class of -1. In addition, the Assert from ship_create() meant to guard against invalid ship_type values is now an Assertion that actually says what the invalid value of ship_type was, to make future debugging easier.
2018-07-06 19:25:31 -07:00
MageKing17 83844222c4 Merge pull request #1780 from asarium/build/prebuiltRetry
Retry prebuilt library download if it fails
2018-07-06 10:14:14 -07:00
MageKing17 ba5233e33b Merge pull request #1782 from asarium/fix/removeQuitMissionPopupHack
Remove hack for On Frame scripting hook and quit mission popup
2018-07-06 10:13:58 -07:00
MageKing17 b0bb660eb2 Merge pull request #1781 from asarium/fix/luaBackgroundDoc
Fix inconsistency in Lua background API documenation
2018-07-06 10:13:15 -07:00
MageKing17 74f258a9b3 Merge pull request #1776 from The-E/cleanup/downgrade_null_vec3d
Downgrade null vec3d warning to a log print
2018-07-06 09:58:02 -07:00
asarium d7d3b8c8e2 Remove hack for On Frame scripting hook and quit mission popup
I added this hack a long time ago and it always bothered me why I didn't
come up with a better solution. This is the better solution which uses
the popup_active function for determining if gr_flip is called within a
popup.
2018-07-06 17:03:29 +02:00
asarium 90aeb3651c Fix inconsistency in Lua background API documenation
The Lua type for matrices is called orientation instead of matrix.
2018-07-06 16:06:25 +02:00
asarium 6ee7679dd6 Retry prebuilt library download if it fails
This has been a problem for nighty and release builds which should be
fixed by this.
2018-07-06 14:48:32 +02:00
Karajorma 5baae08bdf Fix the qtFRED output to match that from regular FRED 2018-07-06 11:10:08 +08:00
MageKing17 646fb64c2f Merge pull request #1778 from asarium/feature/scriptingCallbacks
Add more generic scripting callback system
2018-07-05 15:13:02 -07:00
MageKing17 7544f321d6 Merge pull request #1771 from asarium/feature/scriptingBackgroundSupport
Add scripting API for manipulating mission backgrounds
2018-07-05 15:12:50 -07:00
Karajorma b2ff79fb38 That variable was meant to have a better name. 2018-07-05 14:06:04 +08:00
Karajorma 94c1cf65b3 Let's try this again. 2018-07-05 12:34:39 +08:00
Karajorma 0ce2908ce6 Fix the issues from the review and also fix an issue with qtFred 2018-07-05 12:20:30 +08:00
Karajorma 32fbe572e4 Merge branch 'master' of https://github.com/scp-fs2open/fs2open.github.com into Feature/EternalVariables 2018-07-05 10:31:54 +08:00
Goober5000 fb0ff8f1d0 Merge pull request #1779 from MageKing17/bugfix/lua-ship-targetsubsystem
Stop accessing Ships[] array with an objnum.
2018-07-03 21:53:09 -04:00
MageKing17 2cef1d4aa1 Stop accessing Ships[] array with an objnum.
Lua's Ship.TargetSubsystem VIRTVAR, when set, would write to an attribute of the Ships[] array based on an objnum instead of a ship instance index. Since MAX_OBJECTS is drastically higher than MAX_SHIPS, then depending on how many objects happen to be in the mission, an out-of-bounds array access can be easily generated. This commit makes sure to use the objnum instead as an index to the Objects[] array, and then retrieve the ship instance from it.
2018-07-03 16:50:36 -07:00
asarium 9dfb8faea3 Use strongly-typed handles for sound entries
This converts the previous int handles to a strongly-typed wrapper
handle which will make the API more self-documenting and will ensure
that wrongly used handles are detected at compile time.

I already found a few mistakes with these changes which I also fixed
here.
2018-07-03 10:43:10 +02:00
asarium 9651e7dca6 Add more generic scripting callback system
The current scripting hook is pretty simple and straight forward but it
makes a couple of scripting applications harder to implement than
needed.

For example, a lot of scripts need to do some work every frame
for all or some objects. The script needs to manage an internal list of
all the objects that are affected by that list which includes removing
invalid objects to conserve resources. This effectively mirrors what the
engine already does and adds unnecessary overhead.

In these changes I added a generic event system which can be used by any
part of the code for providing callbacks when a specific event occurs.
As an example, I added hooks for the pre- and post-move events to the
object class which are called before and after physics are applied to an
object.

I integrated that feature into the scripting system so now a script can
simply register a function as a callback which will be called whenever
the target event is executed.
2018-07-02 22:56:45 +02:00
Fabian Woltermann 51557d3aa3 remove extra braces 2018-07-01 09:00:36 +02:00
Fabian Woltermann 521a9b9461 Downgrade the null vec3d in vec3d normalize warning to a log print 2018-07-01 08:59:27 +02:00
m!m 130057c64a Merge pull request #1773 from asarium/fix/variableDlgInvalidName
Validate variable name when adding new variable
2018-07-01 00:45:31 +02:00
asarium f63e18957b Add scripting API for manipulating mission background
This adds a scripting API which can be used for adding and removing
background from a mission similarly to the existing SEXPs but with full
support for floating point numbers.

This was requested by Axem on Discord.
2018-06-30 23:22:07 +02:00
m!m df0be20d22 Merge pull request #1774 from The-E/cleanup/remove_path_warning
Remove "not enough points in path" warning
2018-06-30 23:20:22 +02:00
Fabian Woltermann cee37e7a2f Change this warning to a log print. This is only an issue when it's an issue, and most of the time it's not 2018-06-30 21:35:04 +02:00
asarium 90e16ffed2 Validate variable name when adding new variable
This is present in the variable modification dialog but not in the
editor which is used for adding a variable. This also adds the
validation to the editor for adding a new variable.
2018-06-30 17:42:20 +02:00
Fabian Woltermann c2a52174ba Merge pull request #1760 from asarium/build/gcc8Fixes
Fix GCC8 and FFmpeg warnings
2018-06-30 07:22:22 +02:00
Fabian Woltermann e389f7669d Merge pull request #1768 from asarium/feature/alwaysCacheBitmaps
Enable cache bitmaps by default and remove option
2018-06-30 07:20:56 +02:00
Fabian Woltermann 20681f1550 Merge pull request #1769 from TRBlount/feature/RNGSub
Add $Failure Rate:
2018-06-30 07:20:20 +02:00
TRBlount be8ea029da Resolve feedback 2018-06-29 11:19:56 -06:00
asarium 3dbcebb56e Enable cache bitmaps by default and remove option
Caching bitmaps between missions is no longer a problem for modern
system and this will improve the default load times when playing more
than one mission.
2018-06-29 12:15:21 +02:00
TRBlount 37453ae229 Add Failure Rate 2018-06-28 10:38:37 -06:00
m!m 9d907c99fe Merge pull request #1767 from MageKing17/feature/actual-weapon-range
Add AI profile flag to allow primary weapons to consider range.
2018-06-28 11:08:27 +02:00
MageKing17 490ef52b85 Add AI profile flag to allow primary weapons to consider range.
By enabling the "$Use Actual Primary Range:" profile flag (which can also be set on a per-AI-class basis), the code to determine if the AI should fire its primary weapons will not only perform its current "range based on speed of weapon and target" calculation, but it will also compute the weapon's actual range and not fire if the target is outside of it.
2018-06-27 23:11:40 -07:00
MageKing17 cf1cc5e862 Merge pull request #1765 from MageKing17/bugfix/primary-nolink-out-of-ammo
Nolink ballistic primaries no longer disallow linking when depleted.
2018-06-27 19:56:31 -07:00
m!m fc0105141b Merge pull request #1766 from asarium/fix/deferredSpecStatic
Apply spec_* values to lights in deferred pass
2018-06-27 23:27:57 +02:00
asarium 9878b48dd3 Apply spec_* values to lights in deferred pass
This was not present previously which meant that the command line values
were simply ignored by the engine. This adds the scaling back in which
should restore the lighting behavior to the previous status.
2018-06-27 19:39:14 +02:00
Fabian Woltermann af99fee8fc Merge pull request #1762 from asarium/feature/shaderCachePurge
Purge old shader cache files from file system
2018-06-27 19:13:25 +02:00
MageKing17 1cc09d5b8b Merge pull request #1764 from asarium/fix/emptyGameSoundPitch
Make sure that sound pitch range is initialized properly
2018-06-27 09:39:55 -07:00
MageKing17 d5c5cc6eb3 Nolink ballistic primaries no longer disallow linking when depleted.
When a ship with three primary banks has a Nolink weapon in one bank, the other two banks are still allowed to link; if that Nolink weapon has a limited ammo supply, however, depleting that ammo supply would disallow primary linking even though the weapon never contributed to primary linking in the first place. This commit changes the logic to only care if the depleted weapon doesn't have the Nolink flag. The ideal solution is probably to change how primary linking works so that even if the weapon doesn't have the Nolink flag the remaining primaries can still link, but that would be much more involved.
2018-06-27 09:04:14 -07:00
asarium b5bb5097b9 Make sure that sound pitch range is initialized properly
If a sound did not receive a valid sound name then the parsing function
would exit early and not set the pitch range properly. This would cause
a divide by zero if the duration of the sound was queried.

This moves the initialization of the pitch range to the start of the
parsing functions which makes sure that the range is initialized even if
the function exits early.
2018-06-27 17:23:13 +02:00
asarium f87e5bf318 Fix new warnings reported by GCC8
This also enabled GCC8 in Travis CI so that no new warnings are
introduced in other commits.
2018-06-26 11:51:08 +02:00
asarium 48667f0cbd Fix FFmpeg deprecation warnings 2018-06-24 23:07:00 +02:00
asarium 66637ef5cb Purge old shader cache files from file system
This automatically removes old shader cache files from the mod directory
when FSO is started. Those old files are likely to not be used anymore
so this will reduce the amount of disk space FSO uses for the shader
cache.
2018-06-24 22:21:33 +02:00
MageKing17 3b2b58e2cc Merge pull request #1757 from asarium/opengl/betterShaderCache
Improve handling of the shader cache
2018-06-23 21:51:07 -07:00
asarium d5282ca697 Improve handling of the shader cache
This adds an identification of the OpenGL implementation to the shader
content hash to avoid issues when using the same FSO install with
multiple graphics drivers.

Also adds support for querying the supported binary formats and
gracefully handling missing support for the format of a stored shader.
This can be useful when downgrading the version of a graphics driver
since the older version may not support the binary format yet.
2018-06-23 23:19:13 +02:00
m!m 6a099d2adc Merge pull request #1761 from asarium/fix/tgaLocking
Fix loading of TGA files with unexpected bit depths
2018-06-23 17:42:14 +02:00
Fabian Woltermann 6aa1f4899f Merge pull request #1756 from asarium/fix/modelClippingFlicker
Discard submodels by generating clipped vertices
2018-06-23 11:19:53 +02:00
asarium 4ec7d21965 Fix loading of TGA files with unexpected bit depths
The TGA loading code pretends that it does pixel conversion but doesn't
actually do that. This changes ensures that this circumstance is
communicated to the caller of bm_lock which will allow that code to
handle the case properly.

This was reported by Bomb3rman on discord.
2018-06-23 10:24:17 +02:00
MageKing17 bd5a4c4348 Merge pull request #1759 from Goober5000/cap_waypoint_speed_documentation
clarify documentation in cap-waypoint-speed
2018-06-21 18:13:00 -07:00
Goober5000 9135a01b1d clarify documentation in cap-waypoint-speed
The cap-waypoint-speed sexp only works for speeds above 0; this PR changes the documentation to clarify that.  I also tweaked an if() block in ship_return_time_to_goal because it used a >=0 comparison whereas every other comparison used >0.  (This is only for consistency, because the >0 check is used before this point would be reached.)
2018-06-21 17:04:02 -04:00
Fabian Woltermann 032579923e Merge pull request #1755 from asarium/fix/fullLogPathInLog
Write full log path and add legacy mode reason to log file
2018-06-18 08:08:36 +02:00
asarium 8c1e753991 Add log output for legacy mode reason
This will make debugging config location issues easier since the log
will state which path os_is_legacy_mode took while determining the
legacy mode status.
2018-06-17 20:51:11 +02:00
asarium 6a4c74084e Discard submodels by generating clipped vertices
This removes the clipping plane submodel removal code and replaces it
with shader code that generates vertices outside the clipping volume if
a model should not be rendered. This even improved performance since
clipping no longer needs to be active for all model rendering
operations.

This should finally fix #1579.
2018-06-17 14:27:19 +02:00
asarium 3799ce7d2f Write full log path to log file
This should make it a bit easier to determine if FSO is using the new
config file or the old one from only a log file.
2018-06-17 12:56:42 +02:00
m!m 2e213d5c97 Merge pull request #1659 from The-E/fix/1653
Delete all objects on mission end (Fix for #1653)
2018-06-17 12:14:22 +02:00
m!m 0c17177a1e Merge pull request #1713 from asarium/qtfred2_/goalsDialog
Port goal editor dialog code to qtFRED
2018-06-17 12:14:04 +02:00
m!m 93ced64c6f Merge pull request #1725 from asarium/opengl/thickModelOutlines
Render hardpoint model outlines using geometry shaders
2018-06-17 12:13:44 +02:00
m!m 4020b7c594 Merge pull request #1723 from asarium/feature/intelligentLegacyMode
Enable legacy config mode if legacy config is newer
2018-06-17 12:03:40 +02:00
m!m 13b26fd59f Merge pull request #1735 from asarium/cleanup/2dCallDereferences
Remove unnecessary function pointer dereferences in gr API
2018-06-15 12:03:14 +02:00
Goober5000 15bda8c4ac Merge pull request #1748 from asarium/build/unreachable
Add macro for marking unreachable code
2018-06-11 00:31:15 -04:00
asarium 39ab45dc7c Add macro for marking unreachable code
This can be used for mark parts of the code which should be unreachable
in normal execution. In debug mode, if such a statement is reached an
Error dialog is shown which aborts the execution. In release mode the
macro is replaced with a compiler specific expression that lets the
compiler know that this part is unreachable which allows it to optimize
the code better.
2018-06-09 17:38:17 +02:00
Fabian Woltermann 16a19783ae Merge pull request #1744 from asarium/fix/openAlGetErrorError
Fix OpenAL errors when sound is disabled
2018-06-09 08:41:15 +02:00
Goober5000 b1bc4ef44f Merge pull request #1743 from asarium/fix/1739
Respect trailing white space in tstrings.tbl strings
2018-06-08 21:14:33 -04:00
Goober5000 08e664a93a Merge pull request #1749 from asarium/feature/movieSrtSubtitles
Add support for external subtitle files
2018-06-08 20:55:42 -04:00
asarium aeee05c8dd Add support for external subtitle files
This allows to use external subtile files (currently only SRT is
configured) for providing subtitles for movie files. This should be more
universal since it also supports container formats with no support for
subtitle streams.

To use this code the srt file needs to be named
"<movie name>-<language code>.srt" where the language code is the file
extension name specified in the localization table. For english the
"-..." part can be omitted.
2018-06-08 23:29:15 +02:00
asarium 1fb3a65a90 Fix function brace wrapping in clang-format config 2018-06-08 23:28:54 +02:00
Goober5000 d53dc195ee Merge pull request #1742 from asarium/fix/1741
Enable log output for qtFRED
2018-06-08 15:21:14 -04:00
m!m 5b8880daa7 Merge pull request #1737 from Goober5000/fix_issue_1601
Change Warning about missing 640x480 interface art to a log statement
2018-06-08 19:42:41 +02:00
Goober5000 b0fc9cb31a address code review 2018-06-07 22:18:10 -04:00
m!m 323354295f Merge pull request #1751 from plieblang/PsnetTypoFix
Fix rsequence being reset twice and ssequence not being reset at all
2018-06-07 23:24:38 +02:00
plieblang b1881a700d Fix copy/paste error when closing socket 2018-06-07 12:12:54 -07:00
asarium 357cd76252 Render hardpoint model outlines using geometry shaders
This adds support for rendering models using thick lines (that means
lines wider than 1 pixel) which is required by the hardpoint HUD gauge.
This feature was present before the switch to OpenGL code and had to be
removed since the core profile does not support rendering lines wider
than 1 pixel.

This uses a geometry shader for converting all the triangles from a
model to 3 quads along the triangle lines which are as thick as set by
the model renderer. Geometry shaders are quite slow if they generate a
lot of geometry (and this generates 4 times the usual amount of geometry
in the shader) so it's probably not a very fast rendering operation but
it is only needed once per frame so it shouldn't be too bad.

I also added support for the RenderDoc API since I needed that for
debugging and it might be useful in the future. It will only become
active if RenderDoc is actually attached to the process so in most cases
the new code will do nothing.
2018-06-07 16:44:41 +02:00
Fabian Woltermann 30e70db561 Merge pull request #1750 from asarium/build/clang-format-config
Add initial clang-format config file
2018-06-07 13:40:14 +02:00
Goober5000 2c106f8c4b Merge pull request #1747 from ngld/pr/convertSexpInt3
Converted all Int3() calls in sexp.cpp into Warnings, Errors and Asserts
2018-06-06 22:59:50 -04:00
asarium 73bfb7a97e Add initial clang-format config file
This is largely based on how the existing code is formatted and is in no
way enforced by CI or anything else. This is only so that we actually
have a clang format file in the VCS since it's very useful.
2018-06-06 23:04:08 +02:00
ngld 4bead819f9 Implemented requested changes from code review 2018-06-06 03:35:13 +02:00
Goober5000 268828f092 Merge pull request #1736 from asarium/fix/translationBugs
Implement various translation features requested by Novachen
2018-06-05 21:28:14 -04:00
ngld 1614384a6a Converted all Int3() calls in sexp.cpp into Warnings, Errors and Asserts. 2018-06-06 02:20:52 +02:00
asarium 29b6af84cc Fix OpenAL errors when sound is disabled
Since there is no OpenAL context if sound is disabled there were errors
when calling alGetError on a non-existant context. This fixes that by
aborting the sound API call when the sound system wasn't initialized.
2018-06-05 12:31:37 +02:00
asarium cafee143c4 Respect trailing white space in tstrings.tbl strings
The current code drops trailing white space which can cause issues if
the translated string is used in concatenations. The retail tstrings.tbl
has some entries with white space at the end but since those strings are
not used for concatenations (or else this issue would have been found
earlier) this change should not cause issues there.

This fixes #1739.
2018-06-05 11:17:00 +02:00
asarium 6e21c8a736 Enable log output for qtFRED
This fixes #1741.
2018-06-05 11:09:31 +02:00
asarium bb56958dfc Fix various issues in the medal_stuff class
The assignment operator and copy constructors could be replaced with
their default implementations. The destrutor was also not needed since
it only executed the same action the default constructor would have
done.
2018-06-04 11:56:45 +02:00
asarium 120750ebd2 Adress code review feedback 2018-06-04 11:56:45 +02:00
asarium 3430a1c438 Disable hard-coded "cluster bomb" hack
This disables the old hack code if the weapon class has an alternate
name which may have been translated. See #1730 for more information.
2018-06-04 11:56:45 +02:00
asarium 1dc2e848cd Add option for disabling built-in translations 2018-06-04 11:56:45 +02:00
asarium 305429bf8b Add alternative display name for medals
This will only be used in the GUI which will allow translating the name
without having to change missions which use the name of the medal in
SEXPs.
2018-06-04 11:56:44 +02:00
asarium ae149b6061 Add convencience function for retrieving weapon alt name
I also fixed a few issues where the internal char array was used as a
mutable string which changed the string after it was parsed which is not
good(TM).

This also replaces all user-facing occurences of usages of name to use
the new function so that the correct, possibly translated, name is displayed
to the user.
2018-06-04 11:56:44 +02:00
Goober5000 429858d02e fix GitHub issue #1601
This turns the Warning about missing 640 interface art into a log print.  This applies to all instances of 640/1024: loading screens, cbrief and briefing backgrounds, and ship/weapon selection backgrounds.
2018-06-02 17:39:38 -04:00
asarium 1448277c29 Enable legacy config mode if legacy config is newer
There were some reports that using a newer launcher together with an
outdated launcher was causing some issues since the new launcher would
write the new config file which would cause FSO to ignore the changes of
the old launcher since the new config file already exists.

This fixes that by adding a check for when the config locations were
last modified. On Linux and Mac it checks when the old config locations
were modified last while on Windows it checks the registry to determine
if there was a change after the new config file was created.
2018-06-02 12:09:21 +02:00
Fabian Woltermann 61c533559b Removes an assert in object.cpp that was commented out and sets the number of retail stars to 0 when resetting the background in the lab 2018-06-02 11:58:01 +02:00
asarium e92121bed4 Remove unnecessary function pointer dereferences in gr API
Multiple function pointer dereferences are valid in C but do not change
the result of the operation. The graphics API had some function
definitions which used multiple pointer dereferences while the rest of
the functions did not.

This changes all occurences of the double dereferences to normal GR_CALL
declarations to keep the style in the API definitions consistent.
2018-05-31 15:07:20 +02:00
asarium 7e399681cd Enable qtFRED for all deployments
This enabled qtFRED building for all deployments (releases, nightlies
and test builds). qtFRED is relatively stable now and should be
available for wider testing which may be provided by nightly builds.

This also adds AppImage support fot qtFRED although I still couldn't get
it to work entirely since there is some sort of libpng issue which
prevents icons from showing up correctly.
2018-04-24 14:57:52 +02:00
asarium f7b0f93c00 Port goal editor dialog code to qtFRED
The sexp_tree widget makes the model based dialog a bit ugly here since
it is required for some model operations even though it is a UI
component. In the future it could be split into a model component and an
UI component to allow better separation between model and UI.
2018-04-22 21:43:01 +02:00
Fabian Woltermann 758ca86f6f And fix the other one too 2018-03-16 20:10:21 +01:00
Fabian Woltermann 6406e2fbd4 fix variable conversion warning 2018-03-16 15:53:19 +01:00
Fabian Woltermann 18c2dbbde9 WIP fix for #1653.
This adds a step to the post-mission cleanup where we explicitly go through Objects and call obj_delete on everything not already deleted; this obviously needs testing.

Also a few cleanup steps in lab_init to make sure the lab isn't contaminated by leftover data from previously played missions.
2018-03-16 12:59:43 +01:00
Karajorma ef6c5d4da7 Still have some old variable names 2018-03-01 20:09:34 +08:00
Karajorma cb960a3416 Fix the saving for non-eternal variables. 2018-03-01 19:26:41 +08:00
Karajorma 194d944108 Merge branch 'master' of https://github.com/scp-fs2open/fs2open.github.com into Feature/EternalVariables 2018-03-01 18:53:03 +08:00
Karajorma 9ac97f2422 Eternal Variables initial commit - Saving non-eternals on restart or mission quit not working properly. 2018-02-24 17:52:08 +08:00
531 changed files with 40713 additions and 15462 deletions

No files matched your search

+99
View File
@@ -0,0 +1,99 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: false
AlignEscapedNewlinesLeft: false
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
IncludeCategories:
- Regex: '^(<.*\.(h|hh|hpp)>)$' # Includes of external libraries
Priority: 4
- Regex: '^(<.*>)$' # standard library includes (won't match deprecated C headers)
Priority: 5
- Regex: '^"[^/]*\.(h)"$' # Local includes
Priority: 1
- Regex: '^".*\.(h)"$' # standard engine includes
Priority: 2
- Regex: '.*' # Catch all in case something is unhandled above
Priority: 3
IncludeIsMainRegex: '$'
IndentCaseLabels: false
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Left
ReflowComments: true
SortIncludes: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 4
UseTab: ForIndentation
...
+2
View File
@@ -3,12 +3,14 @@ Checks: "-*,\
modernize-*,\
-modernize-raw-string-literal,\
-modernize-use-using,\
-modernize-make-unique,\
performance-*,\
-performance-type-promotion-in-math-fn,\
misc-*,\
-misc-macro-parentheses,\
-misc-misplaced-widening-cast,\
-misc-static-assert,\
-modernize-make-unique,\
"
WarningsAsErrors: ''
HeaderFilterRegex: 'code/.*$|freespace2/.*$|qtfred/.*$|test/src/.*$|build/.*$'
-3
View File
@@ -26,9 +26,6 @@
*.unsuccessfulbuild
ipch/
[Oo]bj/
[Bb]in
[Dd]ebug*/
[Rr]elease*/
Ankh.NoLoad
*.VC.db
*.VC.VC.opendb
+3
View File
@@ -1,3 +1,6 @@
[submodule "cmake/external/rpavlik-cmake-modules"]
path = cmake/external/rpavlik-cmake-modules
url = https://github.com/asarium/cmake-modules.git
[submodule "lib/libRocket"]
path = lib/libRocket
url = https://github.com/asarium/libRocket.git
+164 -140
View File
@@ -1,157 +1,181 @@
language: generic
language: bash
sudo: required
dist: trusty
cache:
directories:
directories:
- $HOME/cmake-3.8
- $HOME/.ccache
addons:
apt:
packages: &global_deps
- ninja-build
- libopenal-dev
- libreadline6-dev
- libpng12-dev
- libjpeg62-dev
- liblua5.1-0-dev
- libjansson-dev
- libsdl2-dev
- valgrind
- qt57base
coverity_scan:
project:
name: "scp-fs2open/fs2open.github.com"
notification_email: niffiwan.scp@gmail.com
build_command: "ci/travis/script.sh"
# must match TRAVIS_BRANCH check below
branch_pattern: coverity_scan
apt:
packages: &global_deps
- ninja-build
- libopenal-dev
- libreadline6-dev
- libpng12-dev
- libjpeg62-dev
- liblua5.1-0-dev
- libjansson-dev
- libsdl2-dev
- libfreetype6-dev
- valgrind
- qt57base
coverity_scan:
project:
name: "scp-fs2open/fs2open.github.com"
notification_email: [email protected]
build_command: "ci/travis/script.sh"
# must match TRAVIS_BRANCH check below
branch_pattern: coverity_scan
env:
global:
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
# via the "travis encrypt" command using the project repo's public key
# also note that fork's don't get access to secure keys
# you have to test using a branch in the main repo
- secure: "C3wF967ZeliwwP1vC12EMIBOaC568n26Z/cPnwzn317ve59DWH3YSfPZVgvt08GzmaXITGGsJvPB+qxfGoKvQzYE4O1B73q81RpUe5pB3IhF+ThQ91VfQZIRJR5xEGJaLINUlHTTZGX5jxlkVO9wAcauVj/s3b8sQ3dvUZauPvk="
# These declarations set INDIEGAMES_USER and INDIEGAMES_PASSWORD for uploading nightly builds to the indiegames server
- secure: "lUuRu8XIi8MKNf1ebOfyC4iVEpPyASojJIDWXRo2bNqEF4ILAljXdkVeXeN6H5yKCHD52cxCNTtyePIG/o3p3QEuGSVud9bDS3D7LaQicLETGGrsw3l07U49gF2OKHXGopg0MzBbZUU9QmhoFTAe8t6PV9NDuEayYCheqvTqjZg="
- secure: "E/DHLYcPK/hBUqxBYYlUqp5sjgvIqY5A0qRHyQ4bmjsB+WB/Xx71bGCSiF7hk6lTxar1ZI1i5RAXXh9AIvNVaYAIdEOlCP+q3gvwCYuc5naZEKmkxlUCf0oEL4O9Fye93A/3VkFHuBdC1TGPYYf69m4W5r4367wWO9dPRIdWpJA="
# These declarations set FS2DOWNLOADS_USER and FS2DOWNLOADS_PASSWORD
- secure: "h6GbMX2jLsW1bS9fCM9fthOSJ1nfQQIRWi6EUH2p8u4NFLD5Bfi/C8JhQPKHUzyo3wvKkSHl+PsW7bgr1oXLusRwAur/dtv2N3imqvtbfIz305b00hZlsvbcYmQmUzQFSAdOGShK57JJ5aKQKccaUBP25KqB7Q+JaqBRdaMBS54="
- secure: "fUDAPAUUaaYZy8I4zU3SJ0JcK7aw4eb6eTdaEr7LyNyTMSfPgwY6P1MrbSQC0lJNQIUQ5ffjdxE5g7D7OYpoJF9L14ni4UY8t2QASt7kmpgcYihmjeuYy8FQXgmFG8CTxiWBPKTybZJ7voQcvIvRaNG7b2wM9PMfc5lRIondB6c="
global:
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
# via the "travis encrypt" command using the project repo's public key
# also note that fork's don't get access to secure keys
# you have to test using a branch in the main repo
- secure: "C3wF967ZeliwwP1vC12EMIBOaC568n26Z/cPnwzn317ve59DWH3YSfPZVgvt08GzmaXITGGsJvPB+qxfGoKvQzYE4O1B73q81RpUe5pB3IhF+ThQ91VfQZIRJR5xEGJaLINUlHTTZGX5jxlkVO9wAcauVj/s3b8sQ3dvUZauPvk="
# These declarations set INDIEGAMES_USER and INDIEGAMES_PASSWORD for uploading nightly builds to the indiegames server
- secure: "lUuRu8XIi8MKNf1ebOfyC4iVEpPyASojJIDWXRo2bNqEF4ILAljXdkVeXeN6H5yKCHD52cxCNTtyePIG/o3p3QEuGSVud9bDS3D7LaQicLETGGrsw3l07U49gF2OKHXGopg0MzBbZUU9QmhoFTAe8t6PV9NDuEayYCheqvTqjZg="
- secure: "E/DHLYcPK/hBUqxBYYlUqp5sjgvIqY5A0qRHyQ4bmjsB+WB/Xx71bGCSiF7hk6lTxar1ZI1i5RAXXh9AIvNVaYAIdEOlCP+q3gvwCYuc5naZEKmkxlUCf0oEL4O9Fye93A/3VkFHuBdC1TGPYYf69m4W5r4367wWO9dPRIdWpJA="
# These declarations set FS2DOWNLOADS_USER and FS2DOWNLOADS_PASSWORD
- secure: "h6GbMX2jLsW1bS9fCM9fthOSJ1nfQQIRWi6EUH2p8u4NFLD5Bfi/C8JhQPKHUzyo3wvKkSHl+PsW7bgr1oXLusRwAur/dtv2N3imqvtbfIz305b00hZlsvbcYmQmUzQFSAdOGShK57JJ5aKQKccaUBP25KqB7Q+JaqBRdaMBS54="
- secure: "fUDAPAUUaaYZy8I4zU3SJ0JcK7aw4eb6eTdaEr7LyNyTMSfPgwY6P1MrbSQC0lJNQIUQ5ffjdxE5g7D7OYpoJF9L14ni4UY8t2QASt7kmpgcYihmjeuYy8FQXgmFG8CTxiWBPKTybZJ7voQcvIvRaNG7b2wM9PMfc5lRIondB6c="
deploy:
- provider: releases
api_key:
secure: "Wdt4Ccefo7a0ZDjEJQJgpghh7n72FtNJuKSAPUvoz4gtEX6Ct9J8yJI1t9V3jE3CTbbLJ21/Q6eZRDfT7UfNJe5DdepoJsP9DeFhKMWqQCq+AChqQWlm0KeZAffJoJreL8vXYhnRYcLT9ceZHEH6AqwN9TPV+xJziGPISAkYNZ8="
skip_cleanup: true
file_glob: true
file: "/tmp/builds/*"
on:
condition: '"$RELEASE_BUILD" == true'
tags: true
- provider: releases
api_key:
secure: "Wdt4Ccefo7a0ZDjEJQJgpghh7n72FtNJuKSAPUvoz4gtEX6Ct9J8yJI1t9V3jE3CTbbLJ21/Q6eZRDfT7UfNJe5DdepoJsP9DeFhKMWqQCq+AChqQWlm0KeZAffJoJreL8vXYhnRYcLT9ceZHEH6AqwN9TPV+xJziGPISAkYNZ8="
skip_cleanup: true
file_glob: true
file: "/tmp/builds/*"
on:
condition: '"$RELEASE_BUILD" == true'
tags: true
- provider: script
script: bash ci/travis/ftp_deploy.sh
on:
condition: '"$NIGHTLY_BUILD" == true'
tags: true
- provider: script
script: bash ci/travis/ftp_deploy.sh
on:
condition: '"$NIGHTLY_BUILD" == true'
tags: true
- provider: script
skip_cleanup: true
script: bash ci/travis/ftp_deploy.sh
on:
condition: $TEST_BUILD = true
all_branches: true
- provider: script
skip_cleanup: true
script: bash ci/travis/ftp_deploy.sh
on:
condition: $TEST_BUILD = true
all_branches: true
matrix:
include:
# note that gcc Debug MUST be 1st for Coverity
- os: linux
env: CONFIGURATION="Debug" CC=gcc-5 CXX=g++-5
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- *global_deps
- g++-5
- os: linux
env: CONFIGURATION="Debug" CC=gcc-7 CXX=g++-7
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- g++-7
- *global_deps
- os: linux
env: CONFIGURATION="Debug" CC=clang-4.0 CXX=clang++-4.0 CMAKE_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-4.0
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- *global_deps
- clang-4.0
- clang-tidy-4.0
- libc++-dev
script:
- ./ci/travis/script.sh
- ./ci/travis/clang_tidy.sh
- os: osx
env: CONFIGURATION="Debug"
include:
# note that gcc Debug MUST be 1st for Coverity
- os: linux
env: CONFIGURATION="Debug" CC=gcc-5 CXX=g++-5
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- *global_deps
- g++-5
- os: linux
env: CONFIGURATION="Debug" CC=gcc-8 CXX=g++-8
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- g++-8
- *global_deps
- os: linux
env: CONFIGURATION="Debug" CC=clang-4.0 CXX=clang++-4.0 CMAKE_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-4.0
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- *global_deps
- clang-4.0
- clang-tidy-4.0
- libc++-dev
script:
- ./ci/travis/script.sh
- ./ci/travis/clang_tidy.sh
- os: osx
env: CONFIGURATION="Debug"
- os: windows
env: CONFIGURATION="Debug" CMAKE_TOOLSET=v141_xp CMAKE_GENERATOR="Visual Studio 15 2017"
- os: windows
env: CONFIGURATION="Debug" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
- os: linux
env: CONFIGURATION="Release" CC=gcc-5 CXX=g++-5
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- *global_deps
- g++-5
- os: linux
env: CONFIGURATION="Release" CC=gcc-8 CXX=g++-8
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- g++-8
- *global_deps
- os: linux
env: CONFIGURATION="Release" CC=clang-4.0 CXX=clang++-4.0
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-4.0
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- *global_deps
- clang-4.0
- libc++-dev
- os: osx
env: CONFIGURATION="Release"
- os: windows
env: CONFIGURATION="Release" CMAKE_TOOLSET=v141_xp CMAKE_GENERATOR="Visual Studio 15 2017"
- os: windows
env: CONFIGURATION="Release" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
# As long as Windows is still experimental on Travis CI, allow failures
allow_failures:
- os: windows
env: CONFIGURATION="Debug" CMAKE_TOOLSET=v141_xp CMAKE_GENERATOR="Visual Studio 15 2017"
- os: windows
env: CONFIGURATION="Debug" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
- os: windows
env: CONFIGURATION="Release" CMAKE_TOOLSET=v141_xp CMAKE_GENERATOR="Visual Studio 15 2017"
- os: windows
env: CONFIGURATION="Release" CMAKE_TOOLSET="" CMAKE_GENERATOR="Ninja"
fast_finish: true
- os: linux
env: CONFIGURATION="Release" CC=gcc-5 CXX=g++-5
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- *global_deps
- g++-5
- os: linux
env: CONFIGURATION="Release" CC=gcc-7 CXX=g++-7
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- g++-7
- *global_deps
- os: linux
env: CONFIGURATION="Release" CC=clang-4.0 CXX=clang++-4.0
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-4.0
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- *global_deps
- clang-4.0
- libc++-dev
- os: osx
env: CONFIGURATION="Release"
before_install:
# ugly hack; if running a coverity scan abort all except the 1st build
# see note re gcc compiler above needing to be 1st
# also note that branch_pattern & the TRAVIS_BRANCH check must match
# unfortunately COVERITY_SCAN_BRANCH isn't defined until later in the
# build process
- if ([[ "${TRAVIS_JOB_NUMBER##*.}" != "1" ]] && [[ "${TRAVIS_BRANCH}" == "coverity_scan" ]]); then false ; fi
- source "./ci/travis/check_release.sh"
- "./ci/travis/before_install.sh"
# ugly hack; if running a coverity scan abort all except the 1st build
# see note re gcc compiler above needing to be 1st
# also note that branch_pattern & the TRAVIS_BRANCH check must match
# unfortunately COVERITY_SCAN_BRANCH isn't defined until later in the
# build process
- if ([[ "${TRAVIS_JOB_NUMBER##*.}" != "1" ]] && [[ "${TRAVIS_BRANCH}" == "coverity_scan" ]]); then false ; fi
- source "./ci/travis/check_release.sh"
- "./ci/travis/before_install.sh"
install:
- "./ci/travis/install.sh"
- export PATH=$HOME/cmake-3.6/bin:$PATH
- if [ "$TRAVIS_OS_NAME" = "windows" ]; then export PATH="/c/Program Files/CMake/bin":$PATH; fi
- "./ci/travis/install.sh"
- export PATH=$HOME/cmake-3.6/bin:$PATH
before_script:
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then QT_ENV_SCRIPT=$(find /opt -name 'qt*-env.sh'); source $QT_ENV_SCRIPT; fi
- "./ci/travis/before_script.sh"
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then QT_ENV_SCRIPT=$(find /opt -name 'qt*-env.sh'); source $QT_ENV_SCRIPT; fi
- "./ci/travis/before_script.sh"
script:
- if [ "$BUILD_DEPLOYMENT" = true ] ; then ./ci/travis/release.sh ; else ./ci/travis/script.sh ; fi
- if [ "$BUILD_DEPLOYMENT" = true ] ; then ./ci/travis/release.sh ; else ./ci/travis/script.sh ; fi
-1
View File
@@ -84,7 +84,6 @@ IF (WIN32)
OPTION(FSO_BUILD_FRED2 "Build FRED2 binary" ON)
elseif(UNIX)
option(FSO_BUILD_APPIMAGE "Build an AppImage package" OFF)
set(APPIMAGE_ASSISTANT "" CACHE STRING "The root directory of an AppImage clone.")
ENDIF(WIN32)
OPTION(FSO_BUILD_TOOLS "Build tools related to FSO" OFF)
+1
View File
@@ -133,6 +133,7 @@ if ($DeployBuild) {
cmake -DCMAKE_INSTALL_PREFIX="$env:APPVEYOR_BUILD_FOLDER/../install" -DFSO_USE_SPEECH="ON" `
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$($buildConfig.SimdType)" `
-DQT5_INSTALL_ROOT="$($buildConfig.QtDir)" -DFSO_BUILD_QTFRED=ON `
-G "$($buildConfig.Generator)" -T "$($buildConfig.Toolset)" ..
$Configs = @("Release", "FastDebug")
+3
View File
@@ -8,4 +8,7 @@ if [ "$TRAVIS_OS_NAME" = "linux" ]; then
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
# Nothing to do here
:
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
# Nothing to do here
:
fi
+18 -7
View File
@@ -2,15 +2,19 @@
set -ex
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
mkdir -p /tmp/builds
if [ "$RELEASE_BUILD" = true ]; then
# Package the source code in release builds
PARENT_DIR="$(basename "$PWD")"
(cd .. && tar -czvf /tmp/builds/$PACKAGE_NAME-source-Unix.tar.gz --exclude-vcs "$PARENT_DIR")
fi
fi
mkdir -p build
cd build
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
if [ "$RELEASE_BUILD" = true ]; then
PARENT_DIR="$(basename $PWD)"
(cd .. && tar -czvf /tmp/builds/$PACKAGE_NAME-source-Unix.tar.gz --exclude-vcs "$PARENT_DIR")
fi
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
@@ -27,8 +31,7 @@ if [ "$TRAVIS_OS_NAME" = "linux" ]; then
mkdir -p $config
cd $config
eval $CMAKE -DFSO_INSTALL_DEBUG_FILES=ON -DCMAKE_BUILD_TYPE=$config -DCMAKE_INSTALL_PREFIX="/tmp/release/$config" \
-DFSO_BUILD_APPIMAGE=ON -DAPPIMAGE_ASSISTANT="$HOME/AppImageAssistant" \
-DFSO_BUILD_INCLUDED_LIBS=ON -DFFMPEG_USE_PRECOMPILED=ON ../..
-DFSO_BUILD_APPIMAGE=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFFMPEG_USE_PRECOMPILED=ON -DFSO_BUILD_QTFRED=OFF ../..
cd ..
done
else
@@ -40,4 +43,12 @@ elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
else
cmake -G "Xcode" $CMAKE_OPTIONS ..
fi
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
if [ "$CMAKE_GENERATOR" = "Ninja" ]; then
cmake -DFSO_USE_SPEECH="OFF" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
-DFSO_BUILD_FRED2="OFF" -G "$CMAKE_GENERATOR" ..
else
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="OFF" -DFSO_BUILD_TESTS="ON" \
-DMSVC_SIMD_INSTRUCTIONS=SSE2 -DFSO_BUILD_FRED2="ON" -G "$CMAKE_GENERATOR" -T "$CMAKE_TOOLSET" ..
fi
fi
+5
View File
@@ -58,6 +58,11 @@ if [ "$BUILD_DEPLOYMENT" = true ]; then
echo "Skipping non-release configuration";
exit 0;
fi
if [ "$TRAVIS_OS_NAME" = "windows" ]; then
echo "Skipping non-release platform"
exit 0
fi
fi
export RELEASE_BUILD
+7 -2
View File
@@ -16,14 +16,19 @@ if [ "$TRAVIS_OS_NAME" = "linux" ]; then
cd $HOME
if [ "${BUILD_DEPLOYMENT}" = true ]; then
wget -c "https://github.com/probonopd/AppImageKit/releases/download/5/AppImageAssistant" # (64-bit)
chmod a+x ./AppImageAssistant
wget -O appimagetool -c "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" # (64-bit)
chmod a+x ./appimagetool
wget -O linuxdeployqt -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" # (64-bit)
chmod a+x ./linuxdeployqt
fi
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
gem install xcpretty
brew update
brew outdated cmake || brew upgrade cmake
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
choco install mingw ninja
fi
cmake --version
+34 -1
View File
@@ -8,7 +8,40 @@ if [ "$TRAVIS_OS_NAME" = "linux" ]; then
for config in $BUILD_CONFIGS
do
cd "$config"
ninja appimage
# Compile all targets
ninja all
# Install Freespace2 targets
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/fso -DCOMPONENT=Unspecified -P cmake_install.cmake
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/fso -DCOMPONENT=Freespace2 -P cmake_install.cmake
# We need to be a bit creative for determining the AppImage name since we don't want to hard-code the name
FILENAME="$(find /tmp/release/$config/fso/bin -name 'fs2_open_*' -type f -printf "%f\n").AppImage"
$HOME/appimagetool -n /tmp/release/$config/fso "/tmp/release/$config/fso/$FILENAME"
: <<'END'
# Install qtFRED targets
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/qtfred/usr -DCOMPONENT=Unspecified -P cmake_install.cmake
cmake -DCMAKE_INSTALL_PREFIX=/tmp/release/$config/qtfred/usr -DCOMPONENT=qtFRED -P cmake_install.cmake
PREV="$(pwd)"
cd /tmp/release/$config/qtfred
unset QTDIR; unset QT_PLUGIN_PATH; unset LD_LIBRARY_PATH
$HOME/linuxdeployqt usr/qtfred.desktop -bundle-non-qt-libs
# Move our AppRun script to the right location
mv usr/AppRun AppRun
echo "Embed newer libstdc++ for distros that don't come with it (ubuntu 14.04)";
mkdir -p usr/optional/; mkdir -p usr/optional/libstdc++/;
cp /usr/lib/x86_64-linux-gnu/libstdc++.so.6 ./usr/optional/libstdc++/;
$HOME/appimagetool -n . "$(find /tmp/release/$config/qtfred/usr/bin -name 'qtfred_*' -type f -printf "%f\n").AppImage"
cd "$PREV"
END
cd ..
done
+13 -2
View File
@@ -7,8 +7,13 @@ cd build
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
ninja -k 20 all
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
--suppressions="$TRAVIS_BUILD_DIR/ci/travis/valgrind.supp" ./bin/unittests --gtest_shuffle
if [ "$CONFIGURATION" = "Debug" ]; then
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
--suppressions="$TRAVIS_BUILD_DIR/ci/travis/valgrind.supp" ./bin/unittests --gtest_shuffle
else
./bin/unittests --gtest_shuffle
fi
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
cmake --build . --config "$CONFIGURATION" | tee build.log | xcpretty
XCODE_RET=${PIPESTATUS[0]}
@@ -17,4 +22,10 @@ elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
curl --upload-file build.log.tar.gz "https://transfer.sh/build.log.tar.gz"
exit $XCODE_RET
fi
elif [ "$TRAVIS_OS_NAME" = "windows" ]; then
if [ "$CMAKE_GENERATOR" = "Ninja" ]; then
cmake --build . --config "$CONFIGURATION"
else
cmake --build . --config "$CONFIGURATION" -- /verbosity:minimal
fi
fi
+16 -1
View File
@@ -25,4 +25,19 @@
fun:_dl_init
fun:dl_open_worker
fun:_dl_catch_error
}
}
{
CLang Lua unitialized value error
Memcheck:Cond
...
fun:luaH_get
fun:lua_rawget
fun:_ZN12_GLOBAL__N_117ade_index_handlerEP9lua_State
}
{
False-positive uninitialized variable warning
Memcheck:Cond
fun:_Z23cf_check_location_flagsjj
fun:_Z29cf_create_default_path_stringPcjiPKcbj
...
}
+3 -1
View File
@@ -1,4 +1,6 @@
[Desktop Entry]
Type=Application
Name=FreeSpace Open
Exec=$<TARGET_FILE_NAME:Freespace2>
Icon=app_icon.png
Icon=app_icon
Categories=Game;
+6 -8
View File
@@ -6,18 +6,16 @@ configure_file("${CMAKE_CURRENT_LIST_DIR}/AppRun.in" "${CMAKE_CURRENT_BINARY_DIR
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/AppRun-$<CONFIG>"
INPUT "${CMAKE_CURRENT_BINARY_DIR}/AppRun.gen")
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/AppRun-$<CONFIG>" DESTINATION "." RENAME "AppRun")
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/AppRun-$<CONFIG>" DESTINATION "." RENAME "AppRun"
COMPONENT "Freespace2")
configure_file("${CMAKE_CURRENT_LIST_DIR}/AppImage.desktop.in" "${CMAKE_CURRENT_BINARY_DIR}/AppImage.desktop.gen" @ONLY)
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/AppImage-$<CONFIG>.desktop"
INPUT "${CMAKE_CURRENT_BINARY_DIR}/AppImage.desktop.gen")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/AppImage-$<CONFIG>.desktop" DESTINATION "." RENAME "fso.desktop")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/AppImage-$<CONFIG>.desktop" DESTINATION "." RENAME "fso.desktop"
COMPONENT "Freespace2")
install(FILES "${CMAKE_SOURCE_DIR}/freespace2/resources/app_icon.png" DESTINATION ".")
add_custom_target(appimage
COMMAND "${APPIMAGE_ASSISTANT}" "${CMAKE_INSTALL_PREFIX}" "${CMAKE_INSTALL_PREFIX}/fs2_open_${FSO_BINARY_SUFFIX}.AppImage")
add_dependencies(appimage install)
install(FILES "${CMAKE_SOURCE_DIR}/freespace2/resources/app_icon.png" DESTINATION "."
COMPONENT "Freespace2")
+11
View File
@@ -85,6 +85,17 @@ set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wreturn-type")
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-deprecated -Wno-char-subscripts")
# These two warnings cause a lot of false-positives in the FSO code base
check_cxx_compiler_flag(-Wstringop-truncation SUPPORTS_STRINGOP_TRUNCATION)
if(SUPPORTS_STRINGOP_TRUNCATION)
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-stringop-truncation")
endif()
check_cxx_compiler_flag(-Wstringop-overflow SUPPORTS_STRINGOP_OVERFLOW)
if(SUPPORTS_STRINGOP_TRUNCATION)
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-stringop-overflow")
endif()
set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-but-set-variable -Wno-array-bounds -Wno-empty-body -Wno-clobbered -Wno-unused-parameter")
set(COMPILER_FLAGS_DEBUG "-O0 -g -Wshadow")
+4 -3
View File
@@ -36,6 +36,7 @@ set(WARNING_FLAGS
/wd4592 # "symbol will be dynamically initialized" is being generated by a compiler bug, see https://stackoverflow.com/a/34027257 for an explanation - m!m
$<$<CONFIG:Release>:/wd4101> # In release mode there are unreferenced variables because debug needs them
/wd4995 # "'vsprintf': name was marked as #pragma deprecated" is being caused by our custom definition of vsprintf. I have no idea what causes this or how to fix it - m!m
/wd4723 # "potential divide by 0" is caused by some code that definitely will not divide by zero - m!m
)
target_compile_options(compiler INTERFACE ${WARNING_FLAGS})
@@ -135,9 +136,9 @@ else()
ENDIF()
endif()
target_compile_definitions(compiler INTERFACE _CRT_SECURE_NO_DEPRECATE
_CRT_SECURE_NO_WARNINGS _SECURE_SCL=0 NOMINMAX "$<$<CONFIG:FastDebug>:_ITERATOR_DEBUG_LEVEL=0>")
target_compile_definitions(compiler INTERFACE _CRT_SECURE_NO_DEPRECATE _CRT_SECURE_NO_WARNINGS _SECURE_SCL=0 NOMINMAX
"$<$<CONFIG:FastDebug>:_ITERATOR_DEBUG_LEVEL=0>" _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING)
if (FSO_FATAL_WARNINGS)
# Make warnings fatal if the right variable is set
target_compile_options(compiler INTERFACE "/WX")
+10
View File
@@ -225,3 +225,13 @@ function(list_target_dependencies _target _out_var)
list(REMOVE_DUPLICATES out_list)
set(${_out_var} ${out_list} PARENT_SCOPE)
endfunction(list_target_dependencies)
macro(add_file_folder FOLDER_NAME)
string(MAKE_C_IDENTIFIER "${FOLDER_NAME}" VARIABLE_NAME)
set(files_${VARIABLE_NAME} ${files_${VARIABLE_NAME}} ${ARGN})
string(REPLACE "/" "\\" FIXED_FOLDER_FILE "${FOLDER_NAME}")
source_group("${FIXED_FOLDER_FILE}" FILES ${ARGN})
set(source_files ${source_files} ${ARGN})
endmacro(add_file_folder)
+5 -1
View File
@@ -3,7 +3,7 @@ INCLUDE(source_groups.cmake)
INCLUDE(voice_rec.cmake)
ADD_LIBRARY(code STATIC ${file_root} ${VOICE_REC_FILES})
ADD_LIBRARY(code STATIC ${source_files} ${VOICE_REC_FILES})
target_compile_features(code PUBLIC ${REQUIRED_CXX_FEATURES})
@@ -37,6 +37,10 @@ TARGET_LINK_LIBRARIES(code PUBLIC compiler)
target_link_libraries(code PUBLIC md5)
target_link_libraries(code PUBLIC discord-rpc)
target_link_libraries(code PUBLIC libRocket)
enable_clang_tidy(code)
IF (FSO_USE_SPEECH)
+4 -4
View File
@@ -567,9 +567,9 @@ extern void ai_dock_with_object(object *docker, int docker_index, object *dockee
extern void ai_stay_still(object *still_objp, vec3d *view_pos);
extern void ai_do_default_behavior(object *obj);
extern void ai_start_waypoints(object *objp, waypoint_list *wp_list, int wp_flags);
extern void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hitpos, int shield_quadrant, vec3d *hit_normal);
extern void ai_ship_destroy(int shipnum, Ship::Exit_Flags method);
extern void ai_turn_towards_vector(vec3d *dest, object *objp, float frametime, float turn_time, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec = NULL, int sexp_flags = 0);
extern void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal);
extern void ai_ship_destroy(int shipnum);
extern void ai_turn_towards_vector(vec3d *dest, object *objp, float turn_time, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec = nullptr, int sexp_flags = 0);
extern void init_ai_object(int objnum);
extern void ai_init(void); // Call this one to parse ai.tbl.
extern void ai_level_init(void); // Call before each level to reset AI
@@ -622,7 +622,7 @@ extern float ai_path();
extern void evade_weapon();
extern int might_collide_with_ship(object *obj1, object *obj2, float dot_to_enemy, float dist_to_enemy, float duration);
extern int ai_fire_primary_weapon(object *objp); //changed to return weather it fired-Bobboau
extern int ai_fire_secondary_weapon(object *objp, int priority1 = -1, int priority2 = -1);
extern int ai_fire_secondary_weapon(object *objp);
extern float ai_get_weapon_dist(ship_weapon *swp);
extern void turn_towards_point(object *objp, vec3d *point, vec3d *slide_vec, float bank_override);
extern int ai_maybe_fire_afterburner(object *objp, ai_info *aip);
+2
View File
@@ -87,6 +87,7 @@ namespace AI {
Fix_heat_seeker_stealth_bug,
Fix_linked_primary_bug,
Force_beam_turret_fov,
Free_afterburner_use,
Glide_decay_requires_thrust,
Hack_improve_non_homing_swarm_turret_fire_accuracy,
Huge_turret_weapons_ignore_bombs,
@@ -110,6 +111,7 @@ namespace AI {
Smart_subsystem_targeting_for_turrets,
Strict_turred_tagged_only_targeting,
Turrets_ignore_target_radius,
Use_actual_primary_range,
Use_additive_weapon_velocity,
Use_newtonian_dampening,
Use_only_single_fov_for_turrets,
+4
View File
@@ -357,6 +357,8 @@ void parse_ai_profiles_tbl(const char *filename)
set_flag(profile, "$smart afterburner management:", AI::Profile_Flags::Smart_afterburner_management);
set_flag(profile, "$free afterburner use:", AI::Profile_Flags::Free_afterburner_use);
set_flag(profile, "$allow rapid secondary dumbfire:", AI::Profile_Flags::Allow_rapid_secondary_dumbfire);
set_flag(profile, "$huge turret weapons ignore bombs:", AI::Profile_Flags::Huge_turret_weapons_ignore_bombs);
@@ -458,6 +460,8 @@ void parse_ai_profiles_tbl(const char *filename)
set_flag(profile, "$ai can slow down when attacking big ships:", AI::Profile_Flags::Ai_can_slow_down_attacking_big_ships);
set_flag(profile, "$use actual primary range:", AI::Profile_Flags::Use_actual_primary_range);
profile->bay_arrive_speed_mult = 1.0f;
profile->bay_depart_speed_mult = 1.0f;
if (optional_string("$bay arrive speed multiplier:")) {
+20 -26
View File
@@ -64,10 +64,11 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
void ai_big_avoid_ship();
int ai_big_maybe_follow_subsys_path(int do_dot_check=1);
void ai_big_strafe_position();
static int ai_big_strafe_maybe_retreat(const vec3d *target_pos);
extern int model_which_octant_distant_many( vec3d *pnt, int model_num,matrix *model_orient, vec3d * model_pos, polymodel **pm, int *octs);
extern void compute_desired_rvec(vec3d *rvec, vec3d *goal_pos, vec3d *cur_pos);
extern void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collide_pos, vec3d *collision_normal);
extern void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collision_normal);
// Called by ai_big_pick_attack_point.
@@ -631,7 +632,7 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
else
rvec = NULL;
ai_turn_towards_vector(enemy_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, rel_pos, 0.0f, 0, rvec);
ai_turn_towards_vector(enemy_pos, Pl_objp, sip->srotation_time, nullptr, rel_pos, 0.0f, 0, rvec);
// calc range of primary weapon
weapon_travel_dist = ai_get_weapon_dist(&Ships[Pl_objp->instance].weapons);
@@ -641,7 +642,7 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
accelerate_ship(aip, 1.0f);
ship *shipp = &Ships[Pl_objp->instance];
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (dot_to_enemy > 0.75f)) {
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (dot_to_enemy > 0.75f)) {
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
afterburners_start(Pl_objp);
aip->afterburner_stop_time = Missiontime + 3*F1_0;
@@ -683,7 +684,7 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
accelerate_ship(aip, accel);
ship *shipp = &Ships[Pl_objp->instance];
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (accel > 0.95f)) {
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (accel > 0.95f)) {
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
afterburners_start(Pl_objp);
aip->afterburner_stop_time = Missiontime + 3*F1_0;
@@ -707,14 +708,14 @@ extern float set_secondary_fire_delay(ai_info *aip, ship *shipp, weapon_info *sw
extern void ai_choose_secondary_weapon(object *objp, ai_info *aip, object *en_objp);
extern int maybe_avoid_big_ship(object *objp, object *ignore_objp, ai_info *aip, vec3d *goal_point, float delta_time);
extern void maybe_cheat_fire_synaptic(object *objp, ai_info *aip);
extern void maybe_cheat_fire_synaptic(object *objp);
// Determine if Pl_objp should fire weapons at current target, based on input parameters
//
// dist_to_enemy => distance (in m) to attack point on current target
// dot_to_enemy => dot product between fvec of Pl_objp and vector from Pl_objp to attack point
//
void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy, vec3d * /*firing_pos*/, vec3d * /*enemy_pos*/, vec3d * /*enemy_vel*/)
static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
{
ai_info *aip;
ship_weapon *swp;
@@ -845,8 +846,6 @@ void ai_big_switch_to_chase_mode(ai_info *aip)
aip->submode_start_time = Missiontime;
}
extern int ai_big_strafe_maybe_retreat(float dist, vec3d *target_pos);
// Make object Pl_objp chase object En_objp, which is a big ship, not a small ship.
void ai_big_chase()
{
@@ -859,7 +858,7 @@ void ai_big_chase()
Assert(aip->mode == AIM_CHASE);
maybe_cheat_fire_synaptic(Pl_objp, aip);
maybe_cheat_fire_synaptic(Pl_objp);
ai_set_positions(Pl_objp, En_objp, aip, &player_pos, &enemy_pos);
@@ -882,7 +881,7 @@ void ai_big_chase()
dot_to_enemy = vm_vec_dot(&vec_to_enemy, &Pl_objp->orient.vec.fvec);
if (aip->ai_flags[AI::AI_Flags::Target_collision]) {
if ( ai_big_strafe_maybe_retreat(dist_to_enemy, &enemy_pos) ) {
if ( ai_big_strafe_maybe_retreat(&enemy_pos) ) {
aip->mode = AIM_STRAFE;
aip->submode_parm0 = Missiontime; // use parm0 as time strafe mode entered (i.e. MODE start time)
aip->submode = AIS_STRAFE_AVOID;
@@ -1045,7 +1044,7 @@ void ai_big_chase()
if ((dist_normal_to_enemy < ATTACK_COLLIDE_AVOID_DIST + speed_dist) || (time_to_enemy < ATTACK_COLLIDE_AVOID_TIME) ) {
// get away, simulate crsh recovery (don't use avoid)
// accelerate_ship(aip, -1.0f);
big_ship_collide_recover_start(Pl_objp, En_objp, &Pl_objp->pos, NULL);
big_ship_collide_recover_start(Pl_objp, En_objp, nullptr);
// aip->submode = SM_AVOID;
// aip->submode_start_time = Missiontime;
} else if ((dist_normal_to_enemy < ATTACK_COLLIDE_SLOW_DIST) || (time_to_enemy < ATTACK_COLLIDE_SLOW_TIME) ) {
@@ -1144,7 +1143,7 @@ void ai_big_chase()
// TODO: investigate why ships fire (and aren't close to hitting ship) when following a path near
// a big ship
if (aip->mode != AIM_EVADE && aip->path_start == -1 ) {
ai_big_maybe_fire_weapons(dist_to_enemy, dot_to_enemy, &player_pos, &predicted_enemy_pos, &En_objp->phys_info.vel);
ai_big_maybe_fire_weapons(dist_to_enemy, dot_to_enemy);
} else {
if (flFrametime < 1.0f)
aip->time_enemy_in_range *= (1.0f - flFrametime);
@@ -1153,11 +1152,6 @@ void ai_big_chase()
}
}
void ai_big_ship(object * /*objp*/)
{
// do nothing
}
// all three parms are output parameters
// Enemy object is En_objp
// pos => world pos of attack point
@@ -1228,7 +1222,7 @@ void ai_big_attack_get_data(vec3d *enemy_pos, float *dist_to_enemy, float *dot_t
// check to see if Pl_objp has gotten too close to attacking point.. if so, break off by entering
// AIS_STRAFE_RETREAT
int ai_big_strafe_maybe_retreat(float /*dist*/, vec3d *target_pos)
static int ai_big_strafe_maybe_retreat(const vec3d *target_pos)
{
ai_info *aip;
aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
@@ -1258,7 +1252,7 @@ int ai_big_strafe_maybe_retreat(float /*dist*/, vec3d *target_pos)
if (aip->ai_flags[AI::AI_Flags::Target_collision]) {
// use standard collision resolution
aip->ai_flags.remove(AI::AI_Flags::Target_collision);
big_ship_collide_recover_start(Pl_objp, En_objp, &Pl_objp->pos, NULL);
big_ship_collide_recover_start(Pl_objp, En_objp, nullptr);
} else {
// too close for comfort so fly to box point + 300
aip->submode = AIS_STRAFE_RETREAT1;
@@ -1298,12 +1292,12 @@ void ai_big_strafe_attack()
}
ai_big_attack_get_data(&target_pos, &target_dist, &target_dot);
if ( ai_big_strafe_maybe_retreat(target_dist, &target_pos) )
if ( ai_big_strafe_maybe_retreat(&target_pos) )
return;
if (aip->ai_flags[AI::AI_Flags::Kamikaze]) {
if (target_dist < 1200.0f) {
ai_turn_towards_vector(&target_pos, Pl_objp, flFrametime, Ship_info[Ships[Pl_objp->instance].ship_info_index].srotation_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&target_pos, Pl_objp, Ship_info[Ships[Pl_objp->instance].ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0);
accelerate_ship(aip, 1.0f);
if ((target_dist < 400.0f) && ai_maybe_fire_afterburner(Pl_objp, aip)) {
afterburners_start(Pl_objp);
@@ -1347,7 +1341,7 @@ void ai_big_strafe_attack()
}
// maybe fire weapons at target
ai_big_maybe_fire_weapons(target_dist, target_dot, &Pl_objp->pos, &En_objp->pos, &En_objp->phys_info.vel);
ai_big_maybe_fire_weapons(target_dist, target_dot);
turn_towards_point(Pl_objp, &target_pos, NULL, 0.0f);
fix last_hit = Missiontime - aip->last_hit_time;
@@ -1493,7 +1487,7 @@ void ai_big_strafe_glide_attack()
vm_vec_sub2(&target_pos, &En_objp->pos);
turn_towards_point(Pl_objp, &target_pos, NULL, 0.0f);
ai_big_maybe_fire_weapons(target_dist, target_dot, &Pl_objp->pos, &En_objp->pos, &En_objp->phys_info.vel);
ai_big_maybe_fire_weapons(target_dist, target_dot);
}
// if haven't been hit in quite a while, leave strafe mode
@@ -1517,7 +1511,7 @@ void ai_big_strafe_avoid()
mode_time = Missiontime - aip->submode_start_time;
ai_big_attack_get_data(&target_pos, &target_dist, &target_dot);
if ( ai_big_strafe_maybe_retreat(target_dist, &target_pos) )
if ( ai_big_strafe_maybe_retreat(&target_pos) )
return;
if ( mode_time > fl2f(0.5)) {
@@ -1704,7 +1698,7 @@ void ai_big_strafe()
//
// Check if weapon_objnum was fired by Pl_objp's target, and whether Pl_objp's target is a big ship, if
// so, enter AIM_STRAFE
int ai_big_maybe_enter_strafe_mode(object *pl_objp, int weapon_objnum, int /*consider_target_only*/)
int ai_big_maybe_enter_strafe_mode(const object *pl_objp, int weapon_objnum)
{
ai_info *aip;
ship_info *sip;
@@ -1778,7 +1772,7 @@ int ai_big_maybe_enter_strafe_mode(object *pl_objp, int weapon_objnum, int /*co
// Consider attacking a turret, if a turret actually fired the weapon
// input: ship_objp => ship that will attack the turret
// weapon_objp =>
void ai_big_strafe_maybe_attack_turret(object *ship_objp, object *weapon_objp)
void ai_big_strafe_maybe_attack_turret(const object *ship_objp, const object *weapon_objp)
{
ai_info *aip;
object *parent_objp;
+2 -3
View File
@@ -17,14 +17,13 @@ struct ai_info;
struct vec3d;
class ship_subsys;
void ai_big_ship(object *objp);
void ai_big_chase();
void ai_big_subsys_path_cleanup(ai_info *aip);
// strafe functions
void ai_big_strafe();
int ai_big_maybe_enter_strafe_mode(object *objp, int weapon_objnum, int consider_target_only=0);
void ai_big_strafe_maybe_attack_turret(object *ship_objp, object *weapon_objp);
int ai_big_maybe_enter_strafe_mode(const object *objp, int weapon_objnum);
void ai_big_strafe_maybe_attack_turret(const object *ship_objp, const object *weapon_objp);
void ai_big_pick_attack_point(object *objp, object *attacker_objp, vec3d *attack_point, float fov=1.0f);
void ai_big_pick_attack_point_turret(object *objp, ship_subsys *ssp, vec3d *gpos, vec3d *gvec, vec3d *attack_point, float weapon_travel_dist, float fov=1.0f);
+77 -103
View File
@@ -745,6 +745,8 @@ void parse_ai_class()
set_aic_flag(aicp, "$smart afterburner management:", AI::Profile_Flags::Smart_afterburner_management);
set_aic_flag(aicp, "$free afterburner use:", AI::Profile_Flags::Free_afterburner_use);
set_aic_flag(aicp, "$allow rapid secondary dumbfire:", AI::Profile_Flags::Allow_rapid_secondary_dumbfire);
set_aic_flag(aicp, "$huge turret weapons ignore bombs:", AI::Profile_Flags::Huge_turret_weapons_ignore_bombs);
@@ -764,6 +766,8 @@ void parse_ai_class()
set_aic_flag(aicp, "$all ships manage shields:", AI::Profile_Flags::All_ships_manage_shields);
set_aic_flag(aicp, "$ai can slow down when attacking big ships:", AI::Profile_Flags::Ai_can_slow_down_attacking_big_ships);
set_aic_flag(aicp, "$use actual primary range:", AI::Profile_Flags::Use_actual_primary_range);
}
void reset_ai_class_names()
@@ -1132,7 +1136,7 @@ void ai_update_danger_weapon(int attacked_objnum, int weapon_objnum)
// If rvec != NULL, use it to match bank by calling vm_matrix_interpolate.
// (rvec defaults to NULL)
void ai_turn_towards_vector(vec3d *dest, object *objp, float /*frametime*/, float turn_time, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec, int sexp_flags)
void ai_turn_towards_vector(vec3d *dest, object *objp, float turn_time, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec, int sexp_flags)
{
matrix curr_orient;
vec3d vel_in, vel_out, desired_fvec, src;
@@ -1500,12 +1504,12 @@ void turn_towards_point(object *objp, vec3d *point, vec3d *slide_vec, float bank
if (aip->ai_flags[AI::AI_Flags::Formation_object, AI::AI_Flags::Formation_wing]) {
if (&Objects[aip->goal_objnum] != objp) {
float rotvel_z = objp->phys_info.rotvel.xyz.z;
ai_turn_towards_vector(point, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, slide_vec, NULL, bank_override, 0);
ai_turn_towards_vector(point, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, slide_vec, nullptr, bank_override, 0);
objp->phys_info.rotvel.xyz.z = rotvel_z;
}
} else {
// normal turn
ai_turn_towards_vector(point, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, slide_vec, NULL, bank_override, 0);
ai_turn_towards_vector(point, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, slide_vec, nullptr, bank_override, 0);
}
}
@@ -1520,7 +1524,7 @@ void turn_away_from_point(object *objp, vec3d *point, float bank_override)
vm_vec_sub(&opposite_point, &objp->pos, point);
vm_vec_add2(&opposite_point, &objp->pos);
ai_turn_towards_vector(&opposite_point, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, NULL, NULL, bank_override, AITTV_FAST);
ai_turn_towards_vector(&opposite_point, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, nullptr, nullptr, bank_override, AITTV_FAST);
}
@@ -1789,7 +1793,7 @@ float get_wing_lowest_av_ab_speed(object *objp)
wingnum = aip->wing;
if (((shipp->flags[Ship::Ship_Flags::Afterburner_locked]) || !(sip->flags[Ship::Info_Flags::Afterburner])) || (shipp->current_max_speed < 5.0f) || (objp->phys_info.afterburner_max_vel.xyz.z <= shipp->current_max_speed) || !(aip->ai_flags[AI::AI_Flags::Free_afterburner_use])) {
if (((shipp->flags[Ship::Ship_Flags::Afterburner_locked]) || !(sip->flags[Ship::Info_Flags::Afterburner])) || (shipp->current_max_speed < 5.0f) || (objp->phys_info.afterburner_max_vel.xyz.z <= shipp->current_max_speed) || !(aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use])) {
lowest_max_av_ab_speed = shipp->current_max_speed;
}
else
@@ -1814,7 +1818,7 @@ float get_wing_lowest_av_ab_speed(object *objp)
if ((oaip->mode == AIM_WAYPOINTS) && (oaip->wing == wingnum) && (oaip->ai_flags[AI::AI_Flags::Formation_object, AI::AI_Flags::Formation_wing])) {
float cur_max;
if ((oshipp->flags[Ship::Ship_Flags::Afterburner_locked]) || !(osip->flags[Ship::Info_Flags::Afterburner]) || (o->phys_info.afterburner_max_vel.xyz.z <= oshipp->current_max_speed) || !(oaip->ai_flags[AI::AI_Flags::Free_afterburner_use])) {
if ((oshipp->flags[Ship::Ship_Flags::Afterburner_locked]) || !(osip->flags[Ship::Info_Flags::Afterburner]) || (o->phys_info.afterburner_max_vel.xyz.z <= oshipp->current_max_speed) || !(oaip->ai_flags[AI::AI_Flags::Free_afterburner_use] || oaip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use])) {
cur_max = oshipp->current_max_speed;
}
else
@@ -3448,35 +3452,6 @@ float compute_time_to_enemy(float dist_to_enemy, object *pobjp)
return time_to_enemy + flFrametime;
}
// Stuff *dot and *tts.
// *dot is always computed. If dot is less than zero, the magnitude is
// incorrect, not having been divided by distance.
// If *dot is > 0.0f, then tts is computed. This is the time it will take object
// *objp to get to *pos, assuming it moves right at it.
void fds_aux(float *dot, float *tts, vec3d *pos, float /*dtime*/, object *objp)
{
vec3d v2s;
vm_vec_sub(&v2s, pos, &objp->pos);
*dot = vm_vec_dot(&v2s, &objp->orient.vec.fvec);
if (*dot > 0.0f) {
float dist;
dist = vm_vec_dist(&objp->pos, pos);
if (dist > 0.1f)
*dot /= dist;
else
*dot = 1.0f;
if (objp->phys_info.speed > 0.1f)
*tts = dist / objp->phys_info.speed;
else
*tts = dist * 100.0f;
}
}
// --------------------------------------------------------------------------
void ai_set_positions(object *pl_objp, object *en_objp, ai_info *aip, vec3d *player_pos, vec3d *enemy_pos)
{
@@ -3892,7 +3867,7 @@ float ai_path_0()
}
if (dist_to_goal > 0.1f)
ai_turn_towards_vector(&gcvp, Pl_objp, flFrametime, sip->srotation_time, slop_vec, NULL, 0.0f, 0);
ai_turn_towards_vector(&gcvp, Pl_objp, sip->srotation_time, slop_vec, nullptr, 0.0f, 0);
// Code to control speed is MUCH less forgiving in path following than in waypoint
// following. Must be very close to path or might hit objects.
@@ -4034,10 +4009,10 @@ float ai_path_1()
if (r <= 1.0f) {
vec3d midpoint;
vm_vec_avg3(&midpoint, &gcvp, &closest_point, &closest_point);
ai_turn_towards_vector(&midpoint, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0, prvec);
ai_turn_towards_vector(&midpoint, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0, prvec);
}
else {
ai_turn_towards_vector(&gcvp, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0, prvec);
ai_turn_towards_vector(&gcvp, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0, prvec);
}
}
@@ -4382,11 +4357,11 @@ void ai_fly_to_target_position(vec3d* target_pos, bool* pl_done_p=NULL, bool* pl
vm_vector_2_matrix(&Pl_objp->orient, &perp, NULL, NULL);
} else {
vm_vec_scale_add(&perp, &Pl_objp->pos, &Autopilot_flight_leader->phys_info.vel, 1000.0f);
ai_turn_towards_vector(&perp, Pl_objp, flFrametime, sip->srotation_time*3.0f*scale, slop_vec, NULL, 0.0f, 0);
ai_turn_towards_vector(&perp, Pl_objp, sip->srotation_time*3.0f*scale, slop_vec, nullptr, 0.0f, 0);
}
} else {
if (dist_to_goal > 0.1f) {
ai_turn_towards_vector(target_pos, Pl_objp, flFrametime, sip->srotation_time*3.0f*scale, slop_vec, NULL, 0.0f, 0);
ai_turn_towards_vector(target_pos, Pl_objp, sip->srotation_time*3.0f*scale, slop_vec, nullptr, 0.0f, 0);
}
}
@@ -4440,7 +4415,7 @@ void ai_fly_to_target_position(vec3d* target_pos, bool* pl_done_p=NULL, bool* pl
ab_allowed = false;
}
if (!(sip->flags[Ship::Info_Flags::Afterburner]) || (shipp->flags[Ship::Ship_Flags::Afterburner_locked]) || !(aip->ai_flags[AI::AI_Flags::Free_afterburner_use])) {
if (!(sip->flags[Ship::Info_Flags::Afterburner]) || (shipp->flags[Ship::Ship_Flags::Afterburner_locked]) || !(aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use])) {
ab_allowed = false;
}
@@ -5051,7 +5026,7 @@ void slide_face_ship()
dist = vm_vec_normalized_dir(&vec_from_enemy, &Pl_objp->pos, &En_objp->pos);
ai_turn_towards_vector(&En_objp->pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&En_objp->pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
dot_from_enemy = vm_vec_dot(&vec_from_enemy, &En_objp->orient.vec.fvec);
@@ -5234,7 +5209,7 @@ vec3d G_predicted_pos, G_fire_pos;
// Else
// Select Any ol' weapon.
// Returns primary_bank index.
int ai_select_primary_weapon_OLD(object *objp, object * /*other_objp*/, Weapon::Info_Flags flags)
static int ai_select_primary_weapon_OLD(const object *objp, Weapon::Info_Flags flags)
{
ship *shipp = &Ships[objp->instance];
ship_weapon *swp = &shipp->weapons;
@@ -5325,7 +5300,7 @@ int ai_select_primary_weapon(object *objp, object *other_objp, Weapon::Info_Flag
//not using the new AI, use the old version of this function instead.
if (!(Ai_info[shipp->ai_index].ai_profile_flags[AI::Profile_Flags::Smart_primary_weapon_selection]))
{
return ai_select_primary_weapon_OLD(objp, other_objp, flags);
return ai_select_primary_weapon_OLD(objp, flags);
}
Assert( shipp->ship_info_index >= 0 && shipp->ship_info_index < static_cast<int>(Ship_info.size()));
@@ -6051,8 +6026,7 @@ int check_ok_to_fire(int objnum, int target_objnum, weapon_info *wip)
// --------------------------------------------------------------------------
// Fire a secondary weapon.
// Maybe choose to fire a different one.
// priority1 and priority2 are optional parameters with defaults = -1
int ai_fire_secondary_weapon(object *objp, int /*priority1*/, int /*priority2*/)
int ai_fire_secondary_weapon(object *objp)
{
ship_weapon *swp;
ship *shipp;
@@ -6072,7 +6046,7 @@ int ai_fire_secondary_weapon(object *objp, int /*priority1*/, int /*priority2*
Assert( shipp->ship_info_index >= 0 && shipp->ship_info_index < static_cast<int>(Ship_info.size()));
// Select secondary weapon.
current_bank = swp->current_secondary_bank; //ai_select_secondary_weapon(objp, swp, priority1, priority2);
current_bank = swp->current_secondary_bank;
if (current_bank == -1) {
return rval;
@@ -6539,14 +6513,14 @@ void ai_chase_ct()
vm_vec_add2(&tvec, &Pl_objp->orient.vec.rvec);
}
ai_turn_towards_vector(&tvec, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&tvec, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
accelerate_ship(aip, 1.0f);
}
/**
* ATTACK submode handler for chase mode.
*/
void ai_chase_eb(ai_info *aip, ship_info *sip, vec3d *predicted_enemy_pos, float /*dist_to_enemy*/)
static void ai_chase_eb(ai_info *aip, ship_info *sip, vec3d *predicted_enemy_pos)
{
vec3d _pep;
float dot_to_enemy, dot_from_enemy;
@@ -6558,7 +6532,7 @@ void ai_chase_eb(ai_info *aip, ship_info *sip, vec3d *predicted_enemy_pos, float
if ((dot_to_enemy > dot_from_enemy + 0.1f) || (dot_to_enemy > 0.9f))
vm_vec_scale_add(&_pep, &Pl_objp->pos, &En_objp->orient.vec.fvec, 100.0f);
ai_turn_towards_vector(&_pep, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&_pep, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
accelerate_ship(aip, 0.0f);
}
@@ -6755,7 +6729,7 @@ void attack_set_accel(ai_info *aip, ship_info *sip, float dist_to_enemy, float d
// Pl_objp (aip) tries to get behind En_objp.
// New on 2/21/98: If this ship can move backwards and slide, maybe do that to get behind.
void get_behind_ship(ai_info *aip, ship_info *sip, float /*dist_to_enemy*/)
static void get_behind_ship(ai_info *aip, ship_info *sip)
{
vec3d new_pos;
float dot;
@@ -6764,7 +6738,7 @@ void get_behind_ship(ai_info *aip, ship_info *sip, float /*dist_to_enemy*/)
vm_vec_normalized_dir(&vec_from_enemy, &Pl_objp->pos, &En_objp->pos);
vm_vec_scale_add(&new_pos, &En_objp->pos, &En_objp->orient.vec.fvec, -100.0f); // Pick point 100 units behind.
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
dot = vm_vec_dot(&vec_from_enemy, &En_objp->orient.vec.fvec);
@@ -6783,7 +6757,7 @@ int avoid_player(object *objp, vec3d *goal_pos)
if (aip->ai_flags[AI::AI_Flags::Avoiding_small_ship]) {
ship_info *sip = &Ship_info[Ships[objp->instance].ship_info_index];
ai_turn_towards_vector(&aip->avoid_goal_point, objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&aip->avoid_goal_point, objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
accelerate_ship(aip, 0.5f);
return 1;
}
@@ -6981,7 +6955,7 @@ int maybe_avoid_big_ship(object *objp, object *ignore_objp, ai_info *aip, vec3d
vec3d v2g;
ai_turn_towards_vector(&aip->avoid_goal_point, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&aip->avoid_goal_point, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
vm_vec_normalized_dir(&v2g, &aip->avoid_goal_point, &Pl_objp->pos);
float dot = vm_vec_dot(&objp->orient.vec.fvec, &v2g);
float d2 = (1.0f + dot) * (1.0f + dot);
@@ -7073,7 +7047,7 @@ void ai_stealth_find()
}
}
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
return;
}
@@ -7083,9 +7057,9 @@ void ai_stealth_find()
if (dist_to_enemy > 500.0f) {
vec3d rvec;
compute_desired_rvec(&rvec, &new_pos, &Pl_objp->pos);
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0, &rvec);
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0, &rvec);
} else {
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
}
dot_from_enemy = -vm_vec_dot(&vec_to_enemy, &En_objp->orient.vec.fvec);
@@ -7213,7 +7187,7 @@ void ai_stealth_sweep()
return;
}
ai_turn_towards_vector(&goal_pt, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&goal_pt, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
float dot = 1.0f;
if (dist_to_goal < 100) {
@@ -7273,9 +7247,9 @@ void ai_chase_attack(ai_info *aip, ship_info *sip, vec3d *predicted_enemy_pos, f
if (dist_to_enemy > 500.0f) {
vec3d rvec;
compute_desired_rvec(&rvec, predicted_enemy_pos, &Pl_objp->pos);
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, rel_pos, bank_override, 0, &rvec);
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, rel_pos, bank_override, 0, &rvec);
} else {
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, rel_pos, bank_override, 0);
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, rel_pos, bank_override, 0);
}
attack_set_accel(aip, sip, dist_to_enemy, dot_to_enemy, dot_from_enemy);
@@ -7313,7 +7287,7 @@ void ai_chase_es(ai_info *aip, ship_info *sip)
float bank_override = Pl_objp->phys_info.speed;
ai_turn_towards_vector(&tvec, Pl_objp, flFrametime/2, sip->srotation_time, NULL, NULL, bank_override, 0);
ai_turn_towards_vector(&tvec, Pl_objp, sip->srotation_time, nullptr, nullptr, bank_override, 0);
accelerate_ship(aip, 1.0f);
}
@@ -7339,7 +7313,7 @@ void ai_chase_ga(ai_info *aip, ship_info *sip)
bank_override = Pl_objp->phys_info.speed;
ai_turn_towards_vector(&tvec, Pl_objp, flFrametime/2, sip->srotation_time, NULL, NULL, bank_override, 0);
ai_turn_towards_vector(&tvec, Pl_objp, sip->srotation_time, nullptr, nullptr, bank_override, 0);
accelerate_ship(aip, 2.0f);
@@ -8001,7 +7975,7 @@ void ai_cruiser_chase()
// kamikaze - ram and explode
if (aip->ai_flags[AI::AI_Flags::Kamikaze]) {
ai_turn_towards_vector(&En_objp->pos, Pl_objp, flFrametime, turn_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&En_objp->pos, Pl_objp, turn_time, nullptr, nullptr, 0.0f, 0);
accelerate_ship(aip, 1.0f);
}
@@ -8041,7 +8015,7 @@ void ai_cruiser_chase()
}
// now move as desired
ai_turn_towards_vector(&goal_pos, Pl_objp, flFrametime, turn_time, NULL, NULL, 0.0f, 0, rvecp);
ai_turn_towards_vector(&goal_pos, Pl_objp, turn_time, nullptr, nullptr, 0.0f, 0, rvecp);
accelerate_ship(aip, accel);
// maybe switch to new mode
@@ -8322,7 +8296,7 @@ void ai_chase()
break;
case SM_EVADE_BRAKE:
ai_chase_eb(aip, sip, &predicted_enemy_pos, dist_to_enemy);
ai_chase_eb(aip, sip, &predicted_enemy_pos);
break;
case SM_EVADE:
@@ -8334,7 +8308,7 @@ void ai_chase()
break;
case SM_GET_BEHIND:
get_behind_ship(aip, sip, dist_to_enemy);
get_behind_ship(aip, sip);
break;
case SM_GET_AWAY: // Used to get away from opponent to prevent endless circling.
@@ -8768,7 +8742,11 @@ void ai_chase()
scale = (scale - 0.6f) * 1.5f;
else
scale = 0.0f;
if (dist_to_enemy < pwip->max_speed * (1.0f + scale)) {
float range = pwip->max_speed * (1.0f + scale);
if (aip->ai_profile_flags[AI::Profile_Flags::Use_actual_primary_range]) {
range = std::min( {range, pwip->max_speed * pwip->lifetime, pwip->weapon_range} );
}
if (dist_to_enemy < range) {
if(ai_fire_primary_weapon(Pl_objp) == 1){
has_fired = 1;
}else{
@@ -9329,7 +9307,7 @@ float dock_orient_and_approach(object *docker_objp, int docker_index, object *do
{
float dot, accel;
float turn_time = Ship_info[Ships[docker_objp->instance].ship_info_index].srotation_time;
ai_turn_towards_vector(&goal_point, docker_objp, flFrametime, turn_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&goal_point, docker_objp, turn_time, nullptr, nullptr, 0.0f, 0);
dot = vm_vec_dot(&docker_objp->orient.vec.fvec, &away_vec);
accel = 0.1f;
@@ -9964,10 +9942,10 @@ void ai_big_guard()
}
// got the point, now let's go there
ai_turn_towards_vector(&goal_pt, Pl_objp, flFrametime, Ship_info[Ships[Pl_objp->instance].ship_info_index].srotation_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&goal_pt, Pl_objp, Ship_info[Ships[Pl_objp->instance].ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0);
accelerate_ship(aip, 1.0f);
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (cur_guard_rad > 1.1f * max_guard_dist)) {
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (cur_guard_rad > 1.1f * max_guard_dist)) {
vec3d v2g;
float dot_to_goal_point;
@@ -10088,9 +10066,9 @@ void ai_guard()
// quite far away, so try to go straight to
compute_desired_rvec(&rvec, &goal_point, &Pl_objp->pos);
ai_turn_towards_vector(&goal_point, Pl_objp, flFrametime, Ship_info[shipp->ship_info_index].srotation_time, NULL, NULL, 0.0f, 0, &rvec);
ai_turn_towards_vector(&goal_point, Pl_objp, Ship_info[shipp->ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0, &rvec);
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (accel_scale * (0.25f + dist_to_goal_point/700.0f) > 0.8f)) {
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (accel_scale * (0.25f + dist_to_goal_point/700.0f) > 0.8f)) {
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
afterburners_start(Pl_objp);
aip->afterburner_stop_time = Missiontime + 3*F1_0;
@@ -10713,8 +10691,8 @@ void ai_dock()
char *goal_ship_class_name = goal_sip->name;
char *goal_dock_path_name = model_get(goal_sip->model_num)->paths[aip->mp_index].name;
Warning(LOCATION, "Ship class %s has only %i points on dock path \"%s\". Recommended minimum number of points is 4. "\
"Docking along that path will look strange. You may wish to edit the model.", goal_ship_class_name, aip->path_length, goal_dock_path_name);
mprintf(("Ship class %s has only %i points on dock path \"%s\". Recommended minimum number of points is 4. "\
"Docking along that path will look strange. You may wish to edit the model.", goal_ship_class_name, aip->path_length, goal_dock_path_name));
}
aip->submode = AIS_DOCK_1;
@@ -11385,7 +11363,7 @@ float gwlr_1(object *objp, ai_info *aip)
/**
* Compute the largest radius of a ship forming on *objp's wing.
*/
float gwlr_object_1(object *objp, ai_info * /*aip*/)
static float gwlr_object_1(object *objp)
{
float max_radius;
object *o;
@@ -11418,7 +11396,7 @@ float get_wing_largest_radius(object *objp, int formation_object_flag)
aip = &Ai_info[shipp->ai_index];
if (formation_object_flag) {
return gwlr_object_1(objp, aip);
return gwlr_object_1(objp);
} else {
return gwlr_1(objp, aip);
}
@@ -11808,7 +11786,7 @@ int ai_formation()
ship_info *sip = &Ship_info[shipp->ship_info_index];
bool ab_allowed = false;
if ((sip->flags[Ship::Info_Flags::Afterburner]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (aip->ai_flags[AI::AI_Flags::Free_afterburner_use])) {
if ((sip->flags[Ship::Info_Flags::Afterburner]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (aip->ai_flags[AI::AI_Flags::Free_afterburner_use] || aip->ai_profile_flags[AI::Profile_Flags::Free_afterburner_use])) {
ab_allowed = true;
} else {
if (Pl_objp->phys_info.flags & PF_AFTERBURNER_ON)
@@ -12191,7 +12169,7 @@ void ai_maybe_launch_cmeasure(object *objp, ai_info *aip)
}
// --------------------------------------------------------------------------
void ai_preprocess_ignore_objnum(object * /*objp*/, ai_info *aip)
static void ai_preprocess_ignore_objnum(ai_info *aip)
{
if (aip->ai_flags[AI::AI_Flags::Temporary_ignore])
{
@@ -13064,7 +13042,6 @@ void ai_execute_behavior(ai_info *aip)
case AIM_NONE:
break;
case AIM_BIGSHIP:
ai_big_ship(Pl_objp);
break;
case AIM_PATH: {
int path_num;
@@ -13441,7 +13418,7 @@ void ai_warp_out(object *objp)
// Return object index of weapon that could produce a shockwave that should be known about to *objp.
// Return nearest one.
int ai_find_shockwave_weapon(object *objp, ai_info * /*aip*/)
static int ai_find_shockwave_weapon(const object *objp)
{
missile_obj *mo;
float nearest_dist = 999999.9f;
@@ -13507,7 +13484,7 @@ void ai_announce_ship_dying(object *dying_objp)
// Return object index of weapon that could produce a shockwave that should be known about to *objp.
// Return nearest one.
int ai_find_shockwave_ship(object *objp, ai_info * /*aip*/)
static int ai_find_shockwave_ship(object *objp)
{
ship_obj *so;
float nearest_dist = 999999.9f;
@@ -13550,7 +13527,7 @@ int aas_1(object *objp, ai_info *aip, vec3d *safe_pos)
// If we don't currently know of a weapon to avoid, try to find one.
// If we can't find one, then clear the bit so we don't keep coming here.
if (aip->shockwave_object == -1) {
int shockwave_weapon = ai_find_shockwave_weapon(objp, aip);
int shockwave_weapon = ai_find_shockwave_weapon(objp);
if (shockwave_weapon == -1) {
aip->ai_flags.remove(AI::AI_Flags::Avoid_shockwave_weapon);
return 0;
@@ -13639,7 +13616,7 @@ int aas_1(object *objp, ai_info *aip, vec3d *safe_pos)
}
} else if (aip->ai_flags[AI::AI_Flags::Avoid_shockwave_ship]) {
if (aip->shockwave_object == -1) {
int shockwave_ship = ai_find_shockwave_ship(objp, aip);
int shockwave_ship = ai_find_shockwave_ship(objp);
if (shockwave_ship == -1) {
aip->ai_flags.remove(AI::AI_Flags::Avoid_shockwave_ship);
return 0;
@@ -13869,7 +13846,7 @@ int maybe_big_ship_collide_recover_frame(object *objp, ai_info *aip)
vec3d v2g;
if (aip->ai_flags[AI::AI_Flags::Big_ship_collide_recover_1]) {
ai_turn_towards_vector(&aip->big_recover_pos_1, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, NULL, NULL, 0.0f, 0, NULL);
ai_turn_towards_vector(&aip->big_recover_pos_1, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0, nullptr);
dist = vm_vec_normalized_dir(&v2g, &aip->big_recover_pos_1, &objp->pos);
dot = vm_vec_dot(&objp->orient.vec.fvec, &v2g);
accelerate_ship(aip, dot);
@@ -13883,7 +13860,7 @@ int maybe_big_ship_collide_recover_frame(object *objp, ai_info *aip)
return 1;
} else if (aip->ai_flags[AI::AI_Flags::Big_ship_collide_recover_2]) {
ai_turn_towards_vector(&aip->big_recover_pos_2, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, NULL, NULL, 0.0f, 0, NULL);
ai_turn_towards_vector(&aip->big_recover_pos_2, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0, nullptr);
dist = vm_vec_normalized_dir(&v2g, &aip->big_recover_pos_2, &objp->pos);
dot = vm_vec_dot(&objp->orient.vec.fvec, &v2g);
accelerate_ship(aip, dot);
@@ -14003,7 +13980,7 @@ void ai_frame(int objnum)
if (maybe_big_ship_collide_recover_frame(Pl_objp, aip))
return;
ai_preprocess_ignore_objnum(Pl_objp, aip);
ai_preprocess_ignore_objnum(aip);
target_objnum = set_target_objnum(aip, aip->target_objnum);
Assert(objnum != target_objnum);
@@ -14158,7 +14135,7 @@ void ai_frame(int objnum)
}
}
void ai_control_info_check( object * /*obj*/, ai_info *aip )
static void ai_control_info_check(ai_info *aip)
{
if(aip->ai_override_flags.none_set())
return;
@@ -14259,7 +14236,7 @@ void ai_process( object * obj, int ai_index, float frametime )
if (rfc == 1) {
// Wanderer - sexp based override goes here - only if rfc is valid though
ai_control_info_check(obj, aip);
ai_control_info_check(aip);
vec3d copy_desired_rotvel = obj->phys_info.rotvel;
physics_read_flying_controls( &obj->orient, &obj->phys_info, &AI_ci, frametime);
// if obj is in formation and not flight leader, don't update rotvel
@@ -14794,10 +14771,10 @@ int firing_aspect_seeking_bomb(object *objp)
return 0;
}
// *objp collided with big ship *big_objp at global point *collide_pos
// Make it fly away from the collision point.
// *objp collided with big ship *big_objp at some global point.
// Make it fly away from the collision point.
// collision_normal is NULL, when a collision is imminent and we just want to bug out.
void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d * /*collide_pos*/, vec3d *collision_normal)
void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collision_normal)
{
ai_info *aip;
@@ -14886,9 +14863,9 @@ void ai_update_lethality(object *pship_obj, object *other_obj, float damage)
/**
* Object *objp_ship was hit by either weapon *objp_weapon or collided into by ship hit_objp at point *hitpos.
* Object *objp_ship was hit by either weapon *objp_weapon or collided into by ship hit_objp
*/
void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hitpos, int /*shield_quadrant*/, vec3d *hit_normal)
void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal)
{
int hitter_objnum = -2;
object *objp_hitter = NULL;
@@ -14930,7 +14907,7 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hitpos, int /*shie
// And the current object is _not_ a big ship
if (!Ship_info[Ships[objp_ship->instance].ship_info_index].is_big_or_huge()) {
// Recover from hitting a big ship. Note, if two big ships collide, they just pound away at each other. Oh well. Recovery looks dumb and it's very late.
big_ship_collide_recover_start(objp_ship, hit_objp, hitpos, hit_normal);
big_ship_collide_recover_start(objp_ship, hit_objp, hit_normal);
}
}
}
@@ -15067,7 +15044,7 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hitpos, int /*shie
return;
if ( (hit_objp->type == OBJ_WEAPON) && !(aip->ai_flags[AI::AI_Flags::No_dynamic]) ) {
if ( ai_big_maybe_enter_strafe_mode(objp_ship, OBJ_INDEX(hit_objp), 1) )
if ( ai_big_maybe_enter_strafe_mode(objp_ship, OBJ_INDEX(hit_objp)) )
return;
}
break;
@@ -15187,10 +15164,7 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hitpos, int /*shie
// Ship shipnum has been destroyed.
// Cleanup.
// the parameter 'method' is used to tell is this ship was destroyed or it departed normally.
// This function will get called in either case, and there are things that should be done if
// the ship actually gets destroyed which shouldn't get done if it departed.
void ai_ship_destroy(int shipnum, Ship::Exit_Flags /*method*/)
void ai_ship_destroy(int shipnum)
{
int objnum;
object *other_objp;
@@ -15441,7 +15415,7 @@ int ai_issue_rearm_request(object *requester_objp)
// we aren't able to do anything!
else {
Assert(result == 4);
Assertion(false, "This case should have already been caught by the is_support_allowed precheck!");
UNREACHABLE("This case should have already been caught by the is_support_allowed precheck!");
return -1;
}
}
@@ -15510,7 +15484,7 @@ int ai_return_path_num_from_dockbay(object *dockee_objp, int dockbay_index)
/**
* Actually go ahead and fire the synaptics.
*/
void cheat_fire_synaptic(object *objp, ship *shipp, ai_info * /*aip*/)
static void cheat_fire_synaptic(object *objp, ship *shipp)
{
ship_weapon *swp;
swp = &shipp->weapons;
@@ -15532,7 +15506,7 @@ void cheat_fire_synaptic(object *objp, ship *shipp, ai_info * /*aip*/)
// if they're near one or more enemies
// every so often
// fire a synaptic if they have one.
void maybe_cheat_fire_synaptic(object *objp, ai_info *aip)
void maybe_cheat_fire_synaptic(object *objp)
{
// Only do in subspace missions.
if (!(The_mission.flags[Mission::Mission_Flags::Subspace]))
@@ -15564,7 +15538,7 @@ void maybe_cheat_fire_synaptic(object *objp, ai_info *aip)
int count = num_nearby_fighters(iff_get_attackee_mask(obj_team(objp)), &objp->pos, 1500.0f);
if (count > 0)
cheat_fire_synaptic(objp, shipp, aip);
cheat_fire_synaptic(objp, shipp);
}
}
}
+1 -1
View File
@@ -125,7 +125,7 @@ const char *Ai_goal_text(int goal)
case AI_GOAL_REARM_REPAIR:
return XSTR( "rearm ", 484);
case AI_GOAL_FLY_TO_SHIP:
return XSTR( "rendezvous with ", -1);
return XSTR( "rendezvous with ", 1597);
}
// Avoid compiler warning
+3 -3
View File
@@ -1874,7 +1874,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
turret->last_fired_weapon_info_index = turret_weapon_class;
Script_system.SetHookObjects(4, "Ship", &Objects[parent_objnum], "Weapon", nullptr, "Beam", objp, "Target", &Objects[turret->turret_enemy_objnum]);
Script_system.RunCondition(CHA_ONTURRETFIRED, 0, NULL, &Objects[parent_objnum]);
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[parent_objnum]);
Script_system.RemHookVars(4, "Ship", "Weapon", "Beam", "Target");
}
@@ -2009,7 +2009,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
wp->turret_subsys = turret;
Script_system.SetHookObjects(4, "Ship", &Objects[parent_objnum], "Weapon", objp, "Beam", nullptr, "Target", &Objects[turret->turret_enemy_objnum]);
Script_system.RunCondition(CHA_ONTURRETFIRED, 0, NULL, &Objects[parent_objnum]);
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[parent_objnum]);
Script_system.RemHookVars(4, "Ship", "Weapon", "Beam", "Target");
// if the gun is a flak gun
@@ -2126,7 +2126,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
tsi->turret->last_fired_weapon_info_index = tsi->weapon_class;
Script_system.SetHookObjects(4, "Ship", &Objects[tsi->parent_objnum], "Weapon", &Objects[weapon_objnum], "Beam", nullptr, "Target", &Objects[tsi->turret->turret_enemy_objnum]);
Script_system.RunCondition(CHA_ONTURRETFIRED, 0, NULL, &Objects[tsi->parent_objnum]);
Script_system.RunCondition(CHA_ONTURRETFIRED, &Objects[tsi->parent_objnum]);
Script_system.RemHookVars(4, "Ship", "Weapon", "Beam", "Target");
// muzzle flash?
+2 -2
View File
@@ -1387,7 +1387,7 @@ void asteroid_hit( object * pasteroid_obj, object * other_obj, vec3d * hitpos, f
weapon_info *wip;
wip = &Weapon_info[Weapons[other_obj->instance].weapon_info_index];
// If the weapon didn't play any impact animation, play custom asteroid impact animation
if ( wip->impact_weapon_expl_effect < 0 ) {
if (!wip->impact_weapon_expl_effect.isValid()) {
particle::create( hitpos, &vmd_zero_vector, 0.0f, Asteroid_impact_explosion_radius, particle::PARTICLE_BITMAP, Asteroid_impact_explosion_ani );
}
}
@@ -1547,7 +1547,7 @@ static void asteroid_maybe_break_up(object *pasteroid_obj)
}
asp->final_death_time = timestamp(-1);
}
Script_system.RunCondition(CHA_DEATH, '\0', NULL, pasteroid_obj);
Script_system.RunCondition(CHA_DEATH, pasteroid_obj);
Script_system.RemHookVar("Self");
}
}
+17 -23
View File
@@ -591,7 +591,7 @@ int bm_create(int bpp, int w, int h, void *data, int flags) {
memset(entry, 0, sizeof(bitmap_entry));
sprintf(entry->filename, "TMP%dx%d+%d", w, h, bpp);
sprintf_safe(entry->filename, "TMP%dx%d+%d", w, h, bpp);
entry->type = BM_TYPE_USER;
entry->comp_type = BM_TYPE_NONE;
entry->palette_checksum = 0;
@@ -1155,7 +1155,7 @@ static int bm_load_info(BM_TYPE type, const char *filename, CFILE *img_cfp, int
}
}
else {
Assertion(false, "Unknown file type specified! This is probably a coding error.");
UNREACHABLE("Unknown file type specified! This is probably a coding error.");
return -1;
}
@@ -1253,7 +1253,7 @@ int bm_load(const char *real_filename) {
// Mark the slot as filled, because cf_read might load a new bitmap
// into this slot.
strncpy(entry->filename, filename, MAX_FILENAME_LEN - 1);
strcpy_s(entry->filename, filename);
entry->type = type;
entry->comp_type = c_type;
entry->signature = Bm_next_signature++;
@@ -1681,7 +1681,7 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
if (type == BM_TYPE_EFF) {
entry->info.ani.eff.type = eff_type;
sprintf(entry->info.ani.eff.filename, "%s_%.4d", clean_name, i);
sprintf_safe(entry->info.ani.eff.filename, "%s_%.4d", clean_name, i);
// bm_load_info() returns non-0 on failure
if (bm_load_info(eff_type, entry->info.ani.eff.filename,
@@ -1744,13 +1744,13 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
entry->load_count++;
if (i == 0) {
sprintf(entry->filename, "%s", filename);
sprintf_safe(entry->filename, "%s", filename);
} else {
if (type == BM_TYPE_PNG) {
sprintf(entry->filename, "%s_%04d", filename, i);
sprintf_safe(entry->filename, "%s_%04d", filename, i);
}
else {
sprintf(entry->filename, "%s[%d]", filename, i);
sprintf_safe(entry->filename, "%s[%d]", filename, i);
}
}
@@ -1876,27 +1876,23 @@ int bm_load_sub_fast(const char *real_filename, int *handle, int dir_type, bool
}
int bm_load_sub_slow(const char *real_filename, const int num_ext, const char **ext_list, CFILE **img_cfp, int dir_type) {
char full_path[MAX_PATH];
size_t size = 0, offset = 0;
int rval = -1;
const void* file_data = nullptr;
rval = cf_find_file_location_ext(real_filename, num_ext, ext_list, dir_type, sizeof(full_path) - 1, full_path, &size, &offset, 0, &file_data);
auto res = cf_find_file_location_ext(real_filename, num_ext, ext_list, dir_type, false);
// could not be found, or is invalid for some reason
if ((rval < 0) || (rval >= num_ext))
if (!res.found)
return -1;
CFILE *test = cfopen_special(full_path, "rb", size, offset, file_data, dir_type);
CFILE *test = cfopen_special(res.full_name.c_str(), "rb", res.size, res.offset, res.data_ptr, dir_type);
if (test != NULL) {
if (img_cfp != NULL)
*img_cfp = test;
return rval;
return res.extension_index;
}
// umm, that's not good...
Warning(LOCATION, "Could not open file %s!", res.full_name.c_str());
return -1;
}
@@ -2385,7 +2381,7 @@ void bm_lock_png(int handle, bitmap_slot *bs, bitmap *bmp, int /*bpp*/, ubyte /*
void bm_lock_tga(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags) {
ubyte *data = NULL;
int d_size, byte_size;
int byte_size;
char filename[MAX_FILENAME_LEN];
auto be = &bs->entry;
@@ -2393,6 +2389,8 @@ void bm_lock_tga(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags)
// Unload any existing data
bm_free_data(bs);
bpp = be->bm.true_bpp;
if (Is_standalone) {
Assert(bpp == 8);
} else {
@@ -2409,7 +2407,6 @@ void bm_lock_tga(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags)
if (data) {
memset(data, 0, be->mem_taken);
d_size = byte_size;
} else {
return;
}
@@ -2429,7 +2426,7 @@ void bm_lock_tga(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags)
// this will populate filename[] whether it's EFF or not
EFF_FILENAME_CHECK;
tga_error = targa_read_bitmap(filename, data, NULL, d_size, be->dir_type);
tga_error = targa_read_bitmap(filename, data, nullptr, byte_size, be->dir_type);
if (tga_error != TARGA_ERROR_NONE) {
bm_free_data(bs);
@@ -2526,7 +2523,7 @@ int bm_make_render_target(int width, int height, int flags) {
entry->type = (flags & BMP_FLAG_RENDER_TARGET_STATIC) ? BM_TYPE_RENDER_TARGET_STATIC : BM_TYPE_RENDER_TARGET_DYNAMIC;
entry->signature = Bm_next_signature++;
sprintf(entry->filename, "RT_%dx%d+%d", w, h, bpp);
sprintf_safe(entry->filename, "RT_%dx%d+%d", w, h, bpp);
entry->bm.w = (short)w;
entry->bm.h = (short)h;
entry->bm.rowsize = (short)w;
@@ -2589,9 +2586,6 @@ void bm_page_in_start() {
for (auto& slot : block) {
auto& entry = slot.entry;
if (!Cmdline_cache_bitmaps && (entry.type != BM_TYPE_NONE)) {
bm_unload_fast(entry.handle);
}
entry.preloaded = 0;
entry.preload_count = 0;
#ifdef BMPMAN_NDEBUG
+1 -1
View File
@@ -962,7 +962,7 @@ size_t cam_get_num()
/**
* Looks up camera by name, returns -1 on failure
*/
camid cam_lookup(char *name)
camid cam_lookup(const char* name)
{
size_t i, size=Cameras.size();
for(i = 0; i < size; i++)
+2 -2
View File
@@ -68,7 +68,7 @@ public:
void set_rotation_velocity(angles *in_rotation_rate, float in_acceleration_time = 0.0f);
//Get
char *get_name() {return name;}
const char* get_name() { return name; }
int get_signature() {return sig;}
object *get_object_host();
int get_object_host_submodel();
@@ -163,7 +163,7 @@ camid cam_create(const char *n_name, vec3d *n_pos, vec3d *n_norm, object *n_obje
void cam_delete(camid cid);
bool cam_set_camera(camid cid);
void cam_reset_camera();
camid cam_lookup(char *name);
camid cam_lookup(const char* name);
camid cam_get_camera(uint index);
camid cam_get_current();
size_t cam_get_num();
+120 -87
View File
@@ -33,70 +33,66 @@
#include "cfile/cfilesystem.h"
#include "osapi/osapi.h"
#include "parse/encrypt.h"
#include "cfilesystem.h"
#include <limits>
char Cfile_root_dir[CFILE_ROOT_DIRECTORY_LEN] = "";
char Cfile_user_dir[CFILE_ROOT_DIRECTORY_LEN] = "";
#ifdef SCP_UNIX
char Cfile_user_dir_legacy[CFILE_ROOT_DIRECTORY_LEN] = "";
#endif
// During cfile_init, verify that Pathtypes[n].index == n for each item
// Each path must have a valid parent that can be tracable all the way back to the root
// Each path must have a valid parent that can be tracable all the way back to the root
// so that we can create directories when we need to.
//
// Please make sure extensions are all lower-case, or we'll break unix compatibility
//
cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
// What type this is Path Extensions Parent
// type
{CF_TYPE_INVALID, NULL, NULL, CF_TYPE_INVALID},
// Root must be index 1!!
{CF_TYPE_ROOT, "", ".mve .ogg", CF_TYPE_ROOT},
{CF_TYPE_DATA, "data", ".cfg .txt", CF_TYPE_ROOT},
{CF_TYPE_MAPS, "data" DIR_SEPARATOR_STR "maps", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA},
{CF_TYPE_TEXT, "data" DIR_SEPARATOR_STR "text", ".txt .net", CF_TYPE_DATA},
{CF_TYPE_MODELS, "data" DIR_SEPARATOR_STR "models", ".pof", CF_TYPE_DATA},
{CF_TYPE_TABLES, "data" DIR_SEPARATOR_STR "tables", ".tbl .tbm", CF_TYPE_DATA},
{CF_TYPE_SOUNDS, "data" DIR_SEPARATOR_STR "sounds", ".wav .ogg", CF_TYPE_DATA},
{CF_TYPE_SOUNDS_8B22K, "data" DIR_SEPARATOR_STR "sounds" DIR_SEPARATOR_STR "8b22k", ".wav .ogg", CF_TYPE_SOUNDS},
{CF_TYPE_SOUNDS_16B11K, "data" DIR_SEPARATOR_STR "sounds" DIR_SEPARATOR_STR "16b11k", ".wav .ogg", CF_TYPE_SOUNDS},
{CF_TYPE_VOICE, "data" DIR_SEPARATOR_STR "voice", "", CF_TYPE_DATA},
{CF_TYPE_VOICE_BRIEFINGS, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "briefing", ".wav .ogg",
CF_TYPE_VOICE},
{CF_TYPE_VOICE_CMD_BRIEF, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "command_briefings", ".wav .ogg",
CF_TYPE_VOICE},
{CF_TYPE_VOICE_DEBRIEFINGS, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "debriefing", ".wav .ogg",
CF_TYPE_VOICE},
{CF_TYPE_VOICE_PERSONAS, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "personas", ".wav .ogg", CF_TYPE_VOICE},
{CF_TYPE_VOICE_SPECIAL, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "special", ".wav .ogg", CF_TYPE_VOICE},
{CF_TYPE_VOICE_TRAINING, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "training", ".wav .ogg", CF_TYPE_VOICE},
{CF_TYPE_MUSIC, "data" DIR_SEPARATOR_STR "music", ".wav .ogg", CF_TYPE_DATA},
{CF_TYPE_MOVIES, "data" DIR_SEPARATOR_STR "movies", ".mve .msb .ogg .mp4 .srt", CF_TYPE_DATA},
{CF_TYPE_INTERFACE, "data" DIR_SEPARATOR_STR "interface", ".pcx .ani .dds .tga .eff .png .jpg", CF_TYPE_DATA},
{CF_TYPE_FONT, "data" DIR_SEPARATOR_STR "fonts", ".vf .ttf", CF_TYPE_DATA},
{CF_TYPE_EFFECTS, "data" DIR_SEPARATOR_STR "effects", ".ani .eff .pcx .neb .tga .jpg .png .dds .sdr", CF_TYPE_DATA},
{CF_TYPE_HUD, "data" DIR_SEPARATOR_STR "hud", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA},
{CF_TYPE_PLAYERS, "data" DIR_SEPARATOR_STR "players", ".hcf", CF_TYPE_DATA},
{CF_TYPE_PLAYER_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "images", ".pcx .png .dds",
CF_TYPE_PLAYERS},
{CF_TYPE_SQUAD_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "squads", ".pcx .png .dds",
CF_TYPE_PLAYERS},
{CF_TYPE_SINGLE_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "single", ".pl2 .cs2 .plr .csg .css",
CF_TYPE_PLAYERS},
{CF_TYPE_MULTI_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "multi", ".plr", CF_TYPE_PLAYERS},
{CF_TYPE_CACHE, "data" DIR_SEPARATOR_STR "cache", ".clr .tmp .bx", CF_TYPE_DATA}, // clr=cached color
{CF_TYPE_MULTI_CACHE, "data" DIR_SEPARATOR_STR "multidata", ".pcx .png .dds .fs2 .txt", CF_TYPE_DATA},
{CF_TYPE_MISSIONS, "data" DIR_SEPARATOR_STR "missions", ".fs2 .fc2 .ntl .ssv", CF_TYPE_DATA},
{CF_TYPE_CONFIG, "data" DIR_SEPARATOR_STR "config", ".cfg .tbl .tbm .xml .csv", CF_TYPE_DATA},
{CF_TYPE_DEMOS, "data" DIR_SEPARATOR_STR "demos", ".fsd", CF_TYPE_DATA},
{CF_TYPE_CBANIMS, "data" DIR_SEPARATOR_STR "cbanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA},
{CF_TYPE_INTEL_ANIMS, "data" DIR_SEPARATOR_STR "intelanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA},
{CF_TYPE_SCRIPTS, "data" DIR_SEPARATOR_STR "scripts", ".lua .lc", CF_TYPE_DATA},
{CF_TYPE_FICTION, "data" DIR_SEPARATOR_STR "fiction", ".txt", CF_TYPE_DATA},
{CF_TYPE_FREDDOCS, "data" DIR_SEPARATOR_STR "freddocs", ".html", CF_TYPE_DATA},
// clang-format off
cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
// What type this is Path Extensions Parent type
{ CF_TYPE_INVALID, NULL, NULL, CF_TYPE_INVALID },
// Root must be index 1!!
{ CF_TYPE_ROOT, "", ".mve .ogg", CF_TYPE_ROOT },
{ CF_TYPE_DATA, "data", ".cfg .txt", CF_TYPE_ROOT },
{ CF_TYPE_MAPS, "data" DIR_SEPARATOR_STR "maps", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
{ CF_TYPE_TEXT, "data" DIR_SEPARATOR_STR "text", ".txt .net", CF_TYPE_DATA },
{ CF_TYPE_MODELS, "data" DIR_SEPARATOR_STR "models", ".pof", CF_TYPE_DATA },
{ CF_TYPE_TABLES, "data" DIR_SEPARATOR_STR "tables", ".tbl .tbm", CF_TYPE_DATA },
{ CF_TYPE_SOUNDS, "data" DIR_SEPARATOR_STR "sounds", ".wav .ogg", CF_TYPE_DATA },
{ CF_TYPE_SOUNDS_8B22K, "data" DIR_SEPARATOR_STR "sounds" DIR_SEPARATOR_STR "8b22k", ".wav .ogg", CF_TYPE_SOUNDS },
{ CF_TYPE_SOUNDS_16B11K, "data" DIR_SEPARATOR_STR "sounds" DIR_SEPARATOR_STR "16b11k", ".wav .ogg", CF_TYPE_SOUNDS },
{ CF_TYPE_VOICE, "data" DIR_SEPARATOR_STR "voice", "", CF_TYPE_DATA },
{ CF_TYPE_VOICE_BRIEFINGS, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "briefing", ".wav .ogg", CF_TYPE_VOICE },
{ CF_TYPE_VOICE_CMD_BRIEF, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "command_briefings", ".wav .ogg", CF_TYPE_VOICE },
{ CF_TYPE_VOICE_DEBRIEFINGS, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "debriefing", ".wav .ogg", CF_TYPE_VOICE },
{ CF_TYPE_VOICE_PERSONAS, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "personas", ".wav .ogg", CF_TYPE_VOICE },
{ CF_TYPE_VOICE_SPECIAL, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "special", ".wav .ogg", CF_TYPE_VOICE },
{ CF_TYPE_VOICE_TRAINING, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "training", ".wav .ogg", CF_TYPE_VOICE },
{ CF_TYPE_MUSIC, "data" DIR_SEPARATOR_STR "music", ".wav .ogg", CF_TYPE_DATA },
{ CF_TYPE_MOVIES, "data" DIR_SEPARATOR_STR "movies", ".mve .msb .ogg .mp4 .srt .webm .png",CF_TYPE_DATA },
{ CF_TYPE_INTERFACE, "data" DIR_SEPARATOR_STR "interface", ".pcx .ani .dds .tga .eff .png .jpg", CF_TYPE_DATA },
{ CF_TYPE_FONT, "data" DIR_SEPARATOR_STR "fonts", ".vf .ttf", CF_TYPE_DATA },
{ CF_TYPE_EFFECTS, "data" DIR_SEPARATOR_STR "effects", ".ani .eff .pcx .neb .tga .jpg .png .dds .sdr", CF_TYPE_DATA },
{ CF_TYPE_HUD, "data" DIR_SEPARATOR_STR "hud", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
{ CF_TYPE_PLAYERS, "data" DIR_SEPARATOR_STR "players", ".hcf", CF_TYPE_DATA },
{ CF_TYPE_PLAYER_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "images", ".pcx .png .dds", CF_TYPE_PLAYERS },
{ CF_TYPE_SQUAD_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "squads", ".pcx .png .dds", CF_TYPE_PLAYERS },
{ CF_TYPE_SINGLE_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "single", ".pl2 .cs2 .plr .csg .css .json", CF_TYPE_PLAYERS },
{ CF_TYPE_MULTI_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "multi", ".plr .json", CF_TYPE_PLAYERS },
{ CF_TYPE_CACHE, "data" DIR_SEPARATOR_STR "cache", ".clr .tmp .bx", CF_TYPE_DATA }, //clr=cached color
{ CF_TYPE_MULTI_CACHE, "data" DIR_SEPARATOR_STR "multidata", ".pcx .png .dds .fs2 .txt", CF_TYPE_DATA },
{ CF_TYPE_MISSIONS, "data" DIR_SEPARATOR_STR "missions", ".fs2 .fc2 .ntl .ssv", CF_TYPE_DATA },
{ CF_TYPE_CONFIG, "data" DIR_SEPARATOR_STR "config", ".cfg .tbl .tbm .xml .csv", CF_TYPE_DATA },
{ CF_TYPE_DEMOS, "data" DIR_SEPARATOR_STR "demos", ".fsd", CF_TYPE_DATA },
{ CF_TYPE_CBANIMS, "data" DIR_SEPARATOR_STR "cbanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
{ CF_TYPE_INTEL_ANIMS, "data" DIR_SEPARATOR_STR "intelanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
{ CF_TYPE_SCRIPTS, "data" DIR_SEPARATOR_STR "scripts", ".lua .lc", CF_TYPE_DATA },
{ CF_TYPE_FICTION, "data" DIR_SEPARATOR_STR "fiction", ".txt", CF_TYPE_DATA },
{ CF_TYPE_FREDDOCS, "data" DIR_SEPARATOR_STR "freddocs", ".html", CF_TYPE_DATA },
{ CF_TYPE_INTERFACE_MARKUP, "data" DIR_SEPARATOR_STR "interface" DIR_SEPARATOR_STR "markup", ".rml", CF_TYPE_INTERFACE },
{ CF_TYPE_INTERFACE_CSS, "data" DIR_SEPARATOR_STR "interface" DIR_SEPARATOR_STR "css", ".rcss", CF_TYPE_INTERFACE },
};
// clang-format on
#define CFILE_STACK_MAX 8
@@ -230,14 +226,8 @@ int cfile_init(const char *exe_dir, const char *cdrom_dir)
cfile_chdir(buf);
// set root directory
strncpy(Cfile_root_dir, buf, CFILE_ROOT_DIRECTORY_LEN-1);
strncpy(Cfile_user_dir, os_get_config_path().c_str(), CFILE_ROOT_DIRECTORY_LEN-1);
#ifdef SCP_UNIX
// Initialize path of old pilot files
extern const char* Osreg_user_dir_legacy;
snprintf(Cfile_user_dir_legacy, CFILE_ROOT_DIRECTORY_LEN-1, "%s/%s/", getenv("HOME"), Osreg_user_dir_legacy);
#endif
strcpy_s(Cfile_root_dir, buf);
strcpy_s(Cfile_user_dir, os_get_config_path().c_str());
for (i = 0; i < MAX_CFILE_BLOCKS; i++) {
Cfile_block_list[i].type = CFILE_BLOCK_UNUSED;
@@ -362,8 +352,7 @@ int cfile_push_chdir(int type)
return -1;
}
strncpy(Cfile_stack[Cfile_stack_pos++], OriginalDirectory,
CFILE_ROOT_DIRECTORY_LEN - 1);
strcpy_s(Cfile_stack[Cfile_stack_pos++], OriginalDirectory);
cf_create_default_path_string(dir, sizeof(dir) - 1, type, NULL);
@@ -486,17 +475,17 @@ char *cf_add_ext(const char *filename, const char *ext)
*
* @param filename Name of file to delete
* @param path_type Path type (CF_TYPE_xxx)
* @param location_flags Where to search for the location of the file to delete
*
* @return 0 on failure, 1 on success
*/
int cf_delete(const char *filename, int path_type)
int cf_delete(const char *filename, int path_type, uint32_t location_flags)
{
char longname[MAX_PATH_LEN];
Assert(CF_TYPE_SPECIFIED(path_type));
cf_create_default_path_string(longname, sizeof(longname) - 1,
path_type, filename);
cf_create_default_path_string(longname, sizeof(longname) - 1, path_type, filename, false, location_flags);
return (_unlink(longname) != -1);
}
@@ -522,12 +511,12 @@ int cf_access(const char *filename, int dir_type, int mode)
// If offset equates to boolean true, it was found in a VP and the logic will negate the function return
int cf_exists(const char *filename, int dir_type)
{
size_t offset = 1;
if ( (filename == NULL) || !strlen(filename) )
return 0;
return (cf_find_file_location(filename, dir_type, 0, NULL, NULL, &offset) && !offset);
auto find_res = cf_find_file_location(filename, dir_type);
return find_res.found && !find_res.offset;
}
// Goober5000
@@ -538,7 +527,7 @@ int cf_exists_full(const char *filename, int dir_type)
if ( (filename == NULL) || !strlen(filename) )
return 0;
return cf_find_file_location(filename, dir_type, 0, NULL, NULL, NULL);
return cf_find_file_location(filename, dir_type).found;
}
// same as the above, but with extension check
@@ -550,7 +539,7 @@ int cf_exists_full_ext(const char *filename, int dir_type, const int num_ext, co
if ( (num_ext <= 0) || (ext_list == NULL) )
return 0;
return (cf_find_file_location_ext(filename, num_ext, ext_list, dir_type, 0, NULL, NULL, NULL) != -1);
return cf_find_file_location_ext(filename, num_ext, ext_list, dir_type).found;
}
#ifdef _WIN32
@@ -624,7 +613,7 @@ static void mkdir_recursive(const char *path) {
// Creates the directory path if it doesn't exist. Even creates all its
// parent paths.
void cf_create_directory( int dir_type )
void cf_create_directory(int dir_type, uint32_t location_flags)
{
int num_dirs = 0;
int dir_tree[CF_MAX_PATH_TYPES];
@@ -646,7 +635,7 @@ void cf_create_directory( int dir_type )
int i;
for (i=num_dirs-1; i>=0; i-- ) {
cf_create_default_path_string( longname, sizeof(longname)-1, dir_tree[i], NULL );
cf_create_default_path_string(longname, sizeof(longname) - 1, dir_tree[i], nullptr, false, location_flags);
if (stat(longname, &statbuf) != 0) {
mprintf(( "CFILE: Creating new directory '%s'\n", longname ));
mkdir_recursive(longname);
@@ -673,14 +662,13 @@ extern int game_cd_changed();
// error ==> NULL
//
CFILE *_cfopen(const char* source, int line, const char *file_path, const char *mode, int type, int dir_type, bool localize)
CFILE* _cfopen(const char* source, int line, const char* file_path, const char* mode, int type, int dir_type,
bool localize, uint32_t location_flags)
{
/* Bobboau, what is this doing here? 31 is way too short... - Goober5000
if( strlen(file_path) > 31 )
Error(LOCATION, "file name %s too long, \nmust be less than 31 charicters", file_path);*/
char longname[_MAX_PATH];
if ( !cfile_inited ) {
Int3();
return NULL;
@@ -702,6 +690,8 @@ CFILE *_cfopen(const char* source, int line, const char *file_path, const char *
// the harddisk. No fancy packfile stuff here!
if ( strchr(mode,'w') || strchr(mode,'+') || strchr(mode,'a') ) {
char longname[_MAX_PATH];
// For write-only files, require a full path or a path type
#ifdef SCP_UNIX
if ( strpbrk(file_path, "/") ) {
@@ -715,9 +705,9 @@ CFILE *_cfopen(const char* source, int line, const char *file_path, const char *
Assert( dir_type != CF_TYPE_ANY );
// Create the directory if necessary
cf_create_directory( dir_type );
cf_create_directory(dir_type, location_flags);
cf_create_default_path_string( longname, sizeof(longname)-1, dir_type, file_path );
cf_create_default_path_string(longname, sizeof(longname) - 1, dir_type, file_path, false, location_flags);
}
Assert( !(type & CFILE_MEMORY_MAPPED) );
@@ -767,30 +757,29 @@ CFILE *_cfopen(const char* source, int line, const char *file_path, const char *
//================================================
// Search for file on disk, on cdrom, or in a packfile
size_t offset, size;
char copy_file_path[MAX_PATH_LEN]; // FIX change in memory from cf_find_file_location
strcpy_s(copy_file_path, file_path);
const void* file_data = nullptr;
if ( cf_find_file_location( copy_file_path, dir_type, sizeof(longname) - 1, longname, &size, &offset, localize, &file_data ) ) {
auto find_res = cf_find_file_location( copy_file_path, dir_type, localize, location_flags );
if ( find_res.found ) {
// Fount it, now create a cfile out of it
nprintf(("CFileDebug", "Requested file %s found at: %s\n", file_path, longname));
nprintf(("CFileDebug", "Requested file %s found at: %s\n", file_path, find_res.full_name.c_str()));
if ( type & CFILE_MEMORY_MAPPED ) {
// Can't open memory mapped files out of pack or memory files
if ( offset == 0 && file_data != nullptr ) {
if ( find_res.offset == 0 && find_res.data_ptr != nullptr ) {
#if defined _WIN32
HANDLE hFile;
hFile = CreateFile(longname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
hFile = CreateFile(find_res.full_name.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
return cf_open_mapped_fill_cfblock(source, line, hFile, dir_type);
}
#elif defined SCP_UNIX
FILE *fp = fopen( longname, "rb" );
FILE* fp = fopen(find_res.full_name.c_str(), "rb");
if (fp) {
return cf_open_mapped_fill_cfblock(source, line, fp, dir_type);
}
@@ -799,7 +788,8 @@ CFILE *_cfopen(const char* source, int line, const char *file_path, const char *
} else {
// since cfopen_special already has all the code to handle the opening we can just use that here
return _cfopen_special(source, line, longname, mode, size, offset, file_data, dir_type);
return _cfopen_special(source, line, find_res.full_name.c_str(), mode, find_res.size, find_res.offset,
find_res.data_ptr, dir_type);
}
}
@@ -907,7 +897,7 @@ static int cfget_cfile_block()
mprintf(("Out of cfile blocks! Currently opened files:\n"));
dump_opened_files();
Assertion(false, "There are no more free cfile blocks. This means that there are too many files opened by FSO.\n"
UNREACHABLE("There are no more free cfile blocks. This means that there are too many files opened by FSO.\n"
"This is probably caused by a programming or scripting error where a file does not get closed."); // out of free cfile blocks
return -1;
}
@@ -1360,6 +1350,19 @@ void cfread_string_len(char *buf,int n, CFILE *file)
buf[len] = 0;
}
SCP_string cfread_string_len(CFILE *file)
{
int len = cfread_int(file);
SCP_string str;
str.resize(len);
if (len)
cfread(&str[0], len, 1, file);
return str;
}
// equivalent write functions of above read functions follow
int cfwrite_float(float f, CFILE *file)
@@ -1973,3 +1976,33 @@ int cflush(CFILE *cfile)
return result;
}
int cfile_get_path_type(const SCP_string& dir)
{
SCP_string buf = dir;
// Remove trailing slashes; avoid buffer overflow on 1-char strings
while (buf.size() > 0 && (buf[buf.size() - 1] == '\\' || buf[buf.size() - 1] == '/')) {
buf.resize(buf.size() - 1);
}
// Remove leading slashes
while (buf.size() > 0 && (buf[0] == '\\' || buf[0] == '/')) {
buf = buf.substr(1);
}
// Use official DIR_SEPARATOR_CHAR
for (char& c : buf) {
if (c == '\\' || c == '/') {
c = DIR_SEPARATOR_CHAR;
}
}
for (auto& Pathtype : Pathtypes) {
if (Pathtype.path != nullptr && buf == Pathtype.path) {
return Pathtype.index;
}
}
return CF_TYPE_INVALID;
}
+105 -15
View File
@@ -79,9 +79,11 @@ typedef struct {
#define CF_TYPE_SCRIPTS 35
#define CF_TYPE_FICTION 36
#define CF_TYPE_FREDDOCS 37
#define CF_TYPE_INTERFACE_MARKUP 38
#define CF_TYPE_INTERFACE_CSS 39
#define CF_MAX_PATH_TYPES 38 // Can be as high as you'd like //DTP; yeah but beware alot of things uses CF_MAX_PATH_TYPES
#define CF_MAX_PATH_TYPES \
40 // Can be as high as you'd like //DTP; yeah but beware alot of things uses CF_MAX_PATH_TYPES
// TRUE if type is specified and valid
#define CF_TYPE_SPECIFIED(path_type) (((path_type)>CF_TYPE_INVALID) && ((path_type)<CF_MAX_PATH_TYPES))
@@ -95,6 +97,64 @@ typedef struct {
#define CF_SORT_TIME 2
#define CF_SORT_REVERSE 3
/**
* @brief Contains a collection of flags for specifying from where a CFILE should be opened
*
* There are two types of flags. CF_LOCATION_GAME_ROOT and CF_LOCATION_USER_ROOT specify in which basic root directory
* CFile should search for files.
*
* The remaining flags control what type of location may be used for the operation. It's possible to restrict the
* location to the primary mod, the remaining mods or the top-level root directory.
*/
enum CFileLocationFlags {
CF_LOCATION_ROOT_GAME = 1 << 0, //!< The game root location. This is the location of the game data (e.g. FS2 retail)
/**
* @brief The user directories.
*
* If the engine is in portable mode then using this flag exclusively will result in a failure to open files!
*/
CF_LOCATION_ROOT_USER = 1 << 1,
/**
* @brief The memory root
*
* This contains all the built-in files available to the engine.
*/
CF_LOCATION_ROOT_MEMORY = 1 << 2,
/**
* @brief Mask for extracting root type from a location bit field
*/
CF_LOCATION_ROOT_MASK = 0xFFFF,
CF_LOCATION_TYPE_ROOT = 1 << 16, //!< The basic, top-level root location
/**
* @brief The primary mod location.
*
* This is the mod that appears first on the command line. If there are no mods then the root location is considered
* to be the primary mod
*/
CF_LOCATION_TYPE_PRIMARY_MOD = 1 << 17,
/**
* @brief The remaining mods.
*
* If there are no mods on the command line then this might not include any valid location.
*/
CF_LOCATION_TYPE_SECONDARY_MODS = 1 << 18,
/**
* @brief Bitmask for extracting the type from a location bit field
*/
CF_LOCATION_TYPE_MASK = 0xFFFF0000,
/**
* @brief A combination of all flags
*
* This should be used when the default behavior without any location filtering is desired.
*/
CF_LOCATION_ALL = CF_LOCATION_ROOT_MASK | CF_LOCATION_TYPE_MASK
};
#define cfread_fix(file) (fix)cfread_int(file)
#define cfwrite_fix(i,file) cfwrite_int(i,file)
@@ -111,9 +171,6 @@ extern const char *Get_file_list_child;
#define CFILE_ROOT_DIRECTORY_LEN 256
extern char Cfile_root_dir[CFILE_ROOT_DIRECTORY_LEN];
extern char Cfile_user_dir[CFILE_ROOT_DIRECTORY_LEN];
#ifdef SCP_UNIX
extern char Cfile_user_dir_legacy[CFILE_ROOT_DIRECTORY_LEN];
#endif
//================= LOW-LEVEL FUNCTIONS ==================
int cfile_init(const char *exe_dir, const char *cdrom_dir=NULL);
@@ -130,11 +187,10 @@ char *cf_add_ext(const char *filename, const char *ext);
// return CF_TYPE (directory location type) of a CFILE you called cfopen() successfully on.
int cf_get_dir_type(CFILE *cfile);
// Opens the file. If no path is given, use the extension to look into the
// default path. If mode is NULL, delete the file.
CFILE *_cfopen(const char* source_file, int line, const char *filename, const char *mode,
int type = CFILE_NORMAL, int dir_type = CF_TYPE_ANY, bool localize = false);
// default path. If mode is NULL, delete the file.
CFILE* _cfopen(const char* source_file, int line, const char* filename, const char* mode, int type = CFILE_NORMAL,
int dir_type = CF_TYPE_ANY, bool localize = false, uint32_t location_flags = CF_LOCATION_ALL);
#define cfopen(...) _cfopen(LOCATION, __VA_ARGS__) // Pass source location to the function
// like cfopen(), but it accepts a fully qualified path only (ie, the result of a cf_find_file_location() call)
@@ -156,7 +212,7 @@ void cf_set_version( CFILE * cfile, int version );
void cf_set_max_read_len(CFILE *cfile, size_t len);
// Deletes a file. Returns 0 on error, 1 if successful
int cf_delete(const char *filename, int dir_type);
int cf_delete(const char *filename, int dir_type, uint32_t location_flags = CF_LOCATION_ALL);
// Same as _access function to read a file's access bits
int cf_access(const char *filename, int dir_type, int mode);
@@ -289,6 +345,13 @@ void cfread_string(char *buf,int n, CFILE *file);
*/
void cfread_string_len(char *buf,int n, CFILE *file);
/**
* @brief Read a string from the file where the length is stored in the file
* @param file The file to read the string from
* @return The string that was read
*/
SCP_string cfread_string_len(CFILE *file);
// functions for writing cfiles
int cfwrite_char(char c, CFILE *file);
int cfwrite_float(float f, CFILE *file);
@@ -311,12 +374,26 @@ int cfwrite_string(const char *buf, CFILE *file);
*/
int cfwrite_string_len(const char *buf, CFILE *file);
int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *filter, int sort = CF_SORT_NONE, SCP_vector<file_list_info> *info = NULL );
int cf_get_file_list( int max, char **list, int type, const char *filter, int sort = CF_SORT_NONE, file_list_info *info = NULL );
int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char **list, int type, const char *filter, int sort = CF_SORT_NONE, file_list_info *info = NULL );
int cf_get_file_list(SCP_vector<SCP_string>& list, int pathtype, const char* filter, int sort = CF_SORT_NONE,
SCP_vector<file_list_info>* info = nullptr, uint32_t location_flags = CF_LOCATION_ALL);
int cf_get_file_list(int max, char** list, int type, const char* filter, int sort = CF_SORT_NONE,
file_list_info* info = nullptr, uint32_t location_flags = CF_LOCATION_ALL);
int cf_get_file_list_preallocated(int max, char arr[][MAX_FILENAME_LEN], char** list, int type, const char* filter,
int sort = CF_SORT_NONE, file_list_info* info = nullptr,
uint32_t location_flags = CF_LOCATION_ALL);
void cf_sort_filenames( int n, char **list, int sort, file_list_info *info = NULL );
void cf_sort_filenames( SCP_vector<SCP_string> &list, int sort, SCP_vector<file_list_info> *info = NULL );
struct CFileLocation {
bool found = false;
SCP_string full_name;
size_t size = 0;
size_t offset = 0;
const void* data_ptr = nullptr;
explicit CFileLocation(bool found_in = false) : found(found_in) {}
};
// Searches for a file. Follows all rules and precedence and searches
// CD's and pack files.
// Input: filespace - Filename & extension
@@ -326,7 +403,17 @@ void cf_sort_filenames( SCP_vector<SCP_string> &list, int sort, SCP_vector<file_
// size - File size
// offset - Offset into pack file. 0 if not a packfile.
// Returns: If not found returns 0.
int cf_find_file_location( const char *filespec, int pathtype, int max_out, char *pack_filename, size_t *size, size_t *offset, bool localize = false, const void** data_out = nullptr);
CFileLocation cf_find_file_location(const char* filespec, int pathtype, bool localize = false,
uint32_t location_flags = CF_LOCATION_ALL);
struct CFileLocationExt : public CFileLocation {
int extension_index = -1;
explicit CFileLocationExt(int extension_index_in = -1)
: CFileLocation(extension_index_in >= 0), extension_index(extension_index_in)
{
}
};
// Searches for a file. Follows all rules and precedence and searches
// CD's and pack files. Searches all locations in order for first filename using ext filter list.
@@ -340,7 +427,8 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
// offset - Offset into pack file. 0 if not a packfile.
// Returns: If not found returns -1, else returns offset into ext_list.
// (NOTE: This function is exponentially slow, so don't use it unless truely needed!!)
int cf_find_file_location_ext(const char *filename, const int ext_num, const char **ext_list, int pathtype, int max_out = 0, char *pack_filename = NULL, size_t *size = NULL, size_t *offset = NULL, bool localize = false, const void** data_out = nullptr);
CFileLocationExt cf_find_file_location_ext(const char* filename, const int ext_num, const char** ext_list, int pathtype,
bool localize = false);
// Functions to change directories
int cfile_chdir(const char *dir);
@@ -355,6 +443,8 @@ int cfile_push_chdir(int type);
// restore directory on top of the stack
int cfile_pop_dir();
int cfile_get_path_type(const SCP_string& dir);
namespace cfile
{
// exceptions and other errors
+263 -209
View File
@@ -48,9 +48,6 @@ enum CfileRootType {
CF_ROOTTYPE_MEMORY = 2,
};
// for a defined and specifically set location to get/send pilot/campaign files
SCP_string Pilot_file_path;
// Created by:
// specifying hard drive tree
// searching for pack files on hard drive // Found by searching all known paths
@@ -59,6 +56,7 @@ SCP_string Pilot_file_path;
typedef struct cf_root {
char path[CF_MAX_PATHNAME_LENGTH]; // Contains something like c:\projects\freespace or c:\projects\freespace\freespace.vp
int roottype; // CF_ROOTTYPE_PATH = Path, CF_ROOTTYPE_PACK =Pack file, CF_ROOTTYPE_MEMORY=In memory
uint32_t location_flags;
} cf_root;
// convenient type for sorting (see cf_build_pack_list())
@@ -347,9 +345,9 @@ void cf_build_pack_list( cf_root *root )
std::sort(temp_roots_sort, temp_roots_sort + temp_root_count, cf_packfile_sort_func);
// now insert them all into the real root list properly
cf_root *new_root;
for (i = 0; i < temp_root_count; i++) {
new_root = cf_create_root();
auto new_root = cf_create_root();
new_root->location_flags = root->location_flags;
strcpy_s( new_root->path, root->path );
#ifndef NDEBUG
@@ -378,10 +376,11 @@ static char normalize_directory_separator(char in)
return in;
}
static void cf_add_mod_roots(const char* rootDirectory)
static void cf_add_mod_roots(const char* rootDirectory, uint32_t basic_location)
{
if (Cmdline_mod)
{
bool primary = true;
for (const char* cur_pos=Cmdline_mod; strlen(cur_pos) != 0; cur_pos+= (strlen(cur_pos)+1))
{
SCP_stringstream ss;
@@ -405,9 +404,16 @@ static void cf_add_mod_roots(const char* rootDirectory)
cf_root* root = cf_create_root();
strncpy(root->path, rootPath.c_str(), CF_MAX_PATHNAME_LENGTH-1);
if (primary) {
root->location_flags = basic_location | CF_LOCATION_TYPE_PRIMARY_MOD;
} else {
root->location_flags = basic_location | CF_LOCATION_TYPE_SECONDARY_MODS;
}
root->roottype = CF_ROOTTYPE_PATH;
cf_build_pack_list(root);
primary = false;
}
}
}
@@ -425,10 +431,16 @@ void cf_build_root_list(const char *cdrom_dir)
#ifdef WIN32
// Nothing to do here, Windows uses the current directory as the base
#else
cf_add_mod_roots(Cfile_user_dir_legacy);
cf_add_mod_roots(os_get_legacy_user_dir(), CF_LOCATION_ROOT_USER);
root = cf_create_root();
strncpy(root->path, Cfile_user_dir_legacy, CF_MAX_PATHNAME_LENGTH - 1);
strncpy(root->path, os_get_legacy_user_dir(), CF_MAX_PATHNAME_LENGTH - 1);
root->location_flags |= CF_LOCATION_ROOT_USER | CF_LOCATION_TYPE_ROOT;
if (Cmdline_mod == nullptr || strlen(Cmdline_mod) <= 0) {
// If there are no mods then the root is the primary mod
root->location_flags |= CF_LOCATION_TYPE_PRIMARY_MOD;
}
// do we already have a slash? as in the case of a root directory install
if ((strlen(root->path) < (CF_MAX_PATHNAME_LENGTH - 1)) && (root->path[strlen(root->path) - 1] != DIR_SEPARATOR_CHAR)) {
@@ -436,10 +448,6 @@ void cf_build_root_list(const char *cdrom_dir)
}
root->roottype = CF_ROOTTYPE_PATH;
// If it wasn't set before, set the pilot path
if (Pilot_file_path.empty())
Pilot_file_path = root->path;
// Next, check any VP files under the current directory.
cf_build_pack_list(root);
#endif
@@ -449,13 +457,19 @@ void cf_build_root_list(const char *cdrom_dir)
{
// =========================================================================
// now look for mods under the users HOME directory to use before system ones
cf_add_mod_roots(Cfile_user_dir);
cf_add_mod_roots(Cfile_user_dir, CF_LOCATION_ROOT_USER);
// =========================================================================
// =========================================================================
// set users HOME directory as default for loading and saving files
root = cf_create_root();
strncpy(root->path, Cfile_user_dir, CF_MAX_PATHNAME_LENGTH - 1);
strcpy_s(root->path, Cfile_user_dir);
root->location_flags |= CF_LOCATION_ROOT_USER | CF_LOCATION_TYPE_ROOT;
if (Cmdline_mod == nullptr || strlen(Cmdline_mod) <= 0) {
// If there are no mods then the root is the primary mod
root->location_flags |= CF_LOCATION_TYPE_PRIMARY_MOD;
}
// do we already have a slash? as in the case of a root directory install
if ((strlen(root->path) < (CF_MAX_PATHNAME_LENGTH - 1)) && (root->path[strlen(root->path) - 1] != DIR_SEPARATOR_CHAR)) {
@@ -463,10 +477,6 @@ void cf_build_root_list(const char *cdrom_dir)
}
root->roottype = CF_ROOTTYPE_PATH;
// set the default player location to here
if (Pilot_file_path.empty())
Pilot_file_path = root->path;
// Next, check any VP files under the current directory.
cf_build_pack_list(root);
// =========================================================================
@@ -477,11 +487,17 @@ void cf_build_root_list(const char *cdrom_dir)
if ( !_getcwd(working_directory, CF_MAX_PATHNAME_LENGTH ) ) {
Error(LOCATION, "Can't get current working directory -- %d", errno );
}
cf_add_mod_roots(working_directory);
cf_add_mod_roots(working_directory, CF_LOCATION_ROOT_GAME);
root = cf_create_root();
root->location_flags |= CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT;
if (Cmdline_mod == nullptr || strlen(Cmdline_mod) <= 0) {
// If there are no mods then the root is the primary mod
root->location_flags |= CF_LOCATION_TYPE_PRIMARY_MOD;
}
strcpy_s(root->path, working_directory);
size_t path_len = strlen(root->path);
@@ -493,10 +509,6 @@ void cf_build_root_list(const char *cdrom_dir)
root->roottype = CF_ROOTTYPE_PATH;
// If the path wasn't set before use the working directory
if ( Pilot_file_path.empty() )
Pilot_file_path = root->path;
//======================================================
// Next, check any VP files under the current directory.
cf_build_pack_list(root);
@@ -517,6 +529,7 @@ void cf_build_root_list(const char *cdrom_dir)
// The final root is the in-memory root
root = cf_create_root();
root->location_flags = CF_LOCATION_ROOT_MEMORY | CF_LOCATION_TYPE_ROOT;
memset(root->path, 0, sizeof(root->path));
root->roottype = CF_ROOTTYPE_MEMORY;
@@ -977,15 +990,12 @@ void cf_free_secondary_filelist()
*
* @param filespec Filename & extension
* @param pathtype See CF_TYPE_ defines in CFILE.H
* @param max_out Maximum string length that should be stuffed into pack_filename
* @param pack_filename OUTPUT: Absolute path and filename of this file. Could be a packfile or the actual file.
* @param size OUTPUT: File size
* @param offset OUTPUT: Offset into pack file. 0 if not a packfile.
* @param localize Undertake localization
* @param location_flags Specifies where to search for the specified flag
*
* @return If not found returns 0.
* @return A structure which describes the found file
*/
int cf_find_file_location( const char *filespec, int pathtype, int max_out, char *pack_filename, size_t *size, size_t *offset, bool localize, const void** data_out )
CFileLocation cf_find_file_location(const char* filespec, int pathtype, bool localize, uint32_t location_flags)
{
int i;
uint ui;
@@ -993,7 +1003,6 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
char longname[MAX_PATH_LEN];
Assert( (filespec != NULL) && (strlen(filespec) > 0) ); //-V805
Assert( (pack_filename == NULL) || (max_out > 1) );
// see if we have something other than just a filename
// our current rules say that any file that specifies a direct
@@ -1009,16 +1018,15 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
#endif
FILE *fp = fopen(filespec, "rb" );
if (fp) {
if ( size ) *size = filelength(fileno(fp));
if ( offset ) *offset = 0;
if ( pack_filename ) {
strncpy( pack_filename, filespec, max_out );
}
CFileLocation res(true);
res.size = static_cast<size_t>(filelength(fileno(fp)));
res.offset = 0;
res.full_name = filespec;
fclose(fp);
return 1;
return res;
}
return 0; // If they give a full path, fail if not found.
return CFileLocation(); // If they give a full path, fail if not found.
}
// Search the hard drive for files first.
@@ -1057,43 +1065,39 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
}
if (cfs_slow_search) {
cf_create_default_path_string( longname, sizeof(longname)-1, search_order[ui], filespec, localize );
cf_create_default_path_string(longname, sizeof(longname) - 1, search_order[ui], filespec, localize,
location_flags);
#if defined _WIN32
_finddata_t findstruct;
intptr_t findhandle = _findfirst(longname, &findstruct);
if (findhandle != -1) {
if (size)
*size = findstruct.size;
CFileLocation res;
res.found = true;
res.size = static_cast<size_t>(findstruct.size);
_findclose(findhandle);
if (offset)
*offset = 0;
res.offset = 0;
res.full_name = longname;
if (pack_filename)
strncpy( pack_filename, longname, max_out );
return 1;
return res;
}
#endif
{
FILE *fp = fopen(longname, "rb" );
if (fp) {
if (size)
*size = filelength( fileno(fp) );
CFileLocation res(true);
res.size = static_cast<size_t>(filelength( fileno(fp) ));
fclose(fp);
if (offset)
*offset = 0;
res.offset = 0;
res.full_name = longname;
if (pack_filename)
strncpy(pack_filename, longname, max_out);
return 1;
return res;
}
}
}
@@ -1107,6 +1111,15 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
if ( (pathtype != CF_TYPE_ANY) && (pathtype != f->pathtype_index) )
continue;
if (location_flags != CF_LOCATION_ALL) {
// If a location flag was specified we need to check if the root of this file satisfies the request
auto root = cf_get_root(f->root_index);
if (!cf_check_location_flags(root->location_flags, location_flags)) {
// Root does not satisfy location flags
continue;
}
}
if (localize) {
// create localized filespec
@@ -1114,70 +1127,58 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
if ( lcl_add_dir_to_path_with_filename(longname, MAX_PATH_LEN - 1) ) {
if ( !stricmp(longname, f->name_ext) ) {
if (size)
*size = f->size;
CFileLocation res(true);
res.size = static_cast<size_t>(f->size);
res.offset = (size_t)f->pack_offset;
res.data_ptr = f->data;
if (offset)
*offset = (size_t)f->pack_offset;
if (f->data != nullptr) {
// This is an in-memory file so we just copy the pathtype name + file name
res.full_name = Pathtypes[f->pathtype_index].path;
res.full_name += DIR_SEPARATOR_STR;
res.full_name += f->name_ext;
} else if (f->pack_offset < 1) {
// This is a real file, return the actual file path
res.full_name = f->real_name;
} else {
// File is in a pack file
cf_root *r = cf_get_root(f->root_index);
if (data_out)
*data_out = f->data;
if (pack_filename) {
if (f->data != nullptr) {
// This is an in-memory file so we just copy the pathtype name + file name
strncpy(pack_filename, Pathtypes[f->pathtype_index].path, max_out);
strncat(pack_filename, DIR_SEPARATOR_STR, max_out);
strncat(pack_filename, f->name_ext, max_out);
} else if (f->pack_offset < 1) {
// This is a real file, return the actual file path
strncpy( pack_filename, f->real_name, max_out );
} else {
// File is in a pack file
cf_root *r = cf_get_root(f->root_index);
strncpy( pack_filename, r->path, max_out );
}
res.full_name = r->path;
}
return 1;
return res;
}
}
}
// file either not localized or localized version not found
if ( !stricmp(filespec, f->name_ext) ) {
if (size)
*size = f->size;
CFileLocation res(true);
res.size = static_cast<size_t>(f->size);
res.offset = (size_t)f->pack_offset;
res.data_ptr = f->data;
if (offset)
*offset = (size_t)f->pack_offset;
if (f->data != nullptr) {
// This is an in-memory file so we just copy the pathtype name + file name
res.full_name = Pathtypes[f->pathtype_index].path;
res.full_name += DIR_SEPARATOR_STR;
res.full_name += f->name_ext;
} else if (f->pack_offset < 1) {
// This is a real file, return the actual file path
res.full_name = f->real_name;
} else {
// File is in a pack file
cf_root *r = cf_get_root(f->root_index);
if (data_out)
*data_out = f->data;
if (pack_filename) {
if (f->data != nullptr) {
// This is an in-memory file so we just copy the pathtype name + file name
strncpy(pack_filename, Pathtypes[f->pathtype_index].path, max_out);
strncat(pack_filename, DIR_SEPARATOR_STR, max_out);
strncat(pack_filename, f->name_ext, max_out);
} else if (f->pack_offset < 1) {
// This is a real file, return the actual file path
strncpy( pack_filename, f->real_name, max_out );
} else {
// File is in a pack file
cf_root *r = cf_get_root(f->root_index);
strncpy( pack_filename, r->path, max_out );
}
res.full_name = r->path;
}
return 1;
return res;
}
}
return 0;
return CFileLocation();
}
// -- from parselo.cpp --
@@ -1194,14 +1195,11 @@ extern char *stristr(char *str, const char *substr);
* @param ext_list Extension filter list
* @param pathtype See CF_TYPE_ defines in CFILE.H
* @param max_out Maximum string length that should be stuffed into pack_filename
* @param pack_filename OUTPUT: Absolute path and filename of this file. Could be a packfile or the actual file.
* @param size OUTPUT: File size
* @param offset OUTPUT: Offset into pack file. 0 if not a packfile.
* @param localize Undertake localization
*
* @return If not found returns -1, else returns offset into ext_list.
* @return A structure containing information about the found file
*/
int cf_find_file_location_ext( const char *filename, const int ext_num, const char **ext_list, int pathtype, int max_out, char *pack_filename, size_t *size, size_t *offset, bool localize, const void** data_out)
CFileLocationExt cf_find_file_location_ext( const char *filename, const int ext_num, const char **ext_list, int pathtype, bool localize)
{
int cur_ext, i;
uint ui;
@@ -1213,7 +1211,6 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
Assert( (filename != NULL) && (strlen(filename) < MAX_FILENAME_LEN) );
Assert( (ext_list != NULL) && (ext_num > 1) ); // if we are searching for just one ext
// then this is the wrong function to use
Assert( (pack_filename == NULL) || (max_out > 1) );
// if we have a full path already then fail. this function if for searching via filter only!
@@ -1223,7 +1220,7 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
if ( strpbrk(filename,"/\\:") ) { // do we have a full path already?
#endif
Int3();
return 0;
return CFileLocationExt();
}
// Search the hard drive for files first.
@@ -1281,44 +1278,35 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
#if defined _WIN32
_finddata_t findstruct;
intptr_t findhandle = _findfirst(longname, &findstruct);
if (findhandle != -1) {
if (size)
*size = findstruct.size;
if (data_out)
*data_out = nullptr;
CFileLocationExt res(cur_ext);
res.found = true;
res.size = static_cast<size_t>(findstruct.size);
_findclose(findhandle);
if (offset)
*offset = 0;
res.offset = 0;
res.full_name = longname;
if (pack_filename)
strncpy( pack_filename, longname, max_out );
return cur_ext;
return res;
}
#endif
{
FILE *fp = fopen(longname, "rb" );
if (fp) {
if (size)
*size = filelength( fileno(fp) );
if (data_out)
*data_out = nullptr;
CFileLocationExt res(cur_ext);
res.found = true;
res.size = static_cast<size_t>(filelength( fileno(fp) ));
fclose(fp);
if (offset)
*offset = 0;
res.offset = 0;
res.full_name = longname;
if (pack_filename)
strncpy(pack_filename, longname, max_out);
return cur_ext;
return res;
}
}
}
@@ -1403,76 +1391,62 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
if ( lcl_add_dir_to_path_with_filename(longname, MAX_PATH_LEN - 1) ) {
if ( !stricmp(longname, f->name_ext) ) {
if (size)
*size = f->size;
CFileLocationExt res(cur_ext);
res.found = true;
res.size = static_cast<size_t>(f->size);
res.offset = (size_t)f->pack_offset;
res.data_ptr = f->data;
if (offset)
*offset = f->pack_offset;
if (f->data != nullptr) {
// This is an in-memory file so we just copy the pathtype name + file name
res.full_name = Pathtypes[f->pathtype_index].path;
res.full_name += DIR_SEPARATOR_STR;
res.full_name += f->name_ext;
} else if (f->pack_offset < 1) {
// This is a real file, return the actual file path
res.full_name = f->real_name;
} else {
// File is in a pack file
cf_root *r = cf_get_root(f->root_index);
if (data_out)
*data_out = f->data;
if (pack_filename) {
if (f->data != nullptr) {
// This is an in-memory file so we just copy the pathtype name + file name
strncpy(pack_filename, Pathtypes[f->pathtype_index].path, max_out);
strncat(pack_filename, DIR_SEPARATOR_STR, max_out);
strncat(pack_filename, f->name_ext, max_out);
}
else if (f->pack_offset < 1) {
// This is a real file, return the actual file path
strncpy(pack_filename, f->real_name, max_out);
}
else {
// File is in a pack file
cf_root *r = cf_get_root(f->root_index);
strncpy(pack_filename, r->path, max_out);
}
res.full_name = r->path;
}
// found it, so cleanup and return
file_list_index.clear();
return cur_ext;
return res;
}
}
}
// file either not localized or localized version not found
if ( !stricmp(filespec, f->name_ext) ) {
if (size)
*size = f->size;
CFileLocationExt res(cur_ext);
res.found = true;
res.size = static_cast<size_t>(f->size);
res.offset = (size_t)f->pack_offset;
res.data_ptr = f->data;
if (offset)
*offset = f->pack_offset;
if (f->data != nullptr) {
// This is an in-memory file so we just copy the pathtype name + file name
res.full_name = Pathtypes[f->pathtype_index].path;
res.full_name += DIR_SEPARATOR_STR;
res.full_name += f->name_ext;
} else if (f->pack_offset < 1) {
// This is a real file, return the actual file path
res.full_name = f->real_name;
} else {
// File is in a pack file
cf_root *r = cf_get_root(f->root_index);
if (data_out)
*data_out = f->data;
if (pack_filename) {
if (f->data != nullptr) {
// This is an in-memory file so we just copy the pathtype name + file name
strncpy(pack_filename, Pathtypes[f->pathtype_index].path, max_out);
strncat(pack_filename, DIR_SEPARATOR_STR, max_out);
strncat(pack_filename, f->name_ext, max_out);
}
else if (f->pack_offset < 1) {
// This is a real file, return the actual file path
strncpy(pack_filename, f->real_name, max_out);
}
else {
// File is in a pack file
cf_root *r = cf_get_root(f->root_index);
strncpy(pack_filename, r->path, max_out);
}
res.full_name = r->path;
}
// found it, so cleanup and return
file_list_index.clear();
return cur_ext;
return res;
}
// ok, we're still here, so strip off the extension again in order to
@@ -1483,7 +1457,7 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
}
}
return -1;
return CFileLocationExt();
}
@@ -1582,7 +1556,8 @@ static int cf_file_already_in_list( SCP_vector<SCP_string> &list, const char *fi
// This one has a 'type', which is a CF_TYPE_* value. Because this specifies the directory
// location, 'filter' only needs to be the filter itself, with no path information.
// See above descriptions of cf_get_file_list() for more information about how it all works.
int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *filter, int sort, SCP_vector<file_list_info> *info )
int cf_get_file_list(SCP_vector<SCP_string>& list, int pathtype, const char* filter, int sort,
SCP_vector<file_list_info>* info, uint32_t location_flags)
{
char *ptr;
uint i;
@@ -1610,7 +1585,8 @@ int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *fi
}
#if defined _WIN32
cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, (char*)Get_file_list_child );
cf_create_default_path_string(filespec, sizeof(filespec) - 1, pathtype, (char*)Get_file_list_child, false,
location_flags);
strcat_s(filespec, DIR_SEPARATOR_STR);
strcat_s(filespec, filter);
@@ -1650,7 +1626,8 @@ int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *fi
}
#elif defined SCP_UNIX
cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, (char*)Get_file_list_child );
cf_create_default_path_string(filespec, sizeof(filespec) - 1, pathtype, (char*)Get_file_list_child, false,
location_flags);
DIR *dirp;
struct dirent *dir;
@@ -1718,6 +1695,16 @@ int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *fi
continue;
}
if (location_flags != CF_LOCATION_ALL) {
// If a location flag was specified we need to check if the root of this file satisfies the request
auto root = cf_get_root(f->root_index);
if (!cf_check_location_flags(root->location_flags, location_flags)) {
// Root does not satisfy location flags
continue;
}
}
if ( !cf_matches_spec( filter,f->name_ext)) {
continue;
}
@@ -1795,7 +1782,8 @@ int cf_file_already_in_list( int num_files, char **list, const char *filename )
// This one has a 'type', which is a CF_TYPE_* value. Because this specifies the directory
// location, 'filter' only needs to be the filter itself, with no path information.
// See above descriptions of cf_get_file_list() for more information about how it all works.
int cf_get_file_list( int max, char **list, int pathtype, const char *filter, int sort, file_list_info *info )
int cf_get_file_list(int max, char** list, int pathtype, const char* filter, int sort, file_list_info* info,
uint32_t location_flags)
{
char *ptr;
uint i;
@@ -1818,7 +1806,7 @@ int cf_get_file_list( int max, char **list, int pathtype, const char *filter, in
char filespec[MAX_PATH_LEN];
#if defined _WIN32
cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, filter );
cf_create_default_path_string(filespec, sizeof(filespec) - 1, pathtype, filter, false, location_flags);
_finddata_t find;
intptr_t find_handle;
@@ -1859,7 +1847,7 @@ int cf_get_file_list( int max, char **list, int pathtype, const char *filter, in
}
#elif defined SCP_UNIX
cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, NULL );
cf_create_default_path_string(filespec, sizeof(filespec) - 1, pathtype, nullptr, false, location_flags);
DIR *dirp;
struct dirent *dir;
@@ -1932,6 +1920,16 @@ int cf_get_file_list( int max, char **list, int pathtype, const char *filter, in
continue;
}
if (location_flags != CF_LOCATION_ALL) {
// If a location flag was specified we need to check if the root of this file satisfies the request
auto root = cf_get_root(f->root_index);
if (!cf_check_location_flags(root->location_flags, location_flags)) {
// Root does not satisfy location flags
continue;
}
}
if (num_files >= max)
break;
@@ -2015,7 +2013,8 @@ int cf_file_already_in_list_preallocated( int num_files, char arr[][MAX_FILENAME
// This one has a 'type', which is a CF_TYPE_* value. Because this specifies the directory
// location, 'filter' only needs to be the filter itself, with no path information.
// See above descriptions of cf_get_file_list() for more information about how it all works.
int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char **list, int pathtype, const char *filter, int sort, file_list_info *info )
int cf_get_file_list_preallocated(int max, char arr[][MAX_FILENAME_LEN], char** list, int pathtype, const char* filter,
int sort, file_list_info* info, uint32_t location_flags)
{
int num_files = 0, own_flag = 0;
@@ -2044,7 +2043,7 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
// Search the default directories
#if defined _WIN32
cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, filter );
cf_create_default_path_string(filespec, sizeof(filespec) - 1, pathtype, filter, false, location_flags);
intptr_t find_handle;
_finddata_t find;
@@ -2085,7 +2084,7 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
}
#elif defined SCP_UNIX
cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, NULL );
cf_create_default_path_string(filespec, sizeof(filespec) - 1, pathtype, nullptr, false, location_flags);
DIR *dirp;
struct dirent *dir;
@@ -2121,7 +2120,7 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
if ( !Get_file_list_filter || (*Get_file_list_filter)(dir->d_name) ) {
strncpy(arr[num_files], dir->d_name, MAX_FILENAME_LEN - 1 );
strcpy_s(arr[num_files], dir->d_name );
char *ptr = strrchr(arr[num_files], '.');
if ( ptr ) {
*ptr = 0;
@@ -2156,6 +2155,16 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
continue;
}
if (location_flags != CF_LOCATION_ALL) {
// If a location flag was specified we need to check if the root of this file satisfies the request
auto root = cf_get_root(f->root_index);
if (!cf_check_location_flags(root->location_flags, location_flags)) {
// Root does not satisfy location flags
continue;
}
}
if (num_files >= max)
break;
@@ -2222,7 +2231,8 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
// filename - optional, if set, tacks the filename onto end of path.
// Output: path - Fully qualified pathname.
//Returns 0 if the result would be too long (invalid result)
int cf_create_default_path_string(char *path, uint path_max, int pathtype, const char *filename, bool localize )
int cf_create_default_path_string(char* path, uint path_max, int pathtype, const char* filename, bool localize,
uint32_t location_flags)
{
#ifdef SCP_UNIX
if ( filename && strpbrk(filename,"/") ) {
@@ -2233,7 +2243,22 @@ int cf_create_default_path_string(char *path, uint path_max, int pathtype, const
strncpy( path, filename, path_max );
} else {
cf_root *root = cf_get_root(0);
cf_root* root = nullptr;
for (auto i = 0; i < Num_roots; ++i) {
auto current_root = cf_get_root(i);
if (current_root->roottype != CF_ROOTTYPE_PATH) {
// We want a "real" path here so only path roots are valid
continue;
}
if (cf_check_location_flags(current_root->location_flags, location_flags)) {
// We found a valid root
root = current_root;
break;
}
}
if (!root) {
Assert( filename != NULL );
@@ -2243,12 +2268,7 @@ int cf_create_default_path_string(char *path, uint path_max, int pathtype, const
Assert(CF_TYPE_SPECIFIED(pathtype));
// force a specific directory to search for player files
if ( (pathtype == CF_TYPE_PLAYERS) || (pathtype == CF_TYPE_SINGLE_PLAYERS) || (pathtype == CF_TYPE_MULTI_PLAYERS) ) {
strncpy(path, Pilot_file_path.c_str(), path_max);
} else {
strncpy(path, root->path, path_max);
}
strncpy(path, root->path, path_max);
strcat_s(path, path_max, Pathtypes[pathtype].path);
@@ -2294,7 +2314,8 @@ int cf_create_default_path_string(char *path, uint path_max, int pathtype, const
// filename - optional, if set, tacks the filename onto end of path.
// Output: path - Fully qualified pathname.
//Returns 0 if the result would be too long (invalid result)
int cf_create_default_path_string( SCP_string &path, int pathtype, const char *filename, bool /*localize*/ )
int cf_create_default_path_string(SCP_string& path, int pathtype, const char* filename, bool /*localize*/,
uint32_t location_flags)
{
#ifdef SCP_UNIX
if ( filename && strpbrk(filename,"/") ) {
@@ -2305,7 +2326,22 @@ int cf_create_default_path_string( SCP_string &path, int pathtype, const char *f
path.assign(filename);
} else {
cf_root *root = cf_get_root(0);
cf_root* root = nullptr;
for (auto i = 0; i < Num_roots; ++i) {
auto current_root = cf_get_root(i);
if (current_root->roottype != CF_ROOTTYPE_PATH) {
// We want a "real" path here so only path roots are valid
continue;
}
if (cf_check_location_flags(current_root->location_flags, location_flags)) {
// We found a valid root
root = current_root;
break;
}
}
if (!root) {
Assert( filename != NULL );
@@ -2316,12 +2352,7 @@ int cf_create_default_path_string( SCP_string &path, int pathtype, const char *f
Assert(CF_TYPE_SPECIFIED(pathtype));
std::ostringstream s_path;
// force a specific directory to search for player files
if ( (pathtype == CF_TYPE_PLAYERS) || (pathtype == CF_TYPE_SINGLE_PLAYERS) || (pathtype == CF_TYPE_MULTI_PLAYERS) ) {
s_path << Pilot_file_path;
} else {
s_path << root->path;
}
s_path << root->path;
s_path << Pathtypes[pathtype].path;
@@ -2386,3 +2417,26 @@ void cfile_spew_pack_file_crcs()
fclose(out);
}
bool cf_check_location_flags(uint32_t check_flags, uint32_t desired_flags)
{
Assertion((check_flags & CF_LOCATION_ROOT_MASK) != 0, "check_flags must have a valid root value");
Assertion((check_flags & CF_LOCATION_TYPE_MASK) != 0, "check_flags must have a valid type value");
auto check_root = check_flags & CF_LOCATION_ROOT_MASK;
auto desired_root_flags = desired_flags & CF_LOCATION_ROOT_MASK;
// If the root part is not set then assume that every root matches
if (desired_root_flags != 0 && (check_root & desired_root_flags) == 0) {
return false;
}
auto check_type = check_flags & CF_LOCATION_TYPE_MASK;
auto desired_type_flags = desired_flags & CF_LOCATION_TYPE_MASK;
if (desired_type_flags != 0 && (check_type & desired_type_flags) == 0) {
return false;
}
return true;
}
+6 -2
View File
@@ -29,6 +29,8 @@ typedef struct cf_pathtype {
// During cfile_init, verify that Pathtypes[n].index == n for each item
extern cf_pathtype Pathtypes[CF_MAX_PATH_TYPES];
bool cf_check_location_flags(uint32_t check_flags, uint32_t desired_flags);
// Returns the default storage path for files given a
// particular pathtype. In other words, the path to
// the unpacked, non-cd'd, stored on hard drive path.
@@ -39,7 +41,9 @@ extern cf_pathtype Pathtypes[CF_MAX_PATH_TYPES];
// filename - optional, if set, tacks the filename onto end of path.
// Output: path - Fully qualified pathname.
//Returns 0 if result would be too long (invalid result)
int cf_create_default_path_string( char *path, uint path_max, int pathtype, const char *filename=NULL, bool localize = false);
int cf_create_default_path_string( SCP_string &path, int pathtype, const char *filename=NULL, bool localize = false );
int cf_create_default_path_string(char* path, uint path_max, int pathtype, const char* filename = nullptr,
bool localize = false, uint32_t location_flags = CF_LOCATION_ALL);
int cf_create_default_path_string(SCP_string& path, int pathtype, const char* filename = nullptr, bool localize = false,
uint32_t location_flags = CF_LOCATION_ALL);
#endif //_CFILESYSTEM_H
+10 -16
View File
@@ -173,7 +173,6 @@ Flag exe_params[] =
{ "-no_deferred", "Disable Deferred Lighting", true, EASY_DEFAULT_MEM, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_deferred"},
{ "-enable_shadows", "Enable Shadows", true, EASY_MEM_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_shadows"},
{ "-no_vsync", "Disable vertical sync", true, 0, EASY_DEFAULT, "Game Speed", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_vsync", },
{ "-cache_bitmaps", "Cache bitmaps between missions", true, 0, EASY_DEFAULT_MEM, "Game Speed", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-cache_bitmaps", },
{ "-dualscanlines", "Add another pair of scanning lines", true, 0, EASY_DEFAULT, "HUD", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-dualscanlines", },
{ "-targetinfo", "Enable info next to target", true, 0, EASY_DEFAULT, "HUD", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-targetinfo", },
@@ -233,7 +232,6 @@ Flag exe_params[] =
{ "-fullscreen_window", "Run in fullscreen window", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fullscreen_window", },
{ "-stats", "Show statistics", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-stats", },
{ "-coords", "Show coordinates", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-coords", },
{ "-show_mem_usage", "Show memory usage", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-show_mem_usage", },
{ "-pofspew", "Generate all ibx files immediately", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-pofspew", },
{ "-tablecrcs", "Dump table CRCs for multi validation", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-tablecrcs", },
{ "-missioncrcs", "Dump mission CRCs for multi validation", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-missioncrcs", },
@@ -248,7 +246,6 @@ Flag exe_params[] =
{ "-no_unfocused_pause","Don't pause if the window isn't focused", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_unfocused_pause", },
{ "-benchmark_mode", "Puts the game into benchmark mode", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-benchmark_mode", },
{ "-noninteractive", "Disables interactive dialogs", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noninteractive", },
{ "-json_pilot", "Dump pilot files in JSON format", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-json_pilot", },
{ "-json_profiling", "Generate JSON profiling output", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-json_profiling", },
{ "-profile_frame_time","Profile engine subsystems", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-profile_frame_timings", },
{ "-debug_window", "Enable the debug window", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-debug_window", },
@@ -363,11 +360,9 @@ int Cmdline_no_deferred_lighting = 0;
int Cmdline_aniso_level = 0;
// Game Speed related
cmdline_parm cache_bitmaps_arg("-cache_bitmaps", NULL, AT_NONE); // Cmdline_cache_bitmaps
cmdline_parm no_fpscap("-no_fps_capping", "Don't limit frames-per-second", AT_NONE); // Cmdline_NoFPSCap
cmdline_parm no_vsync_arg("-no_vsync", NULL, AT_NONE); // Cmdline_no_vsync
int Cmdline_cache_bitmaps = 0; // caching of bitmaps between missions (faster loads, can hit swap on reload with <512 Meg RAM though) - taylor
int Cmdline_NoFPSCap = 0; // Disable FPS capping - kazan
int Cmdline_no_vsync = 0;
@@ -493,7 +488,6 @@ cmdline_parm frame_profile_write_file("-profile_write_file", NULL, AT_NONE); //
cmdline_parm no_unfocused_pause_arg("-no_unfocused_pause", NULL, AT_NONE); //Cmdline_no_unfocus_pause
cmdline_parm benchmark_mode_arg("-benchmark_mode", NULL, AT_NONE); //Cmdline_benchmark_mode
cmdline_parm noninteractive_arg("-noninteractive", NULL, AT_NONE); //Cmdline_noninteractive
cmdline_parm json_pilot("-json_pilot", NULL, AT_NONE); //Cmdline_json_pilot
cmdline_parm json_profiling("-json_profiling", NULL, AT_NONE); //Cmdline_json_profiling
cmdline_parm show_video_info("-show_video_info", NULL, AT_NONE); //Cmdline_show_video_info
cmdline_parm frame_profile_arg("-profile_frame_time", NULL, AT_NONE); //Cmdline_frame_profile
@@ -524,7 +518,6 @@ bool Cmdline_profile_write_file = false;
bool Cmdline_no_unfocus_pause = false;
bool Cmdline_benchmark_mode = false;
bool Cmdline_noninteractive = false;
bool Cmdline_json_pilot = false;
bool Cmdline_json_profiling = false;
bool Cmdline_frame_profile = false;
bool Cmdline_show_video_info = false;
@@ -546,6 +539,7 @@ cmdline_parm deprecated_htl_arg("-nohtl", "Deprecated", AT_NONE);
cmdline_parm deprecated_brieflighting_arg("-brief_lighting", "Deprecated", AT_NONE);
cmdline_parm deprecated_sndpreload_arg("-snd_preload", "Deprecated", AT_NONE);
cmdline_parm deprecated_missile_lighting_arg("-missile_lighting", "Deprecated", AT_NONE);
cmdline_parm deprecated_cache_bitmaps_arg("-cache_bitmaps", "Deprecated", AT_NONE);
int Cmdline_deprecated_spec = 0;
int Cmdline_deprecated_glow = 0;
@@ -556,6 +550,7 @@ int Cmdline_deprecated_jpgtga = 0;
int Cmdline_deprecated_nohtl = 0;
bool Cmdline_deprecated_brief_lighting = 0;
bool Cmdline_deprecated_missile_lighting = false;
bool Cmdline_deprecated_cache_bitmaps = false;
#ifndef NDEBUG
// NOTE: this assumes that os_init() has already been called but isn't a fatal error if it hasn't
@@ -626,6 +621,10 @@ void cmdline_debug_print_cmdline()
{
mprintf(("Deprecated flag '-missile_lighting' found. Please remove from your cmdline.\n"));
}
if (Cmdline_deprecated_cache_bitmaps) {
mprintf(("Deprecated flag '-cache_bitmaps' found. Please remove from your cmdline.\n"));
}
}
#endif
@@ -1965,10 +1964,6 @@ bool SetCmdlineParams()
Cmdline_ballistic_gauge = 1;
}
if ( cache_bitmaps_arg.found() ) {
Cmdline_cache_bitmaps = 1;
}
if(old_collision_system.found())
Cmdline_old_collision_sys = 1;
@@ -2089,11 +2084,6 @@ bool SetCmdlineParams()
Cmdline_noninteractive = true;
}
if (json_pilot.found())
{
Cmdline_json_pilot = true;
}
if (json_profiling.found())
{
Cmdline_json_profiling = true;
@@ -2159,6 +2149,10 @@ bool SetCmdlineParams()
Cmdline_deprecated_missile_lighting = true;
}
if (deprecated_cache_bitmaps_arg.found()) {
Cmdline_deprecated_cache_bitmaps = true;
}
return true;
}
-2
View File
@@ -82,7 +82,6 @@ extern int Cmdline_no_emissive;
extern int Cmdline_aniso_level;
// Game Speed related
extern int Cmdline_cache_bitmaps;
extern int Cmdline_NoFPSCap;
extern int Cmdline_no_vsync;
@@ -157,7 +156,6 @@ extern bool Cmdline_profile_write_file;
extern bool Cmdline_no_unfocus_pause;
extern bool Cmdline_benchmark_mode;
extern bool Cmdline_noninteractive;
extern bool Cmdline_json_pilot;
extern bool Cmdline_json_profiling;
extern bool Cmdline_frame_profile;
extern bool Cmdline_show_video_info;
+2 -2
View File
@@ -2345,7 +2345,7 @@ int check_control(int id, int key)
// which has just been released
Script_system.SetHookVar("Action", 's', Control_config[id].text);
Script_system.RunCondition(CHA_ONACTIONSTOPPED, '\0', NULL, NULL, id);
Script_system.RunCondition(CHA_ONACTIONSTOPPED, nullptr, id);
Script_system.RemHookVar("Action");
Control_config[id].continuous_ongoing = false;
@@ -2419,7 +2419,7 @@ void control_used(int id)
if (Control_config[id].used < Last_frame_timestamp) {
if (!Control_config[id].continuous_ongoing) {
Script_system.SetHookVar("Action", 's', Control_config[id].text);
Script_system.RunCondition(CHA_ONACTION, '\0', NULL, NULL, id);
Script_system.RunCondition(CHA_ONACTION, nullptr, id);
Script_system.RemHookVar("Action");
if (Control_config[id].type == CC_TYPE_CONTINUOUS)
+6
View File
@@ -3,6 +3,12 @@
#include <memory>
namespace cutscene {
FrameSize::FrameSize(size_t in_width, size_t in_height, size_t in_stride)
: width(in_width), height(in_height), stride(in_stride)
{
}
FrameSize::FrameSize() = default;
Decoder::Decoder() : m_decoding(true) {
}
+24 -12
View File
@@ -10,28 +10,26 @@ struct FrameSize {
size_t width = 0;
size_t height = 0;
size_t stride = 0;
FrameSize(size_t width, size_t in_height, size_t in_stride);
FrameSize();
};
class VideoFrame {
protected:
VideoFrame() {}
VideoFrame() = default;
public:
virtual ~VideoFrame() {}
public:
virtual ~VideoFrame() = default;
double frameTime = -1.0;
int id = -1;
FrameSize ySize;
FrameSize uvSize;
virtual size_t getPlaneNumber() = 0;
struct DataPointers {
ubyte* y;
ubyte* u;
ubyte* v;
};
virtual FrameSize getPlaneSize(size_t plane) = 0;
virtual DataPointers getDataPointers() = 0;
virtual void* getPlaneData(size_t plane) = 0;
};
/**
@@ -43,10 +41,19 @@ using FramePtr = std::unique_ptr<T>;
typedef std::unique_ptr<VideoFrame> VideoFramePtr;
enum class FramePixelFormat {
Invalid,
YUV420,
BGR,
BGRA
};
struct MovieProperties {
FrameSize size;
float fps = -1.0f;
FramePixelFormat pixelFormat = FramePixelFormat::Invalid;
};
struct AudioFrame {
@@ -66,6 +73,11 @@ struct SubtitleFrame {
};
typedef std::unique_ptr<SubtitleFrame> SubtitleFramePtr;
struct PlaybackProperties {
bool with_audio = true;
bool looping = false;
};
/**
* @brief Abstract class for decoding a video or audio stream
*
@@ -99,7 +111,7 @@ class Decoder {
* @param fileName The name of the file that should be opened
* @return @c true if the initialization was successfull, @c false otherwise
*/
virtual bool initialize(const SCP_string& fileName) = 0;
virtual bool initialize(const SCP_string& fileName, const PlaybackProperties& properties) = 0;
/**
* @brief Returns the properties of the video
+67 -24
View File
@@ -14,46 +14,85 @@ struct movie_vertex {
namespace cutscene {
namespace player {
VideoPresenter::VideoPresenter(const MovieProperties& props) {
VideoPresenter::VideoPresenter(const MovieProperties& props) : _properties(props)
{
GR_DEBUG_SCOPE("Init video");
_planeTextureHandles.fill(-1);
auto w = static_cast<int>(props.size.width);
auto h = static_cast<int>(props.size.height);
// Create buffer textures
_yTexBuffer.reset(new uint8_t[w * h]);
_ytex = bm_create(8, w, h, _yTexBuffer.get(), BMP_AABITMAP);
switch (props.pixelFormat) {
case FramePixelFormat::YUV420:
_planeTextureBuffers[0].reset(new uint8_t[w * h]);
_planeTextureHandles[0] = bm_create(8, w, h, _planeTextureBuffers[0].get(), BMP_AABITMAP);
_uTexBuffer.reset(new uint8_t[w / 2 * h / 2]);
_utex = bm_create(8, w / 2, h / 2, _uTexBuffer.get(), BMP_AABITMAP);
_planeTextureBuffers[1].reset(new uint8_t[w / 2 * h / 2]);
_planeTextureHandles[1] = bm_create(8, w / 2, h / 2, _planeTextureBuffers[1].get(), BMP_AABITMAP);
_vTexBuffer.reset(new uint8_t[w / 2 * h / 2]);
_vtex = bm_create(8, w / 2, h / 2, _vTexBuffer.get(), BMP_AABITMAP);
_planeTextureBuffers[2].reset(new uint8_t[w / 2 * h / 2]);
_planeTextureHandles[2] = bm_create(8, w / 2, h / 2, _planeTextureBuffers[2].get(), BMP_AABITMAP);
material_set_movie(&_render_material, _ytex, _utex, _vtex);
material_set_movie(&_movie_material, _planeTextureHandles[0], _planeTextureHandles[1], _planeTextureHandles[2]);
break;
case FramePixelFormat::BGR:
_planeTextureBuffers[0].reset(new uint8_t[w * h * 3]);
_planeTextureHandles[0] = bm_create(24, w, h, _planeTextureBuffers[0].get(), 0);
material_set_unlit(&_rgb_material, _planeTextureHandles[0], 1.0f, false, false);
break;
case FramePixelFormat::BGRA:
_planeTextureBuffers[0].reset(new uint8_t[w * h * 4]);
_planeTextureHandles[0] = bm_create(32, w, h, _planeTextureBuffers[0].get(), 0);
material_set_unlit(&_rgb_material, _planeTextureHandles[0], 1.0f, true, false);
break;
default:
UNREACHABLE("Unhandled enum value!");
break;
}
}
VideoPresenter::~VideoPresenter() {
GR_DEBUG_SCOPE("Deinit video");
bm_release(_ytex);
bm_release(_utex);
bm_release(_vtex);
_ytex = _utex = _vtex = -1;
for (auto& handle : _planeTextureHandles) {
if (handle > 0) {
bm_release(handle);
handle = -1;
}
}
}
void VideoPresenter::uploadVideoFrame(const VideoFramePtr& frame) {
GR_DEBUG_SCOPE("Update video frame");
auto ptrs = frame->getDataPointers();
memcpy(_yTexBuffer.get(), ptrs.y, frame->ySize.stride * frame->ySize.height);
memcpy(_uTexBuffer.get(), ptrs.u, frame->uvSize.stride * frame->uvSize.height);
memcpy(_vTexBuffer.get(), ptrs.v, frame->uvSize.stride * frame->uvSize.height);
for (size_t i = 0; i < frame->getPlaneNumber(); ++i) {
auto size = frame->getPlaneSize(i);
auto data = frame->getPlaneData(i);
gr_update_texture(_ytex, 8, _yTexBuffer.get(), (int) frame->ySize.width, (int) frame->ySize.height);
gr_update_texture(_utex, 8, _uTexBuffer.get(), (int) frame->uvSize.width, (int) frame->uvSize.height);
gr_update_texture(_vtex, 8, _vTexBuffer.get(), (int) frame->uvSize.width, (int) frame->uvSize.height);
memcpy(_planeTextureBuffers[i].get(), data, size.stride * size.height);
int bpp = 0;
switch (_properties.pixelFormat) {
case FramePixelFormat::YUV420:
bpp = 8;
break;
case FramePixelFormat::BGR:
bpp = 24;
break;
case FramePixelFormat::BGRA:
bpp = 32;
break;
default:
UNREACHABLE("Unhandled enum value!");
break;
}
gr_update_texture(_planeTextureHandles[i], bpp, _planeTextureBuffers[i].get(), static_cast<int>(size.width),
static_cast<int>(size.height));
}
}
void VideoPresenter::displayFrame(float x1, float y1, float x2, float y2) {
@@ -85,10 +124,14 @@ void VideoPresenter::displayFrame(float x1, float y1, float x2, float y2) {
auto offset = gr_add_to_immediate_buffer(sizeof(vertex_data), vertex_data);
vertex_layout layout;
layout.add_vertex_component(vertex_format_data::POSITION2, sizeof(vertex_data[0]), offset + offsetof(movie_vertex, pos));
layout.add_vertex_component(vertex_format_data::TEX_COORD2, sizeof(vertex_data[0]), offset + offsetof(movie_vertex, uv));
layout.add_vertex_component(vertex_format_data::POSITION2, sizeof(vertex_data[0]), offsetof(movie_vertex, pos));
layout.add_vertex_component(vertex_format_data::TEX_COORD2, sizeof(vertex_data[0]), offsetof(movie_vertex, uv));
gr_render_movie(&_render_material, PRIM_TYPE_TRISTRIP, &layout, 4, gr_immediate_buffer_handle);
if (_properties.pixelFormat == FramePixelFormat::YUV420) {
gr_render_movie(&_movie_material, PRIM_TYPE_TRISTRIP, &layout, 4, gr_immediate_buffer_handle, offset);
} else {
gr_render_primitives(&_rgb_material, PRIM_TYPE_TRISTRIP, &layout, 0, 4, gr_immediate_buffer_handle, offset);
}
}
}
+5 -8
View File
@@ -12,16 +12,13 @@ namespace cutscene {
namespace player {
class VideoPresenter {
int _ytex = -1;
std::unique_ptr<uint8_t[]> _yTexBuffer;
MovieProperties _properties;
int _utex = -1;
std::unique_ptr<uint8_t[]> _uTexBuffer;
std::array<int, 3> _planeTextureHandles;
std::array<std::unique_ptr<uint8_t[]>, 3> _planeTextureBuffers;
int _vtex = -1;
std::unique_ptr<uint8_t[]> _vTexBuffer;
movie_material _render_material;
movie_material _movie_material;
material _rgb_material; // Material used when a RGB/RGBA movie is played
public:
explicit VideoPresenter(const MovieProperties& props);
+3
View File
@@ -223,5 +223,8 @@ void AudioDecoder::finishDecoding() {
// Push the last bits of audio data into the queue
flushAudioBuffer();
}
void AudioDecoder::flushBuffers() {
avcodec_flush_buffers(m_status->audioCodecCtx);
}
}
}
+2
View File
@@ -30,6 +30,8 @@ class AudioDecoder: public FFMPEGStreamDecoder<AudioFrame> {
void decodePacket(AVPacket* packet) override;
void finishDecoding() override;
void flushBuffers() override;
};
}
}
+204 -87
View File
@@ -28,22 +28,26 @@ class AVPacketScope
: _packet(av_packet) {
}
AVPacketScope(const AVPacketScope&) = delete;
AVPacketScope& operator=(const AVPacketScope&) = delete;
~AVPacketScope() {
av_packet_unref(_packet);
}
};
const char* CHECKED_EXTENSIONS[] = {
"webm",
"mp4",
"ogg",
"mve"
};
const char* CHECKED_EXTENSIONS[] = {"webm", "mp4", "ogg",
"png", // This is designed to be used with APNG animations
"mve"};
const char *CHECKED_SUBT_EXTENSIONS[] = {"srt"};
const char* CHECKED_SUBT_EXTENSIONS[] = {"srt"};
double getFrameRate(AVStream* stream, AVCodecContext* codecCtx) {
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(58, 3, 102)
auto fps = av_q2d(stream->r_frame_rate);
#else
auto fps = av_q2d(av_stream_get_r_frame_rate(stream));
#endif
if (fps < 0.000001)
{
@@ -58,7 +62,7 @@ double getFrameRate(AVStream* stream, AVCodecContext* codecCtx) {
return fps;
}
CodecContextParameters getCodecParameters(AVStream *stream) {
CodecContextParameters getCodecParameters(AVStream* stream) {
CodecContextParameters paras;
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
paras.width = stream->codecpar->width;
@@ -84,7 +88,7 @@ CodecContextParameters getCodecParameters(AVStream *stream) {
return paras;
}
SCP_string normalizeLanguage(const char *langauge_name) {
SCP_string normalizeLanguage(const char* langauge_name) {
if (!stricmp(langauge_name, "eng")) {
return "English";
}
@@ -101,6 +105,72 @@ SCP_string normalizeLanguage(const char *langauge_name) {
// Default to english for everything else
return "English";
}
/**
* @brief Given a FFmpeg pixel format returns the format it should be converted to
* @param in_fmt The input format
* @return The output format
*/
AVPixelFormat getConversionFormat(AVPixelFormat in_fmt)
{
switch (in_fmt) {
case AV_PIX_FMT_RGB24:
case AV_PIX_FMT_BGR24:
case AV_PIX_FMT_BGR8:
case AV_PIX_FMT_BGR4:
case AV_PIX_FMT_BGR4_BYTE:
case AV_PIX_FMT_RGB8:
case AV_PIX_FMT_RGB4:
case AV_PIX_FMT_RGB4_BYTE:
case AV_PIX_FMT_RGB48BE:
case AV_PIX_FMT_RGB48LE:
case AV_PIX_FMT_RGB565BE:
case AV_PIX_FMT_RGB565LE:
case AV_PIX_FMT_RGB555BE:
case AV_PIX_FMT_RGB555LE:
case AV_PIX_FMT_BGR565BE:
case AV_PIX_FMT_BGR565LE:
case AV_PIX_FMT_BGR555BE:
case AV_PIX_FMT_BGR555LE:
case AV_PIX_FMT_RGB444LE:
case AV_PIX_FMT_RGB444BE:
case AV_PIX_FMT_BGR444LE:
case AV_PIX_FMT_BGR444BE:
case AV_PIX_FMT_BGR48BE:
case AV_PIX_FMT_BGR48LE:
case AV_PIX_FMT_0RGB:
case AV_PIX_FMT_RGB0:
case AV_PIX_FMT_0BGR:
case AV_PIX_FMT_BGR0:
return AV_PIX_FMT_BGR24;
case AV_PIX_FMT_RGBA64BE:
case AV_PIX_FMT_RGBA64LE:
case AV_PIX_FMT_BGRA64BE:
case AV_PIX_FMT_BGRA64LE:
case AV_PIX_FMT_ARGB:
case AV_PIX_FMT_RGBA:
case AV_PIX_FMT_ABGR:
case AV_PIX_FMT_BGRA:
return AV_PIX_FMT_BGRA;
default:
// Assume that everything else is converted to YUV 420
return AV_PIX_FMT_YUV420P;
}
}
FramePixelFormat getPixelFormat(AVPixelFormat fmt)
{
switch (fmt) {
case AV_PIX_FMT_BGR24:
return FramePixelFormat::BGR;
case AV_PIX_FMT_BGRA:
return FramePixelFormat::BGRA;
default:
return FramePixelFormat::YUV420;
}
}
}
namespace cutscene {
@@ -146,8 +216,15 @@ std::unique_ptr<InputStream> openStream(const SCP_string& name) {
return input;
}
std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream> &stream,
std::unique_ptr<InputStream> &subt) {
std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& stream,
std::unique_ptr<InputStream>& subt,
const PlaybackProperties& properties)
{
if (subt && properties.looping) {
mprintf(("FFmpeg: External subtitles and looping movies are not supported!\n"));
return nullptr;
}
std::unique_ptr<DecoderStatus> status(new DecoderStatus());
auto ctx = stream->m_ctx->ctx();
@@ -165,14 +242,18 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream> &st
return nullptr;
}
auto audioStream = av_find_best_stream(ctx, AVMEDIA_TYPE_AUDIO, -1, videoStream, &status->audioCodec, 0);
if (audioStream < 0) {
if (audioStream == AVERROR_STREAM_NOT_FOUND) {
mprintf(("FFmpeg: No audio stream found in file!\n"));
} else if (audioStream == AVERROR_DECODER_NOT_FOUND) {
mprintf(("FFmpeg: Codec for audio stream could not be found!\n"));
} else {
mprintf(("FFmpeg: Unknown error while finding audio stream!\n"));
int audioStream = -1;
if (properties.with_audio) {
audioStream = av_find_best_stream(ctx, AVMEDIA_TYPE_AUDIO, -1, videoStream, &status->audioCodec, 0);
if (audioStream < 0) {
if (audioStream == AVERROR_STREAM_NOT_FOUND) {
mprintf(("FFmpeg: No audio stream found in file!\n"));
} else if (audioStream == AVERROR_DECODER_NOT_FOUND) {
mprintf(("FFmpeg: Codec for audio stream could not be found!\n"));
} else {
mprintf(("FFmpeg: Unknown error while finding audio stream!\n"));
}
}
}
@@ -205,18 +286,18 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream> &st
if (status->subtitleStream == nullptr) {
// We don't have an external subtitle stream or loading from that file has failed
auto &current_language = Lcl_languages[Lcl_current_lang];
auto& current_language = Lcl_languages[Lcl_current_lang];
for (uint32_t i = 0; i < ctx->nb_streams; ++i) {
auto test_stream = ctx->streams[i];
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
auto &pars = test_stream->codecpar;
auto& pars = test_stream->codecpar;
if (!(pars->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
continue;
}
#endif
AVDictionaryEntry *tag = nullptr;
AVDictionaryEntry* tag = nullptr;
if ((tag = av_dict_get(test_stream->metadata, "language", nullptr, 0)) == nullptr) {
continue;
}
@@ -233,6 +314,11 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream> &st
status->videoCodecPars = getCodecParameters(status->videoStream);
if (properties.looping && status->videoCodecPars.codec_id == AV_CODEC_ID_INTERPLAY_VIDEO) {
mprintf(("FFmpeg: Looping is not supported for inteplay (MVE) movies!\n"));
return nullptr;
}
int err;
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
status->videoCodecCtx = avcodec_alloc_context3(status->videoCodec);
@@ -340,8 +426,9 @@ std::unique_ptr<InputStream> openInputStream(const SCP_string& name) {
return nullptr;
}
std::unique_ptr<InputStream> openSubtitleStream(const SCP_string &name) {
auto &current_language = Lcl_languages[Lcl_current_lang];
std::unique_ptr<InputStream> openSubtitleStream(const SCP_string& name)
{
auto& current_language = Lcl_languages[Lcl_current_lang];
for (auto ext : CHECKED_SUBT_EXTENSIONS) {
SCP_string fileName;
@@ -362,10 +449,11 @@ std::unique_ptr<InputStream> openSubtitleStream(const SCP_string &name) {
}
}
bool FFMPEGDecoder::initialize(const SCP_string& fileName) {
bool FFMPEGDecoder::initialize(const SCP_string& fileName, const PlaybackProperties& properties)
{
SCP_string movieName = fileName;
// First make the file name lower case
std::transform(movieName.begin(), movieName.end(), movieName.begin(), ::tolower);
std::transform(movieName.begin(), movieName.end(), movieName.begin(), [](char c) { return (char)::tolower(c); });
// Then remove the extension
size_t dotPos = movieName.find('.');
@@ -382,7 +470,7 @@ bool FFMPEGDecoder::initialize(const SCP_string& fileName) {
auto subt = openSubtitleStream(movieName);
// We now have a valid input stream, try to find the correct streams
auto status = initializeStatus(input, subt);
auto status = initializeStatus(input, subt, properties);
if (!status) {
return false;
}
@@ -394,21 +482,25 @@ bool FFMPEGDecoder::initialize(const SCP_string& fileName) {
std::swap(m_input, input);
std::swap(m_subtitleInput, subt);
std::swap(m_status, status);
m_properties = properties;
return true;
}
MovieProperties FFMPEGDecoder::getProperties() const {
MovieProperties FFMPEGDecoder::getProperties() const
{
MovieProperties props;
props.size.width = static_cast<size_t>(m_status->videoCodecPars.width);
props.size.height = static_cast<size_t>(m_status->videoCodecPars.height);
props.fps = static_cast<float>(getFrameRate(m_status->videoStream, m_status->videoCodecCtx));
props.pixelFormat = getPixelFormat(getConversionFormat(m_status->videoCodecPars.pixel_format));
return props;
}
void FFMPEGDecoder::startDecoding() {
std::unique_ptr<VideoDecoder> videoDecoder(new VideoDecoder(m_status.get()));
std::unique_ptr<VideoDecoder> videoDecoder(new VideoDecoder(m_status.get(), getConversionFormat(m_status->videoCodecPars.pixel_format)));
std::unique_ptr<AudioDecoder> audioDecoder;
std::unique_ptr<SubtitleDecoder> subtitleDecoder;
@@ -430,74 +522,98 @@ void FFMPEGDecoder::startDecoding() {
auto ctx = m_input->m_ctx->ctx();
AVPacket packet;
while (isDecoding()) {
auto read_err = av_read_frame(ctx, &packet);
AVPacketScope scope(&packet);
if (read_err < 0) {
if (read_err == AVERROR_EOF) {
// Finished reading -> break out of loop
break;
} else if (avio_feof(ctx->pb) != 0) {
// Also EOF!
break;
} else {
// Some kind of other error, try to continue reading
do {
if (m_properties.looping) {
// Only seek if we are looping the movie. The MVE code doesn't support seeking to this function may not be
// called there
auto seek_err = av_seek_frame(ctx, -1, 0, AVSEEK_FLAG_BACKWARD);
if (seek_err < 0) {
char errorStr[512];
av_strerror(read_err, errorStr, sizeof(errorStr));
mprintf(("FFMPEG: Failed to read frame! Error: %s\n", errorStr));
// Skip packet
continue;
av_strerror(seek_err, errorStr, sizeof(errorStr));
mprintf(("FFMPEG: Failed to seek to start of movie file! Error: %s\n", errorStr));
break;
}
}
if (packet.stream_index == m_status->videoStreamIndex) {
videoDecoder->decodePacket(&packet);
VideoFramePtr ptr;
while((ptr = videoDecoder->getFrame()) != nullptr) {
pushFrameData(std::move(ptr));
}
} else if (audioDecoder && packet.stream_index == m_status->audioStreamIndex) {
audioDecoder->decodePacket(&packet);
AudioFramePtr ptr;
while ((ptr = audioDecoder->getFrame()) != nullptr) {
pushAudioData(std::move(ptr));
}
} else if (subtitleDecoder && packet.stream_index == m_status->subtitleStreamIndex) {
subtitleDecoder->decodePacket(&packet);
SubtitleFramePtr ptr;
while ((ptr = subtitleDecoder->getFrame()) != nullptr) {
pushSubtitleData(std::move(ptr));
}
}
}
if (isDecoding()) {
// If we are still alive then read the last frames from the decoders
videoDecoder->finishDecoding();
VideoFramePtr video_ptr;
while ((video_ptr = videoDecoder->getFrame()) != nullptr) {
pushFrameData(std::move(video_ptr));
}
videoDecoder->flushBuffers();
if (audioDecoder) {
audioDecoder->finishDecoding();
AudioFramePtr audio_frame;
while ((audio_frame = audioDecoder->getFrame()) != nullptr) {
pushAudioData(std::move(audio_frame));
audioDecoder->flushBuffers();
}
if (subtitleDecoder) {
subtitleDecoder->flushBuffers();
}
while (isDecoding()) {
auto read_err = av_read_frame(ctx, &packet);
AVPacketScope scope(&packet);
if (read_err < 0) {
if (read_err == AVERROR_EOF) {
// Finished reading -> break out of loop
break;
} else if (avio_feof(ctx->pb) != 0) {
// Also EOF!
break;
} else {
// Some kind of other error, try to continue reading
char errorStr[512];
av_strerror(read_err, errorStr, sizeof(errorStr));
mprintf(("FFMPEG: Failed to read frame! Error: %s\n", errorStr));
// Skip packet
continue;
}
}
if (packet.stream_index == m_status->videoStreamIndex) {
videoDecoder->decodePacket(&packet);
VideoFramePtr ptr;
while ((ptr = videoDecoder->getFrame()) != nullptr) {
pushFrameData(std::move(ptr));
}
} else if (audioDecoder && packet.stream_index == m_status->audioStreamIndex) {
audioDecoder->decodePacket(&packet);
AudioFramePtr ptr;
while ((ptr = audioDecoder->getFrame()) != nullptr) {
pushAudioData(std::move(ptr));
}
} else if (subtitleDecoder && packet.stream_index == m_status->subtitleStreamIndex) {
subtitleDecoder->decodePacket(&packet);
SubtitleFramePtr ptr;
while ((ptr = subtitleDecoder->getFrame()) != nullptr) {
pushSubtitleData(std::move(ptr));
}
}
}
}
if (isDecoding()) {
// If we are still alive then read the last frames from the decoders
videoDecoder->finishDecoding();
VideoFramePtr video_ptr;
while ((video_ptr = videoDecoder->getFrame()) != nullptr) {
pushFrameData(std::move(video_ptr));
}
if (audioDecoder) {
audioDecoder->finishDecoding();
AudioFramePtr audio_frame;
while ((audio_frame = audioDecoder->getFrame()) != nullptr) {
pushAudioData(std::move(audio_frame));
}
}
}
// If the video is being looped then we start again from the beginning
} while (m_properties.looping && isDecoding());
// Stop the decoder first to let the subtitle thread know that it shouldn't continue
stopDecoder();
if (subtitle_thread) {
subtitle_thread->join();
}
stopDecoder();
}
bool FFMPEGDecoder::hasAudio() const { return m_status->audioStreamIndex >= 0; }
@@ -520,7 +636,8 @@ void FFMPEGDecoder::close() {
m_subtitleInput = nullptr;
}
}
void FFMPEGDecoder::runSubtitleDecoder(SubtitleDecoder *decoder) {
void FFMPEGDecoder::runSubtitleDecoder(SubtitleDecoder* decoder)
{
auto ctx = m_subtitleInput->m_ctx->ctx();
AVPacket packet;
+4 -2
View File
@@ -18,16 +18,18 @@ class FFMPEGDecoder: public Decoder {
std::unique_ptr<DecoderStatus> m_status;
PlaybackProperties m_properties;
bool hasExternalSubtitle() const;
void runSubtitleDecoder(SubtitleDecoder *decoder);
void runSubtitleDecoder(SubtitleDecoder* decoder);
public:
FFMPEGDecoder();
~FFMPEGDecoder() override;
bool initialize(const SCP_string& fileName) override;
bool initialize(const SCP_string& fileName, const PlaybackProperties& properties) override;
MovieProperties getProperties() const override;
+3
View File
@@ -129,6 +129,9 @@ void SubtitleDecoder::pushSubtitleFrame(AVPacket* packet, AVSubtitle* subtitle)
pushFrame(std::move(frame));
}
void SubtitleDecoder::flushBuffers() {
avcodec_flush_buffers(m_status->subtitleCodecCtx);
}
}
}
+1
View File
@@ -16,6 +16,7 @@ class SubtitleDecoder: public FFMPEGStreamDecoder<SubtitleFrame> {
void finishDecoding() override;
void pushSubtitleFrame(AVPacket* subtitle, AVSubtitle* pSubtitle);
void flushBuffers() override;
};
}
+61 -62
View File
@@ -3,11 +3,9 @@
#include "tracing/tracing.h"
namespace {
const AVPixelFormat DESTINATION_FORMAT = AV_PIX_FMT_YUV420P;
SwsContext* getSWSContext(int width, int height, AVPixelFormat fmt) {
return sws_getContext(width, height, fmt, width, height, DESTINATION_FORMAT,
SWS_BILINEAR, nullptr, nullptr, nullptr);
SwsContext* getSWSContext(int width, int height, AVPixelFormat fmt, AVPixelFormat destination_fmt)
{
return sws_getContext(width, height, fmt, width, height, destination_fmt, SWS_BILINEAR, nullptr, nullptr, nullptr);
}
double getFrameTime(int64_t pts, AVRational time_base) {
@@ -18,34 +16,53 @@ double getFrameTime(int64_t pts, AVRational time_base) {
namespace cutscene {
namespace ffmpeg {
class FFMPEGVideoFrame: public VideoFrame {
public:
FFMPEGVideoFrame() : frame(nullptr) {
}
size_t _width;
size_t _height;
AVFrame* _frame;
public:
FFMPEGVideoFrame(size_t width, size_t height, AVFrame* frame) : _width(width), _height(height), _frame(frame) {}
~FFMPEGVideoFrame() override {
if (frame != nullptr) {
av_freep(&frame->data[0]);
av_frame_free(&frame);
if (_frame != nullptr) {
av_freep(&_frame->data[0]);
av_frame_free(&_frame);
}
}
DataPointers getDataPointers() override {
DataPointers ptrs;
ptrs.y = frame->data[0];
ptrs.u = frame->data[1];
ptrs.v = frame->data[2];
return ptrs;
size_t getPlaneNumber() override
{
switch (_frame->format) {
case AV_PIX_FMT_YUV420P:
// YUV data is planar
return 3;
default:
// Everything else is packed
return 1;
}
}
FrameSize getPlaneSize(size_t plane) override
{
switch (_frame->format) {
case AV_PIX_FMT_YUV420P: {
// YUV data is planar
auto width = plane > 0 ? _width / 2 : _width;
auto height = plane > 0 ? _height / 2 : _height;
AVFrame* frame;
return {width, height, (size_t)_frame->linesize[plane]};
}
default:
// Everything else is packed
return {_width, _height, (size_t)_frame->linesize[plane]};
}
}
void* getPlaneData(size_t plane) override { return _frame->data[plane]; }
};
VideoDecoder::VideoDecoder(DecoderStatus* status)
: FFMPEGStreamDecoder(status),
m_frameId(0) {
VideoDecoder::VideoDecoder(DecoderStatus* status, AVPixelFormat destination_fmt)
: FFMPEGStreamDecoder(status), m_frameId(0), m_destinationFormat(destination_fmt)
{
m_swsCtx = getSWSContext(m_status->videoCodecPars.width, m_status->videoCodecPars.height,
m_status->videoCodecPars.pixel_format);
m_status->videoCodecPars.pixel_format, destination_fmt);
}
VideoDecoder::~VideoDecoder() {
@@ -53,53 +70,32 @@ VideoDecoder::~VideoDecoder() {
}
void VideoDecoder::convertAndPushPicture(const AVFrame* frame) {
// Allocate a picture to hold the YUV data
// Allocate a picture to hold the destination data
AVFrame* yuvFrame = av_frame_alloc();
av_frame_copy(yuvFrame, frame);
yuvFrame->format = DESTINATION_FORMAT;
yuvFrame->format = m_destinationFormat;
av_image_alloc(yuvFrame->data,
yuvFrame->linesize,
m_status->videoCodecPars.width,
m_status->videoCodecPars.height,
DESTINATION_FORMAT,
1);
av_image_alloc(yuvFrame->data, yuvFrame->linesize, m_status->videoCodecPars.width, m_status->videoCodecPars.height,
m_destinationFormat, 1);
std::unique_ptr<FFMPEGVideoFrame> videoFramePtr(new FFMPEGVideoFrame());
if (m_status->videoCodecPars.pixel_format == DESTINATION_FORMAT) {
av_image_copy(yuvFrame->data,
yuvFrame->linesize,
(const uint8_t**) (frame->data),
frame->linesize,
DESTINATION_FORMAT,
m_status->videoCodecPars.width,
m_status->videoCodecPars.height);
if (m_status->videoCodecPars.pixel_format == m_destinationFormat) {
av_image_copy(yuvFrame->data, yuvFrame->linesize, (const uint8_t**)(frame->data), frame->linesize,
m_destinationFormat, m_status->videoCodecPars.width, m_status->videoCodecPars.height);
} else {
// Convert frame to YUV
sws_scale(
m_swsCtx,
(uint8_t const* const*) frame->data,
frame->linesize,
0,
m_status->videoCodecPars.height,
yuvFrame->data,
yuvFrame->linesize
);
// Convert frame to destination format
sws_scale(m_swsCtx, (uint8_t const* const*)frame->data, frame->linesize, 0, m_status->videoCodecPars.height,
yuvFrame->data, yuvFrame->linesize);
}
std::unique_ptr<FFMPEGVideoFrame> videoFramePtr(
new FFMPEGVideoFrame(static_cast<size_t>(m_status->videoCodecPars.width),
static_cast<size_t>(m_status->videoCodecPars.height), yuvFrame));
videoFramePtr->id = ++m_frameId;
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(58, 3, 102)
videoFramePtr->frameTime = getFrameTime(frame->best_effort_timestamp, m_status->videoStream->time_base);
#else
videoFramePtr->frameTime = getFrameTime(av_frame_get_best_effort_timestamp(frame), m_status->videoStream->time_base);
videoFramePtr->frame = yuvFrame;
videoFramePtr->ySize.height = static_cast<size_t>(m_status->videoCodecPars.height);
videoFramePtr->ySize.width = static_cast<size_t>(m_status->videoCodecPars.width);
videoFramePtr->ySize.stride = static_cast<size_t>(yuvFrame->linesize[0]);
// 420P means that the UV channels have half the width and height
videoFramePtr->uvSize.height = static_cast<size_t>(m_status->videoCodecPars.height / 2);
videoFramePtr->uvSize.width = static_cast<size_t>(m_status->videoCodecPars.width / 2);
videoFramePtr->uvSize.stride = static_cast<size_t>(yuvFrame->linesize[1]);
#endif
pushFrame(VideoFramePtr(videoFramePtr.release()));
}
@@ -162,5 +158,8 @@ void VideoDecoder::finishDecoding() {
}
#endif
}
void VideoDecoder::flushBuffers() {
avcodec_flush_buffers(m_status->videoCodecCtx);
}
}
}
+4 -1
View File
@@ -9,17 +9,20 @@ class VideoDecoder: public FFMPEGStreamDecoder<VideoFrame> {
private:
int m_frameId;
SwsContext* m_swsCtx;
AVPixelFormat m_destinationFormat;
void convertAndPushPicture(const AVFrame* frame);
public:
explicit VideoDecoder(DecoderStatus* status);
explicit VideoDecoder(DecoderStatus* status, AVPixelFormat destination_fmt);
~VideoDecoder() override;
void decodePacket(AVPacket* packet) override;
void finishDecoding() override;
void flushBuffers() override;
};
}
}
+2
View File
@@ -74,6 +74,8 @@ class FFMPEGStreamDecoder {
virtual void finishDecoding() = 0;
virtual void flushBuffers() = 0;
virtual FramePtr<frame_type> getFrame();
};
+25 -16
View File
@@ -44,21 +44,11 @@ struct PlaybackState {
int subtitle_font = -1;
};
void processEvents(PlaybackState* state) {
void processEvents()
{
io::mouse::CursorManager::get()->showCursor(false);
os_poll();
int k = key_inkey();
switch (k) {
case KEY_ESC:
case KEY_ENTER:
case KEY_SPACEBAR:
state->playing = false;
break;
default:
break;
}
}
template<typename... Args>
@@ -193,6 +183,21 @@ void movie_display_loop(Player* player, PlaybackState* state) {
// We will sleep at most half the time a frame would be displayed
auto sleepTime = static_cast<std::uint64_t>((1. / (4. * player->getMovieProperties().fps)) * 1000.);
auto listener = [state](const SDL_Event& event) {
switch (event.key.keysym.sym) {
case SDLK_ESCAPE:
case SDLK_KP_ENTER:
case SDLK_RETURN:
case SDLK_SPACE:
state->playing = false;
return true;
default:
return false;
}
};
// Use a dedicated listener here since we want to listen for the KEYUP event
auto key_handle = os::events::addEventListener(SDL_KEYUP, os::events::DEFAULT_LISTENER_WEIGHT - 10, listener);
auto lastDisplayTimestamp = timer_get_microseconds();
while (state->playing) {
TRACE_SCOPE(tracing::CutsceneStep);
@@ -202,12 +207,14 @@ void movie_display_loop(Player* player, PlaybackState* state) {
auto passed = timestamp - lastDisplayTimestamp;
lastDisplayTimestamp = timestamp;
// Play as long as the player reports that there is more to display
state->playing = player->update(passed);
if (player->isPlaybackReady()) {
// Play as long as the player reports that there is more to display
state->playing = player->update(passed);
displayVideo(player, state);
displayVideo(player, state);
}
processEvents(state);
processEvents();
if (passed < sleepTime) {
auto sleep = sleepTime - passed;
@@ -215,6 +222,8 @@ void movie_display_loop(Player* player, PlaybackState* state) {
os_sleep(static_cast<uint>(sleep));
}
}
os::events::removeEventListener(key_handle);
}
}
+36 -22
View File
@@ -17,6 +17,7 @@
#include "io/key.h"
#include "io/timer.h"
#include "player.h"
#include "parse/parselo.h"
using namespace cutscene::player;
@@ -26,10 +27,10 @@ using namespace cutscene;
const int MAX_AUDIO_BUFFERS = 15;
std::unique_ptr<Decoder> findDecoder(const SCP_string& name) {
std::unique_ptr<Decoder> findDecoder(const SCP_string& name, const PlaybackProperties& properties) {
{
std::unique_ptr<Decoder> ffmpeg(new ffmpeg::FFMPEGDecoder());
if (ffmpeg->initialize(name)) {
std::unique_ptr<Decoder> ffmpeg(new ::cutscene::ffmpeg::FFMPEGDecoder());
if (ffmpeg->initialize(name, properties)) {
return ffmpeg;
}
}
@@ -49,7 +50,8 @@ void videoPlaybackInit(PlayerState* state) {
Assert(state != NULL);
if (gr_screen.mode == GR_OPENGL) {
if (gr_screen.mode != GR_STUB) {
// The video presenter is independent of the underlying graphics API
state->videoPresenter.reset(new VideoPresenter(state->props));
}
@@ -121,6 +123,15 @@ void processVideoData(PlayerState* state) {
}
while (currentTime >= state->nextFrame->frameTime) {
if (state->currentFrame) {
if (state->nextFrame->frameTime < state->currentFrame->frameTime) {
// We reached the end of the movie and just looped to the beginning. Now we need to reset the playback
// time
state->playback_time = 0;
currentTime = playbackGetTime(state);
}
}
// Move the next frame to the current frame slot
state->currentFrame = std::move(state->nextFrame);
@@ -272,8 +283,22 @@ bool shouldBeginPlayback(Decoder* decoder) {
}
namespace cutscene {
Player::Player(std::unique_ptr<Decoder>&& decoder) : m_decoder(std::move(decoder)) {
initPlayback();
Player::Player(std::unique_ptr<Decoder>&& decoder, const PlaybackProperties& properties)
: m_decoder(std::move(decoder))
{
Assertion(!m_state.videoInited,
"Internal State has been initialized before! Create a new player for replaying a movie.");
m_decoderThread.reset(new std::thread(std::bind(&Player::decoderThread, this)));
m_state.props = m_decoder->getProperties();
m_state.decoder = m_decoder.get();
videoPlaybackInit(&m_state);
if (properties.with_audio) {
audioPlaybackInit(&m_state);
}
}
Player::~Player() {
@@ -315,19 +340,6 @@ bool Player::processDecoderData() {
return decoding || pendingAudio || pendingVideo;
}
void Player::initPlayback() {
Assertion(!m_state.videoInited, "Internal State has been initialized before! Create a new player for replaying a movie.");
m_decoderThread.reset(new std::thread(std::bind(&Player::decoderThread, this)));
m_state.props = m_decoder->getProperties();
m_state.decoder = m_decoder.get();
videoPlaybackInit(&m_state);
audioPlaybackInit(&m_state);
}
bool Player::update(uint64_t diff_time_micro) {
if (m_state.playbackHasBegun) {
m_state.playback_time += diff_time_micro;
@@ -354,15 +366,16 @@ void Player::decoderThread() {
}
}
std::unique_ptr<Player> Player::newPlayer(const SCP_string& name) {
std::unique_ptr<Player> Player::newPlayer(const SCP_string& name, const PlaybackProperties& properties)
{
mprintf(("Creating player for movie '%s'.\n", name.c_str()));
auto decoder = findDecoder(name);
auto decoder = findDecoder(name, properties);
if (decoder == nullptr) {
return nullptr;
}
return std::unique_ptr<Player>(new Player(std::move(decoder)));
return std::unique_ptr<Player>(new Player(std::move(decoder), properties));
}
const PlayerState& Player::getInternalState() const {
return m_state;
@@ -386,4 +399,5 @@ SCP_string Player::getCurrentSubtitle() {
return m_state.currentSubtitle->text;
}
}
bool Player::isPlaybackReady() const { return m_state.playbackHasBegun || shouldBeginPlayback(m_decoder.get()); }
}
+21 -13
View File
@@ -52,7 +52,7 @@ struct PlayerState {
* @brief A movie player
*/
class Player {
private:
private:
std::unique_ptr<Decoder> m_decoder;
std::unique_ptr<std::thread> m_decoderThread;
@@ -61,14 +61,11 @@ class Player {
bool processDecoderData();
private:
private:
void decoderThread();
void initPlayback();
public:
explicit Player(std::unique_ptr<Decoder>&& decoder);
Player(std::unique_ptr<Decoder>&& decoder, const PlaybackProperties& properties);
public:
~Player();
Player(const Player&) = delete;
@@ -97,6 +94,12 @@ class Player {
*/
const MovieProperties& getMovieProperties() const;
/**
* @brief Determines if this player can start displaying video.
* @return true if the cutscene is ready, false otherwise
*/
bool isPlaybackReady() const;
/**
* @brief Draws the current movie frame at the specified coordinates.
*
@@ -109,6 +112,10 @@ class Player {
*/
void draw(float x1, float y1, float x2, float y2);
/**
* @brief Gets the subtitle text that should be displayed now
* @return The text, encoded in UTF-8
*/
SCP_string getCurrentSubtitle();
/**
@@ -119,11 +126,12 @@ class Player {
void stopPlayback();
/**
* @brief Creates a player
* The player is configured to play the movie with the specified name
* @param name The movie to play
* @return @c nullptr if the specified movie could not be opened, a valid Player pointer otherwise
*/
static std::unique_ptr<Player> newPlayer(const SCP_string& name);
* @brief Creates a player
* The player is configured to play the movie with the specified name
* @param name The movie to play
* @param properties A structure describing how the movie will be used
* @return @c nullptr if the specified movie could not be opened, a valid Player pointer otherwise
*/
static std::unique_ptr<Player> newPlayer(const SCP_string& name, const PlaybackProperties& properties = PlaybackProperties());
};
}
+8 -4
View File
@@ -24,11 +24,15 @@ void main()
// Now we compute the depth value in projection space using the clipping plane information
float view_depth = 2.0 * zNear * zFar / (zFar + zNear - depth_normalized * (zFar - zNear));
// This is the same formula that is also used by the main shader
float fog_dist = isinf(view_depth) ? 1.0 : clamp((view_depth - fog_start) * 0.75 * fog_scale, 0.0, 1.0);
if (isinf(view_depth)) {
fragOut0.rgb = color_in.rgb;
} else {
// This is the same formula that is also used by the main shader
float fog_dist = clamp((view_depth - fog_start) * 0.75 * fog_scale, 0.0, 1.0);
vec3 finalFogColor = srgb_to_linear(fog_color);
vec3 finalFogColor = srgb_to_linear(fog_color);
fragOut0.rgb = mix(color_in.rgb, finalFogColor, fog_dist);
fragOut0.rgb = mix(color_in.rgb, finalFogColor, fog_dist);
}
fragOut0.a = 1.0;
}
+17 -17
View File
@@ -33,7 +33,7 @@ layout (std140) uniform modelData {
model_light lights[MAX_LIGHTS];
float extrudeWidth;
float outlineWidth;
float fogStart;
float fogScale;
int buffer_matrix_offset;
@@ -105,11 +105,6 @@ in VertexOutput {
#endif
#ifdef FLAG_FOG
float fogDist;
#endif
#ifdef WORKAROUND_CLIPPING_PLANES
#ifdef FLAG_TRANSFORM
float notVisible;
#endif
#endif
vec4 position;
vec3 normal;
@@ -215,11 +210,6 @@ vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial,
void main()
{
#ifdef WORKAROUND_CLIPPING_PLANES
#ifdef FLAG_TRANSFORM
if(vertIn.notVisible >= 0.9) { discard; }
#endif
#endif
#ifdef FLAG_SHADOW_MAP
// need depth and depth squared for variance shadow maps
fragOut0 = vec4(vertIn.position.z, vertIn.position.z * vertIn.position.z * VARIANCE_SHADOW_SCALE_INV, 0.0, 1.0);
@@ -290,11 +280,11 @@ void main()
}
if(gammaSpec) {
specColor.rgb = max(specColor.rgb, vec3(0.03f)); // hardcoded minimum specular value. read John Hable's blog post titled 'Everything Is Shiny'.
#ifdef FLAG_HDR
specColor.rgb = srgb_to_linear(specColor.rgb);
#endif
fresnelFactor = 1.0;
}
#ifdef FLAG_HDR
specColor.rgb = srgb_to_linear(specColor.rgb);
#endif
#endif
baseColor.rgb *= aoFactors.y;
specColor.rgb *= aoFactors.y;
@@ -302,20 +292,29 @@ void main()
#ifdef FLAG_TEAMCOLOR
vec4 teamMask = vec4(0.0, 0.0, 0.0, 0.0);
teamMask = texture(sMiscmap, vec3(texCoord, float(sMiscmapIndex)));
//For team colors applied to a diffuse or spec map, we assume that the base color of the diffuse
//at this point is vec3(0.5). To get accurate results, we subtract 0.5 from the team colors
vec3 team_color = ((base_color - vec3(0.5)) * teamMask.x) + ((stripe_color - vec3(0.5)) * teamMask.y);
vec3 color_offset = vec3(-0.5) * (teamMask.x + teamMask.y);
vec3 team_color = base_color * teamMask.x + stripe_color * teamMask.y + color_offset;
vec3 team_color_glow = (base_color * teamMask.b) + (stripe_color * teamMask.a);
#ifdef FLAG_HDR
team_color = srgb_to_linear(team_color);
team_color_glow = srgb_to_linear(team_color_glow) * GLOW_MAP_SRGB_MULTIPLIER;
baseColor.rgb = linear_to_srgb(baseColor.rgb);
specColor.rgb = linear_to_srgb(specColor.rgb);
#endif
baseColor.rgb += team_color;
baseColor.rgb = max(baseColor.rgb, vec3(0.0)); // We need to make sure that nothing here ever goes negative
specColor.rgb += team_color;
specColor.rgb = max(specColor.rgb, vec3(0.03));
#ifdef FLAG_HDR
baseColor.rgb = srgb_to_linear(baseColor.rgb);
specColor.rgb = srgb_to_linear(specColor.rgb);
#endif
#endif
#endif
// Lights aren't applied when we are rendering to the G-buffers since that gets handled later
@@ -426,6 +425,7 @@ void main()
// emissive colors won't be added later when we are using forward rendering so we need to do that here
baseColor.rgb += emissiveColor.rgb;
#endif
fragOut0 = baseColor;
#ifdef FLAG_DEFERRED
fragOut1 = vec4(vertIn.position.xyz, 1.0);
+83 -22
View File
@@ -1,9 +1,18 @@
#extension GL_ARB_gpu_shader5: enable
#ifdef FLAG_THICK_OUTLINE
layout (triangles) in;
// For every triangle line we generate 2 triangles which can be done with 4 vertices so in total we will need 12 vertices
layout (triangle_strip, max_vertices = 12) out;
#else
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;
#ifdef GL_ARB_gpu_shader5
#endif
#ifdef FLAG_SHADOW_MAP
#ifdef GL_ARB_gpu_shader5
layout(invocations = 4) in;
#endif
#endif
#define MAX_LIGHTS 8
@@ -33,7 +42,7 @@ layout (std140) uniform modelData {
model_light lights[MAX_LIGHTS];
float extrudeWidth;
float outlineWidth;
float fogStart;
float fogScale;
int buffer_matrix_offset;
@@ -106,15 +115,13 @@ in VertexOutput {
#ifdef FLAG_FOG
float fogDist;
#endif
#ifdef WORKAROUND_CLIPPING_PLANES
#ifdef FLAG_TRANSFORM
float notVisible;
#endif
#endif
#ifdef FLAG_SHADOW_MAP
#if !defined(GL_ARB_gpu_shader5)
float instance;
#endif
#ifdef FLAG_TRANSFORM
float clipModel;
#endif
#else
vec4 position;
#endif
@@ -135,11 +142,6 @@ out VertexOutput {
#endif
#ifdef FLAG_FOG
float fogDist;
#endif
#ifdef WORKAROUND_CLIPPING_PLANES
#ifdef FLAG_TRANSFORM
float notVisible;
#endif
#endif
vec4 position;
vec3 normal;
@@ -150,6 +152,7 @@ out VertexOutput {
#endif
} vertOut;
#ifdef FLAG_SHADOW_MAP
void main(void)
{
#ifdef GL_ARB_gpu_shader5
@@ -159,14 +162,25 @@ void main(void)
#endif
for(int vert = 0; vert < gl_in.length(); vert++)
{
#ifdef FLAG_TRANSFORM
if (vertIn[vert].clipModel > 0.9) {
// If the model was clipped in the vertex shader then we do not apply the shadow projection matrix here
gl_Position = gl_in[vert].gl_Position;
} else {
gl_Position = shadow_proj_matrix[instanceID] * gl_in[vert].gl_Position;
}
#else
gl_Position = shadow_proj_matrix[instanceID] * gl_in[vert].gl_Position;
#endif
if(gl_Position.z < -1.0)
gl_Position.z = -1.0;
vertOut.position = gl_in[vert].gl_Position;
vertOut.normal = vertIn[vert].normal;
vertOut.texCoord = vertIn[vert].texCoord;
gl_Layer = instanceID;
#ifdef FLAG_ENV_MAP
vertOut.envReflect = vertIn[vert].envReflect;
#endif
@@ -183,19 +197,66 @@ void main(void)
vertOut.shadowUV[3] = vertIn[vert].shadowUV[3];
vertOut.shadowPos = vertIn[vert].shadowPos;
#endif
#ifdef WORKAROUND_CLIPPING_PLANES
#ifdef FLAG_TRANSFORM
vertOut.notVisible = vertIn[vert].notVisible;
#endif
#ifdef FLAG_CLIP
#if defined(FLAG_CLIP)
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
#endif
#else
#if defined(FLAG_CLIP) || defined(FLAG_TRANSFORM)
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
#endif
#endif
EmitVertex();
}
EndPrimitive();
}
#elif defined(FLAG_THICK_OUTLINE)
const vec2 pixelOffsetDir[4] = vec2[](
vec2(0.0, 1.0),
vec2(1.0, 1.0),
vec2(1.0, -1.0),
vec2(0.0, -1.0)
);
void main(void)
{
for(int vert = 0; vert < gl_in.length(); vert++)
{
int nextVert = (vert + 1) % gl_in.length();
vec4 clip = gl_in[vert].gl_Position;
vec4 diff = gl_in[nextVert].gl_Position - clip; // vector from vert to the next vertex in the list
vec2 normal = normalize(vec2(diff.y, -diff.x)); // Computing the normal of a 2D vector is actually rather simple...
for (int lineVert = 0; lineVert < 4; ++lineVert)
{
// This is the pixel offset along the normal axis
vec2 yOffPixel = pixelOffsetDir[lineVert].y * normal * (outlineWidth / 2.0);
// This is the offset of the vertex along the vector between this vertex and the next one in the triangle
vec2 xOff = pixelOffsetDir[lineVert].x * diff.xy;
// This is the final offset in clip space
vec2 finalOffset = xOff + yOffPixel * vec2(vpwidth, vpheight) * clip.w;
gl_Position = vec4(clip.xyz + vec3(finalOffset, 0.0), clip.w);
vertOut.position = vertIn[vert].position;
vertOut.normal = vertIn[vert].normal;
vertOut.texCoord = vertIn[vert].texCoord;
#ifdef FLAG_ENV_MAP
vertOut.envReflect = vertIn[vert].envReflect;
#endif
#ifdef FLAG_NORMAL_MAP
vertOut.tangentMatrix = vertIn[vert].tangentMatrix;
#endif
#ifdef FLAG_FOG
vertOut.fogDist = vertIn[vert].fogDist;
#endif
#ifdef FLAG_SHADOWS
vertOut.shadowUV[0] = vertIn[vert].shadowUV[0];
vertOut.shadowUV[1] = vertIn[vert].shadowUV[1];
vertOut.shadowUV[2] = vertIn[vert].shadowUV[2];
vertOut.shadowUV[3] = vertIn[vert].shadowUV[3];
vertOut.shadowPos = vertIn[vert].shadowPos;
#endif
#if defined(FLAG_CLIP)
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
#endif
EmitVertex();
}
EndPrimitive();
}
}
#endif
+20 -36
View File
@@ -36,7 +36,7 @@ layout (std140) uniform modelData {
model_light lights[MAX_LIGHTS];
float extrudeWidth;
float outlineWidth;
float fogStart;
float fogScale;
int buffer_matrix_offset;
@@ -113,15 +113,15 @@ out VertexOutput {
#ifdef FLAG_FOG
float fogDist;
#endif
#ifdef WORKAROUND_CLIPPING_PLANES
#ifdef FLAG_TRANSFORM
float notVisible;
#endif
#endif
#ifdef FLAG_SHADOW_MAP
#if !defined(GL_ARB_gpu_shader5)
float instance;
#endif
#ifdef FLAG_TRANSFORM
// This flag is needed to let the geometry shader know that it doesn't need to apply the
// shadow projection to gl_Position
float clipModel;
#endif
#else
vec4 position;
#endif
@@ -152,19 +152,9 @@ void main()
vec4 texCoord;
mat4 orient = mat4(1.0);
mat4 scale = mat4(1.0);
#ifdef WORKAROUND_CLIPPING_PLANES
#ifdef FLAG_TRANSFORM
#ifdef FLAG_TRANSFORM
bool clipModel;
getModelTransform(orient, clipModel, int(vertModelID), buffer_matrix_offset);
vertOut.notVisible = clipModel ? 1.0 : 0.0;
#endif
#else
#ifdef FLAG_TRANSFORM
bool clipModel;
getModelTransform(orient, clipModel, int(vertModelID), buffer_matrix_offset);
#else
bool clipModel = false;
#endif
#endif
texCoord = textureMatrix * vertTexCoord;
vec4 vertex = vertPosition;
@@ -188,9 +178,6 @@ void main()
#else
gl_Position = projMatrix * position;
#endif
#ifdef FLAG_NORMAL_EXTRUDE
gl_Position.xy += (mat3(projMatrix) * normal.xyz).xy * gl_Position.z * extrudeWidth;
#endif
#ifdef FLAG_SHADOWS
vec4 shadowPos = shadow_mv_matrix * modelMatrix * orient * vertPosition;
vertOut.shadowPos = shadow_mv_matrix * modelMatrix * orient * vertPosition;
@@ -213,31 +200,28 @@ void main()
#ifdef FLAG_FOG
vertOut.fogDist = clamp((gl_Position.z - fogStart) * 0.75 * fogScale, 0.0, 1.0);
#endif
#ifdef WORKAROUND_CLIPPING_PLANES
if(use_clip_plane) {
gl_ClipDistance[0] = dot(clip_equation, modelMatrix * orient * vertex);
} else {
gl_ClipDistance[0] = 1.0;
}
#else
#ifdef FLAG_CLIP
#ifdef FLAG_TRANSFORM
if (clipModel) {
gl_ClipDistance[0] = -1.0;
} else if(use_clip_plane) {
// Clip this model by moving all vertices outside the clip volume
gl_Position = vec4(vec3(-2.0), 1.0);
}
#ifdef FLAG_SHADOW_MAP
vertOut.clipModel = clipModel ? 1.0 : 0.0;
#endif
#endif
#ifdef FLAG_CLIP
if(use_clip_plane) {
gl_ClipDistance[0] = dot(clip_equation, modelMatrix * orient * vertex);
} else {
gl_ClipDistance[0] = 1.0;
}
#elif defined(FLAG_TRANSFORM)
gl_ClipDistance[0] = clipModel ? -1.0 : 1.0;
#endif
#endif
#ifndef FLAG_SHADOW_MAP
#ifndef FLAG_SHADOW_MAP
vertOut.position = position;
vertOut.normal = normal;
vertOut.texCoord = texCoord;
#else
#else
vertOut.normal = normal;
vertOut.texCoord = texCoord;
#endif
#endif
}
@@ -0,0 +1,17 @@
in vec2 fragTexCoord;
in vec4 fragColor;
out vec4 fragOut0;
uniform bool textured;
uniform sampler2DArray baseMap;
uniform int baseMapIndex;
void main() {
if (textured) {
fragOut0 = texture(baseMap, vec3(fragTexCoord, float(baseMapIndex))) * fragColor;
} else {
fragOut0 = fragColor;
}
}
@@ -0,0 +1,18 @@
in vec2 vertPosition;
in vec4 vertColor;
in vec2 vertTexCoord;
out vec2 fragTexCoord;
out vec4 fragColor;
uniform mat4 modelViewMatrix;
uniform mat4 projMatrix;
void main()
{
fragTexCoord = vertTexCoord;
fragColor = vertColor;
gl_Position = projMatrix * modelViewMatrix * vec4(vertPosition, 0.0, 1.0);
}
@@ -0,0 +1,36 @@
local exts = {
"",
".lua",
".lc"
}
local function cfileLoader(name)
local file = nil
for i,v in ipairs(exts) do
local real_name = name .. v
file = cf.openFile(real_name, "r", "data/scripts")
if (file:isValid()) then
name = real_name
break;
end
end
if (file == nil or not file:isValid()) then
return "Module '" .. name .. "' is not known by the CFile system"
end
local content = file:read("*a")
file:close()
local func, err = loadstring(content, name)
if err then
return err
end
return func
end
table.insert(package.loaders, 2, cfileLoader)
+6 -3
View File
@@ -5,7 +5,7 @@ IF(MSVC)
set(RES_CONTENT)
set(ARRAY_ELEMENTS)
FOREACH(file ${file_root_def_files_files})
FOREACH(file ${default_files_files})
set(INPUT_NAME "${CMAKE_CURRENT_SOURCE_DIR}/${file}")
SET(OUTPUT "${GENERATED_SOURCE_DIR}/code/${file}")
file(RELATIVE_PATH RELATIVE_FILE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/def_files" "${INPUT_NAME}")
@@ -39,7 +39,7 @@ else()
set(INCLUDE_LIST)
set(ARRAY_ELEMENTS)
FOREACH(file ${file_root_def_files_files})
FOREACH(file ${default_files_files})
set(INPUT_NAME "${CMAKE_CURRENT_SOURCE_DIR}/${file}")
SET(OUTPUT "${GENERATED_SOURCE_DIR}/code/${file}")
file(RELATIVE_PATH RELATIVE_FILE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/def_files" "${INPUT_NAME}")
@@ -53,8 +53,11 @@ else()
file(TO_NATIVE_PATH "${PATH_TYPE}" PATH_TYPE)
if (MINGW)
# There is a bug in CMake where it thinks MinGW uses forward slashes for paths but we need backslashes for Windows builds
string(REPLACE "/" "\\\\" PATH_TYPE "${PATH_TYPE}")
string(REPLACE "/" "\\" PATH_TYPE "${PATH_TYPE}")
endif()
# Properly escape back slashes in strings
string(REPLACE "\\" "\\\\" PATH_TYPE "${PATH_TYPE}")
GET_FILENAME_COMPONENT(FILE_NAME "${RELATIVE_FILE_PATH}" NAME)
string(MAKE_C_IDENTIFIER "${RELATIVE_FILE_PATH}" FIELD_NAME)
+15
View File
@@ -0,0 +1,15 @@
#include "events.h"
namespace events {
util::event<void> EngineUpdate;
util::event<void> EngineShutdown;
util::event<void, int, int> GameLeaveState;
util::event<void, int, int> GameEnterState;
util::event<void, const char*> GameMissionLoad;
}
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include "utils/event.h"
namespace events {
extern util::event<void> EngineUpdate;
extern util::event<void> EngineShutdown;
extern util::event<void, int, int> GameLeaveState;
extern util::event<void, int, int> GameEnterState;
extern util::event<void, const char*> GameMissionLoad;
}
+230 -166
View File
@@ -26,18 +26,10 @@
#include <cstdlib>
// make use of the LOD checker for tbl/tbm parsing (from weapons.cpp)
extern SCP_vector<lod_checker> LOD_checker;
static SCP_vector<color> LOD_color;
int Warp_model;
int Knossos_warp_ani_used;
#define WARPHOLE_GROW_TIME (2.35f) // time for warphole to reach max size (also time to shrink to nothing once it begins to shrink)
#define MAX_FIREBALL_LOD 4
#define MAX_FIREBALLS 200
#define MAX_WARP_LOD 0
@@ -51,10 +43,8 @@ int fireball_used[MAX_FIREBALL_TYPES];
int Num_fireballs = 0;
int Num_fireball_types = 0;
int fireballs_inited = 0;
int Warp_glow_bitmap = -1;
int Warp_ball_bitmap = -1;
bool fireballs_inited = false;
bool fireballs_parsed = false;
#define FB_INDEX(fb) (fb-Fireballs)
@@ -114,12 +104,53 @@ void fireball_play_warphole_close_sound(fireball *fb)
snd_play_3d(gamesnd_get_game_sound(sound_index), &fireball_objp->pos, &Eye_position, fireball_objp->radius); // play warp sound effect
}
static void fireball_generate_unique_id(char *unique_id, int buffer_len, int fireball_index)
{
Assert((fireball_index >= 0) && (fireball_index < MAX_FIREBALL_TYPES));
switch (fireball_index)
{
// use sensible names for the fireball.tbl default entries
case FIREBALL_EXPLOSION_MEDIUM:
strncpy(unique_id, "Medium Explosion", buffer_len);
break;
case FIREBALL_WARP:
strncpy(unique_id, "Warp Effect", buffer_len);
break;
case FIREBALL_KNOSSOS:
strncpy(unique_id, "Knossos Effect", buffer_len);
break;
case FIREBALL_ASTEROID:
strncpy(unique_id, "Asteroid Explosion", buffer_len);
break;
case FIREBALL_EXPLOSION_LARGE1:
strncpy(unique_id, "Large Explosion 1", buffer_len);
break;
case FIREBALL_EXPLOSION_LARGE2:
strncpy(unique_id, "Large Explosion 2", buffer_len);
break;
// base the id on the index
default:
snprintf(unique_id, buffer_len, "Custom Fireball %d", fireball_index - NUM_DEFAULT_FIREBALLS + 1);
break;
}
// null-terminate
unique_id[buffer_len - 1] = '\0';
}
/**
* Set default colors for each explosion type (original values from object.cpp)
*/
static void fireball_set_default_color(int idx)
{
Assert( (idx >= 0) && (idx < MAX_FIREBALL_TYPES) );
Assert((idx >= 0) && (idx < MAX_FIREBALL_TYPES));
switch (idx)
{
@@ -153,71 +184,148 @@ static void fireball_set_default_color(int idx)
}
}
static void fireball_set_default_warp_attributes(int idx)
{
Assert((idx >= 0) && (idx < MAX_FIREBALL_TYPES));
switch (idx)
{
case FIREBALL_WARP:
case FIREBALL_KNOSSOS:
strcpy_s(Fireball_info[idx].warp_glow, "warpglow01");
strcpy_s(Fireball_info[idx].warp_ball, "warpball01");
strcpy_s(Fireball_info[idx].warp_model, "warp.pof");
break;
}
}
void fireball_info_clear(fireball_info *fb)
{
Assert(fb != nullptr);
memset(fb, 0, sizeof(fireball_info));
for (int i = 0; i < MAX_FIREBALL_LOD; ++i)
fb->lod[i].bitmap_id = -1;
fb->warp_glow_bitmap = -1;
fb->warp_ball_bitmap = -1;
fb->warp_model_id = -1;
}
int fireball_info_lookup(const char *unique_id)
{
for (int i = 0; i < Num_fireball_types; ++i)
if (!stricmp(Fireball_info[i].unique_id, unique_id))
return i;
return -1;
}
/**
* Parse fireball tbl
*
* NOTE: we can't be too trusting here so a tbm will only modify the LOD count, not add an entry
*/
void parse_fireball_tbl(const char *filename)
static void parse_fireball_tbl(const char *table_filename)
{
lod_checker lod_check;
color fb_color;
try
{
read_file_text(filename, CF_TYPE_TABLES);
read_file_text(table_filename, CF_TYPE_TABLES);
reset_parse();
required_string("#Start");
while (required_string_either("#End", "$Name:")) {
memset(&lod_check, 0, sizeof(lod_checker));
while (required_string_one_of(3, "#End", "$Name:", "$Unique ID:"))
{
fireball_info *fi;
int existing_idx = -1;
char unique_id[NAME_LENGTH];
char fireball_filename[MAX_FILENAME_LEN];
// unique ID, because indexes are unpredictable
memset(unique_id, 0, NAME_LENGTH);
if (optional_string("$Unique ID:"))
stuff_string(unique_id, F_NAME, NAME_LENGTH);
// base filename
required_string("$Name:");
stuff_string(lod_check.filename, F_NAME, MAX_FILENAME_LEN);
stuff_string(fireball_filename, F_NAME, MAX_FILENAME_LEN);
lod_check.override = -1;
// find out if we are overriding a previous entry;
// per precedent, these strings should only be in TBMs
// UNLIKE precedent, we can now add fireballs in modular tables, not just replace them
if (Parsing_modular_table)
{
if (optional_string("+Explosion_Medium"))
existing_idx = FIREBALL_EXPLOSION_MEDIUM;
else if (optional_string("+Warp_Effect"))
existing_idx = FIREBALL_WARP;
else if (optional_string("+Knossos_Effect"))
existing_idx = FIREBALL_KNOSSOS;
else if (optional_string("+Asteroid"))
existing_idx = FIREBALL_ASTEROID;
else if (optional_string("+Explosion_Large1"))
existing_idx = FIREBALL_EXPLOSION_LARGE1;
else if (optional_string("+Explosion_Large2"))
existing_idx = FIREBALL_EXPLOSION_LARGE2;
else if (optional_string("+Custom_Fireball"))
stuff_int(&existing_idx);
// these entries should only be in TBMs, and it has to include at least one
if (Parsing_modular_table) {
if (optional_string("+Explosion_Medium")) {
lod_check.override = FIREBALL_EXPLOSION_MEDIUM;
}
else if (optional_string("+Warp_Effect")) {
lod_check.override = FIREBALL_WARP;
}
else if (optional_string("+Knossos_Effect")) {
lod_check.override = FIREBALL_KNOSSOS;
}
else if (optional_string("+Asteroid")) {
lod_check.override = FIREBALL_ASTEROID;
}
else if (optional_string("+Explosion_Large1")) {
lod_check.override = FIREBALL_EXPLOSION_LARGE1;
}
else if (optional_string("+Explosion_Large2")){
lod_check.override = FIREBALL_EXPLOSION_LARGE2;
}
else {
required_string("+Custom_Fireball");
stuff_int(&lod_check.override);
// we can ALSO override a previous entry by specifying a previously used unique ID
// either way will work, but if both are specified, unique ID takes precedence
if (strlen(unique_id) > 0)
{
int temp_idx = fireball_info_lookup(unique_id);
if (temp_idx >= 0)
existing_idx = temp_idx;
}
}
lod_check.num_lods = 1;
// now select our entry accordingly...
// are we using a previous entry?
if (existing_idx >= 0)
{
fi = &Fireball_info[existing_idx];
}
// we are creating a new entry, so set some defaults
else
{
// make sure we don't exceed the max
if (Num_fireball_types >= MAX_FIREBALL_TYPES)
{
error_display(0, "Too many fireball entries! Max is %d", MAX_FIREBALL_TYPES);
return;
}
// Do we have an LOD num
if (optional_string("$LOD:")) {
stuff_int(&lod_check.num_lods);
fi = &Fireball_info[Num_fireball_types];
fireball_info_clear(fi);
// If the table didn't specify a unique ID, generate one. This will be assigned a few lines later.
if (strlen(unique_id) == 0)
fireball_generate_unique_id(unique_id, NAME_LENGTH, Num_fireball_types);
// Set remaining fireball defaults
fireball_set_default_color(Num_fireball_types);
fireball_set_default_warp_attributes(Num_fireball_types);
Num_fireball_types++;
}
if (lod_check.num_lods > MAX_FIREBALL_LOD) {
lod_check.num_lods = MAX_FIREBALL_LOD;
// copy over what we already parsed
if (strlen(unique_id) > 0)
strcpy_s(fi->unique_id, unique_id);
strcpy_s(fi->lod[0].filename, fireball_filename);
// Do we have a LOD num?
if (optional_string("$LOD:"))
{
stuff_int(&fi->lod_count);
if (fi->lod_count > MAX_FIREBALL_LOD)
fi->lod_count = MAX_FIREBALL_LOD;
}
// check for particular lighting color
if (optional_string("$Light color:")) {
if (optional_string("$Light color:"))
{
int r, g, b;
stuff_int(&r);
@@ -228,90 +336,57 @@ void parse_fireball_tbl(const char *filename)
CLAMP(g, 0, 255);
CLAMP(b, 0, 255);
gr_init_color(&fb_color, r, g, b);
}
else {
// to keep things simple, we just use 0 alpha to indicate that a default value should be used
memset(&fb_color, 0, sizeof(color));
fi->exp_color[0] = (r / 255.0f);
fi->exp_color[1] = (g / 255.0f);
fi->exp_color[2] = (b / 255.0f);
}
// we may use one filename for multiple entries so we'll have to handle dupes post parse
LOD_checker.push_back(lod_check);
LOD_color.push_back(fb_color);
// check for custom warp glow
if (optional_string("$Warp glow:"))
stuff_string(fi->warp_glow, F_NAME, NAME_LENGTH);
// check for custom warp ball
if (optional_string("$Warp ball:"))
stuff_string(fi->warp_ball, F_NAME, NAME_LENGTH);
// check for custom warp model
if (optional_string("$Warp model:"))
stuff_string(fi->warp_model, F_NAME, NAME_LENGTH);
}
required_string("#End");
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", table_filename, e.what()));
return;
}
}
void fireball_parse_tbl()
{
int i = 0, j;
SCP_vector<lod_checker>::iterator lod;
memset( &Fireball_info, 0, sizeof(fireball_info) * MAX_FIREBALL_TYPES );
if (fireballs_parsed)
return;
// every newly parsed fireball_info will get cleared before being added
// must do this outside of parse_fireball_tbl because it's called twice
Num_fireball_types = 0;
parse_fireball_tbl("fireball.tbl");
// look for any modular tables
parse_modular_table(NOX("*-fbl.tbm"), parse_fireball_tbl);
// we've got our list so pass it off for final checking and loading.
// we assume that entries in fireball.tbl are in the correct order
for (lod = LOD_checker.begin(); lod != LOD_checker.end(); ++lod) {
if ( (i < MAX_FIREBALL_TYPES) && (lod->override < 0) ) {
strcpy_s( Fireball_info[i].lod[0].filename, lod->filename );
Fireball_info[i].lod_count = lod->num_lods;
Num_fireball_types++;
if (LOD_color[i].alpha == 255) {
Fireball_info[i].exp_color[0] = (LOD_color[i].red / 255.0f);
Fireball_info[i].exp_color[1] = (LOD_color[i].green / 255.0f);
Fireball_info[i].exp_color[2] = (LOD_color[i].blue / 255.0f);
} else {
fireball_set_default_color(i);
}
}
i++;
}
// having to do this twice is less than optimal, but less error prone too.
// this handles (and should only have to handle) TBM related entries
i = 0;
for (lod = LOD_checker.begin(); lod != LOD_checker.end(); ++lod) {
// try entry replacement
if ( (lod->override >= 0) && (lod->override < Num_fireball_types) ) {
strcpy_s( Fireball_info[lod->override].lod[0].filename, lod->filename );
Fireball_info[lod->override].lod_count = lod->num_lods;
if (LOD_color[i].alpha == 255) {
Fireball_info[lod->override].exp_color[0] = (LOD_color[i].red / 255.0f);
Fireball_info[lod->override].exp_color[1] = (LOD_color[i].green / 255.0f);
Fireball_info[lod->override].exp_color[2] = (LOD_color[i].blue / 255.0f);
} else {
fireball_set_default_color(lod->override);
}
}
}
// fill in extra LOD filenames
for (i = 0; i < Num_fireball_types; i++) {
for (j = 1; j < Fireball_info[i].lod_count; j++) {
for (int i = 0; i < Num_fireball_types; i++)
{
for (int j = 1; j < Fireball_info[i].lod_count; j++)
sprintf( Fireball_info[i].lod[j].filename, "%s_%d", Fireball_info[i].lod[0].filename, j);
}
}
// done
LOD_checker.clear();
fireballs_parsed = true;
}
void fireball_load_data()
{
int i, idx;
@@ -330,13 +405,20 @@ void fireball_load_data()
Error(LOCATION, "Could not load %s anim file\n", fd->lod[idx].filename);
}
}
}
if ( Warp_glow_bitmap == -1 ) {
Warp_glow_bitmap = bm_load( NOX("warpglow01") );
}
if ( Warp_ball_bitmap == -1 ) {
Warp_ball_bitmap = bm_load( NOX("warpball01") );
if (strlen(fd->warp_glow) > 0) {
mprintf(("Loading warp glow '%s'\n", fd->warp_glow));
fd->warp_glow_bitmap = bm_load(fd->warp_glow);
} else {
fd->warp_glow_bitmap = -1;
}
if (strlen(fd->warp_ball) > 0) {
mprintf(("Loading warp ball '%s'\n", fd->warp_ball));
fd->warp_ball_bitmap = bm_load(fd->warp_ball);
} else {
fd->warp_ball_bitmap = -1;
}
}
}
@@ -346,11 +428,11 @@ void fireball_init()
int i;
if ( !fireballs_inited ) {
fireballs_inited = 1;
// Do all the processing that happens only once
fireball_parse_tbl();
fireball_load_data();
fireballs_inited = true;
}
// Reset everything between levels
@@ -361,17 +443,6 @@ void fireball_init()
// Goober5000 - reset Knossos warp flag
Knossos_warp_ani_used = 0;
mprintf(("Loading warp model\n"));
Warp_model = -1;
// Goober5000 - check for existence of file before trying to load it
if (cf_exists_full("warp.pof", CF_TYPE_MODELS))
{
Warp_model = model_load("warp.pof", 0, NULL, 0);
}
mprintf((" %d\n", Warp_model));
}
MONITOR( NumFireballsRend )
@@ -543,7 +614,7 @@ void fireball_maybe_play_warp_close_sound(fireball *fb)
life_left = fb->total_time - fb->time_elapsed;
if ( life_left < WARPHOLE_GROW_TIME ) {
if ( life_left < fb->warp_close_duration ) {
fireball_play_warphole_close_sound(fb);
fb->flags |= FBF_WARP_CLOSE_SOUND_PLAYED;
}
@@ -696,7 +767,7 @@ int fireball_get_lod(vec3d *pos, fireball_info *fd, float size)
/**
* Create a fireball, return object index.
*/
int fireball_create( vec3d * pos, int fireball_type, int render_type, int parent_obj, float size, int reverse, vec3d *velocity, float warp_lifetime, int ship_class, matrix *orient_override, int low_res, int extra_flags, gamesnd_id warp_open_sound, gamesnd_id warp_close_sound)
int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_obj, float size, int reverse, vec3d *velocity, float warp_lifetime, int ship_class, matrix *orient_override, int low_res, int extra_flags, gamesnd_id warp_open_sound, gamesnd_id warp_close_sound, float warp_open_duration, float warp_close_duration)
{
int n, objnum, fb_lod;
object *obj;
@@ -757,6 +828,8 @@ int fireball_create( vec3d * pos, int fireball_type, int render_type, int parent
fb->flags = extra_flags;
fb->warp_open_sound_index = warp_open_sound;
fb->warp_close_sound_index = warp_close_sound;
fb->warp_open_duration = (warp_open_duration < 0.0f) ? WARPHOLE_GROW_TIME : warp_open_duration;
fb->warp_close_duration = (warp_close_duration < 0.0f) ? WARPHOLE_GROW_TIME : warp_close_duration;
matrix orient;
if(orient_override != NULL){
@@ -861,9 +934,9 @@ void fireballs_page_in()
fireball_info *fd;
for ( i = 0; i < Num_fireball_types; i++ ) {
if((i < NUM_DEFAULT_FIREBALLS) || fireball_used[i]){
fd = &Fireball_info[i];
fd = &Fireball_info[i];
if((i < NUM_DEFAULT_FIREBALLS) || fireball_used[i]) {
// if this is a Knossos ani, only load if Knossos_warp_ani_used is true
if ( (i == FIREBALL_KNOSSOS) && !Knossos_warp_ani_used)
continue;
@@ -876,10 +949,19 @@ void fireballs_page_in()
bm_page_in_texture( fd->lod[idx].bitmap_id, fd->lod[idx].num_frames );
}
}
}
bm_page_in_texture( Warp_glow_bitmap );
bm_page_in_texture( Warp_ball_bitmap );
// page in glow and ball bitmaps, if we have any
bm_page_in_texture(fd->warp_glow_bitmap);
bm_page_in_texture(fd->warp_ball_bitmap);
// load the warp model, if we have one
if (strlen(fd->warp_model) > 0 && cf_exists_full(fd->warp_model, CF_TYPE_MODELS)) {
mprintf(("Loading warp model '%s'\n", fd->warp_model));
fd->warp_model_id = model_load(fd->warp_model, 0, nullptr, 0);
} else {
fd->warp_model_id = -1;
}
}
}
void fireball_get_color(int idx, float *red, float *green, float *blue)
@@ -941,30 +1023,23 @@ int fireball_asteroid_explosion_type(asteroid_info *aip)
return index;
}
float fireball_wormhole_intensity( object *obj )
float fireball_wormhole_intensity(fireball *fb)
{
int num, objnum;
fireball *fb;
num = obj->instance;
objnum = OBJ_INDEX(obj);
Assertion( Fireballs[num].objnum == objnum, "Basic sanity check. Fireballs[num].objnum (%d) should == objnum (%d)", Fireballs[num].objnum, objnum );
fb = &Fireballs[num];
float t = fb->time_elapsed;
float rad;
if ( t < WARPHOLE_GROW_TIME ) {
rad = (float)pow(t/WARPHOLE_GROW_TIME,0.4f);
} else if ( t < fb->total_time - WARPHOLE_GROW_TIME ) {
rad = 1;
if ( t < fb->warp_open_duration ) {
rad = (float)pow(t / fb->warp_open_duration, 0.4f);
} else if ( t < fb->total_time - fb->warp_close_duration ) {
rad = 1.0f;
} else {
rad = (float)pow((fb->total_time - t)/WARPHOLE_GROW_TIME,0.4f);
rad = (float)pow((fb->total_time - t) / fb->warp_close_duration, 0.4f);
}
return rad;
}
extern void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, vec3d *pos, int texture_bitmap_num, float radius, float life_percent, float max_radius, bool warp_3d, int warp_glow_bitmap, int warp_ball_bitmap, int warp_model_id);
void fireball_render(object* obj, model_draw_list *scene)
{
int num;
@@ -996,21 +1071,10 @@ void fireball_render(object* obj, model_draw_list *scene)
case FIREBALL_WARP_EFFECT: {
float percent_life = fb->time_elapsed / fb->total_time;
float rad = obj->radius * fireball_wormhole_intensity(fb);
float rad;
// Code to make effect grow/shrink.
float t = fb->time_elapsed;
if ( t < WARPHOLE_GROW_TIME ) {
rad = (float)pow(t/WARPHOLE_GROW_TIME,0.4f)*obj->radius;
} else if ( t < fb->total_time - WARPHOLE_GROW_TIME ) {
rad = obj->radius;
} else {
rad = (float)pow((fb->total_time - t)/WARPHOLE_GROW_TIME,0.4f)*obj->radius;
}
warpin_queue_render(scene, obj, &obj->orient, &obj->pos, Fireballs[num].current_bitmap, rad, percent_life, obj->radius, (Fireballs[num].flags & FBF_WARP_3D) );
fireball_info *fi = &Fireball_info[fb->fireball_info_index];
warpin_queue_render(scene, obj, &obj->orient, &obj->pos, fb->current_bitmap, rad, percent_life, obj->radius, (fb->flags & FBF_WARP_3D) != 0, fi->warp_glow_bitmap, fi->warp_ball_bitmap, fi->warp_model_id);
}
break;
+28 -14
View File
@@ -36,10 +36,11 @@ class asteroid_info;
#define MAX_FIREBALL_TYPES 32 // The maximum number of fireballs that can be defined
#define NUM_DEFAULT_FIREBALLS 6
#define MAX_FIREBALL_LOD 4
#define FIREBALL_NUM_LARGE_EXPLOSIONS 2
extern int fireball_used[MAX_FIREBALL_TYPES];
extern int Num_fireball_types;
// all this moved here by Goober5000 because it makes more sense in the H file
typedef struct fireball_lod {
@@ -50,11 +51,22 @@ typedef struct fireball_lod {
} fireball_lod;
typedef struct fireball_info {
char unique_id[NAME_LENGTH];
int lod_count;
float exp_color[3];
fireball_lod lod[4];
fireball_lod lod[MAX_FIREBALL_LOD];
float exp_color[3]; // red, green, blue
char warp_glow[NAME_LENGTH];
int warp_glow_bitmap;
char warp_ball[NAME_LENGTH];
int warp_ball_bitmap;
char warp_model[NAME_LENGTH];
int warp_model_id;
} fireball_info;
extern fireball_info Fireball_info[MAX_FIREBALL_TYPES];
extern int Num_fireball_types;
// flag values for fireball struct flags member
#define FBF_WARP_CLOSE_SOUND_PLAYED (1<<0)
#define FBF_WARP_CAPITAL_SIZE (1<<1)
@@ -72,8 +84,12 @@ typedef struct fireball {
char lod; // current LOD
float time_elapsed; // in seconds
float total_time; // total lifetime of animation in seconds
gamesnd_id warp_open_sound_index; // for warp-effect - Goober5000
gamesnd_id warp_close_sound_index; // for warp-effect - Goober5000
// for warp-effect - Goober5000
gamesnd_id warp_open_sound_index;
gamesnd_id warp_close_sound_index;
float warp_open_duration;
float warp_close_duration;
} fireball;
// end move
@@ -82,10 +98,15 @@ void fireball_render(object* obj, model_draw_list *scene);
void fireball_delete( object * obj );
void fireball_process_post(object * obj, float frame_time);
// This does not load all the data, just the filenames and such. Only used by FRED.
void fireball_parse_tbl();
int fireball_info_lookup(const char *unique_id);
// reversed is for warp_in/out effects
// Velocity: If not NULL, the fireball will move at a constant velocity.
// warp_lifetime: If warp_lifetime > 0.0f then makes the explosion loop so it lasts this long. Only works for warp effect
int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_obj, float size, int reversed=0, vec3d *velocity=NULL, float warp_lifetime=0.0f, int ship_class=-1, matrix *orient=NULL, int low_res=0, int extra_flags=0, gamesnd_id warp_open_sound=gamesnd_id(), gamesnd_id warp_close_sound=gamesnd_id());
int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_obj, float size, int reversed=0, vec3d *velocity=nullptr, float warp_lifetime=0.0f, int ship_class=-1, matrix *orient=nullptr, int low_res=0, int extra_flags=0, gamesnd_id warp_open_sound=gamesnd_id(), gamesnd_id warp_close_sound=gamesnd_id(), float warp_open_duration=-1.0f, float warp_close_duration=-1.0f);
void fireball_render_plane(int plane);
void fireball_close();
@@ -111,14 +132,7 @@ int fireball_ship_explosion_type(ship_info *sip);
int fireball_asteroid_explosion_type(asteroid_info *aip);
// returns the intensity of a wormhole
float fireball_wormhole_intensity( object *obj );
// internal function to draw warp grid.
extern void warpin_render(object *obj, matrix *orient, vec3d *pos, int texture_bitmap_num, float radius, float life_percent, float max_radius, int warp_3d = 0 );
extern void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, vec3d *pos, int texture_bitmap_num, float radius, float life_percent, float max_radius, int warp_3d);
extern int Warp_model;
float fireball_wormhole_intensity( fireball *fb );
// Goober5000
extern int Knossos_warp_ani_used;
+8 -12
View File
@@ -21,10 +21,6 @@
#include "render/batching.h"
#include "ship/ship.h"
extern int Warp_model;
extern int Warp_glow_bitmap;
extern int Warp_ball_bitmap;
void warpin_batch_draw_face( int texture, vertex *v1, vertex *v2, vertex *v3 )
{
vec3d norm;
@@ -45,7 +41,7 @@ void warpin_batch_draw_face( int texture, vertex *v1, vertex *v2, vertex *v3 )
batching_add_tri(texture, vertlist); // TODO render as emissive
}
void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, vec3d *pos, int texture_bitmap_num, float radius, float life_percent, float max_radius, int warp_3d)
void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, vec3d *pos, int texture_bitmap_num, float radius, float life_percent, float max_radius, bool warp_3d, int warp_glow_bitmap, int warp_ball_bitmap, int warp_model_id)
{
vec3d center;
vec3d vecs[5];
@@ -60,7 +56,7 @@ void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, ve
verts[1] = verts[2] = verts[3] = verts[4] = verts[0];
if (Warp_glow_bitmap >= 0) {
if (warp_glow_bitmap >= 0) {
float r = radius;
bool render_it = true;
@@ -99,12 +95,12 @@ void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, ve
float alpha = (The_mission.flags[Mission::Mission_Flags::Fullneb]) ? (1.0f - neb2_get_fog_intensity(obj)) : 1.0f;
//batch_add_bitmap(Warp_glow_bitmap, TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT, &verts[4], 0, r, alpha);
batching_add_bitmap(Warp_glow_bitmap, &verts[4], 0, r, alpha);
//batch_add_bitmap(warp_glow_bitmap, TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT, &verts[4], 0, r, alpha);
batching_add_bitmap(warp_glow_bitmap, &verts[4], 0, r, alpha);
}
}
if ( (Warp_model >= 0) && (warp_3d || Cmdline_3dwarp) ) {
if ( (warp_model_id >= 0) && (warp_3d || Cmdline_3dwarp) ) {
model_render_params render_info;
float scale = radius / 25.0f;
@@ -119,7 +115,7 @@ void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, ve
render_info.set_detail_level_lock((int)(dist / (radius * 10.0f)));
render_info.set_flags(MR_NO_LIGHTING | MR_NORMAL | MR_NO_FOGGING | MR_NO_CULL | MR_NO_BATCH);
model_render_queue( &render_info, scene, Warp_model, orient, pos);
model_render_queue( &render_info, scene, warp_model_id, orient, pos);
} else {
float Grid_depth = radius/2.5f;
@@ -171,14 +167,14 @@ void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, ve
warpin_batch_draw_face( texture_bitmap_num, &verts[0], &verts[3], &verts[4] );
}
if (Warp_ball_bitmap > -1 && Cmdline_warp_flash == 1) {
if (warp_ball_bitmap >= 0 && Cmdline_warp_flash) {
flash_ball warp_ball(20, .1f,.25f, &orient->vec.fvec, pos, 4.0f, 0.5f);
float adg = (2.0f * life_percent) - 1.0f;
float pct = (powf(adg, 4.0f) - powf(adg, 128.0f)) * 4.0f;
if (pct > 0.00001f) {
warp_ball.render(Warp_ball_bitmap, max_radius * pct * 0.5f, adg * adg, adg * adg * 6.0f);
warp_ball.render(warp_ball_bitmap, max_radius * pct * 0.5f, adg * adg, adg * adg * 6.0f);
}
}
}
+1 -1
View File
@@ -1101,7 +1101,7 @@ void fs2netd_store_stats()
if (Duplicate_login_detected) {
Duplicate_login_detected = false;
multi_display_chat_msg( XSTR("<Duplicate login detected - stats have been tossed>", 1582), 0, 0 );
ml_string( XSTR("<Duplicate login detected - stats have been tossed>", 1583) );
ml_string( XSTR("<Duplicate login detected - stats have been tossed>", 1582) );
fs2netd_store_stats_results();
return;
}
+1 -1
View File
@@ -483,7 +483,7 @@ void parse_helptbl(const char *filename)
break;
case 4: // $end
default:
Assertion(false, "This should never happen.\n");
UNREACHABLE("This should never happen.\n");
break;
}
} // end while
+3 -3
View File
@@ -404,9 +404,9 @@ int gameseq_process_events()
state_reentry--;
return gs[gs_current_stack].current_state;
}
}
int gameseq_get_event_idx(char *s)
int gameseq_get_event_idx(const char* s)
{
for(int i = 0; i < Num_gs_event_text; i++)
{
@@ -418,7 +418,7 @@ int gameseq_get_event_idx(char *s)
return -1;
}
int gameseq_get_state_idx(char *s)
int gameseq_get_state_idx(const char* s)
{
for(int i = 0; i < Num_gs_state_text; i++)
{
+2 -2
View File
@@ -197,8 +197,8 @@ void game_do_state(int current_state);
bool GameState_Stack_Valid();
//WMC
int gameseq_get_event_idx(char *s);
int gameseq_get_state_idx(char *s);
int gameseq_get_event_idx(const char* s);
int gameseq_get_state_idx(const char* s);
//zookeeper
int gameseq_get_state_idx(int state);
+14 -14
View File
@@ -19,7 +19,7 @@
SCP_vector<game_snd> Snds;
SCP_vector<game_snd> Snds_iface;
SCP_vector<int> Snds_iface_handle;
SCP_vector<sound_handle> Snds_iface_handle;
// jg18 - default priorities and limits for retail gameplay sounds
static const int NUM_RETAIL_GAMEPLAY_SOUNDS = 192; // indices 0-191, from retail sounds.tbl
@@ -260,7 +260,7 @@ void gamesnd_add_retail_default_enhanced_sound_data()
void gamesnd_play_iface(interface_snd_id n)
{
if (Snds_iface_handle[n.value()] >= 0)
if (Snds_iface_handle[n.value()].isValid())
snd_stop(Snds_iface_handle[n.value()]);
Snds_iface_handle[n.value()] = snd_play(gamesnd_get_interface_sound(n));
@@ -565,9 +565,9 @@ void gamesnd_unload_gameplay_sounds()
Assert( Snds.size() <= INT_MAX );
for (SCP_vector<game_snd>::iterator gs = Snds.begin(); gs != Snds.end(); ++gs) {
for (auto& entry : gs->sound_entries) {
if (entry.id != -1) {
if (entry.id.isValid()) {
snd_unload(entry.id);
entry.id = -1;
entry.id = sound_load_id::invalid();
}
}
}
@@ -599,9 +599,9 @@ void gamesnd_unload_interface_sounds()
Assert( Snds_iface.size() < INT_MAX );
for (SCP_vector<game_snd>::iterator si = Snds_iface.begin(); si != Snds_iface.end(); ++si) {
for (auto& entry : si->sound_entries) {
if ( entry.id != -1 ) {
if (entry.id.isValid()) {
snd_unload( entry.id );
entry.id = -1;
entry.id = sound_load_id::invalid();
entry.id_sig = -1;
}
}
@@ -617,6 +617,9 @@ void parse_gamesnd_old(game_snd* gs)
gs->sound_entries.resize(1);
auto& entry = gs->sound_entries.back();
// Default pitch is 1.0. This is set here in case we don't have a valid file name
gs->pitch_range = util::UniformFloatRange(1.0f);
stuff_string(entry.filename, F_NAME, MAX_FILENAME_LEN, ",");
if (!stricmp(entry.filename, NOX("empty")))
@@ -673,9 +676,6 @@ void parse_gamesnd_old(game_snd* gs)
}
}
// Default pitch is 1.0
gs->pitch_range = util::UniformFloatRange(1.0f);
// check for extra values per Mantis #2408
ignore_gray_space();
if (stuff_int_optional(&temp, true) == 2)
@@ -840,6 +840,9 @@ void parse_gamesnd_new(game_snd* gs, bool no_create)
// New extended format found
stuff_string(name, F_NAME, MAX_FILENAME_LEN);
// Default pitch is 1.0. This is set here in case we don't have a valid file name
gs->pitch_range = util::UniformFloatRange(1.0f);
if (!stricmp(name, NOX("empty")))
{
entry->filename[0] = 0;
@@ -914,9 +917,6 @@ void parse_gamesnd_new(game_snd* gs, bool no_create)
error_display(1, "Invalid enhanced sound limit: %d\n", temp_limit);
}
}
// Default pitch is 1.0
gs->pitch_range = util::UniformFloatRange(1.0f);
}
void gamesnd_parse_entry(game_snd *gs, bool no_create, SCP_vector<game_snd> *lookupVector)
@@ -1197,7 +1197,7 @@ void parse_sound_table(const char* filename)
if (gamesnd_parse_line(&tempSound, "$Name:", &Snds_iface))
{
Snds_iface.push_back(game_snd(tempSound));
Snds_iface_handle.push_back(-1);
Snds_iface_handle.push_back(sound_handle::invalid());
}
}
@@ -1322,7 +1322,7 @@ float gamesnd_get_max_duration(game_snd* gs) {
int max_length = 0;
for (auto& entry : gs->sound_entries) {
if (entry.id < 0) {
if (!entry.id.isValid()) {
// Lazily load unloaded sound entries when required
entry.id = snd_load(&entry, gs->flags);
}
+1 -1
View File
@@ -578,7 +578,7 @@ void parse_everything_else(const char *filename)
}
break;
default:
Assertion(false, "MageKing17 made a coding error somewhere, and you should laugh at him (and report this error).\n");
UNREACHABLE("MageKing17 made a coding error somewhere, and you should laugh at him (and report this error).\n");
break;
}
}
+1 -1
View File
@@ -28,7 +28,7 @@
#define MISSION_DESC_LENGTH 512
// from player.h
#define CALLSIGN_LEN 28 // shortened from 32 to allow .plr to be attached without exceeding MAX_FILENAME_LEN
#define CALLSIGN_LEN (MAX_FILENAME_LEN - 4 - 1) // shortened from 32 to allow .json to be attached without exceeding MAX_FILENAME_LEN
#define SHORT_CALLSIGN_PIXEL_W 80 // max width of short_callsign[] in pixels
#define MAX_IFFS 10
+1 -15
View File
@@ -103,20 +103,6 @@ typedef struct vec3d {
};
} vec3d;
/** Compares two vec3ds */
inline bool operator==(const vec3d &self, const vec3d &other)
{
return (self.xyz.x == other.xyz.x
&& self.xyz.y == other.xyz.y
&& self.xyz.z == other.xyz.z
);
}
inline bool operator!=(const vec3d &self, const vec3d &other)
{
return !(self == other);
}
typedef struct vec2d {
float x, y;
} vec2d;
@@ -403,7 +389,7 @@ template <class T> void CAP( T& v, T mn, T mx )
}
// faster version of CAP()
#define CLAMP(x, min, max) do { if ( (x) < (min) ) (x) = (min); else if ((x) > (max)) (x) = (max); } while(0)
#define CLAMP(x, min, max) do { if ( (x) < (min) ) (x) = (min); else if ((x) > (max)) (x) = (max); } while(false)
//=========================================================
// Memory management functions
+9
View File
@@ -81,3 +81,12 @@
#define CLANG_ANALYZER_NORETURN
#endif
#endif
#ifndef NDEBUG
#define UNREACHABLE(msg, ...) \
do { \
os::dialogs::Error(__FILE__, __LINE__, msg, ##__VA_ARGS__); \
} while (false)
#else
#define UNREACHABLE(msg, ...) __builtin_unreachable()
#endif
+7
View File
@@ -63,3 +63,10 @@
* @brief Specifies that an analyzer should consider this function as no-return
*/
#define CLANG_ANALYZER_NORETURN
/**
* @brief Specifies that the code at which point this macro appears at is unreachable
* @param msg The message to display in debug mode
* @param ... Format arguments for the message
*/
#define UNREACHABLE(msg, ...)
+9
View File
@@ -72,3 +72,12 @@
#endif
#define CLANG_ANALYZER_NORETURN
#ifndef NDEBUG
#define UNREACHABLE(msg, ...) \
do { \
os::dialogs::Error(__FILE__, __LINE__, msg, ##__VA_ARGS__); \
} while (false)
#else
#define UNREACHABLE(msg, ...) __builtin_unreachable()
#endif
+9
View File
@@ -69,3 +69,12 @@
#endif
#define CLANG_ANALYZER_NORETURN
#ifndef NDEBUG
#define UNREACHABLE(msg, ...) \
do { \
os::dialogs::Error(__FILE__, __LINE__, msg, ##__VA_ARGS__); \
} while (false)
#else
#define UNREACHABLE(msg, ...) __builtin_unreachable()
#endif
+12 -2
View File
@@ -74,11 +74,21 @@
#define SIZE_T_ARG "%Iu"
#define PTRDIFF_T_ARG "%Id"
#define likely(x)
#define unlikely(x)
#define likely(x) (x)
#define unlikely(x) (x)
#define USED_VARIABLE
#define FALLTHROUGH
#define CLANG_ANALYZER_NORETURN
#ifndef NDEBUG
#define UNREACHABLE(msg, ...) \
do { \
os::dialogs::Error(__FILE__, __LINE__, msg, ##__VA_ARGS__); \
} while (false)
#else
#define UNREACHABLE(msg, ...) __assume(false)
#endif
+21 -1
View File
@@ -7,8 +7,9 @@
*
*/
#include "globalincs/pstypes.h"
#include "globalincs/version.h"
#include "globalincs/pstypes.h"
#include "graphics/2d.h"
#include "parse/parselo.h"
@@ -130,5 +131,24 @@ bool version::operator!=(const version& other) const {
return !(*this == other);
}
SCP_string get_version_string()
{
SCP_string str;
sprintf(str, "FreeSpace 2 Open v%s", FS_VERSION_FULL);
#ifndef NDEBUG
str += " Debug";
#endif
// Lets get some more info in here
switch (gr_screen.mode) {
case GR_OPENGL:
str += " OpenGL";
break;
}
return str;
}
}
+7
View File
@@ -85,6 +85,13 @@ bool check_at_least(const version& v);
*/
SCP_string format_version(const version& v);
/**
* @brief
* @return
*/
SCP_string get_version_string();
}
#endif
+7 -7
View File
@@ -19,17 +19,17 @@
#include "cmdline/cmdline.h"
#include "debugconsole/console.h"
#include "gamesequence/gamesequence.h" //WMC - for scripting hooks in gr_flip()
#include "gamesequence/gamesequence.h" //WMC - for scripting hooks in gr_flip()
#include "globalincs/systemvars.h"
#include "graphics/2d.h"
#include "graphics/matrix.h"
#include "graphics/light.h"
#include "graphics/font.h"
#include "graphics/grbatch.h"
#include "graphics/grinternal.h"
#include "graphics/grstub.h"
#include "graphics/light.h"
#include "graphics/matrix.h"
#include "graphics/opengl/gropengl.h"
#include "graphics/opengl/gropengldraw.h"
#include "graphics/grstub.h"
#include "graphics/paths/PathRenderer.h"
#include "graphics/util/GPUMemoryHeap.h"
#include "graphics/util/UniformBuffer.h"
@@ -37,9 +37,10 @@
#include "io/keycontrol.h" // m!m
#include "io/timer.h"
#include "osapi/osapi.h"
#include "scripting/scripting.h"
#include "parse/parselo.h"
#include "popup/popup.h"
#include "render/3d.h"
#include "scripting/scripting.h"
#include "tracing/tracing.h"
#include "utils/boost/hash_combine.h"
@@ -2152,8 +2153,7 @@ void gr_set_bitmap(int bitmap_num, int alphablend_mode, int bitblt_mode, float a
void gr_flip(bool execute_scripting)
{
// m!m avoid running CHA_ONFRAME when the "Quit mission" popup is shown. See mantis 2446 for reference
if (execute_scripting && !quit_mission_popup_shown)
{
if (execute_scripting && !popup_active()) {
TRACE_SCOPE(tracing::LuaOnFrame);
//WMC - Do conditional hooks. Yippee!
+51 -40
View File
@@ -49,6 +49,7 @@ class movie_material;
class batched_bitmap_material;
class nanovg_material;
class decal_material;
class interface_material;
class transform_stack {
@@ -154,13 +155,15 @@ enum shader_type {
SDR_TYPE_DEFERRED_LIGHTING,
SDR_TYPE_DEFERRED_CLEAR,
SDR_TYPE_VIDEO_PROCESS,
SDR_TYPE_PASSTHROUGH_RENDER, //!< Shader for doing the old style fixed-function rendering. Only used internally, use SDR_TYPE_DEFAULT_MATERIAL.
SDR_TYPE_PASSTHROUGH_RENDER, //!< Shader for doing the old style fixed-function rendering. Only used internally, use
//!< SDR_TYPE_DEFAULT_MATERIAL.
SDR_TYPE_SHIELD_DECAL,
SDR_TYPE_BATCHED_BITMAP,
SDR_TYPE_DEFAULT_MATERIAL,
SDR_TYPE_NANOVG,
SDR_TYPE_DECAL,
SDR_TYPE_SCENE_FOG,
SDR_TYPE_ROCKET_UI,
NUM_SHADER_TYPES
};
@@ -186,7 +189,7 @@ enum shader_type {
#define SDR_FLAG_MODEL_HDR (1<<18)
#define SDR_FLAG_MODEL_AMBIENT_MAP (1<<19)
#define SDR_FLAG_MODEL_NORMAL_ALPHA (1<<20)
#define SDR_FLAG_MODEL_NORMAL_EXTRUDE (1<<21)
#define SDR_FLAG_MODEL_THICK_OUTLINES (1<<21) // Renders the model geometry as an outline with configurable line width
#define SDR_FLAG_PARTICLE_POINT_GEN (1<<0)
@@ -776,10 +779,12 @@ typedef struct screen {
void (*gf_render_primitives)(material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle, size_t buffer_offset);
void (*gf_render_primitives_particle)(particle_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
void (*gf_render_primitives_distortion)(distortion_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
void (*gf_render_movie)(movie_material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, int buffer);
void (*gf_render_movie)(movie_material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, int buffer, size_t buffer_offset);
void (*gf_render_primitives_batched)(batched_bitmap_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
void (*gf_render_nanovg)(nanovg_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
void (*gf_render_decals)(decal_material* material_info, primitive_type prim_type, vertex_layout* layout, int num_elements, const indexed_vertex_source& buffers);
void (*gf_render_rocket_primitives)(interface_material* material_info, primitive_type prim_type,
vertex_layout* layout, int n_indices, int vertex_buffer, int index_buffer);
bool (*gf_is_capable)(gr_capability capability);
bool (*gf_get_property)(gr_property property, void* destination);
@@ -942,67 +947,67 @@ void gr_shield_icon(coord2d coords[6], const int resize_mode = GR_RESIZE_FULL);
// Here be the bitmap functions
#define gr_bm_free_data GR_CALL(*gr_screen.gf_bm_free_data)
#define gr_bm_create GR_CALL(*gr_screen.gf_bm_create)
#define gr_bm_init GR_CALL(*gr_screen.gf_bm_init)
#define gr_bm_page_in_start GR_CALL(*gr_screen.gf_bm_page_in_start)
#define gr_bm_data GR_CALL(*gr_screen.gf_bm_data)
#define gr_bm_free_data GR_CALL(gr_screen.gf_bm_free_data)
#define gr_bm_create GR_CALL(gr_screen.gf_bm_create)
#define gr_bm_init GR_CALL(gr_screen.gf_bm_init)
#define gr_bm_page_in_start GR_CALL(gr_screen.gf_bm_page_in_start)
#define gr_bm_data GR_CALL(gr_screen.gf_bm_data)
#define gr_bm_make_render_target GR_CALL(*gr_screen.gf_bm_make_render_target)
#define gr_bm_make_render_target GR_CALL(gr_screen.gf_bm_make_render_target)
__inline int gr_bm_set_render_target(int n, int face = -1)
{
return (*gr_screen.gf_bm_set_render_target)(n, face);
}
#define gr_set_texture_addressing GR_CALL(*gr_screen.gf_set_texture_addressing)
#define gr_set_texture_addressing GR_CALL(gr_screen.gf_set_texture_addressing)
inline int gr_create_buffer(BufferType type, BufferUsageHint usage)
{
return (*gr_screen.gf_create_buffer)(type, usage);
}
#define gr_delete_buffer GR_CALL(*gr_screen.gf_delete_buffer)
#define gr_update_buffer_data GR_CALL(*gr_screen.gf_update_buffer_data)
#define gr_update_buffer_data_offset GR_CALL(*gr_screen.gf_update_buffer_data_offset)
#define gr_update_transform_buffer GR_CALL(*gr_screen.gf_update_transform_buffer)
#define gr_delete_buffer GR_CALL(gr_screen.gf_delete_buffer)
#define gr_update_buffer_data GR_CALL(gr_screen.gf_update_buffer_data)
#define gr_update_buffer_data_offset GR_CALL(gr_screen.gf_update_buffer_data_offset)
#define gr_update_transform_buffer GR_CALL(gr_screen.gf_update_transform_buffer)
#define gr_scene_texture_begin GR_CALL(*gr_screen.gf_scene_texture_begin)
#define gr_scene_texture_end GR_CALL(*gr_screen.gf_scene_texture_end)
#define gr_copy_effect_texture GR_CALL(*gr_screen.gf_copy_effect_texture)
#define gr_scene_texture_begin GR_CALL(gr_screen.gf_scene_texture_begin)
#define gr_scene_texture_end GR_CALL(gr_screen.gf_scene_texture_end)
#define gr_copy_effect_texture GR_CALL(gr_screen.gf_copy_effect_texture)
#define gr_post_process_set_effect GR_CALL(*gr_screen.gf_post_process_set_effect)
#define gr_post_process_set_defaults GR_CALL(*gr_screen.gf_post_process_set_defaults)
#define gr_post_process_begin GR_CALL(*gr_screen.gf_post_process_begin)
#define gr_post_process_end GR_CALL(*gr_screen.gf_post_process_end)
#define gr_post_process_save_zbuffer GR_CALL(*gr_screen.gf_post_process_save_zbuffer)
#define gr_post_process_set_effect GR_CALL(gr_screen.gf_post_process_set_effect)
#define gr_post_process_set_defaults GR_CALL(gr_screen.gf_post_process_set_defaults)
#define gr_post_process_begin GR_CALL(gr_screen.gf_post_process_begin)
#define gr_post_process_end GR_CALL(gr_screen.gf_post_process_end)
#define gr_post_process_save_zbuffer GR_CALL(gr_screen.gf_post_process_save_zbuffer)
inline void gr_post_process_restore_zbuffer() {
gr_screen.gf_post_process_restore_zbuffer();
}
#define gr_deferred_lighting_begin GR_CALL(*gr_screen.gf_deferred_lighting_begin)
#define gr_deferred_lighting_end GR_CALL(*gr_screen.gf_deferred_lighting_end)
#define gr_deferred_lighting_finish GR_CALL(*gr_screen.gf_deferred_lighting_finish)
#define gr_deferred_lighting_begin GR_CALL(gr_screen.gf_deferred_lighting_begin)
#define gr_deferred_lighting_end GR_CALL(gr_screen.gf_deferred_lighting_end)
#define gr_deferred_lighting_finish GR_CALL(gr_screen.gf_deferred_lighting_finish)
#define gr_zbias GR_CALL(*gr_screen.gf_zbias)
#define gr_set_fill_mode GR_CALL(*gr_screen.gf_set_fill_mode)
#define gr_zbias GR_CALL(gr_screen.gf_zbias)
#define gr_set_fill_mode GR_CALL(gr_screen.gf_set_fill_mode)
#define gr_set_line_width GR_CALL(*gr_screen.gf_set_line_width)
#define gr_set_line_width GR_CALL(gr_screen.gf_set_line_width)
#define gr_sphere GR_CALL(*gr_screen.gf_sphere)
#define gr_sphere GR_CALL(gr_screen.gf_sphere)
#define gr_maybe_create_shader GR_CALL(*gr_screen.gf_maybe_create_shader)
#define gr_recompile_all_shaders GR_CALL(*gr_screen.gf_recompile_all_shaders)
#define gr_set_animated_effect GR_CALL(*gr_screen.gf_set_animated_effect)
#define gr_maybe_create_shader GR_CALL(gr_screen.gf_maybe_create_shader)
#define gr_recompile_all_shaders GR_CALL(gr_screen.gf_recompile_all_shaders)
#define gr_set_animated_effect GR_CALL(gr_screen.gf_set_animated_effect)
#define gr_clear_states GR_CALL(*gr_screen.gf_clear_states)
#define gr_clear_states GR_CALL(gr_screen.gf_clear_states)
#define gr_update_texture GR_CALL(*gr_screen.gf_update_texture)
#define gr_get_bitmap_from_texture GR_CALL(*gr_screen.gf_get_bitmap_from_texture)
#define gr_update_texture GR_CALL(gr_screen.gf_update_texture)
#define gr_get_bitmap_from_texture GR_CALL(gr_screen.gf_get_bitmap_from_texture)
#define gr_shadow_map_start GR_CALL(*gr_screen.gf_shadow_map_start)
#define gr_shadow_map_end GR_CALL(*gr_screen.gf_shadow_map_end)
#define gr_render_shield_impact GR_CALL(*gr_screen.gf_render_shield_impact)
#define gr_shadow_map_start GR_CALL(gr_screen.gf_shadow_map_start)
#define gr_shadow_map_end GR_CALL(gr_screen.gf_shadow_map_end)
#define gr_render_shield_impact GR_CALL(gr_screen.gf_render_shield_impact)
__inline void gr_render_primitives(material* material_info, primitive_type prim_type, vertex_layout* layout, int vert_offset, int n_verts, int buffer_handle = -1, size_t buffer_offset = 0)
{
@@ -1029,9 +1034,9 @@ __inline void gr_render_primitives_distortion(distortion_material* material_info
(*gr_screen.gf_render_primitives_distortion)(material_info, prim_type, layout, offset, n_verts, buffer_handle);
}
inline void gr_render_movie(movie_material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, int buffer)
inline void gr_render_movie(movie_material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, int buffer, size_t buffer_offset = 0)
{
(*gr_screen.gf_render_movie)(material_info, prim_type, layout, n_verts, buffer);
(*gr_screen.gf_render_movie)(material_info, prim_type, layout, n_verts, buffer, buffer_offset);
}
__inline void gr_render_model(model_material* material_info, indexed_vertex_source *vert_source, vertex_buffer* bufferp, size_t texi)
@@ -1039,6 +1044,12 @@ __inline void gr_render_model(model_material* material_info, indexed_vertex_sour
(*gr_screen.gf_render_model)(material_info, vert_source, bufferp, texi);
}
__inline void gr_render_rocket_primitives(interface_material* material_info, primitive_type prim_type,
vertex_layout* layout, int n_indices, int vertex_buffer, int index_buffer)
{
(*gr_screen.gf_render_rocket_primitives)(material_info, prim_type, layout, n_indices, vertex_buffer, index_buffer);
}
__inline bool gr_is_capable(gr_capability capability)
{
return (*gr_screen.gf_is_capable)(capability);
+5 -9
View File
@@ -158,32 +158,28 @@ int generic_anim_stream(generic_anim *ga, const bool cache)
{
CFILE *img_cfp = NULL;
int anim_fps = 0;
char full_path[MAX_PATH];
size_t size = 0, offset = 0;
const void* file_data = nullptr;
const int NUM_TYPES = 3;
const ubyte type_list[NUM_TYPES] = {BM_TYPE_EFF, BM_TYPE_ANI, BM_TYPE_PNG};
const char *ext_list[NUM_TYPES] = {".eff", ".ani", ".png"};
int rval = -1;
int bpp;
ga->type = BM_TYPE_NONE;
rval = cf_find_file_location_ext(ga->filename, NUM_TYPES, ext_list, CF_TYPE_ANY, sizeof(full_path) - 1, full_path, &size, &offset, 0, &file_data);
auto res = cf_find_file_location_ext(ga->filename, NUM_TYPES, ext_list, CF_TYPE_ANY, false);
// could not be found, or is invalid for some reason
if ( (rval < 0) || (rval >= NUM_TYPES) )
if ( !res.found )
return -1;
//make sure we can open it
img_cfp = cfopen_special(full_path, "rb", size, offset, file_data, CF_TYPE_ANY);
img_cfp = cfopen_special(res.full_name.c_str(), "rb", res.size, res.offset, res.data_ptr, CF_TYPE_ANY);
if (img_cfp == NULL) {
return -1;
}
strcat_s(ga->filename, ext_list[rval]);
ga->type = type_list[rval];
strcat_s(ga->filename, ext_list[res.extension_index]);
ga->type = type_list[res.extension_index];
//seek to the end
cfseek(img_cfp, 0, CF_SEEK_END);
+8 -1
View File
@@ -335,7 +335,7 @@ void gr_stub_render_primitives_distortion(distortion_material* /*material_info*
{
}
void gr_stub_render_movie(movie_material* /*material_info*/, primitive_type /*prim_type*/, vertex_layout* /*layout*/, int /*n_verts*/, int /*buffer*/)
void gr_stub_render_movie(movie_material* /*material_info*/, primitive_type /*prim_type*/, vertex_layout* /*layout*/, int /*n_verts*/, int /*buffer*/, size_t /*buffer_offset*/)
{
}
@@ -351,6 +351,12 @@ void gr_stub_render_primitives_batched(batched_bitmap_material* /*material_info
{
}
void gr_stub_render_rocket_primitives(interface_material* /*material_info*/, primitive_type /*prim_type*/,
vertex_layout* /*layout*/, int /*n_indices*/, int /*vertex_buffer*/,
int /*index_buffer*/)
{
}
bool gr_stub_is_capable(gr_capability /*capability*/)
{
return false;
@@ -511,6 +517,7 @@ bool gr_stub_init()
gr_screen.gf_render_movie = gr_stub_render_movie;
gr_screen.gf_render_nanovg = gr_stub_render_nanovg;
gr_screen.gf_render_primitives_batched = gr_stub_render_primitives_batched;
gr_screen.gf_render_rocket_primitives = gr_stub_render_rocket_primitives;
gr_screen.gf_is_capable = gr_stub_is_capable;
gr_screen.gf_get_property = [](gr_property,void*) { return false; };
+12 -1
View File
@@ -55,7 +55,18 @@ void line_draw_list::add_vertex(int x, int y, int resize_mode, const color* colo
vtx.position.x = i2fl(x);
vtx.position.y = i2fl(y);
gr_resize_screen_posf(&vtx.position.x, &vtx.position.y, nullptr, nullptr, resize_mode);
float w_scale = 1.0f;
float h_scale = 1.0f;
bool do_resize = gr_resize_screen_posf(&vtx.position.x, &vtx.position.y, &w_scale, &h_scale, resize_mode);
int offset_x = ((do_resize) ? gr_screen.offset_x_unscaled : gr_screen.offset_x);
int offset_y = ((do_resize) ? gr_screen.offset_y_unscaled : gr_screen.offset_y);
// m!m - This is silly but there is no better solution at the moment...
vtx.position.x += i2fl(offset_x) * w_scale;
vtx.position.y += i2fl(offset_y) * h_scale;
vtx.color.xyzw.x = color->red / 255.f;
vtx.color.xyzw.y = color->green / 255.f;
vtx.color.xyzw.z = color->blue / 255.f;
+34 -23
View File
@@ -123,6 +123,18 @@ void material_set_distortion(distortion_material *mat_info, int texture, bool th
mat_info->set_cull_mode(false);
mat_info->set_color(1.0f, 1.0f, 1.0f, 1.0f);
}
void material_set_rocket_interface(interface_material* mat_info, int texture, const vec2d& offset)
{
mat_info->set_texture_map(TM_BASE_TYPE, texture);
mat_info->set_offset(offset);
mat_info->set_cull_mode(false);
mat_info->set_color(1.0f, 1.0f, 1.0f, 1.0f);
mat_info->set_depth_mode(ZBUFFER_TYPE_NONE);
mat_info->set_blend_mode(ALPHA_BLEND_ALPHA_BLEND_ALPHA);
}
void material_set_movie(movie_material* mat_info, int y_bm, int u_bm, int v_bm) {
mat_info->set_depth_mode(ZBUFFER_TYPE_NONE);
@@ -635,27 +647,6 @@ float model_material::get_normal_alpha_max() const
return Normal_alpha_max;
}
void model_material::set_normal_extrude(float width)
{
Normal_extrude = true;
Normal_extrude_width = width;
}
void model_material::set_normal_extrude()
{
Normal_extrude = false;
}
bool model_material::is_normal_extrude_active() const
{
return Normal_extrude;
}
float model_material::get_normal_extrude_width() const
{
return Normal_extrude_width;
}
void model_material::set_fog(int r, int g, int b, float _near, float _far)
{
Fog_params.enabled = true;
@@ -681,6 +672,16 @@ const model_material::fog& model_material::get_fog() const
return Fog_params;
}
void model_material::set_outline_thickness(float thickness) {
Outline_thickness = thickness;
}
float model_material::get_outline_thickness() const {
return Outline_thickness;
}
bool model_material::uses_thick_outlines() const {
return Outline_thickness > 0.0f;
}
uint model_material::get_shader_flags() const
{
uint Shader_flags = 0;
@@ -768,8 +769,8 @@ uint model_material::get_shader_flags() const
Shader_flags |= SDR_FLAG_MODEL_NORMAL_ALPHA;
}
if ( Normal_extrude ) {
Shader_flags |= SDR_FLAG_MODEL_NORMAL_EXTRUDE;
if ( uses_thick_outlines() ) {
Shader_flags |= SDR_FLAG_MODEL_THICK_OUTLINES;
}
return Shader_flags;
@@ -901,3 +902,13 @@ uint decal_material::get_shader_flags() const {
return flags;
}
interface_material::interface_material()
{
set_shader_type(SDR_TYPE_ROCKET_UI);
offset.x = 0;
offset.y = 0;
}
void interface_material::set_offset(const vec2d& new_offset) { this->offset = new_offset; }
vec2d interface_material::get_offset() { return offset; }
+21 -13
View File
@@ -200,10 +200,10 @@ class model_material : public material
float Normal_alpha_min = 0.0f;
float Normal_alpha_max = 1.0f;
bool Normal_extrude = false;
float Normal_extrude_width = -1.0f;
fog Fog_params;
float Outline_thickness = -1.0f;
public:
model_material();
@@ -246,10 +246,9 @@ public:
float get_normal_alpha_min() const;
float get_normal_alpha_max() const;
void set_normal_extrude(float width);
void set_normal_extrude();
bool is_normal_extrude_active() const;
float get_normal_extrude_width() const;
void set_outline_thickness(float thickness = -1.0f);
float get_outline_thickness() const;
bool uses_thick_outlines() const;
void set_batching(bool enabled);
bool is_batched() const;
@@ -316,9 +315,8 @@ class movie_material : public material {
void setVtex(int _Vtex);
};
class batched_bitmap_material : public material
{
public:
class batched_bitmap_material : public material {
public:
batched_bitmap_material();
};
@@ -327,19 +325,29 @@ class nanovg_material : public material {
nanovg_material();
};
class decal_material : public material
{
public:
class decal_material : public material {
public:
decal_material();
uint get_shader_flags() const override;
};
class interface_material : public material {
vec2d offset;
public:
interface_material();
void set_offset(const vec2d& new_offset);
vec2d get_offset();
};
gr_alpha_blend material_determine_blend_mode(int base_bitmap, bool is_transparent);
gr_zbuffer_type material_determine_depth_mode(bool depth_testing, bool is_transparent);
void material_set_interface(material* mat_info, int texture, bool blended, float alpha);
void material_set_rocket_interface(interface_material* mat_info, int texture, const vec2d& offset);
void material_set_unlit(material* mat_info, int texture, float alpha, bool blending, bool depth_testing);
void material_set_unlit_emissive(material* mat_info, int texture, float alpha, float color_scale);
void material_set_unlit_color(material* mat_info, int texture, color *clr, bool blending, bool depth_testing);
+1 -1
View File
@@ -137,7 +137,7 @@ GLenum get_gl_shader_stage(opengl::ShaderStage stage) {
case opengl::STAGE_FRAGMENT:
return GL_FRAGMENT_SHADER;
default:
Assertion(false, "Unhandled shader type found!");
UNREACHABLE("Unhandled shader type found!");
return GL_NONE;
}
}
+21 -15
View File
@@ -29,6 +29,7 @@
#include "math/floating.h"
#include "model/model.h"
#include "nebula/neb.h"
#include "libs/renderdoc/renderdoc.h"
#include "osapi/osapi.h"
#include "osapi/osregistry.h"
#include "render/3d.h"
@@ -90,7 +91,8 @@ static GLenum GL_read_format = GL_BGRA;
GLuint GL_vao = 0;
bool GL_workaround_clipping_planes = false;
SCP_string GL_implementation_id;
SCP_vector<GLint> GL_binary_formats;
static std::unique_ptr<os::OpenGLContext> GL_context = nullptr;
@@ -1172,6 +1174,7 @@ void opengl_setup_function_pointers()
gr_screen.gf_render_movie = gr_opengl_render_movie;
gr_screen.gf_render_nanovg = gr_opengl_render_nanovg;
gr_screen.gf_render_decals = gr_opengl_render_decals;
gr_screen.gf_render_rocket_primitives = gr_opengl_render_rocket_primitives;
gr_screen.gf_is_capable = gr_opengl_is_capable;
gr_screen.gf_get_property = gr_opengl_get_property;
@@ -1365,19 +1368,6 @@ static void init_extensions() {
}
}
static void opengl_do_workaround_checks() {
auto vendor = glGetString(GL_VENDOR);
if (strstr((const char*) vendor, "NVIDIA")) {
// Nvidia has some weird issues with clipping planes. Check #1579 for more information.
GL_workaround_clipping_planes = true;
mprintf((" Applying clipping plane workaround for NVIDIA hardware.\n"));
} else {
// Assume everone else has proper support for this
GL_workaround_clipping_planes = false;
}
}
bool gr_opengl_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps)
{
if (GL_initted) {
@@ -1390,6 +1380,9 @@ bool gr_opengl_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps)
gr_screen.max_h,
gr_screen.bits_per_pixel ));
// Load the RenderDoc API if available before doing anything with OpenGL
renderdoc::loadApi();
graphic_operations = std::move(graphicsOps);
if ( opengl_init_display_device() ) {
@@ -1446,7 +1439,20 @@ bool gr_opengl_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps)
mprintf(( " OpenGL Version : %s\n", glGetString(GL_VERSION) ));
mprintf(( "\n" ));
opengl_do_workaround_checks();
// Build a string identifier for this OpenGL implementation
GL_implementation_id.clear();
GL_implementation_id += reinterpret_cast<const char*>(glGetString(GL_VENDOR));
GL_implementation_id += "\n";
GL_implementation_id += reinterpret_cast<const char*>(glGetString(GL_RENDERER));
GL_implementation_id += "\n";
GL_implementation_id += reinterpret_cast<const char*>(glGetString(GL_VERSION));
GL_implementation_id += "\n";
GL_implementation_id += reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION));
GLint formats = 0;
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &formats);
GL_binary_formats.resize(formats);
glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, GL_binary_formats.data());
if (Cmdline_fullscreen_window || Cmdline_window) {
opengl_go_windowed();
+2 -1
View File
@@ -58,6 +58,7 @@ extern GLuint GL_vao;
extern float GL_alpha_threshold;
extern bool GL_workaround_clipping_planes; //!< If set then clipping planes can not be used for batched model rendering
extern SCP_string GL_implementation_id;
extern SCP_vector<GLint> GL_binary_formats;
#endif
+11
View File
@@ -188,6 +188,9 @@ void gr_opengl_deferred_lighting_finish()
light_data->lightDir.xyz.x = view_dir.xyzw.x;
light_data->lightDir.xyz.y = view_dir.xyzw.y;
light_data->lightDir.xyz.z = view_dir.xyzw.z;
vm_vec_scale(&light_data->specLightColor, static_light_factor);
first_directional = false;
break;
case Light_Type::Cone:
@@ -199,6 +202,9 @@ void gr_opengl_deferred_lighting_finish()
case Light_Type::Point:
light_data->diffuseLightColor = diffuse;
light_data->specLightColor = spec;
vm_vec_scale(&light_data->specLightColor, static_point_factor);
light_data->lightRadius = MAX(l.rada, l.radb) * 1.25f;
light_data->scale.xyz.x = MAX(l.rada, l.radb) * 1.28f;
light_data->scale.xyz.y = MAX(l.rada, l.radb) * 1.28f;
@@ -217,10 +223,15 @@ void gr_opengl_deferred_lighting_finish()
light_data->scale.xyz.y = l.radb * 1.53f;
light_data->scale.xyz.z = length;
vm_vec_scale(&light_data->specLightColor, static_tube_factor);
// Tube lights consist of two different types of lights with almost the same properties
light_data = uniformAligner.addTypedElement<deferred_light_data>();
light_data->diffuseLightColor = diffuse;
light_data->specLightColor = spec;
vm_vec_scale(&light_data->specLightColor, static_tube_factor);
light_data->lightRadius = l.radb * 1.5f;
light_data->lightType = LT_POINT;
+20 -6
View File
@@ -786,18 +786,16 @@ void gr_opengl_render_primitives_distortion(distortion_material* material_info,
GL_CHECK_FOR_ERRORS("start of gr_opengl_render_primitives_distortion()");
}
void gr_opengl_render_movie(movie_material* material_info,
primitive_type prim_type,
vertex_layout* layout,
int n_verts,
int buffer) {
void gr_opengl_render_movie(movie_material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts,
int buffer, size_t buffer_offset)
{
GR_DEBUG_SCOPE("Render movie frame");
gr_set_2d_matrix();
opengl_tnl_set_material_movie(material_info);
opengl_render_primitives(prim_type, layout, n_verts, buffer, 0, 0);
opengl_render_primitives(prim_type, layout, n_verts, buffer, 0, buffer_offset);
gr_end_2d_matrix();
}
@@ -827,6 +825,22 @@ void gr_opengl_render_primitives_batched(batched_bitmap_material* material_info,
opengl_render_primitives(prim_type, layout, n_verts, buffer_handle, offset, 0);
}
void gr_opengl_render_rocket_primitives(interface_material* material_info, primitive_type prim_type,
vertex_layout* layout, int n_indices, int vertex_buffer, int index_buffer)
{
GR_DEBUG_SCOPE("Render rocket ui primitives");
gr_set_2d_matrix();
opengl_tnl_set_rocketui_material(material_info);
opengl_bind_vertex_layout(*layout, opengl_buffer_get_id(GL_ARRAY_BUFFER, vertex_buffer),
opengl_buffer_get_id(GL_ELEMENT_ARRAY_BUFFER, index_buffer));
glDrawElements(opengl_primitive_type(prim_type), n_indices, GL_UNSIGNED_INT, nullptr);
gr_end_2d_matrix();
}
void opengl_draw_textured_quad(GLfloat x1,
GLfloat y1,
+3 -1
View File
@@ -55,9 +55,11 @@ void gr_opengl_render_primitives(material* material_info, primitive_type prim_ty
void gr_opengl_render_primitives_particle(particle_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
void gr_opengl_render_primitives_batched(batched_bitmap_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
void gr_opengl_render_primitives_distortion(distortion_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
void gr_opengl_render_movie(movie_material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, int buffer);
void gr_opengl_render_movie(movie_material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, int buffer, size_t buffer_offset);
void gr_opengl_render_nanovg(nanovg_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
void gr_opengl_render_decals(decal_material* material_info, primitive_type prim_type, vertex_layout* layout, int num_elements, const indexed_vertex_source& binding);
void gr_opengl_render_rocket_primitives(interface_material* material_info, primitive_type prim_type,
vertex_layout* layout, int n_indices, int vertex_buffer, int index_buffer);
void opengl_draw_textured_quad(GLfloat x1, GLfloat y1, GLfloat u1, GLfloat v1,
GLfloat x2, GLfloat y2, GLfloat u2, GLfloat v2 );
@@ -73,9 +73,6 @@ static GLuint Bloom_framebuffer = 0;
static GLuint Bloom_textures[2] = { 0 };
static GLuint Post_framebuffer_id[2] = { 0 };
static GLuint Post_shadow_framebuffer_id = 0;
static GLuint Post_shadow_texture_id = 0;
static GLuint Post_shadow_depth_texture_id = 0;
static int Post_texture_width = 0;
static int Post_texture_height = 0;
@@ -864,76 +861,6 @@ void opengl_setup_bloom_textures()
GL_state.BindFrameBuffer(0);
}
static bool opengl_init_shadow_framebuffer(int size, GLenum color_format) {
mprintf(("Trying to create %dx%d %d-bit shadow framebuffer\n", size, size, color_format == GL_RGBA32F ? 32 : 16));
glGenFramebuffers(1, &Post_shadow_framebuffer_id);
GL_state.BindFrameBuffer(Post_shadow_framebuffer_id);
glGenTextures(1, &Post_shadow_texture_id);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D_ARRAY);
GL_state.Texture.Enable(Post_shadow_texture_id);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, color_format, size, size, 4, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, Post_shadow_texture_id, 0);
glGenTextures(1, &Post_shadow_depth_texture_id);
GL_state.Texture.Enable(Post_shadow_depth_texture_id);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT32, size, size, 4, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, Post_shadow_depth_texture_id, 0);
auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status == GL_FRAMEBUFFER_COMPLETE) {
// Everything is fine
mprintf(("Shadow framebuffer created successfully.\n"));
return true;
}
// Clean up resources
glDeleteTextures(1, &Post_shadow_texture_id);
glDeleteTextures(1, &Post_shadow_depth_texture_id);
glDeleteFramebuffers(1, &Post_shadow_framebuffer_id);
Post_shadow_texture_id = 0;
Post_shadow_depth_texture_id = 0;
Post_shadow_framebuffer_id = 0;
const char* error;
switch (status) {
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
error = "Incomplete framebuffer attachment";
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
error = "Framebuffer is missing an attachment";
break;
case GL_FRAMEBUFFER_UNSUPPORTED:
error = "Framebuffer configuration is unsupported";
break;
default:
error = "Unknown framebuffer status";
break;
}
mprintf(("Failed to create framebuffer: %s\n", error));
return false;
}
// generate and test the framebuffer and textures that we are going to use
static bool opengl_post_init_framebuffer()
{
@@ -953,17 +880,6 @@ static bool opengl_post_init_framebuffer()
opengl_setup_bloom_textures();
if ( Cmdline_shadow_quality ) {
int size = (Cmdline_shadow_quality == 2 ? 1024 : 512);
if (!opengl_init_shadow_framebuffer(size, GL_RGBA32F)) {
if (!opengl_init_shadow_framebuffer(size, GL_RGBA16F)) {
mprintf(("Failed to create either 32 or 16-bit color shadow framebuffer. Disabling shadow support.\n"));
Cmdline_shadow_quality = 0;
}
}
}
GL_state.BindFrameBuffer(0);
rval = true;
+1 -1
View File
@@ -50,7 +50,7 @@ void gr_opengl_query_value(int obj, QueryType type) {
glQueryCounter(slot.name, GL_TIMESTAMP);
break;
default:
Assertion(false, "Unhandled enum value!");
UNREACHABLE("Unhandled enum value!");
break;
}
}
+103 -17
View File
@@ -8,6 +8,7 @@
*/
#include "cfile/cfile.h"
#include "cmdline/cmdline.h"
#include "def_files/def_files.h"
#include "graphics/2d.h"
@@ -63,6 +64,7 @@ opengl_uniform_block_binding GL_uniform_blocks[] = {
* Static lookup reference for shader uniforms
* When adding a new shader, list all associated uniforms and attributes here
*/
// clang-format off
static opengl_shader_type_t GL_shader_types[] = {
{ SDR_TYPE_MODEL, "main-v.sdr", "main-f.sdr", "main-g.sdr",
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD, opengl_vert_attrib::NORMAL, opengl_vert_attrib::TANGENT, opengl_vert_attrib::MODEL_ID }, "Model Rendering" },
@@ -99,7 +101,7 @@ static opengl_shader_type_t GL_shader_types[] = {
{ SDR_TYPE_DEFERRED_LIGHTING, "deferred-v.sdr", "deferred-f.sdr", 0,
{ opengl_vert_attrib::POSITION }, "Deferred Lighting" },
{ SDR_TYPE_DEFERRED_CLEAR, "deferred-clear-v.sdr", "deferred-clear-f.sdr", 0,
{ opengl_vert_attrib::POSITION }, "Clear Deferred Lighting Buffer" },
@@ -126,7 +128,11 @@ static opengl_shader_type_t GL_shader_types[] = {
{ SDR_TYPE_SCENE_FOG, "post-v.sdr", "fog-f.sdr", nullptr,
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Scene fogging" },
{ SDR_TYPE_ROCKET_UI, "rocketui-v.sdr", "rocketui-f.sdr", nullptr,
{ opengl_vert_attrib::POSITION, opengl_vert_attrib::COLOR, opengl_vert_attrib::TEXCOORD }, "libRocket UI" },
};
// clang-format on
/**
* Static lookup reference for shader variant uniforms
@@ -213,9 +219,9 @@ static opengl_shader_variant_t GL_shader_variants[] = {
{ },
"Normal Alpha" },
{ SDR_TYPE_MODEL, false, SDR_FLAG_MODEL_NORMAL_EXTRUDE, "FLAG_NORMAL_EXTRUDE",
{ SDR_TYPE_MODEL, true, SDR_FLAG_MODEL_THICK_OUTLINES, "FLAG_THICK_OUTLINE",
{ },
"Normal Extrusion" },
"Thick outlines" },
{ SDR_TYPE_EFFECT_PARTICLE, true, SDR_FLAG_PARTICLE_POINT_GEN, "FLAG_EFFECT_GEOMETRY",
{ opengl_vert_attrib::UVEC },
@@ -337,19 +343,20 @@ void opengl_shader_shutdown()
GL_shader.clear();
}
static SCP_string opengl_shader_get_header(shader_type type_id, int flags) {
static SCP_string opengl_shader_get_header(shader_type type_id, int flags, bool has_geo_shader) {
SCP_stringstream sflags;
sflags << "#version " << GLSL_version << " core\n";
if (GL_workaround_clipping_planes) {
sflags << "#define WORKAROUND_CLIPPING_PLANES\n";
}
if (Detail.lighting < 3) {
sflags << "#define FLAG_LIGHT_MODEL_BLINN_PHONG\n";
}
if (has_geo_shader) {
// If there is a geometry shader then we define a special preprocessor symbol to make writing shaders easier
sflags << "#define HAS_GEOMETRY_SHADER\n";
}
if (type_id == SDR_TYPE_POST_PROCESS_MAIN || type_id == SDR_TYPE_POST_PROCESS_LIGHTSHAFTS || type_id == SDR_TYPE_POST_PROCESS_FXAA) {
// ignore looking for variants. main post process, lightshafts, and FXAA shaders need special headers to be hacked in
opengl_post_shader_header(sflags, type_id, flags);
@@ -476,9 +483,9 @@ static SCP_string handle_includes(const char* filename, const SCP_string& origin
return output.str();
}
static SCP_vector<SCP_string> opengl_get_shader_content(shader_type type_id, const char* filename, int flags, shader_stage) {
static SCP_vector<SCP_string> opengl_get_shader_content(shader_type type_id, const char* filename, int flags, bool has_geo_shader) {
SCP_vector<SCP_string> parts;
parts.push_back(opengl_shader_get_header(type_id, flags));
parts.push_back(opengl_shader_get_header(type_id, flags, has_geo_shader));
parts.push_back(handle_includes(filename, opengl_load_shader(filename)));
@@ -505,6 +512,9 @@ static SCP_string get_shader_hash(const SCP_vector<SCP_string>& vert,
md5.update(reinterpret_cast<const char*>(&i), sizeof(i));
}
md5.update(GL_implementation_id.data(),
(MD5::size_type)GL_implementation_id.size() * sizeof(SCP_string::value_type));
md5.finalize();
return md5.hexdigest();
@@ -532,7 +542,8 @@ static bool load_cached_shader_binary(opengl::ShaderProgram* program, const SCP_
auto metadata = base_filename + ".json";
auto binary = base_filename + ".bin";
auto metadata_fp = cfopen(metadata.c_str(), "rb", CFILE_NORMAL, CF_TYPE_CACHE);
auto metadata_fp = cfopen(metadata.c_str(), "rb", CFILE_NORMAL, CF_TYPE_CACHE, false,
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
if (!metadata_fp) {
nprintf(("ShaderCache", "Metadata file does not exist.\n"));
return false;
@@ -559,7 +570,22 @@ static bool load_cached_shader_binary(opengl::ShaderProgram* program, const SCP_
auto binary_format = (GLenum) format;
json_decref(metadata_root);
auto binary_fp = cfopen(binary.c_str(), "rb", CFILE_NORMAL, CF_TYPE_CACHE);
bool supported = false;
for (auto supported_fmt : GL_binary_formats) {
if ((GLenum)supported_fmt == binary_format) {
supported = true;
break;
}
}
if (!supported) {
// This can happen in case an implementation stops supporting a particular binary format
nprintf(("ShaderCache", "Unsupported binary format %d encountered in shader cache.\n", binary_format));
return false;
}
auto binary_fp = cfopen(binary.c_str(), "rb", CFILE_NORMAL, CF_TYPE_CACHE, false,
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
if (!binary_fp) {
nprintf(("ShaderCache", "Binary file does not exist.\n"));
return false;
@@ -622,7 +648,8 @@ static void cache_program_binary(GLuint program, const SCP_string& hash) {
auto metadata_name = base_filename + ".json";
auto binary_name = base_filename + ".bin";
auto metadata_fp = cfopen(metadata_name.c_str(), "wb", CFILE_NORMAL, CF_TYPE_CACHE);
auto metadata_fp = cfopen(metadata_name.c_str(), "wb", CFILE_NORMAL, CF_TYPE_CACHE, false,
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
if (!metadata_fp) {
mprintf(("Could not open shader cache metadata file!\n"));
return;
@@ -637,7 +664,8 @@ static void cache_program_binary(GLuint program, const SCP_string& hash) {
cfclose(metadata_fp);
json_decref(metadata);
auto binary_fp = cfopen(binary_name.c_str(), "wb", CFILE_NORMAL, CF_TYPE_CACHE);
auto binary_fp = cfopen(binary_name.c_str(), "wb", CFILE_NORMAL, CF_TYPE_CACHE, false,
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
if (!binary_fp) {
mprintf(("Could not open shader cache binary file!\n"));
return;
@@ -690,13 +718,13 @@ void opengl_compile_shader_actual(shader_type sdr, const uint &flags, opengl_sha
}
}
auto vert_content = opengl_get_shader_content(sdr_info->type_id, sdr_info->vert, flags, SDR_STAGE_VERTEX);
auto frag_content = opengl_get_shader_content(sdr_info->type_id, sdr_info->frag, flags, SDR_STAGE_FRAGMENT);
auto vert_content = opengl_get_shader_content(sdr_info->type_id, sdr_info->vert, flags, use_geo_sdr);
auto frag_content = opengl_get_shader_content(sdr_info->type_id, sdr_info->frag, flags, use_geo_sdr);
SCP_vector<SCP_string> geom_content;
if (use_geo_sdr) {
// read geometry shader
geom_content = opengl_get_shader_content(sdr_info->type_id, sdr_info->geo, flags, SDR_STAGE_GEOMETRY);
geom_content = opengl_get_shader_content(sdr_info->type_id, sdr_info->geo, flags, use_geo_sdr);
}
auto shader_hash = get_shader_hash(vert_content, geom_content, frag_content);
@@ -835,6 +863,62 @@ void gr_opengl_recompile_all_shaders(const std::function<void(size_t, size_t)>&
}
}
static void opengl_purge_shader_cache_type(const char* ext) {
SCP_string filter("*.");
filter += ext;
// Previously the cache files were stored in the mod directory. Since we have a better system now, those files
// should be cleaned out. This is only needed if we have a mod directory since otherwise we would delete the actual
// cache files
if (Cmdline_mod != nullptr && strlen(Cmdline_mod) > 0) {
SCP_vector<SCP_string> cache_files;
cf_get_file_list(cache_files, CF_TYPE_CACHE, filter.c_str(), CF_SORT_NONE, nullptr,
CF_LOCATION_TYPE_PRIMARY_MOD | CF_LOCATION_TYPE_SECONDARY_MODS);
for (auto& file : cache_files) {
cf_delete((file + "." + ext).c_str(), CF_TYPE_CACHE,
CF_LOCATION_TYPE_PRIMARY_MOD | CF_LOCATION_TYPE_SECONDARY_MODS);
}
}
SCP_vector<SCP_string> cache_files;
SCP_vector<file_list_info> file_info;
cf_get_file_list(cache_files, CF_TYPE_CACHE, filter.c_str(), CF_SORT_NONE, &file_info,
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
Assertion(cache_files.size() == file_info.size(),
"cf_get_file_list returned different sizes for file names and file informations!");
const auto TIMEOUT = 2.0 * 30.0 * 24.0 * 60.0 * 60.0; // purge timeout in seconds which is ~2 months
const SCP_string PREFIX = "ogl_shader-";
auto now = std::time(nullptr);
for (size_t i = 0; i < cache_files.size(); ++i) {
auto& name = cache_files[i];
auto write_time = file_info[i].write_time;
if (name.compare(0, PREFIX.size(), PREFIX) != 0) {
// Not an OpenGL cache file
continue;
}
auto diff = std::difftime(now, write_time);
if (diff > TIMEOUT) {
auto full_name = name + "." + ext;
cf_delete(full_name.c_str(), CF_TYPE_CACHE);
}
}
}
static void opengl_purge_old_shader_cache()
{
opengl_purge_shader_cache_type("json");
opengl_purge_shader_cache_type("bin");
}
/**
* Initializes the shader system. Creates a 1x1 texture that can be used as a fallback texture when framebuffer support is missing.
* Also compiles the shaders used for particle rendering.
@@ -859,6 +943,8 @@ void opengl_shader_init()
// Reserve 32 shader slots. This should cover most use cases in real life.
GL_shader.reserve(32);
opengl_purge_old_shader_cache();
// compile effect shaders
gr_opengl_maybe_create_shader(SDR_TYPE_EFFECT_PARTICLE, 0);
gr_opengl_maybe_create_shader(SDR_TYPE_EFFECT_PARTICLE, SDR_FLAG_PARTICLE_POINT_GEN);
+116 -73
View File
@@ -106,7 +106,7 @@ static GLenum convertBufferType(BufferType type) {
case BufferType::Uniform:
return GL_UNIFORM_BUFFER;
default:
Assertion(false, "Unhandled enum value!");
UNREACHABLE("Unhandled enum value!");
return GL_INVALID_ENUM;
}
}
@@ -120,7 +120,7 @@ static GLenum convertUsageHint(BufferUsageHint usage) {
case BufferUsageHint::Streaming:
return GL_STREAM_DRAW;
default:
Assertion(false, "Unhandled enum value!");
UNREACHABLE("Unhandled enum value!");
return GL_INVALID_ENUM;
}
}
@@ -144,7 +144,7 @@ static GLenum convertStencilOp(const StencilOperation stencil_op) {
case StencilOperation::Invert:
return GL_INVERT;
default:
Assertion(false, "Unhandled enum value encountered!");
UNREACHABLE("Unhandled enum value encountered!");
return GL_NONE;
}
}
@@ -177,7 +177,7 @@ static GLenum convertComparisionFunction(ComparisionFunction func) {
mode = GL_NOTEQUAL;
break;
default:
Assertion(false, "Unhandled comparision function value!");
UNREACHABLE("Unhandled comparision function value!");
mode = GL_ALWAYS;
break;
}
@@ -412,70 +412,92 @@ void opengl_destroy_all_buffers()
GL_vertex_buffers_in_use = 0;
}
static bool opengl_init_shadow_framebuffer(int size, GLenum color_format)
{
mprintf(("Trying to create %dx%d %d-bit shadow framebuffer\n", size, size, color_format == GL_RGBA32F ? 32 : 16));
glGenFramebuffers(1, &shadow_fbo);
GL_state.BindFrameBuffer(shadow_fbo);
glGenTextures(1, &Shadow_map_depth_texture);
GL_state.Texture.Enable(Shadow_map_depth_texture);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT32, size, size, 4, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, Shadow_map_depth_texture, 0);
glGenTextures(1, &Shadow_map_texture);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D_ARRAY);
GL_state.Texture.Enable(Shadow_map_texture);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, color_format, size, size, 4, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, nullptr);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, Shadow_map_texture, 0);
auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
GL_state.BindFrameBuffer(0);
if (status == GL_FRAMEBUFFER_COMPLETE) {
// Everything is fine
mprintf(("Shadow framebuffer created successfully.\n"));
return true;
}
// Clean up resources
glDeleteTextures(1, &Shadow_map_texture);
glDeleteTextures(1, &Shadow_map_depth_texture);
glDeleteFramebuffers(1, &shadow_fbo);
Shadow_map_texture = 0;
Shadow_map_depth_texture = 0;
shadow_fbo = 0;
const char* error;
switch (status) {
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
error = "Incomplete framebuffer attachment";
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
error = "Framebuffer is missing an attachment";
break;
case GL_FRAMEBUFFER_UNSUPPORTED:
error = "Framebuffer configuration is unsupported";
break;
default:
error = "Unknown framebuffer status";
break;
}
mprintf(("Failed to create framebuffer: %s\n", error));
return false;
}
void opengl_tnl_init()
{
Transform_buffer_handle = opengl_create_texture_buffer_object();
if(Cmdline_shadow_quality)
{
//Setup shadow map framebuffer
glGenFramebuffers(1, &shadow_fbo);
GL_state.BindFrameBuffer(shadow_fbo);
glGenTextures(1, &Shadow_map_depth_texture);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D_ARRAY);
GL_state.Texture.Enable(Shadow_map_depth_texture);
opengl_set_object_label(GL_TEXTURE, Shadow_map_depth_texture, "Scene shadow depth map");
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
//glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT);
//glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
//glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);
if (Cmdline_shadow_quality) {
int size = (Cmdline_shadow_quality == 2 ? 1024 : 512);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT32, size, size, 4, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, size, size, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, Shadow_map_depth_texture, 0);
//glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, Shadow_map_depth_texture, 0);
glGenTextures(1, &Shadow_map_texture);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D_ARRAY);
GL_state.Texture.Enable(Shadow_map_texture);
opengl_set_object_label(GL_TEXTURE, Shadow_map_texture, "Scene shadow map");
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB32F, size, size, 4, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, size, size, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, Shadow_map_texture, 0);
//glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, Shadow_map_texture, 0);
GL_state.BindFrameBuffer(0);
opengl_check_for_errors("post_init_framebuffer()");
if (!opengl_init_shadow_framebuffer(size, GL_RGBA32F)) {
if (!opengl_init_shadow_framebuffer(size, GL_RGBA16F)) {
mprintf(("Failed to create either 32 or 16-bit color shadow framebuffer. Disabling shadow support.\n"));
Cmdline_shadow_quality = 0;
}
}
}
gr_opengl_deferred_init();
@@ -758,18 +780,10 @@ void opengl_tnl_set_model_material(model_material *material_info)
GL_state.Texture.SetShaderMode(GL_TRUE);
if (GL_workaround_clipping_planes) {
if (Current_shader->flags & SDR_FLAG_MODEL_CLIP) {
GL_state.ClipDistance(0, true);
} else {
GL_state.ClipDistance(0, false);
}
if (Current_shader->flags & SDR_FLAG_MODEL_CLIP) {
GL_state.ClipDistance(0, true);
} else {
if (Current_shader->flags & SDR_FLAG_MODEL_CLIP || Current_shader->flags & SDR_FLAG_MODEL_TRANSFORM) {
GL_state.ClipDistance(0, true);
} else {
GL_state.ClipDistance(0, false);
}
GL_state.ClipDistance(0, false);
}
uint32_t array_index;
@@ -982,6 +996,7 @@ void opengl_tnl_set_material_nanovg(nanovg_material* material_info) {
Current_shader->program->Uniforms.setUniformi("nvg_tex", 0);
}
void opengl_tnl_set_material_decal(decal_material* material_info) {
opengl_tnl_set_material(material_info, false);
@@ -1024,6 +1039,34 @@ void opengl_tnl_set_material_decal(decal_material* material_info) {
}
}
void opengl_tnl_set_rocketui_material(interface_material* material_info)
{
vec3d offset = vmd_zero_vector;
offset.xyz.x = material_info->get_offset().x;
offset.xyz.y = material_info->get_offset().y;
matrix4 modelViewMatrix;
vm_matrix4_set_transform(&modelViewMatrix, &vmd_identity_matrix, &offset);
opengl_tnl_set_material(material_info, false);
Current_shader->program->Uniforms.setUniformMatrix4f("modelViewMatrix", modelViewMatrix);
Current_shader->program->Uniforms.setUniformMatrix4f("projMatrix", gr_projection_matrix);
Current_shader->program->Uniforms.setUniformi("textured", material_info->is_textured() ? GL_TRUE : GL_FALSE);
Current_shader->program->Uniforms.setUniformi("baseMap", 0);
if (material_info->is_textured()) {
float u_scale, v_scale;
uint32_t array_index;
if (!gr_opengl_tcache_set(material_info->get_texture_map(TM_BASE_TYPE), material_info->get_texture_type(),
&u_scale, &v_scale, &array_index)) {
mprintf(("WARNING: Error setting bitmap texture (%i)!\n", material_info->get_texture_map(TM_BASE_TYPE)));
}
Current_shader->program->Uniforms.setUniformi("baseMapIndex", array_index);
}
}
void gr_opengl_set_viewport(int x, int y, int width, int height) {
glViewport(x, y, width, height);
}
Loaded 100 of 531 files, more files were not shown because too many files have changed in this diff. Show more