Compare commits

..
Author SHA1 Message Date
SirKnightly 4a654272ea Automated build commit 2024-10-28 01:17:49 +00:00
Tyler Blount 91a2291c03 Merge pull request #6386 from MjnMixael/fix_skip_to_string
Return false if skip to string can't find the string
2024-10-20 10:36:57 -07:00
Goober5000 83d12684e4 Merge pull request #6390 from Goober5000/re_add_fighter-bomber
add the fighter/bomber type back to objecttypes.tbl
2024-10-13 17:02:11 -04:00
Goober5000 565d91b6dc add the fighter/bomber type back to objecttypes.tbl
A few missions used the fighter/bomber ship type, so this adds the type back to make those missions work again.

Temporary fix for #6388.  A more proper fix will be applied after the official 24.2 release.
2024-10-12 22:12:22 -04:00
mjn-mixael a1a5780104 return false if skip to string can't find the string 2024-10-07 16:17:49 -05:00
wookieejedi 49ee006dd5 Fix overlappig XSTRs (#6381)
The XSTR entry 1779 (strings.tbl) is used for two different texts:

"Disabled" in shadows.cpp;
"Toggle Auto Pilot" in controlsconfigcommon.cpp;

"Disabled" is already assigned to XSTR 413. ATM I have this set to shadow's usage (even though 413 is related to Disabled ships). Alternatively I would be happy to use `"Off", 1693`, which is what the other graphic settings use (though the actual value in the code would still remain `Disabled` of course).
2024-10-06 09:32:07 -04:00
Goober5000 b734d6017f Merge pull request #6382 from Goober5000/cargo_title_initialization
properly initialize cargo titles
2024-10-04 22:20:13 -04:00
Goober5000 349a9927cc properly initialize cargo titles
This adds several missing initializations of cargo titles for both ships and subsystems.  Note that `Subsys_status` initialization needs to happen in `allocate_subsys_status()`, because subsystems can be allocated in red-alert or in the `ship-copy-damage` SEXP, not just parsing.

Follow-up to #6000.  Fixes a rather insidious ERANGE error in Inferno.
2024-10-04 00:56:47 -04:00
Tyler Blount da9ae0dd69 Merge pull request #6368 from Baezon/tmap-25-verts-error
Have TMAP chunks report >25 verts polygon error as well
2024-09-29 13:27:43 -07:00
Tyler Blount 04f5c2ff84 Merge pull request #6363 from Goober5000/voice_manager_modifications
set the modified flag in the Voice Acting Manager
2024-09-29 13:27:26 -07:00
Tyler Blount d723300c86 Merge pull request #6370 from MageKing17/bugfix/ingame-shockwave-options-clarity
Make Shockwaves in-game option force multi-value selection.
2024-09-29 13:26:08 -07:00
wookieejedi c9e9b9849a Fixes Lab Rendering when Zooming (#6373)
Fixes #6372 by more specifically setting the `MR_ATTACHED_MODEL` value and by correctly setting the `MR_NO_INSIGNIA`.

Tested and fixes the issue.
2024-09-29 11:19:16 -04:00
MageKing17 44b4c04058 Make Shockwaves in-game option force multi-value selection.
This makes it so that the "3D"/"2D" display is actually respected in the in-game options menu, rather than just having an ambiguous checkbox labelled "Shockwaves".
2024-09-26 22:23:52 -07:00
Goober5000 fbee2b8f49 Merge pull request #6367 from Goober5000/remove_bogus_ship_types
remove bogus ship types from objecttypes.tbl
2024-09-26 19:54:22 -04:00
Asteroth 6c1bb9a617 make 25 verts error for tmap too 2024-09-25 19:34:41 -04:00
Goober5000 09d89066ec remove bogus ship types from objecttypes.tbl
The "stealth" and "fighter/bomber" ship class flags are not actual ship types, so they should never have been added to objecttypes.tbl.  Remove them from the built-in table.

Additionally, if a mod *does* use "stealth" in its own objecttypes.tbl, remove it.  This prevents the invalid "stealth" type from overriding a valid existing type, which fixes #6366.
2024-09-25 01:27:39 -04:00
Goober5000 03b99a3fd0 Merge pull request #6361 from Goober5000/derp
derp
2024-09-22 22:05:23 -04:00
Goober5000 6f089d74cb set the modified flag in the Voice Acting Manager
When actions in the Voice Acting Manager modify the mission, set the modified flag so that FRED will prompt to save the mission.  And since this requires tracking the number of modifications, enhance the dialog boxes to display this information to the user.

Fixes #6362.
2024-09-22 22:01:21 -04:00
Goober5000 62180212f5 derp
Counting is A-1 SUPAR.
2024-09-21 18:06:35 -04:00
Tyler Blount c6cd2de577 Merge pull request #6357 from Goober5000/swarminfo_corkscrewinfo_functions
use functions for getting swarm info and corkscrew info
2024-09-20 09:32:38 -07:00
Tyler Blount 466995a909 Merge pull request #6355 from MjnMixael/adjust_options_message
Clarify options popup message text
2024-09-20 09:32:11 -07:00
Goober5000 56fc5b457f Merge pull request #6352 from Goober5000/allow_explicitly_empty_sounds
allow explicitly empty sounds
2024-09-17 22:27:56 -04:00
Goober5000 461c62823c Merge pull request #6356 from Goober5000/retail_style_warning_fix
retail-style warning fix
2024-09-17 22:27:48 -04:00
Goober5000 24555ac739 add functions for getting swarm info and corkscrew info
Apparently virtvars can only return one value.  This deprecates the virtvars and adds function equivalents for getting weapon class swarm info and corkscrew info.  Fixes a bug reported by Woolie Wool in Discord.
2024-09-17 14:07:26 -04:00
Goober5000 d67fe30982 retail-style warning fix
The warning for mismatched names-and-indexes implicitly assumed that retail-style sounds would only be added with numeric indexes.  Since adding named sounds in the retail style is, in fact, allowed, update the logic to not warn in that case.

Fixes #6354.
2024-09-16 23:39:58 -04:00
mjn-mixael e35b03dc61 Clarify options popup message text 2024-09-16 09:56:42 -05:00
Goober5000 b596fa305d allow explicitly empty sounds
Make sounds that are specified as "empty" or "none" in sounds.tbl ineligible for treatment as placeholder sounds.  Resolves #6350.
2024-09-13 16:42:13 -04:00
Goober5000 f08d82be23 Merge pull request #6348 from Goober5000/hud_gauge_bugfix
two HUD fixes
2024-09-11 14:03:21 -04:00
Goober5000 dfe34ec58d update documentation 2024-09-11 02:03:40 -04:00
Goober5000 2f3423d70e fix "hudgauge" custom parameter
Since the `OPF_ANY_HUD_GAUGE` type checks for any default or custom HUD gauge in regular SEXP operators, it should do so in scripted SEXP operators as well.
2024-09-11 01:45:44 -04:00
Goober5000 98de7323aa fix crash in hud_get_custom_gauge()
The `Player_ship` variable can sometimes be NULL, especially in FRED, so revise the conditional to check for this.
2024-09-11 01:31:22 -04:00
BMagnu b6879da96d Fix deferred lighting Option (#6346)
* Fix deferred lighting option

* Fix issue

* Fix premature cache

* Appease Clang

* cache specific option not options in general
2024-09-09 21:37:49 +00:00
Goober5000 45d99265b8 Merge pull request #6339 from Goober5000/empty_sounds_fix
further refinement of sound fixes
2024-09-08 21:09:56 -04:00
Goober5000 ee9770d418 properly fill sounds into placeholder slots 2024-09-05 02:36:49 -04:00
Goober5000 9d6c8509ab proactively set placeholder sounds to invalid 2024-09-05 02:36:28 -04:00
Goober5000 854b0139d2 fix sound initialization (#6333)
Fix a small oversight from #6112.  In the empty/placeholder indexed sound situation, although the sound should not be appended (since it indexed), it should still be treated as a new sound, in order for all the first-parse and first-initialize logic to run properly.  Set the right value and add some comments to illuminate the logic.
2024-08-30 08:42:33 -04:00
Goober5000 c59a967f46 Merge pull request #6331 from Goober5000/save_version_update
update detection of save version
2024-08-28 21:45:56 -04:00
Tyler Blount e6f46cf031 Merge pull request #6328 from MjnMixael/fix_fade_icons
Fix fade icons not matching parent
2024-08-28 18:44:48 -07:00
Tyler Blount 10f6f47819 Merge pull request #6327 from MjnMixael/fix_briefing_icons_4k
Fix Briefing Icons at 4K in SCPUI
2024-08-28 18:44:35 -07:00
Goober5000 328e7d37e0 update detection of save version
Looking at the log of missionsave.cpp, the presence of a ship or subsystem cargo title will necessitate a minimum version of 24.1.
2024-08-28 21:23:19 -04:00
mjn-mixael b4ace94637 remove the whole block 2024-08-28 17:05:50 -05:00
mjn-mixael 68943d2c06 cleanup 2024-08-28 16:58:31 -05:00
mjn-mixael a3e62433f2 you're killing me, clang 2024-08-28 13:09:59 -05:00
mjn-mixael 5475c63309 Fix fade icons not matching the scaling and orientation of their parent icons 2024-08-28 12:55:00 -05:00
mjn-mixael 3a7c532d1a remove unncessary return 2024-08-28 10:13:35 -05:00
Goober5000 39565d36e2 Merge pull request #6325 from Goober5000/probability-curves-followup
follow-up to probability curves
2024-08-28 01:02:29 -04:00
Goober5000 c8aa28b1cc follow-up to probability curves
Fix the inadvertent swapping of the two utility functions for parsing sounds.  While we're at it, streamline a few lines, remove a few C-style casts, and remove an unused function prototype.

Follow-up to #6314.  Fixes a crash encountered by Inferno on 24.2-RC1.
2024-08-27 23:30:25 -04:00
Goober5000 b98b8f2d07 Merge pull request #6324 from Goober5000/fotg_sound_fix
fix deletion of looping sounds
2024-08-27 15:27:52 -04:00
Goober5000 28659bb1f9 fix deletion of looping sounds
Per the comment earlier in this function, both -1 and -2 are expected values for sound indexes.  Update the sound validity check accordingly.  Fixes an assertion in `obj_snd_delete()` encountered by FotG when a sound index was -2.
2024-08-27 15:10:14 -04:00
Mike Nelson d68b18dfc8 Upgraded Asteroid Field SEXPs (#6295)
* upgrade asteroid sexps to match new asteroid field features

* clang is a needy boy

* unify the sexp operators into one since there are minimal changes

* cleanup for readability

* address feedback
2024-08-27 20:36:54 +02:00
Mike Nelson 40bbced2f9 Reset hotkey lines before populating (#6318)
* reset hotkey lines before building

* clang is the most high maintenance partner i've ever had
2024-08-27 20:36:46 +02:00
Goober5000 a84941e6d1 Merge pull request #6323 from Goober5000/6317_followup
follow-up to BWO crash fix
2024-08-27 14:29:27 -04:00
John FernandezandGoober5000 faaa235c84 Fix: Always check for nullptrs and make red-alert respect cur_waves from last mission (#6262)
* keep from crashing

* Also, bash the number of waves if necessary

* Add Debug warning to modders

* address feedback

* formatting

---------

Co-authored-by: Goober5000 <[email protected]>
2024-08-27 14:18:37 -04:00
Goober5000 33f136dd26 follow-up to BWO crash fix
The BWO fix in PR #6317 was not quite the correct fix.  The `sim_room_lines` array contains the maximum number of scrollable lines, not the maximum number of lines on the screen at one time.  This partially reverts commit 20338ff28b and implements a new fix that allows the full `MAX_LINES` but also properly checks the list button limit.  Additionally, this adds the list button limit check to other vulnerable code sections.

Fixes the tech room being limited to a single page of missions after #6317.  Testing confirms that the BWO crash is still fixed with this update.
2024-08-27 14:06:13 -04:00
Asteroth bec860e9d8 Small optimization (#6321)
* small optimization

* put this comment where it was before
2024-08-27 02:30:03 -04:00
Mike Nelson 6280ffe0e1 Accessibility IFF colors (#6300)
* accessibility iff colors

* appease clang the conqueror
2024-08-27 00:36:18 +02:00
Kestrellius 91a673ac58 Generic random distributions, including curve-based (#6314)
* Adds PDF to CDF function.

* Further implementation; not complete

* Implements curve integration.

* Implements binary search.

* Finalizes random-range reorganization

* Extends generic range support to various things.

* Removes infinities.

* Fixes bugs.

* Adds handling of invalid prob curves.

* Adjusts warning.

* Exception handling

* Addresses issues raised during review.

* Cleanup

* Appeases clang

* Further appeasement

* even further appeasement

* appeasement^3

* appeasement^4
2024-08-27 00:27:33 +02:00
Goober5000 a74bfab94b Merge pull request #6278 from Goober5000/timestamp_refinement
some timestamp refinements
2024-08-26 16:09:31 -04:00
Goober5000 12784be019 use new isFinite() in several existing expressions 2024-08-26 15:11:15 -04:00
Mike Nelson 23f7fa7f02 Fix brown asteroid being an immortal member of the asteroids kingdom (#6320) 2024-08-26 14:55:31 -04:00
Goober5000 8da346dee3 Merge pull request #6304 from Goober5000/immobile_flags
implement don't-change-position and don't-change-orientation
2024-08-26 13:47:47 -04:00
Goober5000 ac16a54bec Merge pull request #6312 from Goober5000/fred_lock_from_editing
add option in FRED to lock objects from being edited
2024-08-26 13:47:39 -04:00
Goober5000 ddfd0c6fca update comment 2024-08-26 01:54:23 -04:00
Goober5000 dccb7dc8cf Merge pull request #6317 from Goober5000/fix_bwo_crash
fix the mysterious crash in BWO
2024-08-25 22:36:38 -04:00
Goober5000 20338ff28b fix the mysterious crash in BWO
This is an error that existed all the way back in retail.  Each line in the simulator room (i.e. each mission name in the list) is also a "button" in the sense that clicking on it will highlight the line and set some values.  The maximum number of buttons is `LIST_BUTTONS_MAX`, but the maximum number of `sim_room_lines` was a different #define, `MAX_LINES`.  This was set to 200, a far higher value than the `LIST_BUTTONS_MAX` value of 42.  The code responsibly checked the limit, but the limit was incorrect.

(This had not been seen in previous mods because the number of lines was never high enough to reach 42.  BWO happened to use a font that was small enough to fit that many lines in the mission simulator screen.  This explains why removing fonts.tbl prevented the bug from occurring.)

Thus when the number of lines reached 42, the sim room started writing to out-of-bounds memory.  This didn't cause a crash immediately, but did corrupt the `Static_lights` vector, which in turn caused a crash as soon as a model was lit in-mission or in the ship loadout screen.  It's rather strange that this crash only occurred in optimized SSE2 builds though.

The fix is simply to use `LIST_BUTTONS_MAX` as the limit, rather than `MAX_LINES`.  This also removes the unused `MAX_DESC_LINES` and `Num_desc_lines` at the same time.

Fixes #6313.
2024-08-25 21:56:37 -04:00
Goober5000 c8010e5447 some timestamp refinements
1. Make sure the legacy `timestamp_until()` and `timestamp_since()` functions check for any type of invalid timestamp
2. Add a useful `isFinite()` function
3. A timestamp delta on an immediate timestamp is more properly the actual delta, rather than another immediate timestamp
2024-08-24 17:24:39 -04:00
Goober5000 92b628353f Merge pull request #6286 from Goober5000/sound_indexing_refinement
improve sounds.tbl index ordering
2024-08-24 16:22:23 -04:00
Goober5000 ff69743836 Merge pull request #6311 from Goober5000/fix_waypoint_marking
fix waypoint marking
2024-08-24 10:37:15 -04:00
Goober5000 38f8943ccf Merge pull request #6316 from Kestrellius/const-matrices
Adds const to a couple batching matrices.
2024-08-23 21:18:31 -04:00
Goober5000 df0f3da79c Merge pull request #6306 from Kestrellius/conditional-impacts-warning
Adds warning if cond-impact armor type not found.
2024-08-23 21:01:17 -04:00
Kestrellius f5ccf98b17 Adds const to a couple batching matrices. 2024-08-23 17:59:15 -07:00
Kestrellius e87d311d92 further cleanup 2024-08-22 18:35:11 -07:00
Goober5000 b5acdd607f add option in FRED to lock objects from being edited
Add options to the Edit menu to lock and unlock objects.  Locked objects cannot be selected or dragged.  They can still be edited in the various editors (e.g. Ships, Objects) but not in the main viewing area.

Also add the Selection Lock option to the Edit menu.  It was previously available in the toolbar but this provides another way to access it.
2024-08-22 15:25:30 -04:00
Goober5000 332ccbc2df fix waypoint marking
When the Show Waypoints option is toggled, the marking was not updated as it was for the other options (Show Ships, Show Starts, Show IFFs).  Fix this by calling `correct_marking()`.
2024-08-22 14:23:39 -04:00
EatThePath 32b69eda2a Merge pull request #6307 from naomimyselfandi/fix-weapon-class-swarm-info
Fix WeaponClass.SwarmInfo
2024-08-22 14:13:27 -04:00
Kestrellius a569bd9ab7 Cleanup 2024-08-22 07:01:23 -07:00
Kestrellius ca70a5a242 Adds support for explicit no-armor; cleanup 2024-08-20 12:31:13 -07:00
Mike Nelson 397a1c84ba Grant access to shipclass shield hitpoints value (#6308) 2024-08-20 01:18:07 +02:00
Naomi Coffman ce6a6b447e Fix WeaponClass.SwarmInfo 2024-08-19 14:01:53 -04:00
Kestrellius 5531dfc58d Adds warning if cond-impact armor type not found. 2024-08-19 10:10:00 -07:00
wookieejedi db13168729 Cleanup variable name in weapon_do_area_effect function (#6303)
* Cleanup variable name in `weapon_do_area_effect` function

Per discussion in #6302, this PR renames `other_obj` to `impacted_obj` to minimize confusion

* update other functions with impacted_obj naming

* nullptr

* appease clang's strange rules

* fighting clang continues

* use !empty check instead of > 0

* remove un-needed no lint comment
2024-08-18 20:59:18 +00:00
Goober5000 cc5bb307c0 Merge pull request #6268 from Baezon/remove-some-prints
Remove some overzealous prints
2024-08-17 19:16:14 -04:00
Goober5000 6b0fe5a763 fix template warnings when compiling 2d.cpp (#6305)
Fix several compilation warnings related to templates by properly casting these values.  See also the existing example that uses casts in cmdline.cpp.
2024-08-18 00:59:21 +02:00
Goober5000 704bf95a75 implement don't-change-position and don't-change-orientation
Per #4294, this adds two new flag that, together, are equivalent to the legacy "immobile" flag but individually provide more fine-grained control.  Since the physics for position and orientation have a bit of overlap, the new flag functionality simply reverts whatever position or orientation changes were done by the physics sim.

In the FRED and qtFRED ship flags dialogs, the "immobile" flag (aka "Does Not Move") is replaced by the two new flags, but in FSO the situation is more complicated.  The old and new flags coexist and have overlapping functionality, so the mission designer must be careful to set and unset the appropriate flag (that is, it is possible for both "immobile" and "don't-change-position" to be set at the same time, in which case the ship cannot change position without both flags being unset).  The `set-immobile` and `set-mobile` legacy SEXPs ensure that the new flags are removed so as not to conflict with the legacy flag, but the `alter-ship-flag` and `are-ship-flags-set` SEXPs and the `getFlag` and `setFlag` script functions use exactly what the FREDder/scripter specifies and nothing else.

(I attempted to completely replace "immobile" with the two newer flags, but it proved intractable to do this while maintaining reverse compatibility: retrofitting single-flag functions to apply dual flags for one particular situation made the functions harder to understand as well as introducing many edge cases and opportunities for bugs or "gotchas".)

Implements #4294.
2024-08-17 16:46:48 -04:00
Goober5000 9887a7b638 move secondary_point_reload_pct maintenance to a more sensible location 2024-08-17 16:46:48 -04:00
wookieejedi 908c1c7b32 Fixes CTD with new Friendly Fire Feature (#6302)
* Fixes CTD with new Friendly Fire Feature

On current master I was hitting a CTD when firing a weapon with a shockwave at close range (ie player is within the shockwave zone). The minidump showed `other_obj` was null, so this PR adds some safety checks.

Tested and this fixes the crashes.

* fix obj usage

* one more obj cleanup
2024-08-17 18:30:21 +00:00
BMagnu 619591f680 Fix shuffling of older but active directives (#6299) 2024-08-16 22:01:28 +02:00
EatThePath 16447b7c7b Remove routine exceptions for unset option values (#6296) 2024-08-15 23:38:18 +02:00
Asteroth 05a0220f4a Merge remote-tracking branch 'upstream/master' into remove-some-prints 2024-08-15 17:30:32 -04:00
Asteroth 20bd8b4bf4 switch to nprintf 2024-08-15 17:29:16 -04:00
EatThePath 57c160623a Stop checking the options value for deferred lighting all the time when it requires restart to change. (#6297) 2024-08-15 14:09:25 +02:00
Asteroth 590cfa5f81 Merge pull request #6293 from Baezon/remove-some-int3s-from-hud-code
Remove some int3s from offscreen indicator drawing
2024-08-14 18:10:29 -04:00
Goober5000 8390304a6e Merge pull request #6292 from Goober5000/lua_tostring_nullcheck
safety check for lua_tostring()
2024-08-13 22:39:16 -04:00
Goober5000 f7e934440c parameter deconfliction (#6282)
Prevent compiler warnings caused by the `value` parameter of the external serializers hiding the `value` member of `std::integral_constant`.

Follow-up to #6276.
2024-08-13 23:17:28 +02:00
Kestrellius 6da7830b7b Add offset for tabled particle effects (#6264)
* Adds particle effect offset.

* bugfixing

* Switches to a cleaner approach.

* Futureproofing for particle parenting.

* actually let's just bundle parenting into this one

* working on turrets

* grinding toward turret correctness

* still grinding toward correctness

* Gets turrets working correctly.

* Fixes merge artifact

* appeases clang-tidy

* Updates some comments.

* Updates some comments.

* Tiny bit of cleanup.

* Deduplicates comments.
2024-08-13 23:06:44 +02:00
Kestrellius 67a9f6f5b7 Friendly fire control flags and SEXP (#6265)
* Adds flags.

* Basic structures built; still needs work.

* Fills out SEXP.

* bugfixing

* appeases clang-tidy

* Adds flags.

* Basic structures built; still needs work.

* Fills out SEXP.

* bugfixing

* appeases clang-tidy

* further appeasement

* Makes implementation more consistent.

* Fixes and cleanup as requested.

* Adjusts is_nan handling.
2024-08-13 20:32:02 +02:00
John Fernandez e1be949d0e Merge pull request #6288 from JohnAFernandez/Fix-lead-indicator-behavior
Fix renderLeadCurrentTarget
2024-08-13 13:52:33 -04:00
Asteroth c64a3e5e6a shouldnt lose target either 2024-08-13 13:26:04 -04:00
Asteroth 65d281e3cb remove some int3s 2024-08-13 01:40:31 -04:00
Goober5000 4cbd84d59e safety check for lua_tostring()
The return value of `lua_tostring()` is NULL if (and only if) the string conversion failed.  Many places in the code did not check for this situation, which led to the crash in #6290.

Fixes #6290.
2024-08-12 16:00:24 -04:00
Kestrellius d4cd767679 Beam slash curves (#6269)
* Adds curves for slash completion and rotation.

* Finalization.

* Fixes pointer comparison.

* Updates table parameter to better match behavior.

* Makes requested changes.

* Changes rotation amount to use raw curve.

* Sets curve-1.0 to be equal to full turn rotation.
2024-08-12 19:58:37 +02:00
Goober5000 e9592bc4d7 add scripting support for wing wave min/max delay (#6280)
There was scripting support for wing arrival/departure delays, but not for wave delays.  Now there is.
2024-08-12 19:58:25 +02:00
Goober5000 5bc929d06e add is-species SEXP operator (#6283)
As noted on Discord, there was previously no `is-species` operator.  Now there is.

As a bonus, this also fixes a bug where the pre-existing `is-iff` operator did not work with wings that had not yet arrived.
2024-08-12 19:58:16 +02:00
Goober5000 8dc1ffea94 Merge pull request #6260 from Goober5000/coverity_fixes
some coverity fixes
2024-08-11 17:01:39 -04:00
JohnAFernandez a9fdbac199 Fix one comment's accuracy 2024-08-10 01:29:05 -04:00
JohnAFernandez 01d3e14dc1 Fix renderLeadCurrentTarget
This fixes an edge case in the Average and Multiple modes, where secondary lead indicator rendering was skipped by continue statements when the primary weapons were out of range.   I also added some comments that help people actually understand what this function does as it is very confusing.
2024-08-10 01:09:10 -04:00
Goober5000 61e94636ac Merge pull request #6284 from Goober5000/directive_timing
fix a minor bug with directive marking
2024-08-08 19:01:11 -04:00
Goober5000 d16eb20aea improve sounds.tbl index ordering
Although sound indexing is now done by name, mods which index by number (sc. a number that is treated as a name) expect the indexes to be in numeric order.  When multiple levels of -snd.tbm files add mixed retail-style and new-style sounds, this assumption can be violated due to named sounds being placed into indexes that later files expect to be available.

This PR refines the parsing so that sounds which use a numeric index can pre-empt existing named sounds that have been assigned to that index.  Since named sounds can go anywhere, they are just moved to the end of the list.  This allows the ranges 192-199 and 202-249 to be available for numeric indexes as expected under the old style.  MediaVPs named sounds which were previously parsed into those indexes are bumped to the next available index.

Additionally, this PR doubles the range of numbers that are treated as indexes, to more realistically accommodate additional numbered sounds.  (The number/index distinction is rather arbitrary and is primarily used to avoid creating large sections of unused sounds if a mod were to specify a very large number, e.g. 10001, for a sound name.)

Finally, this changes parse warnings to use `error_display()` so that the warning displays the parsed file and line number.
2024-08-08 19:00:20 -04:00
Goober5000 f2bffd3234 fix a minor bug with directive marking
Fix units are denominated in seconds, while timestamp units are denominated in milliseconds.  This fixes the directive timing check which, after the timestamp upgrade, would time out after 5 and 7 milliseconds instead of 5 and 7 seconds.

Follow-up to #4633.
2024-08-07 02:28:20 -04:00
Kestrellius 35db8e31c9 Adds weapon support, switches parse ordering (#6254) 2024-07-29 22:35:57 +02:00
Kestrellius cb75da4de6 Interpolate particle spawning positions for moving spawner objects (#6249)
* Sets up linear interpolation for object particles.

* Makes interpolation time-based.

* Updates comments to match changes.

* appeases clang-tidy

* Adds interpolation for particle particles.
2024-07-29 22:35:44 +02:00
Goober5000 d057c0b830 Merge pull request #6277 from Goober5000/improve_model_texture_parsing
improve model texture parsing
2024-07-29 16:11:32 -04:00
Goober5000 693a4a346d Merge pull request #6276 from BMagnu/ade_rpc_serialize_cleanup
Slightly clean up RPC API
2024-07-29 16:11:21 -04:00
Goober5000 734efbdb54 variable checks and message enhancements 2024-07-29 16:04:23 -04:00
Goober5000 c6844755d3 address false positives in smart pointers 2024-07-29 16:04:23 -04:00
Goober5000 1ca56897bb some coverity fixes
Check the return value of `eval_wing()`, and tweak the checks for `closeup_pos` in `draw_model_rotating()`.  This addresses a few Coverity defects.
2024-07-29 16:04:16 -04:00
Goober5000 1fae61b873 improve model texture parsing
Model textures that are too long will cause a very unfriendly and hard-to-track down "ERANGE: String" error.  The situation can be greatly improved by checking the string length ahead of time, printing a friendly Warning, and truncating the filename.  This will alert the modder to the source of the problem while also allowing gameplay to continue.
2024-07-29 15:47:22 -04:00
Birk Magnussen 500bf1c2ca Add clang NOLINTs
To explain: Clang's being stupid here, and seemingly does not recognize that the placement new in the deserializers requires a non-const ptr.
2024-07-29 19:59:02 +02:00
John Fernandez 19b415e524 Merge pull request #6275 from JohnAFernandez/Fix-Duplicate-Interface-Sound-Entries-Crash
Fix a sound crash
2024-07-29 08:52:38 -04:00
BMagnu 558f922209 add implicit-only includes 2024-07-29 10:26:59 +02:00
Birk Magnussen 7caef527d4 Slightly clean up RPC API 2024-07-28 11:15:02 +02:00
JohnAFernandez 72b5135df4 Fix an interface sound crash
This would crash because duplicate sounds were not being populated with the original entries.  When snd_set_pos was called, the handle to the Sounds array would not be set, making our code think it was not loaded.
2024-07-28 01:01:10 -04:00
Kestrellius f041b8dace Adds consts to parameters for a couple laser rendering functions. (#6270)
* Adds consts to parameters for a couple functions.

* makes it actually compile
2024-07-25 22:58:24 +02:00
Goober5000 372d2dd18e Merge pull request #6267 from vmedea/2024-07-sdl2
Fix SDL2 pkg-config name
2024-07-25 14:57:10 -04:00
BMagnu 81da8a8499 disable misc-no-recursion (#6266) 2024-07-24 23:33:15 +02:00
Asteroth 6a5cd9fcc5 remove some prints 2024-07-24 13:41:13 -04:00
mara 4ea0757950 Fix SDL2 pkg-config name
The pkg-config name for SDL 2 is lowercase 'sdl2', and it was passed in
upper-case so the proper library was never detected on Linux. Fix the name.
2024-07-24 14:47:02 +00:00
Mike Nelson 79d0c93ba5 Print in game options data to scripting output files (#6257) 2024-07-21 12:25:32 -04:00
Tyler Blount eeba1085c9 Merge pull request #6243 from MjnMixael/per_weapon_convergence
Per weapon auto convergence
2024-07-20 11:57:55 -07:00
Mike Nelson 70629876b9 allow accepting a pilot without changing gamestate (#6235) 2024-07-18 22:44:59 -04:00
Goober5000 e1458ae8ab Merge pull request #6259 from Goober5000/6258_followup
fix copy-paste error in timestamp_since
2024-07-17 18:35:41 -04:00
Goober5000 bac4eb84c0 fix copy-paste error in timestamp_since
The time since an invalid timestamp should be INT_MIN, not INT_MAX.  Follow up to #6258.
2024-07-17 14:24:40 -04:00
Goober5000 20602b19c2 Merge pull request #6255 from Goober5000/atan2_safe_to_atan2
change atan2_safe to atan2
2024-07-17 13:30:13 -04:00
Goober5000 3c3289a3cc Merge pull request #6258 from Goober5000/fix_6256
fix `NextFireTimestamp`
2024-07-17 13:30:04 -04:00
Goober5000 2166c756ab per review, make the delta check silent 2024-07-16 20:59:30 -04:00
Goober5000 5faed98e3a handle special timestamp values in timestamp_until and timestamp_since 2024-07-16 20:27:14 -04:00
Goober5000 fe3b72b01e fix NextFireTimestamp
Changes `NextFireTimestamp` to work as advertised.  Fixes #6256.
2024-07-16 17:27:41 -04:00
Asteroth 8914ac6e2d guards ignore protected attackers (#6253) 2024-07-16 15:46:12 -04:00
Goober5000 87ea04fa53 change atan2_safe to atan2
According to DahBlount:
> Most atan2 implementations for a long time had problems when the inputs were close to machine epsilon or when x was less than or equal to 0

And according to z64555:
> Modern versions of C++ should have an atan2() that works correctly when the inputs are at 0 or near epsilon of the floating point specification, meaning Volition's workaround shouldn't be needed anymore.

So this removes `atan2_safe` and changes all instances to `atan2`.  Consequently, the angle range in FRED now shows as [-180, 180] as expected.

Fixes #3730.
2024-07-15 20:55:57 -04:00
wookieejedi f5a268bcef Expose Minimum LoS Detection Radius (#6252)
The somewhat modern AI flag for `Require_exact_los` is extremely useful in multiple different situations, for example making large capital ship weapons not fire into friendly surrounding ships on accident. When the feature was added, the `check_los` function was provided with a default value of `10.0` meters for minimum radius detection. This PR exposes that value to modders so they can set it to a reasonable value depending on the ship sizes of their specific needs. And as a note, the los value just uses a simple numerical comparison check, so the los detection could be set to a negative value with no consequence (hence why error messages were not added, though if folks would like I can certainly add them).
2024-07-15 08:30:31 -04:00
Goober5000 1db093e1d6 Merge pull request #6251 from Goober5000/popup_keys_fix
fix incorrect processing of keys during ESC popup
2024-07-14 20:07:18 -04:00
Goober5000 3d556af391 Merge pull request #1451 from Goober5000/pilot_stats_fixes
better stats handling when switching or resetting campaigns
2024-07-14 20:06:51 -04:00
mjn-mixael e1fd863dd0 cleanup whitespace 2024-07-14 10:11:22 -05:00
mjn-mixael 1744718a03 We can remove this bool now that we have bools for each flag set 2024-07-14 10:08:50 -05:00
mjn-mixael d9cfd1f626 Fix boolean checks that determine the which aiming style to use 2024-07-14 09:53:19 -05:00
Mike Nelson d9f9996c2d expose shockwave damage (#6245) 2024-07-13 09:29:48 -04:00
Goober5000 6f05c26542 fix incorrect processing of keys during ESC popup
In retail, the processing of certain keys during a popup, in the `popup_process_keys()` function, was dependent upon the `PF_ALLOW_DEAD_KEYS` flag.  This flag was never used in retail, causing the if() block to be marked as dead code.  In a4e623db23, the dead code warning was addressed by removing the dependency on `PF_ALLOW_DEAD_KEYS`, which is incorrect.  The "dead keys" should only be processed during the "dead popup".  Since the "dead popup" was moved to its own de[a]dicated "popupdead" section, the "dead keys" processing can be entirely removed from the "normal popup".

Fixes a bug noticed by @PremiumColt where certain keys, especially the time compression keys, were processed while the ESC popup was active.
2024-07-12 20:08:57 -04:00
Goober5000 944549ae5f Merge pull request #6246 from notimaginative/update_prebuilt_libs
update to newest prebuilt libs
2024-07-12 17:33:41 -04:00
Goober5000 fbab427943 Merge pull request #6250 from Goober5000/coverity_on_scp
only run the Coverity workflow on the SCP repository
2024-07-12 17:32:54 -04:00
Goober5000 705238a184 only run the Coverity workflow on the SCP repository
This prevents Coverity from running on any forked repository, by default; both because the workflow will fail, and also because the workflow's results would be identical.  (Any forked repository can, of course, change this within its own scope.)
2024-07-12 16:28:25 -04:00
Goober5000 7557c54aa9 restore clearing of stats based on comments from #6238 2024-07-11 21:53:16 -04:00
Goober5000 f341987471 Merge pull request #6248 from Baezon/bugfix-invulnerability-time-again
Bug fix for aspect invulnerability timing... again
2024-07-11 21:19:33 -04:00
Goober5000 cdbf525877 Merge pull request #6233 from JohnAFernandez/Add-Insignia-Renderer
Fix Insignia Checkbox in the Lab
2024-07-11 21:19:01 -04:00
Goober5000 cc790a00bd Merge pull request #6223 from Goober5000/address_6010
address 6010
2024-07-11 21:17:40 -04:00
Asteroth b565376a02 account for original retail handling 2024-07-11 01:50:13 -04:00
wookieejedi 52f417500c Fix Settings Localization IDs (#6242)
In `strings.tbl` the graphics settings localization IDs are as follows:
1160, "Low"
1161, "Medium"
1162, "High"
1163, "Very High"

These values are used throughout the code, but in some cases with SCPUI upgrades, the IDs got off by 1. This PR fixes those incorrect IDs.
2024-07-09 18:07:18 -04:00
Taylor Richards 79d6e91403 additional fixes 2024-07-09 12:23:35 -04:00
naomimyselfandi 5235aac95b Respect tabled delay for arrival and backup messages (#6239)
* Respect the tabled delay for Arrive Enemy messages

* Respect the tabled delay for Backup messages
2024-07-09 07:59:22 -04:00
Taylor Richards bebed48bf8 address errors 2024-07-09 04:39:39 -04:00
Taylor Richards 38e27f8a25 update to newest prebuilt libs
Supports newer SDL2 from the prebuilt package on win32/win64
Adds support for Windows ARM64
Adds option to use prebuilt SDL2/OpenAL/Freetype libs on Linux
2024-07-09 03:17:29 -04:00
BMagnu 98d5de9d13 Make clang const correctness a little less aggressive (#6244) 2024-07-08 19:40:48 +00:00
mjn-mixael 6fdaf87717 du const 2024-07-08 14:32:09 -05:00
mjn-mixael acccc90ded per weapon auto convergence 2024-07-08 14:06:56 -05:00
John Fernandez de570875d0 Merge pull request #6231 from JohnAFernandez/Fix-unreliable-channel-soundid-chacing
Fix unreliable Sounds index retrieval
2024-07-07 20:51:22 -04:00
BMagnu e17f0260f6 Update clang tidy to 16 as used to compile (#6236) 2024-07-06 23:01:32 +00:00
BMagnu 6b6a622c4d Fix clang-tidy (#6234)
* Allow clang-tidy to run

* Amend CI check
2024-07-06 15:16:44 +02:00
Goober5000 e90416e199 Several coverity fixes (#6232)
* coverity - using `std::move` instead of copying, and change some parameters from value to reference

* coverity - fix or mark potential copy-paste mistakes

* coverity - various checking of parameter and return values

* coverity - miscellaneous fixes, and change some 'intentional' markers to 'false positive' markers
2024-07-06 12:51:31 +02:00
JohnAFernandez a319adad76 Use constexpr and value, because we broke defines 2024-07-05 17:26:36 -04:00
John Fernandez 97e36d8af6 Don't forget to remove the declaration 2024-07-05 15:24:11 -04:00
wookieejedi f20c1bddfd Fix short read error with red alert csg file reading (#6229)
In current master, the debug log commonly shows `CSG => Warning: (0x0011) Short read, information may have been lost!`.

Thanks to Taylor for pointing the following issue out:
The function `pilotfile::csg_read_redalert()` returns if `ship_list_size` is zero, but it still needs to check the `wing_list_size` a bit below that. This has likely not caused data loss issues ATM, because it's reasonable to assume that if `ship_list_size` is zero then so is `wing_list_size`. But it's still a bug and should be fixed before it does cause some real data loss.

This PR moves the relevant read sections to within each respective if-block. That way the function is capable of checking both `ship_list_size` and `wing_list_size` on every load (even if `ship_list_size` is zero).
2024-07-05 12:50:56 -04:00
JohnAFernandez c50b425fee More type fixes 2024-07-05 01:14:36 -04:00
JohnAFernandez 7a99e9a7c9 Even more type conversions 2024-07-05 01:11:48 -04:00
John Fernandez 84ccd1375e Fix Flag Negation 2024-07-05 00:57:06 -04:00
John Fernandez a7fc64389f Use the correct method to get index to Sounds
Our sound code is extremely confusing, so it's no wonder that the author of these functions could not find snd_get_sound_id.
2024-07-05 00:44:29 -04:00
John Fernandez ac44f1478e Merge pull request #6226 from JohnAFernandez/Try-Saving-Config-Name-As-Default
Save current preset name and use as default when saving new preset name
2024-07-04 21:42:03 -04:00
John Fernandez ffd78555a0 Enable turning off insignias in the LAB 2024-07-04 19:33:33 -04:00
John Fernandez 1f834aa406 change render flags to uint64_t
32 more flags, yay!
2024-07-04 18:08:27 -04:00
JohnAFernandez 4f2f8c9f25 Save Current Preset name and Use when Saving 2024-07-04 00:35:55 -04:00
Goober5000 200ef1093c Merge pull request #6225 from Baezon/fix-poof-alignment
fix poof alignment
2024-07-03 21:12:45 -04:00
Goober5000 691fe96151 Merge branch 'master' into pilot_stats_fixes 2024-07-03 20:56:56 -04:00
Asteroth 840759d59a fix poof alignment 2024-07-03 19:41:21 -04:00
Goober5000 83d07277f2 Merge pull request #6224 from Goober5000/fix_coverity_task
fix coverity task
2024-07-03 17:12:36 -04:00
Goober5000 cccf76863f fix coverity task
Per @notimaginative, change the `compiler` variable to uppercase to match its usage in the rest of the file.  This should allow the coverity task to start running again.
2024-07-03 16:41:18 -04:00
Goober5000 c03207f141 address 6010
I took a close look at the code involved in parsing particle tables.  There is no smoking gun, but there are several ways to polish the code which I have implemented here.  The most likely culprits for the slowdown, IMO, are the repeated conversions between SCP_string and C-string, especially in `ParticleManager::getEffectByName()`; followed by the omission of `std::move` in several places.
2024-07-03 15:06:33 -04:00
John Fernandez 5df0acf3ef Merge pull request #6185 from MjnMixael/assign_hud_in_ships
Assign hud in ships.tbl
2024-07-03 10:40:54 -04:00
Mike Nelson 75221b0ff5 deprecate some commandlines and make some options not require restart (#6214) 2024-07-02 22:44:44 -04:00
Mike Nelson 6a4774dcc4 Change warning print 2024-07-02 17:06:28 -05:00
Goober5000 eed055d41a Merge pull request #6219 from Goober5000/lock_perspective_and_slew
enhance lock-perspective to also lock slew mode
2024-07-01 16:29:22 -04:00
Goober5000 e374db538c Merge pull request #6220 from Goober5000/enhance_stuff_int_list
enhance stuff_int_list to allow turning off the warning
2024-07-01 16:29:14 -04:00
Goober5000 6468901c0d address feedback 2024-07-01 16:01:31 -04:00
Kestrellius d14b66456f Adds conditional impact functionality. (#6218)
* Adds conditional impact functionality.

* Changes as requested.

* Second batch of changes.

* Switches out insert_or_assign so the checks pass.
2024-07-01 21:45:48 +02:00
naomimyselfandi 723209ce29 Clarify some SEXP operator documentation (#6216)
* Clarify some SEXP operator documentation

* Reword SEXP operator descriptions per feedback
2024-07-01 21:45:41 +02:00
Goober5000 98da98c53b enhance stuff_int_list to allow turning off the warning
This will be useful for situations where a missing lookup entry is not valid but nevertheless does not merit a warning.
2024-06-30 22:37:20 -04:00
Goober5000 558a8333e4 add an option to not change the view mode 2024-06-30 21:42:51 -04:00
Goober5000 ffcbfeb70b enhance lock-perspective to also lock slew mode
Adds an optional argument to the `lock-perspective` sexp to allow locking of the 'free look' or 'padlock' view.  This prevents the player from looking around which might not be desired in certain forced perspective situations.
2024-06-30 21:41:17 -04:00
Goober5000 c5de5149a9 Merge pull request #6217 from Goober5000/debris_type_parsing
another follow-up to #6021
2024-06-30 17:08:53 -04:00
Mike Nelson e868d94927 cleanup message_kill_all (#6213) 2024-06-29 11:03:15 -04:00
naomimyselfandi 253d97a3df Allow defining custom message types (#6142)
* Vectorize Builtin_messages

* Allow defining custom message types

* Add OPF_MESSAGE_TYPE

* Add send-builtin-message SEXP operator
2024-06-29 12:32:17 +02:00
Goober5000 da93cc6047 another follow-up to #6021
When loading a legacy mission that contains a debris field, FSO will try to index into an empty vector, causing an out-of-bounds exception.  This can be seen by loading Derelict mission dl1-08, "The Horror in the Deep".

The `// Obsolete and only for backwards compatibility` code added in #6021 properly handles asteroid fields, but not debris fields; so the fix is simply to apply the logic to debris fields as well.
2024-06-28 21:35:12 -04:00
BMagnu b57278ab18 Adds Voluemtrics Toggle SEXP (#6215)
* Allow toggle of volumetrics

* enhance description

* Typo
2024-06-28 17:56:22 +02:00
Goober5000 630f479fd9 properly handle game sounds with numeric IDs (#6212)
Patches the gamesnd system in several ways to properly fix the bug identified in #6196.  Due to the way the new sound system was written, sounds with numeric IDs were not necessarily added in their indexed location, even though the code assumed (even prior to #6112) that this would be the case.  The code now uses the proper index for both old *and* new style sounds.  This is done by ensuring, in `gamesnd_parse_entry()`, that the vector contains an entry for the specified numeric ID before doing a search for that ID.

Due to the slightly modified population of the gamesnd vectors, the `Snds_iface_handle` vector is now populated after parsing the various sounds.tbl files rather than during parsing.

Separately, this makes consistent the handling of the `sound_entries` vector which could potentially be empty but also treated an empty state as an assertion failure.
2024-06-27 23:55:42 -04:00
John Fernandez e7a7c830f0 Merge pull request #6184 from MjnMixael/ship_wep_custom_strings
Custom Strings for ships and weapons
2024-06-27 10:21:01 -04:00
Mike Nelson d6e7d56081 expose method to kill all current voice messages (#6207) 2024-06-27 08:07:35 -04:00
Mike Nelson 5c5bcf72e9 don't kill paused messages either (#6206) 2024-06-27 08:07:19 -04:00
wookieejedi 06f909d7e3 Followup to #6187 (#6211)
#6187 fixed transparency for cockpits, but the positioning for deferred lighting alas fell through the cracks. This PR fixes that and allows deferred lighting in cockpits to once again work as intended.

Tested and fix works as expected.
2024-06-26 14:08:38 +00:00
Mike Nelson 46d4a1f219 fix screenshudder option being optimized out by the compiler (#6204) 2024-06-26 16:51:41 +09:00
BMagnu 7e71d4c194 Add ugly hack to prevent SCPUI flicker on Win11 (#6199) 2024-06-26 16:50:38 +09:00
Goober5000 2314294a8c Merge pull request #6209 from Goober5000/parse_names_clear
clear Parse_names on mission init
2024-06-25 19:50:54 -04:00
Goober5000 3bce3fd631 clear Parse_names on mission init
When a new mission is loaded, clear the parse names vector, in lieu of the old `Num_parse_names = 0;` line.  This fixes a bug where FRED will complain about nonexistent ships when loading a different mission.  Follow-up to #5937.
2024-06-25 17:33:39 -04:00
wookieejedi 31452e397b One more follow-up to #6021 (#6202)
* One more follow-up to #6021

Update assertion message and mission saving check since older builds are not going to be able to read fields created with newer builds

* update to use empty
2024-06-24 02:59:31 +00:00
wookieejedi 80e3030a0c Follow-up to asteroids update #6021 (#6201)
The Unlimited Asteroid/Debris Field Types & Subtypes PR (#6021) updated to using vectors to allow for unlimited asteroid and debris types. That update removed the count field, `num_used_field _debris_types`, which counted both asteroids and debris pieces (even though the name only has debris in it). The counter variable was removed in favor of `.size()` but now both asteroid and debris field sizes needed to be checked, so this PR updates the code to account for that. Allows asteroid fields to properly pass the count check and properly again spawn in mission.

Tested on asteroid fields passive and active along with debris fields (both created from sexps and the asteroid mission editor) and everything now works as expected. Also tested on missions with no fields and those also still work as expected.
2024-06-23 10:53:39 -04:00
John Fernandez 4a739c988f Merge pull request #6198 from MjnMixael/fix_ingame_options_init
Fix ingame options init bugs
2024-06-21 19:40:45 -04:00
mjn-mixael 7b4deb6c6b Fix ingame options init bugs 2024-06-21 14:16:43 -05:00
BMagnu 3d285f2f42 Fix transparent cockpit by ensuring ordering (#6187) 2024-06-21 17:38:47 +02:00
BMagnu 7403f4a1c9 Improve Volumetrics Performance (#6159)
* properly trace volumetrics and explicitly set texture setting

* UDF-ify volumetrics

* Fix warning

* only apply lower bound when actually correct
2024-06-21 17:10:14 +02:00
John Fernandez 9f99a9eae4 Merge pull request #4489 from JohnAFernandez/Ensure-break
Simplify logic here
2024-06-20 01:30:56 -04:00
John Fernandez d11003a869 Simply logic here
Break when you've found a match, instead of just mindlessly comparing the rest.

This is technically just an optimization and safety change, but potentially, before, if the loops had been switched, it would have caused unexpected behavior if two copies of the same flag were listed.
2024-06-20 01:11:19 -04:00
Taylor Richards 1b855044c7 fix data length bug in PXO hole punch packet (#6195)
The header length from the tracker is 1 byte larger than the size calculated
by the client due to psnet removing that byte internally. The header length
is adjusted to compensate for this, but only *after* the deserialization
process, so we have to use the received packet size instead.
2024-06-18 20:39:43 +00:00
John Fernandez a390b5a01a Generalize linear interpolation (#5003)
* Remove old interpolate angles quick

* Remove old interpolate functions

These are no longer used.

* Add linear interpolate vm function

More clearing functions

* Add physics snapshot struct to silo interpolation

Two of these two functions require an object pointer, so they cannot be in physics_state.cpp

With doxygen documentation

* Try to placate Linux

* Address Feedback

* And update declaration, of course

* Attempt to appease linter
2024-06-18 20:10:01 +02:00
John Fernandez 8c913c8cc5 Merge pull request #6192 from notimaginative/pxo_hole_punch
add support for PXO's UDP hole punch feature
2024-06-18 12:04:01 -04:00
Goober5000 ebeec69a6d add API for glow point banks (#6107)
* add API for glow point banks

Previously, a model API existed for glow points mounted on thrusters, but not glow points mounted on glow point banks.  This adds glow point bank support.  Also, this refactors and cleans up the implementation of the model API a bit.

* NULL -> nullptr
2024-06-17 21:28:40 +02:00
Taylor Richards 1821df58cf limit debug log spam from file shadows (#6027)
Always log the possible shadow if:
 1) it's a critical file
 2) it's in the same root

Otherwise log it behind a debug filter ("CFileSystem").
2024-06-16 11:04:01 -04:00
Taylor Richards 3f9ec121ae add support for PXO's UDP hole punch feature
Should allow for most games, even those behind CG-NAT, to work without having
to set up port forwarding. This set of changes is only needed for game servers
to work with the new feature. No special handling is required for clients, so
any build from the last few years should work for them.
2024-06-16 01:58:47 -04:00
Goober5000 408f116d95 Merge pull request #6190 from Goober5000/tactical_goals_allowed
make sure 'tactical' variants of disable and disarm are allowed
2024-06-14 21:51:20 -04:00
Goober5000 ce34f77780 add the attack-ship-class goal as valid for player orders 2024-06-14 00:08:47 -04:00
Goober5000 1bb34cc0ae make sure 'tactical' variants of disable and disarm are allowed
The new `ai-disable-ship-tactical` and `ai-disarm-ship-tactical` goals were inadvertently omitted from the ship type default table, causing these goals to not be available in the Event Editor drop-down menu or Ship Editor initial orders.  Testing did not catch this because testing was done using the HUD squad message system which assigned the new goal (if the flag is enabled) without explicitly checking the validity.

Follow-up to #5512.  Fixes #6189.
2024-06-13 23:52:43 -04:00
Goober5000 f733414403 make mission log dynamic (#6111)
* make mission log dynamic

Change the mission log from a static array to a dynamic vector.  This removes any chance of the mission log running into a limit (as regularly happened with the last mission of Shepherds before the limit bump) and also prevents strange mission bugs caused by culling obsolete entries.

This also unifies the API a bit by renaming the public `message_log_` function prefixes to `mission_log_`, removing the redundant `Num_log_lines` variable, and removing `Log_scrollback_vec` from the header.

Implements #5878.

* feedback

* refactor to reference rather than pointer
2024-06-13 00:17:47 +02:00
Goober5000 9a26d1fba5 Merge pull request #6112 from Goober5000/fix_primary_ammo_rearm
fix ballistic primary banks exploding
2024-06-12 02:29:23 -04:00
John Fernandez c7334de3bd Merge pull request #6188 from MjnMixael/fix_warning_every_frame
Prevent printing a warning every frame
2024-06-11 18:43:04 -04:00
mjn-mixael e1f0042e99 prevent printing a warning every frame 2024-06-11 09:51:28 -05:00
BMagnu 559a2616f3 Fix edge case in MSAA shader (#6186) 2024-06-11 13:41:19 +02:00
Mike Nelson 7f20b9cf64 Unlimited Asteroid/Debris Field Types & Subtypes (#6021)
* base working version of unlimited debris types

* Proper FRED support

* make qtFRED handle asteroids properly

* fix qtFRED assertion

* further clean out MAX_RETAIL_DEBRIS_TYPES

* These should be sizes not POFs

* Move this to it's own method

* convert asteroid subtypes to a vector

* unlimit asteroid subtypes

* fix some global shadowing

* signed/unsigned mismatch

* Address feedback
2024-06-10 22:06:10 +02:00
John Fernandez e1b44892e5 Merge pull request #6170 from TheForce172/feature/ShipPathsDialog
Arrival/Departure Paths Dialog
2024-06-10 15:47:02 -04:00
mjn-mixael 866f907e27 comment clarity 2024-06-10 13:00:30 -05:00
mjn-mixael a1aac15e5a Make $Name style gauge config its own thing 2024-06-10 12:54:39 -05:00
mjn-mixael 49e2d60551 Allow setting gauges in ships.tbl per ship 2024-06-10 12:08:55 -05:00
mjn-mixael 67ebeb438e custom strings for ships and weapons 2024-06-10 09:43:20 -05:00
Goober5000 0f4c3ce8c7 Merge pull request #6181 from Kestrellius/beam-multishot
Make the $Shots parameter work for beams.
2024-06-10 00:33:40 -04:00
wookieejedi 786a4eff42 Follow-up to Unified Scanning (#6183)
Fixes a bug with new unified scanning PR (#6000) and adds a bit of cleanup, including consistent brackets, whitespace cleanup, and removing vestigial function from the original PR.

Tested and works as expected.
2024-06-09 22:26:23 +02:00
BMagnu d87e997d79 Increase Lua safety (#6179)
* disable popen

* Check file type when opening with io lib

* Compile on Windows

* Windows include

* Properly conserve function environment

* Correctly copy fenv
2024-06-09 17:43:54 +02:00
Mike Nelson aee0123587 Allow player-specific options even when using In-Game Options (#6045)
* Move these functions into OptionsManager for more global use

* Make sure player options are preferred even when using OptionsManager

* persist the newly loaded options to disk

* Actually let's persist these only if the load is successful and also handle the multi option

* Comment this out for now I guess
2024-06-09 12:29:15 +02:00
Kestrellius be454f74b0 Merge branch 'master' into beam-multishot 2024-06-09 01:33:44 -07:00
Goober5000 c1985656d1 Merge pull request #6105 from Goober5000/object_h_index
replace pointers with indexes in object_h
2024-06-09 02:24:46 -04:00
Goober5000 d5e387479e replace pointers with indexes in object_h
This refactors the object_h struct to store objects as indexes rather than pointers.  This is a prerequisite for making the collection of objects dynamic in the future.  See also #6100.

Follow-up to #5800 and #5829.
2024-06-09 02:06:22 -04:00
Mike Nelson 574c39210f Ingame options respect mods (#5917)
* Save/Load player options to a mod-specific ini file if possible

* use rfind instead of find to ensure it's the last dash character used for trimming

* cleanup + comments + nullptr

* A more robust way of getting the mod root using lambdas

* prevent infinite loop for non Knossos/Knet mods

* Notify the player if options may need updating and pull settings from fs2_open.ini if we can

* proper localization

* update xstr
2024-06-09 00:26:51 +02:00
Mike Nelson 4432341694 Scanning is chaos, let's make it sane (#6000)
* Unify scanning behavior

* Allow modifying the cargo title

* update localization

* update documentation

* update localization

* address feedback

* fix conflict merge resolution error

* fix oversights, missed subsys title # feature, additional xstrs

* don't need sprintf here
2024-06-08 22:20:22 +02:00
Mike Nelson 8b43b5d325 split up debris and asteroid type handling within the asteroid field struct (#6011) 2024-06-08 21:16:06 +02:00
Asteroth 836840154c Merge pull request #6180 from Goober5000/utility_find
utility functions for counting and searching
2024-06-08 13:43:10 -04:00
Asteroth 41bdcfe720 Merge pull request #6182 from Baezon/beam-fixes
Assorted beam fixes
2024-06-08 13:42:42 -04:00
Goober5000 4cdc0b9c0b change Asserts 2024-06-06 00:39:14 -04:00
John Fernandez c4a7a9dd15 Merge pull request #6157 from Kestrellius/fix-beam-particle-vel
Fix beam particle velocity
2024-06-05 12:51:44 -04:00
Kestrellius f4921b6d01 Makes minor structural changes as requested. 2024-06-05 09:39:10 -07:00
The Force 900199d97f Add confirmation on cancel 2024-06-04 22:57:10 +01:00
Asteroth 230fdf4d03 assorted beam fixes 2024-06-04 17:32:30 -04:00
Kestrellius 0da93ec5fd Adds multishot for beams. 2024-06-04 13:10:54 -07:00
Goober5000 4ed38896d2 Merge pull request #6177 from Goober5000/fix_warnings
fix compilation warnings
2024-06-04 12:05:33 -04:00
Goober5000 3529e49466 utility functions for counting and searching
Inspired by #6178, this moves the existing `count_items_with_name()` functions into utility.h and adds additional functions for finding specific items with a given `.name` or, more generally, a given field.  The `Damage_types` search has been converted to illustrate how these functions can be used.
2024-06-03 23:09:32 -04:00
Goober5000 64c17f4830 fix compilation warnings
Fixes the few remaining compilation warnings in the current codebase.  Also adds comments to the various casting macros for clarity.
2024-06-03 22:19:29 -04:00
wookieejedi b831c773dd Expose Impact Damage Type to Scripting (#6178)
* Expose Impact Damage Type to Scripting

There's already a sexp that does this, but having the script version for ships is quite useful, too. For example, scripters can set impact damage types for just the player at various difficulties.

Tested and works as expected.

* always set damage type
2024-06-03 21:59:35 -04:00
Goober5000 350130ce9d Merge pull request #6100 from Goober5000/model_and_submodel_indexes
convert model_h and submodel_h to use indexes
2024-06-01 21:20:07 -04:00
wookieejedi 1fa0f43c6f Exposes the New Flight Cursor Mode to Scripting and Fixed Aiming Setting (#6173)
* Exposes the New Flight Cursor Mode to Scripting

Thanks to #6136, FSO supports switching between two methods of flying. This PR exposes those settings and values to scripters. Tested and works as expected.

* fix aiming setting

* add reset position function

* cleanup setting pitch and heading

* one more cleanup

* update to enum support

* remove older version

* one more fix for setting flight mode
2024-06-01 02:47:03 +00:00
Goober5000 b5351c7ca8 Merge pull request #6120 from Goober5000/fred_autorecover
Fred autorecover
2024-05-31 21:46:56 -04:00
Goober5000 e4b5d5fb7e Merge pull request #6149 from Kestrellius/fix-headon-discrepancies
Make headon transition behavior consistent between laser and glow bitmaps
2024-05-31 21:46:45 -04:00
Asteroth b1d4e0a5e2 better option ordering comparison (#6133) 2024-05-31 15:05:33 +02:00
BMagnu 6a83875d93 Fix effect framebuffer blit (#6175) 2024-05-31 14:53:50 +02:00
BMagnu 01bb406b3d Allow overriding low-level keypresses (#6174)
* Clean unneeded properties

* properly queue-ify keys

* Refactor key checking to use functions instead of globals

* Update hooks and cache checked-against key

* Documentation and Naming

* match tilde

* only remove control not debug
2024-05-31 14:53:39 +02:00
Goober5000 14aa38eea9 Merge pull request #6172 from Kestrellius/fix-type-5-beam-rand
Sets type 5 end point rand to use correct values.
2024-05-29 11:48:02 -04:00
Goober5000 e991872c22 Merge pull request #6171 from Baezon/uniform-rand-vector-script
Use uniform random vector for createRandomVector
2024-05-29 11:47:39 -04:00
Kestrellius e9a91f9c1f Sets type 5 end point rand to use correct values. 2024-05-28 17:46:32 -07:00
Kestrellius e710b651de Inlines headon glow render; converts some casts. 2024-05-28 10:58:59 -07:00
Asteroth f0f7eb513f fix 2024-05-27 13:28:13 -04:00
Asteroth 3164261152 update to better random vector 2024-05-27 13:27:46 -04:00
The Force 120b76b21e GCC 2024-05-27 09:30:25 +01:00
Kestrellius c6efd0a0a3 Makes random life factor of children configurable. (#6166)
* Makes random life factor of children configurable.

* Renames parameter and associated variables.
2024-05-26 20:42:53 +02:00
John Fernandez 914f895cac Merge pull request #6162 from TheForce172/MoveShipFileQT
Move Ship Editor Files And Coverity Clean-up
2024-05-26 13:46:00 -04:00
John Fernandez b3a51d776f Merge pull request #6136 from Baezon/aim-cursor
Add 'Flight Cursor' flying style option
2024-05-26 13:23:43 -04:00
Asteroth dbac7d1259 make the options beginner instead of advanced 2024-05-26 13:05:52 -04:00
The Force 42355b2384 Add Paths Editor 2024-05-26 10:48:20 +01:00
The Force 16a0268bd7 Missed a bit 2024-05-26 06:10:05 +01:00
Asteroth 73bbc94e5e (int) -> fl2i 2024-05-24 23:19:44 -04:00
Goober5000 a0d1ad163d Merge pull request #6165 from Baezon/fix-decloaking
Fix for 'decloaking' effect
2024-05-22 21:53:28 -04:00
Asteroth 3b0d4558ca fix for decloaking 2024-05-22 19:35:01 -04:00
The Force ad8d9484c8 Hopfully Last ones 2024-05-22 20:07:20 +01:00
The Force e93a60c68a Missed a reference 2024-05-22 20:02:39 +01:00
The Force d2af199f14 Address GCC Issues 2024-05-22 19:59:22 +01:00
John Fernandez b122c7a10c Merge pull request #6160 from scp-fs2open/dependabot/pip/ci/post/requests-2.32.0
Bump requests from 2.31.0 to 2.32.0 in /ci/post
2024-05-22 14:11:20 -04:00
BMagnu 8b3e36b3c9 Allow replacement of skybox textures (#6161)
* Add skybox texture replace sexp

* Expose Skybox and Skybox instance to scripting

* first batch of comments

* change sexp name

* remove code repetition

* rebake skybox if required
2024-05-22 16:26:18 +09:00
BMagnu 87704fc817 Refactor replacement texture to a modelinstance parameter (#6154)
* Move replacement textures from ship to modelinstance

* Actually set pmi

* Fix texture replace in fred as well

* Fix bad indent

* incorporate feedback
2024-05-21 17:18:32 +02:00
dependabot[bot] 0f67b85ac0 ---
updated-dependencies:
- dependency-name: requests
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
2024-05-21 05:43:09 +00:00
The Force 8e082e7293 Change to size_ts and C++ style casts 2024-05-20 16:46:40 +01:00
The Force aa3192aa94 Remove Code that snuck in from another branch 2024-05-20 16:45:51 +01:00
The Force 6419adfbe4 Move Ship Files To there own folder for legibility 2024-05-20 16:45:40 +01:00
Goober5000 27caca5d2f handle modification of placeholder sounds 2024-05-18 17:34:09 -04:00
Goober5000 e3bdc106f3 fix ballistic primary banks exploding
When game sounds were changed to allow named entries, it became possible for named entries to unexpectedly replace numbered entries.  This was noticed most obviously in the ballistic rearm sound effect, which started using explosions rather than the standard rearm sound effects.  This occurred because MV_Tiny and MV_Small were added into indexes 200 and 201.

To restore the original behavior, the code now prevents sound effects added via TBM from being placed into reserved indexes.  The reserved indexes are instead assigned placeholders, which can subsequently be updated or left alone as the modder prefers.

This also makes the code a bit more robust including patching some sound validity checks in `gamesnd_game_sound_try_load` and `snd_load`.
2024-05-18 17:34:09 -04:00
Goober5000 c1af4317d4 Merge pull request #6156 from Baezon/rand-vec-adjustment
Better rand vec for createRandomorientation
2024-05-18 15:58:59 -04:00
Kestrellius 3f5a154e7a Updates beam-source particle velocity each frame. 2024-05-17 19:58:57 -07:00
Asteroth 8bd8e785b1 adjustments to rand vecs for random orientation 2024-05-17 21:09:36 -04:00
Goober5000 24e9a3a0c1 Merge pull request #6151 from Goober5000/cloaked_flag
add "cloaked" to list of flags
2024-05-17 12:34:53 -04:00
Goober5000 122e29fcaa Merge pull request #6152 from Goober5000/createRandomOrientation
add createRandomOrientation
2024-05-17 12:34:44 -04:00
BMagnu 03311c1527 Remove illegal assignment (#6153) 2024-05-17 10:11:16 -04:00
Goober5000 379077242a it's uniformly random, per Asteroth 2024-05-17 00:45:10 -04:00
Goober5000 cb4258e31f add createRandomOrientation
Considering that we have `ba.createRandomVector()`, we should have `ba.createRandomOrientation()` too.  This is based on an algorithm devised by @Baezon.
2024-05-17 00:16:54 -04:00
Goober5000 8ce463daf5 add "cloaked" to list of flags
This allows "cloaked" to be set and unset using `alter-ship-flag`.  Also clarify documentation on the primitive sensors flag.
2024-05-16 22:58:20 -04:00
Goober5000 fd32abad25 Merge pull request #6144 from Goober5000/emp_voice_fix
properly distinguish between adjusting voice and effects volume
2024-05-15 23:22:43 -04:00
Kestrellius f1c521413c Makes headon transition rate consistent. 2024-05-15 12:34:10 -07:00
Kestrellius 3b31034688 Removes const keyword from a couple things 2024-05-15 11:33:41 -07:00
Goober5000 30d1653cae Merge pull request #6148 from Goober5000/physics_whack_nocap
refine process for capping speed due to physics whack/shock/collide
2024-05-15 03:05:54 -04:00
Goober5000 724e2e7f68 properly distinguish between adjusting voice and effects volume
When messages are distorted due to EMP effects, the voice volume should be controlled by the voice setting, not the effects setting.  Fixes a bug noticed by @skdKitsune, a portion of which dates back to the original public source release.

Also, when volume is adjusted in `snd_set_volume`, make sure the correct voice volumes are used.  Fixes a copy-paste bug from #5694.
2024-05-14 16:42:23 -04:00
Goober5000 5ccc3d5a78 Merge pull request #6130 from Kestrellius/min-pixel-per-weapon
Created per-weapon field for laser min pixel size.
2024-05-14 16:30:25 -04:00
Goober5000 49777052ac Merge branch 'master' into min-pixel-per-weapon 2024-05-14 15:58:56 -04:00
Goober5000 b9466193f5 Merge pull request #6141 from Goober5000/emp_scramble_flag
add ship flag to disable message scrambling when EMP is active
2024-05-14 15:50:25 -04:00
Goober5000 6fdb9459b5 Merge pull request #6147 from Kestrellius/const-particle-functions
Changes particle effect functions to take consts.
2024-05-14 15:50:04 -04:00
Goober5000 0d1c86e0cd Merge pull request #6146 from Kestrellius/bolt-offset
Laser bolt offset
2024-05-14 15:49:52 -04:00
Kestrellius cb93748898 Removes const keyword from copied parameters. 2024-05-14 07:29:54 -07:00
Kestrellius 9192bb00b1 Alters other files to match previous changes. 2024-05-13 13:23:41 -07:00
Kestrellius ebd39bb5df Changes particle effect functions to take consts. 2024-05-13 13:03:42 -07:00
Goober5000 30b0026ca5 refine process for capping speed due to physics whack/shock/collide
The three functions `physics_apply_whack`, `physics_apply_shock`, and `physics_collide_whack` limited speed after the physics had been applied, but they limited absolute speed, not the speed due to the physics.  This modifies the process to limit the change in speed.  It also adds an AI profiles flag to disable the limit if desired.

This also tweaks the three functions (by editing comments and moving lines) to be more consistent, since all three are doing very similar calculations near the end.
2024-05-13 15:53:20 -04:00
Kestrellius c14a62e9d3 Adds comments clarifying positioning details. 2024-05-13 11:25:11 -07:00
Goober5000 046f302458 Merge pull request #6139 from Kestrellius/muzzle-effect
Adds muzzle effect functionality.
2024-05-13 14:02:56 -04:00
wookieejedi 4b6cbb9c01 Expose Collision Rotation Factor to Players (#6145)
* Expose Collision Rotation Factor to Players

Previously, there were hardcoded checks in place to make players have 0 rotational effects when colliding with another ship. This PR adds a new value, "+Player Multiplier for Rotation Factor:" that allows modders to have players experience rotational effects from collisions. Also performed some cleanup of the light and heavy collisional rotational calculations by removing older if-blocks following useful recommendation from Asteroth.

Tested and works as expected.

* make  rot_fac_multiplier_ply_collisions into global value

* update name to better match with ships table

* restore repeated comments to help with separation
2024-05-13 16:57:41 +00:00
Mike Nelson ed78fd84ea remove more ui stuff from API mode debrief (#6137) 2024-05-13 07:38:49 -04:00
Goober5000 393a9d4eba Merge pull request #6140 from Goober5000/small_fixes
several small fixes, mostly for FRED/qtFRED
2024-05-13 00:06:15 -04:00
Goober5000 9b94655250 Merge pull request #6125 from Goober5000/sync_initialization
make initialization consistent among FSO, FRED, and qtFRED
2024-05-13 00:06:08 -04:00
wookieejedi 5a501a8447 Update Align to target when guarding still (#6143)
Follow-up to #6047. This method better accounts for matching the guardee ship orientation when using the new AI flag.

Tested and works as expected. Thanks @BMagnu!
2024-05-12 23:09:58 -04:00
Kestrellius 3747a45dbe Adds three-dimensional bolt offset. 2024-05-12 16:07:24 -07:00
Kestrellius 5d30c07e31 Removes unnecessary commented-out code. 2024-05-12 11:06:21 -07:00
Kestrellius e2bf3bbd46 Adds one-dimensional bolt offset, with bugs. 2024-05-12 10:54:05 -07:00
Asteroth 5d6e68b8fd tweaks and fixes 2024-05-12 13:09:59 -04:00
Goober5000 d51f53fb30 add ship flag to disable message scrambling when EMP is active
What it says on the tin.  This supersedes PR #2917, as it puts the flag check in the proper function and uses a ship flag rather than a mission flag.
2024-05-11 23:38:18 -04:00
John Fernandez 23dda4ba43 Merge pull request #6135 from MjnMixael/fix_debrief_ui_murderer
Do not unload debrief bitmaps in API mode
2024-05-11 22:50:57 -04:00
Goober5000 499a5f4a02 several small fixes, mostly for FRED/qtFRED
1. Add the "Override #Command in event messages" checkbox to qtFRED
2. Add the "Preload Subspace Tunnel" checkbox to the proper button group in qtFRED
3. Reorder lines in fred.rc so the declarations match the order they appear in the dialog
4. Use the correct name when reporting fireball index errors for ship classes
2024-05-11 22:42:38 -04:00
Kestrellius 67e689106c Makes muzzle effects work properly on turrets. 2024-05-11 17:23:27 -07:00
Kestrellius 67999a3fe8 Clean version of shipfx move. 2024-05-11 15:29:24 -07:00
Asteroth 5cb0633314 fixes 2024-05-11 13:38:15 -04:00
Asteroth 2bbc052e7f Merge pull request #6128 from Goober5000/vanilla_time_compression
allow restriction to vanilla time compression range
2024-05-11 12:36:29 -04:00
mjn-mixael a222b29586 Do not unload debrief bitmaps in API mode 2024-05-11 11:32:50 -05:00
Asteroth 49a1e8458f add in game options and adjustments 2024-05-11 12:19:14 -04:00
Kestrellius b5efed380f Adds muzzle effect functionality. 2024-05-10 19:47:51 -07:00
Goober5000 9d9714f0bb Merge pull request #6126 from Goober5000/hud_support_find_closest_fix
patch hud_support_find_closest
2024-05-10 14:38:03 -04:00
Goober5000 edeabbbd58 Merge pull request #6129 from Goober5000/cmdbrief_modify_check
call set_modified() when cmd_brief data has changed
2024-05-10 14:37:48 -04:00
Kestrellius 62f25d7400 Changed variable names to specify laser. 2024-05-10 10:57:24 -07:00
Kestrellius d43818f7dc Merge branch 'min-pixel-per-weapon' 2024-05-10 10:41:25 -07:00
Kestrellius 6c9bf8def4 Implementation changes as requested by BMagnu. 2024-05-10 10:38:02 -07:00
Kestrellius c73c0ef889 Merge branch 'master' into min-pixel-per-weapon 2024-05-10 10:07:13 -07:00
Goober5000 a9141e9733 call set_modified() when cmd_brief data has changed
Fixes #6032.
2024-05-09 22:42:33 -04:00
Goober5000 fc4024ab66 allow restriction to vanilla time compression range
This provides a command-line argument to restrict the time compression range to the classic 1x - 4x.  Implements #6075.

I'm not entirely satisfied with `-orig_speedx_range` but it's the best I came up with that fit into the 19-character limit.  I'd be open to other suggestions.
2024-05-09 19:05:14 -04:00
Goober5000 c2335640ad Merge pull request #6113 from Goober5000/when-argument-fix
don't short-circuit eval_sexp on any nodes in a when-argument tree
2024-05-09 17:39:34 -04:00
Goober5000 8b984781fd Merge pull request #6121 from Goober5000/fix_dradis_blips
Fix DRADIS blips
2024-05-09 17:39:25 -04:00
Asteroth c3b01da2d1 reduce volume threshold (#6127) 2024-05-09 08:01:43 -04:00
Kestrellius 68a936504f Make laser glow scaling configurable. (#6123) 2024-05-08 17:41:50 +02:00
Goober5000 6edaea6056 Merge pull request #6122 from Dark-Visor/color_and_colour
Accept "color" and "colour" in game_settings.tbl
2024-05-07 01:12:43 -04:00
Goober5000 bf7c923020 patch hud_support_find_closest
Rework `hud_support_find_closest()` slightly to do a quick out if the player is no longer a valid object.  Fixes an assertion noticed by Darius that occurs if the player dies when a rearm is imminent.
2024-05-07 01:06:15 -04:00
Goober5000 bfe40e12c6 make initialization consistent among FSO, FRED, and qtFRED
Make the initialization sequence consistent so that FSO, FRED, and qtFRED call their initialization functions in the same order.  Most of the changes involve bringing FRED and qtFRED into sync with FSO.  This fixes fireball prerequisites for the ship types table, applies the script initialization fixes from #5946 to FRED, and generally removes the possibility of any surprises due to FRED differing from FSO.

Also remove the empty `brief_init_colors()` function.
2024-05-07 00:14:18 -04:00
Kestrellius 8d9736d3e3 Created per-weapon field for laser min pixel size. 2024-05-06 16:26:44 -07:00
Goober5000 322f807ac0 Merge pull request #6114 from Goober5000/dynamic_fireballs
make fireball types dynamic
2024-05-06 01:40:14 -04:00
Goober5000 209f5636b0 Merge pull request #6115 from Goober5000/setClip_enhancement
setClip enhancement
2024-05-06 01:39:59 -04:00
Asteroth dea9437c04 add waypoints no formation flag (#6119) 2024-05-05 22:10:19 -04:00
Goober5000 b624019f32 Merge pull request #6094 from Goober5000/hide_key_reset
hide key-reset
2024-05-03 11:02:22 -04:00
Goober5000 d1d173b99f Merge pull request #6116 from Dark-Visor/subtitles
Update Settings for movie subtitles #6064
2024-05-03 11:01:40 -04:00
Dark-Visor b7f4ad9780 Accept "color" and "colour" in game_settings.tbl
Allow optional strings in game_settings.tbl to recognise both
spellings - color/colour.
2024-05-02 13:57:16 +01:00
Goober5000 69c8957500 several improvements to DRADIS blips
1. fix a bug where blips expired immediately every frame; they now track their expiration by object
3. store object numbers rather than object pointers
3. clamp both the high bound and the low bound of alpha values
2024-05-02 01:33:31 -04:00
Goober5000 76359c649f remove some obsolete commented code 2024-05-02 01:32:17 -04:00
Goober5000 855331bcd6 change sweep_percent field to sweep_angle to be more accurate 2024-05-02 01:31:27 -04:00
Goober5000 fa6d64ae7e fix sweep_duration and disambiguate overall frametime
Convert `sweep_duration` from seconds to milliseconds to work correctly with the timestamp system.  Also clarify use of `game_get_overall_frametime()`, especially with `ba.getFrametimeOverall()`; and add `ba.getSecondsOverall()` to do what `ba.getFrametimeOverall()` allegedly did.
2024-05-02 00:01:47 -04:00
Goober5000 bc4cc598c9 qtfred too 2024-05-01 22:42:06 -04:00
Goober5000 3d92d469ac move backup info and make them consistent 2024-05-01 22:22:24 -04:00
Goober5000 9edcf5f450 add routine to recover autosaved mission 2024-05-01 21:42:39 -04:00
Goober5000 2f5e7a4de2 tweak MessageBox call 2024-05-01 21:42:39 -04:00
Goober5000 8d6a8721f9 taylor's patch for file modification time 2024-05-01 21:42:39 -04:00
Goober5000 7ebfa52bf5 standardize file modification time formatting between FRED and qtFRED 2024-05-01 21:42:32 -04:00
Dark-Visor 89e8961984 Add allowances for no alpha and spelling colour
User should be able to input 3 values (r,g,b) and let alpha default to
opaque. Also add "$Movie subtitle colour:" for English spelling of
color.
2024-05-01 15:23:06 +01:00
Dark-Visor 0f4dc47db9 Correction to subtitle_color check
Update check from checking the validity of state color to
Movie_Subtitle_rgba color values.
2024-04-29 18:10:04 +01:00
Dark-Visor eacba95b7b Update to #6064 fix to correct code
Update movie.cpp to correct subtitle declaration and checks.
2024-04-29 17:30:29 +01:00
Asteroth f40941304c Account for scripting when dealing with velocity (#6110)
* add scripted velocity

* fix

* rejigger to handle displacement as well, and add flag

* review tweaks

* one more fix
2024-04-29 01:40:26 -04:00
Dark-Visor eb9c58dc2d Update Settings for movie subtitles #6064
Update mod_table and movie files to include settings for the color and
transparency of the subtitles.
2024-04-28 22:36:07 +01:00
Goober5000 742fd321d5 setClip enhancement
Allow the resize mode to be specified to `gr_set_clip()` without changing the active graphics-wide resize mode.  Along with `drawStringResized`, this provides a shorthand to allow text to be drawn at different sizes, with the appropriate clipping regions, without requiring access to the `CurrentResizeMode` virtvar.
2024-04-27 02:48:08 -04:00
Goober5000 3851832db5 make fireball types dynamic
As requested by Event Horizon, this removes the limit on fireball types.  The fixed array has been replaced with a vector and the relevant code updated accordingly.  There is also a new version of `stuff_int_list()` to parse ints into a vector.

This also adds bounds checking for explosion animations that are parsed for ship classes, ship types, and asteroids, since previously there was no guarantee that the indexes would be in range.
2024-04-25 21:26:35 -04:00
Goober5000 539d89ca8c don't short-circuit eval_sexp on any nodes in a when-argument tree
This is a follow-up to #2942.  That PR solved most of the short-circuiting issues with nested conditionals under when-argument, but it was still possible for the code to incorrectly short-circuit on a nested conditional that had `<argument>` in an action operator but not a condition operator.  The cleanest way to fix this is to not short-circuit on *any* nodes that are part of a when-argument tree.
2024-04-25 00:10:27 -04:00
Goober5000 289d0b66d1 Merge pull request #6093 from Goober5000/sexp_error_check_fix
fix bad node identification for certain SEXP errors
2024-04-23 16:52:39 -04:00
Goober5000 f3c6b0f8f3 Merge pull request #6108 from Goober5000/no_escort_callsigns
add flag to not show callsigns in escort list
2024-04-21 23:29:35 -04:00
Asteroth 1bd65192ba Allow for more field of fire cooldown shenanigans (#6086)
* allow for more fof cd shenanigans

* review fix

* switch to per frame management

* unused variable

* review tweaks
2024-04-20 23:33:24 -04:00
Taylor Richards 2642fa22de add preliminary support for Windows ARM64 (#6079)
First step in the process of working Windows ARM64 support. This adds the most
basic support needed, but by itself will not succesfully build. However these
changes should not interfere with builds for other architectures or platforms,
and should still allow for x86/x64 builds on ARM64 Windows.
2024-04-19 04:30:20 -04:00
Goober5000 ac8d774bc7 Merge pull request #6095 from Baezon/debris-big-damage
Add flag for debris respecting big damage
2024-04-18 15:58:54 -04:00
Goober5000 a57ae15c72 Merge pull request #6109 from Goober5000/fighter_beam_fov_fix
fix fighter beam FOV calculation
2024-04-18 15:58:45 -04:00
Goober5000 26c4ea1057 fix fighter beam FOV calculation
Remarkable that we're still finding bugs in fighter beams after 20 years...

Since field-of-fire angles are specified in degrees, and `cosf` accepts radians, the angle needs to be converted (and then halved, per usage elsewhere).  Although this is a bugfix, this should technically not affect fighter beam behavior because fighter beams always fire down their normals.
2024-04-18 14:39:37 -04:00
Goober5000 148efb4713 add flag to not show callsigns in escort list
As a follow-up to #5523, some mods use callsigns for their ships but prefer not to display the callsigns in the escort list.  In lieu of a more flexible way to configure escort lists, a simple flag is sufficient to implement the desired behavior.
2024-04-18 13:46:58 -04:00
Goober5000 88bf67a64f Merge pull request #6104 from Goober5000/locations_to_enums
convert arrival/departure locations to enum classes
2024-04-18 03:53:30 -04:00
Goober5000 a18b122b19 Merge pull request #6106 from Goober5000/checkVisibility_fix
fix checkVisibility
2024-04-17 23:18:55 -04:00
Goober5000 0a59c533c2 fix checkVisibility
The checkVisibility function did not check its arguments' validity, leaving open the possibility of a null pointer access.
2024-04-17 22:32:54 -04:00
Goober5000 3ad0d3713d convert arrival/departure locations to enum classes
To enforce type safety for arrival and departure locations, this converts them to enum classes.  Various casts are added when appropriate to convert between the indexed and enum values.
2024-04-17 15:05:48 -04:00
Goober5000 7acf56f4f5 Merge pull request #6103 from Goober5000/in_back_of_ship
add 'In back of ship' arrival location
2024-04-17 15:05:24 -04:00
Goober5000 55c41c96a7 add above/below and left/right 2024-04-17 14:37:47 -04:00
Mike Nelson e63383d324 Ingame prejoin API (#6099)
* ingame prejoin api

* fix type mismatch

* return boolean here

* address feedback
2024-04-17 17:48:57 +00:00
Mike Nelson 7ae8c79dea Team Loadout API for SCPUI (#6096)
* team loadout methods

* documentation

* address feedback

* better assertions
2024-04-17 13:24:27 -04:00
Mike Nelson 002783ce7c miscellaneous methods needed (#6090) 2024-04-17 12:48:27 -04:00
Asteroth 72b6ded0ac fix circ default curves (#6102) 2024-04-17 12:48:02 -04:00
Goober5000 4c7f16fb1b add 'In back of ship' arrival location
Allows ships and wings to arrive behind a ship, to complement 'In front of ship'.  In fact, the arrival code is nearly identical, with just a small tweak to distinguish ahead from behind.

Since the new arrival location represents a change in mission format, this also adds code to detect for its usage and set the mission format to 24.1.  Most missions can continue to be saved as version 23.1.
2024-04-16 19:27:47 -04:00
Mike Nelson ecb9fae3c4 check if inputbox is valid (#6092) 2024-04-11 17:49:25 -04:00
wookieejedi 55c20636d9 Improve Mainhall Button Responsiveness (#6098)
* Improve Mainhall Button Responsiveness

Previously, there was a 175 millisecond delay when hovering over a mainhall animation before it triggered. This PR makes that value settable via the mainhall table.

Tested and works as expected. Now custom mainhalls have much more of a spring int their step.

* cleanup num res location
2024-04-11 17:48:28 -04:00
Goober5000 e8d164c926 Merge pull request #6097 from Goober5000/model_range_fix
model range fix
2024-04-11 17:01:43 -04:00
Goober5000 89f4fe54c3 convert model_h and submodel_h to use indexes
Indexes are a more robust way than pointers to manage model and submodel handles, and in the event that models are made dynamic in the future, indexes will be necessary anyway.
2024-04-11 15:15:44 -04:00
Goober5000 7fba753f9d model range fix
Use the correct upper bounds check for `model_get()`.
2024-04-11 14:53:24 -04:00
Asteroth bd05f13f07 add flag for debris respecting big damage 2024-04-11 14:21:44 -04:00
Goober5000 d5a3813e8b hide key-reset
Hides the `key-reset` operator in FRED and elaborates on the help descriptions for both it and `key-reset-multiple`.  Implements #6076.
2024-04-10 21:14:59 -04:00
Goober5000 735d4ab678 fix bad node identification for certain SEXP errors
Set the bad node to the ship node, so that the FREDder can see which ship is receiving the invalid order.  Without this change, the bad node would point to the last value parsed, which is typically the goal priority.

Fixes a misleading error dialog reported in Discord.
2024-04-10 17:54:57 -04:00
Goober5000 71543c9c10 Merge pull request #6058 from Goober5000/skybox_orientation_and_alpha
add skybox alpha, and add scripted functions for alpha and orientation
2024-04-10 17:06:24 -04:00
Goober5000 b2e1ae43a9 Merge pull request #6039 from Goober5000/percent_ships_scanned
add percent-ships-scanned
2024-04-10 17:04:46 -04:00
Goober5000 c7cffcb311 Merge pull request #6091 from notimaginative/fix_chatbox_crash
fix crash when chatbox message is all whitespace
2024-04-10 17:04:37 -04:00
Goober5000 c96f1af375 Merge pull request #1 from BMagnu/skybox_alpha
Fix Skybox Alpha Setting
2024-04-10 12:53:41 -04:00
BMagnu c2d1b69ea2 Set alpha as alpha mult and only if actually required 2024-04-10 12:49:58 +02:00
Taylor Richards 861e5f9813 fix crash when chatbox message is all whitespace
When attempting to add a chat message which is all whitespace the split_str()
function will produce no lines. The strcpy() that follows will then crash
due to an attempt to copy a nullptr.
2024-04-10 05:03:16 -04:00
Taylor Richards f288ef7101 fix issues with get_text() and set_text() for INPUTBOX (#6089) 2024-04-08 19:19:03 -04:00
Taylor Richards 067f862c4d add support for decompression of DDS textures (#6025)
Adds bcdec lib to convert compressed DDS textures to RGBA based on what the
system supports. BC7 if BPTC extension not supported, DXT? if S3TC extension
not supported.

Should support cubemaps and volume textures but those were not tested.

Addtional changes:
 - remove indexed DDS support since it had bugs but didn't work anyway
   (R8 should be used instead)
 - fix issues with volume textures (nothing to test with)
 - remove old compression support flags as they are now obsolete

Fixes #4920
2024-04-08 16:56:33 -04:00
Taylor Richards 3478640b4d fix deprecated/removed code in cutscene ffmpeg (#6088) 2024-04-07 18:43:15 -04:00
Mike Nelson 66204287e6 properly validate mission custom data keys (#6082) 2024-04-07 16:46:05 -04:00
Mike Nelson 6b1d9304ed Multi general api (#6078) 2024-04-07 16:45:51 -04:00
Mike Nelson 66ec2c8154 multi dogfight debrief api (#6084) 2024-04-07 16:48:23 +00:00
Mike Nelson e3918a14f2 API for the Multi Pause UI (#6083) 2024-04-07 12:28:24 -04:00
Mike Nelson 4b1476c101 on loading complete hook (#6085) 2024-04-07 08:09:51 -04:00
Goober5000 86db536bf5 Merge pull request #6071 from Goober5000/support_ship_specific_checks
adjust ship registry checks to accommodate support ships
2024-04-06 20:51:58 -04:00
Goober5000 b3b811841b Merge pull request #6080 from Goober5000/electrical_arc_stuff
more electrical arc API features
2024-04-06 20:51:50 -04:00
Goober5000 cc62643001 Merge pull request #6081 from Goober5000/goal_cheat_fix
mission goal cheat fix
2024-04-06 20:51:41 -04:00
Goober5000 3b7157e2de mission goal cheat fix
If the goals are marked complete, a mission log entry should be added as well.  Fixes some goal weirdness first noticed by DAK on Discord.
2024-04-03 20:32:12 -04:00
Goober5000 a5630d63a5 more electrical arc API features
Follow-up to #6034.  This slightly changes the function signature of `AddElectricArc` but it should be fine since it hasn't appeared in a stable release yet.
2024-04-03 20:27:14 -04:00
Mike Nelson 052b4b29e9 Multi sync API (#6077)
* multi host settings ui initial setup

(cherry picked from commit bcb31c327653329e62e4430815fe1e981751f9dc)

* Finish the rest of the API

* include enums

* set these

* Close game needed

* Handle accepting the host setup

* Don't need to be master to set these and add ways to check master and self

* add client ui to this PR because

* Allow getting the player state string

* Multi sync api methods

* unused variables

* Fix state checking

(cherry picked from commit fcde973cdf)

* typo

* address feedback

(cherry picked from commit ecb33e7cc6)
2024-04-02 17:34:06 +00:00
Mike Nelson ea8e356b63 Multi Start Game UI API (#6068)
* methods for the Multi Start Game UI API

* missed a comma

* properly close the session

* name instead of password
2024-04-02 16:56:56 +00:00
Mike Nelson 9bba53c3e8 Multi Join API (#6059)
* methods required for the multi join ui api

* Move color setting because the API doesn't need it either
2024-04-02 12:19:20 -04:00
Asteroth 3df616e69d Merge remote-tracking branch 'upstream/master' into aim-cursor 2024-04-01 23:09:31 -04:00
Goober5000 0fb18a15c4 Merge pull request #6069 from Baezon/bad-rearm-time
Add bad-rearm-time sexp
2024-03-31 15:01:50 -04:00
Goober5000 e1503a8ac8 Merge pull request #6002 from Goober5000/game_settings_order
allow game_settings options to be read in any order
2024-03-31 15:01:41 -04:00
Goober5000 b11cf2c2db Merge pull request #5887 from Goober5000/wing_destruction_sanity_check
check for potential issues in FRED missions
2024-03-31 15:01:32 -04:00
Asteroth 9c8d02b69b Add 'alignment' for poofs (#6072)
* add poof alignment

* put this back

* review fixes
2024-03-31 10:49:34 -04:00
John Fernandez 055cc6e4c8 Merge pull request #4210 from JohnAFernandez/Team-Loadout-Editor-Possible-Rebase
QTFred Loadout Editor
2024-03-31 00:25:16 -04:00
Goober5000 e3447223eb allow game_settings options to be read in any order
The ai_profiles.tbl options can already be read in any order, so it is modder-friendly to extend this capability to game_settings.tbl as well.  This also updates the "unrecognized parameter" log statement to indicate the filename.

Note that this commit should be viewed while ignoring whitespace changes.
2024-03-30 19:37:29 -04:00
Goober5000 8b575e7a72 add checkbox to control behavior 2024-03-30 19:27:10 -04:00
Goober5000 30547ff026 check for potential issues in FRED missions
Add a routine to the sexp syntax checker that also checks for potential issues.  These are not definitive errors, but situations that might trip up mission designers.  Currently there is one issue checked: the destruction of a wing that has multiple waves and arrives from a docking bay.
2024-03-30 19:27:05 -04:00
JohnAFernandez d564329ffb Remove old TODOs and add confirmation
Copying to other team can erase a lot of progress, therefore make sure we ask for confirmation.
2024-03-30 18:16:42 -04:00
Goober5000 18c5662584 adjust ship registry checks to accommodate support ships
This does two things:

1. Fix a bug in `mission_bring_in_support_ship` that assigns an incorrect parse object index to the support ship's ship registry entry.  Since `Arriving_support_ship` is not an item of `Parse_objects`, it should not have an index.
2. Adjust the in-game join checks at the bottom of `parse_create_object_sub` to more scrupulously account for index mismatches and bounds errors, with a specific exception for the arriving support ship.
2024-03-30 16:00:04 -04:00
JohnAFernandez 534c69ee60 More dialog adjustments 2024-03-30 15:56:48 -04:00
JohnAFernandez b3bafb83b4 Remove Unused Code and Add Skip Validation 2024-03-30 14:23:52 -04:00
JohnAFernandez 9783e96207 No Shadowing and more Column Adjustments 2024-03-30 13:13:34 -04:00
JohnAFernandez 103275e488 Don't for get to save required status 2024-03-30 13:07:53 -04:00
JohnAFernandez 16ff22cce1 Add Functionality for Required Weapons 2024-03-30 12:49:48 -04:00
JohnAFernandez ef31905f3e Appease Clang by not having prefix by accident 2024-03-30 00:41:26 -04:00
JohnAFernandez 18f76652cf It's no longer crashing
And it is now updating correctly.

I don't like it but I don't want to touch it.
2024-03-30 00:38:56 -04:00
Goober5000 d3c43732fa Merge pull request #6074 from Goober5000/fast_fred_reload
speed up FRED reloading with this one weird trick
2024-03-30 00:03:41 -04:00
Goober5000 e6b2cbf900 Merge pull request #5870 from Goober5000/any_wingman_check
add a new check to the Voice Acting Manager
2024-03-30 00:03:35 -04:00
Goober5000 0267fb539c speed up FRED reloading with this one weird trick
Thanks to @notimaginative's detective work, nearly all of the FRED stalling when saving a mission can be avoided by simply not calling `model_free_all()`.  By checking a flag in `clear_mission()`, multiple situations can avoid this slowdown, including reload-after-save and import-FSM.
2024-03-29 23:34:54 -04:00
wookieejedi 218a98dde3 Merge pull request #5978 from BMagnu/shader_backwards_compat
Add runtime flag to split up the main render shader
2024-03-29 23:14:36 -04:00
JohnAFernandez f52ebc8ccb Save my progress ....
Even though it crashes and I have no idea why.
2024-03-29 20:25:59 -04:00
JohnAFernandez 88897b907c Fix Setting 2024-03-29 20:25:59 -04:00
JohnAFernandez 9ab82ae607 Adding Functionality to CombobBox 2024-03-29 20:25:59 -04:00
JohnAFernandez c01c7da121 Version 2, Adding Buttons
And fixing existing issues
2024-03-29 20:25:59 -04:00
JohnAFernandez 817fa2cd98 Save progress because this is a huge headache 2024-03-29 20:25:59 -04:00
JohnAFernandez 41be934485 Finish Polishing Regular List behavior
Also start adding many variable enabler functions
2024-03-29 20:25:59 -04:00
JohnAFernandez b870675cc9 Properly Clear list when switching modes 2024-03-29 20:25:59 -04:00
JohnAFernandez 5b3dddff4a New way of "Clearing" rows
Empty and move text instead of deleting items to avoid apparently inevitable memory bugs.
2024-03-29 20:25:59 -04:00
JohnAFernandez 8c904c36f9 Add extra allocated to newly enabled
So that items do not keep switching places.
2024-03-29 20:25:59 -04:00
JohnAFernandez c7f80725fe Fix copy paste mistake 2024-03-29 20:25:59 -04:00
JohnAFernandez 5af559d1cf Update Window size and Label names 2024-03-29 20:25:59 -04:00
JohnAFernandez d4246432d7 Make List selection update on multiselect 2024-03-29 20:25:59 -04:00
JohnAFernandez 95bc875ac2 Fix Updating the UI
The model was not updating its sending to front end list when getting new info from user input.  It would save it in the model, but not where it was sending information back to the dialog (UI).
2024-03-29 20:25:59 -04:00
JohnAFernandez 6b72772ac9 More Polishing 2024-03-29 20:25:59 -04:00
JohnAFernandez 6de2897347 Ok, making progress on fixing spinbox 2024-03-29 20:25:59 -04:00
JohnAFernandez 7a83c71b87 Starting to fix Functionality
And polish things that already work
2024-03-29 20:25:59 -04:00
JohnAFernandez 74805c83ba Make sure Usable ships make more sense 2024-03-29 20:25:59 -04:00
JohnAFernandez c9f3244268 Ok, prevent some crashes due to missing items 2024-03-29 20:25:59 -04:00
JohnAFernandez 308e2edb3e Ok, it is at least updating correctly. 2024-03-29 20:25:59 -04:00
JohnAFernandez 2baec05a55 More Linter fixes 2024-03-29 20:25:59 -04:00
JohnAFernandez bf2dbb4a02 Trying hard to fix things 2024-03-29 20:25:59 -04:00
JohnAFernandez 228a8994ee Appease linters
Remove unused variables
2024-03-29 20:25:58 -04:00
JohnAFernandez fe2561c893 Fixn 2024-03-29 20:25:58 -04:00
JohnAFernandez ee73fadad1 Get the code to compile at least 2024-03-29 20:25:58 -04:00
JohnAFernandez d75e4e46ab A good chunk of further fixes 2024-03-29 20:25:58 -04:00
JohnAFernandez 2d90756fed Gotta keep chipping away at the boulder 2024-03-29 20:25:58 -04:00
JohnAFernandez 807e416ebb Why yes, there's tons more errors 2024-03-29 20:25:58 -04:00
JohnAFernandez b8bb4d445b Fix some compilation errors 2024-03-29 20:25:58 -04:00
JohnAFernandez f0f57bf576 Remove duplicate function definitions 2024-03-29 20:25:58 -04:00
JohnAFernandez 8b081bf2ed Fix no class declaration 2024-03-29 20:25:58 -04:00
JohnAFernandez 1f034209d0 Fix incomplete line 2024-03-29 20:25:58 -04:00
JohnAFernandez cef7abb1db Disable Reset Lists 2024-03-29 20:25:58 -04:00
JohnAFernandez d9909e2a21 Cleaning out further functions to fit new paradigm. 2024-03-29 20:25:58 -04:00
JohnAFernandez 90097293cb Refactor UpdateUI() to reflect new UI structure 2024-03-29 20:25:58 -04:00
JohnAFernandez c2aa94bdde Properly update list widgets 2024-03-29 20:25:58 -04:00
JohnAFernandez 404a8c9bb7 Cleaning things up a little 2024-03-29 20:25:58 -04:00
JohnAFernandez 209583b449 Save changes.
Still plenty to do to finish converting.
2024-03-29 20:25:58 -04:00
JohnAFernandez 5c746f13a6 Pretty Much Completely Redone 2024-03-29 20:25:58 -04:00
JohnAFernandez dae99e5b80 Also, add add/remove to ui file 2024-03-29 20:25:58 -04:00
JohnAFernandez e5f0b674b5 Rearrange Editor to use add/remove
More edits to follow ...
2024-03-29 20:25:58 -04:00
JohnAFernandez eebc2bfd59 Fix 2024-03-29 20:25:58 -04:00
JohnAFernandez 7eb64e59bb Fixes 2024-03-29 20:25:58 -04:00
JohnAFernandez 7db278410c A little more cleanup 2024-03-29 20:25:58 -04:00
JohnAFernandez ed4d187365 Getting Close hopefully to properly functioning 2024-03-29 20:25:58 -04:00
JohnAFernandez 1bbcdc3dc5 Finish the Loadout Dialog
Finished the Model And Dialog files for the Loadout Editor
2024-03-29 20:25:57 -04:00
JohnAFernandez c36551fbd6 Edits to the Dialog for Clarity. Conciseness
In preparation for writing the model and dialog cpp and h files

And a quick rename

Don't need these

done
2024-03-29 20:25:57 -04:00
Goober5000 6f94d67cfa Merge pull request #6063 from Goober5000/sexp_boolean
allow boolean and numeric scripted SEXPs to return special values
2024-03-26 15:18:07 -04:00
Goober5000 0ffd9bc421 Merge pull request #6067 from Goober5000/fix_fix_missile_detonation
fix fixed-missile-detonation
2024-03-26 15:15:11 -04:00
Goober5000 4899e6454e Merge pull request #6066 from Goober5000/override_submodel_impact
add "override submodel impact" subsystem flag
2024-03-26 15:15:03 -04:00
John Fernandez 8f6f6ab970 Merge pull request #6070 from Baezon/fix-anim-directions
Fix an issue with animation directions
2024-03-25 22:48:58 -04:00
Asteroth 3388341343 fix an issue with animation directions 2024-03-25 20:58:22 -04:00
Asteroth e65803b747 add bad-rearm-time sexp 2024-03-25 20:13:16 -04:00
Goober5000 197356077d fix fixed-missile-detonation
The logic to handle the `$Fixed Missile Detonation:` flag missed an important case: subsystems with concave hull geometry but without destroyable submodels.  The original flag was tested on a bowl-shaped turret, which could be destroyed.  However the bowl-shaped engine on the SSG Rahu was susceptible to the same detonation problem.  By changing the check to always use the radius, whether obtained from a submodel or from the subsystem, the flag fixes the detonation in both cases.
2024-03-25 16:02:30 -04:00
Goober5000 168d3c9ddf add "override submodel impact" subsystem flag
With the `$Damage Impacted Subsystem First:` game_settings flag, weapons will damage submodels over subsystems, even if the subsystem is closer.  Yet occasionally this is not the correct behavior (e.g. for the Rahu's engines).  The new subsystem flag allows this behavior to be selectively overridden.
2024-03-25 15:49:52 -04:00
Goober5000 55ead5c2c6 Merge pull request #6065 from Goober5000/6014_followup
additional lighting fixes
2024-03-25 14:05:09 -04:00
Goober5000 db8a3651cd additional lighting fixes
Fix a minor oversight from #6014; in the ship lab, there are sometimes no suns at all, so remove the assertion.  The lighting check is only needed for supernovas anyway, so make that clear.

Additionally, add further clarification for the distinction between suns, lights, and variables used only for the supernova.  Finally fix one more sun/light discrepancy that escaped notice from #6014.

Fixes an assertion in the ship lab.  Follow-up to #6014.
2024-03-25 13:33:21 -04:00
Goober5000 897e388d1c allow boolean and numeric scripted SEXPs to return special values
This adds the special SEXP return values (SEXP_KNOWN_TRUE, SEXP_NAN, and so forth) as enums, and adds code to intercept these enums if they are returned where the code would normally expect a boolean or number.  If an enum is found, it is converted to its special return value equivalent.

With this change, a script can end a function with `return SEXP_KNOWN_TRUE` or similar.  No other API changes are needed; in particular, no special `$Return Type:`s are needed.

Implements #5959.
2024-03-23 23:35:36 -04:00
Goober5000 aa12ec7790 add skybox alpha, and add scripted functions for alpha and orientation
This allows the skybox orientation and alpha to be accessed and changed through Lua virtvars, and also adds a sexp to change the alpha.

Unfortunately, changing the alpha has no perceptible effect on the skybox.  This will need the attention of a graphics coder to figure out what might need updating.
2024-03-22 13:23:05 -04:00
Goober5000 8ac68c5b8b make the percent operators correctly return KNOWN_FALSE when they are known false 2024-03-13 14:03:32 -04:00
Goober5000 b92f50e94f add percent-ships-scanned
Kind of surprised this SEXP operator hasn't been added before now.  It complements the existing percent-X operators in the Objectives category.

Also, this fixes and clarifies the help documentation for the various percent-X operators.
2024-03-13 12:05:35 -04:00
Birk Magnussen 6ca68151a1 Remove Compiler Warning 2024-02-05 19:23:55 +01:00
Birk Magnussen f61407d899 Introduce shadow map amd optimization 2024-02-05 19:22:33 +01:00
Birk Magnussen 86ef5c356e Optimize uniforms 2024-02-05 19:22:33 +01:00
Birk Magnussen a127a35eee Optimize inter-stage data 2024-02-05 19:22:33 +01:00
Birk Magnussen 2a6c14d3b5 Make it properly configurable 2024-02-05 19:22:33 +01:00
Birk Magnussen 4f28615c6c Set flags correctly 2024-02-05 19:22:33 +01:00
Birk Magnussen 46408cce3a Conditionally set shader flags at run or compiletime 2024-02-05 19:22:33 +01:00
Birk Magnussen 3f1e67330c Large shader capability 2024-02-05 19:22:32 +01:00
Birk Magnussen e16ae385fa Predefine system 2024-02-05 19:22:32 +01:00
Birk Magnussen 2e90c8eed6 Conditional shader includes 2024-02-05 19:22:32 +01:00
Birk Magnussen da352c3eea Refactor gr_capability 2024-02-05 19:22:32 +01:00
Goober5000 da1e2c1049 add a new check to the Voice Acting Manager
This adds a new button to check if messages sent by `"<any wingman>"` have at least one ship with that persona.
2024-01-29 22:08:09 -05:00
Asteroth 46226a6cbe tweaks 2024-01-29 19:34:36 -05:00
Asteroth 84f97936aa Merge remote-tracking branch 'upstream/master' into aim-cursor 2024-01-13 00:53:37 -05:00
Asteroth 8460218707 first draft 2023-09-20 12:20:38 -04:00
Goober5000 676fb4b17d better stats handling when switching or resetting campaigns 2017-08-26 16:40:16 -04:00
549 changed files with 22478 additions and 47946 deletions

No files matched your search

+11 -1
View File
@@ -4,20 +4,27 @@ modernize-*,\
-modernize-avoid-c-arrays,\
-modernize-make-unique,\
-modernize-raw-string-literal,\
-modernize-use-default-member-init,\
-modernize-use-trailing-return-type,\
-modernize-use-using,\
performance-*,\
-performance-no-int-to-ptr,\
-performance-type-promotion-in-math-fn,\
misc-*,\
-misc-include-cleaner,\
-misc-macro-parentheses,\
-misc-misplaced-widening-cast,\
-misc-no-recursion,\
-misc-non-private-member-variables-in-classes,\
-misc-static-assert,\
-misc-unused-parameters,\
-misc-use-anonymous-namespace,\
readability-*,\
-readability-avoid-const-params-in-decls,\
-readability-else-after-return,\
-readability-function-cognitive-complexity,\
-readability-function-size,\
-readability-identifier-length,\
-readability-identifier-naming,\
-readability-implicit-bool-conversion,\
-readability-inconsistent-declaration-parameter-name,\
@@ -29,10 +36,13 @@ readability-*,\
"
WarningsAsErrors: ''
HeaderFilterRegex: 'code/.*$|freespace2/.*$|qtfred/.*$|test/src/.*$|build/.*$'
AnalyzeTemporaryDtors: false
CheckOptions:
- key: 'misc-assert-side-effect.AssertMacros'
value: 'assert,Assert,Assertion'
- key: 'misc-const-correctness.AnalyzeValues'
value: 'false'
- key: 'misc-const-correctness.TransformValues'
value: 'false'
- key: 'modernize-use-emplace.ContainersWithPushBack'
value: 'std::vector;std::deque;std::list;SCP_vector;SCP_deque;SCP_list'
- key: 'readability-braces-around-statements.ShortStatementLines'
+9 -9
View File
@@ -2,17 +2,14 @@ name: Weekly Coverity Scan for Freespace Open
# adapted from code by "albert-github" on the doxygen repository
# many thanks for figuring this out first so it could be less painful for us!
# keep this from running on everyone's fork
# if: github.ref == 'refs/heads/master'
#This mode is for testing
#on: [push, pull_request]
# In production, push on a specific schedule
on:
schedule:
- cron: "57 18 * * *" # Run once per a week on Friday morning (4 AM EST), to avoid Coverity's submission limits
- cron: "5 0 * * 5" # Run once per a week on Friday morning (midnight UTC, 4 AM EST), to avoid Coverity's submission limits
env:
QT_VERSION: 5.12.12
coverity_email: [email protected]
@@ -21,17 +18,20 @@ env:
jobs:
build:
name: Build FSO With Coverity Wrapper
runs-on: ubuntu-latest
if: github.repository == 'scp-fs2open/fs2open.github.com'
runs-on: ${{ matrix.config.os }}
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
strategy:
fail-fast: false
matrix:
config:
- { name: "GCC on ubuntu", os: ubuntu-latest, build_type: "Release" }
steps:
- name: Checkout
uses: actions/checkout@v1
with:
submodules: true # `true` to checkout submodules, `recursive` to recursively checkout submodules
submodules: recursive # `true` to checkout submodules, `recursive` to recursively checkout submodules
# pipe results of wget to a log file because it's very verbose and rarely fails
- name: Install Coverity
@@ -47,7 +47,7 @@ jobs:
- name: Configure CMake for FSO
env:
CONFIGURATION: FastDebug
CONFIGURATION: Release
COMPILER: gcc-9
ENABLE_QTFRED: OFF
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
+3 -1
View File
@@ -5,6 +5,8 @@ set -e
SCRIPT=$(readlink -f "$0")
HERE=$(dirname "$SCRIPT")
git config --global --add safe.directory "$GITHUB_WORKSPACE"
COMMIT_RANGE=$1..$2
if ! git rev-list $COMMIT_RANGE 2>&1 >/dev/null; then
@@ -20,4 +22,4 @@ echo "Running clang-tidy on changed files"
git diff -U0 --no-color "$BASE_COMMIT..$2" | \
$HERE/clang-tidy-diff.py -path "$(pwd)/build" -p1 \
-regex '(code(?!((\/graphics\/shaders\/compiled)|(\/globalincs\/windebug)))|freespace2|qtfred|test|build|tools)\/.*\.(cpp|h)' \
-clang-tidy-binary /usr/bin/clang-tidy-9 -j$(nproc) -export-fixes "$(pwd)/clang-fixes.yaml"
-clang-tidy-binary /usr/bin/clang-tidy-16 -j$(nproc) -export-fixes "$(pwd)/clang-fixes.yaml"
+1 -1
View File
@@ -1,3 +1,3 @@
Mako==1.2.2
requests==2.31.0
requests==2.32.0
semantic-version==2.8.5
+10 -4
View File
@@ -8,8 +8,14 @@ else()
set(IS_64BIT FALSE)
endif()
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|ARM64)")
set(IS_ARM64 TRUE)
set(IS_ARM64 FALSE)
if (NOT "${CMAKE_GENERATOR_PLATFORM}" STREQUAL "") # needed to cover Visual Studio generator
if(CMAKE_GENERATOR_PLATFORM MATCHES "^(aarch64|arm64|ARM64)")
set(IS_ARM64 TRUE)
endif()
else()
set(IS_ARM64 FALSE)
endif()
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|ARM64)")
set(IS_ARM64 TRUE)
endif()
endif()
+5 -1
View File
@@ -46,9 +46,13 @@ target_compile_options(compiler INTERFACE ${WARNING_FLAGS})
set(CMAKE_C_FLAGS "/MP /GS- /analyze- /Zc:wchar_t /errorReport:prompt /Zc:forScope /Gd /EHsc /nologo /Zm200")
set(CMAKE_CXX_FLAGS "/MP /GS- /analyze- /Zc:wchar_t /errorReport:prompt /Zc:forScope /Gd /EHsc /nologo /Zm200")
set(CMAKE_EXE_LINKER_FLAGS "/MANIFEST /DYNAMICBASE:NO /SAFESEH:NO /ERRORREPORT:PROMPT /NOLOGO")
set(CMAKE_EXE_LINKER_FLAGS "/MANIFEST /SAFESEH:NO /ERRORREPORT:PROMPT /NOLOGO")
set(CMAKE_STATIC_LINKER_FLAGS "")
if(NOT IS_ARM64)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DYNAMICBASE:NO")
endif()
# Release
set(CMAKE_C_FLAGS_RELEASE "/GL /Gy- /Ox /Ot /Ob2 /fp:precise /GF /Oy /Oi /Zi /W3")
set(CMAKE_CXX_FLAGS_RELEASE "/GL /Gy- /Ox /Ot /Ob2 /fp:precise /GF /Oy /Oi /Zi /W3")
+1 -1
View File
@@ -26,7 +26,7 @@ ActionResult MoveToSubmodel::execute(ProgramLocals& locals) const
// The calling code should ensure that this never happens
Assertion(locals.hostSubobject >= 0, "Did not have a valid host subobject.");
auto instance = object_get_model_instance(locals.host.objp);
auto instance = object_get_model_instance(locals.host.objp());
Assertion(instance != -1, "Model instances are required if a host subobject is specified.");
auto pmi = model_get_instance(instance);
+2 -2
View File
@@ -37,7 +37,7 @@ ActionResult ParticleEffectAction::execute(ProgramLocals& locals) const
vec3d local_pos;
matrix local_orient;
if (locals.hostSubobject != -1) {
auto instance = object_get_model_instance(locals.host.objp);
auto instance = object_get_model_instance(locals.host.objp());
Assertion(instance != -1, "Model instances are required if a host subobject is specified.");
auto pmi = model_get_instance(instance);
@@ -59,7 +59,7 @@ ActionResult ParticleEffectAction::execute(ProgramLocals& locals) const
auto direction = locals.variables.getValue({"locals", "direction"}).getVector();
source.moveToObject(locals.host.objp, &local_pos);
source.moveToObject(locals.host.objp(), &local_pos);
source.setOrientationFromNormalizedVec(&direction, true);
source.finish();
+3 -3
View File
@@ -26,7 +26,7 @@ ActionResult PlaySoundAction::execute(ProgramLocals& locals) const
vec3d local_pos;
matrix local_orient;
if (locals.hostSubobject != -1) {
auto instance = object_get_model_instance(locals.host.objp);
auto instance = object_get_model_instance(locals.host.objp());
Assertion(instance != -1, "Model instances are required if a host subobject is specified.");
auto pmi = model_get_instance(instance);
@@ -47,8 +47,8 @@ ActionResult PlaySoundAction::execute(ProgramLocals& locals) const
local_pos += locals.variables.getValue({"locals", "position"}).getVector();
vec3d global_pos;
vm_vec_unrotate(&global_pos, &local_pos, &locals.host.objp->orient);
global_pos += locals.host.objp->pos;
vm_vec_unrotate(&global_pos, &local_pos, &locals.host.objp()->orient);
global_pos += locals.host.objp()->pos;
const auto soundId = gamesnd_get_by_name(m_soundIdExpression.execute(locals.variables).c_str());
+3 -2
View File
@@ -601,7 +601,8 @@ float ai_get_weapon_speed(const ship_weapon *swp);
void set_predicted_enemy_pos_turret(vec3d *predicted_enemy_pos, const vec3d *gun_pos, const object *pobjp, const vec3d *enemy_pos, const vec3d *enemy_vel, float weapon_speed, float time_enemy_in_range);
// function to change rearm status for ai ships (called from sexpression code)
extern void ai_set_rearm_status( int team, int new_status );
extern void ai_set_good_rearm_time( int team, int time );
extern void ai_set_bad_rearm_time(int team, int time);
extern void ai_good_secondary_time( int team, int weapon_index, int num_weapons, const char *shipname );
extern void ai_do_objects_docked_stuff(object *docker, int docker_point, object *dockee, int dockee_point, bool update_clients = true);
@@ -634,6 +635,6 @@ void do_random_sidethrust(ai_info *aip, ship_info *sip);
void ai_formation_object_recalculate_slotnums(int form_objnum, int exiting_objnum = -1);
bool test_line_of_sight(vec3d* from, vec3d* to, std::unordered_set<const object*>&& excluded_objects = {}, float threshold = 10.0f, bool test_for_shields = false, bool test_for_hull = true, float* first_intersect_dist = nullptr, object** first_intersect_obj = nullptr);
bool test_line_of_sight(vec3d* from, vec3d* to, std::unordered_set<int>&& excluded_object_ids = {}, float threshold = 10.0f, bool test_for_shields = false, bool test_for_hull = true, float* first_intersect_dist = nullptr, object** first_intersect_obj = nullptr);
#endif
+5
View File
@@ -32,6 +32,8 @@ namespace AI {
Unload_primaries, // Fire primaries as fast as possible!
Trying_unsuccessfully_to_warp, // Trying to warp, but can't warp at the moment
Free_afterburner_use, // Use afterburners while following waypoints or flying towards objects
Waypoints_no_formation, // wont get into formation when running waypoints as part of a wing
NUM_VALUES
};
@@ -160,6 +162,9 @@ namespace AI {
Player_orders_afterburn_hard,
Hudsquadmsg_tactical_disarm_disable,
Align_to_target_when_guarding_still,
Debris_respects_big_damage,
Dont_limit_change_in_speed_due_to_physics_whack,
Guards_ignore_protected_attackers,
NUM_VALUES
};
+36 -3
View File
@@ -184,6 +184,14 @@ void parse_ai_profiles_tbl(const char *filename)
if (optional_string("$Max Beam Friendly Fire Damage:"))
parse_float_list(profile->beam_friendly_damage_cap, NUM_SKILL_LEVELS);
if (optional_string("$Max Weapon Friendly Fire Damage:")) {
parse_float_list(profile->weapon_friendly_damage_cap, NUM_SKILL_LEVELS);
}
if (optional_string("$Max Weapon Self Damage:")) {
parse_float_list(profile->weapon_self_damage_cap, NUM_SKILL_LEVELS);
}
if (optional_string("$Player Countermeasure Life Scale:"))
parse_float_list(profile->cmeasure_life_scale, NUM_SKILL_LEVELS);
@@ -471,10 +479,20 @@ void parse_ai_profiles_tbl(const char *filename)
set_flag(profile, "$firing requires exact los:", AI::Profile_Flags::Require_exact_los);
if (optional_string("$exact los minimum detection radius:")) {
stuff_float(&profile->los_min_detection_radius);
}
set_flag(profile, "$fighterbay arrivals use carrier orientation:", AI::Profile_Flags::Fighterbay_arrivals_use_carrier_orient);
set_flag(profile, "$fighterbay departures use carrier orientation:", AI::Profile_Flags::Fighterbay_departures_use_carrier_orient);
set_flag(profile, "$debris damage respects 'big damage' flag:", AI::Profile_Flags::Debris_respects_big_damage);
set_flag(profile, "$don't limit change in speed due to physics whack:", AI::Profile_Flags::Dont_limit_change_in_speed_due_to_physics_whack);
set_flag(profile, "$guards ignore protected attackers:", AI::Profile_Flags::Guards_ignore_protected_attackers);
if (optional_string("$ai path mode:"))
{
stuff_string(buf, F_NAME, NAME_LENGTH);
@@ -631,13 +649,19 @@ void parse_ai_profiles_tbl(const char *filename)
set_flag(profile, "$align to target when guarding stationary ship:", AI::Profile_Flags::Align_to_target_when_guarding_still);
if (optional_string("$rotation factor multiplier for player collisions:")) {
stuff_float(&profile->rot_fac_multiplier_ply_collisions);
}
// end of options ----------------------------------------
// if we've been through once already and are at the same place, force a move
if (saved_Mp && (saved_Mp == Mp))
{
char tmp[60];
memset(tmp, 0, 60);
strncpy(tmp, Mp, 59);
mprintf(("WARNING: Unrecognized parameter in ai_profiles: %s\n", tmp));
mprintf(("WARNING: Unrecognized parameter in %s: %s\n", filename, tmp));
Mp++;
}
@@ -711,6 +735,7 @@ void ai_profile_t::reset()
flags.reset();
los_min_detection_radius = 10.0f;
ai_path_mode = AI_PATH_MODE_NORMAL;
subsystem_path_radii = 0;
bay_arrive_speed_mult = 1.0f;
@@ -718,6 +743,7 @@ void ai_profile_t::reset()
second_order_lead_predict_factor = 0;
ai_range_aware_secondary_select_mode = AI_RANGE_AWARE_SEC_SEL_MODE_RETAIL;
turret_target_recheck_time = 2000.0f;
rot_fac_multiplier_ply_collisions = 0.0f;
for (int i = 0; i < NUM_SKILL_LEVELS; ++i) {
max_incoming_asteroids[i] = 0;
@@ -740,10 +766,12 @@ void ai_profile_t::reset()
shield_energy_scale[i] = 0;
afterburner_recharge_scale[i] = 0;
player_damage_scale[i] = 0;
player_damage_inflicted_scale[i] = 0;
player_damage_inflicted_scale[i] = 0;
subsys_damage_scale[i] = 0;
beam_friendly_damage_cap[i] = 0;
beam_friendly_damage_cap[i] = -1.f;
weapon_friendly_damage_cap[i] = -1.f;
weapon_self_damage_cap[i] = -1.f;
turn_time_scale[i] = 0;
glide_attack_percent[i] = 0;
circle_strafe_percent[i] = 0;
@@ -823,4 +851,9 @@ void ai_profile_t::reset()
if (mod_supports_version(23, 4, 0)) {
flags.set(AI::Profile_Flags::Hudsquadmsg_tactical_disarm_disable);
}
if (mod_supports_version(24, 2, 0)) {
flags.set(AI::Profile_Flags::Debris_respects_big_damage);
flags.set(AI::Profile_Flags::Force_beam_turret_fov);
flags.set(AI::Profile_Flags::Guards_ignore_protected_attackers);
}
}
+8
View File
@@ -57,6 +57,8 @@ public:
float subsys_damage_scale[NUM_SKILL_LEVELS]; // damage applied to a player subsystem
float beam_friendly_damage_cap[NUM_SKILL_LEVELS]; // damage cap values for friendly beam fire
float weapon_friendly_damage_cap[NUM_SKILL_LEVELS];
float weapon_self_damage_cap[NUM_SKILL_LEVELS];
float turn_time_scale[NUM_SKILL_LEVELS]; // speed at which enemy ships turn
float glide_attack_percent[NUM_SKILL_LEVELS]; // SUSHI: The likelihood (0.0-1.0) of the AI to use the "glide attack" move
float circle_strafe_percent[NUM_SKILL_LEVELS]; // SUSHI: The likelihood (0.0-1.0) of the AI to use the "circle strafe" move
@@ -99,6 +101,9 @@ public:
float detail_distance_mult[MAX_DETAIL_LEVEL + 1]; //MAX_DETAIL_LEVEL really needs to be 4
// minimum radius for the line-of-sight (los) detection --wookieejedi
float los_min_detection_radius;
int ai_path_mode;
// radii to use for the radius for subsystem path points and default value --wookieejedi
@@ -118,6 +123,9 @@ public:
// how often turrets shoulds check for new targets, milliseconds
float turret_target_recheck_time;
// Multiplier value so the player can also experience rotational effects from collisions --wookieejedi
float rot_fac_multiplier_ply_collisions;
void reset();
};
+4 -1
View File
@@ -1933,7 +1933,10 @@ int ai_big_maybe_enter_strafe_mode(const object *pl_objp, int weapon_objnum)
weapon_objp = &Objects[weapon_objnum];
Assert(weapon_objp->type == OBJ_WEAPON);
Assert(weapon_objp->parent >= 0 && weapon_objp->parent < MAX_OBJECTS);
if (weapon_objp->parent < 0) {
return 0;
}
Assert(weapon_objp->parent < MAX_OBJECTS);
parent_objp = &Objects[weapon_objp->parent];
if ( (parent_objp->signature != weapon_objp->parent_sig) || (parent_objp->type != OBJ_SHIP) ) {
return 0;
+70 -20
View File
@@ -216,11 +216,13 @@ int Mission_all_attack = 0; // !0 means all teams attack all teams.
ai_flag_name Ai_flag_names[] = {
{AI::AI_Flags::No_dynamic, "no-dynamic", },
{AI::AI_Flags::Free_afterburner_use, "free-afterburner-use", },
{AI::AI_Flags::Waypoints_no_formation, "waypoints-no-formation" },
};
ai_flag_description Ai_flag_descriptions[] = {
{AI::AI_Flags::No_dynamic, "Will stop allowing the AI to pursue dynamic goals (eg: chasing ships it was not ordered to)."},
{AI::AI_Flags::Free_afterburner_use, "Will allow AI to use afterburners when attacking a big ship, flying to a target position, guarding a ship, and flying in formation."},
{AI::AI_Flags::Waypoints_no_formation, "Ship will not form up with its wingmates while running waypoints with them." },
};
extern const int Num_ai_flag_names = sizeof(Ai_flag_names) / sizeof(ai_flag_name);
@@ -321,16 +323,34 @@ object *Autopilot_flight_leader = NULL;
/**
* Sets the timestamp used to tell is it is a good time for this team to rearm.
* Once the timestamp is no longer valid, then rearming is not a "good time"
* Ends a 'bad rearm time'
* Once the timestamp is no longer valid, then rearming is not a "good time" (may or may not rearm)
*
* @param team Team (friendly, hostile, neutral)
* @param time Time to rearm
*/
void ai_set_rearm_status(int team, int time)
void ai_set_good_rearm_time(int team, int time)
{
Assert( time >= 0 );
Iff_info[team].ai_rearm_timestamp = _timestamp(time * MILLISECONDS_PER_SECOND);
Iff_info[team].ai_good_rearm_timestamp = _timestamp(time * MILLISECONDS_PER_SECOND);
Iff_info[team].ai_bad_rearm_timestamp = TIMESTAMP::invalid();
}
/**
* Sets the timestamp used to tell is it is a bad time for this team to rearm.
* Ends a 'good rearm time'
* Once the timestamp is no longer valid, then rearming is not a "bad time" (may or may not rearm)
*
* @param team Team (friendly, hostile, neutral)
* @param time Time to rearm
*/
void ai_set_bad_rearm_time(int team, int time)
{
Assert(time >= 0);
Iff_info[team].ai_bad_rearm_timestamp = _timestamp(time * MILLISECONDS_PER_SECOND);
Iff_info[team].ai_good_rearm_timestamp = TIMESTAMP::invalid();
}
/**
@@ -339,7 +359,7 @@ void ai_set_rearm_status(int team, int time)
* @return true(1) or false(0) if it is "safe" for the given object to rearm.
* @todo This function could be easily expended to further the definition of "safe"
*/
int ai_good_time_to_rearm(object *objp)
bool ai_good_time_to_rearm(object *objp)
{
int team;
@@ -347,9 +367,24 @@ int ai_good_time_to_rearm(object *objp)
team = Ships[objp->instance].team;
if (The_mission.ai_profile->flags[AI::Profile_Flags::Fix_good_rearm_time_bug])
return Iff_info[team].ai_rearm_timestamp.isValid() && !timestamp_elapsed(Iff_info[team].ai_rearm_timestamp);
return Iff_info[team].ai_good_rearm_timestamp.isValid() && !timestamp_elapsed(Iff_info[team].ai_good_rearm_timestamp);
else
return Iff_info[team].ai_rearm_timestamp.isValid();
return Iff_info[team].ai_good_rearm_timestamp.isValid();
}
/**
* "unsafe" is currently defined by the mission designer using the good/bad time to rearm sexpressions. This status is currently team based.
*
* @return true(1) or false(0) if it is "unsafe" for the given object to rearm.
*/
bool ai_bad_time_to_rearm(object* objp)
{
int team;
Assert(objp->type == OBJ_SHIP);
team = Ships[objp->instance].team;
return Iff_info[team].ai_bad_rearm_timestamp.isValid() && !timestamp_elapsed(Iff_info[team].ai_bad_rearm_timestamp);
}
/**
@@ -1003,8 +1038,10 @@ void ai_level_init()
Ai_goal_signature = 0;
for (i = 0; i < (int) Iff_info.size(); i++)
Iff_info[i].ai_rearm_timestamp = TIMESTAMP::invalid();
for (i = 0; i < (int)Iff_info.size(); i++) {
Iff_info[i].ai_good_rearm_timestamp = TIMESTAMP::invalid();
Iff_info[i].ai_bad_rearm_timestamp = TIMESTAMP::invalid();
}
// clear out the stuff needed for AI firing powerful secondary weapons
ai_init_secondary_info();
@@ -1332,8 +1369,8 @@ void ai_turn_towards_vector(const vec3d* dest, object* objp, const vec3d* slide_
return;
}
// Don't allow a ship to turn if it's immobile.
if ( objp->flags[Object::Object_Flags::Immobile] ) {
// Don't allow a ship to turn if it's prevented from turning.
if ( objp->flags[Object::Object_Flags::Dont_change_orientation, Object::Object_Flags::Immobile] ) {
return;
}
@@ -6198,7 +6235,7 @@ int ai_fire_primary_weapon(object *objp)
weapon_info* wip = &Weapon_info[swp->primary_bank_weapons[swp->current_primary_bank]];
if (aip->target_objnum != -1 && (The_mission.ai_profile->flags[AI::Profile_Flags::Require_exact_los] || wip->wi_flags[Weapon::Info_Flags::Require_exact_los])) {
//Check if th AI has Line of Sight and is allowed to fire
if (!check_los(OBJ_INDEX(objp), aip->target_objnum, 10.0f, swp->current_primary_bank, -1, nullptr)) {
if (!check_los(OBJ_INDEX(objp), aip->target_objnum, The_mission.ai_profile->los_min_detection_radius, swp->current_primary_bank, -1, nullptr)) {
return 0;
}
}
@@ -6575,7 +6612,7 @@ bool check_ok_to_fire(int objnum, int target_objnum, const weapon_info *wip, int
if (The_mission.ai_profile->flags[AI::Profile_Flags::Require_exact_los] || wip->wi_flags[Weapon::Info_Flags::Require_exact_los]) {
//Check if th AI has Line of Sight and is allowed to fire
if (!check_los(objnum, target_objnum, 10.0f, -1, secondary_bank, firing_pos_global)) {
if (!check_los(objnum, target_objnum, The_mission.ai_profile->los_min_detection_radius, -1, secondary_bank, firing_pos_global)) {
return false;
}
}
@@ -6666,7 +6703,7 @@ bool check_los(int objnum, int target_objnum, float threshold, int primary_bank,
vec3d end = Objects[target_objnum].pos;
//Don't collision check against ourselves or our target
return test_line_of_sight(&start, &end, {&Objects[objnum], &Objects[target_objnum]}, threshold);
return test_line_of_sight(&start, &end, {objnum, target_objnum}, threshold);
}
// --------------------------------------------------------------------------
@@ -10232,6 +10269,11 @@ void guard_object_was_hit(object *guard_objp, object *hitter_objp)
if (is_ignore_object(aip, OBJ_INDEX(hitter_objp)))
return;
// If the hitter is protected, ignore it
if (The_mission.ai_profile->flags[AI::Profile_Flags::Guards_ignore_protected_attackers] &&
hitter_objp->flags[Object::Object_Flags::Protected])
return;
// If hitter is on same team as me, don't attack him.
if (Ships[guard_objp->instance].team == Ships[hitter_objp->instance].team)
return;
@@ -10241,9 +10283,9 @@ void guard_object_was_hit(object *guard_objp, object *hitter_objp)
return;
}
// don't attack if you can't see him
// don't attack if you can't see it
if ( awacs_get_level(hitter_objp, &Ships[aip->shipnum], true) < 1.0f ) {
// if he's a stealth and visible, but not targetable, ok to attack.
// if it's stealthed and visible, but not targetable, ok to attack.
if ( is_object_stealth_ship(hitter_objp) ) {
if ( ai_is_stealth_visible(guard_objp, hitter_objp) != STEALTH_IN_FRUSTUM ) {
return;
@@ -10912,7 +10954,8 @@ void ai_guard()
set_accel_for_target_speed(Pl_objp, (dist_to_goal_point-10.0f)/2.0f);
} else if (Pl_objp->phys_info.speed < 1.0f) {
if (aip->ai_profile_flags[AI::Profile_Flags::Align_to_target_when_guarding_still]) {
turn_towards_point(Pl_objp, &guard_objp->pos, nullptr, 0.0f, &guard_objp->orient);
vec3d goal_vec = guard_objp->orient.vec.fvec + Pl_objp->pos;
turn_towards_point(Pl_objp, &goal_vec, nullptr, 0.0f, &guard_objp->orient);
} else {
turn_away_from_point(Pl_objp, &guard_objp->pos, 0.0f);
}
@@ -12613,6 +12656,11 @@ int ai_formation()
}
if (aip->mode == AIM_WAYPOINTS) {
// skip if they have the flag
if (aip->ai_flags[AI::AI_Flags::Waypoints_no_formation] ||
(shipp->wingnum >= 0 && Wings[shipp->wingnum].flags[Ship::Wing_Flags::Waypoints_no_formation]))
return 1;
if (The_mission.ai_profile->flags[AI::Profile_Flags::Fix_ai_path_order_bug]){
// skip if wing leader has no waypoint order or a different waypoint list
// ...or if it's a different start index or direction
@@ -14227,8 +14275,10 @@ int maybe_request_support(object *objp)
// Compute danger threshold.
// Balance this with desire and maybe request support.
if (ai_good_time_to_rearm( objp )) {
if (ai_good_time_to_rearm(objp)) {
try_to_rearm = true;
} else if (ai_bad_time_to_rearm(objp)) {
try_to_rearm = false;
} else if (num_allies_rearming(objp) < 2) {
if (desire >= 8) { // guarantees disabled will cause repair request
try_to_rearm = true;
@@ -16653,7 +16703,7 @@ void maybe_cheat_fire_synaptic(object *objp)
}
}
bool test_line_of_sight(vec3d* from, vec3d* to, std::unordered_set<const object*>&& excluded_objects, float threshold, bool test_for_shields, bool test_for_hull, float* first_intersect_dist, object** first_intersect_obj) {
bool test_line_of_sight(vec3d* from, vec3d* to, std::unordered_set<int>&& excluded_object_ids, float threshold, bool test_for_shields, bool test_for_hull, float* first_intersect_dist, object** first_intersect_obj) {
bool collides = false;
for (object* objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp)) {
@@ -16661,7 +16711,7 @@ bool test_line_of_sight(vec3d* from, vec3d* to, std::unordered_set<const object*
continue;
//Don't collision check against excluded objects
if (excluded_objects.count(objp) > 0)
if (excluded_object_ids.count(OBJ_INDEX(objp)) > 0)
continue;
int model_num = 0;
@@ -16674,7 +16724,7 @@ bool test_line_of_sight(vec3d* from, vec3d* to, std::unordered_set<const object*
model_instance_num = -1;
}
else if (type == OBJ_ASTEROID) {
model_num = Asteroid_info[Asteroids[objp->instance].asteroid_type].model_num[Asteroids[objp->instance].asteroid_subtype];
model_num = Asteroid_info[Asteroids[objp->instance].asteroid_type].subtypes[Asteroids[objp->instance].asteroid_subtype].model_number;
model_instance_num = Asteroids[objp->instance].model_instance_num;
}
else if (type == OBJ_SHIP) {
+52 -35
View File
@@ -133,7 +133,7 @@ bool object_in_turret_fov(const object *objp, const ship_subsys *ss, const vec3d
model_num = Ship_info[Ships[objp->instance].ship_info_index].model_num;
break;
case OBJ_ASTEROID:
model_num = Asteroid_info[Asteroids[objp->instance].asteroid_type].model_num[Asteroids[objp->instance].asteroid_subtype];
model_num = Asteroid_info[Asteroids[objp->instance].asteroid_type].subtypes[Asteroids[objp->instance].asteroid_subtype].model_number;
break;
default:
vm_vec_normalized_dir(&v2e, &objp->pos, tpos);
@@ -1215,6 +1215,7 @@ void ship_get_global_turret_gun_info(const object *objp, const ship_subsys *ssp,
}
model_instance_local_to_global_point(gpos, gun_pos, pm, pmi, tp->turret_gun_sobj, &objp->orient, &objp->pos);
// we might not need to calculate this
if (!gvec)
@@ -1781,45 +1782,47 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
if (!(turret->weapons.flags[Ship::Weapon_Flags::Beam_Free])) {
return false;
}
beam_fire_info fire_info;
// stuff beam firing info
memset(&fire_info, 0, sizeof(beam_fire_info));
fire_info.accuracy = 1.0f;
fire_info.beam_info_index = turret_weapon_class;
fire_info.beam_info_override = nullptr;
fire_info.shooter = &Objects[parent_objnum];
fire_info.target = turret_enemy_objp;
if (wip->wi_flags[Weapon::Info_Flags::Antisubsysbeam])
fire_info.target_subsys = turret->targeted_subsys;
else
fire_info.target_subsys = nullptr;
fire_info.turret = turret;
fire_info.burst_seed = old_burst_seed;
fire_info.fire_method = BFM_TURRET_FIRED;
fire_info.per_burst_rotation = swp->per_burst_rot;
fire_info.burst_index = old_burst_counter;
for (int i = 0; i < wip->shots; i++) {
beam_fire_info fire_info;
// fire a beam weapon
weapon_objnum = beam_fire(&fire_info);
// stuff beam firing info
memset(&fire_info, 0, sizeof(beam_fire_info));
fire_info.accuracy = 1.0f;
fire_info.beam_info_index = turret_weapon_class;
fire_info.beam_info_override = nullptr;
fire_info.shooter = &Objects[parent_objnum];
fire_info.target = turret_enemy_objp;
if (wip->wi_flags[Weapon::Info_Flags::Antisubsysbeam])
fire_info.target_subsys = turret->targeted_subsys;
else
fire_info.target_subsys = nullptr;
fire_info.turret = turret;
fire_info.burst_seed = old_burst_seed;
fire_info.fire_method = BFM_TURRET_FIRED;
fire_info.per_burst_rotation = swp->per_burst_rot;
fire_info.burst_index = (old_burst_counter * wip->shots) + i;
if (weapon_objnum != -1) {
objp = &Objects[weapon_objnum];
// fire a beam weapon
weapon_objnum = beam_fire(&fire_info);
parent_ship->last_fired_turret = turret;
turret->last_fired_weapon_info_index = turret_weapon_class;
turret->turret_last_fired = _timestamp();
if (weapon_objnum != -1) {
objp = &Objects[weapon_objnum];
if (scripting::hooks::OnTurretFired->isActive()) {
scripting::hooks::OnTurretFired->run(scripting::hooks::WeaponUsedConditions{ parent_ship , turret_enemy_objp, SCP_vector<int>{ turret_weapon_class }, true },
scripting::hook_param_list(
scripting::hook_param("Ship", 'o', &Objects[parent_objnum]),
scripting::hook_param("Beam", 'o', objp),
scripting::hook_param("Target", 'o', turret_enemy_objp)
));
parent_ship->last_fired_turret = turret;
turret->last_fired_weapon_info_index = turret_weapon_class;
turret->turret_last_fired = _timestamp();
if (scripting::hooks::OnTurretFired->isActive()) {
scripting::hooks::OnTurretFired->run(scripting::hooks::WeaponUsedConditions{ parent_ship , turret_enemy_objp, SCP_vector<int>{ turret_weapon_class }, true },
scripting::hook_param_list(
scripting::hook_param("Ship", 'o', &Objects[parent_objnum]),
scripting::hook_param("Beam", 'o', objp),
scripting::hook_param("Target", 'o', turret_enemy_objp)
));
}
}
}
turret->flags.set(Ship::Subsystem_Flags::Has_fired); //set fired flag for scripting -nike
return true;
}
@@ -1988,7 +1991,14 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
}
// do mflash if the weapon has it
if (wip->muzzle_flash >= 0) {
if (wip->muzzle_effect.isValid()) {
//spawn particle effect
auto particleSource = particle::ParticleManager::get()->createSource(wip->muzzle_effect);
particleSource.moveToTurret(&Objects[parent_ship->objnum], turret->system_info->turret_gun_sobj, turret->turret_next_fire_pos);
particleSource.setVelocity(&Objects[parent_ship->objnum].phys_info.vel);
particleSource.finish();
}
else if (wip->muzzle_flash >= 0) {
mflash_create(firing_pos, firing_vec, &Objects[parent_ship->objnum].phys_info, wip->muzzle_flash);
}
@@ -2098,7 +2108,14 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
}
// muzzle flash?
if (Weapon_info[tsi->weapon_class].muzzle_flash >= 0) {
if (Weapon_info[tsi->weapon_class].muzzle_effect.isValid()) {
//spawn particle effect
auto particleSource = particle::ParticleManager::get()->createSource(Weapon_info[tsi->weapon_class].muzzle_effect);
particleSource.moveToTurret(&Objects[tsi->parent_objnum], tsi->turret->system_info->turret_gun_sobj, tsi->turret->turret_next_fire_pos - 1);
particleSource.setVelocity(&Objects[tsi->parent_objnum].phys_info.vel);
particleSource.finish();
}
else if (Weapon_info[tsi->weapon_class].muzzle_flash >= 0) {
mflash_create(&turret_pos, &turret_fvec, &Objects[tsi->parent_objnum].phys_info, Weapon_info[tsi->weapon_class].muzzle_flash);
}
+222 -174
View File
@@ -262,6 +262,25 @@ static void inner_bound_pos_fixup(asteroid_field *asfieldp, vec3d *pos)
}
}
/**
* Randomly select an asteroid subtype
*/
const SCP_string& pick_random_asteroid_type()
{
return Asteroid_field.field_asteroid_type[Random::next(static_cast<int>(Asteroid_field.field_asteroid_type.size()))];
}
int get_asteroid_subtype_index_by_name(const SCP_string &name, int asteroid_idx) {
asteroid_info* this_asteroid = &Asteroid_info[asteroid_idx];
for (int i = 0; i < static_cast<int>(this_asteroid->subtypes.size()); i++) {
if (this_asteroid->subtypes[i].type_name == name) {
return i;
}
}
return -1;
}
/**
* Create a single asteroid
*/
@@ -279,8 +298,8 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
int rand_base;
// bogus
if(asfieldp == NULL) {
return NULL;
if(asfieldp == nullptr) {
return nullptr;
}
for (n=0; n<MAX_ASTEROIDS; n++) {
@@ -291,15 +310,11 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
if (n >= MAX_ASTEROIDS) {
nprintf(("Warning","Could not create asteroid, no more slots left\n"));
return NULL;
return nullptr;
}
if((asteroid_type < 0) || (asteroid_type >= (int)Asteroid_info.size())) {
return NULL;
}
if((asteroid_subtype < 0) || (asteroid_subtype >= NUM_ASTEROID_POFS)) {
return NULL;
if (!SCP_vector_inbounds(Asteroid_info, asteroid_type)) {
return nullptr;
}
// HACK: multiplayer asteroid subtype always 0 to keep subtype in sync
@@ -309,9 +324,13 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
asip = &Asteroid_info[asteroid_type];
// bogus
if(asip->modelp[asteroid_subtype] == NULL) {
return NULL;
if (!SCP_vector_inbounds(asip->subtypes, asteroid_subtype)) {
return nullptr;
}
// if the model is not loaded then abort
if(asip->subtypes[asteroid_subtype].model_pointer == nullptr) {
return nullptr;
}
asp = &Asteroids[n];
@@ -326,7 +345,7 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
asp->collide_objsig = -1;
asp->target_objnum = -1;
radius = model_get_radius(asip->model_num[asteroid_subtype]);
radius = model_get_radius(asip->subtypes[asteroid_subtype].model_number);
vm_vec_sub(&delta_bound, &asfieldp->max_bound, &asfieldp->min_bound);
@@ -379,8 +398,8 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
asp->objnum = objnum;
asp->model_instance_num = -1;
if (model_get(asip->model_num[asteroid_subtype])->flags & PM_FLAG_HAS_INTRINSIC_MOTION) {
asp->model_instance_num = model_create_instance(objnum, asip->model_num[asteroid_subtype]);
if (model_get(asip->subtypes[asteroid_subtype].model_number)->flags & PM_FLAG_HAS_INTRINSIC_MOTION) {
asp->model_instance_num = model_create_instance(objnum, asip->subtypes[asteroid_subtype].model_number);
}
// Add to Asteroid_used_list
@@ -435,8 +454,8 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
objp->phys_info.max_vel.xyz.y = 0.0f;
objp->phys_info.max_vel.xyz.z = vm_vec_mag(&objp->phys_info.desired_vel);
objp->phys_info.mass = asip->modelp[asteroid_subtype]->rad * 700.0f;
objp->phys_info.I_body_inv.vec.rvec.xyz.x = 1.0f / (objp->phys_info.mass*asip->modelp[asteroid_subtype]->rad);
objp->phys_info.mass = asip->subtypes[asteroid_subtype].model_pointer->rad * 700.0f;
objp->phys_info.I_body_inv.vec.rvec.xyz.x = 1.0f / (objp->phys_info.mass*asip->subtypes[asteroid_subtype].model_pointer->rad);
objp->phys_info.I_body_inv.vec.uvec.xyz.y = objp->phys_info.I_body_inv.vec.rvec.xyz.x;
objp->phys_info.I_body_inv.vec.fvec.xyz.z = objp->phys_info.I_body_inv.vec.rvec.xyz.x;
objp->hull_strength = asip->initial_asteroid_strength * (0.8f + (float)Game_skill_level/NUM_SKILL_LEVELS)/2.0f;
@@ -465,7 +484,8 @@ void asteroid_sub_create(object *parent_objp, int asteroid_type, vec3d *relvec)
int subtype = Asteroids[parent_objp->instance].asteroid_subtype;
new_objp = asteroid_create(&Asteroid_field, asteroid_type, subtype);
if (new_objp == NULL)
// New asteroid size doesn't have this subtype, so abort
if (new_objp == nullptr)
return;
if ( MULTIPLAYER_MASTER ){
@@ -502,27 +522,35 @@ static void asteroid_load(int asteroid_info_index, int asteroid_subtype)
int i;
asteroid_info *asip;
Assertion(asteroid_info_index < (int)Asteroid_info.size(), "Command to load asteroid at index %i, but only %i asteroids exist", asteroid_info_index, (int)Asteroid_info.size());
Assertion(asteroid_subtype < NUM_ASTEROID_POFS, "Command to load asteroid pof %i, but only %i pofs are allowed", asteroid_subtype, NUM_ASTEROID_POFS);
Assertion(asteroid_info_index < static_cast<int>(Asteroid_info.size()),
"Command to load asteroid at index %i, but only %i asteroids exist",
asteroid_info_index,
static_cast<int>(Asteroid_info.size()));
if ( (asteroid_info_index >= (int)Asteroid_info.size()) || (asteroid_subtype >= NUM_ASTEROID_POFS) ) {
// invalid asteroid index
if (!SCP_vector_inbounds(Asteroid_info, asteroid_info_index)) {
return;
}
asip = &Asteroid_info[asteroid_info_index];
if ( !VALID_FNAME(asip->pof_files[asteroid_subtype]) )
// This asteroid does not have this subtype so just return
if (!SCP_vector_inbounds(asip->subtypes, asteroid_subtype)) {
return;
}
if ( !VALID_FNAME(asip->subtypes[asteroid_subtype].pof_filename) )
return;
//Check if the model is already loaded
if (asip->model_num[asteroid_subtype] >= 0)
if (asip->subtypes[asteroid_subtype].model_number >= 0)
return;
asip->model_num[asteroid_subtype] = model_load( asip->pof_files[asteroid_subtype], 0, NULL );
asip->subtypes[asteroid_subtype].model_number = model_load( asip->subtypes[asteroid_subtype].pof_filename, 0, nullptr );
if (asip->model_num[asteroid_subtype] >= 0)
if (asip->subtypes[asteroid_subtype].model_number >= 0)
{
polymodel *pm = asip->modelp[asteroid_subtype] = model_get(asip->model_num[asteroid_subtype]);
polymodel *pm = asip->subtypes[asteroid_subtype].model_pointer = model_get(asip->subtypes[asteroid_subtype].model_number);
if ( asip->num_detail_levels != pm->n_detail_levels )
{
@@ -553,10 +581,11 @@ void asteroid_create_all()
// each different type (size) of debris piece has a diffenent weight, smaller weighted more heavily than larger.
// choose next type from table ship_debris_odds_table by Random::next()%max_weighted_range,
// the threshold *below* which the debris type is selected.
struct {
struct ShipDebrisOdds {
float random_threshold;
int debris_type;
} ship_debris_odds_table[MAX_ACTIVE_DEBRIS_TYPES];
};
std::vector<ShipDebrisOdds> shipDebrisOddsTable(Asteroid_field.field_debris_type.size());
float max_weighted_range = 0.0f;
@@ -567,7 +596,8 @@ void asteroid_create_all()
return;
}
if (Asteroid_field.num_used_field_debris_types <= 0) {
if ((Asteroid_field.debris_genre == DG_DEBRIS && Asteroid_field.field_debris_type.empty()) ||
(Asteroid_field.debris_genre == DG_ASTEROID && Asteroid_field.field_asteroid_type.empty())) {
Warning(LOCATION, "An asteroid field is enabled, but no asteroid types were enabled.");
return;
}
@@ -602,45 +632,29 @@ void asteroid_create_all()
int num_debris_types = 0;
// get number of ship debris types
// get number of debris types
if (Asteroid_field.debris_genre == DG_DEBRIS) {
for (idx=0; idx<MAX_ACTIVE_DEBRIS_TYPES; idx++) {
if (Asteroid_field.field_debris_type[idx] != -1) {
num_debris_types++;
}
}
num_debris_types = static_cast<int>(Asteroid_field.field_debris_type.size());
// Calculate the odds table
for (idx=0; idx<num_debris_types; idx++) {
float debris_weight = Asteroid_info[Asteroid_field.field_debris_type[idx]].spawn_weight;
ship_debris_odds_table[idx].random_threshold = max_weighted_range + debris_weight;
ship_debris_odds_table[idx].debris_type = Asteroid_field.field_debris_type[idx];
shipDebrisOddsTable[idx].random_threshold = max_weighted_range + debris_weight;
shipDebrisOddsTable[idx].debris_type = Asteroid_field.field_debris_type[idx];
max_weighted_range += debris_weight;
}
}
// Load Asteroid/ship models
// Load Asteroid/debris models
if (Asteroid_field.debris_genre == DG_DEBRIS) {
for (idx=0; idx<num_debris_types; idx++) {
asteroid_load(Asteroid_field.field_debris_type[idx], 0);
}
} else {
if (Asteroid_field.field_debris_type[0] != -1) {
asteroid_load(ASTEROID_TYPE_SMALL, 0);
asteroid_load(ASTEROID_TYPE_MEDIUM, 0);
asteroid_load(ASTEROID_TYPE_LARGE, 0);
}
if (Asteroid_field.field_debris_type[1] != -1) {
asteroid_load(ASTEROID_TYPE_SMALL, 1);
asteroid_load(ASTEROID_TYPE_MEDIUM, 1);
asteroid_load(ASTEROID_TYPE_LARGE, 1);
}
if (Asteroid_field.field_debris_type[2] != -1) {
asteroid_load(ASTEROID_TYPE_SMALL, 2);
asteroid_load(ASTEROID_TYPE_MEDIUM, 2);
asteroid_load(ASTEROID_TYPE_LARGE, 2);
for (const auto& subtype : Asteroid_field.field_asteroid_type) {
asteroid_load(ASTEROID_TYPE_SMALL, get_asteroid_subtype_index_by_name(subtype, ASTEROID_TYPE_SMALL));
asteroid_load(ASTEROID_TYPE_MEDIUM, get_asteroid_subtype_index_by_name(subtype, ASTEROID_TYPE_MEDIUM));
asteroid_load(ASTEROID_TYPE_LARGE, get_asteroid_subtype_index_by_name(subtype, ASTEROID_TYPE_LARGE));
}
}
@@ -650,17 +664,7 @@ void asteroid_create_all()
// For asteroid, load only large asteroids
// get a valid subtype
int counter = Random::next(Asteroid_field.num_used_field_debris_types);
int subtype = -1;
for (int j = 0; j < NUM_ASTEROID_POFS; j++) {
if (Asteroid_field.field_debris_type[j] >= 0) {
if (counter == 0) {
subtype = j;
break;
} else
counter--;
}
}
int subtype = get_asteroid_subtype_index_by_name(pick_random_asteroid_type(), ASTEROID_TYPE_LARGE);
if (subtype >= 0)
asteroid_create(&Asteroid_field, ASTEROID_TYPE_LARGE, subtype);
@@ -669,10 +673,10 @@ void asteroid_create_all()
float rand_choice = frand() * max_weighted_range;
for (idx=0; idx<MAX_ACTIVE_DEBRIS_TYPES; idx++) {
for (idx = 0; idx < static_cast<int>(Asteroid_field.field_debris_type.size()); idx++) {
// for ship debris, choose type according to odds table
if (rand_choice < ship_debris_odds_table[idx].random_threshold) {
asteroid_create(&Asteroid_field, ship_debris_odds_table[idx].debris_type, 0);
if (rand_choice < shipDebrisOddsTable[idx].random_threshold) {
asteroid_create(&Asteroid_field, shipDebrisOddsTable[idx].debris_type, 0);
break;
}
}
@@ -698,7 +702,7 @@ void remove_all_asteroids()
}
// will replace any existing asteroid or debris field with an asteroid field
void asteroid_create_asteroid_field(int num_asteroids, int field_type, int asteroid_speed, bool brown, bool blue, bool orange, vec3d o_min, vec3d o_max, bool inner_box, vec3d i_min, vec3d i_max, SCP_vector<SCP_string> targets)
void asteroid_create_asteroid_field(int num_asteroids, int field_type, int asteroid_speed, vec3d o_min, vec3d o_max, bool inner_box, vec3d i_min, vec3d i_max, SCP_vector<SCP_string> asteroid_types)
{
remove_all_asteroids();
@@ -732,25 +736,11 @@ void asteroid_create_asteroid_field(int num_asteroids, int field_type, int aster
Asteroid_field.speed = (float)asteroid_speed;
Asteroid_field.debris_genre = DG_ASTEROID;
Asteroid_field.field_debris_type[0] = -1;
Asteroid_field.field_debris_type[1] = -1;
Asteroid_field.field_debris_type[2] = -1;
Asteroid_field.field_debris_type.clear();
int count = 0;
if (brown) {
Asteroid_field.field_debris_type[0] = 1;
count++;
}
if (blue) {
Asteroid_field.field_debris_type[1] = 1;
count++;
}
if (orange) {
Asteroid_field.field_debris_type[2] = 1;
count++;
}
Asteroid_field.field_asteroid_type.clear();
Asteroid_field.num_used_field_debris_types = count;
Asteroid_field.field_asteroid_type = std::move(asteroid_types);
Asteroid_field.min_bound = o_min;
Asteroid_field.max_bound = o_max;
@@ -768,16 +758,14 @@ void asteroid_create_asteroid_field(int num_asteroids, int field_type, int aster
Asteroid_field.inner_max_bound = i_max;
}
Asteroid_field.target_names = targets;
// Only create asteroids if we have some to create
if ((count > 0) && (num_asteroids > 0)) {
if ((!Asteroid_field.field_asteroid_type.empty()) && (num_asteroids > 0)) {
asteroid_create_all();
}
}
// will replace any existing asteroid or debris field with a debris field
void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, int debris1, int debris2, int debris3, vec3d o_min, vec3d o_max, bool enhanced)
void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, SCP_vector<int> debris_types, vec3d o_min, vec3d o_max, bool enhanced)
{
remove_all_asteroids();
@@ -792,33 +780,11 @@ void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, int deb
Asteroid_field.speed = (float)asteroid_speed;
Asteroid_field.debris_genre = DG_DEBRIS;
Asteroid_field.field_debris_type[0] = -1;
Asteroid_field.field_debris_type[1] = -1;
Asteroid_field.field_debris_type[2] = -1;
Asteroid_field.field_debris_type.clear();
int count = 0;
for (int i = 0; i < MAX_ACTIVE_DEBRIS_TYPES; i++) {
if (debris1 >= 0) {
Asteroid_field.field_debris_type[i] = debris1;
debris1 = -1;
count++;
continue;
}
if (debris2 >= 0) {
Asteroid_field.field_debris_type[i] = debris2;
debris2 = -1;
count++;
continue;
}
if (debris3 >= 0) {
Asteroid_field.field_debris_type[i] = debris3;
debris3 = -1;
count++;
continue;
}
}
Asteroid_field.field_asteroid_type.clear();
Asteroid_field.num_used_field_debris_types = count;
Asteroid_field.field_debris_type = std::move(debris_types);
Asteroid_field.min_bound = o_min;
Asteroid_field.max_bound = o_max;
@@ -831,7 +797,7 @@ void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, int deb
Asteroid_field.bound_rad = MAX(3000.0f, b_rad);
// Only create debris if we have some to create
if ((count > 0) && (num_asteroids > 0)) {
if ((!Asteroid_field.field_debris_type.empty()) && (num_asteroids > 0)) {
asteroid_create_all();
}
}
@@ -850,10 +816,8 @@ void asteroid_level_init()
Asteroid_field.has_inner_bound = false;
Asteroid_field.field_type = FT_ACTIVE;
Asteroid_field.debris_genre = DG_ASTEROID;
Asteroid_field.field_debris_type[0] = -1;
Asteroid_field.field_debris_type[1] = -1;
Asteroid_field.field_debris_type[2] = -1;
Asteroid_field.num_used_field_debris_types = 0;
Asteroid_field.field_debris_type.clear();
Asteroid_field.field_asteroid_type.clear();
Asteroid_field.target_names.clear();
if (!Fred_running)
@@ -1049,7 +1013,7 @@ bool asteroid_is_within_view(vec3d *pos, float range, bool range_override)
*/
static void maybe_throw_asteroid()
{
Assertion(Asteroid_field.num_used_field_debris_types > 0, "maybe_throw_asteroid() called while num_used_field_debris_types was 0; this should never happen, get a coder!");
Assertion(!Asteroid_field.field_asteroid_type.empty(), "maybe_throw_asteroid() called while field_asteroid_type.size was 0; this should never happen, get a coder!");
for (asteroid_target& target : Asteroid_targets) {
if (!timestamp_elapsed(target.throw_stamp))
@@ -1067,18 +1031,8 @@ static void maybe_throw_asteroid()
target.throw_stamp = _timestamp(1000 + 1200 * target.incoming_asteroids / (Game_skill_level+1));
int counter = Random::next(Asteroid_field.num_used_field_debris_types);
int subtype = -1;
for (int i = 0; i < NUM_ASTEROID_POFS; i++) {
if (Asteroid_field.field_debris_type[i] >= 0) {
if (counter == 0) {
subtype = i;
break;
}
else
counter--;
}
}
// get a valid subtype
int subtype = get_asteroid_subtype_index_by_name(pick_random_asteroid_type(), ASTEROID_TYPE_LARGE);
// this really shouldn't happen but just in case...
if (subtype < 0)
@@ -1255,7 +1209,7 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
// asteroid weapon collision
Assert( other_obj->type == OBJ_WEAPON );
mc.model_instance_num = Asteroids[num].model_instance_num;
mc.model_num = Asteroid_info[Asteroids[num].asteroid_type].model_num[asteroid_subtype]; // Fill in the model to check
mc.model_num = Asteroid_info[Asteroids[num].asteroid_type].subtypes[asteroid_subtype].model_number; // Fill in the model to check
mc.orient = &pasteroid->orient; // The object's orient
mc.pos = &pasteroid->pos; // The object's position
mc.p0 = &other_obj->last_pos; // Point 1 of ray to check
@@ -1436,7 +1390,7 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
} else {
// Asteroid is heavier obj
mc.model_instance_num = Asteroids[num].model_instance_num;
mc.model_num = Asteroid_info[Asteroids[num].asteroid_type].model_num[asteroid_subtype]; // Fill in the model to check
mc.model_num = Asteroid_info[Asteroids[num].asteroid_type].subtypes[asteroid_subtype].model_number; // Fill in the model to check
mc.orient = &pasteroid->orient; // The object's orient
mc.radius = model_get_core_radius(Ship_info[Ships[pship_obj->instance].ship_info_index].model_num);
@@ -1517,14 +1471,16 @@ void asteroid_render(object * obj, model_draw_list *scene)
Assert( asp->flags & AF_USED );
model_clear_instance( Asteroid_info[asp->asteroid_type].model_num[asp->asteroid_subtype]);
model_clear_instance( Asteroid_info[asp->asteroid_type].subtypes[asp->asteroid_subtype].model_number);
model_render_params render_info;
render_info.set_object_number( OBJ_INDEX(obj) );
render_info.set_flags(MR_IS_ASTEROID);
if (asp->model_instance_num >= 0)
render_info.set_replacement_textures(model_get_instance(asp->model_instance_num)->texture_replace);
model_render_queue(&render_info, scene, Asteroid_info[asp->asteroid_type].model_num[asp->asteroid_subtype], &obj->orient, &obj->pos); // Replace MR_NORMAL with 0x07 for big yellow blobs
model_render_queue(&render_info, scene, Asteroid_info[asp->asteroid_type].subtypes[asp->asteroid_subtype].model_number, &obj->orient, &obj->pos); // Replace MR_NORMAL with 0x07 for big yellow blobs
}
}
@@ -1593,9 +1549,8 @@ static float asteroid_create_explosion(object *objp)
fireball_type = FIREBALL_ASTEROID;
}
if (fireball_type >= Num_fireball_types) {
Warning(LOCATION, "Invalid fireball type %i specified for an asteroid, only %i fireball types are defined.", fireball_type, Num_fireball_types);
if (fireball_type >= static_cast<int>(Fireball_info.size())) {
Warning(LOCATION, "Invalid fireball type %i specified for an asteroid; only " SIZE_T_ARG " fireball types are defined.", fireball_type, Fireball_info.size());
return 0;
}
@@ -1759,9 +1714,10 @@ void asteroid_level_close()
//when a level is closed, all models are cleared, so let's make sure that
//is tracked for asteroids as well -Mjn
for (int i = 0; i < (int)Asteroid_info.size(); i++) {
for (int j = 0; j < NUM_ASTEROID_POFS; j++) {
Asteroid_info[i].model_num[j] = -1;
for (size_t i = 0; i < Asteroid_info.size(); i++) {
for (size_t j = 0; j < Asteroid_info[i].subtypes.size(); j++) {
Asteroid_info[i].subtypes[j].model_number = -1;
Asteroid_info[i].subtypes[j].model_pointer = nullptr;
}
}
@@ -2220,15 +2176,71 @@ static void asteroid_parse_section()
}
if (optional_string("$POF file1:")) {
stuff_string(asteroid_p->pof_files[0], F_NAME, MAX_FILENAME_LEN);
asteroid_subtype_info thisType;
thisType.type_name = "Brown";
stuff_string(thisType.pof_filename, F_NAME, MAX_FILENAME_LEN);
thisType.model_number = -1;
thisType.model_pointer = nullptr;
asteroid_p->subtypes.push_back(thisType);
}
if (optional_string("$POF file2:")) {
stuff_string(asteroid_p->pof_files[1], F_NAME, MAX_FILENAME_LEN);
asteroid_subtype_info thisType;
thisType.type_name = "Blue";
stuff_string(thisType.pof_filename, F_NAME, MAX_FILENAME_LEN);
thisType.model_number = -1;
thisType.model_pointer = nullptr;
asteroid_p->subtypes.push_back(thisType);
}
if (optional_string("$POF file3:")) {
stuff_string(asteroid_p->pof_files[2], F_NAME, MAX_FILENAME_LEN);
asteroid_subtype_info thisType;
thisType.type_name = "Orange";
stuff_string(thisType.pof_filename, F_NAME, MAX_FILENAME_LEN);
thisType.model_number = -1;
thisType.model_pointer = nullptr;
asteroid_p->subtypes.push_back(thisType);
}
// For asteroid types we can have unlimited subtypes
if (asteroid_p->type != ASTEROID_TYPE_DEBRIS) {
while (optional_string("$Subtype:")) {
asteroid_subtype_info thisType;
stuff_string(thisType.type_name, F_NAME);
required_string("+POF file:");
stuff_string(thisType.pof_filename, F_NAME, MAX_FILENAME_LEN);
thisType.model_number = -1;
thisType.model_pointer = nullptr;
bool exists = false;
for (const auto& type : asteroid_p->subtypes) {
if (type.type_name == thisType.type_name) {
exists = true;
}
}
if (exists) {
error_display(0,
"Asteroid subtype %s already exists for asteroid %s",
thisType.type_name.c_str(),
asteroid_p->name);
} else {
asteroid_p->subtypes.push_back(thisType);
}
}
}
if (optional_string("$Detail distance:")) {
@@ -2251,10 +2263,7 @@ static void asteroid_parse_section()
}
if(optional_string("$Explosion Animations:")){
int temp[MAX_FIREBALL_TYPES];
auto parsed_ints = stuff_int_list(temp, MAX_FIREBALL_TYPES, RAW_INTEGER_TYPE);
asteroid_p->explosion_bitmap_anims.clear();
asteroid_p->explosion_bitmap_anims.insert(asteroid_p->explosion_bitmap_anims.begin(), temp, temp + parsed_ints);
stuff_fireball_index_list(asteroid_p->explosion_bitmap_anims, asteroid_p->name);
}
if (optional_string("$Explosion Radius Mult:")) {
@@ -2420,7 +2429,7 @@ static void asteroid_parse_tbl(const char* filename)
// Gets the index of an asteroid by name from Asteroid_info
int get_asteroid_index(const char* asteroid_name)
{
for (int i = 0; i < (int)Asteroid_info.size(); i++) {
for (int i = 0; i < static_cast<int>(Asteroid_info.size()); i++) {
if (!stricmp(asteroid_name, Asteroid_info[i].name)) {
return i;
}
@@ -2429,6 +2438,31 @@ int get_asteroid_index(const char* asteroid_name)
return -1;
}
// For FRED. Gets a list of unique asteroid subtype names
SCP_vector<SCP_string> get_list_valid_asteroid_subtypes()
{
SCP_vector<SCP_string> list;
for (const auto& this_asteroid : Asteroid_info) {
if (this_asteroid.type != ASTEROID_TYPE_DEBRIS) {
for (const auto& subtype : this_asteroid.subtypes) {
bool exists = false;
for (const auto& entry : list) {
if (subtype.type_name == entry) {
exists = true;
}
}
if (!exists) {
list.push_back(subtype.type_name);
}
}
}
}
return list;
}
static void verify_asteroid_splits()
{
@@ -2487,7 +2521,14 @@ static void verify_asteroid_list()
}
// Rest should be debris type
for (int i = 0; i < (int)asteroid_list.size(); i++) {
// Remove all subtypes except the first one
asteroid_list[i].subtypes.resize(1);
// Make sure the first subtype is set as debris
asteroid_list[i].subtypes[0].type_name = "Debris";
if (asteroid_list[i].type < 0) {
Asteroid_info.push_back(asteroid_list[i]);
} else {
@@ -2501,14 +2542,8 @@ static void verify_asteroid_list()
//Check that we have the appropriate POF files-Mjn
for (int i = 0; i < (int)Asteroid_info.size(); i++) {
if (Asteroid_info[i].pof_files[0][0] == '\0')
Error(LOCATION, "Missing [POF File 1] for %s", Asteroid_info[i].name);
if (Asteroid_info[i].type != ASTEROID_TYPE_DEBRIS) {
if (Asteroid_info[i].pof_files[1][0] == '\0')
Error(LOCATION, "Missing [POF File 2] for %s", Asteroid_info[i].name);
if (Asteroid_info[i].pof_files[2][0] == '\0')
Error(LOCATION, "Missing [POF File 3] for %s", Asteroid_info[i].name);
if (Asteroid_info[i].subtypes.size() == 0) {
Error(LOCATION, "Asteroid %s needs at least one subtype!", Asteroid_info[i].name);
}
}
}
@@ -2545,7 +2580,7 @@ void asteroid_init()
}
if (Asteroid_icon_closeup_model[0] == '\0')
strcpy_s(Asteroid_icon_closeup_model, Asteroid_info[ASTEROID_TYPE_LARGE].pof_files[0]); // magic file from retail
strcpy_s(Asteroid_icon_closeup_model, Asteroid_info[ASTEROID_TYPE_LARGE].subtypes[0].pof_filename); // magic file from retail
}
@@ -2586,7 +2621,7 @@ void asteroid_frame()
}
// If no asteroid types are defined for the field, abort.
if (Asteroid_field.num_used_field_debris_types <= 0) {
if (Asteroid_field.field_asteroid_type.empty()) {
return;
}
@@ -2698,21 +2733,26 @@ void asteroid_page_in()
return;
if (Asteroid_field.num_initial_asteroids > 0 ) {
int i, j, k;
nprintf(( "Paging", "Paging in asteroids\n" ));
size_t num_debris_types = NUM_ASTEROID_SIZES;
if (Asteroid_field.debris_genre == DG_DEBRIS) {
num_debris_types = Asteroid_field.field_debris_type.size();
}
// max of MAX_ACTIVE_DEBRIS_TYPES possible debris field models
for (i=0; i<MAX_ACTIVE_DEBRIS_TYPES; i++) {
// for asteroids this will loop over all three possible sizes
// for debris this will loop over all selected types
for (size_t i = 0; i < num_debris_types; i++) {
asteroid_info *asip;
if (Asteroid_field.debris_genre == DG_ASTEROID) {
// asteroid
Assertion(i < NUM_ASTEROID_SIZES, "Got invalid call to load a debris type instead of asteroid type!");
Assertion(i < NUM_ASTEROID_SIZES, "Got invalid call to load non-existent asteroid size!");
asip = &Asteroid_info[i];
} else {
// ship debris - always full until empty
// debris - always full until empty
if (Asteroid_field.field_debris_type[i] != -1) {
asip = &Asteroid_info[Asteroid_field.field_debris_type[i]];
} else {
@@ -2721,28 +2761,36 @@ void asteroid_page_in()
}
for (k=0; k<NUM_ASTEROID_POFS; k++) {
for (size_t k = 0; k < asip->subtypes.size(); k++) {
// SHIP DEBRIS - use subtype 0
// DEBRIS FIELDS - always use subtype 0
if (Asteroid_field.debris_genre == DG_DEBRIS) {
if (k > 0) {
break;
}
} else {
// ASTEROID DEBRIS - use subtype (Asteroid_field.field_debris_type[] != -1)
if (Asteroid_field.field_debris_type[k] == -1) {
// ASTEROID FIELDS - use subtype k, if active
bool active = false;
for (const auto& active_type : Asteroid_field.field_asteroid_type) {
if (active_type == asip->subtypes[k].type_name) {
active = true;
}
}
if (!active) {
continue;
}
}
if (asip->model_num[k] < 0)
// model is already paged in
if (asip->subtypes[k].model_number < 0)
continue;
asip->modelp[k] = model_get(asip->model_num[k]);
asip->subtypes[k].model_pointer = model_get(asip->subtypes[k].model_number);
// Page in textures
for (j=0; j<asip->modelp[k]->n_textures; j++ ) {
asip->modelp[k]->maps[j].PageIn();
for (int j = 0; j < asip->subtypes[k].model_pointer->n_textures; j++ ) {
asip->subtypes[k].model_pointer->maps[j].PageIn();
}
}
+19 -20
View File
@@ -24,15 +24,14 @@ class model_draw_list;
#define MAX_ASTEROIDS 2000 //Increased from 512 to 2000 in 2022
#define NUM_ASTEROID_SIZES 3
#define NUM_ASTEROID_POFS 3 // Number of POFs per debris size
#define ASTEROID_TYPE_DEBRIS -1
#define ASTEROID_TYPE_SMALL 0
#define ASTEROID_TYPE_MEDIUM 1
#define ASTEROID_TYPE_LARGE 2
// these should always be equal for the benefit of generic asteroids (c.f. asteroid_page_in)
#define MAX_ACTIVE_DEBRIS_TYPES NUM_ASTEROID_SIZES
// Only used for parsing & saving retail compatible mission files
#define MAX_RETAIL_DEBRIS_TYPES 3
// Goober5000 - currently same as MAX_SHIP_DETAIL_LEVELS (put here to avoid an #include)
#define MAX_ASTEROID_DETAIL_LEVELS 5
@@ -54,13 +53,20 @@ typedef struct asteroid_split_info {
int max; //maximum asteroids to spawn
} asteroid_split_info;
// Data structure for storing asteroid subtype info. POFs, model pointer, model num, etc.
typedef struct asteroid_subtype_info {
char pof_filename[MAX_FILENAME_LEN];
polymodel* model_pointer;
int model_number;
SCP_string type_name;
} asteroid_subtype_info;
class asteroid_info
{
public:
char name[NAME_LENGTH]; // name for the asteroid
int type; // type of asteroid, 0 = small, 1 = medium, 2 = large, -1 = debris
char pof_files[NUM_ASTEROID_POFS][MAX_FILENAME_LEN]; // POF files to load/associate with ship
int num_detail_levels; // number of detail levels for this ship
int num_detail_levels; // number of detail levels for this asteroid
int detail_distance[MAX_ASTEROID_DETAIL_LEVELS]; // distance to change detail levels at
float max_speed; // cap on speed for asteroid
float rotational_vel_multiplier; // rotational velocity multiplier for asteroid --wookieejedi
@@ -72,13 +78,12 @@ public:
float blast; // maximum blast impulse from area effect explosion
float initial_asteroid_strength; // starting strength of asteroid
SCP_vector< asteroid_split_info > split_info;
polymodel *modelp[NUM_ASTEROID_POFS];
int model_num[NUM_ASTEROID_POFS];
SCP_vector<int> explosion_bitmap_anims;
float fireball_radius_multiplier; // the model radius is multiplied by this to determine the fireball size
SCP_string display_name; // only used for hud targeting display and for 'ship' asteroids
float spawn_weight; // ship asteroids only, relative proportion to spawn compared to other types in its asteroid field
SCP_string display_name; // only used for hud targeting display and for debris
float spawn_weight; // debris only, relative proportion to spawn compared to other types in its asteroid field
float gravity_const; // multiplier for mission gravity
SCP_vector<asteroid_subtype_info> subtypes;
asteroid_info( )
: type(ASTEROID_TYPE_DEBRIS), num_detail_levels(0), max_speed(0),
@@ -90,13 +95,6 @@ public:
name[ 0 ] = 0;
display_name = "";
memset( detail_distance, 0, sizeof( detail_distance ) );
for (int i = 0; i < NUM_ASTEROID_POFS; i++)
{
modelp[i] = NULL;
model_num[i] = -1;
pof_files[i][0] = '\0';
}
}
};
@@ -143,8 +141,8 @@ typedef struct asteroid_field {
int num_initial_asteroids; // Number of asteroids at creation.
field_type_t field_type; // active throws and wraps, passive does not
debris_genre_t debris_genre; // type of debris (ship or asteroid) [generic type]
int field_debris_type[MAX_ACTIVE_DEBRIS_TYPES]; // one of the debris type defines above
int num_used_field_debris_types; // how many of the above are used
SCP_vector<int> field_debris_type; // one of the debris type defines above
SCP_vector<SCP_string> field_asteroid_type; // one of the asteroid subtypes
bool enhanced_visibility_checks; // if true then range checks are overridden for spawning and wrapping asteroids in the field
SCP_vector<SCP_string> target_names; // default retail behavior is to just throw at the first big ship in the field
@@ -165,8 +163,8 @@ bool asteroid_is_within_view(vec3d *pos, float range, bool range_override = f
void asteroid_level_init();
void asteroid_level_close();
void asteroid_create_all();
void asteroid_create_asteroid_field(int num_asteroids, int field_type, int asteroid_speed, bool brown, bool blue, bool orange, vec3d o_min, vec3d o_max, bool inner_box, vec3d i_min, vec3d i_max, SCP_vector<SCP_string> targets);
void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, int debris1, int debris2, int debris3, vec3d o_min, vec3d o_max, bool enhanced);
void asteroid_create_asteroid_field(int num_asteroids, int field_type, int asteroid_speed, vec3d o_min, vec3d o_max, bool inner_box, vec3d i_min, vec3d i_max, SCP_vector<SCP_string> asteroid_types);
void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, SCP_vector<int> debris_types, vec3d o_min, vec3d o_max, bool enhanced);
void asteroid_render(object* obj, model_draw_list* scene);
void asteroid_delete( object *asteroid_objp );
void asteroid_process_pre( object *asteroid_objp );
@@ -180,6 +178,7 @@ void asteroid_show_brackets();
void asteroid_target_closest_danger();
void asteroid_add_target(object* objp);
int get_asteroid_index(const char* asteroid_name);
SCP_vector<SCP_string> get_list_valid_asteroid_subtypes();
// need to extern for keycontrol debug commands
object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroid_subtype, bool check_visibility = false);
-4
View File
@@ -1027,10 +1027,6 @@ int bm_is_compressed(int num) {
auto entry = bm_get_entry(num);
BM_TYPE type = BM_TYPE_NONE;
//duh
if (!Use_compressed_textures)
return 0;
type = entry->comp_type;
switch (type) {
+8 -14
View File
@@ -364,10 +364,7 @@ void camera::do_frame(float /*in_frametime*/)
object *camera::get_object_host()
{
if(object_host.isValid())
return object_host.objp;
else
return NULL;
return object_host.objp_or_null();
}
int camera::get_object_host_submodel()
@@ -377,10 +374,7 @@ int camera::get_object_host_submodel()
object *camera::get_object_target()
{
if(object_target.isValid())
return object_target.objp;
else
return NULL;
return object_target.objp_or_null();
}
int camera::get_object_target_submodel()
@@ -424,7 +418,7 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
if(object_host.isValid())
{
object *objp = object_host.objp;
object *objp = object_host.objp();
int model_num = object_get_model(objp);
polymodel *pm = nullptr;
polymodel_instance *pmi = nullptr;
@@ -438,8 +432,8 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
if(object_host_submodel < 0 || pm == NULL)
{
vm_vec_unrotate(&c_pos, &pt, &object_host.objp->orient);
vm_vec_add2(&c_pos, &object_host.objp->pos);
vm_vec_unrotate(&c_pos, &pt, &object_host.objp()->orient);
vm_vec_add2(&c_pos, &object_host.objp()->pos);
}
else
{
@@ -488,7 +482,7 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
{
if(object_target.isValid())
{
object *target_objp = object_target.objp;
object *target_objp = object_target.objp();
int model_num = object_get_model(target_objp);
polymodel *target_pm = nullptr;
polymodel_instance *target_pmi = nullptr;
@@ -525,7 +519,7 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
{
if(eyep)
{
vm_vector_2_matrix(&c_ori, &host_normal, vm_vec_same(&host_normal, &object_host.objp->orient.vec.uvec)?NULL:&object_host.objp->orient.vec.uvec, NULL);
vm_vector_2_matrix(&c_ori, &host_normal, vm_vec_same(&host_normal, &object_host.objp()->orient.vec.uvec)?NULL:&object_host.objp()->orient.vec.uvec, NULL);
target_set = true;
}
else if (use_host_orient)
@@ -534,7 +528,7 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
}
else
{
c_ori = object_host.objp->orient;
c_ori = object_host.objp()->orient;
}
}
else
+1
View File
@@ -377,6 +377,7 @@ struct CFileLocation {
SCP_string full_name;
size_t size = 0;
size_t offset = 0;
time_t m_time = 0;
const void* data_ptr = nullptr;
explicit CFileLocation(bool found_in = false) : found(found_in) {}
+24 -2
View File
@@ -595,7 +595,7 @@ static void cf_add_mod_roots(const char* rootDirectory, uint32_t basic_location)
cf_root* root = cf_create_root();
root->path = rootPath;
root->path = std::move(rootPath);
if (primary) {
root->location_flags = basic_location | CF_LOCATION_TYPE_PRIMARY_MOD;
} else {
@@ -826,7 +826,8 @@ static void check_file_shadows(const int root_index __UNUSED, const int pathtype
}
// this log message occurs in the middle of an existing line, hence the extra new lines
mprintf(("\nWARNING! A %sfile being indexed may be shadowed by an existing file!\n New:\n %s\n Existing:\n %s\n",
// critical files and files in same root are always logged, files in different root are behind a filter
nprintf(((critical || !root->path.compare(r->path)) ? "General" : "CFileSystem", "\nWARNING! A %sfile being indexed may be shadowed by an existing file!\n New:\n %s\n Existing:\n %s\n",
critical ? "critical " : "",
newfile.c_str(), curfile.c_str()));
@@ -1236,6 +1237,22 @@ static bool sub_path_match(const SCP_string &search, const SCP_string &index)
return !stricmp(search.c_str(), index.c_str());
}
static time_t get_mtime(int fd)
{
#ifdef _WIN32
struct _stat buf;
#define fstat _fstat
#else
struct stat buf;
#endif
if (fstat(fd, &buf) != 0) {
return 0;
}
return buf.st_mtime;
}
/**
* Searches for a file.
*
@@ -1270,6 +1287,7 @@ CFileLocation cf_find_file_location(const char* filespec, int pathtype, uint32_t
if (fp) {
CFileLocation res(true);
res.size = static_cast<size_t>(filelength(fileno(fp)));
res.m_time = get_mtime(fileno(fp));
fclose(fp);
@@ -1332,6 +1350,7 @@ CFileLocation cf_find_file_location(const char* filespec, int pathtype, uint32_t
if (fp) {
CFileLocation res(true);
res.size = static_cast<size_t>(filelength( fileno(fp) ));
res.m_time = get_mtime(fileno(fp));
fclose(fp);
@@ -1388,6 +1407,7 @@ CFileLocation cf_find_file_location(const char* filespec, int pathtype, uint32_t
res.offset = (size_t)f->pack_offset;
res.data_ptr = f->data;
res.name_ext = f->name_ext;
res.m_time = f->write_time;
if (f->data != nullptr) {
// This is an in-memory file so we just copy the pathtype name + file name
@@ -1523,6 +1543,7 @@ CFileLocationExt cf_find_file_location_ext(const char *filename, const int ext_n
CFileLocationExt res(cur_ext);
res.found = true;
res.size = static_cast<size_t>(filelength( fileno(fp) ));
res.m_time = get_mtime(fileno(fp));
fclose(fp);
@@ -1611,6 +1632,7 @@ CFileLocationExt cf_find_file_location_ext(const char *filename, const int ext_n
res.offset = (size_t)f->pack_offset;
res.data_ptr = f->data;
res.name_ext = f->name_ext;
res.m_time = f->write_time;
if (f->data != nullptr) {
// This is an in-memory file so we just copy the pathtype name + file name
+23 -50
View File
@@ -165,11 +165,9 @@ Flag exe_params[] =
{ "-nonormal", "Disable normal maps", true, EASY_DEFAULT | EASY_HI_MEM_OFF, EASY_ALL_ON | EASY_HI_MEM_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nonormal" },
{ "-emissive_light", "Enable emissive light from ships", true, 0, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-emissive_light" },
{ "-noheight", "Disable height/parallax maps", true, EASY_DEFAULT | EASY_HI_MEM_OFF, EASY_ALL_ON | EASY_HI_MEM_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noheight" },
{ "-3dshockwave", "Enable 3D shockwaves", true, EASY_ALL_ON | EASY_HI_MEM_ON, EASY_DEFAULT | EASY_HI_MEM_OFF, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-3dshockwave" },
{ "-no_post_process", "Disable post-processing", true, EASY_DEFAULT | EASY_HI_MEM_OFF, EASY_ALL_ON | EASY_HI_MEM_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_post_process" },
{ "-soft_particles", "Enable soft particles", true, EASY_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-soft_particles" },
{ "-aa", "Enable Post-process anti-aliasing", true, EASY_ALL_ON | EASY_HI_MEM_ON, EASY_DEFAULT | EASY_HI_MEM_OFF, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-aa" },
{ "-nolightshafts", "Disable lightshafts", true, EASY_DEFAULT | EASY_HI_MEM_OFF, EASY_ALL_ON | EASY_HI_MEM_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nolightshafts"},
{ "-fb_explosions", "Enable Framebuffer Shockwaves", true, EASY_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fb_explosions", },
{ "-fb_thrusters", "Enable Framebuffer Thrusters", true, EASY_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fb_thrusters", },
{ "-no_deferred", "Disable Deferred Lighting", true, EASY_DEFAULT | EASY_HI_MEM_OFF, EASY_ALL_ON | EASY_HI_MEM_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_deferred"},
@@ -193,13 +191,10 @@ Flag exe_params[] =
{ "-capture_mouse", "Capture the mouse within the window", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-capture_mouse", },
{ "-stretch_menu", "Stretch interface to fill screen", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-stretch_menu", },
{ "-noscalevid", "Disable scale-to-window for movies", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noscalevid", },
{ "-nomotiondebris", "Disable motion debris", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nomotiondebris",},
{ "-3dwarp", "Enable 3D warp", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-3dwarp", },
{ "-warp_flash", "Enable flash upon warp", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-warp_flash", },
{ "-no_ap_interrupt", "Disable interrupting autopilot", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_ap_interrupt", },
{ "-no_screenshake", "Disable screen shaking", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_screenshake", },
{ "-vr", "Enable Virtual Reality Mode", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-vr", },
{ "-no_unfocused_pause","Don't pause if the window isn't focused", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_unfocused_pause", },
{ "-orig_speedx_range", "Restrict speedup/slowdown (1x to 4x)", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-orig_speedx_range", },
//flag launcher text FSO on_flags off_flags category reference URL
{ "-nosound", "Disable all sound", false, 0, EASY_DEFAULT, "Audio", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nosound", },
@@ -242,6 +237,8 @@ Flag exe_params[] =
{ "-prefer_ipv6", "Prefer IPv6 DNS lookups", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-prefer_ipv6", },
{ "-log_multi_packet", "Log multi packet types ", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-log_multi_packet",},
{ "-no_bsp_align", "Disable pof BSP data alignment", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_bsp_align", },
{ "-no_large_shaders", "Split large shader into smaller shaders", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_large_shaders", },
#ifdef WIN32
{ "-fix_registry", "Use a different registry path", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fix_registry", },
#endif
@@ -342,15 +339,12 @@ cmdline_parm emissive_power_arg("-emissive", "Multiplies the brightness of all a
cmdline_parm emissive_arg("-emissive_light", "Enable emissive light from ships", AT_NONE); // semi-deprecated but still functional
cmdline_parm env("-noenv", NULL, AT_NONE); // Cmdline_env
cmdline_parm glow_arg("-noglow", NULL, AT_NONE); // Cmdline_glow -- use Bobs glow code
cmdline_parm nomotiondebris_arg("-nomotiondebris", NULL, AT_NONE); // Cmdline_nomotiondebris -- Removes those ugly floating rocks -C
cmdline_parm noscalevid_arg("-noscalevid", NULL, AT_NONE); // Cmdline_noscalevid -- disable video scaling that fits to window
cmdline_parm spec_arg("-nospec", NULL, AT_NONE); // Cmdline_spec --
cmdline_parm normal_arg("-nonormal", NULL, AT_NONE); // Cmdline_normal -- disable normal mapping
cmdline_parm height_arg("-noheight", NULL, AT_NONE); // Cmdline_height -- enable support for parallax mapping
cmdline_parm enable_3d_shockwave_arg("-3dshockwave", NULL, AT_NONE);
cmdline_parm softparticles_arg("-soft_particles", NULL, AT_NONE);
cmdline_parm no_postprocess_arg("-no_post_process", "Disables post-processing", AT_NONE);
cmdline_parm bloom_intensity_arg("-bloom_intensity", "Set bloom intensity, requires post-processing", AT_INT);
cmdline_parm post_process_aa_arg("-aa", "Enables post-process antialiasing", AT_NONE);
cmdline_parm post_process_aa_preset_arg("-aa_preset", "Sets the AA effect to use. See the wiki for details", AT_INT);
cmdline_parm deprecated_fxaa_arg("-fxaa", nullptr, AT_NONE);
@@ -360,7 +354,6 @@ cmdline_parm deprecated_smaa_preset_arg("-smaa_preset", "SMAA quality (0-3), req
cmdline_parm msaa_enabled_arg("-msaa", nullptr, AT_INT);
cmdline_parm fb_explosions_arg("-fb_explosions", NULL, AT_NONE);
cmdline_parm fb_thrusters_arg("-fb_thrusters", NULL, AT_NONE);
cmdline_parm flightshaftsoff_arg("-nolightshafts", NULL, AT_NONE);
cmdline_parm shadow_quality_arg("-shadow_quality", NULL, AT_INT);
cmdline_parm enable_shadows_arg("-enable_shadows", NULL, AT_NONE);
cmdline_parm no_deferred_lighting_arg("-no_deferred", NULL, AT_NONE); // Cmdline_no_deferred
@@ -378,10 +371,7 @@ int Cmdline_spec = 1;
int Cmdline_emissive = 0;
int Cmdline_normal = 1;
int Cmdline_height = 1;
int Cmdline_enable_3d_shockwave = 0;
int Cmdline_softparticles = 0;
int Cmdline_bloom_intensity = 25;
bool Cmdline_force_lightshaft_off = false;
int Cmdline_no_deferred_lighting = 0;
bool Cmdline_deferred_lighting_cockpit = false;
int Cmdline_aniso_level = 0;
@@ -407,22 +397,16 @@ int Cmdline_orb_radar = 0;
int Cmdline_rearm_timer = 0;
// Gameplay related
cmdline_parm use_3dwarp("-3dwarp", nullptr, AT_NONE); // Is now Fireball_use_3d_warp
cmdline_parm use_warp_flash("-warp_flash", nullptr, AT_NONE); // Cmdline_warp_flash
cmdline_parm allow_autpilot_interrupt("-no_ap_interrupt", nullptr, AT_NONE);
cmdline_parm stretch_menu("-stretch_menu", nullptr, AT_NONE); // Cmdline_stretch_menu
cmdline_parm capture_mouse("-capture_mouse", nullptr, AT_NONE); // Cmdline_capture_mouse
cmdline_parm no_screenshake("-no_screenshake", nullptr, AT_NONE); // Cmdline_no_screenshake
cmdline_parm vr("-vr", nullptr, AT_NONE);
cmdline_parm deadzone("-deadzone",
"Sets the joystick deadzone. Integer value from 0 to 100 as a percentage of the joystick's range (100% would make the stick do nothing). Disables deadzone slider in the in-game Options menu.", AT_INT); //Cmdline_deadzone
int Cmdline_ship_choice_3d = 0;
int Cmdline_weapon_choice_3d = 0;
int Cmdline_autopilot_interruptable = 1;
int Cmdline_stretch_menu = 0;
bool Cmdline_capture_mouse = false;
int Cmdline_no_screenshake = 0;
int Cmdline_deadzone = -1;
bool Cmdline_enable_vr = false;
@@ -479,6 +463,7 @@ cmdline_parm prefer_ipv4_arg("-prefer_ipv4", nullptr, AT_NONE);
cmdline_parm prefer_ipv6_arg("-prefer_ipv6", nullptr, AT_NONE);
cmdline_parm log_multi_packet_arg("-log_multi_packet", nullptr, AT_NONE);
cmdline_parm no_bsp_align_arg("-no_bsp_align", nullptr, AT_NONE);
cmdline_parm no_large_shaders("-no_large_shaders", NULL, AT_NONE);
#ifdef WIN32
cmdline_parm fix_registry("-fix_registry", NULL, AT_NONE);
#endif
@@ -502,6 +487,7 @@ bool Cmdline_prefer_ipv4 = false;
bool Cmdline_prefer_ipv6 = false;
bool Cmdline_dump_packet_type = false;
bool Cmdline_no_bsp_align = false;
bool Cmdline_no_large_shaders = false;
#ifdef WIN32
bool Cmdline_alternate_registry_path = false;
#endif
@@ -530,6 +516,7 @@ cmdline_parm parse_cmdline_only(PARSE_COMMAND_LINE_STRING, "Ignore any cmdline_f
cmdline_parm reparse_mainhall_arg("-reparse_mainhall", NULL, AT_NONE); //Cmdline_reparse_mainhall
cmdline_parm frame_profile_write_file("-profile_write_file", NULL, AT_NONE); // Cmdline_profile_write_file
cmdline_parm no_unfocused_pause_arg("-no_unfocused_pause", NULL, AT_NONE); //Cmdline_no_unfocus_pause
cmdline_parm retail_time_compression_range_arg("-orig_speedx_range", NULL, AT_NONE); //Cmdline_retail_time_compression_range
cmdline_parm benchmark_mode_arg("-benchmark_mode", NULL, AT_NONE); //Cmdline_benchmark_mode
cmdline_parm pilot_arg("-pilot", nullptr, AT_STRING); //Cmdline_pilot
cmdline_parm noninteractive_arg("-noninteractive", NULL, AT_NONE); //Cmdline_noninteractive
@@ -568,6 +555,7 @@ int Cmdline_verify_vps = 0;
int Cmdline_reparse_mainhall = 0;
bool Cmdline_profile_write_file = false;
bool Cmdline_no_unfocus_pause = false;
bool Cmdline_retail_time_compression_range = false;
bool Cmdline_benchmark_mode = false;
const char *Cmdline_pilot = nullptr;
bool Cmdline_noninteractive = false;
@@ -610,6 +598,13 @@ cmdline_parm deprecated_spec_tube_arg("-spec_tube", "Deprecated", AT_NONE);
cmdline_parm deprecated_ambient_factor_arg("-ambient_factor", "Deprecated", AT_NONE); //
cmdline_parm deprecated_ship_choice_3d_arg("-ship_choice_3d", "Deprecated", AT_NONE);
cmdline_parm deprecated_weapon_choice_3d_arg("-weapon_choice_3d", "Deprecated", AT_NONE);
cmdline_parm deprecated_no_screenshake("-no_screenshake", "Deprecated", AT_NONE);
cmdline_parm deprecated_bloom_intensity_arg("-bloom_intensity", "Deprecated", AT_INT);
cmdline_parm deprecated_nomotiondebris_arg("-nomotiondebris", "Deprecated", AT_NONE);
cmdline_parm deprecated_flightshaftsoff_arg("-nolightshafts", "Deprecated", AT_NONE);
cmdline_parm deprecated_use_warp_flash("-warp_flash", "Deprecated", AT_NONE);
cmdline_parm deprecated_use_3dwarp("-3dwarp", "Deprecated", AT_NONE);
cmdline_parm deprecated_enable_3d_shockwave_arg("-3dshockwave", "Deprecated", AT_NONE);
#ifndef NDEBUG
// NOTE: this assumes that os_init() has already been called but isn't a fatal error if it hasn't
@@ -1883,10 +1878,6 @@ bool SetCmdlineParams()
Cmdline_show_pos = 1;
}
if ( nomotiondebris_arg.found() ) {
Motion_debris_enabled = false;
}
if( mipmap_arg.found() ) {
Cmdline_mipmap = 1;
}
@@ -1927,21 +1918,9 @@ bool SetCmdlineParams()
Cmdline_orb_radar = 1;
}
if ( use_3dwarp.found() ) {
Fireball_use_3d_warp = true;
}
if ( use_warp_flash.found() ) {
Fireball_warp_flash = true;
}
if ( allow_autpilot_interrupt.found() ) {
Cmdline_autopilot_interruptable = 0;
}
if ( no_screenshake.found() ) {
Cmdline_no_screenshake = 1;
}
if ( deadzone.found() ) {
Cmdline_deadzone = deadzone.get_int();
@@ -2115,6 +2094,10 @@ bool SetCmdlineParams()
if (no_bsp_align_arg.found()) {
Cmdline_no_bsp_align = true;
}
if (no_large_shaders.found()) {
Cmdline_no_large_shaders = true;
}
#ifdef WIN32
if (fix_registry.found()) {
@@ -2157,11 +2140,6 @@ bool SetCmdlineParams()
Cmdline_ati_color_swap = 1;
}
if ( enable_3d_shockwave_arg.found() )
{
Cmdline_enable_3d_shockwave = 1;
}
if ( softparticles_arg.found() )
{
Cmdline_softparticles = 1;
@@ -2182,16 +2160,6 @@ bool SetCmdlineParams()
Gr_post_processing_enabled = false;
}
if ( bloom_intensity_arg.found() )
{
Cmdline_bloom_intensity = bloom_intensity_arg.get_int();
}
if ( flightshaftsoff_arg.found() )
{
Cmdline_force_lightshaft_off = true;
}
if( reparse_mainhall_arg.found() )
{
Cmdline_reparse_mainhall = 1;
@@ -2257,6 +2225,11 @@ bool SetCmdlineParams()
{
Cmdline_no_unfocus_pause = true;
}
if (retail_time_compression_range_arg.found())
{
Cmdline_retail_time_compression_range = true;
}
if (benchmark_mode_arg.found())
{
+2 -6
View File
@@ -63,10 +63,7 @@ extern int Cmdline_noscalevid; // disables fit-to-window for movies - taylor
extern int Cmdline_spec;
extern int Cmdline_normal;
extern int Cmdline_height;
extern int Cmdline_enable_3d_shockwave;
extern int Cmdline_softparticles;
extern int Cmdline_bloom_intensity;
extern bool Cmdline_force_lightshaft_off;
extern int Cmdline_no_deferred_lighting;
extern bool Cmdline_deferred_lighting_cockpit;
extern int Cmdline_emissive;
@@ -84,12 +81,9 @@ extern int Cmdline_orb_radar;
extern int Cmdline_rearm_timer;
// Gameplay related
extern int Cmdline_ship_choice_3d;
extern int Cmdline_weapon_choice_3d;
extern int Cmdline_autopilot_interruptable;
extern int Cmdline_stretch_menu;
extern bool Cmdline_capture_mouse;
extern int Cmdline_no_screenshake;
extern int Cmdline_deadzone;
extern bool Cmdline_enable_vr;
@@ -130,6 +124,7 @@ extern bool Cmdline_noshadercache;
extern bool Cmdline_prefer_ipv4;
extern bool Cmdline_prefer_ipv6;
extern bool Cmdline_dump_packet_type;
extern bool Cmdline_no_large_shaders;
#ifdef WIN32
extern bool Cmdline_alternate_registry_path;
#endif
@@ -149,6 +144,7 @@ extern int Cmdline_verify_vps;
extern int Cmdline_reparse_mainhall;
extern bool Cmdline_profile_write_file;
extern bool Cmdline_no_unfocus_pause;
extern bool Cmdline_retail_time_compression_range;
extern bool Cmdline_benchmark_mode;
extern const char *Cmdline_pilot;
extern bool Cmdline_noninteractive;
+18 -6
View File
@@ -141,6 +141,9 @@ SCP_vector<cc_line> Cc_lines;
// Backups for use when user closes the config menu without saving
SCP_vector<CCI> Control_config_backup;
// The current preset that the user is working on and will likely want to save to
static SCP_string Current_preset_name;
// Undo system
Undo_system Undo_controls;
@@ -1291,11 +1294,12 @@ bool control_config_accept(bool API_Access)
char* cstr; // Must be a char *, because popup_input may return nullptr and std::string don't like it
retry:;
SCP_string default_string = (Current_preset_name.empty()) ? Player->callsign : Current_preset_name;
cstr = popup_input(flags,
"Confirm new custom preset name.\n\nThe name must not be empty.\n\n Press [Enter] to accept, [Esc] to "
"abort to config menu.",
32 - 6,
Player->callsign);
default_string.c_str());
if (cstr == nullptr) {
// Abort
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
@@ -1354,6 +1358,9 @@ bool control_config_accept(bool API_Access)
// consistant ordering
Control_config_presets.resize(1);
load_preset_files();
// finally, save the new preset so that changes will get saved to this preset
Current_preset_name = preset.name;
} else {
return false;
}
@@ -1537,9 +1544,11 @@ void control_config_init(bool API_Access)
// Init preset cycling system
auto preset_it = control_config_get_current_preset();
if (preset_it == Control_config_presets.end()) {
Current_preset_name.clear();
Defaults_cycle_pos = 0;
} else {
Current_preset_name = preset_it->name;
Defaults_cycle_pos = static_cast<unsigned int>(std::distance(Control_config_presets.begin(), preset_it));
}
@@ -1651,6 +1660,9 @@ void control_config_close(bool API_Access)
Cc_lines.clear();
Conflicts.clear();
Undo_controls.clear();
// Clear this, just to be tidy
Current_preset_name.clear();
}
SCP_vector<CC_preset>::iterator control_config_get_current_preset(bool invert_agnostic) {
@@ -1896,7 +1908,7 @@ int control_config_draw_list(int select_tease_line) {
char buf[256]; // c_str buffer
int font_height = gr_get_font_height();
for (line = Scroll_offset; cc_line_query_visible(line); ++line) {
for (line = Scroll_offset; cc_line_query_visible(line) && (line - Scroll_offset < LIST_BUTTONS_MAX); ++line) {
z = Cc_lines[line].cc_index;
// screen coordinate y = list box origin y + (this item's relative y - topmost item's relative y)
@@ -2091,7 +2103,7 @@ int control_config_bind_key_on_frame(int ctrl, selItem item, bool API_Access)
}
if ((ctrl == BANK_WHEN_PRESSED || ctrl == GLIDE_WHEN_PRESSED) && (Last_key >= 0) && (k <= 0) &&
!keyd_pressed[Last_key]) {
!key_is_pressed(Last_key)) {
// If the selected cc_item is BANK_WHEN_PRESSED or GLIDE_WHEN_PRESSED, and
// If the polled key is a modifier, and
// k was consumed, and
@@ -2820,12 +2832,12 @@ int check_control_used(int id, int key)
// check what current modifiers are pressed
mask = 0;
if (keyd_pressed[KEY_LSHIFT] || key_down_count(KEY_LSHIFT) || keyd_pressed[KEY_RSHIFT] || key_down_count(KEY_RSHIFT)) {
if (key_is_pressed(KEY_LSHIFT, true) || key_is_pressed(KEY_RSHIFT, true)) {
// Any shift key is pressed, add KEY_SHIFTED mask
mask |= KEY_SHIFTED;
}
if (keyd_pressed[KEY_LALT] || key_down_count(KEY_LALT) || keyd_pressed[KEY_RALT] || key_down_count(KEY_RALT)) {
if (key_is_pressed(KEY_LALT, true) || key_is_pressed(KEY_RALT, true)) {
// Any alt key is pressed, add KEY_ALTED to the mask
mask |= KEY_ALTED;
}
@@ -2841,7 +2853,7 @@ int check_control_used(int id, int key)
z &= KEY_MASK;
if (keyd_pressed[z] || key_down_count(z)) {
if (key_is_pressed(z, true)) {
// Key combo is pressed, control activated
control_used(id);
return 1;
@@ -2784,10 +2784,12 @@ bool CCB::operator!=(const CCB& A) const {
}
bool CCB::has_first_conflict(const CCB& A) const {
// coverity[copy_paste_error:FALSE]
return !first.empty() && (first.conflicts_with(A.first) || first.conflicts_with(A.second));
}
bool CCB::has_second_conflict(const CCB& A) const {
// coverity[copy_paste_error:FALSE]
return !second.empty() && (second.conflicts_with(A.first) || second.conflicts_with(A.second));
}
+1 -1
View File
@@ -6,7 +6,7 @@ namespace {
const int OUT_CH_LAYOUT = AV_CH_LAYOUT_STEREO;
const int OUT_SAMPLE_RATE = 48000;
const AVSampleFormat OUT_SAMPLE_FORMAT = AV_SAMPLE_FMT_S16;
const int OUT_NUM_CHANNELS = av_get_channel_layout_nb_channels(OUT_CH_LAYOUT);
const int OUT_NUM_CHANNELS = av_popcount64(OUT_CH_LAYOUT);
const int DEFAULT_SRC_NUM_SAMPLES = 1024;
+5 -1
View File
@@ -69,7 +69,11 @@ CodecContextParameters getCodecParameters(AVStream* stream) {
paras.height = stream->codecpar->height;
paras.pixel_format = (AVPixelFormat)stream->codecpar->format;
paras.channel_layout = stream->codecpar->channel_layout;
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(59, 36, 255)
paras.channel_layout = stream->codecpar->ch_layout.u.mask;
#else
paras.channel_layout = stream->codecpar->channel_layout;
#endif
paras.sample_rate = stream->codecpar->sample_rate;
paras.audio_format = (AVSampleFormat)stream->codecpar->format;
+1 -1
View File
@@ -122,7 +122,7 @@ void SubtitleDecoder::pushSubtitleFrame(AVPacket* packet, AVSubtitle* subtitle)
}
SubtitleFramePtr frame(new SubtitleFrame());
frame->text = processed_text;
frame->text = std::move(processed_text);
frame->displayStartTime = start_time;
frame->displayEndTime = end_time;
+15 -1
View File
@@ -45,6 +45,7 @@ struct PlaybackState {
vec2d posBottomRight;
int subtitle_font = -1;
color subtitle_color = Color_bright_white;
};
void processEvents()
@@ -102,7 +103,7 @@ void displayVideo(Player* player, PlaybackState* state) {
auto subtitle = player->getCurrentSubtitle();
if (!subtitle.empty() && state->subtitle_font >= 0) {
gr_set_color_fast(&Color_bright_white);
gr_set_color_fast(&state->subtitle_color);
font::set_font(state->subtitle_font);
int width;
@@ -179,7 +180,20 @@ void initialize_player_state(Player* player, PlaybackState* state) {
if (state->subtitle_font < 0) {
Warning(LOCATION, "Failed to load subtitle font '%s'! Subtitles will be disabled.", Movie_subtitle_font.c_str());
}
if ((Movie_subtitle_rgba[0] >= 0 && Movie_subtitle_rgba[0] <= 255) &&
(Movie_subtitle_rgba[1] >= 0 && Movie_subtitle_rgba[1] <= 255) &&
(Movie_subtitle_rgba[2] >= 0 && Movie_subtitle_rgba[2] <= 255) &&
(Movie_subtitle_rgba[3] >= 0 && Movie_subtitle_rgba[3] <= 255))
{
gr_init_alphacolor(&state->subtitle_color,
Movie_subtitle_rgba[0],
Movie_subtitle_rgba[1],
Movie_subtitle_rgba[2],
Movie_subtitle_rgba[3]);
}
}
else if (font::FontManager::numberOfFonts() > 0) {
state->subtitle_font = 0; // if not explicitly specified, default to the first available font
File diff suppressed because it is too large. Load diff
+332 -177
View File
@@ -3,6 +3,17 @@
#include "cfile/cfile.h"
#include "osapi/osregistry.h"
#ifdef WITH_OPENGL
#include <glad/glad.h>
#else
static constexpr int GLAD_GL_EXT_texture_compression_s3tc = 0;
static constexpr int GLAD_GL_ARB_texture_compression_bptc = 0;
#endif
#define BCDEC_IMPLEMENTATION 1
PUSH_SUPPRESS_WARNINGS
#include "ddsutils/bcdec.h"
POP_SUPPRESS_WARNINGS
/* Currently supported formats:
* DXT1a (compressed)
@@ -12,12 +23,9 @@
* uncompressed 1555 (16-bit, 1-bit being alpha)
* uncompressed 8888 (32-bit)
* uncompressed 888 (24-bit, no alpha)
* paletted 8-bit (256 colors)
* uncompressed R8 (8-bit, Red channel as luminance)
*/
int Texture_compression_available = 0;
int Use_compressed_textures = 0;
// power of two check, to verify that a given DDS will always be usable since
// some may not be power-of-2
@@ -26,39 +34,219 @@ static inline int is_power_of_two(int w, int h)
return ( (w && !(w & (w-1))) && (h && !(h & (h-1))) );
}
// This function is used to verify that the file format specified in the DX10 Header
// is supported by the OpenGL extensions
bool dds_read_dx10_header(CFILE* dds_file, DDS_HEADER_DXT10* header)
static bool valid_dx10_format(const DDS_HEADER_DXT10 &header)
{
header->dxgiFormat = static_cast<DXGI_FORMAT>(cfread_uint(dds_file));
header->resourceDimension = static_cast<D3D10_RESOURCE_DIMENSION>(cfread_uint(dds_file));
header->miscFlag = cfread_uint(dds_file);
header->arraySize = cfread_uint(dds_file);
header->miscFlags2 = cfread_uint(dds_file);
switch (header.dxgiFormat) {
case DXGI_FORMAT::DXGI_FORMAT_BC7_TYPELESS:
case DXGI_FORMAT::DXGI_FORMAT_BC7_UNORM:
case DXGI_FORMAT::DXGI_FORMAT_BC7_UNORM_SRGB:
return true;
switch (header->dxgiFormat) {
case DXGI_FORMAT::DXGI_FORMAT_BC7_TYPELESS:
case DXGI_FORMAT::DXGI_FORMAT_BC7_UNORM:
case DXGI_FORMAT::DXGI_FORMAT_BC7_UNORM_SRGB:
return true;
default:
return false;
default:
return false;
}
}
int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *height, int *bpp, int *compression_type, int *levels, size_t *size, ubyte *palette)
static bool conversion_needed(const DDS_HEADER &dds_header)
{
if ((dds_header.ddspf.dwFlags & DDPF_FOURCC) != DDPF_FOURCC) {
return false;
}
switch (dds_header.ddspf.dwFourCC) {
case FOURCC_DXT1:
case FOURCC_DXT3:
case FOURCC_DXT5:
return !GLAD_GL_EXT_texture_compression_s3tc;
case FOURCC_DX10:
// anything other than BC7 will end up invalid
return !GLAD_GL_ARB_texture_compression_bptc;
default:
break;
}
// anything not specifically listed should end up invalid
return false;
}
// Memory usage for uncompressed textures is quite high. Some MVP assets can
// require well over a GB of VRAM for a single ship after conversion. To help
// alleviate this we need to resize those textures where possible. At 1024x1024
// the memory requirement is reduced to about 36 MB per ship with a full set
// of textures.
//
// NOTE: modifies header!!
//
// returns: number of mipmap levels to skip
static uint conversion_resize(DDS_HEADER &dds_header)
{
const size_t MAX_SIZE = 1024;
uint width, height, depth, offset = 0;
if (dds_header.dwMipMapCount <= 1) {
return 0;
}
width = dds_header.dwWidth;
height = dds_header.dwHeight;
depth = dds_header.dwDepth;
// drop levels until we get to an appropriate size, but make sure we have
// at least 1 mipmap level remaining at the end (in case there's not a full chain)
while (((width > MAX_SIZE) || (height > MAX_SIZE)) && (offset < dds_header.dwMipMapCount-1)) {
width >>= 1;
height >>= 1;
depth >>= 1;
++offset;
}
// no change needed
if ( !offset ) {
return offset;
}
// update header with new values
dds_header.dwWidth = std::max(1U, width);
dds_header.dwHeight = std::max(1U, height);
dds_header.dwDepth = std::max(1U, depth);
return offset;
}
static int _dds_read_header(CFILE *ddsfile, DDS_HEADER &dds_header, DDS_HEADER_DXT10 *dds_header_dx10 = nullptr)
{
DDS_HEADER_DXT10 dx10_header;
// read the code
int code = cfread_int(ddsfile);
// check it
if (code != DDS_FILECODE) {
return DDS_ERROR_BAD_HEADER;
}
// read header variables
dds_header.dwSize = cfread_uint(ddsfile);
dds_header.dwFlags = cfread_uint(ddsfile);
dds_header.dwHeight = cfread_uint(ddsfile);
dds_header.dwWidth = cfread_uint(ddsfile);
dds_header.dwPitchOrLinearSize = cfread_uint(ddsfile);
dds_header.dwDepth = cfread_uint(ddsfile);
dds_header.dwMipMapCount = cfread_uint(ddsfile);
// skip over the crap we don't care about
cfseek(ddsfile, 11*4, CF_SEEK_CUR);
dds_header.ddspf.dwSize = cfread_uint(ddsfile);
dds_header.ddspf.dwFlags = cfread_uint(ddsfile);
dds_header.ddspf.dwFourCC = cfread_uint(ddsfile);
dds_header.ddspf.dwRGBBitCount = cfread_uint(ddsfile);
dds_header.ddspf.dwRBitMask = cfread_uint(ddsfile);
dds_header.ddspf.dwGBitMask = cfread_uint(ddsfile);
dds_header.ddspf.dwBBitMask = cfread_uint(ddsfile);
dds_header.ddspf.dwABitMask = cfread_uint(ddsfile);
dds_header.dwCaps = cfread_uint(ddsfile);
dds_header.dwCaps2 = cfread_uint(ddsfile);
// Unused but need them checked for later
dds_header.dwCaps3 = cfread_uint(ddsfile);
dds_header.dwCaps4 = cfread_uint(ddsfile);
dds_header.dwReserved2 = cfread_uint(ddsfile);
if (dds_header.ddspf.dwFourCC == FOURCC_DX10) {
dx10_header.dxgiFormat = static_cast<DXGI_FORMAT>(cfread_uint(ddsfile));
dx10_header.resourceDimension = static_cast<D3D10_RESOURCE_DIMENSION>(cfread_uint(ddsfile));
dx10_header.miscFlag = cfread_uint(ddsfile);
dx10_header.arraySize = cfread_uint(ddsfile);
dx10_header.miscFlags2 = cfread_uint(ddsfile);
if (dds_header_dx10) {
memcpy(dds_header_dx10, &dx10_header, sizeof(DDS_HEADER_DXT10));
}
}
// sanitize values
dds_header.dwDepth = std::max(1U, dds_header.dwDepth);
dds_header.dwMipMapCount = std::max(1U, dds_header.dwMipMapCount);
#ifndef NDEBUG
if (dds_header.dwDepth > 1) {
Assertion(dds_header.dwFlags & DDSD_DEPTH, "ERROR: Volume texture missing proper flags!!");
}
#endif
// set pitch manually (per MS docs)
dds_header.dwFlags &= ~DDSD_LINEARSIZE;
dds_header.dwFlags |= DDSD_PITCH;
if (dds_header.ddspf.dwFlags & DDPF_FOURCC) {
int block_size = (dds_header.ddspf.dwFourCC == FOURCC_DXT1) ? 8 : 16;
dds_header.dwPitchOrLinearSize = std::max(1U, (dds_header.dwWidth+3)/4) * block_size;
} else {
// this isn't technically correct, but it's only wrong for formats we don't support
dds_header.dwPitchOrLinearSize = (dds_header.dwWidth * dds_header.ddspf.dwRGBBitCount + 7) / 8;
}
return DDS_ERROR_NONE;
}
static size_t compute_dds_size(const DDS_HEADER &dds_header)
{
uint d_width, d_height, d_depth;
size_t d_size = 0;
for (uint i = 0; i < dds_header.dwMipMapCount; i++) {
d_width = std::max(1U, dds_header.dwWidth >> i);
d_height = std::max(1U, dds_header.dwHeight >> i);
d_depth = std::max(1U, dds_header.dwDepth >> i);
if (dds_header.ddspf.dwFlags & DDPF_FOURCC) {
// size of data block (4x4)
d_size += ((d_width + 3) / 4) * ((d_height + 3) / 4) * d_depth * ((dds_header.ddspf.dwFourCC == FOURCC_DXT1) ? 8 : 16);
} else {
d_size += d_width * d_height * d_depth * (dds_header.ddspf.dwRGBBitCount / 8);
}
}
// assumes valid cubemap (should be checked elsewhere)
if (dds_header.dwCaps2 & DDSCAPS2_CUBEMAP) {
// the previously computed size is just per face, mult by 6 for full size
d_size *= 6;
}
Assertion(d_size > 0, "ERROR: DDS size computed to 0!!");
return d_size;
}
static int get_bit_count(const DDS_HEADER &dds_header)
{
if (dds_header.ddspf.dwFlags & DDPF_RGB) {
return dds_header.ddspf.dwRGBBitCount;
} else if (dds_header.ddspf.dwFlags & DDPF_FOURCC) {
if (dds_header.ddspf.dwFourCC == FOURCC_DXT1) {
return 24;
} else {
return 32;
}
}
return 0;
}
int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *height, int *bpp, int *compression_type, int *levels, size_t *size)
{
DDS_HEADER dds_header;
DDS_HEADER_DXT10 dds_header_dx10;
int code = 0;
CFILE *ddsfile;
char real_name[MAX_FILENAME_LEN];
int retval = DDS_ERROR_NONE;
int ct = DDS_UNCOMPRESSED;
int bits = 0;
int i, is_cubemap = 0;
uint32_t d_width = 0, d_height = 0, d_depth = 0;
size_t d_size = 0;
int is_cubemap = 0;
if (img_cfp == NULL) {
@@ -81,113 +269,36 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
ddsfile = img_cfp;
}
// read the code
code = cfread_int(ddsfile);
retval = _dds_read_header(ddsfile, dds_header, &dds_header_dx10);
// check it
if (code != DDS_FILECODE) {
retval = DDS_ERROR_BAD_HEADER;
if (retval != DDS_ERROR_NONE) {
goto Done;
}
// read header variables
dds_header.dwSize = cfread_uint(ddsfile);
dds_header.dwFlags = cfread_uint(ddsfile);
dds_header.dwHeight = cfread_uint(ddsfile);
dds_header.dwWidth = cfread_uint(ddsfile);
dds_header.dwPitchOrLinearSize = cfread_uint(ddsfile);
dds_header.dwDepth = cfread_uint(ddsfile);
dds_header.dwMipMapCount = cfread_uint(ddsfile);
// check for valid cubemap (we require all 6 faces)
if (dds_header.dwCaps2 & DDSCAPS2_CUBEMAP) {
if ( !(dds_header.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES) ) {
retval = DDS_ERROR_CUBEMAP_FACES;
ct = DDS_DXT_INVALID;
goto Done;
}
// skip over the crap we don't care about
for (i = 0; i < 11; i++)
cfread_uint(ddsfile);
// it's a valid cubemap, probably
is_cubemap = 1;
}
dds_header.ddspf.dwSize = cfread_uint(ddsfile);
dds_header.ddspf.dwFlags = cfread_uint(ddsfile);
dds_header.ddspf.dwFourCC = cfread_uint(ddsfile);
dds_header.ddspf.dwRGBBitCount = cfread_uint(ddsfile);
dds_header.ddspf.dwRBitMask = cfread_uint(ddsfile);
dds_header.ddspf.dwGBitMask = cfread_uint(ddsfile);
dds_header.ddspf.dwBBitMask = cfread_uint(ddsfile);
dds_header.ddspf.dwABitMask = cfread_uint(ddsfile);
dds_header.dwCaps = cfread_uint(ddsfile);
dds_header.dwCaps2 = cfread_uint(ddsfile);
// Unused but need them checked for later
dds_header.dwCaps3 = cfread_uint(ddsfile);
dds_header.dwCaps4 = cfread_uint(ddsfile);
dds_header.dwReserved2 = cfread_uint(ddsfile);
// sanity
if (dds_header.dwDepth == 0)
dds_header.dwDepth = 1;
if (dds_header.dwMipMapCount < 1)
dds_header.dwMipMapCount = 1;
d_width = dds_header.dwWidth;
d_height = dds_header.dwHeight;
d_depth = dds_header.dwDepth;
// calculate the type and size of the data
// determine and verify the type of data for internal use
if (dds_header.ddspf.dwFlags & DDPF_FOURCC) {
// did I mention lately that I hate Microsoft?
// this is here to fix the situation where Microsoft doesn't follow their own docs
if ( !(dds_header.dwFlags & (DDSD_LINEARSIZE | DDSD_PITCH) ) || dds_header.dwPitchOrLinearSize <= 0 ) {
// calculate the block size, mult by 8 for DXT1, 16 for DXT3 & 5
d_size = ((dds_header.dwWidth + 3)/4) * ((dds_header.dwHeight + 3)/4) * ((dds_header.dwDepth + 3)/4) * ((dds_header.ddspf.dwFourCC == FOURCC_DXT1) ? 8 : 16);
} else {
d_size = dds_header.dwPitchOrLinearSize;
}
// if we have mipmaps then compute them into the final size too
for (i = 1; i < (int)dds_header.dwMipMapCount; i++) {
// reduce size by half for the next pass
d_width /= 2;
d_height /= 2;
if (d_width <= 0)
d_width = 1;
if (d_height <= 0)
d_height = 1;
// size of data block (4x4)
d_size += ((d_width + 3) / 4) * ((d_height + 3) / 4) * ((dds_header.ddspf.dwFourCC == FOURCC_DXT1) ? 8 : 16);
}
if ( dds_header.dwCaps2 & DDSCAPS2_CUBEMAP ) {
if ( !(dds_header.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES) ) {
retval = DDS_ERROR_CUBEMAP_FACES;
ct = DDS_DXT_INVALID;
goto Done;
}
// it's a valid cubemap, probably
is_cubemap = 1;
// the previously computed size is just per face, mult by 6 for full size
d_size *= 6;
}
Assert( d_size > 0 );
*size = d_size;
switch (dds_header.ddspf.dwFourCC) {
case FOURCC_DXT1:
bits = 24;
ct = (is_cubemap) ? DDS_CUBEMAP_DXT1 : DDS_DXT1;
break;
case FOURCC_DXT3:
bits = 32;
ct = (is_cubemap) ? DDS_CUBEMAP_DXT3 : DDS_DXT3;
break;
case FOURCC_DXT5:
bits = 32;
ct = (is_cubemap) ? DDS_CUBEMAP_DXT5 : DDS_DXT5;
break;
@@ -200,9 +311,8 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
break;
case FOURCC_DX10:
if (dds_read_dx10_header(ddsfile, &dds_header_dx10)) {
if (valid_dx10_format(dds_header_dx10)) {
// Currently only BC7 is supported
bits = 32;
ct = DDS_BC7;
} else {
retval = DDS_ERROR_UNSUPPORTED;
@@ -218,46 +328,7 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
goto Done;
break;
}
} else if ( dds_header.ddspf.dwFlags & (DDPF_RGB | DDPF_PALETTEINDEXED8) ) {
d_size += d_width * d_height * d_depth * (dds_header.ddspf.dwRGBBitCount / 8);
// calculate full data size for all mipmap levels
for (i = 1; i < (int)dds_header.dwMipMapCount; i++) {
d_width /= 2;
d_height /= 2;
d_depth /= 2;
if (d_width < 1)
d_width = 1;
if (d_height < 1)
d_height = 1;
if (d_depth < 1)
d_depth = 1;
d_size += d_width * d_height * d_depth * (dds_header.ddspf.dwRGBBitCount / 8);
}
Assert( d_size > 0 );
if ( dds_header.dwCaps2 & DDSCAPS2_CUBEMAP ) {
if ( !(dds_header.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES) ) {
retval = DDS_ERROR_CUBEMAP_FACES;
ct = DDS_DXT_INVALID;
goto Done;
}
// it's a valid cubemap, probably
is_cubemap = 1;
// the previously computed size is just per face, mult by 6 for full size
d_size *= 6;
}
*size = d_size;
bits = dds_header.ddspf.dwRGBBitCount;
} else if (dds_header.ddspf.dwFlags & DDPF_RGB) {
ct = (is_cubemap) ? DDS_CUBEMAP_UNCOMPRESSED : DDS_UNCOMPRESSED;
} else {
// it's not a readable format
@@ -265,21 +336,33 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
goto Done;
}
// maybe do conversion if format not supported
if (conversion_needed(dds_header)) {
// switch to uncompressed format and reset vars
dds_header.ddspf.dwFlags &= ~DDPF_FOURCC;
dds_header.ddspf.dwFlags |= DDPF_RGB;
dds_header.ddspf.dwRGBBitCount = 32;
// NOTE: modifies header and returns offset for mipmap count
dds_header.dwMipMapCount -= conversion_resize(dds_header);
dds_header.dwMipMapCount = std::max(1U, dds_header.dwMipMapCount);
ct = (is_cubemap) ? DDS_CUBEMAP_UNCOMPRESSED : DDS_UNCOMPRESSED;
}
// we don't support compressed, non-power-of-2 images
if ( (ct != DDS_UNCOMPRESSED) && (!is_power_of_two(dds_header.dwWidth, dds_header.dwHeight)) ) {
retval = DDS_ERROR_NON_POWER_OF_2;
goto Done;
}
// make sure that the video card can handle compressed textures before using them
if ( !Use_compressed_textures && (ct != DDS_UNCOMPRESSED) && (ct != DDS_DXT_INVALID) ) {
retval = DDS_ERROR_NO_COMPRESSION;
goto Done;
}
// stuff important info
if (size)
*size = compute_dds_size(dds_header);
if (bpp)
*bpp = bits;
*bpp = get_bit_count(dds_header);
if (compression_type)
*compression_type = ct;
@@ -293,12 +376,6 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
if (levels)
*levels = dds_header.dwMipMapCount;
if (palette && (bits == 8)) {
cfseek(ddsfile, (ct == DDS_BC7) ? DX10_OFFSET : DDS_OFFSET, CF_SEEK_SET);
cfread(palette, 1, 1024, ddsfile);
}
Done:
if (img_cfp == NULL) {
// close file and return
@@ -313,11 +390,10 @@ Done:
int dds_read_bitmap(const char *filename, ubyte *data, ubyte *bpp, int cf_type)
{
int retval;
int w,h,ct,lvl;
size_t size = 0;
int bits = 0;
CFILE *cfp;
char real_name[MAX_FILENAME_LEN];
DDS_HEADER dds_header;
// this better not happen.. ever
Assert(filename != NULL);
@@ -332,25 +408,104 @@ int dds_read_bitmap(const char *filename, ubyte *data, ubyte *bpp, int cf_type)
cfp = cfopen(real_name, "rb", CFILE_NORMAL, cf_type);
// just in case
if (cfp == NULL)
if (cfp == nullptr)
return DDS_ERROR_INVALID_FILENAME;
// read the header -- if its at this stage, it should be legal.
retval = dds_read_header(real_name, cfp, &w, &h, &bits, &ct, &lvl, &size);
retval = _dds_read_header(cfp, dds_header);
Assert(retval == DDS_ERROR_NONE);
// this really shouldn't be needed but better safe than sorry
if (retval != DDS_ERROR_NONE) {
cfclose(cfp);
return retval;
}
cfseek(cfp, (ct == DDS_BC7) ? DX10_OFFSET : DDS_OFFSET, CF_SEEK_SET);
cfseek(cfp, (dds_header.ddspf.dwFourCC == FOURCC_DX10) ? DX10_OFFSET : DDS_OFFSET, CF_SEEK_SET);
size = compute_dds_size(dds_header);
// read in the data
cfread(data, 1, (int)size, cfp);
if ( !conversion_needed(dds_header) ) {
cfread(data, 1, (int)size, cfp);
} else {
// Compression format not supported, convert to BGRA
ubyte *comp_data = (ubyte*)vm_malloc(size);
cfread(comp_data, 1, (int)size, cfp);
ubyte *src = comp_data;
ubyte *dst = data;
uint d_width, d_height, d_depth;
size_t data_offset = 0;
// NOTE: this alters the width, height, and depth values in the header,
// so we have to jump through some hoops to get the proper values
const uint mipmap_offset = conversion_resize(dds_header);
const int num_faces = (dds_header.dwCaps2 & DDSCAPS2_CUBEMAP) ? 6 : 1;
const bool has_depth = (dds_header.dwFlags & DDSD_DEPTH) == DDSD_DEPTH;
for (int f = 0; f < num_faces; ++f) {
// if we resized then skip over all of that data (altering values to match pre-resize)
for (uint x = 0; x < mipmap_offset; ++x) {
d_width = std::max(1U, dds_header.dwWidth << (mipmap_offset - x));
d_height = std::max(1U, dds_header.dwHeight << (mipmap_offset - x));
d_depth = has_depth ? std::max(1U, dds_header.dwDepth << (mipmap_offset - x)) : 1U;
src += (d_width * d_height * d_depth);
}
for (uint m = mipmap_offset; m < dds_header.dwMipMapCount; ++m) {
// width/height/depth at post-resize mipmap sizes, so compensate here
d_width = std::max(1U, dds_header.dwWidth >> (m - mipmap_offset));
d_height = std::max(1U, dds_header.dwHeight >> (m - mipmap_offset));
d_depth = std::max(1U, dds_header.dwDepth >> (m - mipmap_offset));
for (uint d = 0; d < d_depth; ++d) {
for (uint i = 0; i < d_height; i += 4) {
for (uint j = 0; j < d_width; j += 4) {
dst = data + data_offset + ((i * d_width + j) * 4);
if (dds_header.ddspf.dwFourCC == FOURCC_DX10) {
bcdec_bc7(src, dst, d_width * 4);
src += BCDEC_BC7_BLOCK_SIZE;
} else if (dds_header.ddspf.dwFourCC == FOURCC_DXT5) {
bcdec_bc3(src, dst, d_width * 4);
src += BCDEC_BC3_BLOCK_SIZE;
} else if (dds_header.ddspf.dwFourCC == FOURCC_DXT1) {
bcdec_bc1(src, dst, d_width * 4);
src += BCDEC_BC1_BLOCK_SIZE;
} else if (dds_header.ddspf.dwFourCC == FOURCC_DXT3) {
bcdec_bc2(src, dst, d_width * 4);
src += BCDEC_BC2_BLOCK_SIZE;
}
}
}
}
// we need it in bgra, XOR to the rescue
for (size_t x = data_offset; x < (data_offset + (d_width * d_height * d_depth * 4)); x += 4) {
data[x] ^= data[x+2], data[x+2] ^= data[x], data[x] ^= data[x+2];
}
// bump data offset to next layer
data_offset += (d_width * d_height * d_depth * 4);
}
}
vm_free(comp_data);
comp_data = nullptr;
// switch to uncompressed format and reset vars (needed below to get correct bit count)
dds_header.ddspf.dwFlags &= ~DDPF_FOURCC;
dds_header.ddspf.dwFlags |= DDPF_RGB;
dds_header.ddspf.dwRGBBitCount = 32;
}
if (bpp)
*bpp = (ubyte)bits;
*bpp = (ubyte)get_bit_count(dds_header);
// we look done here
cfclose(cfp);
+2 -4
View File
@@ -59,6 +59,7 @@
#define DDSD_HEIGHT 0x00000002
#define DDSD_CAPS 0x00000001
#define DDSD_MIPMAPCOUNT 0x00020000
#define DDSD_DEPTH 0x00800000
#define DDSCAPS_COMPLEX 0x00000008
#define DDSCAPS_PRIMARYSURFACE 0x00000200
@@ -278,7 +279,7 @@ typedef struct {
//reads a dds header
//returns one of the error values
//'compression_type' comes back as one of the DDS_DXTC* defines
int dds_read_header(const char *filename, CFILE *img_cfp = NULL, int *width = 0, int *height = 0, int *bpp = 0, int *compression_type = 0, int *levels = 0, size_t *size = 0, ubyte *palette = NULL);
int dds_read_header(const char *filename, CFILE *img_cfp = NULL, int *width = 0, int *height = 0, int *bpp = 0, int *compression_type = 0, int *levels = 0, size_t *size = 0);
//reads bitmap
//size of the data it stored in size
@@ -290,7 +291,4 @@ void dds_save_image(int width, int height, int bpp, int num_mipmaps, ubyte *data
//returns a string from a DDS error code
const char *dds_error_string(int code);
extern int Texture_compression_available;
extern int Use_compressed_textures;
#endif //__DDS_H
+3
View File
@@ -1197,6 +1197,9 @@ void debris_render(object * obj, model_draw_list *scene)
// render_info.set_flags(MR_NO_LIGHTING);
}
if (db->model_instance_num >= 0)
render_info.set_replacement_textures(model_get_instance(db->model_instance_num)->texture_replace);
submodel_render_queue( &render_info, scene, pm, pmi, db->submodel_num, &obj->orient, &obj->pos );
if (tbase != NULL && (swapped!=-1) && pm) {
+12 -12
View File
@@ -174,7 +174,7 @@ void parse_decals_table(const char* filename) {
SCP_string name;
stuff_string(name, F_NAME);
DecalDefinition def(name);
DecalDefinition def(std::move(name));
def.parse();
DecalDefinitions.push_back(std::move(def));
@@ -186,17 +186,17 @@ void parse_decals_table(const char* filename) {
return;
}
if (!gr_is_capable(CAPABILITY_DEFERRED_LIGHTING)) {
if (!gr_is_capable(gr_capability::CAPABILITY_DEFERRED_LIGHTING)) {
// We need deferred lighting
Decal_system_active = false;
mprintf(("Note: Decal system has been disabled due to lack of deferred lighting.\n"));
}
if (!gr_is_capable(CAPABILITY_NORMAL_MAP)) {
if (!gr_is_capable(gr_capability::CAPABILITY_NORMAL_MAP)) {
// We need normal mapping for the full feature range
Decal_system_active = false;
mprintf(("Note: Decal system has been disabled due to lack of normal mapping.\n"));
}
if (!gr_is_capable(CAPABILITY_SEPARATE_BLEND_FUNCTIONS)) {
if (!gr_is_capable(gr_capability::CAPABILITY_SEPARATE_BLEND_FUNCTIONS)) {
// We need separate blending functions for different color buffers
Decal_system_active = false;
mprintf(("Note: Decal system has been disabled due to lack of separate color buffer blend functions.\n"));
@@ -224,13 +224,13 @@ struct Decal {
if (!object.isValid()) {
return false;
}
if (object.objp->flags[Object::Object_Flags::Should_be_dead]) {
if (object.objp()->flags[Object::Object_Flags::Should_be_dead]) {
return false;
}
if (orig_obj_type != object.objp->type) {
if (orig_obj_type != object.objp()->type) {
mprintf(("Decal object type for object %d has changed from %s to %s. Please let m!m know about this\n",
OBJ_INDEX(object.objp), Object_type_names[orig_obj_type], Object_type_names[object.objp->type]));
object.objnum, Object_type_names[orig_obj_type], Object_type_names[object.objp()->type]));
return false;
}
@@ -241,7 +241,7 @@ struct Decal {
}
}
auto objp = object.objp;
auto objp = object.objp();
if (objp->type == OBJ_SHIP) {
auto shipp = &Ships[objp->instance];
auto model_instance = model_get_instance(shipp->model_instance_num);
@@ -339,7 +339,7 @@ void parseDecalReference(creation_info& dest_info, bool is_new_entry) {
}
if (required_string_if_new("+Radius:", is_new_entry)) {
dest_info.radius = util::parseUniformRange(0.0001f);
dest_info.radius = util::ParsedRandomFloatRange::parseRandomRange(0.0001f);
}
if (required_string_if_new("+Lifetime:", is_new_entry)) {
@@ -347,7 +347,7 @@ void parseDecalReference(creation_info& dest_info, bool is_new_entry) {
dest_info.lifetime = util::UniformFloatRange(-1.0f);
} else {
// Require at least a small lifetime so that the calculations don't have to deal with div-by-zero
dest_info.lifetime = util::parseUniformRange(0.0001f);
dest_info.lifetime = util::ParsedRandomFloatRange::parseRandomRange(0.0001f);
}
}
@@ -393,9 +393,9 @@ void initializeMission() {
}
matrix4 getDecalTransform(Decal& decal) {
Assertion(decal.object.objp->type == OBJ_SHIP, "Only ships are currently supported for decals!");
Assertion(decal.object.objp()->type == OBJ_SHIP, "Only ships are currently supported for decals!");
auto objp = decal.object.objp;
auto objp = decal.object.objp();
auto ship = &Ships[objp->instance];
auto pmi = model_get_instance(ship->model_instance_num);
auto pm = model_get(pmi->model_num);
+2 -2
View File
@@ -65,10 +65,10 @@ typedef int DecalReference;
*/
struct creation_info {
DecalReference definition_handle = -1;
util::UniformFloatRange radius = ::util::UniformFloatRange(-1.0f);
util::ParsedRandomFloatRange radius = ::util::UniformFloatRange(-1.0f);
float width = -1.0f;
float height = -1.0f;
util::UniformFloatRange lifetime = ::util::UniformFloatRange(-1.0f);
util::ParsedRandomFloatRange lifetime = ::util::UniformFloatRange(-1.0f);
bool random_rotation = false;
};
+102 -73
View File
@@ -2,8 +2,9 @@
#include "shadows.sdr" //! #include "shadows.sdr"
#include "lighting.sdr" //! #include "lighting.sdr"
#include "gamma.sdr" //! #include "gamma.sdr"
#include "model_shader_flags.h"
#conditional_include +"LARGE_SHADER" "main_large.sdr"
#conditional_include -"LARGE_SHADER" "main_small.sdr"
#define MAX_LIGHTS 8
#define LT_DIRECTIONAL 0
@@ -96,30 +97,56 @@ layout (std140) uniform modelData {
};
in VertexOutput {
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
vec3 envReflect;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
mat3 tangentMatrix;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
float fogDist;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
vec4 position;
vec3 normal;
vec4 texCoord;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
vec4 shadowUV[4];
vec4 shadowPos;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
} vertIn;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_DIFFUSE
uniform sampler2DArray sBasemap;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_DIFFUSE
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_GLOW
uniform sampler2DArray sGlowmap;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_GLOW
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SPEC
uniform sampler2DArray sSpecmap;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SPEC
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
uniform samplerCube sEnvmap;
uniform samplerCube sIrrmap;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_NORMAL
uniform sampler2DArray sNormalmap;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_NORMAL
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_AMBIENT
uniform sampler2DArray sAmbientmap;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_AMBIENT
uniform sampler2D sFramebuffer;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_MISC
uniform sampler2DArray sMiscmap;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_MISC
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
uniform sampler2DArray shadow_map;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
out vec4 fragOut0;
#ifndef FLAG_SHADOW_MAP
#ifndef MODEL_SDR_FLAG_SHADOW_MAP
out vec4 fragOut1;
out vec4 fragOut2;
out vec4 fragOut3;
@@ -185,7 +212,7 @@ vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial,
void main()
{
#ifdef FLAG_SHADOW_MAP
#ifdef MODEL_SDR_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);
@@ -205,13 +232,13 @@ void main()
vec3 unitNormal = normalize(vertIn.normal);
vec3 normal = unitNormal;
if (FLAG_ACTIVE(MODEL_SDR_FLAG_AMBIENT)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_AMBIENT
// red channel is ambient occlusion factor which only affects ambient lighting.
// green is cavity occlusion factor which only affects diffuse and specular lighting.
aoFactors = texture(sAmbientmap, vec3(texCoord, float(sAmbientmapIndex))).xy;
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_AMBIENT
if (FLAG_ACTIVE(MODEL_SDR_FLAG_NORMAL)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_NORMAL
// Normal map - convert from DXT5nm
vec2 normalSample;
normal.rg = normalSample = (texture(sNormalmap, vec3(texCoord, float(sNormalmapIndex))).ag * 2.0) - 1.0;
@@ -223,7 +250,7 @@ void main()
normal /= norm;
else
normal = unitNormal;
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_NORMAL
vec2 distort = vec2(0.0, 0.0);
@@ -231,26 +258,26 @@ void main()
distort = vec2(cos(vertIn.position.x*vertIn.position.w*0.005+anim_timer*20.0)*sin(vertIn.position.y*vertIn.position.w*0.005),sin(vertIn.position.x*vertIn.position.w*0.005+anim_timer*20.0)*cos(vertIn.position.y*vertIn.position.w*0.005))*0.03;
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_DIFFUSE)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_DIFFUSE
vec2 diffuseTexCoord = texCoord;
if (effect_num == 2) {
diffuseTexCoord = texCoord + distort*(1.0-anim_timer);
}
baseColor = texture(sBasemap, vec3(diffuseTexCoord, float(sBasemapIndex)));
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_HDR
baseColor.rgb = srgb_to_linear(baseColor.rgb);
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_HDR
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ALPHA_MULT)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_ALPHA_MULT
baseColor.a *= alphaMult;
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ALPHA_MULT
if ( blend_alpha == 0 && baseColor.a < 0.95 ) discard; // if alpha blending is not on, discard transparent pixels
// premultiply alpha if blend_alpha is 1. assume that our blend function is srcColor + (1-Alpha)*destColor.
// if blend_alpha is 2, assume blend func is additive and don't modify color
if(blend_alpha == 1) baseColor.rgb = baseColor.rgb * baseColor.a;
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DIFFUSE
// Anti-glint "trick" based on Valve's "Advanced VR Rendering" talk at GDC2015:
// http://media.steampowered.com/apps/valve/2015/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf Page 43
@@ -263,21 +290,22 @@ void main()
// Now that we have a base color and min gloss value, compute the spec color
vec4 specColor = vec4(baseColor.rgb * SPEC_FACTOR_NO_SPEC_MAP, glossData);
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SPEC)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_SPEC
specColor = texture(sSpecmap, vec3(texCoord, float(sSpecmapIndex)));
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ALPHA_MULT)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_ALPHA_MULT
specColor *= alphaMult;
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ALPHA_MULT
if(alphaGloss) glossData = specColor.a;
if(gammaSpec) {
specColor.rgb = max(specColor.rgb, vec3(0.03f)); // hardcoded minimum specular value. read John Hable's blog post titled 'Everything Is Shiny'.
fresnelFactor = 1.0;
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_HDR
specColor.rgb = srgb_to_linear(specColor.rgb);
}
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_HDR
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SPEC
baseColor.rgb *= aoFactors.y;
specColor.rgb *= aoFactors.y;
@@ -285,8 +313,8 @@ void main()
vec4 teamMask = vec4(0.0);
vec3 team_color_glow = vec3(0.0);
if (FLAG_ACTIVE(MODEL_SDR_FLAG_MISC)) {
if (FLAG_ACTIVE(MODEL_SDR_FLAG_TEAMCOLOR)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_MISC
#prereplace IF_FLAG MODEL_SDR_FLAG_TEAMCOLOR
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
@@ -296,52 +324,52 @@ void main()
vec3 team_color = base_color * teamMask.x + stripe_color * teamMask.y + color_offset;
team_color_glow = (base_color * teamMask.b) + (stripe_color * teamMask.a);
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_HDR
baseColor.rgb = linear_to_srgb(baseColor.rgb);
specColor.rgb = linear_to_srgb(specColor.rgb);
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_HDR
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));
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_HDR
baseColor.rgb = srgb_to_linear(baseColor.rgb);
specColor.rgb = srgb_to_linear(specColor.rgb);
}
}
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_HDR
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_TEAMCOLOR
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_MISC
// Lights aren't applied when we are rendering to the G-buffers since that gets handled later
if (FLAG_ACTIVE(MODEL_SDR_FLAG_DEFERRED)) {
if (FLAG_ACTIVE(MODEL_SDR_FLAG_LIGHT)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_DEFERRED
#prereplace IF_FLAG MODEL_SDR_FLAG_LIGHT
// Ambient lighting still needs to be done since that counts as an "emissive" color
vec3 lightAmbient = (emissionFactor + ambientFactor * ambientFactor) * aoFactors.x; // ambientFactor^2 due to legacy OpenGL compatibility behavior
emissiveColor.rgb += baseColor.rgb * lightAmbient;
} else {
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SPEC)) {
#prereplace ELSE_FLAG //MODEL_SDR_FLAG_LIGHT
#prereplace IF_FLAG MODEL_SDR_FLAG_SPEC
baseColor.rgb += pow(1.0 - clamp(dot(eyeDir, normal), 0.0, 1.0), 5.0 * clamp(glossData, 0.01, 1.0)) * specColor.rgb;
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SPEC
// If there is no lighting then we copy the color data so far into the
emissiveColor.rgb += baseColor.rgb;
}
} else {
if (FLAG_ACTIVE(MODEL_SDR_FLAG_LIGHT)) {
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT
#prereplace ELSE_FLAG //MODEL_SDR_FLAG_DEFERRED
#prereplace IF_FLAG MODEL_SDR_FLAG_LIGHT
float shadow = 1.0;
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SHADOWS)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_SHADOWS
shadow = getShadowValue(shadow_map, -vertIn.position.z, vertIn.shadowPos.z, vertIn.shadowUV, fardist, middist, neardist, veryneardist);
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SHADOWS
baseColor.rgb = CalculateLighting(normal, baseColor.rgb, specColor.rgb, glossData, fresnelFactor, shadow, aoFactors.x);
} else {
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SPEC)) {
#prereplace ELSE_FLAG //MODEL_SDR_FLAG_LIGHT
#prereplace IF_FLAG MODEL_SDR_FLAG_SPEC
baseColor.rgb += pow(1.0 - clamp(dot(eyeDir, normal), 0.0, 1.0), 5.0 * clamp(glossData, 0.01, 1.0)) * specColor.rgb;
}
}
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SPEC
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DEFERRED
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ENV)) {
if (FLAG_ACTIVE(MODEL_SDR_FLAG_LIGHT)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_ENV
#prereplace IF_FLAG MODEL_SDR_FLAG_LIGHT
// Bit of a hack here, pretend we're doing blinn-phong shading and use a (modified version of) the derivation from
// Plausible Blinn-Phong Reflection of Standard Cube MIP-Maps - McGuire et al.
// to determine the mip bias.
@@ -385,48 +413,48 @@ void main()
vec3 diffEnvColor = srgb_to_linear(texture(sIrrmap, vec3(envMatrix * vec4(normal, 0.0))).rgb);
vec3 diffEnvLighting = kD * baseColor.rgb * diffEnvColor * aoFactors.x;
emissiveColor.rgb += (specEnvLighting + diffEnvLighting) * baseColor.a;
}
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ENV
if (FLAG_ACTIVE(MODEL_SDR_FLAG_GLOW)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_GLOW
vec3 glowColor = texture(sGlowmap, vec3(texCoord, float(sGlowmapIndex))).rgb;
if (FLAG_ACTIVE(MODEL_SDR_FLAG_MISC)) {
if (FLAG_ACTIVE(MODEL_SDR_FLAG_TEAMCOLOR)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_MISC
#prereplace IF_FLAG MODEL_SDR_FLAG_TEAMCOLOR
float glowColorLuminance = dot(glowColor, vec3(0.299, 0.587, 0.114));
glowColor = team_glow_enabled ? mix(max(team_color_glow, vec3(0.0)), glowColor, clamp(glowColorLuminance - teamMask.b - teamMask.a, 0.0, 1.0)) : glowColor;
}
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_TEAMCOLOR
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_MISC
#prereplace IF_FLAG MODEL_SDR_FLAG_HDR
glowColor = srgb_to_linear(glowColor) * GLOW_MAP_SRGB_MULTIPLIER;
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_HDR
emissiveColor.rgb += glowColor * GLOW_MAP_INTENSITY;
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_GLOW
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ALPHA_MULT)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_ALPHA_MULT
//Since this is emissive, we need to premultiply it for intensity, and apply alpha to not replace existing emissive
emissiveColor *= alphaMult;
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ALPHA_MULT
if (FLAG_ACTIVE(MODEL_SDR_FLAG_FOG)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_FOG
vec3 finalFogColor = fogColor.rgb;
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_HDR
finalFogColor = srgb_to_linear(finalFogColor);
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_DIFFUSE)) {
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_HDR
#prereplace IF_FLAG MODEL_SDR_FLAG_DIFFUSE
if(blend_alpha == 1) finalFogColor *= baseColor.a;
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DIFFUSE
// This code will only be used by the forward renderer so we apply the fog effect to both the emissive and the base
// color.
baseColor.rgb = mix(emissiveColor.rgb + baseColor.rgb, finalFogColor, vertIn.fogDist);
emissiveColor.rgb = vec3(0.0); // Zero the emissive color since it has already been added by the previous line
specColor.rgb *= vertIn.fogDist;
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_FOG
if (FLAG_ACTIVE(MODEL_SDR_FLAG_DIFFUSE)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_DIFFUSE
if(desaturate == 1) {
baseColor.rgb = color.rgb * dot(vec3(1.0), baseColor.rgb) * 0.3333333;
}
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DIFFUSE
if (effect_num == 0) {
float shinefactor = 1.0/(1.0 + pow(abs((fract(abs(texCoord.x))-anim_timer) * 1000.0), 2.0)) * 1000.0;
@@ -435,33 +463,34 @@ void main()
} else if (effect_num == 1) {
float shinefactor = 1.0/(1.0 + pow(abs(vertIn.position.y-anim_timer), 2.0));
emissiveColor.rgb += vec3(shinefactor);
if (!(FLAG_ACTIVE(MODEL_SDR_FLAG_LIGHT))) {
#prereplace IF_NOT_FLAG MODEL_SDR_FLAG_LIGHT
// ATI Wireframe fix *grumble*
baseColor.a = clamp((vertIn.position.y-anim_timer) * 10000.0,0.0,1.0);
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT
} else if (effect_num == 2) {
vec2 screenPos = gl_FragCoord.xy * vec2(vpwidth,vpheight);
baseColor.a = baseColor.a;
float cloak_interp = (sin(vertIn.position.x*vertIn.position.w*0.005+anim_timer*20.0)*sin(vertIn.position.y*vertIn.position.w*0.005)*0.5)-0.5;
if (FLAG_ACTIVE(MODEL_SDR_FLAG_LIGHT)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_LIGHT
baseColor.rgb = mix(texture(sFramebuffer, screenPos + distort*anim_timer + anim_timer*0.1*normal.xy).rgb,baseColor.rgb,clamp(cloak_interp+anim_timer*2.0,0.0,1.0));
} else {
#prereplace ELSE_FLAG //MODEL_SDR_FLAG_LIGHT
baseColor.rgb = mix(texture(sFramebuffer, screenPos + distort*anim_timer + anim_timer*0.1*vertIn.normal.xy).rgb,baseColor.rgb,clamp(cloak_interp+anim_timer*2.0,0.0,1.0));
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT
}
if (!(FLAG_ACTIVE(MODEL_SDR_FLAG_DEFERRED))) {
#prereplace IF_NOT_FLAG MODEL_SDR_FLAG_DEFERRED
// emissive colors won't be added later when we are using forward rendering so we need to do that here
baseColor.rgb += emissiveColor.rgb;
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DEFERRED
fragOut0 = baseColor;
if (FLAG_ACTIVE(MODEL_SDR_FLAG_DEFERRED)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_DEFERRED
fragOut1 = vec4(vertIn.position.xyz, 1.0);
fragOut2 = vec4(normal, glossData);
fragOut3 = vec4(specColor.rgb, fresnelFactor);
fragOut4 = emissiveColor;
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DEFERRED
#endif
}
+65 -36
View File
@@ -1,17 +1,18 @@
#extension GL_ARB_gpu_shader5: enable
#include "model_shader_flags.h"
#conditional_include +"LARGE_SHADER" "main_large.sdr"
#conditional_include -"LARGE_SHADER" "main_small.sdr"
#ifdef FLAG_THICK_OUTLINE
#ifdef MODEL_SDR_FLAG_THICK_OUTLINES
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;
#elif defined(FLAG_SHADOW_MAP)
#elif defined(MODEL_SDR_FLAG_SHADOW_MAP)
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;
#endif
#ifdef FLAG_SHADOW_MAP
#ifdef MODEL_SDR_FLAG_SHADOW_MAP
#ifdef GL_ARB_gpu_shader5
layout(invocations = 4) in;
#endif
@@ -102,11 +103,17 @@ layout (std140) uniform modelData {
};
in VertexOutput {
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
vec3 envReflect;
mat3 tangentMatrix;
float fogDist;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
#ifdef FLAG_SHADOW_MAP
mat3 tangentMatrix;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
float fogDist;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
#ifdef MODEL_SDR_FLAG_SHADOW_MAP
#if !defined(GL_ARB_gpu_shader5)
float instance;
#endif
@@ -116,22 +123,35 @@ in VertexOutput {
#endif
vec3 normal;
vec4 texCoord;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
vec4 shadowUV[4];
vec4 shadowPos;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
} vertIn[];
out VertexOutput {
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
vec3 envReflect;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
mat3 tangentMatrix;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
float fogDist;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
vec4 position;
vec3 normal;
vec4 texCoord;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
vec4 shadowUV[4];
vec4 shadowPos;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
} vertOut;
#ifdef FLAG_SHADOW_MAP
#ifdef MODEL_SDR_FLAG_SHADOW_MAP
void main(void)
{
#ifdef GL_ARB_gpu_shader5
@@ -141,16 +161,17 @@ out VertexOutput {
#endif
for(int vert = 0; vert < gl_in.length(); vert++)
{
if (FLAG_ACTIVE(MODEL_SDR_FLAG_TRANSFORM)) {
#prereplace IF_FLAG MODEL_SDR_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 {
#prereplace ELSE_FLAG //MODEL_SDR_FLAG_TRANSFORM
gl_Position = shadow_proj_matrix[instanceID] * gl_in[vert].gl_Position;
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_TRANSFORM
if(gl_Position.z < -1.0)
gl_Position.z = -1.0;
@@ -160,22 +181,26 @@ out VertexOutput {
gl_Layer = instanceID;
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ENV)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_ENV
vertOut.envReflect = vertIn[vert].envReflect;
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_NORMAL)) {
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ENV
#prereplace IF_FLAG MODEL_SDR_FLAG_NORMAL
vertOut.tangentMatrix = vertIn[vert].tangentMatrix;
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_FOG)) {
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_NORMAL
#prereplace IF_FLAG MODEL_SDR_FLAG_FOG
vertOut.fogDist = vertIn[vert].fogDist;
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SHADOWS)) {
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_FOG
#prereplace IF_FLAG MODEL_SDR_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;
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SHADOWS
if (use_clip_plane) {
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
}
@@ -183,7 +208,7 @@ out VertexOutput {
}
EndPrimitive();
}
#elif defined(FLAG_THICK_OUTLINE)
#elif defined(MODEL_SDR_FLAG_THICK_OUTLINES)
const vec2 pixelOffsetDir[4] = vec2[](
vec2(0.0, 1.0),
vec2(1.0, 1.0),
@@ -214,22 +239,26 @@ out VertexOutput {
vertOut.normal = vertIn[vert].normal;
vertOut.texCoord = vertIn[vert].texCoord;
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ENV)) {
vertOut.envReflect = vertIn[vert].envReflect;
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_NORMAL)) {
vertOut.tangentMatrix = vertIn[vert].tangentMatrix;
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_FOG)) {
vertOut.fogDist = vertIn[vert].fogDist;
}
if (FLAG_ACTIVE(MODEL_SDR_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;
}
#prereplace IF_FLAG MODEL_SDR_FLAG_ENV
vertOut.envReflect = vertIn[vert].envReflect;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ENV
#prereplace IF_FLAG MODEL_SDR_FLAG_NORMAL
vertOut.tangentMatrix = vertIn[vert].tangentMatrix;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_NORMAL
#prereplace IF_FLAG MODEL_SDR_FLAG_FOG
vertOut.fogDist = vertIn[vert].fogDist;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_FOG
#prereplace IF_FLAG MODEL_SDR_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;
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SHADOWS
if (use_clip_plane) {
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
}
+36 -17
View File
@@ -2,7 +2,9 @@
#extension GL_ARB_gpu_shader5: enable
#include "shadows.sdr"
#include "model_shader_flags.h"
#conditional_include +"LARGE_SHADER" "main_large.sdr"
#conditional_include -"LARGE_SHADER" "main_small.sdr"
in vec4 vertPosition;
in vec4 vertTexCoord;
@@ -95,13 +97,22 @@ layout (std140) uniform modelData {
int flags;
};
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_TRANSFORM
uniform samplerBuffer transform_tex;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_TRANSFORM
out VertexOutput {
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
vec3 envReflect;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
mat3 tangentMatrix;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
float fogDist;
#ifdef FLAG_SHADOW_MAP
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
#ifdef MODEL_SDR_FLAG_SHADOW_MAP
#if !defined(GL_ARB_gpu_shader5)
float instance;
#endif
@@ -113,11 +124,15 @@ out VertexOutput {
#endif
vec3 normal;
vec4 texCoord;
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
vec4 shadowUV[4];
vec4 shadowPos;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
} vertOut;
#define TEXELS_PER_MATRIX 4
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_TRANSFORM
void getModelTransform(inout mat4 transform, out bool invisible, int id, int matrix_offset)
{
transform[0] = texelFetch(transform_tex, (matrix_offset + id) * TEXELS_PER_MATRIX);
@@ -127,6 +142,7 @@ void getModelTransform(inout mat4 transform, out bool invisible, int id, int mat
invisible = transform[3].w >= 0.9;
transform[3].w = 1.0;
}
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_TRANSFORM
void main()
{
@@ -137,20 +153,21 @@ void main()
mat4 scale = mat4(1.0);
bool clipModel = false;
if (FLAG_ACTIVE(MODEL_SDR_FLAG_TRANSFORM)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_TRANSFORM
getModelTransform(orient, clipModel, int(vertModelID), buffer_matrix_offset);
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_TRANSFORM
texCoord = textureMatrix * vertTexCoord;
vec4 vertex = vertPosition;
if (FLAG_ACTIVE(MODEL_SDR_FLAG_THRUSTER)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_THRUSTER
if(vertex.z < -1.5) {
vertex.z *= thruster_scale;
}
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_THRUSTER
// Transform the normal into eye space and normalize the result.
normal = normalize(mat3(modelViewMatrix) * mat3(orient) * vertNormal);
position = modelViewMatrix * orient * vertex;
#ifdef FLAG_SHADOW_MAP
#ifdef MODEL_SDR_FLAG_SHADOW_MAP
gl_Position = position;
#if !defined(GL_ARB_gpu_shader5)
#ifdef APPLE
@@ -162,37 +179,39 @@ void main()
#else
gl_Position = projMatrix * position;
#endif
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SHADOWS)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_SHADOWS
vec4 shadowPos = shadow_mv_matrix * modelMatrix * orient * vertPosition;
vertOut.shadowPos = shadow_mv_matrix * modelMatrix * orient * vertPosition;
vertOut.shadowUV[0] = transformToShadowMap(shadow_proj_matrix[0], 0, shadowPos);
vertOut.shadowUV[1] = transformToShadowMap(shadow_proj_matrix[1], 1, shadowPos);
vertOut.shadowUV[2] = transformToShadowMap(shadow_proj_matrix[2], 2, shadowPos);
vertOut.shadowUV[3] = transformToShadowMap(shadow_proj_matrix[3], 3, shadowPos);
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SHADOWS
// Setup stuff for normal maps and envmaps
vec3 t = normalize(mat3(modelViewMatrix) * mat3(orient) * vertTangent.xyz);
vec3 b = cross(normal, t) * vertTangent.w;
vertOut.tangentMatrix = mat3(t, b, normal);
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ENV)) {
#prereplace IF_FLAG MODEL_SDR_FLAG_ENV
// Environment mapping reflection vector.
vec3 envReflect = reflect(normalize(position.xyz), normal);
vertOut.envReflect = vec3(envMatrix * vec4(envReflect, 0.0));
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_FOG)) {
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ENV
#prereplace IF_FLAG MODEL_SDR_FLAG_FOG
vertOut.fogDist = clamp((gl_Position.z - fogStart) * 0.75 * fogScale, 0.0, 1.0);
}
if (FLAG_ACTIVE(MODEL_SDR_FLAG_TRANSFORM)) {
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_FOG
#prereplace IF_FLAG MODEL_SDR_FLAG_TRANSFORM
if (clipModel) {
// Clip this model by moving all vertices outside the clip volume
gl_Position = vec4(vec3(-2.0), 1.0);
}
#ifdef FLAG_SHADOW_MAP
#ifdef MODEL_SDR_FLAG_SHADOW_MAP
vertOut.clipModel = clipModel ? 1.0 : 0.0;
#endif
}
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_TRANSFORM
if(use_clip_plane) {
gl_ClipDistance[0] = dot(clip_equation, modelMatrix * orient * vertex);
@@ -200,7 +219,7 @@ void main()
gl_ClipDistance[0] = 1.0;
}
#ifndef FLAG_SHADOW_MAP
#ifndef MODEL_SDR_FLAG_SHADOW_MAP
vertOut.position = position;
vertOut.normal = normal;
vertOut.texCoord = texCoord;
@@ -0,0 +1,9 @@
#predefine IF_FLAG if ((flags & %s) != 0) {
#predefine IF_NOT_FLAG if ((flags & %s) == 0) {
#predefine ELSE_FLAG } else { %s
#predefine ENDIF_FLAG } %s
#predefine IF_FLAG_COMPILED //if true %s
#predefine ENDIF_FLAG_COMPILED //endif true %s
#define MODEL_SDR_FLAG_MODE_GLSL 1
#include "model_shader_flags.h"
@@ -0,0 +1,6 @@
#predefine IF_FLAG #ifdef %s
#predefine IF_NOT_FLAG #ifndef %s
#predefine ELSE_FLAG #else //%s
#predefine ENDIF_FLAG #endif //%s
#predefine IF_FLAG_COMPILED #ifdef %s
#predefine ENDIF_FLAG_COMPILED #endif //%s
@@ -1,19 +1,35 @@
#define MODEL_SDR_FLAG_LIGHT (1 << 0)
#define MODEL_SDR_FLAG_DEFERRED (1 << 1)
#define MODEL_SDR_FLAG_HDR (1 << 2)
#define MODEL_SDR_FLAG_DIFFUSE (1 << 3)
#define MODEL_SDR_FLAG_GLOW (1 << 4)
#define MODEL_SDR_FLAG_SPEC (1 << 5)
#define MODEL_SDR_FLAG_ENV (1 << 6)
#define MODEL_SDR_FLAG_NORMAL (1 << 7)
#define MODEL_SDR_FLAG_AMBIENT (1 << 8)
#define MODEL_SDR_FLAG_MISC (1 << 9)
#define MODEL_SDR_FLAG_TEAMCOLOR (1 << 10)
#define MODEL_SDR_FLAG_FOG (1 << 11)
#define MODEL_SDR_FLAG_TRANSFORM (1 << 12)
#define MODEL_SDR_FLAG_SHADOWS (1 << 13)
#define MODEL_SDR_FLAG_THRUSTER (1 << 14)
#define MODEL_SDR_FLAG_ALPHA_MULT (1 << 15)
#ifdef MODEL_SDR_FLAG_MODE_CPP
#define SDR_FLAG(name, value, geoshader) constexpr int name = value;
#elif defined MODEL_SDR_FLAG_MODE_CPP_ARRAY
#define SDR_FLAG(name, value, geoshader) {SDR_TYPE_MODEL, geoshader, value, #name, {}, #name},
#elif defined MODEL_SDR_FLAG_MODE_GLSL
#define SDR_FLAG(name, value, geoshader) const int name = value;
#else
#error Make sure to properly define the usage mode for this file!
#endif
SDR_FLAG(MODEL_SDR_FLAG_LIGHT , (1 << 0) , false)
SDR_FLAG(MODEL_SDR_FLAG_DEFERRED , (1 << 1) , false)
SDR_FLAG(MODEL_SDR_FLAG_HDR , (1 << 2) , false)
SDR_FLAG(MODEL_SDR_FLAG_DIFFUSE , (1 << 3) , false)
SDR_FLAG(MODEL_SDR_FLAG_GLOW , (1 << 4) , false)
SDR_FLAG(MODEL_SDR_FLAG_SPEC , (1 << 5) , false)
SDR_FLAG(MODEL_SDR_FLAG_ENV , (1 << 6) , false)
SDR_FLAG(MODEL_SDR_FLAG_NORMAL , (1 << 7) , false)
SDR_FLAG(MODEL_SDR_FLAG_AMBIENT , (1 << 8) , false)
SDR_FLAG(MODEL_SDR_FLAG_MISC , (1 << 9) , false)
SDR_FLAG(MODEL_SDR_FLAG_TEAMCOLOR , (1 << 10), false)
SDR_FLAG(MODEL_SDR_FLAG_FOG , (1 << 11), false)
SDR_FLAG(MODEL_SDR_FLAG_TRANSFORM , (1 << 12), false)
SDR_FLAG(MODEL_SDR_FLAG_SHADOWS , (1 << 13), false)
SDR_FLAG(MODEL_SDR_FLAG_THRUSTER , (1 << 14), false)
SDR_FLAG(MODEL_SDR_FLAG_ALPHA_MULT , (1 << 15), false)
#define FLAG_ACTIVE(flag) (flags & flag) != 0
#ifndef MODEL_SDR_FLAG_MODE_GLSL
//The following ones are used ONLY as compile-time flags, but they still need to be defined here to ensure no conflict occurs
//But since these are checked with ifdefs even for the large shader, they must never be available in GLSL mode
SDR_FLAG(MODEL_SDR_FLAG_SHADOW_MAP , (1 << 16), true)
SDR_FLAG(MODEL_SDR_FLAG_THICK_OUTLINES, (1 << 17), true)
#endif
+3 -2
View File
@@ -174,7 +174,8 @@ void main()
for(int i = 0; i < samples; i++) {
vec4 localPos = texelFetch(texPos, texel, i);
//Calculate local weight from distance Voxel, but if the distance is 0 (i.e. no model at all), set weight to 1 to allow stuff like background emissive
float localWeight = max(step(-0.001, dist),
//However, if the median distance is 0, only deal with current texel if it's local distance is 0 as well
float localWeight = max(step(-0.001, dist) * step(-0.001, localPos.z),
smoothstep(dist + dist * texelWidthFactor * (voxelDepth + voxelDepthFalloff), dist + dist * texelWidthFactor * voxelDepth, localPos.z) *
smoothstep(dist - dist * texelWidthFactor * voxelDepth, dist + dist * texelWidthFactor * (voxelDepth + voxelDepthFalloff), localPos.z)
);
@@ -190,7 +191,7 @@ void main()
fragOut0 = color / weight;
fragOut1 = pos / weight;
fragOut2 = normalize(normal);
fragOut2 = vec4(normalize(normal.xyz), normal.a / weight);
fragOut3 = specular / weight;
fragOut4 = emissive / weight;
gl_FragDepth = depth / weight;
+12 -8
View File
@@ -21,9 +21,11 @@ layout (std140) uniform genericData {
vec3 globalLightDiffuse;
float stepsize;
vec3 nebPos;
float globalstepalpha;
float opacitydistance;
vec3 nebSize;
float alphalim;
vec3 nebulaColor;
float udfScale;
float emissiveSpreadFactor;
float emissiveIntensity;
float emissiveFalloff;
@@ -92,12 +94,14 @@ void main()
vec3 sidestep = 1.0 / vec3(textureSize(volume_tex, 0));
for(float stept = maxtMin; stept < mintMax; stept += stepsize) {
for(float stept = maxtMin; stept < mintMax;) {
//Step setup
vec3 position = camera + rayDirection * stept - nebPos;
vec3 sampleposition = position / nebSize + 0.5;
vec4 volume_sample = textureGrad(volume_tex, sampleposition, gradX, gradY);
float stepsize_current = min(max(stepsize, volume_sample.x * udfScale), mintMax - stept);
#ifdef DO_EDGE_SMOOTHING
//Average 3D texel with texels on corner, in an attempt to reduce jagged edges.
float stepcolor_alpha = volume_sample.a;
@@ -117,7 +121,7 @@ void main()
float stepcolor_alpha = volume_sample.a;
#endif
float stepalpha = globalstepalpha * stepcolor_alpha;
float stepalpha = -(pow(alphalim, 1.0 / (opacitydistance / stepsize_current)) - 1.0f) * stepcolor_alpha;
//All the following computations are just required if we have a stepcoloralpha that is non-zero.
if(stepcolor_alpha > 0.01)
{
@@ -127,10 +131,10 @@ void main()
//Diffuse
#ifdef NOISE
//Mix the actual nebula color with the noise color depending on the product of the noise channels multiplied with intensity, smooth-clamped from 0 to 1
vec3 stepcolor_neb = mix(volume_sample.rgb, noiseColor,
vec3 stepcolor_neb = mix(nebulaColor, noiseColor,
smoothstep(0, 1, (textureGrad(noise_volume_tex, position / noiseColorScale1, gradX, gradY).r + textureGrad(noise_volume_tex, position / noiseColorScale2, gradX, gradY).g) / 2.0 * noiseIntensity));
#else
vec3 stepcolor_neb = volume_sample.rgb;
vec3 stepcolor_neb = nebulaColor;
#endif
vec3 stepcolor_diffuse = stepcolor_neb * henyey_greenstein(dot(rayDirection, globalLightDirection));
float directionalLightStep = 4.0 / float(directionalLightSampleSteps);
@@ -145,17 +149,17 @@ void main()
stepcolor_diffuse *= beer_powder_norm * (1 - exp(-directionalLightDepth * 2.0)) * exp(-directionalLightDepth);
//Emissive
cumnebdist += stepcolor_alpha * stepsize;
cumnebdist += stepcolor_alpha * stepsize_current;
vec3 emissive_lod = textureLod(emissive, fragTexCoord.xy, clamp(cumnebdist * emissiveSpreadFactor, 0, float(textureQueryLevels(emissive) - 1))).rgb;
vec3 stepcolor_emissive = emissive_lod.rgb * pow(1 - globalstepalpha, (depth - stept) * emissiveFalloff) * emissiveIntensity;
vec3 stepcolor_emissive = emissive_lod.rgb * pow(alphalim, 1.0 / (opacitydistance / ((depth - stept) * emissiveFalloff + 0.01))) * emissiveIntensity;
//Step finish
vec3 stepcolor = clamp(stepcolor_diffuse + stepcolor_emissive, 0, 1);
float stepalpha = globalstepalpha * stepcolor_alpha;
cumcolor += stepalpha * cumOMAlpha * stepcolor;
}
cumOMAlpha *= 1.0 - stepalpha;
stept += stepsize_current;
if(cumOMAlpha < alphalim)
break;
+30 -56
View File
@@ -8,9 +8,9 @@ $Fog:
+Start dist: 10.0
+Compl dist: 500.0
$AI:
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Turrets attack this: YES
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
$Skip Death Roll Percent Chance: 0.0
$Name: Sentry Gun
@@ -28,10 +28,10 @@ $Fog:
$AI:
+Accept Player Orders: NO
+Auto attacks: YES
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Guards attack this: YES
+Turrets attack this: YES
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
$Skip Death Roll Percent Chance: 0.0
$Name: Escape Pod
@@ -48,9 +48,9 @@ $Fog:
+Compl dist: 600.0
$AI:
+Valid goals: ( "fly to ship" "attack ship" "attack wing" "dock" "waypoints" "waypoints once" "depart" "undock" "stay still" "play dead" "play dead (persistent)" "stay near ship" )
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Turrets attack this: YES
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
$Skip Death Roll Percent Chance: 0.0
$Name: Cargo
@@ -87,37 +87,11 @@ $AI:
+Accept Player Orders: YES
+Player orders: ( "rearm me" "abort rearm" "depart" )
+Auto attacks: YES
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Guards attack this: YES
+Turrets attack this: YES
+Active docks: ( "support" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
$Skip Death Roll Percent Chance: 0.0
;;WMC - Stealth ships always have another type, so this isn't used
$Name: Stealth
$Counts for Alone: YES
$Praise Destruction: YES
$On Hotkey List: YES
$Target as Threat: YES
$Show Attack Direction: YES
$Max Debris Speed: 200
$FF Multiplier: 1.0
$EMP Multiplier: 4.0
$Protected on cripple: YES
$Fog:
+Start dist: 10.0
+Compl dist: 500.0
$AI:
+Valid goals: ( "fly to ship" "attack ship" "waypoints" "waypoints once" "depart" "attack subsys" "attack wing" "guard ship" "disable ship" "disarm ship" "attack any" "attack ship class" "ignore ship" "ignore ship (new)" "guard wing" "evade ship" "stay still" "play dead" "play dead (persistent)" "stay near ship" "keep safe dist" )
+Accept Player Orders: YES
+Player Orders: ( "attack ship" "disable ship" "disarm ship" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "depart" "disable subsys" )
+Auto attacks: YES
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Guards attack this: YES
+Turrets attack this: YES
+Passive docks: ( "support" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
$Skip Death Roll Percent Chance: 0.0
$Name: Fighter
@@ -136,16 +110,16 @@ $Fog:
+Start dist: 10.0
+Compl dist: 500.0
$AI:
+Valid goals: ( "fly to ship" "attack ship" "waypoints" "waypoints once" "depart" "attack subsys" "attack wing" "guard ship" "disable ship" "disarm ship" "attack any" "attack ship class" "ignore ship" "ignore ship (new)" "guard wing" "evade ship" "stay still" "play dead" "play dead (persistent)" "stay near ship" "keep safe dist" "form on wing")
+Valid goals: ( "fly to ship" "attack ship" "waypoints" "waypoints once" "depart" "attack subsys" "attack wing" "guard ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "attack any" "attack ship class" "ignore ship" "ignore ship (new)" "guard wing" "evade ship" "stay still" "play dead" "play dead (persistent)" "stay near ship" "keep safe dist" "form on wing")
+Accept Player Orders: YES
+Player Orders: ( "attack ship" "disable ship" "disarm ship" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "depart" "disable subsys" )
+Player Orders: ( "attack ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "attack ship class" "depart" "disable subsys" )
+Auto attacks: YES
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Guards attack this: YES
+Turrets attack this: YES
+Can Form Wing: YES
+Passive docks: ( "support" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
$Skip Death Roll Percent Chance: 0.0
$Name: Bomber
@@ -164,16 +138,16 @@ $Fog:
+Start dist: 10.0
+Compl dist: 500.0
$AI:
+Valid goals: ( "fly to ship" "attack ship" "waypoints" "waypoints once" "depart" "attack subsys" "attack wing" "guard ship" "disable ship" "disarm ship" "attack any" "attack ship class" "ignore ship" "ignore ship (new)" "guard wing" "evade ship" "stay still" "play dead" "play dead (persistent)" "stay near ship" "keep safe dist" "form on wing" )
+Valid goals: ( "fly to ship" "attack ship" "waypoints" "waypoints once" "depart" "attack subsys" "attack wing" "guard ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "attack any" "attack ship class" "ignore ship" "ignore ship (new)" "guard wing" "evade ship" "stay still" "play dead" "play dead (persistent)" "stay near ship" "keep safe dist" "form on wing" )
+Accept Player Orders: YES
+Player Orders: ( "attack ship" "disable ship" "disarm ship" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "depart" "disable subsys" )
+Player Orders: ( "attack ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "attack ship class" "depart" "disable subsys" )
+Auto attacks: YES
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Guards attack this: YES
+Turrets attack this: YES
+Can Form Wing: YES
+Passive docks: ( "support" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
$Skip Death Roll Percent Chance: 0.0
;;WMC - This fighter/bomber type doesn't seem to be used anywhere, because no ship is set as both fighter and bomber
@@ -192,16 +166,16 @@ $Fog:
+Start dist: 10.0
+Compl dist: 500.0
$AI:
+Valid goals: ( "fly to ship" "attack ship" "waypoints" "waypoints once" "depart" "attack subsys" "attack wing" "guard ship" "disable ship" "disarm ship" "attack any" "attack ship class" "ignore ship" "ignore ship (new)" "guard wing" "evade ship" "stay still" "play dead" "play dead (persistent)" "stay near ship" "keep safe dist" "form on wing" )
+Valid goals: ( "fly to ship" "attack ship" "waypoints" "waypoints once" "depart" "attack subsys" "attack wing" "guard ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "attack any" "attack ship class" "ignore ship" "ignore ship (new)" "guard wing" "evade ship" "stay still" "play dead" "play dead (persistent)" "stay near ship" "keep safe dist" "form on wing" )
+Accept Player Orders: YES
+Player Orders: ( "attack ship" "disable ship" "disarm ship" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "depart" "disable subsys" )
+Player Orders: ( "attack ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "attack ship class" "depart" "disable subsys" )
+Auto attacks: YES
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Guards attack this: YES
+Turrets attack this: YES
+Can Form Wing: YES
+Passive docks: ( "support" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
$Skip Death Roll Percent Chance: 0.0
$Name: Transport
@@ -230,7 +204,7 @@ $AI:
+Turrets attack this: YES
+Can Form Wing: YES
+Passive docks: ( "support" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Skip Death Roll Percent Chance: 0.0
@@ -262,7 +236,7 @@ $AI:
+Can Form Wing: YES
+Active docks: ( "cargo" )
+Passive docks: ( "support" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Skip Death Roll Percent Chance: 0.0
@@ -292,7 +266,7 @@ $AI:
+Turrets attack this: YES
+Can Form Wing: YES
+Passive docks: ( "support" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Skip Death Roll Percent Chance: 0.0
@@ -322,7 +296,7 @@ $AI:
+Turrets attack this: YES
+Can Form Wing: YES
+Passive docks: ( "support" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Skip Death Roll Percent Chance: 0.0
@@ -352,7 +326,7 @@ $AI:
+Turrets attack this: YES
+Can Form Wing: YES
+Passive docks: ( "support" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Skip Death Roll Percent Chance: 0.0
@@ -382,7 +356,7 @@ $AI:
+Turrets attack this: YES
+Can Form Wing: YES
+Passive docks: ( "support" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Skip Death Roll Percent Chance: 0.0
@@ -412,7 +386,7 @@ $AI:
+Turrets attack this: YES
+Can Form Wing: YES
+Passive docks: ( "support" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Skip Death Roll Percent Chance: 0.0
@@ -440,7 +414,7 @@ $AI:
+Turrets attack this: YES
+Can Form Wing: YES
+Passive docks: ( "support" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Skip Death Roll Percent Chance: 0.0
@@ -466,7 +440,7 @@ $AI:
+Guards attack this: YES
+Turrets attack this: YES
+Passive docks: ( "support" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Skip Death Roll Percent Chance: 0.0
@@ -490,7 +464,7 @@ $AI:
+Guards attack this: YES
+Turrets attack this: YES
+Passive docks: ( "support" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
$Skip Death Roll Percent Chance: 0.0
+38 -34
View File
@@ -37,11 +37,7 @@ constexpr int INTITIAL_FIREBALL_CONTAINTER_SIZE = 256;
SCP_vector<fireball> Fireballs;
SCP_vector<int> Unused_fireball_indices;
fireball_info Fireball_info[MAX_FIREBALL_TYPES];
int fireball_used[MAX_FIREBALL_TYPES];
int Num_fireball_types = 0;
SCP_vector<fireball_info> Fireball_info;
bool fireballs_inited = false;
bool fireballs_parsed = false;
@@ -120,7 +116,7 @@ void fireball_play_warphole_close_sound(fireball *fb)
static void fireball_generate_unique_id(char *unique_id, int buffer_len, int fireball_index)
{
Assert((fireball_index >= 0) && (fireball_index < MAX_FIREBALL_TYPES));
Assertion(SCP_vector_inbounds(Fireball_info, fireball_index), "fireball_index is out of bounds!");
switch (fireball_index)
{
@@ -164,7 +160,7 @@ static void fireball_generate_unique_id(char *unique_id, int buffer_len, int fir
*/
static void fireball_set_default_color(int idx)
{
Assert((idx >= 0) && (idx < MAX_FIREBALL_TYPES));
Assertion(SCP_vector_inbounds(Fireball_info, idx), "idx is out of bounds!");
switch (idx)
{
@@ -200,7 +196,7 @@ static void fireball_set_default_color(int idx)
static void fireball_set_default_warp_attributes(int idx)
{
Assert((idx >= 0) && (idx < MAX_FIREBALL_TYPES));
Assertion(SCP_vector_inbounds(Fireball_info, idx), "idx is out of bounds!");
switch (idx)
{
@@ -232,9 +228,9 @@ void fireball_info_clear(fireball_info *fb)
int fireball_info_lookup(const char *unique_id)
{
for (int i = 0; i < Num_fireball_types; ++i)
for (size_t i = 0; i < Fireball_info.size(); ++i)
if (!stricmp(Fireball_info[i].unique_id, unique_id))
return i;
return static_cast<int>(i);
return -1;
}
@@ -308,25 +304,19 @@ static void parse_fireball_tbl(const char *table_filename)
// 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;
}
fi = &Fireball_info[Num_fireball_types];
int new_fireball_index = static_cast<int>(Fireball_info.size());
Fireball_info.emplace_back();
fi = &Fireball_info.back();
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);
fireball_generate_unique_id(unique_id, NAME_LENGTH, new_fireball_index);
// Set remaining fireball defaults
fireball_set_default_color(Num_fireball_types);
fireball_set_default_warp_attributes(Num_fireball_types);
fireball_set_default_color(new_fireball_index);
fireball_set_default_warp_attributes(new_fireball_index);
Num_fireball_types++;
first_time = true;
}
@@ -399,9 +389,9 @@ void fireball_parse_tbl()
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;
// every newly parsed fireball_info will get cleared before being added;
// must clear the vector outside of parse_fireball_tbl because it's called more than once
Fireball_info.clear();
parse_fireball_tbl("fireball.tbl");
@@ -436,10 +426,11 @@ void fireball_parse_tbl()
void fireball_load_data()
{
int i, idx;
int i, n, idx;
fireball_info *fd;
for ( i = 0; i < Num_fireball_types; i++ ) {
n = static_cast<int>(Fireball_info.size());
for ( i = 0; i < n; i++ ) {
fd = &Fireball_info[i];
for(idx=0; idx<fd->lod_count; idx++){
@@ -798,8 +789,7 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
object *obj;
fireball_info *fd;
fireball_lod *fl;
Assert( fireball_type > -1 );
Assert( fireball_type < Num_fireball_types );
Assertion(SCP_vector_inbounds(Fireball_info, fireball_type), "fireball_type is out of bounds!");
fd = &Fireball_info[fireball_type];
@@ -946,13 +936,14 @@ void fireball_close()
void fireballs_page_in()
{
int i, idx;
int i, n, idx;
fireball_info *fd;
for ( i = 0; i < Num_fireball_types; i++ ) {
n = static_cast<int>(Fireball_info.size());
for ( i = 0; i < n; i++ ) {
fd = &Fireball_info[i];
if((i < NUM_DEFAULT_FIREBALLS) || fireball_used[i]) {
if ((i < NUM_DEFAULT_FIREBALLS) || fd->fireball_used) {
// if this is a Knossos ani, only load if Knossos_warp_ani_used is true
if ( (i == FIREBALL_KNOSSOS) && !Knossos_warp_ani_used)
continue;
@@ -984,8 +975,8 @@ void fireball_get_color(int idx, float *red, float *green, float *blue)
{
Assert( red && blue && green );
if ( (idx < 0) || (idx >= Num_fireball_types) ) {
Int3();
if (!SCP_vector_inbounds(Fireball_info, idx)) {
UNREACHABLE("idx is out of bounds!");
*red = 1.0f;
*green = 1.0f;
@@ -1120,3 +1111,16 @@ int fireball_get_count()
return count;
}
void stuff_fireball_index_list(SCP_vector<int> &list, const char *name)
{
stuff_int_list(list, RAW_INTEGER_TYPE);
list.erase(std::remove_if(list.begin(), list.end(), [&](int index) {
if (!SCP_vector_inbounds(Fireball_info, index)) {
Warning(LOCATION, "Fireball index %d for %s was out of bounds. Removing this index.", index, name);
return true;
}
return false;
}), list.end());
}
+5 -5
View File
@@ -33,15 +33,12 @@ class asteroid_info;
#define FIREBALL_EXPLOSION_LARGE1 4 // Used for the big explosion when a ship breaks into pieces
#define FIREBALL_EXPLOSION_LARGE2 5 // Used for the big explosion when a ship breaks into pieces
#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];
// all this moved here by Goober5000 because it makes more sense in the H file
typedef struct fireball_lod {
char filename[MAX_FILENAME_LEN];
@@ -57,6 +54,7 @@ typedef struct fireball_info {
float exp_color[3]; // red, green, blue
bool use_3d_warp;
bool fireball_used;
char warp_glow[NAME_LENGTH];
int warp_glow_bitmap;
@@ -66,8 +64,7 @@ typedef struct fireball_info {
int warp_model_id;
} fireball_info;
extern fireball_info Fireball_info[MAX_FIREBALL_TYPES];
extern int Num_fireball_types;
extern SCP_vector<fireball_info> Fireball_info;
// flag values for fireball struct flags member
#define FBF_WARP_CLOSE_SOUND_PLAYED (1<<0)
@@ -153,4 +150,7 @@ extern bool Fireball_warp_flash;
// Cyborg - get a count of how many valid fireballs are in the mission.
int fireball_get_count();
// Goober5000 - stuffs fireballs and checks that indexes are in bounds
void stuff_fireball_index_list(SCP_vector<int> &list, const char *name);
#endif /* _FIREBALLS_H */
+1 -1
View File
@@ -30,7 +30,7 @@ static auto WarpFlashOption __UNUSED = options::OptionBuilder<bool>("Graphics.Wa
.category(std::make_pair("Graphics", 1825))
.default_val(true)
.level(options::ExpertLevel::Advanced)
.bind_to_once(&Fireball_warp_flash)
.bind_to(&Fireball_warp_flash)
.importance(65)
.finish();
+231 -37
View File
@@ -222,6 +222,7 @@ static EnhancedSoundData Default_sound_priorities[NUM_RETAIL_GAMEPLAY_SOUNDS] =
static const EnhancedSoundData default_enhanced_sound_data(SND_ENHANCED_PRIORITY_MEDIUM_HIGH, 1);
int gamesnd_find_nonreserved_last_index(SCP_vector<game_snd>& lookupVector, bool (*is_reserved_index)(int));
/*
* Update any uninitialized EnhancedSoundData in Snds
@@ -545,7 +546,7 @@ void gamesnd_preload_common_sounds()
Assert( Snds.size() <= INT_MAX );
for (auto& gs: Snds) {
if ( gs.preload ) {
if ( gs.flags & GAME_SND_PRELOAD ) {
for (auto& entry : gs.sound_entries) {
if ( entry.filename[0] != 0 && strnicmp(entry.filename, NOX("none.wav"), 4) != 0 ) {
game_busy( NOX("** preloading common game sounds **") ); // Animate loading cursor... does nothing if loading screen not active.
@@ -566,7 +567,7 @@ void gamesnd_load_gameplay_sounds()
Assert( Snds.size() <= INT_MAX );
for (auto& gs: Snds) {
if ( !gs.preload ) { // don't try to load anything that's already preloaded
if ( !(gs.flags & GAME_SND_PRELOAD) ) { // don't try to load anything that's already preloaded
for (auto& entry : gs.sound_entries) {
if (entry.filename[0] != 0 && strnicmp(entry.filename, NOX("none.wav"), 4) != 0) {
game_busy(NOX("** preloading gameplay sounds **")); // Animate loading cursor... does nothing if loading screen not active.
@@ -633,6 +634,10 @@ void parse_gamesnd_old(game_snd* gs)
int is_3d;
int temp;
// retail-style sounds with numeric indexes, as seen in the original sounds.tbl format
if (can_construe_as_integer(gs->name.c_str()))
gs->flags |= GAME_SND_RETAIL_STYLE;
// An old sound is just a single entry sound set
gs->sound_entries.resize(1);
auto& entry = gs->sound_entries.back();
@@ -649,7 +654,7 @@ void parse_gamesnd_old(game_snd* gs)
{
entry.filename[0] = 0;
advance_to_eoln(nullptr);
gs->flags |= GAME_SND_NOT_VALID;
gs->flags |= (GAME_SND_NOT_VALID | GAME_SND_EXPLICITLY_EMPTY);
return;
}
Mp++;
@@ -658,7 +663,7 @@ void parse_gamesnd_old(game_snd* gs)
if (temp > 0)
{
gs->preload = true;
gs->flags |= GAME_SND_PRELOAD;
}
float default_volume;
@@ -701,7 +706,7 @@ void parse_gamesnd_old(game_snd* gs)
// check for extra values per Mantis #2408
if (stuff_int_optional(&temp) == 2)
{
Warning(LOCATION, "Unexpected extra value %d found for sound '%s' (filename '%s')! Check the format of the sounds.tbl (or .tbm) entry.", temp, gs->name.c_str(), entry.filename);
error_display(0, "Unexpected extra value %d found for sound '%s' (filename '%s')! Check the format of the sounds.tbl (or .tbm) entry.", temp, gs->name.c_str(), entry.filename);
}
advance_to_eoln(NULL);
@@ -770,8 +775,8 @@ void parse_gamesnd_soundset(game_snd* gs, bool no_create) {
// If this gets called then we just saw "+Entry:" so we can begin processing the first entry immediately
do {
// For now there is no way to change an existing entry so ever +Entry statement creates a new sound entry
gs->sound_entries.resize(gs->sound_entries.size() + 1);
// For now there is no way to change an existing entry so every +Entry statement creates a new sound entry
gs->sound_entries.emplace_back();
auto& entry = gs->sound_entries.back();
stuff_string(entry.filename, F_NAME, MAX_FILENAME_LEN);
@@ -783,12 +788,18 @@ void parse_gamesnd_soundset(game_snd* gs, bool no_create) {
if (required_string_no_create("+Preload:", no_create))
{
stuff_boolean(&gs->preload);
bool temp;
stuff_boolean(&temp);
if (temp)
gs->flags |= GAME_SND_PRELOAD;
else
gs->flags &= ~GAME_SND_PRELOAD;
}
if (required_string_no_create("+Volume:", no_create))
{
gs->volume_range = util::parseUniformRange(0.0f, 1.0f);
gs->volume_range = util::ParsedRandomFloatRange::parseRandomRange(0.0f, 1.0f);
}
if (optional_string("+3D Sound:"))
@@ -837,7 +848,7 @@ void parse_gamesnd_soundset(game_snd* gs, bool no_create) {
}
if (optional_string("+Pitch:")) {
gs->pitch_range = util::parseUniformRange(0.0001f);
gs->pitch_range = util::ParsedRandomFloatRange::parseRandomRange(0.0001f);
} else if (!no_create) {
// Default pitch is 1.0
gs->pitch_range = util::UniformFloatRange(1.0f);
@@ -851,7 +862,9 @@ void parse_gamesnd_new(game_snd* gs, bool no_create)
gs->sound_entries.resize(1);
entry = &gs->sound_entries.back();
} else {
if (gs->sound_entries.size() != 1) {
if (gs->sound_entries.empty()) {
gs->sound_entries.resize(1);
} else if (gs->sound_entries.size() > 1) {
error_display(1, "The SCP syntax cannot be used to modify an existing sound that has more than one entry! Use the soundset syntax for adding new entries.");
}
entry = &gs->sound_entries.back();
@@ -870,7 +883,7 @@ void parse_gamesnd_new(game_snd* gs, bool no_create)
if (!stricmp(name, NOX("empty")) || !stricmp(name, NOX("none")))
{
entry->filename[0] = 0;
gs->flags |= GAME_SND_NOT_VALID;
gs->flags |= (GAME_SND_NOT_VALID | GAME_SND_EXPLICITLY_EMPTY);
return;
}
@@ -888,7 +901,13 @@ void parse_gamesnd_new(game_snd* gs, bool no_create)
if (required_string_no_create("+Preload:", no_create))
{
stuff_boolean(&gs->preload);
bool temp;
stuff_boolean(&temp);
if (temp)
gs->flags |= GAME_SND_PRELOAD;
else
gs->flags &= ~GAME_SND_PRELOAD;
}
if (required_string_no_create("+Volume:", no_create))
@@ -944,33 +963,107 @@ void parse_gamesnd_new(game_snd* gs, bool no_create)
}
}
void gamesnd_parse_entry(game_snd *gs, bool no_create, SCP_vector<game_snd> *lookupVector)
bool gamesnd_is_placeholder(const game_snd& gs)
{
return (gs.sound_entries.empty() || gs.sound_entries[0].filename[0] == '\0') && !(gs.flags & GAME_SND_EXPLICITLY_EMPTY);
}
void gamesnd_parse_entry(game_snd *gs, bool &orig_no_create, SCP_vector<game_snd> *lookupVector, size_t lookupVectorMaxIndexableSize, bool (*is_reserved_index)(int))
{
SCP_string name;
stuff_string(name, F_NAME, "\t \n");
if (lookupVector && can_construe_as_integer(name.c_str()))
{
Assertion(is_reserved_index != nullptr, "If lookupVector is supplied, the is_reserved_index() function must also be supplied");
int candidate_index = atoi(name.c_str());
// if this is a number within the range of possible indexes
if (candidate_index >= 0 && static_cast<size_t>(candidate_index) < lookupVectorMaxIndexableSize)
{
// make sure the vector contains an entry for that index
while (lookupVector->size() <= static_cast<size_t>(candidate_index))
{
size_t back_index = lookupVector->size();
lookupVector->emplace_back();
sprintf(lookupVector->back().name, SIZE_T_ARG, back_index);
}
// if there is a named sound already at that index, move it to the end of the vector
// (because named sounds can go anywhere, while indexed sounds need to be at their indexes)
auto candidate_gs = &lookupVector->at(candidate_index);
if (!candidate_gs->name.empty() && !can_construe_as_integer(candidate_gs->name.c_str()))
{
// prevent new named sounds from colliding with reserved indexes
int endIndex = gamesnd_find_nonreserved_last_index(*lookupVector, is_reserved_index);
// add a new sound at the end of the vector
lookupVector->emplace_back();
// swap them
std::swap(lookupVector->at(candidate_index), lookupVector->at(endIndex));
sprintf(lookupVector->at(candidate_index).name, "%d", candidate_index);
}
}
}
int vectorIndex;
if (lookupVector)
vectorIndex = gamesnd_lookup_name(name.c_str(), *lookupVector);
else
vectorIndex = -1;
bool no_create = orig_no_create;
if (!no_create)
{
if (lookupVector != NULL)
if (vectorIndex >= 0)
{
if (gamesnd_lookup_name(name.c_str(), *lookupVector) >= 0)
auto existing_gs = &lookupVector->at(vectorIndex);
// if the existing sound was an empty or placeholder sound, replace it, don't warn
if (gamesnd_is_placeholder(*existing_gs))
{
Warning(LOCATION, "Duplicate sound name \"%s\" found!", name.c_str());
gs = existing_gs;
orig_no_create = true; // prevent sound from being appended in parse_sound_table
// (leave no_create as false because we are creating a new sound and we need all the fields to be filled out)
}
else
{
error_display(0, "Duplicate sound name \"%s\" found!", name.c_str());
}
}
else if (lookupVector)
{
// see if there is an empty or placeholder sound that we can replace
int i = 0;
for (const auto& ii : *lookupVector)
{
if (gamesnd_is_placeholder(ii) && !is_reserved_index(i))
{
vectorIndex = i;
gs = &lookupVector->at(vectorIndex);
orig_no_create = true; // prevent sound from being appended in parse_sound_table
// (leave no_create as false because we are creating a new sound and we need all the fields to be filled out)
// a placeholder can have a single entry with an empty filename, so remove that if it exists
gs->sound_entries.clear();
break;
}
i++;
}
}
gs->name = name;
gs->name = std::move(name);
}
else
{
int vectorIndex = gamesnd_lookup_name(name.c_str(), *lookupVector);
if (vectorIndex < 0)
{
Warning(LOCATION, "No existing sound entry with name \"%s\" found!", name.c_str());
no_create = false;
gs->name = name;
error_display(0, "No existing sound entry with name \"%s\" found!", name.c_str());
no_create = false; // this is a new sound, so we need all the fields to be filled out
gs->name = std::move(name);
}
else
{
@@ -981,7 +1074,9 @@ void gamesnd_parse_entry(game_snd *gs, bool no_create, SCP_vector<game_snd> *loo
if (optional_string("+Filename:"))
{
parse_gamesnd_new(gs, no_create);
} else if (optional_string("+Entry:")) {
}
else if (optional_string("+Entry:"))
{
parse_gamesnd_soundset(gs, no_create);
}
else
@@ -996,11 +1091,16 @@ void gamesnd_parse_entry(game_snd *gs, bool no_create, SCP_vector<game_snd> *loo
* @param gs The game_snd instance to fill in
* @param tag The tag that's required before an entry
* @param lookupVector If non-NULL used to look up @c +nocreate entries
* @param lookupVectorMaxIndexableSize Numbers less than this size will be treated as indexes;
* numbers at or above this size will be treated as numeric IDs that aren't indexes.
* Note that this distinct from the vector's current or default size.
* @param is_reserved_index A function to indicate whether a particular index should not be used
* by a named sound
*
* @return @c true when a new entry has been parsed and should be added to the list of known
* entries. @c false otherwise, for example in case of @c +nocreate
*/
bool gamesnd_parse_line(game_snd *gs, const char *tag, SCP_vector<game_snd> *lookupVector = NULL)
bool gamesnd_parse_line(game_snd *gs, const char *tag, SCP_vector<game_snd> *lookupVector = nullptr, size_t lookupVectorMaxIndexableSize = 0, bool (*is_reserved_index)(int) = nullptr)
{
Assertion(gs != NULL, "Invalid game_snd pointer passed to gamesnd_parse_line!");
@@ -1016,7 +1116,7 @@ bool gamesnd_parse_line(game_snd *gs, const char *tag, SCP_vector<game_snd> *loo
}
}
gamesnd_parse_entry(gs, no_create, lookupVector);
gamesnd_parse_entry(gs, no_create, lookupVector, lookupVectorMaxIndexableSize, is_reserved_index);
return !no_create;
}
@@ -1189,6 +1289,47 @@ void parse_sound_environments()
required_string("#Sound Environments End");
}
// indicate whether an index into Game Sounds is reserved for a built-in sound
bool gamesnd_is_reserved_game_index(int index)
{
if (index >= 0 && index <= 161)
return true;
if (index >= 173 && index <= 191)
return true;
if (index == 200 || index == 201)
return true;
return false;
}
// indicate whether an index into Interface Sounds is reserved for a built-in sound
bool gamesnd_is_reserved_interface_index(int index)
{
if (index >= 0 && index <= 64)
return true;
return false;
}
// Finds an index that
// 1) is just after the last index in lookupVector (i.e. equal to the size);
// 2) does not correspond to a reserved index, as determined by the function.
// If needed, empty game_snds are emplaced onto the vector until these conditions are true.
int gamesnd_find_nonreserved_last_index(SCP_vector<game_snd>& lookupVector, bool (*is_reserved_index)(int))
{
int candidate_last_index = static_cast<int>(lookupVector.size());
// prevent new named sounds from colliding with reserved indexes
while (is_reserved_index(candidate_last_index))
{
lookupVector.emplace_back();
sprintf(lookupVector.back().name, "%d", candidate_last_index);
candidate_last_index = static_cast<int>(lookupVector.size());
}
return candidate_last_index;
}
// Due to the cyclic depdendency between sounds and species, the parsing is now broken up into two stages.
// First, just the sounds are parsed; and second, just the flyby sounds are parsed (or assigned).
static bool Sound_table_first_stage = false;
@@ -1210,9 +1351,19 @@ void parse_sound_table(const char* filename)
while (!check_for_string("#Game Sounds End"))
{
game_snd tempSound;
if (gamesnd_parse_line(&tempSound, "$Name:", &Snds))
if (gamesnd_parse_line(&tempSound, "$Name:", &Snds, static_cast<size_t>(GameSounds::MIN_GAME_SOUNDS) * 2, gamesnd_is_reserved_game_index))
{
Snds.push_back(game_snd(tempSound));
// if we are in this block, this is a new named sound that will be appended
int tempIndex = static_cast<int>(Snds.size());
// retail sounds with numeric names must match their indexes
if ((tempSound.flags & GAME_SND_RETAIL_STYLE) && (atoi(tempSound.name.c_str()) != tempIndex) && !gamesnd_is_placeholder(tempSound))
error_display(0, "Retail-style sound %s has a name that does not match its index %d!", tempSound.name.c_str(), tempIndex);
// prevent new named sounds from colliding with reserved indexes
tempIndex = gamesnd_find_nonreserved_last_index(Snds, gamesnd_is_reserved_game_index);
Snds.emplace_back(std::move(tempSound));
}
}
@@ -1230,10 +1381,19 @@ void parse_sound_table(const char* filename)
while (!check_for_string("#Interface Sounds End"))
{
game_snd tempSound;
if (gamesnd_parse_line(&tempSound, "$Name:", &Snds_iface))
if (gamesnd_parse_line(&tempSound, "$Name:", &Snds_iface, static_cast<size_t>(InterfaceSounds::MIN_INTERFACE_SOUNDS) * 2, gamesnd_is_reserved_interface_index))
{
Snds_iface.push_back(game_snd(tempSound));
Snds_iface_handle.push_back(sound_handle::invalid());
// if we are in this block, this is a new named sound that will be appended
int tempIndex = static_cast<int>(Snds_iface.size());
// retail sounds with numeric names must match their indexes
if ((tempSound.flags & GAME_SND_RETAIL_STYLE) && (atoi(tempSound.name.c_str()) != tempIndex) && !gamesnd_is_placeholder(tempSound))
error_display(0, "Retail-style sound %s has a name that does not match its index %d!", tempSound.name.c_str(), tempIndex);
// prevent new named sounds from colliding with reserved indexes
tempIndex = gamesnd_find_nonreserved_last_index(Snds_iface, gamesnd_is_reserved_interface_index);
Snds_iface.emplace_back(std::move(tempSound));
}
}
@@ -1314,10 +1474,30 @@ void gamesnd_parse_soundstbl(bool first_stage)
parse_modular_table("*-snd.tbm", parse_sound_table);
if (!first_stage) {
if (first_stage)
{
// these vectors should be the same size
while (Snds_iface_handle.size() < Snds_iface.size())
Snds_iface_handle.push_back(sound_handle::invalid());
// mark any placeholder sounds as invalid
// (most places in the code already check for this, but it is possible for sexps and scripts to attempt to play an empty sound)
for (auto& snd : Snds)
if (gamesnd_is_placeholder(snd))
snd.flags |= GAME_SND_NOT_VALID;
// ditto for interface sounds
for (auto& snd : Snds_iface)
if (gamesnd_is_placeholder(snd))
snd.flags |= GAME_SND_NOT_VALID;
}
else
{
//Set any flyby sounds for species that use the borrowed feature
for (size_t i = 0; i < Species_info.size(); i++) {
if (Species_info[i].borrows_flyby_sounds_species >= 0) {
for (size_t i = 0; i < Species_info.size(); i++)
{
if (Species_info[i].borrows_flyby_sounds_species >= 0)
{
int idx = Species_info[i].borrows_flyby_sounds_species;
Species_info[i].snd_flyby_fighter = Species_info[idx].snd_flyby_fighter;
Species_info[i].snd_flyby_bomber = Species_info[idx].snd_flyby_bomber;
@@ -1377,6 +1557,16 @@ bool gamesnd_game_sound_try_load(gamesnd_id sound)
}
auto gs = gamesnd_get_game_sound(sound);
// check flag the first time
if (gs->flags & GAME_SND_NOT_VALID) {
return false;
}
if (gs->sound_entries.empty()) {
gs->flags |= GAME_SND_NOT_VALID;
return false;
}
for (auto& entry : gs->sound_entries) {
if (!entry.id.isValid()) {
// Lazily load unloaded sound entries when required
@@ -1384,7 +1574,7 @@ bool gamesnd_game_sound_try_load(gamesnd_id sound)
}
}
// check flag
// check flag again
return (gs->flags & GAME_SND_NOT_VALID) == 0;
}
@@ -1403,7 +1593,11 @@ float gamesnd_get_max_duration(game_snd* gs) {
return max_length / gs->pitch_range.max();
}
game_snd_entry* gamesnd_choose_entry(game_snd* gs) {
Assertion(!gs->sound_entries.empty(), "No sound entries found in game sound! This may not happen!");
if (gs->sound_entries.empty()) {
// This entire game_snd should have been skipped due to having the GAME_SND_NOT_VALID flag before we get to this function
UNREACHABLE("No sound entries found in game sound %s! This may not happen!", gs->name.c_str());
gs->sound_entries.emplace_back(); // add an empty entry so that we can return something; it will be invalid and will not be played
}
size_t index = 0;
switch(gs->cycle_type) {
+9 -2
View File
@@ -237,6 +237,8 @@ enum class GameSounds {
BALLISTIC_START_LOAD = 200,//!< (SCP)
BALLISTIC_LOAD = 201,//!< (SCP)
// NOTE: If any other indexes become reserved, be sure to update gamesnd_is_reserved_game_index()
/**
* Keep this below all defined enum values
*/
@@ -310,8 +312,10 @@ enum class InterfaceSounds {
INTERFACE_UNDEFINED_60 =60,//!< vasudan hall - vasudan pa 3
VASUDAN_BUP =61,//!< bup bup bup-bup bup bup
INTERFACE_UNDEFINED_62 =62,//!< thankyou
INTERFACE_UNDEFINED_63 =62,//!< vasudan hall - exit open
INTERFACE_UNDEFINED_64 =62,//!< vasudan hall - exit close
INTERFACE_UNDEFINED_63 =63,//!< vasudan hall - exit open
INTERFACE_UNDEFINED_64 =64,//!< vasudan hall - exit close
// NOTE: If any other indexes become reserved, be sure to update gamesnd_is_reserved_interface_index()
/**
* Keep this below all defined enum values
@@ -352,6 +356,9 @@ class interface_snd_id : public util::ID<interface_snd_tag, int, -1> {
}
};
bool gamesnd_is_reserved_game_index(int index);
bool gamesnd_is_reserved_interface_index(int index);
void gamesnd_parse_soundstbl(bool first_stage); // Loads in general game sounds from sounds.tbl
void gamesnd_close(); // close out gamesnd... only call from game_shutdown()!
void gamesnd_load_gameplay_sounds();
+5
View File
@@ -216,6 +216,11 @@ DWORD WINAPI SCP_mspdbcs_DumpStackThread( LPVOID pv )
stackFrame.AddrPC.Offset = context.Rip;
stackFrame.AddrStack.Offset = context.Rsp;
stackFrame.AddrFrame.Offset = context.Rbp;
#elif defined(_M_ARM64)
dwMachType = IMAGE_FILE_MACHINE_ARM64;
stackFrame.AddrPC.Offset = context.Pc;
stackFrame.AddrStack.Offset = context.Sp;
stackFrame.AddrFrame.Offset = context.Fp;
#else
# error UNKNOWN ARCHITECTURE
#endif
+8 -3
View File
@@ -99,6 +99,14 @@ struct ivec2 {
int x, y;
};
inline bool operator<(const ivec3& l, const ivec3& r){
return l.x < r.x || (l.x == r.x && (l.y < r.y || (l.y == r.y && l.z < r.z)));
}
inline bool operator<(const ivec2& l, const ivec2& r){
return l.x < r.x || (l.x == r.x && l.y < r.y);
}
namespace scripting {
class ade_table_entry;
}
@@ -117,9 +125,6 @@ typedef struct vec3d {
} xyz;
float a1d[3];
};
void serialize(lua_State* /*L*/, const scripting::ade_table_entry& /*tableEntry*/, const luacpp::LuaValue& value, ubyte* data, int& packet_size);
void deserialize(lua_State* /*L*/, const scripting::ade_table_entry& /*tableEntry*/, char* data_ptr, ubyte* data, int& offset);
} vec3d;
typedef struct vec2d {
+3 -3
View File
@@ -239,9 +239,9 @@ detail_levels Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS] = {
detail_levels Detail = Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS - 1];
const SCP_vector<std::pair<int, std::pair<const char*, int>>> DetailLevelValues = {{ 0, {"Minimum", 1680}},
{ 1, {"Low", 1161}},
{ 2, {"Medium", 1162}},
{ 3, {"High", 1163}},
{ 1, {"Low", 1160}},
{ 2, {"Medium", 1161}},
{ 3, {"High", 1162}},
{ 4, {"Ultra", 1721}}};
const auto ModelDetailOption __UNUSED = options::OptionBuilder<int>("Graphics.Detail",
+1 -1
View File
@@ -27,7 +27,7 @@ void Undo_system::clamp_stacks() {
// This while() shouldn't ever be triggered, but this is a safety to prevent any weird edge-cases.
while (redo_stack.size() > max_undos) {
delete redo_stack.front();
undo_stack.pop_front();
redo_stack.pop_front();
}
}
+170
View File
@@ -147,4 +147,174 @@ typename T::size_type stringcost(const T& op, const T& input, typename T::size_t
return cost;
}
template <typename T>
int count_items_with_name(const char* name, const T* item_array, int num_items)
{
if (!name || !item_array)
return 0;
int count = 0;
for (int i = 0; i < num_items; ++i)
if (!stricmp(name, item_array[i].name))
++count;
return count;
}
template <typename T>
int count_items_with_name(const char* name, const T& item_vector)
{
if (!name)
return 0;
int count = 0;
for (const auto& item : item_vector)
if (!stricmp(name, item.name))
++count;
return count;
}
template <typename T>
int count_items_with_scp_string_name(const char* name, const T& item_vector)
{
if (!name)
return 0;
int count = 0;
for (const auto& item : item_vector)
if (!stricmp(name, item.name.c_str()))
++count;
return count;
}
template <typename VECTOR_T, typename ITEM_T, typename FIELD_T>
int find_item_with_field(const VECTOR_T& item_vector, FIELD_T ITEM_T::* field, const char* str)
{
if (!str)
return -1;
int index = 0;
for (const ITEM_T& item : item_vector)
{
if (!stricmp(item.*field, str))
return index;
else
++index;
}
return -1;
}
template <typename VECTOR_T, typename ITEM_T, typename FIELD_T>
int find_item_with_field(const VECTOR_T& item_vector, FIELD_T ITEM_T::* field, const SCP_string& str)
{
int index = 0;
for (const ITEM_T& item : item_vector)
{
if (lcase_equal(item.*field, str))
return index;
else
++index;
}
return -1;
}
template <typename VECTOR_T, typename ITEM_T, typename FIELD_T>
int find_item_with_field(const VECTOR_T& item_vector, FIELD_T ITEM_T::* field, const FIELD_T& search)
{
int index = 0;
for (const ITEM_T& item : item_vector)
{
if (item.*field == search)
return index;
else
++index;
}
return -1;
}
template <typename ITEM_T, typename FIELD_T>
int find_item_with_field(const ITEM_T* item_array, int num_items, FIELD_T ITEM_T::* field, const char* str)
{
if (!str)
return -1;
for (int i = 0; i < num_items; ++i)
if (!stricmp(item_array[i].*field, str))
return i;
return -1;
}
template <typename ITEM_T, typename FIELD_T>
int find_item_with_field(const ITEM_T* item_array, int num_items, FIELD_T ITEM_T::* field, const SCP_string& str)
{
for (int i = 0; i < num_items; ++i)
if (lcase_equal(item_array[i].*field, str))
return i;
return -1;
}
template <typename ITEM_T, typename FIELD_T>
int find_item_with_field(const ITEM_T* item_array, int num_items, FIELD_T ITEM_T::* field, const FIELD_T& search)
{
for (int i = 0; i < num_items; ++i)
if (item_array[i].*field == search)
return i;
return -1;
}
template <typename VECTOR_T>
int find_item_with_name(const VECTOR_T& item_vector, const char* str)
{
if (!str)
return -1;
int index = 0;
for (const auto& item : item_vector)
{
if (!stricmp(item.name, str))
return index;
else
++index;
}
return -1;
}
template <typename ITEM_T>
int find_item_with_name(const ITEM_T* item_array, int num_items, const char* str)
{
return find_item_with_field(item_array, num_items, &ITEM_T::name, str);
}
template <typename VECTOR_T>
int find_item_with_name(const VECTOR_T& item_vector, const SCP_string& str)
{
int index = 0;
for (const auto& item : item_vector)
{
if (lcase_equal(item.name, str))
return index;
else
++index;
}
return -1;
}
template <typename NULLISH_T>
NULLISH_T coalesce(NULLISH_T possibly_null, NULLISH_T value_if_null)
{
Assertion(value_if_null != nullptr, "value_if_null can never be null itself!");
return (possibly_null != nullptr) ? possibly_null : value_if_null;
}
#endif
+49 -12
View File
@@ -61,6 +61,30 @@
#include "SDL_cpuinfo.h"
#endif
#define GR_CAPABILITY_ENTRY(capability) gr_capability_def{ gr_capability::CAPABILITY_##capability, #capability }
gr_capability_def gr_capabilities[] = {
GR_CAPABILITY_ENTRY(ENVIRONMENT_MAP),
GR_CAPABILITY_ENTRY(NORMAL_MAP),
GR_CAPABILITY_ENTRY(HEIGHT_MAP),
GR_CAPABILITY_ENTRY(SOFT_PARTICLES),
GR_CAPABILITY_ENTRY(DISTORTION),
GR_CAPABILITY_ENTRY(POST_PROCESSING),
GR_CAPABILITY_ENTRY(DEFERRED_LIGHTING),
GR_CAPABILITY_ENTRY(SHADOWS),
GR_CAPABILITY_ENTRY(THICK_OUTLINE),
GR_CAPABILITY_ENTRY(BATCHED_SUBMODELS),
GR_CAPABILITY_ENTRY(TIMESTAMP_QUERY),
GR_CAPABILITY_ENTRY(SEPARATE_BLEND_FUNCTIONS),
GR_CAPABILITY_ENTRY(PERSISTENT_BUFFER_MAPPING),
gr_capability_def {gr_capability::CAPABILITY_BPTC, "BPTC Texture Compression"}, //This one had a different parse string already!
GR_CAPABILITY_ENTRY(LARGE_SHADER)
};
const size_t gr_capabilities_num = sizeof(gr_capabilities) / sizeof(gr_capabilities[0]);
#undef GR_CAPABILITY_ENTRY
const char* Resolution_prefixes[GR_NUM_RESOLUTIONS] = {"", "2_"};
screen gr_screen;
@@ -126,9 +150,9 @@ static auto GammaOption __UNUSED = options::OptionBuilder<float>("Graphics.Gamma
const SCP_vector<std::pair<int, std::pair<const char*, int>>> DetailLevelValues = {{ 0, {"Minimum", 1680}},
{ 1, {"Low", 1161}},
{ 2, {"Medium", 1162}},
{ 3, {"High", 1163}},
{ 1, {"Low", 1160}},
{ 2, {"Medium", 1161}},
{ 3, {"High", 1162}},
{ 4, {"Ultra", 1721}}};
const auto LightingOption __UNUSED = options::OptionBuilder<int>("Graphics.Lighting",
@@ -1452,14 +1476,15 @@ static void init_window_icon() {
bm_release(icon_handle);
}
SCP_string gr_capability_to_string(gr_capability capability)
SCP_string gr_capability_to_human_readable_string(gr_capability capability)
{
switch (capability) {
case CAPABILITY_BPTC:
return "BPTC Texture Compression";
default:
auto capability_it = std::find_if(&gr_capabilities[0], &gr_capabilities[gr_capabilities_num],
[capability](const gr_capability_def &entry) { return entry.capability == capability; });
if (capability_it != &gr_capabilities[gr_capabilities_num])
return capability_it->parse_name;
else
return "Invalid Capability";
}
}
bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode, int d_width, int d_height, int d_depth)
@@ -1576,6 +1601,17 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
}
}
if (!gr_is_viewport_window() && !Cmdline_window_res.has_value()) {
// For whatever reason, it seems that a combination of Win 11 and presumably NVidia GPU's causes weird artifacts.
// These artifacts do not appear in windowed mode, or with an attached renderdoc / nvidia nsight.
// Similarly using the -window_res command line parameter prevents this.
// To the best of our knowledge, this is because all of the aforementioned methods route the rendering through another buffer
// (be that a window, a render overlay from nsight, or an FSO-internal buffer) instead of directly rendering to the OS-provided direct screen backbuffer.
// As the cost of -window_res is one single blit of a fullscreen buffer, it's probably an acceptable compromise to get rid of render artifacts.
// As such, forcibly enable -window_res at the screen resolution here, if we're in fullscreen.
Cmdline_window_res.emplace(static_cast<uint16_t>(width), static_cast<uint16_t>(height));
}
if (d_mode == GR_DEFAULT) {
// OpenGL should be default
mode = GR_OPENGL;
@@ -1692,12 +1728,13 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
mprintf(("Checking graphics capabilities:\n"));
mprintf((" Persistent buffer mapping: %s\n",
gr_is_capable(CAPABILITY_PERSISTENT_BUFFER_MAPPING) ? "Enabled" : "Disabled"));
gr_is_capable(gr_capability::CAPABILITY_PERSISTENT_BUFFER_MAPPING) ? "Enabled" : "Disabled"));
mprintf(("Checking mod required rendering features...\n"));
for (gr_capability ext : Required_render_ext) {
if (!gr_is_capable(ext)) {
Error(LOCATION, "Feature %s required by mod not supported by system.\n", gr_capability_to_string(ext).c_str());
Error(LOCATION, "Feature %s required by mod not supported by system.\n",
gr_capability_to_human_readable_string(ext).c_str());
}
}
mprintf((" All required features are supported.\n"));
@@ -1745,7 +1782,7 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
Gr_inited = 1;
if (!gr_is_capable(CAPABILITY_SHADOWS) && Shadow_quality != ShadowQuality::Disabled) {
if (!gr_is_capable(gr_capability::CAPABILITY_SHADOWS) && Shadow_quality != ShadowQuality::Disabled) {
Warning(LOCATION, "Shadows are enabled, but the system does not fulfill the requirements. Disabling shadows...");
Shadow_quality = ShadowQuality::Disabled;
}
+12 -6
View File
@@ -219,9 +219,6 @@ enum shader_type {
// Shader flags
#define SDR_FLAG_MODEL_SHADOW_MAP (1<<13)
#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)
#define SDR_FLAG_BLUR_HORIZONTAL (1<<0)
@@ -321,7 +318,7 @@ template<> struct hash<vertex_layout> {
};
}
typedef enum gr_capability {
enum class gr_capability {
CAPABILITY_ENVIRONMENT_MAP,
CAPABILITY_NORMAL_MAP,
CAPABILITY_HEIGHT_MAP,
@@ -335,8 +332,17 @@ typedef enum gr_capability {
CAPABILITY_TIMESTAMP_QUERY,
CAPABILITY_SEPARATE_BLEND_FUNCTIONS,
CAPABILITY_PERSISTENT_BUFFER_MAPPING,
CAPABILITY_BPTC
} gr_capability;
CAPABILITY_BPTC,
CAPABILITY_LARGE_SHADER
};
struct gr_capability_def {
gr_capability capability;
const char* parse_name;
};
extern gr_capability_def gr_capabilities[];
extern const size_t gr_capabilities_num;
enum class gr_property
{
+57 -3
View File
@@ -5,6 +5,9 @@
#include "globalincs/systemvars.h"
#include "cmdline/cmdline.h"
#define MODEL_SDR_FLAG_MODE_CPP
#include "def_files/data/effects/model_shader_flags.h"
gr_alpha_blend material_determine_blend_mode(int base_bitmap, bool blending)
{
if ( blending ) {
@@ -728,20 +731,71 @@ uint model_material::get_shader_flags() const
{
uint Shader_flags = 0;
if (!gr_is_capable(gr_capability::CAPABILITY_LARGE_SHADER)) {
Shader_flags |= get_shader_runtime_early_flags();
}
if (Shadow_casting) {
// if we're building the shadow map, we likely only need the flags here and above so bail
Shader_flags |= SDR_FLAG_MODEL_SHADOW_MAP;
Shader_flags |= MODEL_SDR_FLAG_SHADOW_MAP;
return Shader_flags;
}
if (uses_thick_outlines() && gr_is_capable(CAPABILITY_THICK_OUTLINE)) {
Shader_flags |= SDR_FLAG_MODEL_THICK_OUTLINES;
if (uses_thick_outlines() && gr_is_capable(gr_capability::CAPABILITY_THICK_OUTLINE)) {
Shader_flags |= MODEL_SDR_FLAG_THICK_OUTLINES;
}
if (!gr_is_capable(gr_capability::CAPABILITY_LARGE_SHADER)) {
Shader_flags |= get_shader_runtime_flags();
}
return Shader_flags;
}
int model_material::get_shader_runtime_early_flags() const {
int flags = 0;
if (is_batched())
flags |= MODEL_SDR_FLAG_TRANSFORM;
return flags;
}
int model_material::get_shader_runtime_flags() const {
int flags = 0;
if (is_lit())
flags |= MODEL_SDR_FLAG_LIGHT;
if (is_deferred())
flags |= MODEL_SDR_FLAG_DEFERRED;
if (is_hdr())
flags |= MODEL_SDR_FLAG_HDR;
if (get_texture_map(TM_BASE_TYPE) > 0)
flags |= MODEL_SDR_FLAG_DIFFUSE;
if (get_texture_map(TM_GLOW_TYPE) > 0)
flags |= MODEL_SDR_FLAG_GLOW;
if (get_texture_map(TM_SPECULAR_TYPE) > 0 || get_texture_map(TM_SPEC_GLOSS_TYPE) > 0)
flags |= MODEL_SDR_FLAG_SPEC;
if (ENVMAP > 0)
flags |= MODEL_SDR_FLAG_ENV;
if (get_texture_map(TM_NORMAL_TYPE) > 0)
flags |= MODEL_SDR_FLAG_NORMAL;
if (get_texture_map(TM_AMBIENT_TYPE) > 0)
flags |= MODEL_SDR_FLAG_AMBIENT;
if (get_texture_map(TM_MISC_TYPE) > 0)
flags |= MODEL_SDR_FLAG_MISC;
if (get_texture_map(TM_MISC_TYPE) > 0 && is_team_color_set())
flags |= MODEL_SDR_FLAG_TEAMCOLOR;
if (is_fogged())
flags |= MODEL_SDR_FLAG_FOG;
if (is_shadow_receiving())
flags |= MODEL_SDR_FLAG_SHADOWS;
if (get_thrust_scale() > 0.0f)
flags |= MODEL_SDR_FLAG_THRUSTER;
if (is_alpha_mult_active())
flags |= MODEL_SDR_FLAG_ALPHA_MULT;
return flags;
}
particle_material::particle_material():
material()
{
+2
View File
@@ -252,6 +252,8 @@ public:
bool is_batched() const;
uint get_shader_flags() const override;
int get_shader_runtime_early_flags() const;
int get_shader_runtime_flags() const;
void set_fog(int r, int g, int b, float near, float far);
void set_fog();
+18 -19
View File
@@ -1202,9 +1202,6 @@ static bool printNextDebugMessage() {
#endif
static void init_extensions() {
// if S3TC compression is found, then "GL_ARB_texture_compression" must be an extension
Use_compressed_textures = GLAD_GL_EXT_texture_compression_s3tc;
Texture_compression_available = true;
// Swifty put this in, but it's not doing anything. Once he uses it, he can uncomment it.
//int use_base_vertex = Is_Extension_Enabled(OGL_ARB_DRAW_ELEMENTS_BASE_VERTEX);
@@ -1412,8 +1409,8 @@ bool gr_opengl_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps)
GL_max_renderbuffer_size,
GL_max_renderbuffer_size ));
mprintf(( " Can use compressed textures: %s\n", Use_compressed_textures ? NOX("YES") : NOX("NO") ));
mprintf(( " Texture compression available: %s\n", Texture_compression_available ? NOX("YES") : NOX("NO") ));
mprintf(( " S3TC texture support: %s\n", GLAD_GL_EXT_texture_compression_s3tc ? NOX("YES") : NOX("NO") ));
mprintf(( " BPTC texture support: %s\n", GLAD_GL_ARB_texture_compression_bptc ? NOX("YES") : NOX("NO") ));
mprintf(( " Post-processing enabled: %s\n", (Gr_post_processing_enabled) ? "YES" : "NO"));
mprintf(( " Using %s texture filter.\n", (GL_mipmap_filter) ? NOX("trilinear") : NOX("bilinear") ));
@@ -1437,32 +1434,34 @@ bool gr_opengl_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps)
bool gr_opengl_is_capable(gr_capability capability)
{
switch ( capability ) {
case CAPABILITY_ENVIRONMENT_MAP:
case gr_capability::CAPABILITY_ENVIRONMENT_MAP:
return true;
case CAPABILITY_NORMAL_MAP:
case gr_capability::CAPABILITY_NORMAL_MAP:
return Cmdline_normal ? true : false;
case CAPABILITY_HEIGHT_MAP:
case gr_capability::CAPABILITY_HEIGHT_MAP:
return Cmdline_height ? true : false;
case CAPABILITY_SOFT_PARTICLES:
case CAPABILITY_DISTORTION:
case gr_capability::CAPABILITY_SOFT_PARTICLES:
case gr_capability::CAPABILITY_DISTORTION:
return Gr_enable_soft_particles && !Cmdline_no_fbo && !Cmdline_no_geo_sdr_effects;
case CAPABILITY_POST_PROCESSING:
case gr_capability::CAPABILITY_POST_PROCESSING:
return Gr_post_processing_enabled && !Cmdline_no_fbo;
case CAPABILITY_DEFERRED_LIGHTING:
case gr_capability::CAPABILITY_DEFERRED_LIGHTING:
return !Cmdline_no_fbo && light_deferred_enabled();
case CAPABILITY_SHADOWS:
case CAPABILITY_THICK_OUTLINE:
case gr_capability::CAPABILITY_SHADOWS:
case gr_capability::CAPABILITY_THICK_OUTLINE:
return !Cmdline_no_geo_sdr_effects;
case CAPABILITY_BATCHED_SUBMODELS:
case gr_capability::CAPABILITY_BATCHED_SUBMODELS:
return true;
case CAPABILITY_TIMESTAMP_QUERY:
case gr_capability::CAPABILITY_TIMESTAMP_QUERY:
return GLAD_GL_ARB_timer_query != 0; // Timestamp queries are available from 3.3 onwards
case CAPABILITY_SEPARATE_BLEND_FUNCTIONS:
case gr_capability::CAPABILITY_SEPARATE_BLEND_FUNCTIONS:
return GLAD_GL_ARB_draw_buffers_blend != 0; // We need an OpenGL extension for this
case CAPABILITY_PERSISTENT_BUFFER_MAPPING:
case gr_capability::CAPABILITY_PERSISTENT_BUFFER_MAPPING:
return GLAD_GL_ARB_buffer_storage != 0;
case CAPABILITY_BPTC:
case gr_capability::CAPABILITY_BPTC:
return GLAD_GL_ARB_texture_compression_bptc != 0;
case gr_capability::CAPABILITY_LARGE_SHADER:
return !Cmdline_no_large_shaders;
}
return false;
+13 -5
View File
@@ -68,7 +68,7 @@ void gr_opengl_deferred_lighting_begin(bool clearNonColorBufs)
Deferred_lighting = true;
GL_state.ColorMask(true, true, true, true);
GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT6 };
GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5 };
if (Cmdline_msaa_enabled > 0) {
//Ensure MSAA Mode if necessary
@@ -226,7 +226,7 @@ void gr_opengl_deferred_lighting_finish()
opengl_shader_set_current(gr_opengl_maybe_create_shader(SDR_TYPE_DEFERRED_LIGHTING, 0));
// Render on top of the composite buffer texture
glDrawBuffer(GL_COLOR_ATTACHMENT6);
glDrawBuffer(GL_COLOR_ATTACHMENT5);
glReadBuffer(GL_COLOR_ATTACHMENT4);
glBlitFramebuffer(0,
0,
@@ -523,8 +523,10 @@ void gr_opengl_deferred_lighting_finish()
opengl_draw_full_screen_textured(0.0f, 0.0f, 1.0f, 1.0f);
}
else if (The_mission.volumetrics && !override_fog) {
else if (The_mission.volumetrics && The_mission.volumetrics->get_enabled() && !override_fog) {
GR_DEBUG_SCOPE("Volumetric Nebulae");
TRACE_SCOPE(tracing::Volumetrics);
const volumetric_nebula& neb = *The_mission.volumetrics;
Assertion(neb.isVolumeBitmapValid(), "The volumetric nebula was not properly initialized!");
@@ -550,9 +552,11 @@ void gr_opengl_deferred_lighting_finish()
uint32_t array_index;
gr_set_texture_addressing(TMAP_ADDRESS_CLAMP);
gr_opengl_tcache_set(neb.getVolumeBitmapHandle(), TCACHE_TYPE_3DTEX, &u_scale, &v_scale, &array_index, 3);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (neb.getNoiseActive()) {
gr_set_texture_addressing(TMAP_ADDRESS_WRAP);
gr_opengl_tcache_set(neb.getNoiseVolumeBitmapHandle(), TCACHE_TYPE_3DTEX, &u_scale, &v_scale, &array_index, 4);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
}
@@ -567,8 +571,12 @@ void gr_opengl_deferred_lighting_finish()
data->nebPos = neb.getPos();
data->nebSize = neb.getSize();
data->stepsize = neb.getStepsize();
data->globalstepalpha = neb.getStepalpha();
data->opacitydistance = neb.getOpacityDistance();
data->alphalimit = neb.getAlphaLim();
data->nebColor[0] = std::get<0>(neb.getNebulaColor());
data->nebColor[1] = std::get<1>(neb.getNebulaColor());
data->nebColor[2] = std::get<2>(neb.getNebulaColor());
data->udfScale = neb.getUDFScale();
data->emissiveSpreadFactor = neb.getEmissiveSpread();
data->emissiveIntensity = neb.getEmissiveIntensity();
data->emissiveFalloff = neb.getEmissiveFalloff();
@@ -598,7 +606,7 @@ void gr_opengl_deferred_lighting_finish()
else {
// Transfer the resolved lighting back to the color texture
// TODO: Maybe this could be improved so that it doesn't require the copy back operation?
glReadBuffer(GL_COLOR_ATTACHMENT6);
glReadBuffer(GL_COLOR_ATTACHMENT5);
glBlitFramebuffer(0,
0,
gr_screen.max_w,
+5 -31
View File
@@ -44,7 +44,6 @@ GLuint Scene_specular_texture_ms;
GLuint Scene_emissive_texture_ms;
GLuint Scene_composite_texture;
GLuint Scene_luminance_texture;
GLuint Scene_effect_texture;
GLuint Scene_depth_texture;
GLuint Scene_depth_texture_ms;
GLuint Cockpit_depth_texture;
@@ -105,7 +104,6 @@ void opengl_setup_scene_textures()
Scene_ldr_texture = 0;
Scene_color_texture = 0;
Scene_effect_texture = 0;
Scene_depth_texture = 0;
return;
}
@@ -252,7 +250,7 @@ void opengl_setup_scene_textures()
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, Scene_texture_width, Scene_texture_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
opengl_set_object_label(GL_TEXTURE, Scene_composite_texture, "Scene Composite texture");
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT6, GL_TEXTURE_2D, Scene_composite_texture, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT5, GL_TEXTURE_2D, Scene_composite_texture, 0);
//Set up luminance texture (used as input for FXAA)
// also used as a light accumulation buffer during the deferred pass
@@ -271,24 +269,6 @@ void opengl_setup_scene_textures()
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, Scene_texture_width, Scene_texture_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
opengl_set_object_label(GL_TEXTURE, Scene_luminance_texture, "Scene Luminance texture");
// setup effect texture
glGenTextures(1, &Scene_effect_texture);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D);
GL_state.Texture.Enable(Scene_effect_texture);
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);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, Scene_texture_width, Scene_texture_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
opengl_set_object_label(GL_TEXTURE, Scene_effect_texture, "Scene Effect texture");
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT5, GL_TEXTURE_2D, Scene_effect_texture, 0);
// setup cockpit depth texture
glGenTextures(1, &Cockpit_depth_texture);
@@ -356,9 +336,6 @@ void opengl_setup_scene_textures()
glDeleteTextures(1, &Scene_emissive_texture);
Scene_emissive_texture = 0;
glDeleteTextures(1, &Scene_effect_texture);
Scene_effect_texture = 0;
glDeleteTextures(1, &Scene_depth_texture);
Scene_depth_texture = 0;
@@ -667,11 +644,6 @@ void opengl_scene_texture_shutdown()
Scene_emissive_texture = 0;
}
if ( Scene_effect_texture ) {
glDeleteTextures(1, &Scene_effect_texture);
Scene_effect_texture = 0;
}
if ( Scene_depth_texture ) {
glDeleteTextures(1, &Scene_depth_texture);
Scene_depth_texture = 0;
@@ -729,7 +701,7 @@ void gr_opengl_scene_texture_begin()
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
} else {
GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT6 };
GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5 };
glDrawBuffers(6, buffers);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
@@ -832,6 +804,8 @@ void gr_opengl_copy_effect_texture()
return;
}
//Make sure we're reading from the up-to-date color texture
glReadBuffer(GL_COLOR_ATTACHMENT0);
glDrawBuffer(GL_COLOR_ATTACHMENT5);
glBlitFramebuffer(0, 0, gr_screen.max_w, gr_screen.max_h, 0, 0, gr_screen.max_w, gr_screen.max_h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
@@ -1199,7 +1173,7 @@ void gr_opengl_stop_decal_pass() {
GL_COLOR_ATTACHMENT2,
GL_COLOR_ATTACHMENT3,
GL_COLOR_ATTACHMENT4,
GL_COLOR_ATTACHMENT6,
GL_COLOR_ATTACHMENT5,
};
glDrawBuffers(6, buffers2);
}
-2
View File
@@ -31,7 +31,6 @@ extern GLuint Scene_normal_texture_ms;
extern GLuint Scene_specular_texture_ms;
extern GLuint Scene_emissive_texture_ms;
extern GLuint Scene_luminance_texture;
extern GLuint Scene_effect_texture;
extern GLuint Scene_composite_texture;
extern GLuint Scene_depth_texture;
extern GLuint Scene_depth_texture_ms;
@@ -156,7 +155,6 @@ extern int Scene_texture_initialized;
extern GLuint Scene_color_texture;
extern GLuint Scene_ldr_texture;
extern GLuint Scene_luminance_texture;
extern GLuint Scene_effect_texture;
extern int Scene_texture_width;
extern int Scene_texture_height;
+12 -7
View File
@@ -1,5 +1,16 @@
#include "gropenglopenxr.h"
// this block should go before the #includes otherwise MSVC will sometimes warn about APIENTRY redefinition
// (glad.h checks for redefinition of the symbol, but minwindef.h does not)
#ifdef WIN32
#define XR_USE_PLATFORM_WIN32
#include <unknwn.h>
#endif
// the other platforms do not go before the #includes because this will cause conflicts from symbols defined in XLib,
// specifically None and Always; see https://stackoverflow.com/questions/22476110/c-compiling-error-including-x11-x-h-x11-xlib-h
#include "io/cursor.h"
#include "io/mouse.h"
#include "graphics/matrix.h"
@@ -10,13 +21,7 @@
#include "graphics/opengl/ShaderProgram.h"
#include "osapi/osapi.h"
#ifdef WIN32
#define XR_USE_PLATFORM_WIN32
#include <unknwn.h>
#elif defined __APPLE_CC__
#if defined __APPLE_CC__
//Not supported
+148 -13
View File
@@ -183,16 +183,12 @@ static opengl_shader_type_t GL_shader_types[] = {
* When adding a new shader variant for a shader, list all associated uniforms and attributes here
*/
static opengl_shader_variant_t GL_shader_variants[] = {
{SDR_TYPE_MODEL, true, SDR_FLAG_MODEL_SHADOW_MAP, "FLAG_SHADOW_MAP", {}, "Shadow Mapping"},
//Model shader flags, both those set always as a compile flag as well as those that are usually runtime checks, need to be defined in this file
#define MODEL_SDR_FLAG_MODE_CPP_ARRAY
#include "def_files/data/effects/model_shader_flags.h"
#undef MODEL_SDR_FLAG_MODE_CPP_ARRAY
{SDR_TYPE_MODEL, true, SDR_FLAG_MODEL_THICK_OUTLINES, "FLAG_THICK_OUTLINE", {}, "Thick outlines"},
{SDR_TYPE_EFFECT_PARTICLE,
true,
SDR_FLAG_PARTICLE_POINT_GEN,
"FLAG_EFFECT_GEOMETRY",
{opengl_vert_attrib::UVEC},
"Geometry shader point-based particles"},
{SDR_TYPE_EFFECT_PARTICLE, true, SDR_FLAG_PARTICLE_POINT_GEN, "FLAG_EFFECT_GEOMETRY", {opengl_vert_attrib::UVEC}, "Geometry shader point-based particles"},
{SDR_TYPE_POST_PROCESS_BLUR, false, SDR_FLAG_BLUR_HORIZONTAL, "PASS_0", {}, "Horizontal blur pass"},
@@ -394,12 +390,68 @@ static void handle_includes_impl(SCP_vector<SCP_string>& include_stack,
auto current_source_number = include_counter + 1;
const char* INCLUDE_STRING = "#include";
const char* CONDITIONAL_INCLUDE_STRING = "#conditional_include";
SCP_stringstream input(original);
int line_num = 1;
for (SCP_string line; std::getline(input, line);) {
auto include_start = line.find(INCLUDE_STRING);
auto include_start = line.find(CONDITIONAL_INCLUDE_STRING);
if (include_start != SCP_string::npos) {
//This is a conditional include. Figure out whether to include, or whether not to.
// Conditional include syntax: #conditional_include (+|-)"capability" "filename"
// On +, include if capability is available, on -, include if not available
include_start += strlen(CONDITIONAL_INCLUDE_STRING) + 1;
bool require_capability = true;
switch(line.at(include_start)) {
case '+':
require_capability = true;
break;
case '-':
require_capability = false;
break;
default:
Error(LOCATION,
"Shader %s:%d: Malformed conditional_include line. Expected + or -, got %c.",
filename.c_str(),
line_num,
line.at(include_start));
break;
}
auto first_quote = line.find('"', include_start);
auto second_quote = line.find('"', first_quote + 1);
if (first_quote == SCP_string::npos || second_quote == SCP_string::npos) {
Error(LOCATION,
"Shader %s:%d: Malformed conditional_include line. Could not find both quote characters for capability.",
filename.c_str(),
line_num);
}
auto condition = line.substr(first_quote + 1, second_quote - first_quote - 1);
auto capability = std::find_if(&gr_capabilities[0], &gr_capabilities[gr_capabilities_num],
[condition](const gr_capability_def &ext_pair) { return !stricmp(ext_pair.parse_name, condition.c_str()); });
if (capability == &gr_capabilities[gr_capabilities_num]) {
Error(LOCATION,
"Shader %s:%d: Malformed conditional_include line. Capability %s does not exist.",
filename.c_str(),
line_num,
condition.c_str());
}
//Prepare for including if capability is correct, skip otherwise.
if(gr_is_capable(capability->capability) == require_capability)
include_start = second_quote + 1 - strlen(INCLUDE_STRING);
else
include_start = SCP_string::npos - 1;
}
else {
//Only search for normal includes if it's not a conditional include.
include_start = line.find(INCLUDE_STRING);
}
if (include_start != SCP_string::npos && include_start != SCP_string::npos - 1) {
auto first_quote = line.find('"', include_start + strlen(INCLUDE_STRING));
auto second_quote = line.find('"', first_quote + 1);
@@ -440,7 +492,7 @@ static void handle_includes_impl(SCP_vector<SCP_string>& include_stack,
// We are done with the include file so now we can return to the original file
output << "#line " << line_num + 1 << " " << current_source_number << "\n";
} else {
} else if (include_start != SCP_string::npos - 1) {
output << line << "\n";
}
@@ -460,6 +512,89 @@ static SCP_string handle_includes(const char* filename, const SCP_string& origin
return output.str();
}
static SCP_string handle_predefines(const char* filename, const SCP_string& original){
SCP_stringstream output;
SCP_unordered_map<SCP_string, SCP_string> defines;
const char* PREDEFINE_STRING = "#predefine";
const char* PREREPLACE_STRING = "#prereplace";
SCP_stringstream input(original);
for (SCP_string line; std::getline(input, line);) {
auto predefine_start = line.find(PREDEFINE_STRING);
auto prereplace_start = line.find(PREREPLACE_STRING);
if (predefine_start != SCP_string::npos){
predefine_start += strlen(PREDEFINE_STRING);
auto token_start = line.find(' ', predefine_start);
auto token_end = line.find(' ', token_start + 1);
if (token_start == SCP_string::npos || token_end == SCP_string::npos) {
Error(LOCATION,
"Shader %s: Malformed predefine line. Could not find define token.",
filename);
}
auto token = line.substr(token_start + 1, token_end - token_start - 1);
auto replaceWith = line.substr(token_end + 1);
auto replaceStrToken = replaceWith.find("%s");
if (replaceStrToken == SCP_string::npos || replaceWith.find("%s", replaceStrToken + 1) != SCP_string::npos){
Error(LOCATION,
"Shader %s: Malformed predefine line. Replacing string must have exactly one %%s.",
filename);
}
if (defines.find(token) != defines.end()) {
Error(LOCATION,
"Shader %s: Malformed predefine line. Token %s is already defined.",
filename,
token.c_str());
}
defines.emplace(std::move(token), std::move(replaceWith));
output << "\n"; //At this point, don't mess with the linecount
}
else if (prereplace_start != SCP_string::npos){
prereplace_start += strlen(PREREPLACE_STRING);
auto token_start = line.find(' ', prereplace_start);
auto token_end = line.find(' ', token_start + 1);
if (token_start == SCP_string::npos || token_end == SCP_string::npos) {
Error(LOCATION,
"Shader %s: Malformed prereplace line. Could not find define token.",
filename);
}
auto token = line.substr(token_start + 1, token_end - token_start - 1);
auto replaceArg = line.substr(token_end + 1);
auto replaceWithIt = defines.find(token);
if (replaceWithIt == defines.end()) {
Error(LOCATION,
"Shader %s: Malformed prereplace line. Could not find token %s.",
filename,
token.c_str());
}
size_t size = replaceWithIt->second.length() - 1 + replaceArg.size();
std::unique_ptr<char[]> buffer = make_unique<char[]>(size);
snprintf(buffer.get(), size, replaceWithIt->second.c_str(), replaceArg.c_str());
buffer[size - 1] = '\0';
output << buffer.get() << "\n";
}
else {
output << line << "\n";
}
}
return output.str();
}
static SCP_vector<SCP_string>
opengl_get_shader_content(shader_type type_id, const char* filename, int flags, bool has_geo_shader, bool spirv_shader)
{
@@ -470,7 +605,7 @@ opengl_get_shader_content(shader_type type_id, const char* filename, int flags,
} else {
parts.push_back(opengl_shader_get_header(type_id, flags, has_geo_shader));
parts.push_back(handle_includes(filename, opengl_load_shader(filename)));
parts.push_back(handle_predefines(filename, handle_includes(filename, opengl_load_shader(filename))));
}
return parts;
@@ -936,7 +1071,7 @@ void opengl_shader_init()
opengl_purge_old_shader_cache();
// compile effect shaders
if (gr_opengl_is_capable(CAPABILITY_SOFT_PARTICLES)) {
if (gr_opengl_is_capable(gr_capability::CAPABILITY_SOFT_PARTICLES)) {
// only compile soft particle shaders if they are supported, as to avoid introducing geo shaders if they aren't needed
gr_opengl_maybe_create_shader(SDR_TYPE_EFFECT_PARTICLE, 0);
gr_opengl_maybe_create_shader(SDR_TYPE_EFFECT_PARTICLE, SDR_FLAG_PARTICLE_POINT_GEN);
+1 -1
View File
@@ -1225,7 +1225,7 @@ int opengl_compress_image( ubyte **compressed_data, ubyte *in_data, int width, i
{
Assert( in_data != NULL );
if ( !Texture_compression_available ) {
if ( !GLAD_GL_EXT_texture_compression_s3tc ) {
return 0;
}
+31 -13
View File
@@ -39,6 +39,9 @@
#include "render/3d.h"
#include "weapon/trails.h"
#define MODEL_SDR_FLAG_MODE_CPP
#include "def_files/data/effects/model_shader_flags.h"
extern int GLOWMAP;
extern int SPECMAP;
extern int SPECGLOSSMAP;
@@ -843,18 +846,33 @@ void opengl_tnl_set_model_material(model_material *material_info)
// it is uncritical at this time as texture reads are gated behind feature flags in the shader.
// This will be fixed in future cleanups, where we plan to introduce engine-generated default textures to substitute
// if the material doesn't provide anything.
Current_shader->program->Uniforms.setTextureUniform("sBasemap", 0);
Current_shader->program->Uniforms.setTextureUniform("sGlowmap", 1);
Current_shader->program->Uniforms.setTextureUniform("sSpecmap", 2);
Current_shader->program->Uniforms.setTextureUniform("sEnvmap", 3);
Current_shader->program->Uniforms.setTextureUniform("sIrrmap", 11);
Current_shader->program->Uniforms.setTextureUniform("sNormalmap", 4);
Current_shader->program->Uniforms.setTextureUniform("sHeightmap", 5);
Current_shader->program->Uniforms.setTextureUniform("sAmbientmap", 6);
Current_shader->program->Uniforms.setTextureUniform("sMiscmap", 7);
Current_shader->program->Uniforms.setTextureUniform("shadow_map", 8);
const bool setAllUniforms = gr_is_capable(gr_capability::CAPABILITY_LARGE_SHADER);
const int flags = material_info->get_shader_runtime_early_flags() | material_info->get_shader_runtime_flags();
if (setAllUniforms || (flags & MODEL_SDR_FLAG_DIFFUSE))
Current_shader->program->Uniforms.setTextureUniform("sBasemap", 0);
if (setAllUniforms || (flags & MODEL_SDR_FLAG_GLOW))
Current_shader->program->Uniforms.setTextureUniform("sGlowmap", 1);
if (setAllUniforms || (flags & MODEL_SDR_FLAG_SPEC))
Current_shader->program->Uniforms.setTextureUniform("sSpecmap", 2);
if (setAllUniforms || (flags & MODEL_SDR_FLAG_ENV)) {
Current_shader->program->Uniforms.setTextureUniform("sEnvmap", 3);
Current_shader->program->Uniforms.setTextureUniform("sIrrmap", 11);
}
if (setAllUniforms || (flags & MODEL_SDR_FLAG_NORMAL))
Current_shader->program->Uniforms.setTextureUniform("sNormalmap", 4);
if (setAllUniforms || (flags & MODEL_SDR_FLAG_AMBIENT))
Current_shader->program->Uniforms.setTextureUniform("sAmbientmap", 6);
if (setAllUniforms || (flags & MODEL_SDR_FLAG_MISC))
Current_shader->program->Uniforms.setTextureUniform("sMiscmap", 7);
if (setAllUniforms || (flags & MODEL_SDR_FLAG_SHADOWS))
Current_shader->program->Uniforms.setTextureUniform("shadow_map", 8);
Current_shader->program->Uniforms.setTextureUniform("sFramebuffer", 9);
Current_shader->program->Uniforms.setTextureUniform("transform_tex", 10);
if (setAllUniforms || (flags & MODEL_SDR_FLAG_TRANSFORM))
Current_shader->program->Uniforms.setTextureUniform("transform_tex", 10);
//No shader ever defines this, so don't push it.
//Current_shader->program->Uniforms.setTextureUniform("sHeightmap", 5);
if (material_info->get_texture_map(TM_BASE_TYPE) > 0) {
gr_opengl_tcache_set(material_info->get_texture_map(TM_BASE_TYPE),
@@ -941,7 +959,7 @@ void opengl_tnl_set_model_material(model_material *material_info)
if (material_info->get_animated_effect() > 0) {
if (Scene_framebuffer_in_frame) {
GL_state.Texture.Enable(9, GL_TEXTURE_2D, Scene_effect_texture);
GL_state.Texture.Enable(9, GL_TEXTURE_2D, Scene_composite_texture);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
} else {
GL_state.Texture.Enable(9, GL_TEXTURE_2D, Framebuffer_fallback_texture_id);
@@ -1032,7 +1050,7 @@ void opengl_tnl_set_material_distortion(distortion_material* material_info)
});
Current_shader->program->Uniforms.setTextureUniform("frameBuffer", 2);
GL_state.Texture.Enable(2, GL_TEXTURE_2D, Scene_effect_texture);
GL_state.Texture.Enable(2, GL_TEXTURE_2D, Scene_composite_texture);
Current_shader->program->Uniforms.setTextureUniform("distMap", 3);
if (material_info->get_thruster_rendering()) {
+4 -15
View File
@@ -224,11 +224,7 @@ bool gr_lightshafts_enabled()
return false;
}
if (Using_in_game_options) {
return graphics::LightshaftsOption->getValue();
} else {
return !Cmdline_force_lightshaft_off;
}
return graphics::LightshaftsOption->getValue();
}
int gr_bloom_intensity()
@@ -241,11 +237,7 @@ int gr_bloom_intensity()
return 0;
}
if (Using_in_game_options) {
return graphics::BloomIntensityOption->getValue();
} else {
return Cmdline_bloom_intensity;
}
return graphics::BloomIntensityOption->getValue();
}
void gr_set_bloom_intensity(int intensity)
@@ -254,9 +246,6 @@ void gr_set_bloom_intensity(int intensity)
return;
}
if (Using_in_game_options) {
graphics::Post_processing_bloom_intensity = intensity;
} else {
Cmdline_bloom_intensity = intensity;
}
graphics::Post_processing_bloom_intensity = intensity;
options::OptionsManager::instance()->set_ingame_range_option("Graphics.BloomIntensity", intensity);
}
+3 -3
View File
@@ -37,7 +37,7 @@ bool Shadow_quality_uses_mod_option = false;
auto ShadowQualityOption = options::OptionBuilder<ShadowQuality>("Graphics.Shadows",
std::pair<const char*, int>{"Shadow Quality", 1750},
std::pair<const char*, int>{"The quality of the shadows", 1751})
.values({{ShadowQuality::Disabled, {"Disabled", 1779}},
.values({{ShadowQuality::Disabled, {"Disabled", 413}},
{ShadowQuality::Low, {"Low", 1160}},
{ShadowQuality::Medium, {"Medium", 1161}},
{ShadowQuality::High, {"High", 1162}},
@@ -494,8 +494,8 @@ void shadows_render_all(fov_t fov, matrix *eye_orient, vec3d *eye_pos)
render_info.set_object_number(OBJ_INDEX(objp));
render_info.set_flags(MR_IS_ASTEROID | MR_NO_TEXTURING | MR_NO_LIGHTING);
model_clear_instance( Asteroid_info[Asteroids[objp->instance].asteroid_type].model_num[Asteroids[objp->instance].asteroid_subtype]);
model_render_queue(&render_info, &scene, Asteroid_info[Asteroids[objp->instance].asteroid_type].model_num[Asteroids[objp->instance].asteroid_subtype], &objp->orient, &objp->pos);
model_clear_instance( Asteroid_info[Asteroids[objp->instance].asteroid_type].subtypes[Asteroids[objp->instance].asteroid_subtype].model_number);
model_render_queue(&render_info, &scene, Asteroid_info[Asteroids[objp->instance].asteroid_type].subtypes[Asteroids[objp->instance].asteroid_subtype].model_number, &objp->orient, &objp->pos);
}
break;
+5 -35
View File
@@ -6,6 +6,8 @@
#include "light.h"
#include "globalincs/systemvars.h"
#include "shadows.h"
#define MODEL_SDR_FLAG_MODE_CPP
#include "def_files/data/effects/model_shader_flags.h"
namespace {
@@ -55,39 +57,7 @@ void convert_model_material(model_uniform_data* data_out,
data_out->anim_timer = 0;
data_out->use_clip_plane = 0;
data_out->flags = 0;
if (material.is_lit())
data_out->flags |= MODEL_SDR_FLAG_LIGHT;
if (material.is_deferred())
data_out->flags |= MODEL_SDR_FLAG_DEFERRED;
if (material.is_hdr())
data_out->flags |= MODEL_SDR_FLAG_HDR;
if (material.get_texture_map(TM_BASE_TYPE) > 0)
data_out->flags |= MODEL_SDR_FLAG_DIFFUSE;
if (material.get_texture_map(TM_GLOW_TYPE) > 0)
data_out->flags |= MODEL_SDR_FLAG_GLOW;
if (material.get_texture_map(TM_SPECULAR_TYPE) > 0 || material.get_texture_map(TM_SPEC_GLOSS_TYPE) > 0)
data_out->flags |= MODEL_SDR_FLAG_SPEC;
if (ENVMAP > 0)
data_out->flags |= MODEL_SDR_FLAG_ENV;
if (material.get_texture_map(TM_NORMAL_TYPE) > 0)
data_out->flags |= MODEL_SDR_FLAG_NORMAL;
if (material.get_texture_map(TM_AMBIENT_TYPE) > 0)
data_out->flags |= MODEL_SDR_FLAG_AMBIENT;
if (material.get_texture_map(TM_MISC_TYPE) > 0)
data_out->flags |= MODEL_SDR_FLAG_MISC;
if (material.get_texture_map(TM_MISC_TYPE) > 0 && material.is_team_color_set())
data_out->flags |= MODEL_SDR_FLAG_TEAMCOLOR;
if (material.is_fogged())
data_out->flags |= MODEL_SDR_FLAG_FOG;
if (material.is_batched())
data_out->flags |= MODEL_SDR_FLAG_TRANSFORM;
if (material.is_shadow_receiving())
data_out->flags |= MODEL_SDR_FLAG_SHADOWS;
if (material.get_thrust_scale() > 0.0f)
data_out->flags |= MODEL_SDR_FLAG_THRUSTER;
if (material.is_alpha_mult_active())
data_out->flags |= MODEL_SDR_FLAG_ALPHA_MULT;
data_out->flags = material.get_shader_runtime_early_flags() | material.get_shader_runtime_flags();
if (material.get_animated_effect() >= 0) {
data_out->anim_timer = material.get_animated_effect_time();
@@ -217,7 +187,7 @@ void convert_model_material(model_uniform_data* data_out,
data_out->fardist = Shadow_cascade_distances[3];
}
if (shader_flags & SDR_FLAG_MODEL_SHADOW_MAP) {
if (shader_flags & MODEL_SDR_FLAG_SHADOW_MAP) {
for (size_t i = 0; i < MAX_SHADOW_CASCADES; ++i) {
data_out->shadow_proj_matrix[i] = Shadow_proj_matrix[i];
}
@@ -267,7 +237,7 @@ void convert_model_material(model_uniform_data* data_out,
}
}
if ( shader_flags & SDR_FLAG_MODEL_THICK_OUTLINES ) {
if ( shader_flags & MODEL_SDR_FLAG_THICK_OUTLINES ) {
data_out->outlineWidth = material.get_outline_thickness();
}
+1 -1
View File
@@ -59,7 +59,7 @@ UniformBufferManager::UniformBufferManager()
bool success = gr_get_property(gr_property::UNIFORM_BUFFER_OFFSET_ALIGNMENT, &_offset_alignment);
Assertion(success, "Uniform buffer usage requires a backend which allows to query the offset alignment!");
_use_persistent_mapping = gr_is_capable(CAPABILITY_PERSISTENT_BUFFER_MAPPING);
_use_persistent_mapping = gr_is_capable(gr_capability::CAPABILITY_PERSISTENT_BUFFER_MAPPING);
_segment_fences.fill(nullptr);
changeSegmentSize(4096);
+4 -1
View File
@@ -319,10 +319,13 @@ struct volumetric_fog_data {
float stepsize;
vec3d nebPos;
float globalstepalpha;
float opacitydistance;
vec3d nebSize;
float alphalimit;
float nebColor[3];
float udfScale;
float emissiveSpreadFactor;
float emissiveIntensity;
+24 -28
View File
@@ -2844,43 +2844,39 @@ int hud_get_dock_time( object *docker_objp )
/**
* @brief Locate the closest support ship which is trying to dock with player
*
* @param objnum Object number of player
* @param objp Object of player
* @return Number of support ship, -1 if there is no support ship currently trying to dock
*/
int hud_support_find_closest( int objnum )
int hud_support_find_closest( object *objp )
{
ai_info *aip;
object *objp;
int i;
objp = &Objects[objnum];
// invalid if player is dead or a ghost
if (objp->flags[Object::Object_Flags::Should_be_dead] || objp->type != OBJ_SHIP)
return -1;
for (auto sop: list_range(&Ship_obj_list)) {
if (Objects[sop->objnum].flags[Object::Object_Flags::Should_be_dead])
continue;
if ( Ship_info[Ships[Objects[sop->objnum].instance].ship_info_index].flags[Ship::Info_Flags::Support] ) {
int pship_index, sindex;
auto shipp = &Ships[Objects[sop->objnum].instance];
if ( Ship_info[shipp->ship_info_index].flags[Ship::Info_Flags::Support] ) {
// make sure support ship is not dying
auto shipp = &Ships[Objects[sop->objnum].instance];
if ( !(shipp->flags[Ship::Ship_Flags::Dying] || shipp->flags[Ship::Ship_Flags::Exploded]) ) {
Assert( objp->type == OBJ_SHIP );
aip = &Ai_info[Ships[Objects[sop->objnum].instance].ai_index];
pship_index = objp->instance;
auto aip = &Ai_info[shipp->ai_index];
// we must check all goals for this support ship -- not just the first one
for ( i = 0; i < MAX_AI_GOALS; i++ ) {
for ( int i = 0; i < MAX_AI_GOALS; i++ ) {
// we can use == in the next statement (and should) since a ship will only ever be
// following one order at a time.
if ( aip->goals[i].ai_mode == AI_GOAL_REARM_REPAIR ) {
Assert( aip->goals[i].target_name );
sindex = ship_name_lookup( aip->goals[i].target_name );
if ( sindex == pship_index )
return sop->objnum;
auto entry = ship_registry_get( aip->goals[i].target_name );
if (entry && entry->status == ShipStatus::PRESENT) {
if ( entry->shipnum == objp->instance )
return sop->objnum;
}
}
}
}
@@ -2902,7 +2898,7 @@ void hud_support_view_update()
// If we haven't determined yet who the rearm ship is, try to!
if (Hud_support_objnum == -1) {
Hud_support_objnum = hud_support_find_closest( OBJ_INDEX(Player_obj) );
Hud_support_objnum = hud_support_find_closest( Player_obj );
if ( Hud_support_objnum >= 0 ) {
Hud_support_obj_sig = Objects[Hud_support_objnum].signature;
Hud_support_target_sig = Player_obj->signature;
@@ -3063,7 +3059,7 @@ void HudGaugeSupport::render(float /*frametime*/)
renderStringAlignCenter(position[0], position[1] + text_val_offset_y, w, outstr);
} else {
if ( Hud_support_objnum == -1 ) {
if (The_mission.support_ships.arrival_location == ARRIVE_FROM_DOCK_BAY)
if (The_mission.support_ships.arrival_location == ArrivalLocation::FROM_DOCK_BAY)
{
strcpy_s(outstr, XSTR( "exiting hangar", 1622));
}
@@ -3754,10 +3750,6 @@ int hud_objective_notify_active()
* @details Since the player's view vector may be different from the ship's forward vector,
* we calculate the offset of those two in pixels and store the x and y offsets in
* variables HUD_nose_x and HUD_nose_y (Swifty)
*
* @param viewer_obj Object, likely to be player
* @param wiggedy_wack
* @param eye_orient
*/
void HUD_set_offsets()
{
@@ -3767,6 +3759,8 @@ void HUD_set_offsets()
} else {
HUD_get_nose_coordinates(&HUD_nose_x, &HUD_nose_y);
}
hud_reticle_set_flight_cursor_offset();
}
/**
@@ -3914,7 +3908,9 @@ void hud_page_in()
HudGauge* hud_get_custom_gauge(const char* name, bool check_all_gauges)
{
auto player_sip = Player_ship->ship_info_index < 0 ? nullptr : &Ship_info[Player_ship->ship_info_index];
ship_info *player_sip = nullptr;
if (Player_ship && Player_ship->ship_info_index >= 0)
player_sip = &Ship_info[Player_ship->ship_info_index];
// go through all gauges for all ships and defaults
if (check_all_gauges) {
@@ -3977,9 +3973,9 @@ int hud_get_default_gauge_index(const char *name)
return -1;
}
HudGauge *hud_get_gauge(const char *name)
HudGauge *hud_get_gauge(const char *name, bool check_all_custom_gauges)
{
auto gauge = hud_get_custom_gauge(name);
auto gauge = hud_get_custom_gauge(name, check_all_custom_gauges);
if (gauge == nullptr)
{
int idx = hud_get_default_gauge_index(name);
+7 -2
View File
@@ -112,6 +112,11 @@ extern float Player_rearm_eta;
extern int Hud_max_targeting_range;
// maps of hud gauges configs to apply to ships as parsed in ships.tbl
// this is cleared once parsing is completed
// First string in the pair is the gauge name, second is the ship name
extern SCP_vector<std::pair<SCP_string, SCP_string>> Hud_parsed_ships;
void HUD_init_colors();
void HUD_init();
void hud_scripting_close(lua_State*);
@@ -194,7 +199,7 @@ void hud_maybe_render_multi_text();
int hud_get_draw();
void hud_toggle_draw();
int hud_disabled();
int hud_support_find_closest( int objnum );
int hud_support_find_closest( object *objp );
// Goober5000
void hud_set_draw(int draw);
@@ -593,7 +598,7 @@ public:
HudGauge *hud_get_custom_gauge(const char *name, bool check_all_gauges = false);
int hud_get_default_gauge_index(const char *name);
HudGauge *hud_get_gauge(const char *name);
HudGauge *hud_get_gauge(const char *name, bool check_all_custom_gauges = false);
extern SCP_vector<std::unique_ptr<HudGauge>> default_hud_gauges;
+2 -2
View File
@@ -132,8 +132,8 @@ void parse_ssm(const char *filename)
{
int temp = atoi(unique_id);
if ((temp < 0) || (temp >= Num_fireball_types))
error_display(0, "Fireball index [%d] out of range (should be 0-%d) for SSM strike [%s]", temp, Num_fireball_types - 1, s->name);
if (!SCP_vector_inbounds(Fireball_info, temp))
error_display(0, "Fireball index [%d] out of range (should be 0-%d) for SSM strike [%s]", temp, static_cast<int>(Fireball_info.size()) - 1, s->name);
else
s->fireball_type = temp;
}
+1 -1
View File
@@ -438,7 +438,7 @@ void HudGaugeBrackets::renderObjectBrackets(object *targetp, color *clr, int w_c
{
int pof = 0;
pof = Asteroids[targetp->instance].asteroid_subtype;
modelnum = Asteroid_info[Asteroids[targetp->instance].asteroid_type].model_num[pof];
modelnum = Asteroid_info[Asteroids[targetp->instance].asteroid_type].subtypes[pof].model_number;
bound_rc = model_find_2d_bound_min( modelnum, &targetp->orient, &targetp->pos,&x1,&y1,&x2,&y2 );
}
break;
+14 -11
View File
@@ -359,19 +359,22 @@ void HudGaugeEscort::renderIcon(int x, int y, int index)
{
hud_stuff_ship_name(buf, sp);
// maybe concatenate the callsign
if (*buf)
if (!Dont_show_callsigns_in_escort_list)
{
char callsign[NAME_LENGTH];
// maybe concatenate the callsign
if (*buf)
{
char callsign[NAME_LENGTH];
hud_stuff_ship_callsign(callsign, sp);
if (*callsign)
sprintf(&buf[strlen(buf)], " (%s)", callsign);
}
// maybe substitute the callsign
else
{
hud_stuff_ship_callsign(buf, sp);
hud_stuff_ship_callsign(callsign, sp);
if (*callsign)
sprintf(&buf[strlen(buf)], " (%s)", callsign);
}
// maybe substitute the callsign
else
{
hud_stuff_ship_callsign(buf, sp);
}
}
}
+6 -6
View File
@@ -812,7 +812,7 @@ void hud_scrollback_button_pressed(int n)
case SHOW_EVENTS_BUTTON:
Scrollback_mode = SCROLLBACK_MODE_EVENT_LOG;
Scroll_max = Num_log_lines * gr_get_font_height();
Scroll_max = mission_log_scrollback_num_lines() * gr_get_font_height();
hud_scroll_reset();
break;
@@ -913,9 +913,9 @@ void hud_scrollback_init()
Background_bitmap = bm_load(Hud_mission_log_fname[gr_screen.res]);
// Status_bitmap = bm_load(Hud_mission_log_status_fname[gr_screen.res]);
message_log_init_scrollback(Hud_mission_log_list_coords[gr_screen.res][2]);
mission_log_init_scrollback(Hud_mission_log_list_coords[gr_screen.res][2]);
if (Scrollback_mode == SCROLLBACK_MODE_EVENT_LOG)
Scroll_max = Num_log_lines * gr_get_font_height();
Scroll_max = mission_log_scrollback_num_lines() * gr_get_font_height();
else if (Scrollback_mode == SCROLLBACK_MODE_OBJECTIVES)
Scroll_max = Num_obj_lines * gr_get_font_height();
else
@@ -928,7 +928,7 @@ void hud_scrollback_init()
void hud_scrollback_close()
{
ML_objectives_close();
message_log_shutdown_scrollback();
mission_log_shutdown_scrollback();
if (Background_bitmap >= 0)
bm_release(Background_bitmap);
//if (Status_bitmap >= 0)
@@ -960,7 +960,7 @@ void hud_scrollback_do_frame(float /*frametime*/)
} else if (Scrollback_mode == SCROLLBACK_MODE_MSGS_LOG) {
Scrollback_mode = SCROLLBACK_MODE_EVENT_LOG;
Scroll_max = Num_log_lines * gr_get_font_height();
Scroll_max = mission_log_scrollback_num_lines() * gr_get_font_height();
hud_scroll_reset();
} else {
@@ -975,7 +975,7 @@ void hud_scrollback_do_frame(float /*frametime*/)
case KEY_SHIFTED | KEY_TAB:
if (Scrollback_mode == SCROLLBACK_MODE_OBJECTIVES) {
Scrollback_mode = SCROLLBACK_MODE_EVENT_LOG;
Scroll_max = Num_log_lines * gr_get_font_height();
Scroll_max = mission_log_scrollback_num_lines() * gr_get_font_height();
hud_scroll_reset();
} else if (Scrollback_mode == SCROLLBACK_MODE_MSGS_LOG) {
+47 -3
View File
@@ -216,6 +216,8 @@ int parse_ship_start()
return ship_index;
}
SCP_vector<std::pair<SCP_string, SCP_string>> Hud_parsed_ships;
void parse_hud_gauges_tbl(const char *filename)
{
int i;
@@ -341,10 +343,11 @@ void parse_hud_gauges_tbl(const char *filename)
SCP_vector<int> ship_classes;
bool retail_config = false;
int n_ships = 0;
SCP_string name;
while (optional_string("#Gauge Config")) {
ship_classes.clear();
switch (optional_string_either("$Ship:", "$Ships:")) {
switch (optional_string_one_of(3, "$Ship:", "$Ships:", "$Name:")) {
case 0:
mprintf(("$Ship in hud_gauges.tbl and -hdg.tbms is deprecated. Use \"$Ships: (\"Some ship class\") instead.\n"));
@@ -391,6 +394,8 @@ void parse_hud_gauges_tbl(const char *filename)
}
break;
case 1:
mprintf(("$Ships in hud_gauges.tbl and -hdg.tbms can be replaced. Gauge Config Settings can now be defined per-ship in ships.tbl. \n"));
int shiparray[256];
n_ships = (int)stuff_int_list(shiparray, 256, SHIP_INFO_TYPE);
@@ -413,6 +418,38 @@ void parse_hud_gauges_tbl(const char *filename)
ship_clr_p = &ship_color;
}
if (optional_string("$Font:")) {
ship_font = font::parse_font();
}
if (optional_string("$Chase View Only:")) {
stuff_boolean(&chase_view_only);
}
break;
case 2:
stuff_string(name, F_NAME);
if (optional_string("$Load Retail Configuration:")) {
stuff_boolean(&retail_config);
}
// Here we add in any ships who set their HUD Config in ships.tbl
for (const auto& pair : Hud_parsed_ships) {
if (!stricmp(pair.first.c_str(), name.c_str())) {
int idx = ship_info_lookup(pair.second.c_str());
ship_classes.push_back(idx);
Ship_info[idx].hud_enabled = true;
Ship_info[idx].hud_retail = retail_config;
}
}
if (optional_string("$Color:")) {
stuff_int_list(colors, 3);
check_color(colors);
gr_init_alphacolor(&ship_color, colors[0], colors[1], colors[2], 255);
ship_clr_p = &ship_color;
}
if (optional_string("$Font:")) {
ship_font = font::parse_font();
}
@@ -580,6 +617,8 @@ void hud_positions_init()
// load missing retail gauges for the default and ship-specific HUDs
load_missing_retail_gauges();
Hud_parsed_ships.clear();
}
void load_missing_retail_gauges()
@@ -2132,6 +2171,7 @@ void load_gauge_center_reticle(gauge_settings* settings)
int scaleY = 10;
int size = 5;
int autoaim_frame = -1;
int flight_cursor_frame = -1;
settings->origin[0] = 0.5f;
settings->origin[1] = 0.5f;
@@ -2181,13 +2221,17 @@ void load_gauge_center_reticle(gauge_settings* settings)
if (optional_string("Firepoint Y coordinate multiplier:"))
stuff_int(&scaleY);
if(optional_string("Autoaim Frame:"))
if (optional_string("Autoaim Frame:"))
stuff_int(&autoaim_frame);
if (optional_string("Flight Cursor Frame:"))
stuff_int(&flight_cursor_frame);
hud_gauge->initBitmaps(fname);
hud_gauge->initHiRes(fname);
hud_gauge->initFirepointDisplay(firepoints, scaleX, scaleY, size);
hud_gauge->setAutoaimFrame(autoaim_frame);
hud_gauge->setFlightCursorFrame(flight_cursor_frame);
gauge_assign_common(settings, std::move(hud_gauge));
}
@@ -5476,7 +5520,7 @@ void load_gauge_scripting(gauge_settings* settings) {
SCP_string name;
stuff_string(name, F_NAME);
hud_gauge->initName(name);
hud_gauge->initName(std::move(name));
gauge_assign_common(settings, std::move(hud_gauge));
}
+75 -23
View File
@@ -225,6 +225,8 @@ int Reticle_launch_coords[GR_NUM_RESOLUTIONS][2] = {
static int Threat_lock_timer; // timestamp for when to show next flashing frame for lock threat
static int Threat_lock_frame; // frame offset of current lock flashing warning
static vertex Player_flight_cursor_offset;
HudGaugeReticle::HudGaugeReticle():
HudGauge(HUD_OBJECT_CENTER_RETICLE, HUD_CENTER_RETICLE, true, false, (VM_EXTERNAL | VM_DEAD_VIEW | VM_WARP_CHASE | VM_PADLOCK_ANY | VM_TOPDOWN | VM_OTHER_SHIP), 255, 255, 255)
@@ -254,6 +256,8 @@ void HudGaugeReticle::render(float /*frametime*/)
}
ship_info *sip = &Ship_info[Player_ship->ship_info_index];
int bitmap_size_x, bitmap_size_y;
bm_get_info(crosshair.first_frame, &bitmap_size_x, &bitmap_size_y);
if (autoaim_frame_offset > 0 || sip->autoaim_lock_snd.isValid() || sip->autoaim_lost_snd.isValid()) {
ship *shipp = &Ships[Objects[Player->objnum].instance];
@@ -283,38 +287,66 @@ void HudGaugeReticle::render(float /*frametime*/)
setGaugeColor(HUD_C_BRIGHT);
if (HUD_shadows){
gr_set_color_fast(&Color_black);
// the typical reticle indicating the direction of shooting
int shoot_reticle = 0;
if (has_autoaim_lock)
shoot_reticle = crosshair.first_frame + autoaim_frame_offset;
else
shoot_reticle = crosshair.first_frame;
if (has_autoaim_lock)
{
// Render the shadow twice to increase visibility
renderBitmap(crosshair.first_frame + autoaim_frame_offset, position[0] + 1, position[1] + 1);
renderBitmap(crosshair.first_frame + autoaim_frame_offset, position[0] + 1, position[1] + 1);
}
else
{
// Render the shadow twice to increase visibility
renderBitmap(crosshair.first_frame, position[0] + 1, position[1] + 1);
renderBitmap(crosshair.first_frame, position[0] + 1, position[1] + 1);
}
gr_set_color_fast(&gauge_color);
// a secondary 'reticle' for distinguishing the flight cursor from the above
int flight_reticle = flight_cursor_frame_offset >= 0 ? crosshair.first_frame + flight_cursor_frame_offset : -1;
int mobile_reticle = flight_reticle;
int fixed_reticle = shoot_reticle;
// depending on the parameters of the ship the 'mobile' reticle may be the one indicating the shoot direction
if (sip->aims_at_flight_cursor) {
mobile_reticle = shoot_reticle;
fixed_reticle = flight_reticle;
}
if (has_autoaim_lock)
renderBitmap(crosshair.first_frame + autoaim_frame_offset, position[0], position[1]);
if (fixed_reticle == shoot_reticle)
setGaugeColor(HUD_C_BRIGHT);
else
renderBitmap(crosshair.first_frame, position[0], position[1]);
setGaugeColor(HUD_C_NORMAL);
if (fixed_reticle >= 0) {
if (HUD_shadows) {
gr_set_color_fast(&Color_black);
// Render the shadow twice to increase visibility
renderBitmap(fixed_reticle, position[0] + 1, position[1] + 1);
renderBitmap(fixed_reticle, position[0] + 1, position[1] + 1);
gr_set_color_fast(&gauge_color);
}
renderBitmap(fixed_reticle, position[0], position[1]);
} else {
renderCircle(fl2i(base_w * 0.5f), fl2i(base_h * 0.5f), fl2i(base_h * 0.03f), false);
}
if (Player_flight_mode == FlightMode::FlightCursor || sip->aims_at_flight_cursor) {
if (mobile_reticle == shoot_reticle)
setGaugeColor(HUD_C_BRIGHT);
else
setGaugeColor(HUD_C_NORMAL);
int x = fl2i(Player_flight_cursor_offset.screen.xyw.x + 0.5f);
int y = fl2i(Player_flight_cursor_offset.screen.xyw.y + 0.5f);
unsize(&x, &y);
if (mobile_reticle >= 0)
renderBitmap(mobile_reticle, fl2i(x - base_w * 0.5f) + position[0], fl2i(y - base_h * 0.5f) + position[1]);
else {
renderCircle(x, y, fl2i(base_h * 0.03f), false);
}
}
if (firepoint_display) {
fp.clear();
getFirepointStatus();
if (!fp.empty()) {
int ax, ay;
bm_get_info(crosshair.first_frame, &ax, &ay);
int centerX = position[0] + (ax / 2);
int centerY = position[1] + (ay / 2);
for (SCP_vector<firepoint>::iterator fpi = fp.begin(); fpi != fp.end(); ++fpi) {
if (fpi->active == 2)
@@ -323,7 +355,9 @@ void HudGaugeReticle::render(float /*frametime*/)
setGaugeColor(HUD_C_NORMAL);
else
setGaugeColor(HUD_C_DIM);
int centerX = position[0] + (bitmap_size_x / 2);
int centerY = position[1] + (bitmap_size_y / 2);
renderCircle((int) (centerX + (fpi->xy.x * firepoint_scale_x)), (int) (centerY + (fpi->xy.y * firepoint_scale_y)), firepoint_size);
}
}
@@ -415,6 +449,13 @@ void HudGaugeReticle::getFirepointStatus() {
}
}
void HudGaugeReticle::setFlightCursorFrame(int framenum) {
if (framenum < 0 || framenum > crosshair.num_frames - 1)
flight_cursor_frame_offset = -1;
else
flight_cursor_frame_offset = framenum;
}
void HudGaugeReticle::setAutoaimFrame(int framenum) {
if (framenum < 0 || framenum > crosshair.num_frames - 1)
autoaim_frame_offset = 0;
@@ -1140,3 +1181,14 @@ void hud_update_reticle( player *pp )
}
}
}
// calculates what the screen position of the flight cursor should be
void hud_reticle_set_flight_cursor_offset() {
matrix view_mat;
vm_angles_2_matrix(&view_mat, &Player_flight_cursor);
view_mat = view_mat * Eye_matrix;
vec3d view_pos = Eye_position + view_mat.vec.fvec * 10000.0f;
g3_rotate_vertex(&Player_flight_cursor_offset, &view_pos);
g3_project_vertex(&Player_flight_cursor_offset);
}
+3
View File
@@ -44,6 +44,7 @@ protected:
int firepoint_scale_y;
int autoaim_frame_offset;
bool has_autoaim_lock;
int flight_cursor_frame_offset;
public:
HudGaugeReticle();
void render(float frametime) override;
@@ -52,6 +53,7 @@ public:
void initFirepointDisplay(bool firepoint, int scaleX, int scaleY, int size);
void getFirepointStatus();
void setAutoaimFrame(int framenum);
void setFlightCursorFrame(int framenum);
};
class HudGaugeThrottle: public HudGauge
@@ -168,5 +170,6 @@ public:
void hud_init_reticle();
void hud_update_reticle( player *pp );
void hud_reticle_set_flight_cursor_offset();
#endif
+1 -1
View File
@@ -641,7 +641,7 @@ void HudGaugeShield::showShields(object *objp, int mode)
model_render_params render_info;
render_info.set_flags(MR_NO_LIGHTING | MR_AUTOCENTER | MR_NO_FOGGING);
render_info.set_replacement_textures(sp->ship_replacement_textures);
render_info.set_replacement_textures(model_get_instance(sp->model_instance_num)->texture_replace);
render_info.set_detail_level_lock(1);
render_info.set_object_number(OBJ_INDEX(objp));
+3 -3
View File
@@ -508,7 +508,7 @@ int hud_squadmsg_read_key( int k )
// after messaging is over. Return true for a while.
if ( !timestamp_elapsed(Msg_eat_key_timestamp) ) {
for (i = 0; i < num_keys_used; i++ ) {
if ( keyd_pressed[keys_used[i]] )
if ( key_is_pressed(keys_used[i]) )
return 1;
}
}
@@ -524,7 +524,7 @@ int hud_squadmsg_read_key( int k )
key_found = 1;
}
if ( keyd_pressed[k] ) {
if ( key_is_pressed(k) ) {
key_found = 1;
}
@@ -639,7 +639,7 @@ void hud_squadmsg_repair_rearm( int toggle_state, object *objp)
if ( mission_is_repair_scheduled( tobj ) ) {
message_send_builtin(MESSAGE_ALREADY_ON_WAY, nullptr, nullptr, multi_player_num, multi_player_team);
} else {
robjnum = hud_support_find_closest(OBJ_INDEX(tobj));
robjnum = hud_support_find_closest( tobj );
if ( robjnum != -1 ) {
message_send_builtin(MESSAGE_ALREADY_ON_WAY, &Ships[Objects[robjnum].instance], nullptr, multi_player_num, multi_player_team);
} else {
+34 -15
View File
@@ -1587,13 +1587,14 @@ int hud_target_ship_can_be_scanned(ship *shipp)
if (shipp->flags[Ship::Ship_Flags::Cargo_revealed])
return 0;
// allow ships with scannable flag set
if (shipp->flags[Ship::Ship_Flags::Scannable])
// The old behavior treats some ship types as always scannable. The new behavior only checks the ship's Scannable flag.
if (shipp->flags[Ship::Ship_Flags::Scannable]) {
return 1;
// ignore ships that don't carry cargo
if ((sip->class_type < 0) || !(Ship_types[sip->class_type].flags[Ship::Type_Info_Flags::Scannable]))
} else if (Use_new_scanning_behavior) {
return 0;
} else if ((sip->class_type < 0) || !(Ship_types[sip->class_type].flags[Ship::Type_Info_Flags::Scannable])) {
return 0;
}
return 1;
}
@@ -2518,7 +2519,7 @@ void hud_target_in_reticle_new()
{
int pof = 0;
pof = Asteroids[A->instance].asteroid_subtype;
mc.model_num = Asteroid_info[Asteroids[A->instance].asteroid_type].model_num[pof];
mc.model_num = Asteroid_info[Asteroids[A->instance].asteroid_type].subtypes[pof].model_number;
}
break;
case OBJ_JUMP_NODE:
@@ -3045,7 +3046,7 @@ void HudGaugeReticleTriangle::renderTriangle(vec3d *hostile_pos, int aspect_flag
// even if the screen position overflowed, it will still be pointing in the correct direction
unsize( &hostile_vertex.screen.xyw.x, &hostile_vertex.screen.xyw.y );
ang = atan2_safe(-(hostile_vertex.screen.xyw.y - tablePosY), hostile_vertex.screen.xyw.x - tablePosX);
ang = atan2(-(hostile_vertex.screen.xyw.y - tablePosY), hostile_vertex.screen.xyw.x - tablePosX);
sin_ang=sinf(ang);
cos_ang=cosf(ang);
@@ -4038,6 +4039,7 @@ void HudGaugeLeadIndicator::renderLeadCurrentTarget()
//overwritten if using non-default leadIndicatorBehaviors, this is desired.
bank_to_fire = hud_get_best_primary_bank(&prange);
wip = &Weapon_info[swp->primary_bank_weapons[bank_to_fire]];
bool no_primary_indicator = false;
if (Lead_indicator_behavior != leadIndicatorBehavior::DEFAULT && Player_ship->flags[Ship::Ship_Flags::Primary_linked]) {
vec3d averaged_lead_pos;
@@ -4066,6 +4068,7 @@ void HudGaugeLeadIndicator::renderLeadCurrentTarget()
continue;
}
// Note! This is function call that actually determines if primary or secondary target gauges are going to be rendered.
frame_offset = pickFrame(weapon_range, srange, dist_to_target);
if (frame_offset >= 0) {
@@ -4081,6 +4084,10 @@ void HudGaugeLeadIndicator::renderLeadCurrentTarget()
if (average_instances > 0 && Lead_indicator_behavior == leadIndicatorBehavior::AVERAGE) {
averaged_lead_pos = averaged_lead_pos/i2fl(average_instances);
renderIndicator(frame_offset, targetp, &averaged_lead_pos);
// This handles an edge case where secondary weapon indicators might not have been rendered, despite possibly being in range.
} else if ( frame_offset == -1) {
no_primary_indicator = true;
}
}
else if (bank_to_fire >= 0) { //leadIndicatorBehavior::DEFAULT
@@ -4088,7 +4095,11 @@ void HudGaugeLeadIndicator::renderLeadCurrentTarget()
prange = 0.0f; // no ballistic trajectory, primary is 'always out of range'
}
// Note! This is function call that actually determines if primary or secondary target gauges are going to be rendered.
frame_offset = pickFrame(prange, srange, dist_to_target);
// note here, that srange being -1.0f is indicative of the Dont_merge_indicators flag being used above,
// or the missile being a dumbfire.
if ( frame_offset < 0 && srange != -1.0f ) {
return;
}
@@ -4097,16 +4108,26 @@ void HudGaugeLeadIndicator::renderLeadCurrentTarget()
renderIndicator(frame_offset, targetp, &lead_target_pos);
}
}
else return;
//Cyborg - this `else return;` would force the secondary indicator off if no primaries are available.
//Sure this is not a very common case, but we don't need the early return.
//We are safe from any ill effects because we're not going to try to render any primary indicators
//after this point anyway (the first argument for renderIndicator is forced to 0 below).
//Anyone who rewrites this function to somehow re-evaluate primary indicators will have to revist this.
//else return;
//do dumbfire lead indicator - color is orange (255,128,0) - bright, (192,96,0) - dim
//phreak changed 9/01/02
//Cyborg - This section mainly handles dumbfire indicators, unless Dont_merge_indicators is set, forcing a separate indicator
//for homing weapons. OR if no_primary_indicator is true (no primary indicator was drawn when in multiple or average mode)
//We are guaranteed (if the target is in the homing cone) to get here because in both of those situations srange is
//forced to -1.0f, precluding the early returns.
if((swp->current_secondary_bank>=0) && (swp->secondary_bank_weapons[swp->current_secondary_bank] >= 0)) {
int bank=swp->current_secondary_bank;
wip=&Weapon_info[swp->secondary_bank_weapons[bank]];
//get out of here if the secondary weapon is a homer or if its out of range
if ( wip->is_homing() && !wip->wi_flags[Weapon::Info_Flags::Dont_merge_indicators] )
//get out of here if the secondary weapon is a homer and we don't have independent indicator behavior
if ( wip->is_homing() && !wip->wi_flags[Weapon::Info_Flags::Dont_merge_indicators] && !no_primary_indicator )
return;
double max_dist = MIN((wip->lifetime * wip->max_speed), wip->weapon_range);
@@ -4751,7 +4772,7 @@ int hud_communications_state(ship *sp, bool for_death_scream)
}
// Goober5000 - check for scrambled communications
if (emp_active_local() || sp->flags[Ship::Ship_Flags::Scramble_messages])
if ((emp_active_local() && !sp->flags[Ship::Ship_Flags::EMP_doesnt_scramble_messages]) || sp->flags[Ship::Ship_Flags::Scramble_messages])
return COMM_SCRAMBLED;
return COMM_OK;
@@ -6540,8 +6561,7 @@ void HudGaugeOffscreen::calculatePosition(vertex* target_point, vec3d *tpos, vec
g3_project_vertex(eye_vertex);
if (eye_vertex->flags&PF_OVERFLOW) {
Int3(); // This is unlikely to happen, but can if a clip goes through the player's eye.
Player_ai->target_objnum = -1;
// This is unlikely to happen, but can if a clip goes through the player's eye.
if (!in_frame)
g3_end_frame();
return;
@@ -6603,7 +6623,6 @@ void HudGaugeOffscreen::calculatePosition(vertex* target_point, vec3d *tpos, vec
xpos = gr_screen.clip_right_unscaled - half_gauge_length;
} else {
Int3();
if (!in_frame)
g3_end_frame();
return;
@@ -7350,7 +7369,7 @@ void HudGaugeHardpoints::render(float /*frametime*/)
vertex draw_point;
vec3d subobj_pos;
int render_flags = MR_NO_LIGHTING | MR_AUTOCENTER | MR_NO_FOGGING | MR_NO_TEXTURING | MR_NO_ZBUFFER;
uint64_t render_flags = MR_NO_LIGHTING | MR_AUTOCENTER | MR_NO_FOGGING | MR_NO_TEXTURING | MR_NO_ZBUFFER;
setGaugeColor();
float alpha = gr_screen.current_color.alpha / 255.0f;
+19 -11
View File
@@ -57,7 +57,7 @@ static int Target_static_next;
static int Target_static_playing;
sound_handle Target_static_looping = sound_handle::invalid();
int Target_display_cargo;
bool Target_display_cargo;
char Cargo_string[256] = "";
#ifndef NDEBUG
@@ -570,7 +570,7 @@ void HudGaugeTargetBox::renderTargetShip(object *target_objp)
target_shipp = &Ships[target_objp->instance];
target_sip = &Ship_info[target_shipp->ship_info_index];
int flags=0;
uint64_t flags = 0;
if ( Detail.targetview_model ) {
// take the forward orientation to be the vector from the player to the current target
vm_vec_sub(&orient_vec, &target_objp->pos, &Player_obj->pos);
@@ -677,7 +677,7 @@ void HudGaugeTargetBox::renderTargetShip(object *target_objp)
if(target_sip->model_num_hud >= 0){
model_render_immediate( &render_info, target_sip->model_num_hud, &target_objp->orient, &obj_pos);
} else {
render_info.set_replacement_textures(target_shipp->ship_replacement_textures);
render_info.set_replacement_textures(model_get_instance(target_shipp->model_instance_num)->texture_replace);
model_render_immediate( &render_info, target_sip->model_num, &target_objp->orient, &obj_pos);
}
@@ -746,7 +746,7 @@ void HudGaugeTargetBox::renderTargetDebris(object *target_objp)
debris *debrisp;
vec3d orient_vec, up_vector;
float factor;
int flags=0;
uint64_t flags = 0;
debrisp = &Debris[target_objp->instance];
@@ -777,6 +777,9 @@ void HudGaugeTargetBox::renderTargetDebris(object *target_objp)
model_render_params render_info;
if (debrisp->model_instance_num >= 0)
render_info.set_replacement_textures(model_get_instance(debrisp->model_instance_num)->texture_replace);
color thisColor = GaugeWirecolor;
bool thisOverride = GaugeWirecolorOverride;
@@ -863,9 +866,9 @@ void HudGaugeTargetBox::renderTargetWeapon(object *target_objp)
weapon_info *target_wip = NULL;
weapon *wp = NULL;
object *viewer_obj, *viewed_obj;
int *replacement_textures = NULL;
std::shared_ptr<model_texture_replace> replacement_textures = nullptr;
int target_team, is_homing, is_player_missile, missile_view, viewed_model_num, hud_target_lod, w, h;
int flags=0;
uint64_t flags = 0;
target_team = obj_team(target_objp);
@@ -902,10 +905,13 @@ void HudGaugeTargetBox::renderTargetWeapon(object *target_objp)
viewed_obj = wp->homing_object;
missile_view = TRUE;
viewed_model_num = homing_sip->model_num;
replacement_textures = homing_shipp->ship_replacement_textures;
hud_target_lod = homing_sip->hud_target_lod;
}
int pmi_id = object_get_model_instance(viewed_obj);
if (pmi_id >= 0)
replacement_textures = model_get_instance(pmi_id)->texture_replace;
// take the forward orientation to be the vector from the player to the current target
vm_vec_sub(&orient_vec, &viewed_obj->pos, &viewer_obj->pos);
vm_vec_normalize(&orient_vec);
@@ -1068,7 +1074,6 @@ void HudGaugeTargetBox::renderTargetWeapon(object *target_objp)
model_render_immediate( &render_info, homing_sip->model_num_hud, &viewed_obj->orient, &obj_pos);
} else {
render_info.set_flags(flags | MR_NO_FOGGING);
render_info.set_replacement_textures(homing_shipp->ship_replacement_textures);
model_render_immediate( &render_info, homing_sip->model_num, &viewed_obj->orient, &obj_pos );
}
@@ -1136,7 +1141,7 @@ void HudGaugeTargetBox::renderTargetAsteroid(object *target_objp)
float time_to_impact, factor;
int pof;
int flags=0; //draw flags for wireframe
uint64_t flags = 0; //draw flags for wireframe
asteroidp = &Asteroids[target_objp->instance];
pof = asteroidp->asteroid_subtype;
@@ -1166,10 +1171,13 @@ void HudGaugeTargetBox::renderTargetAsteroid(object *target_objp)
vm_vec_copy_scale(&obj_pos,&orient_vec,factor);
renderTargetSetup(&camera_eye, &camera_orient, 0.5f);
model_clear_instance(Asteroid_info[asteroidp->asteroid_type].model_num[pof]);
model_clear_instance(Asteroid_info[asteroidp->asteroid_type].subtypes[pof].model_number);
model_render_params render_info;
if (asteroidp->model_instance_num >= 0)
render_info.set_replacement_textures(model_get_instance(asteroidp->model_instance_num)->texture_replace);
color thisColor = GaugeWirecolor;
bool thisOverride = GaugeWirecolorOverride;
@@ -1223,7 +1231,7 @@ void HudGaugeTargetBox::renderTargetAsteroid(object *target_objp)
render_info.set_flags(flags | MR_NO_FOGGING);
model_render_immediate( &render_info, Asteroid_info[asteroidp->asteroid_type].model_num[pof], &target_objp->orient, &obj_pos );
model_render_immediate( &render_info, Asteroid_info[asteroidp->asteroid_type].subtypes[pof].model_number, &target_objp->orient, &obj_pos );
if ( Monitor_mask >= 0 ) {
gr_stencil_set(GR_STENCIL_NONE);
+1 -1
View File
@@ -30,7 +30,7 @@ class object;
#define TBOX_FLASH_SUBSYS 4
extern sound_handle Target_static_looping;
extern int Target_display_cargo;
extern bool Target_display_cargo;
extern char Cargo_string[256];
extern int Target_window_coords[GR_NUM_RESOLUTIONS][4];
+131 -30
View File
@@ -13,6 +13,7 @@
#include "mission/missionparse.h"
#include "parse/parselo.h"
#include "ship/ship.h"
#include "options/Option.h"
extern int radar_target_id_flags;
@@ -40,6 +41,21 @@ flag_def_list rti_flags[] = {
int Num_rti_flags = sizeof(rti_flags)/sizeof(flag_def_list);
static bool AccessiblitySupported = false;
// used by In-Game Options menu
static bool AccessibilityEnabled = false;
static auto AccessibilityOption = options::OptionBuilder<bool>("Game.IffAccessibility",
std::pair<const char*, int>{"Accessibility IFF Colors", 1855},
std::pair<const char*, int>{"Enables or disables IFF Accessibility color overrides", 1856})
.category(std::make_pair("Game", 1824))
.default_val(false)
.level(options::ExpertLevel::Advanced)
.bind_to_once(&AccessibilityEnabled)
.importance(60)
.finish();
/**
* Borrowed from ship.cpp, ship_iff_init_colors
*
@@ -113,6 +129,8 @@ struct observed_color_t {
static SCP_vector<SCP_vector<observed_color_t>> observed_color_table;
static SCP_vector<SCP_vector<observed_color_t>> accessibility_observed_color_table;
void resolve_iff_data()
{
// first get the traitor
@@ -157,13 +175,30 @@ void resolve_iff_data()
int target_iff = iff_lookup(observed_color.iff_name);
// valid?
if (target_iff >= 0)
if (target_iff >= 0) {
iff->observed_color_map[target_iff] = observed_color.color_index;
else
} else{
Warning(LOCATION,
"Observed color IFF %s not found for IFF %s in iff_defs.tbl!\n",
observed_color.iff_name,
iff->iff_name);
}
}
// resolve the accessibility observed color list names
for (const auto& observed_color : accessibility_observed_color_table[cur_iff]) {
// find out who
int target_iff = iff_lookup(observed_color.iff_name);
// valid?
if (target_iff >= 0) {
iff->accessibility_observed_color_map[target_iff] = observed_color.color_index;
} else {
Warning(LOCATION,
"Observed color IFF %s not found for IFF %s in iff_defs.tbl!\n",
observed_color.iff_name,
iff->iff_name);
}
}
// resolve the all teams at war relationships
@@ -246,6 +281,10 @@ void parse_iff_table(const char* filename)
stuff_string(traitor_name, F_NAME, NAME_LENGTH);
}
if (optional_string("$Accessibility Supported:")) {
stuff_boolean(&AccessiblitySupported);
}
int rgb[3];
// check if alternate colours are wanted to be used for these
@@ -435,9 +474,12 @@ void parse_iff_table(const char* filename)
Iff_info.push_back(ifft);
attack_names.emplace_back();
observed_color_table.emplace_back();
accessibility_observed_color_table.emplace_back();
iffp = &Iff_info[Iff_info.size() - 1];
//Initialize this to white for new IFFs
iffp->color_index = iff_init_color(255, 255, 255);
// Initialize this to white for new IFFs
iffp->accessibility_color_index = iff_init_color(255, 255, 255);
//Make sure flags are reset for new IFFs
iffp->default_parse_flags.reset();
}
@@ -450,6 +492,12 @@ void parse_iff_table(const char* filename)
iffp->color_index = iff_init_color(rgb[0], rgb[1], rgb[2]);
}
// get the accessiblity iff color
if (optional_string_either("$Accessibility Colour:", "$Accessibility Color:") != -1) {
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
iffp->accessibility_color_index = iff_init_color(rgb[0], rgb[1], rgb[2]);
}
// get relationships between IFFs -------------------------------------
@@ -470,6 +518,18 @@ void parse_iff_table(const char* filename)
observed_color_table[cur_iff].back().color_index = iff_init_color(rgb[0], rgb[1], rgb[2]);
}
// get the list of accessibility observed colors
while (optional_string("+Accessibility Sees")) {
accessibility_observed_color_table[cur_iff].emplace_back();
// get iff observed
stuff_string_until(accessibility_observed_color_table[cur_iff].back().iff_name, "As:", NAME_LENGTH);
required_string("As:");
// get color observed
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
accessibility_observed_color_table[cur_iff].back().color_index = iff_init_color(rgb[0], rgb[1], rgb[2]);
}
// get F3 override
iffp->hotkey_team = IFF_hotkey_team::Default;
if (optional_string("+Hotkey Team:"))
@@ -529,7 +589,8 @@ void parse_iff_table(const char* filename)
}
// this is cleared between each level but let's just set it here for thoroughness
iffp->ai_rearm_timestamp = TIMESTAMP::invalid();
iffp->ai_good_rearm_timestamp = TIMESTAMP::invalid();
iffp->ai_bad_rearm_timestamp = TIMESTAMP::invalid();
}
required_string("#End");
@@ -550,6 +611,11 @@ void iff_init()
// parse any modular tables
parse_modular_table("*-iff.tbm", parse_iff_table);
if (!AccessiblitySupported) {
options::OptionsManager::instance()->removeOption(AccessibilityOption);
AccessibilityEnabled = false;
}
// now resolve the relationships
resolve_iff_data();
}
@@ -664,14 +730,22 @@ color *iff_get_color(int color_index, int is_bright)
*/
color *iff_get_color_by_team(int team, int seen_from_team, int is_bright)
{
Assert(team >= 0 && team < (int)Iff_info.size());
Assert(seen_from_team < (int)Iff_info.size());
Assert(is_bright == 0 || is_bright == 1);
Assertion(SCP_vector_inbounds(Iff_info, team), "Cannot get color by team because team is invalid. Get a coder!");
Assertion((is_bright == 0 || is_bright == 1), "Error with brightness selection when getting color. Get a coder!");
int color_index;
if (AccessibilityEnabled) {
color_index = Iff_info[team].accessibility_color_index;
} else {
color_index = Iff_info[team].color_index;
}
// is this guy being seen by anyone?
if (seen_from_team < 0)
return is_bright == 0 ? &Iff_colors[Iff_info[team].color_index].first : &Iff_colors[Iff_info[team].color_index].second;
if (seen_from_team < 0) {
return is_bright == 0 ? &Iff_colors[color_index].first : &Iff_colors[color_index].second;
}
// Goober5000 - base the following on "sees X as" from iff code
// c.f. AL's comment:
@@ -681,13 +755,21 @@ color *iff_get_color_by_team(int team, int seen_from_team, int is_bright)
// drawn friendly. If the team is different than the player's, then draw the
// appropriate IFF.
// This goes here because seen_from_team can validly be a negative number. In that case color_map is undefined
// but that doesn't matter because we return in the statement above here. Below here, color_map needs to be defined
// which will happen if seen_from_team is valid.
Assertion(SCP_vector_inbounds(Iff_info, seen_from_team), "Cannot get color because seen_from_team is invalid. Get a coder!");
// assume an observed color is defined; if not, use normal color
auto it = Iff_info[seen_from_team].observed_color_map.find(team);
int color_index = Iff_info[team].color_index;
if (SCP_vector_inbounds(Iff_info, seen_from_team)) {
const auto& color_map = AccessibilityEnabled ? Iff_info[seen_from_team].accessibility_observed_color_map : Iff_info[seen_from_team].observed_color_map;
if (it != Iff_info[seen_from_team].observed_color_map.end())
color_index = it->second;
// assume an observed color is defined; if not, use normal color
auto it = color_map.find(team);
if (it != color_map.end()) {
color_index = it->second;
}
}
return is_bright == 0 ? &Iff_colors[color_index].first : &Iff_colors[color_index].second;
}
@@ -699,23 +781,39 @@ color *iff_get_color_by_team(int team, int seen_from_team, int is_bright)
*/
color *iff_get_color_by_team_and_object(int team, int seen_from_team, int is_bright, object *objp)
{
Assert(team >= 0 && team < (int)Iff_info.size());
Assert(seen_from_team < (int)Iff_info.size());
Assert(is_bright == 0 || is_bright == 1);
Assertion(SCP_vector_inbounds(Iff_info, team), "Cannot get color by team because team is invalid. Get a coder!");
Assertion((is_bright == 0 || is_bright == 1), "Error with brightness selection when getting color. Get a coder!");
int alt_color_index = -1;
int color_index;
if (AccessibilityEnabled) {
color_index = Iff_info[team].accessibility_color_index;
} else {
color_index = Iff_info[team].color_index;
}
// is this guy being seen by anyone?
if (seen_from_team < 0)
return is_bright == 0 ? &Iff_colors[Iff_info[team].color_index].first : &Iff_colors[Iff_info[team].color_index].second;
int color_index = -1;
{
auto it = Iff_info[seen_from_team].observed_color_map.find(team);
if (it != Iff_info[seen_from_team].observed_color_map.end())
color_index = it->second;
if (seen_from_team < 0) {
return is_bright == 0 ? &Iff_colors[color_index].first : &Iff_colors[color_index].second;
}
// This goes here because seen_from_team can validly be a negative number. In that case color_map is undefined
// but that doesn't matter because we return in the statement above here. Below here, color_map needs to be defined
// which will happen if seen_from_team is valid.
Assertion(SCP_vector_inbounds(Iff_info, seen_from_team), "Cannot get color because seen_from_team is invalid. Get a coder!");
if (SCP_vector_inbounds(Iff_info, seen_from_team)) {
const auto& color_map = AccessibilityEnabled ? Iff_info[seen_from_team].accessibility_observed_color_map : Iff_info[seen_from_team].observed_color_map;
auto it = color_map.find(team);
if (it != color_map.end()) {
color_index = it->second;
}
}
int alt_color_index = -1;
// switch in case some sort of parent iff color inheritance for example for bombs is wanted...
switch(objp->type)
{
@@ -738,12 +836,15 @@ color *iff_get_color_by_team_and_object(int team, int seen_from_team, int is_bri
break;
}
int this_color_index = -1;
// temporary solution....
if (alt_color_index >= 0)
color_index = alt_color_index;
if (color_index < 0)
color_index = Iff_info[team].color_index;
if (alt_color_index >= 0) {
this_color_index = alt_color_index;
} else {
this_color_index = color_index;
}
return is_bright == 0 ? &Iff_colors[color_index].first : &Iff_colors[color_index].second;
return is_bright == 0 ? &Iff_colors[this_color_index].first : &Iff_colors[this_color_index].second;
}
+4 -1
View File
@@ -38,11 +38,13 @@ typedef struct iff_info {
// required stuff
char iff_name[NAME_LENGTH];
int color_index; // treat this as private and use iff_get_color or iff_get_color_by_team
int accessibility_color_index;
// relationships
int attackee_bitmask; // treat this as private and use iff_get_attackee_mask or iff_x_attacks_y
int attackee_bitmask_all_teams_at_war; // treat this as private and use iff_get_attackee_mask or iff_x_attacks_y
SCP_map<int, int> observed_color_map; // treat this as private and use iff_get_color or iff_get_color_by_team
SCP_map<int, int> accessibility_observed_color_map;
IFF_hotkey_team hotkey_team;
// flags
@@ -50,7 +52,8 @@ typedef struct iff_info {
flagset<Mission::Parse_Object_Flags> default_parse_flags;
// used internally, not parsed
TIMESTAMP ai_rearm_timestamp;
TIMESTAMP ai_good_rearm_timestamp;
TIMESTAMP ai_bad_rearm_timestamp;
} iff_info;
+133 -116
View File
@@ -21,27 +21,24 @@
#define THREADED // to use the proper set of macros
#include "osapi/osapi.h"
#define KEY_BUFFER_SIZE 16
//-------- Variable accessed by outside functions ---------
ubyte keyd_buffer_type; // 0=No buffer, 1=buffer ASCII, 2=buffer scans
ubyte keyd_repeat;
uint keyd_last_pressed;
uint keyd_last_released;
ubyte keyd_pressed[NUM_KEYS];
int keyd_time_when_last_pressed;
bool key_allow_repeat;
typedef struct keyboard {
ushort keybuffer[KEY_BUFFER_SIZE];
uint time_pressed[KEY_BUFFER_SIZE];
uint TimeKeyWentDown[NUM_KEYS];
uint TimeKeyHeldDown[NUM_KEYS];
uint TimeKeyDownChecked[NUM_KEYS];
uint NumDowns[NUM_KEYS];
uint NumUps[NUM_KEYS];
int down_check[NUM_KEYS]; // nonzero if has been pressed yet this mission
uint keyhead, keytail;
enum class key_state : uint8_t { RELEASED, PRESSED, PRESSED_OVERRIDDEN };
std::array<key_state, NUM_KEYS> state;
SCP_queue<uint> key_queue;
//The time that the key was pressed. Tracks actual presses, even those overridden
uint TimeKeyWentDown[NUM_KEYS];
//The cumulative time that the key has been held down.
//This explicitly excludes any time the button has been down in the current press if the button is pressed.
uint TimeKeyHeldDown[NUM_KEYS];
uint TimeKeyDownChecked[NUM_KEYS];
uint NumDowns[NUM_KEYS];
uint NumUps[NUM_KEYS];
int down_check[NUM_KEYS]; // nonzero if has been pressed yet this mission
} keyboard;
keyboard key_data;
@@ -299,21 +296,15 @@ void key_flush()
SDL_LockMutex( key_lock );
key_data.keyhead = key_data.keytail = 0;
//Clear the keyboard buffer
for (i=0; i<KEY_BUFFER_SIZE; i++ ) {
key_data.keybuffer[i] = 0;
key_data.time_pressed[i] = 0;
}
key_data.key_queue = {};
//Clear the keyboard array
CurTime = timer_get_milliseconds();
for (i=0; i<NUM_KEYS; i++ ) {
keyd_pressed[i] = 0;
key_data.state[i] = keyboard::key_state::RELEASED;
key_data.TimeKeyDownChecked[i] = CurTime;
key_data.TimeKeyWentDown[i] = CurTime;
key_data.TimeKeyHeldDown[i] = 0;
@@ -324,28 +315,14 @@ void key_flush()
SDL_UnlockMutex( key_lock );
}
// A nifty function which performs the function:
// n = (n+1) % KEY_BUFFER_SIZE
// (assuming positive values of n).
int add_one( int n )
{
n++;
if ( n >= KEY_BUFFER_SIZE ) n=0;
return n;
}
// Returns 1 if character waiting... 0 otherwise
int key_checkch()
bool key_checkch()
{
int is_one_waiting = 0;
if ( !key_inited ) return 0;
SDL_LockMutex( key_lock );
SDL_LockMutex( key_lock );
if (key_data.keytail != key_data.keyhead){
is_one_waiting = 1;
}
bool is_one_waiting = !key_data.key_queue.empty();
SDL_UnlockMutex( key_lock );
@@ -366,18 +343,23 @@ int key_inkey()
SDL_LockMutex( key_lock );
if (key_data.keytail!=key_data.keyhead) {
key = key_data.keybuffer[key_data.keyhead];
key_data.keyhead = add_one(key_data.keyhead);
if (!key_data.key_queue.empty()) {
key = key_data.key_queue.front();
key_data.key_queue.pop();
}
SDL_UnlockMutex( key_lock );
SDL_UnlockMutex( key_lock );
Current_key_down = key;
return key;
}
bool key_is_pressed(int keycode, bool include_since_last_count) {
Assertion(keycode >= 0 && keycode < NUM_KEYS, "Checked status for invalid keycode!");
return key_data.state[keycode] == keyboard::key_state::PRESSED || (include_since_last_count && key_down_count(keycode) > 0);
}
// If not installed, uses BIOS and returns getch();
// Else returns pending key (or waits for one if none waiting).
int key_getch()
@@ -403,20 +385,20 @@ uint key_get_shift_status()
SDL_LockMutex( key_lock );
if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] )
if ( key_is_pressed(KEY_LSHIFT) || key_is_pressed(KEY_RSHIFT) )
shift_status |= KEY_SHIFTED;
if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] )
if ( key_is_pressed(KEY_LALT) || key_is_pressed(KEY_RALT) )
shift_status |= KEY_ALTED;
if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] )
if ( key_is_pressed(KEY_LCTRL) || key_is_pressed(KEY_RCTRL) )
shift_status |= KEY_CTRLED;
#ifndef NDEBUG
if (keyd_pressed[KEY_DEBUG_KEY])
if (key_is_pressed(KEY_DEBUG_KEY))
shift_status |= KEY_DEBUGGED;
#else
if (keyd_pressed[KEY_DEBUG_KEY]) {
if (key_is_pressed(KEY_DEBUG_KEY)) {
mprintf(("Cheats_enabled = %i, Key_normal_game = %i\n", Cheats_enabled, Key_normal_game));
if ((Cheats_enabled) && Key_normal_game) {
mprintf(("Debug key\n"));
@@ -431,11 +413,8 @@ uint key_get_shift_status()
// Returns amount of time key (specified by "code") has been down since last call.
// Returns float, unlike key_down_time() which returns a fix.
float key_down_timef(uint scancode)
float key_down_timef(uint scancode)
{
uint time_down, time;
uint delta_time;
if ( !key_inited ) {
return 0.0f;
}
@@ -446,13 +425,14 @@ float key_down_timef(uint scancode)
SDL_LockMutex( key_lock );
time = timer_get_milliseconds();
delta_time = time - key_data.TimeKeyDownChecked[scancode];
uint time = timer_get_milliseconds();
uint last_check_time = key_data.TimeKeyDownChecked[scancode];
uint delta_time = time - last_check_time;
key_data.TimeKeyDownChecked[scancode] = time;
if ( delta_time <= 1 ) {
key_data.TimeKeyWentDown[scancode] = time;
if (keyd_pressed[scancode]) {
key_data.TimeKeyHeldDown[scancode] = 0;
if (key_is_pressed(scancode)) {
SDL_UnlockMutex( key_lock );
return 1.0f;
} else {
@@ -461,13 +441,13 @@ float key_down_timef(uint scancode)
}
}
if ( !keyd_pressed[scancode] ) {
time_down = key_data.TimeKeyHeldDown[scancode];
key_data.TimeKeyHeldDown[scancode] = 0;
} else {
time_down = time - key_data.TimeKeyWentDown[scancode];
key_data.TimeKeyWentDown[scancode] = time;
uint time_down = key_data.TimeKeyHeldDown[scancode];
if ( key_is_pressed(scancode) ) {
//Since the stored time only updates on button release and reset on this check,
//the time the button has been held down this time needs to be added
time_down += time - MAX(key_data.TimeKeyWentDown[scancode], last_check_time);
}
key_data.TimeKeyHeldDown[scancode] = 0;
SDL_UnlockMutex( key_lock );
@@ -497,7 +477,7 @@ int key_down_count(int scancode)
//void key_mark( uint code, int state )
void key_mark( uint code, int state, uint latency )
{
uint scancode, breakbit, temp, event_time;
uint scancode, breakbit, event_time;
ushort keycode;
if ( !key_inited ) return;
@@ -520,70 +500,116 @@ void key_mark( uint code, int state, uint latency )
if (breakbit) {
// Key going up
keyd_last_released = scancode;
keyd_pressed[scancode] = 0;
key_data.NumUps[scancode]++;
// What is the point of this code? "temp" is never used!
temp = 0;
temp |= keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT];
temp |= keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT];
temp |= keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL];
temp |= keyd_pressed[KEY_DEBUG_KEY];
if (event_time < key_data.TimeKeyWentDown[scancode]) {
key_data.TimeKeyHeldDown[scancode] = 0;
} else {
key_data.TimeKeyHeldDown[scancode] += event_time - key_data.TimeKeyWentDown[scancode];
int time_held = 0;
if (event_time >= key_data.TimeKeyWentDown[scancode]) {
//If the suspected key lift is "before" the key was pressed (i.e. fluctuating latency) we don't add any time to the pressed time since last poll
time_held = event_time - key_data.TimeKeyWentDown[scancode];
}
Current_key_down = scancode;
if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] ) {
if ( key_is_pressed(KEY_LSHIFT) || key_is_pressed(KEY_RSHIFT) ) {
Current_key_down |= KEY_SHIFTED;
}
if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] ) {
if ( key_is_pressed(KEY_LALT) || key_is_pressed(KEY_RALT) ) {
Current_key_down |= KEY_ALTED;
}
if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] ) {
if ( key_is_pressed(KEY_LCTRL) || key_is_pressed(KEY_RCTRL) ) {
Current_key_down |= KEY_CTRLED;
}
if (scripting::hooks::OnKeyReleased->isActive()) {
scripting::hooks::OnKeyReleased->run(scripting::hook_param_list(
scripting::hook_param("Key", 's', textify_scancode_universal(Current_key_down))));
#ifndef NDEBUG
if ( key_is_pressed(KEY_DEBUG_KEY) ) {
Current_key_down |= KEY_DEBUGGED;
}
#else
if ( key_is_pressed(KEY_DEBUG_KEY) ) {
mprintf(("Cheats_enabled = %i, Key_normal_game = %i\n", Cheats_enabled, Key_normal_game));
if (Cheats_enabled && Key_normal_game) {
Current_key_down |= KEY_DEBUGGED1;
}
}
#endif
if (scripting::hooks::OnKeyReleased->isActive()) {
scripting::hooks::OnKeyReleased->run(scripting::hooks::KeyPressConditions{ static_cast<int>(scancode) },
scripting::hook_param_list(
scripting::hook_param("Key", 's', textify_scancode_universal(Current_key_down)),
scripting::hook_param("RawKey", 's', textify_scancode_universal(scancode)),
scripting::hook_param("TimeHeld", 'i', time_held),
scripting::hook_param("WasOverridden", 'b', key_data.state[scancode] == keyboard::key_state::PRESSED_OVERRIDDEN)
));
}
// Don't increment counters if was overridden
if (key_data.state[scancode] == keyboard::key_state::PRESSED) {
key_data.NumUps[scancode]++;
key_data.TimeKeyHeldDown[scancode] += time_held;
}
key_data.state[scancode] = keyboard::key_state::RELEASED;
} else {
// Key going down
keyd_last_pressed = scancode;
keyd_time_when_last_pressed = event_time;
if (!keyd_pressed[scancode]) {
if (!key_is_pressed(scancode)) {
// First time down
key_data.TimeKeyWentDown[scancode] = event_time;
keyd_pressed[scancode] = 1;
key_data.NumDowns[scancode]++;
key_data.down_check[scancode]++;
//WMC - For scripting
Current_key_down = scancode;
if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] ) {
if ( key_is_pressed(KEY_LSHIFT) || key_is_pressed(KEY_RSHIFT) ) {
Current_key_down |= KEY_SHIFTED;
}
if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] ) {
if ( key_is_pressed(KEY_LALT) || key_is_pressed(KEY_RALT) ) {
Current_key_down |= KEY_ALTED;
}
if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] ) {
if ( key_is_pressed(KEY_LCTRL) || key_is_pressed(KEY_RCTRL) ) {
Current_key_down |= KEY_CTRLED;
}
if (scripting::hooks::OnKeyPressed->isActive()) {
scripting::hooks::OnKeyPressed->run(scripting::hook_param_list(
scripting::hook_param("Key", 's', textify_scancode_universal(Current_key_down))));
#ifndef NDEBUG
if ( key_is_pressed(KEY_DEBUG_KEY) ) {
Current_key_down |= KEY_DEBUGGED;
}
} else if (!keyd_repeat) {
#else
if ( key_is_pressed(KEY_DEBUG_KEY) ) {
mprintf(("Cheats_enabled = %i, Key_normal_game = %i\n", Cheats_enabled, Key_normal_game));
if (Cheats_enabled && Key_normal_game) {
Current_key_down |= KEY_DEBUGGED1;
}
}
#endif
bool overrideKey = false;
if (scripting::hooks::OnKeyPressed->isActive()) {
scripting::hooks::OnKeyPressed->run(scripting::hooks::KeyPressConditions{ static_cast<int>(scancode) },
scripting::hook_param_list(
scripting::hook_param("Key", 's', textify_scancode_universal(Current_key_down)),
scripting::hook_param("RawKey", 's', textify_scancode_universal(scancode))
));
overrideKey = scripting::hooks::OnKeyPressed->isOverride(scripting::hooks::KeyPressConditions{ static_cast<int>(scancode) },
scripting::hook_param_list(
scripting::hook_param("Key", 's', textify_scancode_universal(Current_key_down)),
scripting::hook_param("RawKey", 's', textify_scancode_universal(scancode))
));
}
if (overrideKey) {
key_data.state[scancode] = keyboard::key_state::PRESSED_OVERRIDDEN;
scancode = 0xAA; //Skip queueing this key
}
else {
key_data.state[scancode] = keyboard::key_state::PRESSED;
key_data.NumDowns[scancode]++;
key_data.down_check[scancode]++;
}
} else if (!key_allow_repeat) {
// Don't buffer repeating key if repeat mode is off
scancode = 0xAA;
}
@@ -591,24 +617,24 @@ void key_mark( uint code, int state, uint latency )
if ( scancode!=0xAA ) {
keycode = (unsigned short)scancode;
if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] ) {
if ( key_is_pressed(KEY_LSHIFT) || key_is_pressed(KEY_RSHIFT) ) {
keycode |= KEY_SHIFTED;
}
if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] ) {
if ( key_is_pressed(KEY_LALT) || key_is_pressed(KEY_RALT) ) {
keycode |= KEY_ALTED;
}
if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] ) {
if ( key_is_pressed(KEY_LCTRL) || key_is_pressed(KEY_RCTRL) ) {
keycode |= KEY_CTRLED;
}
#ifndef NDEBUG
if ( keyd_pressed[KEY_DEBUG_KEY] ) {
if ( key_is_pressed(KEY_DEBUG_KEY) ) {
keycode |= KEY_DEBUGGED;
}
#else
if ( keyd_pressed[KEY_DEBUG_KEY] ) {
if ( key_is_pressed(KEY_DEBUG_KEY) ) {
mprintf(("Cheats_enabled = %i, Key_normal_game = %i\n", Cheats_enabled, Key_normal_game));
if (Cheats_enabled && Key_normal_game) {
keycode |= KEY_DEBUGGED1;
@@ -618,14 +644,7 @@ void key_mark( uint code, int state, uint latency )
#endif
if ( keycode ) {
temp = key_data.keytail+1;
if ( temp >= KEY_BUFFER_SIZE ) temp=0;
if (temp!=key_data.keyhead) {
key_data.keybuffer[key_data.keytail] = keycode;
key_data.time_pressed[key_data.keytail] = keyd_time_when_last_pressed;
key_data.keytail = temp;
}
key_data.key_queue.push(keycode);
}
}
}
@@ -659,9 +678,7 @@ void key_init()
FillSDLArray();
keyd_time_when_last_pressed = timer_get_milliseconds();
keyd_buffer_type = 1;
keyd_repeat = 1;
key_allow_repeat = true;
// Clear the keyboard array
key_flush();
+3 -4
View File
@@ -20,9 +20,6 @@ const size_t SIZE_OF_ASCII_TABLE = 128;
extern int shifted_ascii_table[SIZE_OF_ASCII_TABLE];
extern int ascii_table[SIZE_OF_ASCII_TABLE];
extern ubyte keyd_pressed[NUM_KEYS];
// O/S level hooks...
void key_init();
void key_level_init();
@@ -39,12 +36,14 @@ SDL_Scancode fs2_to_sdl( int scancode );
int key_to_ascii(int keycode );
int key_inkey();
bool key_is_pressed(int keycode, bool include_since_last_count = false);
// global flag that will enable/disable the backspace key from stopping execution
//extern int Backspace_debug;
uint key_get_shift_status();
int key_down_count(int scancode);
int key_checkch();
bool key_checkch();
extern SCP_string CheatUsed;
extern int Cheats_enabled;
+34 -47
View File
@@ -183,8 +183,10 @@ factor_table ftables;
// time compression/dilation values - Goober5000
// (Volition sez "can't compress below 0.25"... not sure if
// this is arbitrary or dictated by code)
#define MAX_TIME_MULTIPLIER 64
#define MAX_TIME_DIVIDER 4
constexpr int MAX_TIME_MULTIPLIER = 64;
constexpr int MAX_TIME_DIVIDER = 4;
constexpr int MAX_TIME_MULTIPLIER_RETAIL = 4;
constexpr int MAX_TIME_DIVIDER_RETAIL = 1;
char CheatBuffer[CHEAT_BUFFER_LEN+1];
@@ -215,7 +217,6 @@ static struct Cheat cheatsTable[] = {
int Tool_enabled = 0;
bool Perspective_locked=false;
extern int AI_watch_object;
extern int Countermeasures_enabled;
@@ -749,28 +750,24 @@ void process_debug_keys(int k)
case KEY_DEBUGGED + KEY_SHIFTED + KEY_COMMA:
case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_COMMA:
if ( Game_mode & GM_NORMAL ) {
if ( Game_time_compression > (F1_0/MAX_TIME_DIVIDER) ) {
change_time_compression(0.5);
} else {
gamesnd_play_error_beep();
if (Game_time_compression > (F1_0 / (Cmdline_retail_time_compression_range ? MAX_TIME_DIVIDER_RETAIL : MAX_TIME_DIVIDER))) {
change_time_compression(0.5f);
break;
}
} else {
gamesnd_play_error_beep();
}
gamesnd_play_error_beep();
break;
// Goober5000: handle as normal here
case KEY_DEBUGGED + KEY_SHIFTED + KEY_PERIOD:
case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_PERIOD:
if ( Game_mode & GM_NORMAL ) {
if ( Game_time_compression < (F1_0*MAX_TIME_MULTIPLIER) ) {
change_time_compression(2);
} else {
gamesnd_play_error_beep();
if (Game_time_compression < (F1_0 * (Cmdline_retail_time_compression_range ? MAX_TIME_MULTIPLIER_RETAIL : MAX_TIME_MULTIPLIER))) {
change_time_compression(2.0f);
break;
}
} else {
gamesnd_play_error_beep();
}
gamesnd_play_error_beep();
break;
// Kill! the currently targeted ship.
@@ -800,11 +797,8 @@ void process_debug_keys(int k)
// play the next mission message
case KEY_DEBUGGED + KEY_V:
extern int Message_debug_index;
extern int Num_messages_playing;
// stop any other messages
if(Num_messages_playing){
message_kill_all(1);
}
message_kill_all(true);
// next message
if(Message_debug_index >= Num_messages - 1){
@@ -823,11 +817,8 @@ void process_debug_keys(int k)
// play the previous mission message
case KEY_DEBUGGED + KEY_SHIFTED + KEY_V:
extern int Message_debug_index;
extern int Num_messages_playing;
// stop any other messages
if(Num_messages_playing){
message_kill_all(1);
}
message_kill_all(true);
// go maybe go down one
if(Message_debug_index == Num_builtin_messages - 1){
@@ -1267,17 +1258,17 @@ void process_debug_keys(int k)
case KEY_PADMINUS: {
int init_flag = 0;
if ( keyd_pressed[KEY_1] ) {
if ( key_is_pressed(KEY_1) ) {
init_flag = 1;
HUD_color_red -= 4;
}
if ( keyd_pressed[KEY_2] ) {
if ( key_is_pressed(KEY_2) ) {
init_flag = 1;
HUD_color_green -= 4;
}
}
if ( keyd_pressed[KEY_3] ) {
if ( key_is_pressed(KEY_3) ) {
init_flag = 1;
HUD_color_blue -= 4;
}
@@ -1296,17 +1287,17 @@ void process_debug_keys(int k)
case KEY_PADPLUS: {
int init_flag = 0;
if ( keyd_pressed[KEY_1] ) {
if ( key_is_pressed(KEY_1) ) {
init_flag = 1;
HUD_color_red += 4;
}
if ( keyd_pressed[KEY_2] ) {
if ( key_is_pressed(KEY_2) ) {
init_flag = 1;
HUD_color_green += 4;
}
if ( keyd_pressed[KEY_3] ) {
if ( key_is_pressed(KEY_3) ) {
init_flag = 1;
HUD_color_blue += 4;
}
@@ -1460,7 +1451,7 @@ void process_player_ship_keys(int k)
// moved this line to beginning of function since hotkeys now encompass
// F5 - F12. We can return after using F11 as a hotkey.
ppsk_hotkeys(masked_k);
if (keyd_pressed[KEY_DEBUG_KEY]){
if (key_is_pressed(KEY_DEBUG_KEY)){
return;
}
@@ -2223,31 +2214,27 @@ int button_function_demo_valid(int n)
break;
case TIME_SLOW_DOWN:
if ( Game_mode & GM_NORMAL ) {
ret = 1;
if ( Game_mode & GM_NORMAL && !Time_compression_locked ) {
// Goober5000 - time dilation only available in cheat mode (see above);
// now you can do it with or without pressing the tilde, per Kazan's request
if ( ((Game_time_compression > F1_0) || (Cheats_enabled && (Game_time_compression > (F1_0/MAX_TIME_DIVIDER)))) && !Time_compression_locked) {
if ((Game_time_compression > F1_0) || (Cheats_enabled && (Game_time_compression > (F1_0 / (Cmdline_retail_time_compression_range ? MAX_TIME_DIVIDER_RETAIL : MAX_TIME_DIVIDER))))) {
change_time_compression(0.5f);
} else {
gamesnd_play_error_beep();
break;
}
} else {
gamesnd_play_error_beep();
}
ret = 1;
gamesnd_play_error_beep();
break;
case TIME_SPEED_UP:
if ( Game_mode & GM_NORMAL ) {
if ( (Game_time_compression < (F1_0*MAX_TIME_MULTIPLIER)) && !Time_compression_locked ) {
change_time_compression(2.0f);
} else {
gamesnd_play_error_beep();
}
} else {
gamesnd_play_error_beep();
}
ret = 1;
if ( Game_mode & GM_NORMAL && !Time_compression_locked ) {
if (Game_time_compression < (F1_0 * (Cmdline_retail_time_compression_range ? MAX_TIME_MULTIPLIER_RETAIL : MAX_TIME_MULTIPLIER))) {
change_time_compression(2.0f);
break;
}
}
gamesnd_play_error_beep();
break;
}
-1
View File
@@ -19,7 +19,6 @@
extern int Dead_key_set[];
extern int Dead_key_set_size;
extern bool Perspective_locked;
extern int Ignored_keys[]; //!< Ignored_keys[CCFG_MAX]; Set by sexp. If >0; value is number of times the key will be temporarily. If <0, key is permamently ignored.
+40 -22
View File
@@ -180,17 +180,23 @@ UI_TIMESTAMP ui_timestamp() {
TIMESTAMP timestamp_delta(TIMESTAMP stamp, int delta_ms)
{
if (!stamp.isValid() || stamp.isImmediate() || stamp.isNever())
if (!stamp.isFinite())
return stamp;
if (stamp.isImmediate())
return TIMESTAMP(timestamp_ms() + delta_ms);
return TIMESTAMP(stamp.value() + delta_ms);
}
UI_TIMESTAMP ui_timestamp_delta(UI_TIMESTAMP stamp, int delta_ms)
{
if (!stamp.isValid() || stamp.isImmediate() || stamp.isNever())
if (!stamp.isFinite())
return stamp;
if (stamp.isImmediate())
return UI_TIMESTAMP(timer_get_milliseconds() + delta_ms);
return UI_TIMESTAMP(stamp.value() + delta_ms);
}
@@ -299,6 +305,12 @@ UI_TIMESTAMP ui_timestamp(int delta_ms) {
// Negative value gives milliseconds ago that timestamp elapsed.
int timestamp_until(int stamp)
{
// handle special values
if (stamp <= 0)
return INT_MAX;
if (stamp == 1)
return 0;
// JAS: FIX
// HACK!! This doesn't handle rollover!
// (Will it ever happen?)
@@ -322,8 +334,8 @@ int timestamp_until(int stamp)
int timestamp_until(TIMESTAMP stamp)
{
Assertion(stamp.isValid() && !stamp.isNever(), "timestamp_until was called with a%s timestamp!", !stamp.isValid() ? "n invalid" : " Never");
if (!stamp.isValid() || stamp.isNever())
Assertion(stamp.isFinite(), "timestamp_until was called with a%s timestamp!", !stamp.isValid() ? "n invalid" : " Never");
if (!stamp.isFinite())
return INT_MAX;
if (stamp.isImmediate())
@@ -334,8 +346,8 @@ int timestamp_until(TIMESTAMP stamp)
int ui_timestamp_until(UI_TIMESTAMP stamp)
{
Assertion(stamp.isValid() && !stamp.isNever(), "timestamp_until was called with a%s timestamp!", !stamp.isValid() ? "n invalid" : " Never");
if (!stamp.isValid() || stamp.isNever())
Assertion(stamp.isFinite(), "timestamp_until was called with a%s timestamp!", !stamp.isValid() ? "n invalid" : " Never");
if (!stamp.isFinite())
return INT_MAX;
if (stamp.isImmediate())
@@ -346,13 +358,19 @@ int ui_timestamp_until(UI_TIMESTAMP stamp)
int timestamp_since(int stamp)
{
// handle special values
if (stamp <= 0)
return INT_MIN;
if (stamp == 1)
return 0;
return timestamp_ms() - stamp;
}
int timestamp_since(TIMESTAMP stamp)
{
Assertion(stamp.isValid() && !stamp.isNever(), "timestamp_since was called with a%s timestamp!", !stamp.isValid() ? "n invalid" : " Never");
if (!stamp.isValid() || stamp.isNever())
Assertion(stamp.isFinite(), "timestamp_since was called with a%s timestamp!", !stamp.isValid() ? "n invalid" : " Never");
if (!stamp.isFinite())
return INT_MIN;
if (stamp.isImmediate())
@@ -363,8 +381,8 @@ int timestamp_since(TIMESTAMP stamp)
int ui_timestamp_since(UI_TIMESTAMP stamp)
{
Assertion(stamp.isValid() && !stamp.isNever(), "timestamp_since was called with a%s timestamp!", !stamp.isValid() ? "n invalid" : " Never");
if (!stamp.isValid() || stamp.isNever())
Assertion(stamp.isFinite(), "timestamp_since was called with a%s timestamp!", !stamp.isValid() ? "n invalid" : " Never");
if (!stamp.isFinite())
return INT_MIN;
if (stamp.isImmediate())
@@ -445,9 +463,9 @@ int ui_timestamp_compare(UI_TIMESTAMP t1, UI_TIMESTAMP t2)
bool timestamp_in_between(TIMESTAMP stamp, TIMESTAMP before, TIMESTAMP after)
{
Assertion(stamp.isValid() && !stamp.isNever(), "timestamp_in_between was called with a%s 'stamp' timestamp!", !stamp.isValid() ? "n invalid" : " Never");
Assertion(before.isValid() && !before.isNever(), "timestamp_in_between was called with a%s 'before' timestamp!", !before.isValid() ? "n invalid" : " Never");
Assertion(after.isValid() && !after.isNever(), "timestamp_in_between was called with a%s 'after' timestamp!", !after.isValid() ? "n invalid" : " Never");
Assertion(stamp.isFinite(), "timestamp_in_between was called with a%s 'stamp' timestamp!", !stamp.isValid() ? "n invalid" : " Never");
Assertion(before.isFinite(), "timestamp_in_between was called with a%s 'before' timestamp!", !before.isValid() ? "n invalid" : " Never");
Assertion(after.isFinite(), "timestamp_in_between was called with a%s 'after' timestamp!", !after.isValid() ? "n invalid" : " Never");
if (!stamp.isValid() || !before.isValid() || !after.isValid())
return false;
@@ -457,9 +475,9 @@ bool timestamp_in_between(TIMESTAMP stamp, TIMESTAMP before, TIMESTAMP after)
bool ui_timestamp_in_between(UI_TIMESTAMP stamp, UI_TIMESTAMP before, UI_TIMESTAMP after)
{
Assertion(stamp.isValid() && !stamp.isNever(), "ui_timestamp_in_between was called with a%s 'stamp' timestamp!", !stamp.isValid() ? "n invalid" : " Never");
Assertion(before.isValid() && !before.isNever(), "ui_timestamp_in_between was called with a%s 'before' timestamp!", !before.isValid() ? "n invalid" : " Never");
Assertion(after.isValid() && !after.isNever(), "ui_timestamp_in_between was called with a%s 'after' timestamp!", !after.isValid() ? "n invalid" : " Never");
Assertion(stamp.isFinite(), "ui_timestamp_in_between was called with a%s 'stamp' timestamp!", !stamp.isValid() ? "n invalid" : " Never");
Assertion(before.isFinite(), "ui_timestamp_in_between was called with a%s 'before' timestamp!", !before.isValid() ? "n invalid" : " Never");
Assertion(after.isFinite(), "ui_timestamp_in_between was called with a%s 'after' timestamp!", !after.isValid() ? "n invalid" : " Never");
if (!stamp.isValid() || !before.isValid() || !after.isValid())
return false;
@@ -476,7 +494,7 @@ bool timestamp_elapsed(int stamp) {
}
bool timestamp_elapsed(TIMESTAMP stamp) {
if (!stamp.isValid() || stamp.isNever()) {
if (!stamp.isFinite()) {
return false;
}
if (stamp.isImmediate()) {
@@ -487,7 +505,7 @@ bool timestamp_elapsed(TIMESTAMP stamp) {
}
bool ui_timestamp_elapsed(UI_TIMESTAMP ui_stamp) {
if (!ui_stamp.isValid() || ui_stamp.isNever()) {
if (!ui_stamp.isFinite()) {
return false;
}
if (ui_stamp.isImmediate()) {
@@ -498,7 +516,7 @@ bool ui_timestamp_elapsed(UI_TIMESTAMP ui_stamp) {
}
bool timestamp_elapsed_last_frame(TIMESTAMP stamp) {
if (!stamp.isValid() || stamp.isNever()) {
if (!stamp.isFinite()) {
return false;
}
if (stamp.isImmediate()) {
@@ -509,7 +527,7 @@ bool timestamp_elapsed_last_frame(TIMESTAMP stamp) {
}
bool ui_timestamp_elapsed_last_frame(UI_TIMESTAMP ui_stamp) {
if (!ui_stamp.isValid() || ui_stamp.isNever()) {
if (!ui_stamp.isFinite()) {
return false;
}
if (ui_stamp.isImmediate()) {
@@ -528,7 +546,7 @@ bool timestamp_elapsed_safe(int a, int b) {
}
bool timestamp_elapsed_safe(TIMESTAMP a, int b) {
if (!a.isValid() || a.isNever()) {
if (!a.isFinite()) {
return false;
}
if (a.isImmediate()) {
@@ -539,7 +557,7 @@ bool timestamp_elapsed_safe(TIMESTAMP a, int b) {
}
bool ui_timestamp_elapsed_safe(UI_TIMESTAMP a, int b) {
if (!a.isValid() || a.isNever()) {
if (!a.isFinite()) {
return false;
}
if (a.isImmediate()) {
+2
View File
@@ -47,6 +47,7 @@ public:
inline bool isNever() const { return m_val == 0; }
inline bool isImmediate() const { return m_val == 1; }
inline bool isFinite() const { return isValid() && !isNever(); }
};
// Timestamp measuring game time. Sensitive to time compression and pausing.
@@ -63,6 +64,7 @@ public:
inline bool isNever() const { return m_val == 0; }
inline bool isImmediate() const { return m_val == 1; }
inline bool isFinite() const { return isValid() && !isNever(); }
};
// For converting from old-style timestamps:
+1 -1
View File
@@ -407,7 +407,7 @@ void CJumpNode::Render(model_draw_list *scene, const vec3d *pos, const vec3d *vi
matrix node_orient = IDENTITY_MATRIX;
int mr_flags = MR_NO_LIGHTING | MR_NO_BATCH;
uint64_t mr_flags = MR_NO_LIGHTING | MR_NO_BATCH;
if(!(m_flags & JN_SHOW_POLYS)) {
mr_flags |= MR_NO_CULL | MR_NO_POLYS | MR_SHOW_OUTLINE | MR_SHOW_OUTLINE_HTL | MR_NO_TEXTURING;
}
+1 -1
View File
@@ -31,7 +31,7 @@ void LabUi::object_changed()
trigger = false;
}
void LabUi::build_species_entry(species_info species_def, int species_idx) const
void LabUi::build_species_entry(const species_info &species_def, int species_idx) const
{
with_TreeNode(species_def.species_name)
{
+1 -1
View File
@@ -13,7 +13,7 @@ class LabUi {
private:
void build_options_menu();
void build_ship_list() const;
void build_species_entry(species_info species_def, int species_idx) const;
void build_species_entry(const species_info &species_def, int species_idx) const;
void build_weapon_list() const;
void build_weapon_subtype_list() const;
void build_background_list() const;
+1
View File
@@ -95,6 +95,7 @@ void LabRenderer::renderModel(float frametime) {
Ships[obj->instance].flags.set(Ship::Ship_Flags::Render_without_miscmap, renderFlags[LabRenderFlag::NoMiscMap]);
Ships[obj->instance].flags.set(Ship::Ship_Flags::Render_without_weapons, !renderFlags[LabRenderFlag::ShowWeapons]);
Ships[obj->instance].flags.set(Ship::Ship_Flags::Render_without_ambientmap, renderFlags[LabRenderFlag::NoAOMap]);
Ships[obj->instance].flags.set(Ship::Ship_Flags::No_insignias, !renderFlags[LabRenderFlag::ShowInsignia]);
Ships[obj->instance].team_name = currentTeamColor;
+8 -2
View File
@@ -118,7 +118,13 @@ static auto DeferredLightingOption = options::OptionBuilder<bool>("Graphics.Defe
bool light_deferred_enabled()
{
if (Using_in_game_options) {
return DeferredLightingOption->getValue();
static bool isToggledOn = DeferredLightingOption->getValue();
// This used to be getting the value of the option object itself,
// however that is not a free operation and changing it requires a restart anyway
// if the restart requirement is lifted care should be taken to cache this value
// and never look it up more than once a frame
// otherwise the performance footprint is measurable enough to worry about.
return isToggledOn;
} else {
return !Cmdline_no_deferred_lighting;
}
@@ -314,7 +320,7 @@ void light_rotate_all()
*/
int light_get_global_count()
{
return (int)Static_light.size();
return static_cast<int>(Static_light.size());
}
/**
+1 -1
View File
@@ -64,7 +64,7 @@ bool *Lcl_unexpected_tstring_check = nullptr;
// NOTE: with map storage of XSTR strings, the indexes no longer need to be contiguous,
// but internal strings should still increment XSTR_SIZE to avoid collisions.
// retail XSTR_SIZE = 1570
// #define XSTR_SIZE 1842 // This is the next available ID
// #define XSTR_SIZE 1857 // This is the next available ID
// struct to allow for strings.tbl-determined x offset
Loaded 100 of 549 files, more files were not shown because too many files have changed in this diff. Show more