Compare commits

...
Author SHA1 Message Date
Fabian Woltermann 5b01036723 vm_vec_random_cone needs to be called with the smaller angle first.
This also adds a check to that function to swap the values around should that not be the case
2018-08-10 17:26:42 +02:00
Fabian Woltermann 8a2641181f Merge pull request #1816 from asarium/fix/1815
Don't reset mission file name on mission end
2018-07-28 18:47:17 +02:00
m!m 36e8c3b623 Merge pull request #1814 from TRBlount/fix/random_cone
Fix vm_vec_random_cone/sphere functions
2018-07-28 18:44:58 +02:00
TRBlount 1c2a136ef7 Fix vm_vec_random_cone/sphere functions 2018-07-28 09:11:59 -06:00
asarium 72272cb8cf Don't reset mission file name on mission end
This was needed by the restart dialog action and got removed since the
Discord changes needed to know if a mission was active or not.

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

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

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

This fixes #1754 by properly handling that case.

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

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

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

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

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

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

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

This should result in slightly more efficient code.

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

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

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

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

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

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

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

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

Removes an unused parameter.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

This fixes that by adding a check for when the config locations were
last modified. On Linux and Mac it checks when the old config locations
were modified last while on Windows it checks the registry to determine
if there was a change after the new config file was created.
2018-06-02 12:09:21 +02:00
Fabian Woltermann b848823a2f Merge pull request #1670 from asarium/feature/bitmapBlocks
Add new bmpman slot management system
2018-06-02 12:08:22 +02:00
Fabian Woltermann 61c533559b Removes an assert in object.cpp that was commented out and sets the number of retail stars to 0 when resetting the background in the lab 2018-06-02 11:58:01 +02:00
Goober5000 04b0f5bb75 Merge pull request #1721 from asarium/fix/unicodeScramble
Fix scrambling unicode messages
2018-06-01 17:24:04 -04:00
Goober5000 fdbba84a5b Merge pull request #1733 from Goober5000/fix_issue_1708
fix issue #1708
2018-05-31 15:52:46 -04:00
asarium e92121bed4 Remove unnecessary function pointer dereferences in gr API
Multiple function pointer dereferences are valid in C but do not change
the result of the operation. The graphics API had some function
definitions which used multiple pointer dereferences while the rest of
the functions did not.

This changes all occurences of the double dereferences to normal GR_CALL
declarations to keep the style in the API definitions consistent.
2018-05-31 15:07:20 +02:00
asarium 079ad97987 Fix clang-tidy issues in Assertion macro 2018-05-30 10:00:42 +02:00
asarium 7ae276fe6a Fix scrambling unicode messages
The code did not account for unicode escape sequences when inserting
scrambling characters which distorted the text and fequently caused
invalid UTF-8 sequences to appear in the text. This fixes that by
using the text iterators already present in the game code. I needed to
rewrite the logic of this block a bit since the previous logic could not
be converted to the way we need to handle unicode sequences at the
moment.

This fixes #1720.
2018-05-30 10:00:42 +02:00
Goober5000 45ddc8ac44 Merge pull request #1729 from chief1983/lib/sdl208
lib/sdl208: Upgrade the included SDL libs to 2.0.8.
2018-05-29 18:57:48 -04:00
Goober5000 6fa422c5e7 fix issue #1708 2018-05-29 17:04:31 -04:00
Cliff Gordon 35c830062d lib/sdl208: Upgrade the included SDL libs to 2.0.8. 2018-05-29 08:39:28 -05:00
Goober5000 243a5bb473 Merge pull request #1702 from Goober5000/minor_sexp_subsystem_cleanup
minor sexp subsystem cleanup
2018-05-29 00:21:29 -04:00
asarium 09abbe1789 Add new bmpman slot management system
This changes how the bitmap slots are managed by the bmpman system.
Instead of allocating a fixed-size array when the game starts this will
manage multiple "blocks" of bitmap slots. When the engine runs out of
slots in the already allocated blocks it simply creates a new block and
allocates the new slot in that.

This removed the hard limit on how many bitmaps can be loaded at the
same time and should fix issues encountered by mods which use a lot of
bitmap slots (I'm looking at you Spoon).

This implements the idea described in #1503.
2018-05-28 09:51:15 +02:00
asarium ad52278a67 Fix clang-tidy issues in Assertion macro 2018-05-28 09:51:15 +02:00
m!m e0a9c88241 Merge pull request #1716 from asarium/build/clang-tidy-diff
Use clang-tidy-diff to only check changed lines
2018-05-27 18:00:25 +02:00
m!m f45dcfc09a Merge pull request #1732 from asarium/fix/appveyorQt
Fix Appveyor Qt build issue
2018-05-26 16:54:23 +02:00
asarium 2036ebd3a0 Fix Appveyor Qt build issue
Apparently, Appveyor has removed the Qt version 5.7 from their servers
which was used by FSO previously. I have updated the paths to use Qt
5.9.5 instead now but there is a problem with Visual Studio 2013 since
there is no 32-bit Qt version for that compiler installed in the
Appveyor system.

For that reason, I decided to use Visual Studio 2015 instead for the
32-bit builds which means that Visual Studio 2013 will not be tested by
Appveyor anymore. Since no one is using that compiler version anymore
that shouldn't be a big issue.

This should fix the CI issues seen on recent PRs and commits.
2018-05-26 14:05:30 +02:00
m!m 469270d4b6 Merge pull request #1701 from Goober5000/is_in_turret_fov
is-in-turret-fov sexp
2018-05-17 19:34:49 +02:00
m!m e59df5d83c Merge pull request #1726 from Goober5000/sexp_bitwise_tweak
make the set-bit and is-bit-set operators fail gracefully
2018-05-17 19:31:22 +02:00
Goober5000 880e03e5d1 requested changes from code review 2018-05-15 22:04:20 -04:00
Goober5000 c1196f8286 requested changes from code review 2018-05-15 21:56:39 -04:00
Goober5000 40cd9e4c07 make the set-bit and is-bit-set operators fail gracefully
These operators used to warn and return NAN if they were given a bit index out of range.  For FREDding convenience, out-of-range bit indexes are now a no-op.  This is particularly helpful in the situation where a FREDder needs to evaluate an extended bit array, one 32-bit chunk at a time, e.g.

0-31 bits: offset 0
32-63 bits: offset -32
64-95 bits: offset -64
96-127 bits: offset -96

Because the sexp system always evaluates every argument, three out of four branches were always evaluated with invalid bit indexes (negative or too large) even if the sexp logic only used one branch.  The new method silently bypasses this behavior.
2018-05-07 18:44:58 -04:00
MageKing17 a90e480b61 Merge pull request #1724 from asarium/fix/showShipViewerMode
Fix "show-ship" flag
2018-05-05 11:35:27 -07:00
asarium 142ae846f4 Fix "show-ship" flag
The viewer mode check seemed to be wrong but I am not entirely sure if I
fixed this correctly. The Viewer_mode variable is a big mess of bitflags
that are not very consistent in what they mean.
2018-05-05 12:25:44 +02:00
asarium 7a827dcb0e Enable all modernize tests by default
This will report the usage of old coding patterns in new code.
modernize-raw-string-literal is disabled since it doesn't work right
with strings with special escape sequences in them.
modernize-use-using is disabled since typedefs are more common in the
FSO code.
2018-05-04 10:03:22 +02:00
asarium 619cb607d0 Use clang-tidy-diff to only check changed lines
This will only check the lines that were changed by a commit or pull
request. This makes it possible to enable more clang-tidy checks without
having to fix all occurences of the warnings in the code base.

Please note that the changes do not work correctly with rebased branches
due to the way Travis CI supplies the commit range. Pull requests will
always be checked properly though.
2018-05-02 12:26:05 +02:00
m!m 56c34eee6d Merge pull request #1685 from asarium/build/clang-tidy-2
Enable and fix more clang-tidy warnings
2018-05-01 19:35:46 +02:00
Fabian Woltermann 379031534d Merge pull request #1718 from asarium/fix/1717
Fix fog rendering in forward renderer
2018-04-29 18:49:04 +02:00
asarium 64b08f51c0 Fix fog rendering in forward renderer
There were actually two bugs here that were fixed:
1. The model draw list code disabled the fog rendering when it thought
it was it deferred rendering mode but did not account for explicitly
disabling the deferred renderer.
2. The fog effect was applied to both the emissive color and the base
color simultaneously which caused visual errors when rendering fogged
objects using the deferred renderer.

This fixes #1717.
2018-04-28 13:53:09 +02:00
asarium adfa12a706 Disable clang-tidy in release mode
The unused parameter warning cannot be disabled easily in release mode
for clang-tidy so this needs to be done to avoid false-positived in
release mode.
2018-04-25 11:57:56 +02:00
asarium d71a589b0f Use CMake 3.8 to make sure clang-tidy warnings fail the build
Previous versions do not support failing the build if warnings should be
treated as errors.
2018-04-25 11:57:56 +02:00
asarium 5118d94d5d Update header filter regex in .clang-tidy 2018-04-25 11:57:56 +02:00
asarium 17179d5b0b Fix unreferenced local variable warning 2018-04-25 11:57:55 +02:00
asarium bd3632d1bf Enable remaining misc- checks and fix detected issues 2018-04-25 11:57:55 +02:00
asarium eeed22b91a Enable misc-unused-parameters
clang-tidy was used for fixing the warnings. It is not clear if this is
actually an improvement so this may still be disabled later.
2018-04-25 11:57:55 +02:00
asarium 48873185ce Another batch of misc- checks 2018-04-25 11:13:20 +02:00
asarium e28ebc2a6c Enable and fix misc-suspicious-string-compare check 2018-04-25 11:13:19 +02:00
asarium dcac9e7223 Enable more misc- checks 2018-04-25 11:12:41 +02:00
asarium 0b4ca71eba Enable modernize-deprecated-headers 2018-04-25 11:12:41 +02:00
asarium 24c3c439d5 Test clang-tidy issues in test code 2018-04-25 11:12:41 +02:00
m!m 706973cb6b Merge pull request #1672 from asarium/feature/typesafeIDs
Add typesafe handle types and use it in game sound system
2018-04-25 10:36:46 +02:00
Fabian Woltermann 91a5bfa74a Merge pull request #1707 from asarium/feature/persistentParticles
Improve handling of non-persistent particles
2018-04-25 10:14:39 +02:00
asarium f7b0f93c00 Port goal editor dialog code to qtFRED
The sexp_tree widget makes the model based dialog a bit ugly here since
it is required for some model operations even though it is a UI
component. In the future it could be split into a model component and an
UI component to allow better separation between model and UI.
2018-04-22 21:43:01 +02:00
m!m 2721c452c4 Merge pull request #1680 from asarium/qtfred2_/eventDialog
Port event editor dialog code to qtFRED
2018-04-22 21:39:57 +02:00
m!m 1030e29ef7 Merge pull request #1703 from asarium/qtfred2_/missionSave
Port mission save code to qtFRED
2018-04-22 17:40:48 +02:00
asarium 8f06e338a4 Add typesafe handle types and use it in game sound system
This adds a new class which allows to create type safe resource handle
types. At the moment, the engine uses ints pretty much everywhere for
providing handles to resources created by the specific subsystems. Since
all ints are the same to the C/C++ typesystem it is perfectly legal to
pass a sound handle to the graphics API as a buffer handle which will
obviously cause issues.

This adds a new type called "ID" which is a wrapper class for a generic
handle but with added type safety. An instance of this class cannot be
passed to a function expecting another type of handle which provided
compile-time type safety for these APIs.

As an initial test I converted the game sound handles to this new type.
I already found a bug in the mainhall system thanks to this new type.
The mainhall used the game sound handles as sound instance handles which
probably meant that that specific code never really worked right. I
removed the code since there was no better alternative for fixing it.
2018-04-22 16:22:45 +02:00
asarium d1a6b48beb Improve handling of non-persistent particles
The current particle system uses dynamic allocation of particle
instances for keeping track of particle instances. This adds unnecessary
overhead in case the code does not need a handle to this particle which
is the case in pretty much all instances.

The new non-persistent particles are stored in a standard vector without
dynamic allocation which should make the processing steps using this
vector much faster and allow better scalability in case more particles
are used by a mission.
2018-04-22 16:22:28 +02:00
asarium ce8fc0a373 Try to close the window on Esc key presses
This will allow the user to cancel the operation or save their changes
instead of discarding them without question.
2018-04-22 16:21:55 +02:00
asarium 991f131376 Fix Clang warnings 2018-04-22 16:21:55 +02:00
asarium ed7917cb26 Port event handling part of Event editor code 2018-04-22 16:21:55 +02:00
asarium e6e6288423 Replace interface functions with qt signals 2018-04-22 16:21:55 +02:00
asarium 48a6361586 Port message handling code of event editor dialog 2018-04-22 16:21:55 +02:00
asarium 8a2faa8b99 Port mission save code to qtFRED
This is pretty much an exact copy of the mission save code of FRED2. I
removed the campaign save code for now since it requires some
interactions with the campaign editor which does not exist yet.
2018-04-22 16:21:41 +02:00
m!m 7d139f9e80 Merge pull request #1667 from asarium/build/teaci
Add TeaCI config file and fix MinGW warnings
2018-04-22 11:23:18 +02:00
m!m cf93aa43c5 Merge pull request #1709 from jg18/qtfred2_/shieldSystemDialog
Finish shield system editor dialog in qtFRED
2018-04-21 23:24:08 +02:00
asarium 89e3533106 Add TeaCI config file
TeaCI is a CI service which provides MinGW CI builds (in Docker
containers so no "real" Windows machines). This would be useful for
validating the Windows only code with additional GCC warnings. It would
also make sure that the MinGW setup we currently have continues to work.
2018-04-21 23:01:19 +02:00
m!m a3f9febdc4 Merge pull request #1668 from asarium/build/minGWFixes
Fix various issues detected by MinGW
2018-04-21 22:59:54 +02:00
jg18 3c738312de make corrections to shield system dialog based on feedback 2018-04-21 12:52:01 -07:00
jg18 363d6d3ba0 finish shield system editor dialog in qtFRED 2018-04-21 12:52:01 -07:00
niffiwan 5578825bf3 Merge pull request #1662 from asarium/fix/luaWaypointAPI
Fix Assert in Lua API when passing invalid name to mn.WaypointList
2018-04-21 23:31:51 +10:00
asarium 9b5710e8c3 Fix various issues detected by MinGW
This fixes various issues I found while trying to compile FSO in a cross
compilation setup using MinGW. This is a prerequisite for merging Tea-CI
support.
2018-04-21 15:13:25 +02:00
m!m b527dd5449 Merge pull request #1665 from asarium/fix/1664
Validate number of parsed briefing stages and icons
2018-04-21 12:47:26 +02:00
m!m 175668e2bb Merge pull request #1700 from asarium/qtfred2_/fixWindowsError
Fix Windows deployment issue
2018-04-21 12:45:55 +02:00
m!m cbf3052094 Merge pull request #1673 from asarium/build/ciFRED
Reenable FRED building for Appveyor
2018-04-21 12:45:34 +02:00
m!m 3507cf96d1 Merge pull request #1711 from asarium/fix/fredStaticInitializer
Fix crash on FRED startup in debug mode
2018-04-20 21:05:10 +02:00
asarium e624f6c1a8 Fix crash on FRED startup in debug mode
The crash was caused by a static initialization order problem where the
static initializer of the FRED app was called before the initializer of
the outwnd filter vector.

This fixes that by initializing the vector as soon as necessary through
the use of a function with a static variable.
2018-04-20 19:52:57 +02:00
asarium 371aad8f8c Fix warnings in FRED code 2018-04-20 14:46:21 +02:00
asarium cb3fd31db4 Reenable FRED building for Appveyor
Apparently this was also disabled accidentally when qtFRED was merged
into master.
2018-04-20 14:46:21 +02:00
niffiwan e2e7eac0c6 Merge pull request #1705 from asarium/qtfred2_/updatedReadme
Update qtFRED readme and add some documentation
2018-04-18 20:46:01 +10:00
asarium 80faaf88b0 Update qtFRED readme and add some documentation
This fixes #1696.
2018-04-18 11:41:29 +02:00
Goober5000 fb0f7dd7de minor sexp subsystem cleanup
Synchronize the two subsystem-of-ship checks in sexp.cpp and sexp_tree.cpp.  Mostly this is just adding OP_BEAM_FLOATING_FIRE to sexp_tree.cpp because whoever added that sexp forgot to add it there.
2018-04-15 18:49:37 -04:00
Goober5000 62aae9d793 add optional argument for distance/range 2018-04-15 18:24:58 -04:00
Goober5000 15663a3551 add is-in-turret-fov sexp
Returns true if the ship is in a turret's FOV, false otherwise.  Requested by JSRNerdo.  Uses the object_in_turret_fov internal function which is the same one used by the turret code when it checks whether it can fire.
2018-04-15 17:59:04 -04:00
m!m 6df837e7f3 Merge pull request #1686 from PeterMitsis/experiment
Minor clean up
2018-04-15 23:06:38 +02:00
asarium 512d08e443 Fix Windows deployment issue
The CMake code did not specify that qwindows.cll also needed to be
distributed with the application which caused errors for users who had
not installed Qt on their system.

This should make qtFRED redistributable without needing a QT
installation.
2018-04-15 19:35:06 +02:00
Peter Mitsis 504abeb305 ship: Remove unused routine ship_select_next_valid_secondary_bank()
Signed-off-by: Peter Mitsis <[email protected]>
2018-04-15 12:58:05 -04:00
Peter Mitsis 2ae2f2910c asteroid: Remove unused routine hud_target_asteroid()
Signed-off-by: Peter Mitsis <[email protected]>
2018-04-15 10:51:50 -04:00
Peter Mitsis 3b4fbde8e6 collide: Apply static keyword to applicable routines
Applying the 'static' keyword to applicable routines both informs the
developer where the routine is likely to be used as well as allows the
compiler to perform additional optimizations.

Signed-off-by: Peter Mitsis <[email protected]>
2018-04-14 19:57:04 -04:00
Peter Mitsis 2d01cd2366 shiphit: apply static keyword to applicable routines
Applies the 'static' keyword to applicable routines to both make it
more clear to the developer where such routines are likely to be used
as well as to provide additional information to the compiler so it can
make better optimizations.

Signed-off-by: Peter Mitsis <[email protected]>
2018-04-14 19:57:04 -04:00
Peter Mitsis 2beb136ecf shipfx: Apply static keyword to applicable routines
Applying the static keyword to applicable routines makes it both
more clear to the developer where those routines are likely to be
used as well as provide additional information to the compiler to
allow it to make better optimization choices.

Signed-off-by: Peter Mitsis <[email protected]>
2018-04-14 19:57:04 -04:00
Peter Mitsis c728cc40b2 ship: Apply static keyword to ship routines
Applies the 'static' keyword to various sihp related routines. This both
makes it more clear to the developer where those routines might be used
as well as allowing the compiler to leverage that knowledge and potentially
make additional optimizations.

Signed-off-by: Peter Mitsis <[email protected]>
2018-04-14 19:57:04 -04:00
Peter Mitsis d13ddb387f asteroid: Remove unused routines
Removes the following two routines as not only are they unused, but
they have been unused for years.
    get_debris_from_same_group()
    asteroid_get_random_in_cone()

Signed-off-by: Peter Mitsis <[email protected]>
2018-04-14 19:57:03 -04:00
Peter Mitsis 666c177dec Fix asteriod typo
Replaces instances of 'asteriod' with 'asteroid'.

Signed-off-by: Peter Mitsis <[email protected]>
2018-04-14 19:57:03 -04:00
Peter Mitsis d5ba2369a2 asteroid: Apply static keyword to asteroid routines
Applies the 'static' keyword to various asteroid routines. This both
makes it more clear to the developer where those routines might be used
as well as allowing the compiler to leverage that knowledge and potentially
make additional optimizations.

Signed-off-by: Peter Mitsis <[email protected]>
2018-04-14 19:57:03 -04:00
Peter Mitsis 7bf7a8fc66 keycontrol: Remove reference to hud_target_asteroid()
Removes the extern declaration of hud_target_asteroid() from
keycontrol.cpp as it is not used in that module.

Signed-off-by: Peter Mitsis <[email protected]>
2018-04-14 19:57:03 -04:00
Fabian Woltermann a3d2320f0a Merge pull request #1681 from asarium/build/clang-tidy
Add clang-tidy to Travis CI configuration
2018-04-14 11:48:30 +02:00
asarium 9d352ddc5f Fix .clang-tidy format 2018-04-13 16:26:57 +02:00
MageKing17 299e584284 Merge pull request #1684 from asarium/fix/1683
Set team_glow_enabled uniform to proper value
2018-04-13 07:13:48 -07:00
asarium 4f22b12ec6 Mark all external libraries as system includes 2018-04-13 15:40:11 +02:00
asarium 57985b5f1a Enable misc-new-delete-overloads 2018-04-13 12:10:24 +02:00
asarium 513115ceeb Enable misc-noexcept-move-constructor check 2018-04-13 12:10:24 +02:00
asarium 95acebfce8 Add misc-multiple-statement-macro check 2018-04-13 12:10:24 +02:00
asarium ca5605cfb4 Add misc-move-forwarding-reference check 2018-04-13 12:10:24 +02:00
asarium ea4e5f222d Make .clang-tidy easier to read 2018-04-13 12:10:22 +02:00
asarium 538afc73a2 Keep building on Travis CI until more errors have occured
This will make it easier to find warnings and clang-tidy notifications
since ninja won't stop after the first warning or error was reported.
2018-04-13 12:10:03 +02:00
asarium 16560326e7 Add more clang-tidy checks 2018-04-13 12:10:01 +02:00
asarium 68372b18a2 Enable performance clang-tidy warnings 2018-04-13 12:08:56 +02:00
asarium c6abe74f06 Replace noexcept with compatibility macro 2018-04-13 12:08:07 +02:00
asarium f1c79c2ca7 Fix override warnings produced by clang-tidy 2018-04-13 12:08:06 +02:00
asarium 7944eda1cb Add Clang-tidy support 2018-04-13 11:40:38 +02:00
asarium 1571caa95e Set team_glow_enabled uniform to proper value
This was missed when converting the model uniforms to a uniform buffer
and caused some issues with team colors. This sets that uniform to the
value it had before the uniform buffer changes.

This fixes #1683.
2018-04-13 10:36:32 +02:00
m!m 9f97ea909a Merge pull request #1669 from jg18/qtfred2_/fictionViewerDialog
Add fiction viewer dialog to qtFRED
2018-04-13 09:57:01 +02:00
MageKing17 7469558e97 Merge pull request #1676 from asarium/fix/jsonOutputEfxSupport
Write EFX support information to JSON output
2018-04-12 17:10:38 -07:00
jg18 6747c630af Finish up qtFRED fiction viewer dialog 2018-04-11 21:45:38 -07:00
jg18 d80d8dd08e Use SignalBlockers with fiction viewer dialog 2018-04-09 23:51:19 -07:00
jg18 5ebf806c72 fix CI error about unused variable 2018-04-09 23:51:19 -07:00
jg18 6d2d092cc6 wrapup fiction viewer dialog corrections 2018-04-09 23:51:18 -07:00
jg18 cafee9c66a Add qtFRED notice about multiple fiction viewer stages 2018-04-09 23:51:18 -07:00
jg18 8fc281c7be Fix bugs in qtFRED fiction viewer dialog 2018-04-09 23:51:02 -07:00
jg18 8cae09bfe8 Add fiction viewer dialog to qtFRED (WIP) 2018-04-09 23:43:10 -07:00
jg18 5c5e48847e Add qtFRED keyboard shortcut for fiction viewer dialog 2018-04-09 23:42:47 -07:00
Joshua Glatt ae17e3f4b7 Merge pull request #1679 from asarium/qtfred2_/initSystem
Copy original FRED initialization code
2018-04-09 08:08:27 -07:00
m!m ebfc904e52 Merge pull request #1678 from jg18/qtfred2_/guisGalore
Add GUIs for background, shield system, and voice acting editors to qtFRED
2018-04-09 09:47:24 +02:00
asarium f3a3ed982f Copy original FRED initialization code
This copies the original FRED code for initializing the individual game
systems to qtFRED. This should fix the various issues caused by missing
game system initialization calls.
2018-04-09 09:45:41 +02:00
jg18 fabf05454b Make corrections to background editor UI and add dialog shortcut 2018-04-08 21:12:35 -07:00
m!m d309644e53 Merge pull request #1677 from jg18/qtfred2_/blockUiUpdate
Add SignalBlockers to qtFRED
2018-04-08 10:56:37 +02:00
jg18 63b21893df add stub dialog implementations and more corrections 2018-04-07 23:58:43 -07:00
jg18 81f4c03364 corrections to new GUIs 2018-04-07 23:01:04 -07:00
jg18 3668ce67d5 Add SignalBlockers to qtFRED 2018-04-07 19:52:23 -07:00
asarium 28ddf7d8d2 Write EFX support information to JSON output
The initial JSON flags output lacked this information but it is needed
for proper support by the launcher. This adds a new entry in the JSON
structure without changing anything else so it does not require a new
output version.
2018-04-06 13:48:49 +02:00
jg18 b2d427fb00 Add .ui files for background, shield system, and voice acting editor dialogs 2018-04-01 15:31:46 -07:00
Fabian Woltermann 3a4d5788a8 Merge pull request #1675 from asarium/fix/textureDetail
Fix texture detail errors
2018-04-01 20:34:53 +02:00
asarium 7e3ca7eb46 Fix texture detail errors
When I made the texture array changes I forgot to test the texture
detail feature which caused some visual corruption when using a texture
detail which was less than the maximum. This should fix that.
2018-04-01 13:21:14 +02:00
Fabian Woltermann 95620e5de6 Merge pull request #1671 from asarium/fix/soundSetObjectSounds
Assign minimum and maximum value properly in RandomRange
2018-03-29 15:31:04 +02:00
asarium ae738abcf5 Assign minimum and maximum value properly in RandomRange
The minimum and maximum values were not initialized correctly which
caused code which relied on those values to fail unexpectedly.

This assigns the value properly and adds a documentation note which
clarifies when the values are valid.
2018-03-29 14:25:37 +02:00
Tyler Blount e3c815c194 Merge pull request #1657 from asarium/qtfred2_/sexpContextMenu
Add SEXP tree context menu building
2018-03-19 10:53:16 -06:00
asarium daca57de4c Add replace Variable implementation 2018-03-18 22:56:59 +01:00
asarium 5650199b04 Implement "Add paste" 2018-03-18 19:10:22 +01:00
asarium b1e392be2f Add support for adding typed data 2018-03-18 18:58:10 +01:00
asarium 9f0e21f941 Fix menu enablement status
Also added simple add Data implementations
2018-03-18 18:46:19 +01:00
asarium 5258066545 Validate number of parsed briefing stages and icons
This fixes two possible assertions and two possible buffer overflows
which could have been caused by a mission with wrong values for
$num_stages and $num_icons.

This fixes #1664.
2018-03-18 15:50:10 +01:00
asarium f740583547 Add add/replace/insert actions 2018-03-18 15:49:01 +01:00
asarium fd92813198 Add Cut/Copy/Paste action handlers 2018-03-18 10:35:28 +01:00
asarium fc87b129ac Add expand all action 2018-03-18 10:27:08 +01:00
asarium d5509411de Add data editing support 2018-03-18 10:27:02 +01:00
asarium a1d7ec7855 Add delete action handler 2018-03-17 17:37:56 +01:00
asarium 7d3bc7fc58 Add support for the start_mission parameter to qtFRED 2018-03-17 17:06:50 +01:00
asarium 6ed82d88a9 Fix minor issues in editor code 2018-03-17 17:04:13 +01:00
m!m 8b49ebf323 Merge pull request #1660 from The-E/feature/ogl_anisotropy
Make the OGL_Anisotropy setting more usable
2018-03-17 10:22:51 +01:00
Goober5000 4bcc85e963 Merge pull request #1661 from asarium/fix/booleanSexpCrash
Fix wrong return value when getting boolean value from Lua
2018-03-16 22:19:30 -04:00
asarium 55c1c3ce9d Fix wrong handle return type 2018-03-16 23:53:34 +01:00
asarium 2bddcf8344 Fix Assert in Lua API when passing invalid name to mn.WaypointLists
Since atoi return 0 on error the code tries to access the waypoint list
with index -1 which causes an assert in the lookup code. This fixes that
by using the error detection capabilities of strtol.
2018-03-16 23:53:19 +01:00
asarium 235391154e Fix wrong return value when getting boolean value from Lua
This is probably a bug from when I changed how those functions worked.
The function is supposed to return if it successfully retreived a value
from the Lua stack but instead of returning true if it was, it returned
the value it just retrieved. This works fine if that value is true but
causes issues if it was false.
2018-03-16 22:32:58 +01:00
Fabian Woltermann 758ca86f6f And fix the other one too 2018-03-16 20:10:21 +01:00
Fabian Woltermann 6406e2fbd4 fix variable conversion warning 2018-03-16 15:53:19 +01:00
Fabian Woltermann 1c5bf39e8d Use GL_max_anisotropy by default 2018-03-16 13:05:21 +01:00
Fabian Woltermann 18c2dbbde9 WIP fix for #1653.
This adds a step to the post-mission cleanup where we explicitly go through Objects and call obj_delete on everything not already deleted; this obviously needs testing.

Also a few cleanup steps in lab_init to make sure the lab isn't contaminated by leftover data from previously played missions.
2018-03-16 12:59:43 +01:00
Fabian Woltermann 0b3ff5e698 Make the anisotropy setting controllable via commandline 2018-03-16 08:14:35 +01:00
asarium 5c0e88dd60 Add actions to context menu 2018-03-15 14:18:35 +01:00
asarium 1498367e48 Add SEXP tree context menu building
This adds displaying the correct context menu for the qtFRED SEXP tree
widget. The actions are not implemented yet.
2018-03-14 11:46:59 +01:00
Fabian Woltermann a8747b7b93 Merge pull request #1656 from asarium/fix/noRuntimeDll
Disable building targets with runtime DLLs as default
2018-03-14 10:12:50 +01:00
asarium dadf58f6b1 Disable building targets with runtime DLLs as default
This caused issues for some users and was an accidental change
introduced by the qtFRED merge.
2018-03-14 09:16:51 +01:00
m!m e9a642673c Merge pull request #1654 from asarium/qtfred2_/sync
Merge qtFRED into the main branch
2018-03-12 10:21:44 +01:00
asarium 42fbc92d73 Don't build qtFRED for deploy builds 2018-03-11 13:45:27 +01:00
m!m 6141fc7f73 Merge pull request #1652 from The-E/fix/1623
Fix for 1623
2018-03-11 09:06:20 +01:00
asarium c1fd6e7026 Call processEvents from game_busy
That will avoid unresponsive application errors when loading a big
mission.
2018-03-11 08:49:34 +01:00
Tyler Blount 9114d94e0c Merge pull request #1650 from asarium/qtfred2_/sexpTree
Add initial support for displaying SEXPs in a tree widget
2018-03-10 16:15:09 -07:00
asarium 235234ea66 Fix some warnings 2018-03-10 18:30:55 +01:00
Fabian Woltermann 512887482a use correct array lookups (how did VS not find these....?) 2018-03-10 18:00:30 +01:00
Fabian Woltermann 04fd9679bd Fix mprintf calls 2018-03-10 14:06:12 +01:00
m!m 07a2f5a155 Merge pull request #1651 from TRBlount/fred/changeHeadaniExt
Make APNG the default file extension for the Event Editors head ani file dialog
2018-03-10 12:55:53 +01:00
Fabian Woltermann 85874105e3 Remove unnecessary early exit 2018-03-10 12:17:17 +01:00
Fabian Woltermann 248b70b780 Replace this assert with a proper exit path + debug log print 2018-03-10 12:11:17 +01:00
Fabian Woltermann f05a50f57b Merge pull request #1638 from The-E/feature/lighting_settings_rework
Reworks the lighting settings according to the discussion in #1634.
2018-03-10 08:57:56 +01:00
Fabian Woltermann a5fc5e322d Merge branch 'feature/lighting_settings_rework' of https://github.com/The-E/fs2open.github.com into feature/lighting_settings_rework 2018-03-10 08:16:46 +01:00
Fabian Woltermann 91c4884fd3 Use the correct index in the popup 2018-03-10 08:15:59 +01:00
Fabian Woltermann eaad5a01a2 Create a popup to notify people that shaders are being recompiled 2018-03-10 08:15:59 +01:00
Fabian Woltermann 905417b866 Use 32 as a default specPower value in the Blinn-Phong render path 2018-03-10 08:15:59 +01:00
asarium 5061a112db Set default shader uniforms every time the shader is compiled 2018-03-10 08:15:59 +01:00
Fabian Woltermann b7981c0ce4 Implemented callback and shader recompile, but there is still strange behaviour 2018-03-10 08:15:59 +01:00
Fabian Woltermann c0328bb4f5 Beams should always be rendered at lighting detail >= 2 2018-03-10 08:15:59 +01:00
Fabian Woltermann dd2074d91d Reworks the lighting settings according to the discussion in #1634.
This fixes #1634
2018-03-10 08:15:59 +01:00
TRBlount e7a8adb367 Make APNG default file for head ani selection 2018-03-09 16:11:57 -07:00
asarium 809ac2300d Turn modified state into a signal 2018-03-09 23:52:21 +01:00
Fabian Woltermann 8ea179781a Merge pull request #1610 from asarium/feature/windowIcon
Allow mods to specify the window icon
2018-03-09 20:06:54 +01:00
Fabian Woltermann 77768b3328 Merge pull request #1632 from asarium/opengl/betterDecals
Add normal map rendering to decals
2018-03-09 20:06:06 +01:00
Fabian Woltermann 873162690d Merge pull request #1649 from asarium/fix/1647
Fix rendering position of hardpoint models
2018-03-09 20:03:31 +01:00
Fabian Woltermann 5c5ce5e66a Use the correct index in the popup 2018-03-09 15:00:39 +01:00
Fabian Woltermann 7d54dd9a05 Create a popup to notify people that shaders are being recompiled 2018-03-09 14:57:40 +01:00
asarium eb322476b2 Add initial tree creation code to event editor
With these changes the event editor can now display the SEXP tree of a
mission. No other operations are supported at the moment.
2018-03-08 22:42:45 +01:00
asarium aadb22c9f1 Fix the rest of the SEXP tree code 2018-03-08 22:28:25 +01:00
asarium d4b0dc9cc2 Convert mask color to proper alpha channels for SEXP icons 2018-03-08 22:28:25 +01:00
asarium b7e703553b Port sexp tree 2018-03-08 22:28:25 +01:00
Tyler Blount 6b97dcfe60 Merge pull request #1648 from asarium/qtfred2_/sync
Sync qtfred branch
2018-03-08 12:05:57 -07:00
asarium 8099bb737b Fix rendering position of hardpoint models
The previous fix to the weapon orientation failed to account for the
change from local to global space for the weapon position. This fixes
that by rotating the model positions to world space before submitting
the render call.

This fixes #1647.
2018-03-08 11:57:34 +01:00
asarium 91d6d90c9b Merge branch 'master' into qtfred2_/sync 2018-03-08 10:34:00 +01:00
m!m e5e5d14108 Merge pull request #1646 from asarium/fix/1645
Avoid reusing model material instance when setting fog
2018-03-06 18:59:12 +01:00
asarium 4fa43ed639 Avoid reusing model material instance when setting fog
The rendering material used by the model render list was reused by
multiple draw call submissions so a non-transparent mesh would reset the
fog value set before which would break meshes submitted after that.

There are still some issues with how the fog is rendered which causes
differences between how opaque and transparent meshes are drawn but I
will fix that in another pull request.

This fixes #1645.
2018-03-06 17:34:29 +01:00
asarium 1ace8b3abc Reenable decals in nebulas
With the recent changes to how fog is handled in nebulas it is now
possible to render decals correctly in a nebula environment so there is
no need to disable decals when the mission is in a nebula.
2018-03-06 11:38:07 +01:00
asarium 520e532c56 Add normal map rendering to decals
This changes the decal system so that it is able to modify the normal
map of the scene. I tested this with some existing normal maps but I am
not entirely sure if the tangent matrix I construct uses the right
values so some additional testing with normal maps made specifically for
decals would be good.

This also fixed the issues introduced by the changes to how directional
lighting was handled. Now a decal can have a diffuse and a glow map. The
diffuse map is used to change the values of the color buffer and also
supports ambient lighting. The glow map renders into the emissive buffer
and should be used for effects that should not receive lighting.
2018-03-06 11:38:01 +01:00
Fabian Woltermann 9a9e088861 Merge pull request #1644 from asarium/opengl/nebulaPostProcessing
Improve handling of nebula fog for deferred lighting
2018-03-06 09:34:43 +01:00
asarium 39f24bce23 Improve handling of nebula fog for deferred lighting
The previous method of rendering nebula fog didn't work correctly with
deferred shading since it changed the color of the material which
obviously caused some issues when it received light from a beam or a
weapon. This wasn't very noticable before because the directional lights
were handled correctly but since all the lighting operations have been
moved into the deferred shading phase it is very obvious that something
is wrong with our nebula rendering.

This fixes that by introducing a new shader which does a fullscreen pass
after resolving all the lights. It applies the usual fog formula based
on the depth of the fragment but it can only use a fixed distance range.
FSO support specifying a range for every object type but the default
range I chose should work properly for all ship types.

The new code only applies to opaque meshes. Transparent meshes are
fogged using the standard formula.
2018-03-05 22:40:05 +01:00
m!m 3dd9bc8aef Merge pull request #1643 from asarium/fix/hudHardpointsStencil
Fix stencil rendering in hardpoint rendering
2018-03-05 17:00:46 +01:00
Fabian Woltermann 03aa479efc Merge pull request #1642 from asarium/fix/hardpointOrientation
Fix missile hardpoint orientation in HUD gauge
2018-03-05 14:37:25 +01:00
asarium 31931777bc Fix stencil rendering in hardpoint rendering
There were actually multiple issues here. The addition of color mask and
stencil state to the material system overwrote the state set by the
hardpoint renderer so the stencil buffer was never written or read
correctly. I fixed this by introducing three new model render flags
(there were a few open slots in the bit mask so I used those) which set
the correct state using the material system. That also makes setting up
the rendering environment much easier.

Second, gr_opengl_stencil_set used mixed up parameter values which were
probably broken when I introduced more detailed stencil state tracking.
I restored those values to how they were in 3.8.

This fixes the other issue reported in #1640.
2018-03-05 14:28:59 +01:00
Fabian Woltermann 59d0c561d6 Use 32 as a default specPower value in the Blinn-Phong render path 2018-03-05 09:06:43 +01:00
Fabian Woltermann ca55f4ea9c Merge pull request #1641 from asarium/fix/lazySoundLoading
Load unloaded sounds when trying to determine sound length
2018-03-05 08:28:24 +01:00
Fabian Woltermann 8c223afcd0 Merge pull request #1639 from asarium/opengl/unifiedGammaHandling
Move gamma correction into common header
2018-03-05 08:27:29 +01:00
Fabian Woltermann 4dc8c57d3c Merge pull request #1 from asarium/fix/shaderDefaultUniforms
Set default shader uniforms every time the shader is compiled
2018-03-05 08:02:51 +01:00
asarium 82f74d570b Fix missile hardpoint orientation in HUD gauge
The code previously used the matrix stack for handling the orientation
or the weapon models. That is no longer supported by the model renderer
(since it would make handling the transforms harder for no real reason).
I fixed the issue by passing the object orientation directory to the
model render function.

This is a fix for one of the problems mentioned in #1640.
2018-03-05 00:20:21 +01:00
asarium 8df4835d51 Set default shader uniforms every time the shader is compiled 2018-03-04 23:30:49 +01:00
asarium 5a5dbd0df2 Load unloaded sounds when trying to determine sound length
This can happen if a script tries to determine the length of a sound
before actually playing it. This fixes the assertion by loading the
sound when it is necessary.
2018-03-04 22:41:15 +01:00
Fabian Woltermann cc876f8bc3 Implemented callback and shader recompile, but there is still strange behaviour 2018-03-04 20:14:09 +01:00
m!m 45d09fd49b Merge pull request #1637 from The-E/feature/no_max_lights
Remove the MAX_LIGHTS define
2018-03-04 16:45:43 +01:00
m!m 6fcdabeb45 Merge pull request #1635 from asarium/fix/emissiveLightNebula
Handle emissive light properly in nebulas
2018-03-04 16:45:14 +01:00
Fabian Woltermann 2e632467f4 Beams should always be rendered at lighting detail >= 2 2018-03-04 16:31:03 +01:00
asarium 5c599fa9ee Move gamma correction into common header
This moves the constant definition and functions for converting from and
to linear color space into a single file that is included in all other
files.
2018-03-04 13:21:45 +01:00
asarium 6b654ce38a Handle emissive light properly in nebulas
The emissive part of the lighting was not using the fog values properly
so ships didn't rendered right in nebulas. This fixes that by applying
the standard fog color transform to the emissive part of the scene.
2018-03-04 12:29:01 +01:00
Fabian Woltermann 2cba774a33 Reworks the lighting settings according to the discussion in #1634.
This fixes #1634
2018-03-04 10:25:45 +01:00
Fabian Woltermann 32fec00e97 Remove the MAX_LIGHTS define 2018-03-04 08:55:21 +01:00
niffiwan 66c9baf893 Merge pull request #1626 from asarium/opengl/vertexInterfaceBlocks
Use vertex interface blocks for vertex shader attributes
2018-03-04 10:52:59 +10:00
niffiwan 1c04be91bb Merge pull request #1624 from asarium/cleanup/grFog
Remove gr_set_fog
2018-03-04 10:52:42 +10:00
m!m 6d52cab0a4 Merge pull request #1627 from asarium/fix/lineDrawList
Add a mechanism for batching line draw calls
2018-03-03 22:46:50 +01:00
Samuel Cho aa60a639fb Merge pull request #1633 from The-E/fix/team_colors_washed_out
Add SRGB adjustment to the team colors
2018-03-03 12:25:27 -08:00
asarium dfd9fe7610 Use vertex interface blocks for vertex shader attributes
This is a minor cleanup of how the engine passes vertex attribute data
from one shader stage to the next. The current code uses standalone
attribute variables which require a unique name over the entire shader
program which means that the variable names need to be different when a
geometry shader is used which makes the code more complicated and harder
to understand.
2018-03-03 19:34:18 +01:00
Fabian Woltermann ef0c6b5c78 this should do it 2018-03-03 16:33:00 +01:00
Fabian Woltermann a3f493d8c1 make the code more readable here 2018-03-03 15:16:40 +01:00
Fabian Woltermann b6981875a5 Address some feedback make it all work correctly 2018-03-03 15:04:46 +01:00
Fabian Woltermann 7c1147541d Add SRGB adjustment to the team colors, make the logic less weird. 2018-03-03 11:48:02 +01:00
Karajorma ef6c5d4da7 Still have some old variable names 2018-03-01 20:09:34 +08:00
niffiwan be9a881cb5 Merge pull request #1630 from niffiwan/bsp_opt
add small bsp tree optimisation
2018-03-01 21:45:58 +10:00
Karajorma cb960a3416 Fix the saving for non-eternal variables. 2018-03-01 19:26:41 +08:00
Karajorma 194d944108 Merge branch 'master' of https://github.com/scp-fs2open/fs2open.github.com into Feature/EternalVariables 2018-03-01 18:53:03 +08:00
niffiwan 8f2aec3b9a add small bsp tree optimisation
don't add no_collide (& similar) submodels to the bsp trees
this has been in the fotg branch for ages without causing any apparant
issues
2018-03-01 20:00:59 +10:00
MageKing17 78abbf89e6 Merge pull request #1625 from Flip-Sandwich/master
Fixes electronics flag behavior with shockwaves
2018-02-27 19:09:32 -08:00
Fabian Woltermann 4de3451d6c Merge pull request #1628 from The-E/fix/lab-glowpoints
Make glowpoints in the lab work correctly
2018-02-26 12:16:33 +01:00
Fabian Woltermann 8f5f77fa42 Merge pull request #1622 from asarium/opengl/directionalDeferredLights
Use deferred shader for applying directional lights
2018-02-26 11:18:33 +01:00
Fabian Woltermann 354246caf4 Make sure that glowpoints attached to rotating subobjects actually do rotate in the lab 2018-02-26 09:49:13 +01:00
faceman 4797b29311 fixes shockwaves with electronics flagged weapons, properly this time 2018-02-26 15:42:54 +11:00
asarium 2e0253e301 Add a mechanism for batching line draw calls
The previous version used NanoVG which caused quite a serious FPS drop.
This adds a buffer batching class which groups line drawing operations
together and submits them to the GPU with a single draw call.
2018-02-25 19:55:41 +01:00
asarium 0d188fe076 Use deferred shader for applying directional lights
This moves all lighting operations into the deferred shading phase of
the rendering pipeline. Previously, directional lights were applied to
all objects while they were being rendered. This was probably done to
avoid doing multiple full screen passes later but caused some problems
since the color information in the G-buffers was not correct for doing
later lighting operations.

This was especially noticable in dark scenes where point lights would
appear to ignore the color of the rendered objects. This should be fixed
with these changes.

I did some performance testing and to my surprise this actually improves
performance in very demanding scenes. My guess would be that applying
the shadows while rendering the objects caused a lot of overdraw which
is not the case anymore since shadows are only computed for visible
pixels. In simple scenes the opposite happens which leads to decreased
performance in those cases but in my opinion the improvement in
demanding scenes outweights this performance decrease.
2018-02-25 12:43:45 +01:00
asarium c463709399 Remove gr_set_fog
Specifying the fog rendering options is now handled by the materials
system and the implementation of gr_set_fog was pretty much empty so I
removed it.
2018-02-24 19:37:39 +01:00
asarium 25357ce8a2 Allow mods to specify the window icon
This is mostly intended for total conversions to allow them to set
themselves apart from FS2 based mods. It uses the new in-memory
filesystem to support a default icon in case no icon was specified by
the mod.
2018-02-24 18:08:41 +01:00
Karajorma 9ac97f2422 Eternal Variables initial commit - Saving non-eternals on restart or mission quit not working properly. 2018-02-24 17:52:08 +08:00
MageKing17 9953c6a7c4 Merge pull request #1616 from The-E/1615_fix
Do not try to delete opengl buffers when we have no idea what they are
2018-02-23 09:33:20 -08:00
MageKing17 1db36b7ba5 Merge pull request #1619 from The-E/debug_filter_defaults
The extra debug filters really should not be enabled by default.
2018-02-23 09:25:31 -08:00
Fabian Woltermann 77b6648d22 Merge pull request #1613 from asarium/opengl/shaderIncludes
Add support for includes in shader files
2018-02-23 12:58:04 +01:00
Fabian Woltermann 09ca5d3dd6 Merge pull request #1621 from The-E/dockpoint_warning
Print out a warning if we can't find a dockpoint during missionparse
2018-02-21 08:36:35 +01:00
Fabian Woltermann 942f72d09a Print out a warning if we can't find either dockpoint 2018-02-20 16:47:02 +01:00
Fabian Woltermann ee27db60de The extra debug filters really should not be enabled by default. 2018-02-20 11:54:23 +01:00
MageKing17 66c0d27270 Merge pull request #1618 from MageKing17/bugfix/ai-profiles-parsing-end
Make AI profile tables actually stop parsing if #End is missing.
2018-02-18 15:10:44 -08:00
m!m 206364a113 Merge pull request #1617 from The-E/missile_lighting_no_export
Do not export -missile_lighting to launchers
2018-02-18 23:14:05 +01:00
MageKing17 ac9547d610 Make AI profile tables actually stop parsing if #End is missing.
By making parse_ai_profiles_tbl() actually check the return value of skip_to_start_of_string_either() (and break if the appropriate characters aren't found), AI profile tables should no longer keep parsing past the end of the file and into invalid memory, until they either find an "#End" in memory somewhere or just plain crash.

As a pleasant bonus, a missing "#End" should now generate an appropriate error message.
2018-02-18 13:13:18 -08:00
Fabian Woltermann 6534c0a3f6 Remove the -missile_lighting flag from the list of exported cmdline options 2018-02-18 22:12:29 +01:00
Fabian Woltermann cdeeee688d Merge pull request #1605 from Flip-Sandwich/subsysdamagefix
Negative damages no longer heal subsystems
2018-02-18 21:01:57 +01:00
Fabian Woltermann 8b5f257d0d Merge pull request #1614 from asarium/feature/luaLanguageFunctions
Add lua functions for accessing the current engine language
2018-02-18 20:59:23 +01:00
Fabian Woltermann b2652e0628 While working through the atexit table, this function somehow got called, leading to the debug_filter.cfg being altered, as explained in #1615 2018-02-18 19:55:44 +01:00
asarium 2eea0a6eb1 Add lua functions for accessing the current engine language
This can be used by scripts to implement language specific behavior.
2018-02-18 17:12:17 +01:00
m!m 67c67548fd Merge pull request #1611 from The-E/smooth_lab_cam
Make the lab's camera smoother
2018-02-18 16:05:33 +01:00
m!m 12e45e88fa Merge pull request #1612 from The-E/LabHelpText
Print a helpful reminder about the camera controls
2018-02-18 00:01:25 +01:00
Fabian Woltermann e2129355bf Remove the bloom printout, add a camera distance printout 2018-02-17 21:00:47 +01:00
m!m 857582a980 Merge pull request #1608 from The-E/LightTypeEnum
Use an enum class to mark light types
2018-02-17 19:24:51 +01:00
asarium c4dd593dd7 Move lighing functions into one file
There was a slight difference between the GGX function from the main
shader and the deferred shader. The deferred shader didn't use the
fresnel value stored in the G-buffer for some reason.
2018-02-17 19:07:26 +01:00
asarium 30404d4b04 Move shadow functions into separate shader file 2018-02-17 19:02:02 +01:00
asarium c8e3e01ca0 Add support for includes in shader files
This can be used for keeping code for common functionality in one file
(e.g. lighting functions). The code which detects include statements is
pretty simple so it may break if it is used in a more complicated.
Circular includes are detected and treated as an error.
2018-02-17 18:59:11 +01:00
Fabian Woltermann 16ed58f403 Print a helpful reminder about the camera controls 2018-02-17 16:25:15 +01:00
Fabian Woltermann 5ac2571efa Clamp the lab camera's phi component to [0.01, 3.13] to avoid locking issues 2018-02-17 11:56:26 +01:00
Fabian Woltermann 7dfa5b5739 move this variable initialization out of the switch statement 2018-02-17 10:46:59 +01:00
m!m 0178374b98 Merge pull request #1606 from The-E/NewLab
Use mission backgrounds in the F3 lab
2018-02-16 11:26:51 +01:00
Fabian Woltermann 738e4a8153 Remove unused variable 2018-02-16 09:49:11 +01:00
Fabian Woltermann 1a4181fb67 Merge pull request #1609 from Flip-Sandwich/master
Fixes beam behaviour with additive/cap/etc damage types
2018-02-16 09:47:32 +01:00
faceman 85c2b3a7f0 Removes a magic number from ship.cpp 2018-02-16 16:08:45 +11:00
faceman 508b8a176b Fixes beam behaviour with additive/cap/etc damage types 2018-02-16 15:12:25 +11:00
Fabian Woltermann ca313ae17f Addressing CI issues 2018-02-15 14:41:14 +01:00
Fabian Woltermann 87bb2cbcc7 Remove debris rendering for now 2018-02-15 14:19:59 +01:00
Fabian Woltermann 9e673ff7fe light_reset needs to be called on every frame.
this also adds a trace scope to sunspot processing
2018-02-15 11:09:53 +01:00
Fabian Woltermann 126b6718db Reset the background window when it's closed 2018-02-15 11:01:34 +01:00
Fabian Woltermann b0fc182fab Fix crash when switching between weapons and ships 2018-02-15 10:44:45 +01:00
Fabian Woltermann 158292afba We can't show tech or external models yet 2018-02-15 10:35:25 +01:00
Fabian Woltermann e334c1f736 Specify all values explicitly 2018-02-15 10:21:13 +01:00
Fabian Woltermann f6fa053d94 Addressing feedback 2018-02-15 10:17:32 +01:00
Fabian Woltermann 4e24fba7fa Make sure the index is always incremented 2018-02-15 10:09:37 +01:00
Fabian Woltermann 0ea638f520 Fix an uninitialized variable being stuffed into a vector 2018-02-15 10:05:46 +01:00
Fabian Woltermann d75ec93484 Merge pull request #1604 from Flip-Sandwich/master
Consistent beam damage per frame regardless of time acceleration
2018-02-14 20:11:18 +01:00
Fabian Woltermann 468a9f280a Merge pull request #1607 from asarium/fix/aiProfilesWarning
Don't include the default ai_profiles system in CFile
2018-02-14 20:10:15 +01:00
Fabian Woltermann 69f4fa60f5 Remove unused variables 2018-02-14 17:10:26 +01:00
Fabian Woltermann 95ed536225 change the light type to an enum class 2018-02-14 17:07:42 +01:00
asarium 96d3eebad9 Don't include the default ai_profiles system in CFile
This fixes a warning caused by parsing the default ai_profiles table
twice. The default table was moved out of the data/tables folder and
into a special builtin category which will not be included in CFile.
2018-02-14 16:45:04 +01:00
Fabian Woltermann 3b21b2469f A clean, up-to-date patch of the new lab code 2018-02-14 16:19:38 +01:00
Fabian Woltermann cbe1d20fcc Merge pull request #1310 from asarium/feature/inMemoryCfile
Add support for accessing default files with CFile
2018-02-14 11:45:34 +01:00
m!m 3d3bbb5dc4 Merge pull request #1602 from The-E/RadarRangeWarning
Downgrade the invalid radar range error in the plr reader code to a warning
2018-02-14 11:12:34 +01:00
asarium 4c5b1c679b Add support for accessing default files with CFile
This allows to use more complex file structures in the executable
without requiring that those exist as real files. The rest of the code
does not need to handle the difference between a default file and a real
file anymore which means that it's now possible to embed image files
into the executable since bmpman only needs to use the standard CFile
API.

I added two tests which check if the default file can be found and
opened and if a mod file overrides the default file which should always
be possible.
2018-02-14 11:02:59 +01:00
faceman 65941e2e84 forgot to specify that 0.0f is indeed a float 2018-02-14 11:04:54 +11:00
faceman 538adf1bf6 Negative damages should not heal subsystems IMO 2018-02-14 11:00:34 +11:00
faceman a6d8b6b5fa Consistent beam damage per frame regardless of time acceleration 2018-02-14 10:41:49 +11:00
Fabian Woltermann 7fb5f08530 Merge pull request #1603 from asarium/fix/shipSoundGhostCrash
Fix assertion failure in ship_get_sound
2018-02-13 09:42:39 +01:00
asarium ffad093153 Fix assertion failure in ship_get_sound
This assertion could be hit if the player died and the engine tried to
play a sound for the now destroyed ship. Since the existing code already
had a check for the case that the object is an observer I just added
another case for OBJ_GHOST.
2018-02-12 19:46:25 +01:00
Fabian Woltermann 6a73d8f9d0 Having an invalid radar range in the pilot file should not be a fatal error. 2018-02-12 12:08:13 +01:00
m!m a0a88128ef Merge pull request #1599 from The-E/DirectionalLightFix
Make sure directional lights are always rendered
2018-02-12 11:40:05 +01:00
Fabian Woltermann 6fad19c8bc More changes requested by CI 2018-02-12 10:40:56 +01:00
Fabian Woltermann 119b5d662b Addressing feedback and CI issues 2018-02-12 08:57:39 +01:00
Fabian Woltermann 0b612c2f1a Remove an unused #define 2018-02-10 14:20:45 +01:00
Fabian Woltermann 8aee62b818 Make sure directional lights are always rendered; this kinda spiralled out into a bit of general cleanup regarding the lighting code. 2018-02-10 14:09:32 +01:00
m!m 1314b8634a Merge pull request #1597 from asarium/fix/int_list_warning
Fix off-by-one error in stuff_int_list
2018-02-10 12:12:59 +01:00
asarium b557985e90 Fix off-by-one error in stuff_int_list 2018-02-10 10:54:12 +01:00
Fabian Woltermann 4f43a2edf3 Merge pull request #1594 from The-E/MissileLightingdefault
Remove the -missile_lighting commandline parameter
2018-02-09 09:35:16 +01:00
m!m 6083c89b45 Merge pull request #1596 from asarium/fix/parse_int_list_errors
Improve error messages in stuff_int_list
2018-02-08 21:57:15 +01:00
asarium eefba9159a Improve error messages in stuff_int_list
This also converts an assertion into a proper error message which would
contain the actual file and line number.
2018-02-08 19:48:10 +01:00
m!m 8fed2fcfe3 Merge pull request #1590 from The-E/OGLDebugMessageSpamFix
Reduce the amount of Debug message spam due to non-fatal OGL warnings
2018-02-08 19:12:06 +01:00
Fabian Woltermann d149dd18b5 Use correct bit math operator 2018-02-07 15:32:37 +01:00
Fabian Woltermann a7d624f82d Add -missile_lighting to the deprecated flags 2018-02-06 16:38:52 +01:00
m!m aaab3fa03b Merge pull request #1589 from The-E/DebugFilterFix
Fix for debug_filters defaulting to +Parse
2018-02-06 14:20:41 +01:00
Fabian Woltermann 0d51cb0d14 Merge branch 'MissileLightingdefault' of https://github.com/The-E/fs2open.github.com into MissileLightingdefault 2018-02-05 16:21:55 +01:00
Fabian Woltermann 1c56d9f497 Remove the -missile_lighting commandline parameter 2018-02-05 16:18:15 +01:00
Fabian Woltermann dfc8cd1168 Remove the -missile_lighting commandline parameter 2018-02-05 16:16:55 +01:00
Fabian Woltermann ccaa766474 Merge pull request #1486 from asarium/opengl/combinedVertexBuffers
Pack vertex and index data into one buffer
2018-02-04 16:16:45 +01:00
Fabian Woltermann 741c28d785 Merge pull request #1565 from asarium/ci/gcc7
Add GCC 7 configuration for Travis CI
2018-02-04 16:15:25 +01:00
Fabian Woltermann d73a21a579 Fix variable shadowing warning 2018-02-03 23:02:19 +01:00
Fabian Woltermann 5b8f4343a3 Since OGL debug messages are only useful for coders, most of the time, we shouldn't print them to the general log unless they're actually critical 2018-02-03 22:58:43 +01:00
Fabian Woltermann 310785a961 Somehow, this loop to search for an existing debug filter did not work correctly anymore? 2018-02-03 22:38:53 +01:00
Fabian Woltermann 9029aad64d Merge pull request #1586 from asarium/fix/1579_workaround
Add a workaround for clipping planes on NVIDIA
2018-01-30 20:58:07 +01:00
asarium acc018507b Pack vertex and index data into one buffer
This changes the model loading code such that all index and vertex data
is packed in a single GPU buffer for each data type (index and vertex
data are still in separate buffers). This reduces the amount of buffer
rebinding needed when rendering a scene which will reduce the CPU
overhead. Furthermore, this opens up possibilities of future
improvements for which it is beneficial if all data is in the same
buffer (e.g. MultiDrawIndirect rendering).

To manage where to put the data in the GPU buffer I implemented a
custom HeapAllocator which manages where data can be put. It uses a very
primitive first-fit algorithm but that is sufficient for this usage
type. This does add quite a lot of overhead while allocating GPU model
data (I did some tracing and some allocation calls took as long as
130ms).

This fixes #1457.
2018-01-27 13:54:36 +01:00
asarium 25698b4534 Add a workaround for clipping planes on NVIDIA 2018-01-27 13:40:04 +01:00
Fabian Woltermann a2f6897c43 Merge pull request #1581 from asarium/feature/luaVersionCheck
Add lua function for checking the engine version
2018-01-26 17:05:24 +01:00
Fabian Woltermann 0777f24f08 Merge pull request #1583 from The-E/JumpnodeNameAssertion
Improve the JumpNode::SetName assertion to be readable by non-coders
2018-01-22 10:28:11 +01:00
Fabian Woltermann ed45baa843 Improve the JumpNode::SetName assertion to be readable by non-coders 2018-01-21 23:38:58 +01:00
m!m 13ff2ec907 Merge pull request #1582 from asarium/fix/nanovgPerformance
Add simple NanoVG draw buffer for better performance
2018-01-20 20:51:49 +01:00
asarium e795327a3f Add simple NanoVG draw buffer for better performance
This improves the rendering performance of the target hotkey brackets a
bit which caused a significant slowdown previously.
2018-01-20 18:32:39 +01:00
asarium 3c238d61e2 Add lua function for checking the engine version
This can be used to check if an API function is available in the current
version of the engine without causing runtime errors.
2018-01-20 16:37:31 +01:00
m!m 2d3e7e54e8 Merge pull request #1534 from asarium/fix/fs2netdSigbus
Fix SIGBUS crash in fs2netd
2018-01-18 16:14:54 +01:00
Tyler Blount 8ba05c1c3d Merge pull request #1578 from SamuelCho/reflection_blur_fix
Fix gloss-dependent blurred reflections
2018-01-16 09:01:54 -07:00
Tyler Blount 277962974c Merge pull request #1576 from SamuelCho/specularFixes
Specular lighting shader fixes
2018-01-15 23:17:40 -07:00
SamuelCho eab5b8b40a Allocate additional immutable storage for glGenerateMipMap when generating cube map mip levels if there's only one level 2018-01-15 22:15:04 -08:00
SamuelCho 842554e237 Flipped specular minimum floor to be done before gamma correction. Adjusted minimum specular value to 0.03 from 0.04 since that's Substance Painter's minimum. Brought back fresnel factor from the Blinn Phong function since that's needed for retail models. 2018-01-15 13:47:48 -08:00
Fabian Woltermann 563dc35dea Merge pull request #1575 from ngld/fix/setSubspaceDrive
Fix set-subspace-drive on debug builds and make the sexp_val Assert more helpful
2018-01-14 11:21:16 +01:00
ngld 3fc6958f88 Fix set-subspace-drive on debug builds and make this Assert more helpful 2018-01-14 02:48:11 +01:00
Fabian Woltermann a886a1659c Merge pull request #1574 from asarium/opengl/decalSystem
Add screen space decal rendering system
2018-01-13 14:36:36 +01:00
asarium 99f69c903e Add screen space decal rendering system
This allows to render screen space decals into the deferred lighting
buffers no matter how complex the underlying geometry is.

Currently there is only limited support for using this in the engine.
Only weapon impact decals are supported at the moment for testing
purposes.
2018-01-12 17:09:49 +01:00
m!m 830fd70f9e Merge pull request #1573 from SamuelCho/ggx
Replaced Blinn-Phong BRDF with GGX BRDF
2018-01-12 09:49:54 +01:00
m!m c4ff34970f Merge pull request #1572 from MageKing17/bugfix/unicode-distance
Correct backwards arguments in unicode::num_codepoints().
2018-01-12 09:31:52 +01:00
SamuelCho f216b8bf7f Replaced Blinn-Phong BRDF with GGX BRDF 2018-01-11 22:25:43 -08:00
MageKing17 0ec2c7fef0 Correct backwards arguments in unicode::num_codepoints().
When Unicode_text_mode was false, unicode::num_codepoints() would return (the size_t equivalent of) a negative number, because it was checking the distance from end to start instead of the distance from start to end.
2018-01-11 20:40:42 -08:00
MageKing17 1f70fb2bf2 Merge pull request #1570 from niffiwan/fix/default_volumes_pilot_create
set default volumes on pilot create
2018-01-11 10:57:52 -08:00
niffiwan 304a6a3a0d define the defaults volumes correctly 2018-01-11 19:56:12 +10:00
m!m ec6bea233b Merge pull request #1569 from chief1983/lib/sdl207
Upgrade the included SDL libs to 2.0.7.
2018-01-11 10:28:58 +01:00
niffiwan 9e495d7f94 set default volumes on pilot create
previously newly created pilots inherited the volumes from the last
pilot
2018-01-11 12:08:28 +10:00
Cliff Gordon 0344fd6e35 lib/sdl207: Also update the hash to use the new SCP Prebuilt lib version. 2018-01-10 10:02:58 -06:00
Cliff b8b7d41786 lib/sdl207: Upgrade the included SDL libs to 2.0.7. 2018-01-09 19:43:52 -06:00
asarium 3410822d9d Add GCC 7 build configuration for Travis CI
There are a few new warnings in GCC7 so this makes sure that no warning
gets missed by our CI setup. The new configuration should be updated to
the newest GCC version whenever possible.
2018-01-09 10:36:33 +01:00
MageKing17 aea63832ed Merge pull request #1568 from asarium/fix/1561
Reset loaded ship object when closing the F3 lab
2018-01-07 15:45:54 -08:00
MageKing17 1ee1886a9a Merge pull request #1567 from asarium/feature/wingLuaParameter
Add support for passing various parameter types to Lua SEXPs
2018-01-07 15:45:27 -08:00
MageKing17 c0a8ceb48f Merge pull request #1566 from asarium/fix/invalidSexpException
Fix game crash when a lua SEXP is not initialized properly
2018-01-07 15:44:46 -08:00
MageKing17 6bdbbd5c40 Merge pull request #1564 from asarium/build/cleanupOpenALLibs
Remove unnecessary OpenAL binaries in main repository
2018-01-07 15:42:13 -08:00
MageKing17 c66839a9bf Merge pull request #1562 from asarium/fix/readyroomCrash
Reset campaign room text pointers when freeing campaign data
2018-01-07 15:39:26 -08:00
asarium 40ba3162dc Reset loaded ship object when closing the F3 lab
The crash described in #1561 was caused by a NULL ai profile. The
profile was not set because the lab system already had a loaded ship
object (see line 2230). These changes make sure that the loaded ship
object is deleted before closing the lab system which ensures that the
ai profile is set the next time the lab is initialized.

This fixes #1561.
2018-01-07 14:31:42 +01:00
asarium e81547ae88 Add support for weapon class SEXP parameters 2018-01-07 12:26:33 +01:00
asarium 7577018bd3 Add support for ship class SEXP parameters 2018-01-07 12:24:18 +01:00
asarium 2181512949 Add support for passing wing parameters to Lua SEXPs
This was requested by Axem on Discord.
2018-01-06 19:28:45 +01:00
asarium dff5e4c21d Fix game crash when a lua SEXP is not initialized properly
These changes make sure that this situation is detected properly and an
informative error message is shown.
2018-01-06 19:11:48 +01:00
Fabian Woltermann d7ea260607 Merge pull request #1546 from asarium/fix/wrongMemset
Fix two minor issues detected by GCC7 warnings
2018-01-05 14:53:51 +01:00
m!m 7f7ed74bd6 Merge pull request #1563 from asarium/feature/hudTracingScopes
Add tracing scopes for HUD rendering
2018-01-05 12:30:10 +01:00
m!m 0df6c22216 Merge pull request #1547 from asarium/build/ccache
Enable ccache when available
2018-01-05 12:20:30 +01:00
asarium e8ab065bde Remove unnecessary OpenAL binaries in main repository
This is now handled by the prebuilt packages and not needed anymore.
2018-01-05 12:16:18 +01:00
asarium f79b83c60b Enable ccache when available
This will automatically enable ccache when it is detected on the system
and use it for faster compilations.
2018-01-04 20:52:03 +01:00
Fabian Woltermann 3ab6e43254 Merge pull request #1558 from The-E/revert_1555
Revert changes from #1555
2018-01-04 20:24:08 +01:00
asarium abbef793fc Add tracing scopes for HUD rendering
While debugging a performance issue reported on Discord I noticed that
the HUD rendering code does not have any tracing scopes. This adds a few
tracing scopes to that code to make performance debugging a bit easier.
2018-01-04 20:19:10 +01:00
m!m bd85f61971 Merge pull request #1560 from The-E/fix_1559
Sanity checking in maybe_play_flyby_snd
2018-01-04 16:23:29 +01:00
asarium 47967cb72a Reset campaign room text pointers when freeing campaign data
Previously the campaign room caused a heap-use-after-free error
(detected by AddressSanitizer) when loading the campaign failed two
times. This fixes the error by resetting the text pointers to their
default values when freeing the campaign list data.
2018-01-04 14:41:42 +01:00
Fabian Woltermann 7f56037369 Fully revert this 2018-01-04 13:39:16 +01:00
Fabian Woltermann 659828c213 If no flyby sounds are defined for a species, do not attempt to play any. 2018-01-04 11:10:06 +01:00
Fabian Woltermann 2c4884595e Revert changes from #1555 2018-01-04 10:47:57 +01:00
Fabian Woltermann 1621bd169b Merge pull request #1556 from asarium/fix/1554
Make sure updating a texture uses the right texture unit
2018-01-04 09:16:08 +01:00
Fabian Woltermann c496a08ab1 Merge pull request #1557 from asarium/fix/1555
Use correct attachment for depth/stencil buffer
2018-01-03 19:46:38 +01:00
m!m 012e37afb9 Merge pull request #10 from The-E/fix/1555
This seems to stop the flood.
2018-01-03 18:37:59 +01:00
Fabian Woltermann 4fc1183622 If we change the depth and stencil attachments in one place, we need to change them in all places. 2018-01-03 16:09:22 +01:00
asarium 1eaa67bb5b Use correct attachment for depth/stencil buffer
This should be the correct way to set the combined depth/stencil buffer.
This has not been tested yet since I do not have a GPU which causes
these issues.

This fixes #1555.
2018-01-03 13:45:43 +01:00
asarium bf74f29634 Make sure updating a texture uses the right texture unit
The normally faster version that was used before misbehaved if that
texture unit already used the specified texture object which caused the
glTexSubImage3D to cause out of bounds issues some times.

This fixes #1554.
2018-01-03 13:33:03 +01:00
m!m 6159e13162 Merge pull request #1551 from asarium/feature/messageSexpParameters
Add ability for passing messages to scripted SEXPs
2018-01-03 11:52:05 +01:00
asarium 1bd09a91d3 Add ability for passing messages to scripted SEXPs 2018-01-01 19:40:35 +01:00
MageKing17 8cf0e8eb1d Merge pull request #1550 from chief1983/fix/1541_mac_chdir
Only change directory on MacOS when parent process path is /sbin/launchd.
2017-12-30 17:16:51 -08:00
chief1983 2dcb75057c fix/1541_mac_chdir: Only change directory on MacOS when parent process path is /sbin/launchd. 2017-12-30 16:39:34 -06:00
asarium d95f173f26 Fix another sprintf warning of GCC7 2017-12-28 10:52:56 +01:00
asarium 47b21f6792 Fix wrong usage of memset
This caused a warning in GCC7 which is fixed by this. This will also
initialize the array properly since the previous version may not have
worked correctly even if the entire array woudld have been written (on
all supported platform it would have worked since repeating -1 on all 4
bytes of an int will still produce -1).
2017-12-28 10:50:10 +01:00
m!m 5ec8896c4a Merge pull request #1545 from ngld/fix/waveFileMissing
Log a proper error message if WaveFile::Open tries to load a missing file
2017-12-28 10:26:10 +01:00
ngld 560b49158b Log a proper error message if WaveFile::Open tries to load a missing file 2017-12-28 00:33:16 +01:00
Fabian Woltermann c109dc6aca Merge pull request #1539 from asarium/fix/shipSexpParamters
Pass ship variables as actual handles to scripts
2017-12-25 17:40:30 +01:00
m!m 581e5b0242 Merge pull request #1543 from asarium/fix/unicodeSpeech
Convert speech text properly to wide string
2017-12-24 12:44:15 +01:00
asarium ace3fc619e Convert speech text properly to wide string
The previous code could only handle ASCII data correctly but this new
code is also able to handle UTF-8 data correctly by using the Windows
API function MultiByteToWideChar. Since the conversion only happens in
Windows-only code this is not a portability issue.

This fixes an issue reported on the forums where non-ASCII text was not
spoken correctly by the TTS system.
2017-12-23 20:30:55 +01:00
m!m 7d418d50ce Merge pull request #1542 from devnexen/ffmpeg_decoder_fix
this codec layer handling not present but only from a certain version.
2017-12-23 13:10:07 +01:00
David Carlier ebd24341d4 this codec layer handling not present but only from a certain version. 2017-12-23 08:49:52 +00:00
asarium e8c80dbefc Pass ship variables as actual handles to scripts
This was requested by Axem on the forums.
2017-12-22 09:26:24 +01:00
m!m 68e19a19c5 Merge pull request #1331 from asarium/feature/scriptedSEXPs
Add ability to dynamically add new SEXPs at runtime
2017-12-20 12:41:05 +01:00
asarium f780d9e22a Add ability to dynamically add new SEXPs at runtime
This add a system for adding generic instances of the DynamicSEXP class
to the SEXP system. The only implementation at the moment is the LuaSEXP
which is used by the mn.addSEXP lua API to allow Lua to add new SEXPs.

Since this requires that FRED also runs lua scripts I added a mod table
option to enable scripting in FRED. Since the current scripts are not
built with FRED in mind it would likely break all these scripts if FRED
would be opened with normal scripting enabled.

This fixes #1320.
2017-12-20 10:45:40 +01:00
m!m c5117cf55e Merge pull request #1538 from TRBlount/fix/apply_recoil
Remove second instance of apply recoil flag in Weapon_Info_Flags
2017-12-20 10:28:32 +01:00
TRBlount f9704ebd89 Remove second instance of apply recoil flag in Weapon_Info_Flags 2017-12-19 12:41:53 -07:00
Fabian Woltermann eb738b3ef7 Merge pull request #1518 from asarium/fix/additionalFFmpegLogging
Add additional logging output for FFmpeg library version
2017-12-18 21:31:29 +01:00
Fabian Woltermann f04debfb36 Merge pull request #1537 from asarium/fix/parsingCrash
Fix some FRED issues
2017-12-18 21:30:47 +01:00
asarium aa8fb89a17 Fix unreadable FRED tooltip
I forgot to set the alpha blend mode in the NanoVG changes which meant
that the code used additive blending by default which is not good if the
color in use is black. This sets the blend mode to the value that
corresponds to the values used by the NanoVG reference code.
2017-12-18 19:04:36 +01:00
asarium 44e5f89e41 Fix crash in parsing code
The `nullptr` check was removed by mistake.
2017-12-18 18:28:49 +01:00
Fabian Woltermann fee0b900de Merge pull request #1489 from asarium/opengl/betterModelClipping
Use built-in OpenGL clipping planes for model transforms
2017-12-16 10:43:01 +01:00
Fabian Woltermann 6b209223ee Merge pull request #1531 from asarium/build/bundleOpenAL
Include OpenAL Soft DLLs as part of the build
2017-12-16 10:42:30 +01:00
Fabian Woltermann cb06c73b6a Merge pull request #1527 from asarium/feature/scriptedXSTRs
Add support for translating strings in scripts
2017-12-16 10:33:48 +01:00
Fabian Woltermann 7ab8a96903 Merge pull request #1526 from asarium/feature/xstrStringVars
Add support for setting string variables from a XSTR
2017-12-16 10:33:06 +01:00
Fabian Woltermann a58376404d Merge pull request #1523 from asarium/feature/movieSubtitles
Add localized subtitle support to the video player
2017-12-16 10:32:31 +01:00
Fabian Woltermann cfe89f411b Merge pull request #1535 from chief1983/always_preload_snd
Always Preload Game Sounds
2017-12-11 19:34:57 +01:00
m!m 91c9417d3e Merge pull request #1424 from chief1983/fix/470_attempt_2
Fix for #470: Proposal 2
2017-12-11 00:05:45 +01:00
Cliff f37c519b79 always_preload_snd: Is there ever a good reason not to preload mission sounds at this point? 2017-12-10 13:18:58 -06:00
Cliff Gordon 4dd194f4d6 fix/470_attempt_2: One more thing missing. 2017-12-10 13:16:42 -06:00
Cliff Gordon b38367b22f fix/470_attempt_2: Some more cleanup from this being copied from a set of functions and structs. 2017-12-10 13:16:42 -06:00
Cliff Gordon 72517ff9a2 fix/470_attempt_2: I should probably read my examples closer. Just make these local variables since I didn't bring in the struct from the example as it was overkill for us. 2017-12-10 13:16:42 -06:00
Cliff Gordon c3e212094e fix/470_attempt_2: Try to fix SIGPIPE crash using Kroki's example. 2017-12-10 13:16:42 -06:00
asarium 5f7721f300 Fix SIGBUS crash in fs2netd
This was reported by chief1983 on Discord. The standalone server crashed
with a SIGBUS error caused by an invalid socket file handle in
FS2NetD_DataReady(). This should fix that by adding additional checks
where necessary to make sure that our socket is valid when the socket
functions are used.
2017-12-10 19:42:56 +01:00
Fabian Woltermann 9e9378dcb6 Merge pull request #1533 from asarium/fix/jpegInterfaceCrash
Fix crash when using JPEGs as interface bitmaps
2017-12-10 18:39:03 +01:00
asarium 9b9041513d Fix crash when using JPEGs as interface bitmaps 2017-12-10 13:29:16 +01:00
Fabian Woltermann 51aac78080 Merge pull request #1529 from asarium/cleanup/noParseEofChar
Replace the special EOF char value with a standard null byte
2017-12-10 12:39:56 +01:00
m!m 3dd21f6cb6 Merge pull request #1532 from z64555/fix/mpshield_hits
Moves player control check for modelpoint shields into…
2017-12-10 12:22:01 +01:00
z64555 a42b27c0b8 Moves player control check for modelpoint shields into hud_augment_shield_quadrant(). AI ships can now use shield_transfer() on quadrant indices larger than 3. 2017-12-08 15:01:10 -06:00
asarium ca73920b8e Replace the special EOF char value with a standard null byte
This was an issue since UTF-8 encoded text can contain -128 as part of
an encoding sequence which causes a lot of issues for the parsing code.
I could not find any indication why the original code didn't use null
bytes from the start and I also couldn't find any code that would break
because of this. If anyone knows why this was done like this please let
me know.
2017-12-07 14:42:01 +01:00
asarium 17374106d1 Include OpenAL Soft DLLs as part of the build
This will remove the dependency on a system version of OpenAL and also
enable the advanced sound code for everyone. This removes the ability to
use a custom OpenAL version but removing the only system dependency we
currently have is worth a lot more than being able to use a custom
OpenAL version.
2017-12-06 10:42:02 +01:00
asarium 6da5302d34 Add localized subtitle support to the video player
This adds support for displaying subtitles embedded in movie files. This
supports files with multiple subtitle streams where each stream contains
the subtitles for one language. When the movie file is opened, the
stream for the currently active language will be used and displayed.

This resolves one of the points mentioned in #1522.

This also depends on PR #1484.
2017-12-05 12:04:13 +01:00
asarium d0a1efacb8 Improve video player API
This moves all the cutscene specific code out of the movie player code
and into the cutscene code so that the movie player can be reused for
usage in other environments.

This is required for #1041 since an implementation of that feature would
reuse the movie player code of the cutscene code but without all the
main loop stuff.
2017-12-05 12:01:50 +01:00
MageKing17 8168099eac Merge pull request #1530 from asarium/fix/fredSpheres
Fix usage of wrong buffer handles in opengl_draw_sphere()
2017-12-05 00:56:31 -08:00
asarium ae943503cb Fix usage of wrong buffer handles in opengl_draw_sphere()
This fixes another issue reported by Trivial Psychic on the forums.
2017-12-04 18:06:37 +01:00
asarium 4368db845d Add support for setting string variables from a XSTR
This allows to set string variables to localized values which will make
translating missions much easier.

This resolves one of the points mentioned in #1522.
2017-12-04 13:12:30 +01:00
m!m c25163e265 Merge pull request #1528 from asarium/fix/labGhosting
Enable all color channels before doing a clear
2017-12-04 12:58:17 +01:00
asarium 4bf9277c10 Enable all color channels before doing a clear
If the previous rendering operation left the color mask in any other
state than completely enabled then the clear will only affect the
enabled channels. This makes sure that all channels are enabled before
doing the clear.

This fixes an issue reported on the forums:
https://www.hard-light.net/forums/index.php?topic=94200.msg1859118#msg1859118
2017-12-04 11:56:47 +01:00
asarium 0bcdf19851 Add mission load screen scripting hook
This also includes a scripting function for retrieving the title of the
current mission.

This resolves point 4 of #1522.
2017-12-03 18:51:06 +01:00
asarium c4095d1af1 Add support for translating strings in scripts
This allows to use the XSTR mechanism in script to make translating
script text possible. This is compatible with the existing XSTR format
so automatic tstrings.tbl generator tools should work fine with this.

This resolves point 2 of #1522.
2017-12-03 18:51:06 +01:00
MageKing17 5d8f779cff Merge pull request #1416 from asarium/feature/onlyUnicode
Add true Unicode support
2017-12-03 09:32:04 -08:00
m!m 6f2592e733 Merge pull request #1525 from asarium/fix/disappearingShipSelection
Add a few graphics debug scropes to the ship selection
2017-12-02 22:20:01 +01:00
asarium 528a43952e Add a few graphics debug scropes to the ship selection
I added these while investigating the issue which was fixed in the
last commit and more debug scopes are always useful.
2017-12-02 19:34:36 +01:00
m!m 62d1f1978b Merge pull request #1475 from asarium/opengl/genericNanoVG
Add a NanoVG renderer using the generic rendering API
2017-12-02 19:34:01 +01:00
asarium b9b556c7a5 Add a NanoVG renderer using the generic rendering API
One of the main points of contention when adding the NanoVG based
TrueType text rendering was that it required an external Opengl
renderer which may interfere with our rendering engine by changing
OpenGL state without telling the rest of the engine. Since the rendering
interface for NanoVG is abstract and can be easily replaced, I did just
that and replaced it with an implementation that uses only generic
graphics functions without relying on the specific graphics API.

This will improve the interoperability of NanoVG with our engine and
should make later changes to the rendering engine easier since there is
no external rendering code which may interfere with our own code.
2017-12-02 18:31:00 +01:00
m!m 16b0db8eb9 Merge pull request #1524 from asarium/fix/3dSoundWarning
Only display 3D sound warnings for mods with 3.8.0 support
2017-12-02 17:20:43 +01:00
asarium 2c36ea35b4 Only display 3D sound warnings for mods with 3.8.0 support
This was an issue since a lot of mods used wrong sounds and after the
FFmpeg changes the code would display a warning for those sounds by
default. This will restore the old behavior of printing the warning to
the log where it is easier to ignore if the mod does not explicitly
support 3.8.0.
2017-12-01 12:06:23 +01:00
asarium 43e540cc4c Add true Unicode support
This adds proper Unicode support by allowing the parse system to read
UTF-8 encoded files. The new mode is controlled by a mod option which
allows older mods to continue using the legacy text encoding.

That option changes the behavior of several systems in FSO. It disallows
the usage of Volition fonts since they don't support Unicode encoding
and changes a few usages of special characters to their unicode
counterparts of generic rendering solutions.

This fixes #1415.
2017-11-30 13:26:20 +01:00
Fabian Woltermann 67627bd786 Merge pull request #1490 from asarium/opengl/vertexAttribBinding
Use OpenGL vertex array objects for better performance
2017-11-30 12:57:39 +01:00
m!m ea0c4b7b78 Merge pull request #1519 from asarium/build/fixAppimageLibraryPath
Fix LD_LIBRARY_PATH value in AppImage runs
2017-11-23 15:07:27 +01:00
Fabian Woltermann 29e56bb19a Merge pull request #1520 from asarium/fix/randomRangeWrongField
Fix wrong field usage in RandomRange
2017-11-23 15:05:13 +01:00
asarium 57da3e1ef6 Fix wrong field usage in RandomeRange 2017-11-23 12:53:30 +01:00
asarium 16ac19946f Fix LD_LIBRARY_PATH value in AppImage runs
The previous version used PATH instead of LD_LIBRARY_PATH which may have
caused some issues if the system is configured in a way that depends on
the value of LD_LIBRARY_PATH. It also broke launchers that tried to fix
library issues by changing LD_LIBRARY_PATH.
2017-11-22 11:31:04 +01:00
asarium e319b6f941 Use built-in OpenGL clipping planes for model transforms
This changes the batched transform code so that instead of using discard
in the fragment shader it uses the built-in clipping capabilities of
OpenGL for removing invisible sub models. This improves performance in
GPU-limited scenes by ~1ms if shadows are enabled.
2017-11-22 10:32:20 +01:00
asarium 8c88b68327 Use OpenGL vertex array objects for better performance
The original OpenGL Core changes only used a single vertex array object
for specifying the data layout of our vertex data. This uses the OpenGL
extension GL_ARB_vertex_attrib_binding to extend that so that each
vertex_layout uses a separate vertex array object which should improve
performance by reducing the CPU overhead while switching the vertex
layout. Since we need to use offsets into the vertex buffers at some
points this can not be done with the core functions since those do not
support specifying an offset when binding a vertex buffer.
GL_ARB_vertex_attrib_binding does support that and also features an
improved API for specifying the vertex layout. If that extension is not
available then the rendering engine will fall back to the current code.

In CPU intensive scenes I observed a frametime improvement of 1-2 ms.
2017-11-21 12:02:10 +01:00
asarium e75ed62692 Add additional logging output for FFmpeg library version
I had to debug some ffmpeg library issues and added these additional log
statements. They may be useful in the future.
2017-11-21 10:55:09 +01:00
MageKing17 748857ca2f Merge pull request #1517 from asarium/fix/1516
Fix PCX alpha color correction
2017-11-20 13:43:56 -08:00
m!m bff8231d87 Merge pull request #1509 from asarium/feature/jsonFlagPrinting
Add support for printing command line flags in JSON output
2017-11-20 22:10:33 +01:00
MageKing17 29087a3237 Merge pull request #1511 from asarium/build/gcc7Warnings
Fix new warnings generated by GCC 7
2017-11-20 12:20:30 -08:00
asarium a228a127e2 Fix PCX alpha color correction
This is a bugfix for an issue introduced in
72a797f732 which broke 8 bits-per-pixel
alpha bitmap reading.

This fixes #1516.
2017-11-20 13:17:22 +01:00
asarium 2692240ed9 Add additional information to JSON output 2017-11-19 13:27:56 +01:00
asarium a47dcc0548 Fix fall-through warnings introduced by GCC7 2017-11-19 12:12:42 +01:00
m!m 9fed19d4fc Merge pull request #1505 from MageKing17/feature/bmpman-usage
Add in-game BMPMAN usage display.
2017-11-19 11:56:03 +01:00
MageKing17 9446e61587 Add in-game BMPMAN usage display.
Can be enabled with the "-bmpmanusage" command-line option, toggled via the debug console, or toggled via a debug/cheat key combo (`+B).
2017-11-18 16:55:58 -08:00
MageKing17 1ffd0d3ef8 Merge pull request #1512 from asarium/feature/freddocsCfile
Search for fred docs using cfile
2017-11-18 14:50:43 -08:00
MageKing17 1a94018fb4 Merge pull request #1515 from MageKing17/bugfix/fred-close-exception
Avoid exception when closing FRED related to bm_release().
2017-11-18 14:49:14 -08:00
MageKing17 e8ef727a19 Avoid exception when closing FRED related to bm_release().
Now that BMPMAN dynamically allocates the bm_bitmaps array, and deallocates it in bm_close(), which is explicitly called by gr_close(), FRED generates an exception on close because of trying to release bitmap handles after bm_bitmaps has been deallocated and set to null. This is because gr_close() is called by CFREDView::OnDestroy(), but the mission textures aren't fully paged out until CMainFrame::OnClose() (well, technically, CMainFrame::OnClose() calls CFrameWnd::OnClose(), which calls CWinApp::CloseAllDocuments(), which calls CDocManager::CloseAllDocuments(), which calls CDocTemplate::CloseAllDocuments(), which calls CDocument::OnCloseDocument(), which calls CFREDDoc::DeleteContents(), which calls CFREDDoc::editor_init_mission(), which calls reset_mission(), which calls clear_mission(), which calls model_free_all(), which calls model_instance_free_all(), which calls model_unload() for every model, which calls model_page_out_textures(), which *finally* calls the crashing bm_release()). This commit moves the gr_close() call to CMainFrame::OnClose(), *after* it calls CFrameWnd::OnClose(), which avoids the exception as bm_bitmaps is still intact long enough for those final textures to be freed from it.
2017-11-18 04:38:03 -08:00
MageKing17 dfdfd59367 Merge pull request #1514 from MageKing17/feature/window-title
Window title overhaul.
2017-11-17 03:57:56 -08:00
asarium 4f7b718167 Fix sprintf warnings by checking the return value 2017-11-17 12:52:16 +01:00
MageKing17 b1046b1c1c Window title overhaul.
FSO now allows the window title to be specified via game_settings.tbl, some never-used function arguments were pruned at the same time, and fred.rc now receives version information (for the About dialogue and the title bar) from a cmake-generated header, so the version numbers get filled in properly. Speaking of FRED's About dialogue, it now displays the copyright symbol properly.
2017-11-17 02:51:36 -08:00
MageKing17 4663aed194 Merge pull request #1513 from MageKing17/bugfix/training-variable-timing
Move game_do_training_checks() to be right before goal processing.
2017-11-17 02:50:32 -08:00
MageKing17 a56432f5fc Move game_do_training_checks() to be right before goal processing.
In-mission events (SEXP chains that are used for directives and all mission logic) can sometimes call "training SEXPs", which depend on special variables set in the game_do_training_checks() function. However, this function was called near the end of game_frame(), well after mission_eval_goals() (which processes all mission events). This means that most training SEXPs wouldn't actually evaluate as true until the frame after whatever condition they were checking became fulfilled. This, combined with PR #1388 making the "targeted" SEXP actually use the appropriate variables (Players_target and Players_targeted_subsys), means that Diaspora's very first training mission's very first instruction (after launching from the launch tube, anyway) could not be completed, because the mission logic assumed that "key-pressed" and "targeted" would both return true on the same frame (which, after PR #1388, they did not).

This commit moves game_do_training_checks() to be called immediately before mission_eval_goals(), and therefore immediately after obj_move_all(), meaning Training_context_speed_set can become set the same frame the player's ship reaches the appropriate velocity and the relevant SEXPs can operate on the most up-to-date data available.
2017-11-16 23:26:05 -08:00
asarium 206ce536ec Search for fred docs using cfile
This will allow to put the FRED docs somewhere else instead of into the
root directory of a TC.
2017-11-14 23:15:58 +01:00
Fabian Woltermann d8ccf84452 Merge pull request #1482 from asarium/cleanup/sexpSCPString
Use SCP_strings and SCP_vectors in SEXP code
2017-11-14 09:35:44 +01:00
Fabian Woltermann bed9c13233 Merge pull request #1497 from z64555/cleanup/swarm_missiles
Refactors swarm_update_direction() a bit...
2017-11-14 09:34:30 +01:00
Fabian Woltermann 16993b236f Merge pull request #1479 from asarium/opengl/modelUniformBuffers
Use uniform buffer blocks for passing uniform data to shaders
2017-11-14 09:33:45 +01:00
Fabian Woltermann 94f8d547e0 Merge pull request #1487 from asarium/cleanup/modelVertexStruct
Use a C-struct for managing GPU model data layout
2017-11-14 09:32:48 +01:00
MageKing17 b6908d10c4 Merge pull request #1470 from asarium/fix/1469
Fix error line reported by Lua Errors
2017-11-13 16:31:16 -08:00
m!m a54aa24a64 Merge pull request #1510 from TRBlount/fix/motion_debris_load
Fix motion debris anim loading in mission-set-nebula sexp
2017-11-12 11:57:28 +01:00
MageKing17 d083089e1d Merge pull request #1508 from The-E/lab_fix_window_background
Fix window drawing in the F3 lab
2017-11-11 23:30:40 -08:00
MageKing17 338436d590 Merge pull request #1506 from MageKing17/bugfix/music-table-section-skipping
Fix music table parsing when a soundtrack needs to be skipped.
2017-11-11 23:27:58 -08:00
asarium 1d2f778b76 Add support for printing command line flags in JSON output
This will output the flags data in a better format than the current
binary format. For determining if the JSON output should be used this
uses an optional parameter for -get_flags. The command line parsing does
not cause an error if a parameter is specified for an option that does
not support them. This way, the launcher can just pass "json_v1" to the
option and an old build will just silently ignore it and use the binary
format.
2017-11-11 20:29:36 +01:00
Fabian Woltermann aad1bbbb05 The labviewer window background got its width and height mixed up in 6dbd7c34, this fixes that 2017-11-11 20:24:10 +01:00
TRBlount 1e4bede8c5 Fix motion debris anim loading 2017-11-11 10:34:28 -07:00
MageKing17 38b331dc92 Fix music table parsing when a soundtrack needs to be skipped.
For some reason, commit 8b43ed823c moved the consumption of the "#Soundtrack End" token out of parse_soundtrack(), when if a soundtrack needs to be skipped (e.g. because it's in a .tbm, flagged with +nocreate, and the original doesn't exist), it will skip straight past "#Soundtrack End" to reach the next "#Soundtrack Start". It also changed how music tables are parsed so that they'll skip any junk data that happens to be between sections, which is atypical of how tables are parsed. This commit changes both of these things: "Soundtrack End" is once again consumed near the end of parse_soundtrack(), and the while loop uses check_for_string() instead of skipping to the start of a section.
2017-11-09 15:08:40 -08:00
m!m d3965b1f9d Merge pull request #1502 from MageKing17/feature/tabled-bmpman-limit
Allow BMPMAN slot limit to be defined by mod table.
2017-11-09 09:23:20 +01:00
asarium 986099a495 Handle bmpman shutdown explicitly
This was previously done with atexit which caused issues if bmpman was
initialized more than once which is the case for the unit tests.
2017-11-07 15:43:27 -08:00
MageKing17 07ff605c58 Attempt to guarantee that bm_bitmaps will only be allocated once.
Even if bm_init() gets called more than once, for whatever reason. Unless bm_close() is called first, in which case it will re-allocate, potentially with a different MAX_BITMAPS (but it's okay, because there shouldn't be any active handles to worry about if bm_close() was called).
2017-11-07 15:33:36 -08:00
m!m a8171c118f Merge pull request #1500 from TRBlount/fix/directional_glows
Fix directional glow issues
2017-11-06 12:44:47 +01:00
TRBlount 4b9c7b19aa Add comment regarding the length and radius of a beam muzzle glow 2017-11-04 12:24:12 -06:00
TRBlount 33d2294a49 Fix ramp up/down sequence and basic size/positioning of directional glows 2017-11-04 12:16:06 -06:00
MageKing17 8e558b2095 Move MAX_BITMAPS to bmpman.cpp/.h, use error_display() for warnings.
Per discussion on the PR. Also corrected sizeof(bm_bitmaps) to sizeof(bm_bitmaps[0]) * MAX_BITMAPS.
2017-11-04 08:52:56 -07:00
MageKing17 703bfab587 Merge pull request #1504 from asarium/fix/defaultMaterialClipPlane
Fix Assertion failure when rendering clip planes using default material
2017-11-04 07:39:40 -07:00
MageKing17 344502c436 Merge pull request #1495 from asarium/feature/betterSoundSets
Add support for multiple sounds in one game sound entry
2017-11-04 06:53:10 -07:00
asarium ef06593ed7 Fix Assertion failure when rendering clip planes using default material
The texture array changes introduced the default material which is
similar to the passthrough shader but allows to use texture arrays. The
vertex shader is the same as for the passthrough shader so that shader
also supports clipping planes.
2017-11-04 14:42:50 +01:00
MageKing17 a22b336bfe Merge pull request #1493 from asarium/fix/particleDirection
Fix several oversights and bugs in the particle effect code
2017-11-04 05:05:43 -07:00
MageKing17 37b81efea4 Allow BMPMAN slot limit to be defined by mod table.
bm_init() now dynamically allocates the bm_bitmaps array, and MAX_BITMAPS can be changed by the mod table.
2017-11-02 16:37:57 -07:00
MageKing17 7c6f99c68b Merge pull request #1501 from TRBlount/fix/DRADIS_visuals
Make DRADIS blips use decaying alpha
2017-11-01 15:31:09 -07:00
TRBlount f7b7aaead3 Use std::abs() 2017-10-31 15:21:54 -06:00
TRBlount 80dcefa0fc Add comment specifying functionality 2017-10-31 13:31:43 -06:00
TRBlount 27a70d545d Update using time since last sweep. 2017-10-31 13:13:59 -06:00
TRBlount e4614f01ba Fix DRADIS blip alpha 2017-10-30 16:07:54 -06:00
Tyler Blount e2d8502a3e Merge pull request #1488 from asarium/fix/renderTargetError
Fix OpenGL function usage in opengl_make_render_target
2017-10-30 15:23:22 -06:00
Fabian Woltermann dee0cf600f Merge pull request #1499 from asarium/fix/linuxNightlyBuilds
Fix dependency issues when building libcurl for FTP deploy
2017-10-30 13:55:35 +01:00
asarium 6181c0b2f7 Fix dependency issues when building libcurl for FTP deploy 2017-10-29 11:20:39 +01:00
z64555 0f942afaae Simplify out-of-frame calls.
*Homing conditions are now consistant with in-frame checks
*Swarm missiles will now only change their homing pos during a change frame. This'll reduce their hit rate if SWARM_FRAME_STOP_SWARMING is too low, but will make their pathing more cinematic.
2017-10-22 14:42:33 -05:00
z64555 cdde87662a Refactors swarm_update_direction() a bit for readability and consistency.
* Changed stop distance to a stop frame. Frame was chosen instead of distance or time to ensure missiles won't appear to jerk twice in succession.
2017-10-22 02:00:01 -05:00
m!m 4e7f8fa92a Merge pull request #1496 from MageKing17/bugfix/music-parse-assertion
Fix misused assertion in music table parsing code.
2017-10-21 19:47:22 +02:00
MageKing17 867ebfed89 Fix misused assertion in music table parsing code.
The condition of an assertion doesn't exist in a release build, and assertions should never be used for bad data anyway.
2017-10-21 09:56:12 -07:00
asarium 0ff8a2c159 Add support for multiple sounds in one game sound entry
This adds support for specifying multiple sounds for a single game sound
entry. The engine then selects which sound will be played based on the
strategy provided by the game data. This required a few changes to some
of the game code since previously every game sound had exactly one sound
file attached to it. The most notable change is that it is no longer
possible to determine the exact duration a sound can have so instead the
new code computes the maximum duration a sound can have and uses that
where appropriate.

This also adds support for randomizing the pitch and volume of the sound
to provide a more varied experience even if only a single sound is used.

One possible issue that exists is that the "sequential" strategy only
works globally at the moment so if two sources use the same game sound
concurrently then the two sources will share the sequence of sounds
since there is no sound instance data at the moment. That can be added
in a future change but should not present a huge issue for most
use-cases.

Visual Studio on Appveyor somehow causes deprecation error on _our_
definition of vsprintf. I have no idea why these changes introduced this
warning but I won't debug Visual Studio compiler bugs that I can't
reproduce with my Visual Studio version so I just disabled those
warnings.
2017-10-17 10:57:22 +02:00
asarium 8272304cfa Remove global Snds and Snds_iface vector 2017-10-17 10:30:00 +02:00
asarium 0522566790 Replace direct usages of Snds vector with a function call
This will make it easier to validate the used handles and is generally
better since it doesn't require a global sounds vector.
2017-10-09 15:02:29 +02:00
MageKing17 59e7b10b73 Merge pull request #1494 from asarium/fix/ballisticSoundOutOfRange
Fix out-of-range vector access in ballistic sound code
2017-10-06 16:19:47 -07:00
asarium eb4cfeb256 Fix out-of-range vector access in ballistic sound code
The code probably tried to check if the sound is available but since the
sounds vector is not long enough if the sound is not specified in the
table it would cause an out-of-bounds failure if the sound was missing
from the table. Furthermore, the current code would only have worked if
the sound was preloaded since the id is -1 until the sound is loaded for
the first time.
2017-10-06 19:51:26 +02:00
asarium a7b1c00a84 Fix handling of relative source directions
Previously, the source orientation was always aligned to the world so it
couldn't adapt to a weapon that changes direction. This fixes that by
introducing a "relative" mode for source orientations that is enabled by
default and disabled if the direction is set explicitly.
2017-10-04 15:59:09 +02:00
asarium e484a84d97 Fix several oversights and bugs in the particle effect code
The particle sources of the beams were missing multiple properties
(direction and impact normals) and the generic shape effect didn't have
any way of controlling how long the source was active. This fixes that
by introducing an effect timing field similar to the single particle
effect.
2017-10-04 10:51:35 +02:00
MageKing17 bd2bb12ad3 Merge pull request #1492 from MageKing17/bugfix/shield-impact-sounds
Make shield impact sounds more intuitive.
2017-10-03 12:00:49 -07:00
MageKing17 c890c0af1f Make shield impact sounds more intuitive.
Shield impact sounds now re-use the shield quadrant calculated by the collision code instead of naively recalculating based on global hitpos, allowing the hull impact sound to play if the shot pierces shields or was fired from within the shield mesh, and simplifying the relevant calculations in the process.
2017-10-03 09:06:34 -07:00
m!m 9cda43afb2 Merge pull request #1491 from ashdnazg/mingw_fix_include
Add include <cinttypes> (fix mingw build)
2017-10-03 11:50:44 +02:00
Eshed 34b4321416 add include
required by PRIu64
2017-10-03 11:32:56 +03:00
asarium 3a18a88e30 Fix OpenGL function usage in opengl_make_render_target
The function previously used glFramebufferTexture3D which caused issues
on the Mesa drivers and probably also with other drivers. This fixes
that by using glFramebufferTextureLayer which is the right function for
this use case.
2017-09-26 14:10:56 +02:00
asarium 686bf15879 Ensure that init_render is called before rendering the scene
This was previously not enforced and some code did not call this
function at the correct time which caused crashes since data was not
initialized correctly. This adds a check to ensure that the function was
called and fixes the code that uses the model_draw_list.
2017-09-24 15:53:14 +02:00
asarium 22f0ba89a4 Use a C-struct for managing GPU model data layout
In previous versions of FSO the GPU data of a model was stored in
various different layouts depending on what data was required for
rendering that model. Since the transform batching code was added to the
model loading code this wasn't the case anymore since all data had to
use the same vertex stride even if the data wasn't used.

This made these changes possible where a standard C-struct is now used
for managing the layout of the data in GPU memory. This makes the code
easier to read and also easier to extend in the future since all layout
data is available in the struct.
2017-09-20 17:39:31 +02:00
Fabian Woltermann a3bf47991b Merge pull request #1485 from asarium/fix/1483
Ensure that viewport setting calls are valid
2017-09-16 19:27:13 +02:00
asarium 6af1768147 Ensure that viewport setting calls are valid
This fixes a CTD when FRED is started since the graphics function
pointers are not valid at that point which causes a null pointer
dereference when starting FRED. This fixes that by checking if the
graphics system has been initialized before calling that function.

This fixes #1483.
2017-09-16 18:24:13 +02:00
asarium 0d9fbd4725 Use SCP_strings and SCP_vectors in SEXP code
I split this from #1331 to make reviewing these two changesets easier.

These changes convert all usages of const char* to SCP_string in the
static SEXP arrays so that the dynamic SEXP system can use SCP_strings
instead of having to allocate the strings and then somehow figure out
which strings must be freed at the end of the program.

This also converts the SEXP arrays to vectors so that new SEXP operators
can be added at runtime later.
2017-09-14 11:11:52 +02:00
asarium c6975fda3c Use uniform buffer blocks for passing uniform data to shaders
This uses UBOs for building a buffer object of uniform data before
using that data to draw objects. This should reduce the CPU overhead by
reducing the amount of glUniform calls required for executing a single
draw call. This is especially useful if rendering is limited by the CPU
which should help performance for people with slower CPUs.

This fixes #910.
2017-09-13 11:54:16 +02:00
Fabian Woltermann 52baa1f115 Merge pull request #1480 from asarium/fix/movieScaling
Restore 2D matrix setting behavior
2017-09-12 12:19:39 +02:00
asarium d684dcea1b Restore 2D matrix setting behavior
This restores the behavior from before the matrix system changes. The
observed behavior is more or less the desired behavior sinde setting the
2D projection matrix resets the model matrix stack but it happens to
work with the previous movie code since the 2D matrix is not set if no
perspective projection matrix was set before. This would need to be
fixed if the movie player should ever work within a mission but for now
this will fix the reported bug.
2017-09-12 11:35:11 +02:00
Fabian Woltermann fa7f49f1e4 Merge pull request #1478 from asarium/opengl/externalLightManagment
Move light handling out of OpenGL code
2017-09-10 14:33:53 +02:00
Fabian Woltermann cc3dc5f566 Merge pull request #1476 from asarium/feature/pngScreenshots
Use PNG instead of TGA for saving screenshots
2017-09-10 14:33:27 +02:00
Fabian Woltermann 19c50412ba Merge pull request #1477 from asarium/opengl/gsInstancing
Use geometry shader instancing for shadow map rendering
2017-09-10 14:33:07 +02:00
asarium cdd391caa8 Move light handling out of OpenGL code
There is nothing specific to OpenGL in that code anymore since it's all
handled in the shaders at this point. This will make the lighting
information available in the normal graphics code which allows to use
those values when filling the uniform buffer for the model rendering.
2017-09-10 11:48:38 +02:00
asarium 4860f72678 Use geometry shader instancing for shadow map rendering
This provides ~10% to 20% of an improvement if shadows are enabled. The
required features are not available in our OpenGL target version so I
added a fallback meachanism that will continue to use the standard
instancing method.

With an RX 480 and these changes I can play/watch the BP2 Icarus
cutscene at a consistent 60FPS which wasn't possible before.
2017-09-09 21:14:25 +02:00
Fabian Woltermann 5ba33228cb Merge pull request #1473 from asarium/fix/1472
Only use 16 bit-per-pixel for PCX data loading
2017-09-09 20:48:18 +02:00
Fabian Woltermann b7f3fdbb98 Merge pull request #1471 from asarium/fix/unsupportedShadowFramebuffer
Add proper fallback path for unsupported shadow framebuffer
2017-09-09 20:47:38 +02:00
Fabian Woltermann 1bffdce6ef Merge pull request #1474 from asarium/opengl/externalMatrixStack
Move graphics matrix handling out of OpenGL code
2017-09-09 20:46:19 +02:00
asarium b130d526ff Use PNG instead of TGA for saving screenshots
This was requested by Axem for improving the usability of FSO
screenshots. This will remove the need to convert the TGA files to PNG
before uploading them to an online image hoster.
2017-09-09 18:28:55 +02:00
asarium 4c1ed2f66a Move graphics matrix handling out of OpenGL code
All transformations are now handled by shaders so there is nothing
special going on in the graphics API specific code anymore. Since model
uniform buffers require access to these matrices I moved the matrix
handling out of the graphics API code.
2017-09-05 12:36:32 +02:00
asarium d30a73a578 Only use 16 bit-per-pixel for PCX data loading
The PCX loader requires this or else the data isn't loaded correctly.
This matches what the code did before the texture array merge but it
only does it for PCX textures now since the other formats handle 32 and
24 bits per pixel correctly.

This fixes #1472.
2017-09-04 13:11:04 +02:00
Fabian Woltermann fa03117eaf Merge pull request #1323 from asarium/opengl/uniformBuffers
Use a uniform buffer object for storing deferred lighting data
2017-09-04 12:32:12 +02:00
asarium 2eb109dc49 Add proper fallback path for unsupported shadow framebuffer
If a 32-bit color shadow framebuffer is not supported this will first
try to fall back to 16-bit and if that still doesn't work it will
disable shadows completely. This should fix the rendering artifacts
reported on the forums here:
http://www.hard-light.net/forums/index.php?topic=93867.msg1854164#msg1854164
2017-09-04 12:02:49 +02:00
asarium bef57f7559 Fix error line reported by Lua Errors
This adds empty lines to the beginning of the Lua source passed to the
interpreter so that the interpreter sees the lines in the source as they
appear in the table.

This might slow down parsing a bit since get_line_num is quite slow but
it should not be noticable in most instances since the script tables
tend to be quite short.

This fixes #1469.
2017-09-04 10:56:39 +02:00
asarium b807c670db Use unsynchronized buffer mapping for updating uniform buffer
Since the system already tracks if a buffer is still in use by the GPU
the buffer updates can assume that there will be no synchronization
issues if the buffer is mapped into memory.
2017-09-03 12:40:33 +02:00
asarium 24b71441c0 Add debug scope to uniform buffer retiring function 2017-09-03 12:40:33 +02:00
asarium e47581ffa5 Add documentation to new classes 2017-09-03 12:40:33 +02:00
asarium c585314ff1 Use a uniform buffer object for storing deferred lighting data
This converts the deferred lighting shader to use uniform buffers for
the dynamic data sent to the GPU while rendering the lighting effects.
This doesn't affect performance but the deferred lighting code is a
nicely isolated piece of rendering code where I could test how the
rendering code could use the uniform buffers.

This is related to #910.
2017-09-03 12:40:33 +02:00
MageKing17 97d09ae6ad Merge pull request #1468 from asarium/cleanup/noStandaloneClippingPlanes
Remove graphics functions for explicit clipping planes
2017-09-02 08:44:30 -07:00
asarium 250bf919a7 Remove graphics functions for explicit clipping planes
The function implementations were empty anyway and the code that called
them wasn't used anymore.
2017-09-02 13:20:41 +02:00
MageKing17 f8dd06ccef Merge pull request #1467 from Goober5000/medal_button_hotspot
add field for setting the hotspot index of the exit button in the medals screen
2017-09-01 11:27:11 -07:00
Fabian Woltermann 67416cc8f6 Merge pull request #1447 from asarium/opengl/useExtensions
Only generate headers for OpenGL 3.2
2017-09-01 17:01:46 +02:00
Fabian Woltermann 7118697a35 Merge pull request #1454 from asarium/opengl/noImmediateDraws
Move immediate mode rendering into generic graphics code
2017-09-01 17:00:06 +02:00
Fabian Woltermann 095c1ebe2b Merge pull request #1458 from Goober5000/time_docked_fixes
several fixes to time-docked and time-undocked
2017-09-01 16:58:00 +02:00
Fabian Woltermann 8c89c19c7e Merge pull request #1155 from asarium/feature/debugWindowScrolling
Add scrolling support to new debug window
2017-09-01 16:37:10 +02:00
m!m ae3d06c54f Merge pull request #1328 from chief1983/libupgrade/sdl2_0_5
Upgrade included libSDL2 to 2.0.5
2017-09-01 15:04:54 +02:00
Cliff dbbb8af17b Avoid a potential crash when ff is enabled without a joystick. 2017-08-31 20:38:40 -05:00
Cliff Gordon a23830359a libupgrade/sdl2_0_5: joy_get_device is not defined, use this instead, thanks @ashdnazg 2017-08-31 19:56:15 -05:00
Cliff Gordon 31e572ec03 Revert "Allow force feedback to work again."
This reverts commit 19b5ee97f7.
2017-08-31 19:56:15 -05:00
Cliff Gordon 29b5c4bf7a libupgrade/sdl2_0_5: Attempt to migrate the MinGW support to the official libs using the filename they are published with. 2017-08-31 19:56:15 -05:00
Cliff Gordon 3811270a09 libupgrade/sdl2_0_5: Upgrade to SDL 2.0.5. 2017-08-31 19:56:15 -05:00
Cliff Gordon 64fc95ec8c libupgrade/sdl2_0_5: Remove old build system files from gitignore. 2017-08-31 19:56:15 -05:00
MageKing17 0c70672a84 Merge pull request #1461 from Goober5000/fix_emp_time_for_capship_turrets
make "same emp time for capships" actually work
2017-08-31 07:00:47 -07:00
Goober5000 67e6bcca9f make "same emp time for capships" actually work
Back when I added the "same emp time for capships" flag in SVN r9540, I neglected to multiply the EMP time by 1000, as the EMP disruption time for fighters is specified in seconds but the time for capships is specified in milliseconds.  So, using this flag would cause capships to suffer EMP disruption for almost no time at all.

This PR fixes that, and also extends the explosion-effect sexp to specify this parameter.  And I also cleaned up the fireball section by calling eval_num(n) just once instead of several times.
2017-08-31 04:16:15 -04:00
m!m 8de33ab56a Merge pull request #1464 from Goober5000/boolify_is_sexp_true
change is_sexp_true return type from int to bool
2017-08-31 10:06:47 +02:00
Goober5000 b786b8e230 fix another mismatch 2017-08-31 02:10:01 -04:00
Goober5000 9dc308331b fix some warnings I missed earlier 2017-08-30 16:03:15 -04:00
Goober5000 628ac86c3e Merge pull request #1465 from asarium/feature/dynamicTstrings
Looks good to me.
2017-08-30 12:23:20 -04:00
asarium dcee8a302e Remove limit for tstring table entries
Since 4500 strings are not enough for some mods there was a request for
removing that limit. I chose to use an unordered map for storing the
entries since the indices are not guaranteed to be sequential.

This fixes Mantis 3199.
2017-08-30 13:04:24 +02:00
Goober5000 c7673f0591 swap order of parameters to avoid short-circuiting 2017-08-29 20:25:04 -04:00
Goober5000 000d0c3a0d change |= and &= to be the more verbose and correct logical operators 2017-08-29 14:11:35 -04:00
Goober5000 ec19f9be98 change is_sexp_true return type from int to bool 2017-08-29 13:50:22 -04:00
Goober5000 3005a67573 Merge pull request #1459 from Goober5000/string_concatenate_block
add string-concatenate-block sexp
2017-08-29 13:49:18 -04:00
Goober5000 33d4a7efa7 more fiddling with string format arguments 2017-08-29 12:30:16 -04:00
MageKing17 6c4e03d9dc Merge pull request #1462 from Goober5000/fix_sexp_error_reporting
fix Assertion in sexp error reporting
2017-08-29 06:32:49 -07:00
m!m 537ee433de Merge pull request #1463 from Goober5000/fix_sound_coordinates
fix negative coordinates in play-sound-from-x
2017-08-29 09:54:20 +02:00
Goober5000 2cff45f2c5 fix negative coordinates in play-sound-from-x
When the OPF_NUMBER and OPF_POSITIVE behaviors were made more robust, it exposed a latent bug in the play-sound sexps.  These had OPF_POSITIVE where they should have had OPF_NUMBER.  With this fix, sounds can now play from all coordinates, positive or negative.
2017-08-28 19:12:40 -04:00
Goober5000 466e4c159f use SIZE_T_ARG 2017-08-28 18:39:01 -04:00
Goober5000 6c7de5120e improve warning messages per feedback 2017-08-28 14:40:44 -04:00
Goober5000 b2b0ba3630 to be pedantic, this happens at the very end of error-reporting mode 2017-08-28 14:26:34 -04:00
Goober5000 14dcff6f5f might as well restrict the test to only running during error-check mode 2017-08-28 14:23:53 -04:00
Goober5000 d826537485 fix Assertion in sexp error reporting
There is a bug where, when displaying an error message with a sexp node that contains a variable, the code will trigger an Assertion in the process of printing the error message.  This is because it tries to transcode the sexp variable from name to index, when that has already been done further up the pipeline.  This fixes that by adding a quick test to see if the expected variable name is an integer.
2017-08-28 14:17:02 -04:00
Cliff Gordon 95c0fad96f Merge pull request #1460 from asarium/fix/openglErrors
Readd accidentally removed OpenGL calls
2017-08-28 10:35:07 -05:00
MageKing17 85b3a30376 Merge pull request #1456 from Goober5000/is_docked_sexp
add is-docked sexp
2017-08-28 08:09:13 -07:00
asarium 3c347ae938 Readd accidentally removed OpenGL calls
I changed those lines in another PR and forgot to revert these before I
submitted it. This will fix the OpenGL errors that appeared when shadows
were enabled.
2017-08-28 16:53:50 +02:00
Fabian Woltermann 09b28f2219 Merge pull request #1453 from asarium/opengl/noRedundantActiveTexture
Avoid redundant glActiveTexture calls
2017-08-28 09:00:56 +02:00
Fabian Woltermann 3c0eec27de Merge pull request #1432 from asarium/qtfred2_/dev
Add most of the remaining menu action implementations
2017-08-28 08:59:41 +02:00
Fabian Woltermann 2fb078f32b Merge pull request #1455 from asarium/fix/deleteUnusedFile
Delete unused OpenGL video presenter
2017-08-28 08:57:26 +02:00
Goober5000 a19b3030b6 enhance warning messages 2017-08-27 18:01:14 -04:00
Goober5000 5095b1c57a several fixes to time-docked and time-undocked
Time-undocked will cause FSO to freeze unless you know what you're doing, so this PR fixes some gotcha areas.  Inspired by The E's rant on Discord which, while not 100% correct, did indicate some areas for improvement.

1) Set the default "number of times docked" argument to 1 when the sexp is created in FRED, same as with the has-[un]docked-delay sexps
2) Catch any <= 0 counts when the sexp is called in FRED and set them to 1.  (This was done for other sexps which used mission_log_get_time_indexed, but was not done for time-[un]docked for some reason.)
3) Add an assertion to mission_log_get_time_indexed as a last resort to guard against invalid counts.
2017-08-27 17:18:39 -04:00
Goober5000 ab14742f96 add is-docked sexp 2017-08-27 16:24:04 -04:00
asarium 492c4ba10a Delete unused OpenGL video presenter
The deletion of this file was missed in the cutscene changes.
2017-08-27 18:12:01 +02:00
asarium 999eb8a3f9 Add documentation to new functions 2017-08-27 17:32:58 +02:00
asarium 03aa75c39a Move immediate mode rendering into generic graphics code
Since this code is the same for all possible graphics backends it can be
moved outside the OpenGL implementation to simplify that code.
2017-08-27 17:14:02 +02:00
asarium 4f096c26b2 Avoid redundant glActiveTexture calls
This introduces a new function in the OpenGL state tracker which
combines setting the active texture unit and enabling a texture. The
reason this is a good idea is that this new function can filter out
unneeded calls to glActiveTexture if the texture is already enabled on
that specific unit. This happens very often when rendering several
submodels of a model which share their textures.

This is unlikely to yield significant performance improvements but
avoiding unneded OpenGL calls is always a good idea.
2017-08-27 13:46:44 +02:00
Goober5000 3db9fe9383 add field for setting the hotspot index of the exit button in the medals screen 2017-08-26 13:35:38 -04:00
Fabian Woltermann d1e236451f Merge pull request #1452 from asarium/fix/tgaLocking
Fix memory allocation in tga loading code
2017-08-26 18:11:11 +02:00
m!m 6cf7cb0843 Merge pull request #1450 from Goober5000/mantis_3174_fix
toss out the campaign savefile if we are restarting a previously finished campaign
2017-08-26 18:10:29 +02:00
asarium 2084eb01e8 Fix memory allocation in tga loading code
The code did not use the right method for calculating the required size
of the memory. This was never noticed before because the old OpenGL
texture loading code only used 16-bit textures for interface data but
the new code uses 32-bit textures which exhausted the available memory.

This was found and reported by @chief1983.
2017-08-26 17:08:26 +02:00
Goober5000 7d1365800f clean up old comments 2017-08-26 03:43:26 -04:00
Goober5000 66ce0acc17 toss out the campaign savefile if we are restarting a previously finished campaign 2017-08-26 03:38:20 -04:00
Fabian Woltermann c29954d672 Merge pull request #1449 from asarium/fix/arrayDetectionBug
Fix bug in texture array detection code
2017-08-25 19:55:49 +02:00
asarium f2d5246ccb Fix bug in texture array detection code
The code would have displayed the warning but didn't actually set the
flag to let the rest of the code know.
2017-08-25 18:22:34 +02:00
asarium b6dcc4f5ef Only generate headers for OpenGL 3.2
Since our target version is only OpenGL 3.2 all additional functionality
should only be used through their respective extensions to avoid
accidentially using a function not available in our minimum target
environment.
2017-08-25 18:18:17 +02:00
Fabian Woltermann bd62ceeeb0 Merge pull request #1318 from asarium/opengl/textureArrays
Use OpenGL texture arrays for animations
2017-08-25 18:00:56 +02:00
asarium f1bf0a411c Use OpenGL texture arrays for animations
This converts all usages of bmpman textures to OpenGL texture arrays.
That means that all frames of an animation are stored in a single OpenGL
texture object and can be accessed at the same time in a single draw
call. This should significantly reduce the overhead of drawing lots of
particles since all particles of a single animation can be drawn with a
single draw call.

This fixes #1169.
2017-08-25 11:31:02 +02:00
asarium 28898ca8e3 Add scrolling support to new debug window 2017-08-25 09:51:09 +02:00
MageKing17 3acdf3e801 Merge pull request #1399 from asarium/fix/1306
Use unique_ptr for storing HUD gauge pointers
2017-08-24 09:23:54 -07:00
MageKing17 f1101bee5d Merge pull request #1414 from asarium/feature/targettedFSOVersion
Add mod table setting for specifying targetted FSO version
2017-08-24 09:21:58 -07:00
MageKing17 e617f0cc41 Merge pull request #1435 from asarium/fix/ffGlobalGain
Add config option for setting the FF strength
2017-08-24 09:09:55 -07:00
MageKing17 7c9f73fbdc Merge pull request #1444 from asarium/fix/travisSourceCompression
Actually compress the source archive
2017-08-24 09:09:10 -07:00
Fabian Woltermann c36b47a35c Merge pull request #1290 from asarium/opengl/simplifyGrInterface
Move 2D drawing functions to a generic implementation
2017-08-24 17:41:32 +02:00
m!m 8d0b0a76f2 Merge pull request #1446 from MageKing17/bugfix/cmeasure-timer-interval-init
Explicitly initialize cmeasure_timer_interval to 0.
2017-08-24 17:21:05 +02:00
MageKing17 36e5afe1be Explicitly initialize cmeasure_timer_interval to 0.
If we rely on uninitialized values, we're likely to wind up with countermeasures that are only ever active for a single frame.
2017-08-24 04:54:42 -07:00
m!m 20398150d8 Merge pull request #647 from MageKing17/feature/countermeasure-pulse-interval
Allow countermeasures to pulse at regular intervals instead of globally.
2017-08-24 10:38:41 +02:00
m!m e085cc20ab Merge pull request #1445 from MageKing17/bugfix/beam-sound-unpause
Actually unpause 3D beam sounds correctly.
2017-08-24 09:25:33 +02:00
asarium 6b5869853c Correctly handle alpha blending for gr_flash_alpha 2017-08-23 14:42:54 +02:00
asarium a6411cc1d3 Add documentation for drawing functions 2017-08-23 14:42:54 +02:00
asarium bd4427a832 Reformat 2017-08-23 14:42:54 +02:00
asarium 6dbd7c34e6 Clean up a few remaining functions 2017-08-23 14:42:54 +02:00
asarium 7a3029d1e3 Remove unused gr_screen API functions 2017-08-23 14:42:54 +02:00
asarium 1bca5f128d Convert curve and circle functions 2017-08-23 14:42:54 +02:00
asarium 6bbb6be880 Move line drawing functions to generic implementation 2017-08-23 14:42:54 +02:00
asarium c1c2b72ef0 Move gr_string out of OpenGL code 2017-08-23 14:42:54 +02:00
asarium 1aa85d236e Begin moving 2D functions to a generic implementation
Thanks to the new material system, it's now possible to easily make the
2D functions independent of the underlying graphics API which allows to
reduce the size of the gr_screen 2D API.
2017-08-23 14:42:54 +02:00
MageKing17 1afc5eec13 Actually unpause 3D beam sounds correctly.
beam_pause_sounds() "pauses" looping beam sounds by setting their volume to 0; beam_unpause_sounds() "unpaused" by calling beam_recalc_sounds(), which only set the volume correctly when -no_3d_sound is set; 3D sound updates the sound's position without changing its volume. This PR just makes beam_unpause_sounds() perform the inverse operation of beam_pause_sounds() if 3D sounds are enabled.
2017-08-23 05:03:25 -07:00
Fabian Woltermann 759c9b1148 Merge pull request #1439 from asarium/opengl/genericVideoDisplay
Remove OpenGL code from cutscene presenter
2017-08-23 14:02:53 +02:00
Fabian Woltermann 47bb378342 Merge pull request #1438 from asarium/fix/aabitmapRemapping
Move 4 bit color conversion out of graphics code
2017-08-23 14:02:35 +02:00
m!m 0b3dad8dc0 Merge pull request #1308 from niffiwan/feature/tint_shader
Add colour-configurable tint shader
2017-08-23 12:53:50 +02:00
m!m 13e601a523 Merge pull request #1372 from MageKing17/feature/avx2-build-support
Add AVX2 to the list of supported MSVC compiler optimizations.
2017-08-23 12:50:16 +02:00
MageKing17 5de1b684f4 Merge pull request #1442 from asarium/fix/noWarningStacktrace
Remove stack trace from warning dialogs
2017-08-23 03:46:21 -07:00
asarium c5dcaf88d8 Actually compress the source archive
The previous command simply created a tar with a tar.gz ending which is
wrong. This fixes that.
2017-08-23 12:45:47 +02:00
MageKing17 55558cc608 Merge pull request #1437 from asarium/fix/unixSources
Build Unix source package before configuring
2017-08-23 03:44:43 -07:00
MageKing17 addc3ef383 Allow countermeasures to pulse at regular intervals instead of globally.
Adds a new "+Pulse Interval:" countermeasure field that enables the new behavior; all countermeasures that don't have this field defined still use the old behavior of the global frame counter.

This changes countermeasure logic quite a bit, but I attempted to mitigate performance implications by re-using an existing traversal of the object list in order to build the list of active countermeasures each frame. If any countermeasures are actively pulsing in a frame, the object list is traversed again, looking for homing weapons. Each homing weapon then goes through the active countermeasure list and checks to see if it got decoyed. Most of this central logic is unchanged from the old behavior, although no longer separated into two functions, and it should be more efficient since it's using a prepared list of active countermeasures instead of traversing the object list looking for countermeasures for every homing missile (which are themselves found by traversing the object list).
2017-08-23 03:39:48 -07:00
MageKing17 2c1abf78d1 Merge pull request #1443 from asarium/build/versionBump
Bump development version after final release
2017-08-23 03:37:14 -07:00
asarium 77c950ccd4 Bump development version after final release 2017-08-23 09:48:36 +02:00
asarium b160184f5b Remove stack trace from warning dialogs
It serves no purpose there since it's a message specifically designed to
be seen by modders and most times the stack trace doesn't even contain
useful information since there are no debug symbols present.
2017-08-23 00:02:28 +02:00
asarium f8d0a9bc7d Remove most remaining OpenGL header includes 2017-08-18 17:53:23 +02:00
asarium 72fa41a284 Use the generic rendering interface for cutscenes 2017-08-18 17:53:23 +02:00
asarium 72a797f732 Move 4 bit color conversion out of graphics code
Currently, the graphics code does some color remapping on 8
bit-per-pixel textures since those textures use special 4-bit pixel
values. These changes move that conversion out of the graphics code and
into the image loading/font bitmap creation code.

The reason this is needed is because this conversion breaks 8-bit
textures that try to use the full range of colors. I need to do exactly
that for moving the cutscene renderer to our generic rendering interface
which I can't do at the moment since the existing color conversion
corrupts the video data.

I have tested this with retail data and could not find any visual
changes after applying these changes.
2017-08-16 17:20:32 +02:00
asarium 2b0ec7161a Build Unix source package before configuring
The previous version included the make files which increased the size of
the package.
2017-08-15 10:18:09 +02:00
asarium 90c23c007c Add config option for setting the FF strength 2017-08-10 10:09:02 +02:00
asarium 4648721674 Add mod table parsing to qtfred initializers 2017-08-04 20:04:54 +02:00
asarium ae4a7319e5 Add About dialog 2017-08-04 15:13:16 +02:00
asarium 3c7f7f9df0 Add error checker action 2017-08-04 14:13:47 +02:00
asarium e11250f7e8 Add subsystem selection actions 2017-08-04 13:28:36 +02:00
asarium 24dec72f41 Add control object action 2017-08-04 10:55:50 +02:00
asarium 89c36b68c7 Add Align object action 2017-08-04 10:54:56 +02:00
asarium e66d9d1246 Add Level object action 2017-08-04 10:53:27 +02:00
asarium 789135516e Add Misc menu shortcuts 2017-08-04 10:53:27 +02:00
asarium 91b61d446f Add group action support 2017-08-04 10:53:27 +02:00
asarium 8e5aafb6e5 Add delete actions 2017-08-04 10:53:27 +02:00
asarium cb0080bfc1 Add actions for hiding and showing toolbar and statusbar 2017-08-04 10:53:27 +02:00
asarium a03180c46e Add Save camera position action 2017-08-04 10:53:27 +02:00
asarium a18fdd2112 Add support for hiding specific teams 2017-08-04 10:53:27 +02:00
asarium 7c81ac1d86 Improve waypoint dialog layout and behavior
The dialog is not resizable anymore and the combobox is disabled if
there are no entries.
2017-08-04 10:53:27 +02:00
asarium bc7414c403 Improve window title handling 2017-08-04 10:53:27 +02:00
asarium a7418d6dde Add documentation to runAfterInit 2017-08-04 10:53:27 +02:00
m!m f83c2e9cdc Merge pull request #1431 from asarium/qtfred2_/sync
Sync qtFRED branch
2017-08-04 10:52:53 +02:00
asarium 965a327630 Merge branch 'master' into qtfred2_/sync 2017-08-04 09:09:32 +02:00
Tyler Blount c9bb3f4caa Merge pull request #1428 from asarium/qtfred2_/dev
Add ship selection dialog
2017-08-02 01:12:36 -06:00
asarium 3e1b020bf5 Add local rotate action 2017-07-31 13:02:56 +02:00
asarium 60d6aaccec Add orbit rotate functionality 2017-07-31 12:57:28 +02:00
asarium 18a957e8bf Fix list selection 2017-07-31 10:20:55 +02:00
asarium ad7bddfd41 Copy old mission load code to qtFRED 2017-07-30 17:50:56 +02:00
asarium a90d859891 Add object selection dialog 2017-07-30 17:37:35 +02:00
asarium 841872aae0 Add mod table setting for specifying targetted FSO version
This adds a small system for letting a mod specify which version of FSO
was designed for. That would allow us to introduce code which would
normally break backwards-compatibility by putting it in an if block
which checks if the mod supports the FSO version which ontroduced the
behavioral change.

There is currently no code which uses the new functions yet so I added a
few tests to verify that the options do what they are designed to do.

This fixes #1389.
2017-07-14 20:09:29 +02:00
m!m 9b1e9600ce Merge pull request #1410 from asarium/qtfred2_/dev
Add form and disband wing actions
2017-07-10 09:44:25 +02:00
asarium 07a806e01f Clear mission on load 2017-07-09 13:25:38 +02:00
asarium ccd33eb50f Add zoom toolbar actions 2017-07-09 13:23:53 +02:00
asarium 1805c77f7c Add disband wing action and update enabled status 2017-07-09 12:46:26 +02:00
asarium 481ebec316 Add form wing action
This also introduces the new generic dialog system which should allow
the mission code to open specific dialogs without depending on the
actual Qt implementation.
2017-07-09 10:25:06 +02:00
m!m 99d8b19ee8 Merge pull request #1408 from TRBlount/qtfred2_dialogs
Add Mission Specs Editor
2017-07-08 11:12:35 +02:00
TRBlount 5adc3216df Fix CI compilation on Linux and Windows Debug 2017-07-08 02:21:18 -06:00
TRBlount 55f39e088d Use Dialog Provider and fix some model functions 2017-07-08 02:04:36 -06:00
TRBlount 71b572b7f4 Fix CI issues 2017-07-07 17:58:18 -06:00
TRBlount c1908669d9 Finish Custom Wing Name Editor 2017-07-07 16:31:29 -06:00
TRBlount a9d25fd18d Add Custom Wing Model 2017-07-07 14:37:00 -06:00
TRBlount 72c5d17739 Add Custom Wing dialog 2017-07-07 13:59:53 -06:00
TRBlount ecf10d8227 Fix comments and add Command Messages 2017-07-07 04:18:11 -06:00
TRBlount 8ab448dd70 Move to modification system
Alerts the user whenever they have unsaved changes
2017-07-07 03:16:21 -06:00
TRBlount ea53cff723 Add Mission Spec Model 2017-07-07 02:37:58 -06:00
TRBlount 407888641c Modify UI to use correct components
Some misuse of Spin Boxes and Line Edits
2017-07-05 18:40:36 -06:00
TRBlount ac554f24c2 Fix include formatting and Combo Box issues 2017-07-05 02:27:42 -06:00
TRBlount 56670b2ed7 Figure out QFileDialogs, issues with AI Profile Box 2017-07-05 02:19:16 -06:00
TRBlount 7e26955853 Figure out text cursors 2017-07-04 19:30:54 -06:00
TRBlount c085eef9a0 Update UI file and setup mission flags 2017-07-04 02:15:14 -06:00
TRBlount 8061125d84 Continue implementation
Some data actually saves now
2017-07-03 08:21:48 -06:00
asarium 72013d4c31 Use unique_ptr for storing HUD gauge pointers
The previous system used naked pointers which probably worked fine but
this should give us some extra memory-leak security.
2017-07-03 12:52:39 +02:00
TRBlount 93b1c0df17 Get dialog to close on accepted and rejected 2017-07-03 00:55:31 -06:00
TRBlount 41f889e55d Add Mission Spec Editor and begin implementation 2017-07-02 17:46:00 -06:00
Goober5000 416d45d060 deprecate string-concatenate since it's now redundant 2017-07-01 23:05:48 -04:00
Goober5000 18be4e854c add string-concatenate-block, which is a better design than the original string-concatenate 2017-07-01 23:05:48 -04:00
Tyler Blount 7d92178777 Merge pull request #1398 from asarium/qtfred2_/dev
Add object orientation editor
2017-07-01 16:54:35 -06:00
asarium ac69bd5712 Remove dialog test code 2017-07-01 23:47:15 +02:00
asarium d6b6ea715a Add Object orientation and location editor 2017-07-01 23:42:04 +02:00
asarium 8c59b06b59 Add form for object orientation editor 2017-06-29 08:57:13 +02:00
Tyler Blount e59d31d66e Merge pull request #1392 from asarium/qtfred2_/dev
Add waypoint editor
2017-06-28 01:28:31 -06:00
asarium 19c01563ca Add missing files 2017-06-28 08:52:28 +02:00
asarium 80f1f50582 Add edit popup menu and double click handling 2017-06-27 23:47:36 +02:00
asarium a057e111ba Add fully working waypoint editor
This is the first editor that is functional and uses.
2017-06-27 23:44:43 +02:00
asarium b45998b58d Add waypoint editor dialog form 2017-06-27 23:35:55 +02:00
m!m 472a3f09f7 Merge pull request #1380 from TRBlount/qtfred2_dialogs
Add Team Loadout and Mission Objective editors
2017-06-20 08:48:06 +02:00
TRBlount d6c4ff374c Update Team Loadout and Mission Objective Editors
Changes the above editors to use dialog button boxes and spacer widgets
instead of min/max sizes.
2017-06-18 00:57:23 -06:00
TRBlount b14c12befa Add Mission Goal and Team Loadout Dialogs 2017-06-18 00:57:23 -06:00
Tyler Blount 2d7606740a Merge pull request #1377 from asarium/qtfred2_/dev
Add object creation and drag movement of ships
2017-06-18 00:57:00 -06:00
asarium 1712a42807 Add abstracted dialog system 2017-06-17 15:52:36 +02:00
asarium f811d7591f Remove the need to specify the editor pointer 2017-06-14 17:56:30 +02:00
asarium 7e9f0c8e6f Connect toolbar button for showing distances 2017-06-14 17:46:33 +02:00
asarium 255814dd4f Fix warning 2017-06-13 11:38:10 +02:00
asarium e076aa6990 Add briefing editor to main window and fix layout 2017-06-13 11:14:16 +02:00
asarium 16d48fbf1b Port object moving and creation code 2017-06-13 10:56:44 +02:00
Tyler Blount 937de9355b Merge pull request #1373 from asarium/qtfred2_/dev
qtFRED development changes
2017-06-12 00:57:55 -06:00
asarium 947b25e2cc Add executable icon 2017-06-11 23:20:02 +02:00
asarium e6f92f316a Move Briefing editor dialog to correct folder 2017-06-11 22:08:42 +02:00
asarium f65de9bb43 Fix compilation warning 2017-06-11 20:04:42 +02:00
asarium 956e908b6e Separate editor viewport state into separate class
This moves all the data related to the editor state that is not directly
connected to the renderer into its own class and file. This should
resemble the fredrenderer <-> fredview separation in the original FRED.
2017-06-11 20:04:41 +02:00
asarium 0442c1c6ac Fix case of Editor file 2017-06-11 20:04:40 +02:00
asarium 1a3b14316d Move init and shutdown stuff out of editor.cpp 2017-06-11 20:04:38 +02:00
asarium 350e8a2cf5 Add various selection modes including box selection 2017-06-11 20:04:37 +02:00
asarium 4cd9993640 Add Event dialog code 2017-06-11 20:04:36 +02:00
asarium 41137fedbd Begin adding dialog infrastructure 2017-06-11 20:04:34 +02:00
asarium 52901e7351 Add viewpoint status label 2017-06-11 20:04:33 +02:00
MageKing17 526076f8ff Add AVX2 to the list of supported MSVC compiler optimizations.
Also adds AVX2 autodetection so that AVX2-capable processors will generate AVX2 projects by default. To my surprise, there is actually a noticeable performance increase between AVX and AVX2 builds.
2017-06-10 14:19:19 -07:00
m!m 8236a7d7f8 Merge pull request #1370 from TRBlount/Briefing_Editor
Add Briefing Editor Dialog
2017-06-10 11:42:44 +02:00
Tyler Blount 70e63dcf6c Fix include casing 2017-06-10 02:45:47 -06:00
TRBlount 557ff6be1d Add Briefing Editor Dialog 2017-06-10 01:37:16 -06:00
m!m 95896e6ec7 Merge pull request #1369 from asarium/qtfred2_/dev
Update qtFRED development files
2017-06-10 09:22:34 +02:00
asarium e6acd9a313 Add current ship control mode
Also fixed infinite recursion in key handler.
2017-06-09 23:16:06 +02:00
asarium c1cb978687 Fix context menu of RenderWindow 2017-06-09 18:58:53 +02:00
asarium 51698af1b0 Add viewpoint switching 2017-06-09 13:57:30 +02:00
asarium 9d3659cf88 Fix UI file compilation 2017-06-09 11:34:52 +02:00
asarium 3eddce06dd Add buddies settings to EventDialog form 2017-06-09 11:19:11 +02:00
asarium 9c75a2178c Remove unneeded variable name parameter in CMake config 2017-06-09 11:05:17 +02:00
asarium d26253c5f8 Add an application icon
It's currently the normal FRED icon.
2017-06-09 10:55:28 +02:00
asarium 6b5cac174a Add dialogs folder 2017-06-09 10:11:51 +02:00
asarium 1f39915a5e Add Event editor dialog form 2017-06-09 10:07:02 +02:00
asarium d60306288b Rebind movement speed shortcuts to fix camera movement 2017-06-09 10:06:55 +02:00
asarium 305e71e290 Copy display_distances code to fix rendering bug 2017-06-08 22:55:20 +02:00
asarium befe668c8b Remove deleted file from CMake config 2017-06-08 19:28:42 +02:00
asarium 25e87fb8a0 Use a timer with a 5 millisecond interval for our idle function
It uses less resources than the 0-interval timer.
2017-06-08 19:22:21 +02:00
asarium 9a11f232f6 Call super function in event filter 2017-06-08 19:11:01 +02:00
asarium 49a37ccf91 Fix view speed changing 2017-06-08 19:08:52 +02:00
asarium ee8d03b4cf Fix onIdle behavior 2017-06-08 19:07:02 +02:00
asarium 16b80faaaf Fix Travis CI warnings 2017-06-08 18:42:13 +02:00
asarium 0f7810fdb4 Add support for changing movement speed 2017-06-08 16:19:30 +02:00
asarium f85dfbb048 Add support for hiding objects
Also cleaned up some parameter handling
2017-06-08 15:32:47 +02:00
asarium 96ed407dd7 Fix endless loop 2017-06-08 13:04:36 +02:00
asarium cd7cf82430 Use render widget as focus proxy to redirect key events 2017-06-08 13:00:14 +02:00
asarium cff16f7b0b Remove object iterator 2017-06-08 12:49:06 +02:00
asarium 1a08bfa3e7 Handle window activation and deactivation 2017-06-08 12:39:45 +02:00
asarium dbc52e2aa7 Add handling of different cursor modes 2017-06-08 12:21:12 +02:00
asarium b1725bae76 Separate RenderWidget and RenderWindow
RenderWindow now only handled rendering and RenderWidget handles GUI
interaction by intercepting all GUI events for the RenderWindow.
2017-06-08 11:08:00 +02:00
asarium 4b10c61a5f Add initial cursor handling 2017-06-08 09:39:28 +02:00
asarium c18220048d Add handling of control constain buttons 2017-06-07 18:53:19 +02:00
asarium 08b8c1d768 Permanently create view popup menu 2017-06-07 17:56:39 +02:00
asarium 0f6a61894a Prevent context menu on the toolbar 2017-06-07 17:22:19 +02:00
asarium 3345aee144 Add viewport context menu
Still not complete but most actions are there already
2017-06-07 17:20:10 +02:00
asarium 207d3e6eba Continually update the view settings 2017-06-07 16:09:36 +02:00
asarium 8be0a19a98 Use a more elegant signal-slot solution for view option handling 2017-06-07 13:02:05 +02:00
asarium b517a47f81 Handle view settings updates 2017-06-07 12:35:51 +02:00
asarium 4afd5d9d1c Use normal event handler instead of event filter for shortcut override 2017-06-07 12:05:56 +02:00
asarium 7eaff0e63f Synchronize view settings with renderer settings 2017-06-07 10:52:10 +02:00
asarium 755df8c38b Fix crash when there is no valid filename 2017-06-07 10:51:56 +02:00
m!m 8357964e53 Merge pull request #1365 from asarium/qtfred2_/dev
Further qtFRED development
2017-06-07 10:38:54 +02:00
asarium e10b431735 Reformat FredView to fix GCC whitespace warning 2017-06-07 09:34:22 +02:00
asarium be5d7cc2cd Move most view parameters into the view struct 2017-06-06 23:42:41 +02:00
asarium 2e016ccffb Add support for storing recent files 2017-06-06 22:52:07 +02:00
asarium 4305649a64 Use standard key combinations for common actions 2017-06-06 22:51:42 +02:00
asarium 27c971a92b Actually fix MSVC 2013 compilation 2017-06-06 10:12:35 +02:00
asarium 1e1c8c7cb8 Actually add event based redrawing 2017-06-06 10:07:00 +02:00
asarium 94bb727ebe Fix MSVC 2013 compilation 2017-06-06 09:45:37 +02:00
m!m 884259fc14 Merge pull request #1360 from asarium/qtfred2_/editorSignals
Add signals to Editor class and implement window title switching
2017-06-05 21:47:19 +02:00
asarium 0b6a3115a7 Load debug filer file at startup 2017-06-05 19:13:52 +02:00
asarium ec6a786654 Create default ship on mission start 2017-06-05 18:02:16 +02:00
asarium a3744d8818 Fix installation step for FastDebug 2017-06-05 14:51:09 +02:00
asarium 5dc0c0d98d Add the Qt main code to fix compilation issues with FastDebug
This also removed the need to link the runtime dynamically.
2017-06-05 00:34:36 +02:00
asarium ad6551cf38 Override shortcuts when the key is on the key pad
This fixes the movement speed shortcuts
2017-06-04 15:57:12 +02:00
asarium 1cdc0840be Connect Open and New actions 2017-06-04 14:00:28 +02:00
asarium e7f619d65e Refactor render handling and editor separation 2017-06-04 13:44:22 +02:00
asarium 3ddc93fd9d Remove speed shortcuts to fix cmaera controls for now 2017-06-03 11:01:02 +02:00
asarium 6b32bdb732 Make sure our viewport is in use when updating the window 2017-06-02 22:21:09 +02:00
asarium cabc6f6412 Add organization and application names 2017-06-02 19:40:14 +02:00
asarium 164e20ef96 Remove usage of Qt in editor code 2017-06-02 19:24:12 +02:00
asarium d18b97014e Fix Unix compilation 2017-06-02 17:20:28 +02:00
asarium abdf713944 Add manifest for Windows 2017-06-02 17:16:54 +02:00
asarium 24a3369e9d Make sure member is initialied with a valid value 2017-06-01 23:47:32 +02:00
asarium cb94183629 Implement user name retrieval on Windows 2017-06-01 23:47:15 +02:00
asarium 7ecfa209ca Add Ship class combo box
This is still a few features of the old combobox.
2017-06-01 22:57:42 +02:00
asarium 22105d1e3e Use FredView as the new main window 2017-06-01 21:46:12 +02:00
asarium 588659a367 Rename frmFRED to match the name of the original FRED name 2017-06-01 11:40:49 +02:00
z64555 423d14c24a Add (another) UI for main window, mainwindow.ui is slated to be removed. 2017-06-01 11:27:42 +02:00
asarium 2f44c3242f Convert XPM to PNG and add images to resources 2017-06-01 11:19:14 +02:00
z64555 1167a4edcb Include art assets for UI 2017-06-01 11:04:40 +02:00
asarium 862010b4e0 Fix Qt config for mac 2017-06-01 10:46:02 +02:00
asarium 95dff1dacf Port mission clear code to qtfred 2017-06-01 10:40:43 +02:00
asarium bc38232f3a Use Qt 5.7 for Travis 2017-05-31 21:55:51 +02:00
asarium a29708ea89 Reformatted FredRenderer 2017-05-31 18:24:08 +02:00
asarium baeb9ac78b Improve handling of fredGlobals 2017-05-31 10:02:37 +02:00
asarium 211b9c9d71 Install custom Qt message handler 2017-05-31 09:44:55 +02:00
asarium 4c05a103fa Improve startup window display
Windows will now only be displayed once startup is complete and not when
the graphics code is initialized.
2017-05-31 00:29:42 +02:00
asarium 540e52ffbc Forward unused keyboard event to render window 2017-05-31 00:08:43 +02:00
m!m 0fc55babaf Merge pull request #1356 from asarium/qtfred2
Initial QtFRED source code
2017-05-29 10:10:54 +02:00
asarium 4ce085cd49 Add signals to Editor class and implement window title switching 2017-05-29 09:18:15 +02:00
asarium 3edb4575d3 Fix Visual Studio 2015 compiler bug 2017-05-28 22:50:25 +02:00
asarium 26af516704 Fix gtest variable for forced shared crt 2017-05-28 18:59:18 +02:00
asarium 668dccf925 Use dynamic runtime and disable FRED compilation 2017-05-28 14:34:35 +02:00
asarium acdf88fdeb Set focus policy for render widget 2017-05-28 14:28:59 +02:00
asarium 577c49eedb Add appveyor qt configuration 2017-05-28 14:08:55 +02:00
asarium 9cd3d80b81 Change setOption usage for Qt 5.2 compatibility 2017-05-28 13:51:48 +02:00
asarium e8316662b8 Improve update behavior 2017-05-28 13:23:59 +02:00
asarium 6a82c1eee7 Reformat file 2017-05-28 13:04:49 +02:00
asarium a309cb51b1 Add assertions for making sure a renderer exists 2017-05-28 13:02:28 +02:00
asarium af60cefbd5 Include QWidget header to fix compilation 2017-05-28 12:35:01 +02:00
asarium 8e2b1f354a Add message if dynamic runtime is not enabled 2017-05-28 12:32:02 +02:00
asarium 1d3ee16198 Remove unused field and fix brace warning
The fields were also unused by the previous FRED renderer so we are not
simply missing the code that used them.
2017-05-28 11:39:26 +02:00
asarium cb7f2a5dfd Remove unused include 2017-05-28 11:23:51 +02:00
asarium 18a621764c Fix warnings in FredRenderer 2017-05-28 10:48:35 +02:00
asarium 22c7e31c8a Merge branch 'fix/openglIncludes' into qtfred2 2017-05-28 10:36:01 +02:00
asarium 00ff9e8751 Correct message referencing wxFRED 2017-05-28 10:32:15 +02:00
asarium ba26f6e221 Add Travis CI configuration 2017-05-28 10:21:28 +02:00
asarium ed01e155f6 Fix typo 2017-05-28 09:58:17 +02:00
asarium cd110bb2c1 Some minor improvements to the main function 2017-05-28 09:30:00 +02:00
asarium 2c30dbcda6 Add better control of viewport destruction order 2017-05-27 23:51:39 +02:00
asarium 160d49fa82 Remove unused function 2017-05-27 23:03:27 +02:00
asarium 431ad4144f Fix Visual Studio uni test compilation with shared runtime 2017-05-27 23:03:00 +02:00
asarium 2555d11427 Use lambda instead of std::bind 2017-05-27 21:52:54 +02:00
asarium e1882fc314 Add better mechanism for specifying Qt install root 2017-05-27 21:52:30 +02:00
asarium 2804b5d9d3 Update rendering handling. 2017-05-27 20:39:24 +02:00
asarium 2bbe201130 Various changes while trying to find cause for shutdown crash 2017-05-27 19:04:36 +02:00
asarium bbbc08fa87 Fix borders around render widget 2017-05-27 19:04:21 +02:00
asarium a8def1e1b3 Improve CMake setup, now has proper source folder support 2017-05-27 19:02:53 +02:00
asarium 987a442dd6 Reorganize QtFRED file structure 2017-05-27 13:26:30 +02:00
asarium 09d39da97c Remove unneeded renderer initialization 2017-05-27 13:14:11 +02:00
asarium 0a2e6f581b Add commandline parsing
Also fixed some initialization inconsistencies
2017-05-27 11:37:45 +02:00
asarium 98cde8f21f Fix XSTR related crash when loading a mission 2017-05-27 11:05:42 +02:00
asarium 9d22d75ba8 Add claifying comment in main 2017-05-27 11:05:29 +02:00
asarium df095e6bdf Fix various Qt and rendering issues
Now this is actually able to show the mission grid (but mission loading
still fails).
2017-05-27 09:55:06 +02:00
asarium 243f7f7ce8 Disable memcpy checks if third party libraries are used 2017-05-25 23:46:10 +02:00
asarium 32b6696162 Fix qtfred code 2017-05-25 23:42:44 +02:00
asarium ac8befa4e6 Reimport previous qtfred source 2017-05-25 23:42:32 +02:00
niffiwan e003d08249 Fix lua function documentation 2017-03-20 20:37:38 +10:00
niffiwan c8baf8b344 Don't assume sexp will have all RGB supplied
Fix annoying clang pedantry with union aggregate init lists
2017-03-19 16:01:20 +10:00
niffiwan b5f75af66e Allow tint shader to be controlled by sexp & lua
i.e. the RGB values can be set/changed
2017-03-19 12:52:51 +10:00
niffiwan 25415342ea Add colour-configurable tint shader
FotG needs a tint shader for a feature; basically toggle screen tinting
when a key is pressed as a visual indicator of which mode your ship it
in. Was previously done in a custom shader.
2017-03-12 22:04:33 +10:00
1031 changed files with 109712 additions and 25469 deletions

No files matched your search

+99
View File
@@ -0,0 +1,99 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: false
AlignEscapedNewlinesLeft: false
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
IncludeCategories:
- Regex: '^(<.*\.(h|hh|hpp)>)$' # Includes of external libraries
Priority: 4
- Regex: '^(<.*>)$' # standard library includes (won't match deprecated C headers)
Priority: 5
- Regex: '^"[^/]*\.(h)"$' # Local includes
Priority: 1
- Regex: '^".*\.(h)"$' # standard engine includes
Priority: 2
- Regex: '.*' # Catch all in case something is unhandled above
Priority: 3
IncludeIsMainRegex: '$'
IndentCaseLabels: false
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Left
ReflowComments: true
SortIncludes: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 4
UseTab: ForIndentation
...
+23
View File
@@ -0,0 +1,23 @@
---
Checks: "-*,\
modernize-*,\
-modernize-raw-string-literal,\
-modernize-use-using,\
-modernize-make-unique,\
performance-*,\
-performance-type-promotion-in-math-fn,\
misc-*,\
-misc-macro-parentheses,\
-misc-misplaced-widening-cast,\
-misc-static-assert,\
"
WarningsAsErrors: ''
HeaderFilterRegex: 'code/.*$|freespace2/.*$|qtfred/.*$|test/src/.*$|build/.*$'
AnalyzeTemporaryDtors: false
CheckOptions:
- key: 'misc-assert-side-effect.AssertMacros'
value: 'assert,Assert,Assertion'
- key: 'modernize-use-emplace.ContainersWithPushBack'
value: 'std::vector;std::deque;std::list;SCP_vector;SCP_deque;SCP_list'
...
+21
View File
@@ -0,0 +1,21 @@
build:
image: teaci/msys$$arch
pull: true
shell: mingw$$arch
commands:
- git submodule update --init --recursive
- if [ $$arch = 32 ]; then target=i686; fi
- if [ $$arch = 64 ]; then target=x86_64; fi
- pacman -S --needed --noconfirm --noprogressbar mingw-w64-${target}-pkg-config mingw-w64-${target}-cmake
- mkdir build && cd build
- cmake -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=$$CONFIGURATION -DFSO_USE_SPEECH=OFF -DFSO_USE_VOICEREC=OFF -DFSO_FATAL_WARNINGS=ON -DFSO_BUILD_FRED2=OFF ..
- make -j$(nproc) all
matrix:
arch:
- 64
- 32
CONFIGURATION:
- Debug
- Release
+4 -30
View File
@@ -1,33 +1,3 @@
*.o
*.a
.dirstamp
libtool
ltmain.sh
m4/libtool.m4
m4/ltoptions.m4
m4/ltsugar.m4
m4/ltversion.m4
m4/lt~obsolete.m4
compile
.deps/
code/.deps/
Makefile
Makefile.in
aclocal.m4
autom4te.cache/
config.*
code/fs2_open_*
code/wxFRED2_*
configure
depcomp
install-sh
missing
.svn
*.layout
projects/Xcode/Frameworks/
#========
#OS junk files
[Tt]humbs.db
*.DS_Store
@@ -286,3 +256,7 @@ CMakeSettings.json
# Weird files created by Linux
.fuse_hidden*
# This gets ignored by one of the rules above for some reason...
!/code/scripting/lua/LuaConvert.h
!/code/debugconsole/
-3
View File
@@ -1,6 +1,3 @@
[submodule "cmake/external/cotire"]
path = cmake/external/cotire
url = https://github.com/sakra/cotire.git
[submodule "cmake/external/rpavlik-cmake-modules"]
path = cmake/external/rpavlik-cmake-modules
url = https://github.com/asarium/cmake-modules.git
+45 -12
View File
@@ -3,7 +3,8 @@ sudo: required
dist: trusty
cache:
directories:
- $HOME/cmake
- $HOME/cmake-3.8
- $HOME/.ccache
addons:
apt:
packages: &global_deps
@@ -16,6 +17,7 @@ addons:
- libjansson-dev
- libsdl2-dev
- valgrind
- qt57base
coverity_scan:
project:
name: "scp-fs2open/fs2open.github.com"
@@ -69,19 +71,36 @@ matrix:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- g++-5
- *global_deps
- g++-5
- os: linux
env: CONFIGURATION="Debug" CC=clang-3.6 CXX=clang++-3.6
env: CONFIGURATION="Debug" CC=gcc-8 CXX=g++-8
addons:
apt:
sources:
- llvm-toolchain-precise
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- clang-3.6
- libc++-dev
- g++-8
- *global_deps
- os: linux
env: CONFIGURATION="Debug" CC=clang-4.0 CXX=clang++-4.0 CMAKE_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-4.0
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- *global_deps
- clang-4.0
- clang-tidy-4.0
- libc++-dev
script:
- ./ci/travis/script.sh
- ./ci/travis/clang_tidy.sh
- os: osx
env: CONFIGURATION="Debug"
@@ -91,19 +110,32 @@ matrix:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- g++-5
- *global_deps
- g++-5
- os: linux
env: CONFIGURATION="Release" CC=clang-3.6 CXX=clang++-3.6
env: CONFIGURATION="Release" CC=gcc-8 CXX=g++-8
addons:
apt:
sources:
- llvm-toolchain-precise
- ubuntu-toolchain-r-test
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- clang-3.6
- libc++-dev
- g++-8
- *global_deps
- os: linux
env: CONFIGURATION="Release" CC=clang-4.0 CXX=clang++-4.0
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-4.0
- sourceline: 'ppa:beineri/opt-qt571-trusty'
packages:
- *global_deps
- clang-4.0
- libc++-dev
- os: osx
env: CONFIGURATION="Release"
before_install:
@@ -117,8 +149,9 @@ before_install:
- "./ci/travis/before_install.sh"
install:
- "./ci/travis/install.sh"
- export PATH=$HOME/cmake/bin:$PATH
- export PATH=$HOME/cmake-3.6/bin:$PATH
before_script:
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then QT_ENV_SCRIPT=$(find /opt -name 'qt*-env.sh'); source $QT_ENV_SCRIPT; fi
- "./ci/travis/before_script.sh"
script:
- if [ "$BUILD_DEPLOYMENT" = true ] ; then ./ci/travis/release.sh ; else ./ci/travis/script.sh ; fi
+20 -7
View File
@@ -40,6 +40,14 @@ set(CMAKE_CONFIGURATION_TYPES Debug Release FastDebug CACHE STRING "Available co
PROJECT(FS2_Open)
find_program(CCACHE_PROGRAM ccache)
# Currently only GCC support ccache properly without generating additional warnings
if(CCACHE_PROGRAM AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
message(STATUS "Using ccache for compilation: ${CCACHE_PROGRAM}")
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}")
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "${CCACHE_PROGRAM}")
endif()
IF(CMAKE_CROSSCOMPILING)
SET(IMPORT_EXE_DIR "IMPORT_EXE_DIR-NOTFOUND" CACHE FILEPATH "Required for a cross compiling build, point to binary directory of a cmake build for the real OS")
INCLUDE(${IMPORT_EXE_DIR}/ImportExecutables.cmake)
@@ -53,7 +61,7 @@ endif()
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/finder")
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/external/rpavlik-cmake-modules")
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/external/cotire/CMake")
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/external/cotire")
IF(RESET_INSTALL_PREFIX)
IF(NOT $ENV{FS2PATH} STREQUAL "")
@@ -85,7 +93,7 @@ OPTION(FSO_BUILD_TESTS "Build unit tests" OFF)
OPTION(FSO_DEVELOPMENT_MODE "Generate binaries in development mode, only use if you know what you're doing!" OFF)
OPTION(FSO_BUILD_WXFRED2 "Build wxFRED2 binary" OFF)
OPTION(FSO_BUILD_QTFRED "Build qtFRED2 binary" OFF)
IF(WIN32 OR APPLE)
# On windows and mac the default should be to always build the included libraries
@@ -108,6 +116,8 @@ SET(FSO_RUN_ARGUMENTS "" CACHE STRING "Additional arguments passed to a generate
option(FSO_INSTALL_DEBUG_FILES "Install some debug files (currently only PDB files on windows)" OFF)
option(ENABLE_COTIRE "Enable cotire for faster compilation. Enabled by default." ON)
MARK_AS_ADVANCED(FORCE FSO_CMAKE_DEBUG)
MARK_AS_ADVANCED(FORCE FSO_BUILD_INCLUDED_LIBS)
MARK_AS_ADVANCED(FORCE FSO_USE_OPENALSOFT)
@@ -115,6 +125,7 @@ MARK_AS_ADVANCED(FORCE FSO_USE_LUAJIT)
MARK_AS_ADVANCED(FORCE FSO_DEVELOPMENT_MODE)
MARK_AS_ADVANCED(FORCE FSO_FATAL_WARNINGS)
mark_as_advanced(FORCE FSO_INSTALL_DEBUG_FILES)
mark_as_advanced(FORCE ENABLE_COTIRE)
# Include cotire file from https://github.com/sakra/cotire/
include(cotire)
@@ -134,6 +145,8 @@ if(FSO_BUILD_APPIMAGE)
include(appimage)
endif()
include(clang-tidy)
# This includes source code for some tools, either used in the build or also for something else
ADD_SUBDIRECTORY(tools)
@@ -147,9 +160,9 @@ IF(FSO_BUILD_FRED2)
ADD_SUBDIRECTORY(fred2)
ENDIF(FSO_BUILD_FRED2)
IF(FSO_BUILD_WXFRED2)
ADD_SUBDIRECTORY(wxfred2)
ENDIF(FSO_BUILD_WXFRED2)
IF(FSO_BUILD_QTFRED)
ADD_SUBDIRECTORY(qtfred)
ENDIF()
if(FSO_BUILD_TESTS)
add_subdirectory(test)
@@ -176,12 +189,12 @@ include(doxygen)
# Print used options to log
IF (WIN32)
message(STATUS "Building FRED2: ${FSO_BUILD_FRED2}")
message(STATUS "Using text to speech: ${FSO_USE_SPEECH}")
message(STATUS "Using voice recogition: ${FSO_USE_VOICEREC}")
message(STATUS "Building FRED2: ${FSO_BUILD_FRED2}")
elseif(UNIX)
message(STATUS "Building AppImage: ${FSO_BUILD_APPIMAGE}")
ENDIF()
message(STATUS "Building FSO tools: ${FSO_BUILD_TOOLS}")
message(STATUS "Building wxFRED: ${FSO_BUILD_WXFRED2}")
message(STATUS "Building qtFRED: ${FSO_BUILD_QTFRED}")
message(STATUS "Fatal warnings: ${FSO_FATAL_WARNINGS}")
+5 -2
View File
@@ -1,4 +1,5 @@
version: 1.0.0.{build}
image: Visual Studio 2015
configuration:
- Debug
- Release
@@ -6,11 +7,13 @@ clone_depth: 10
environment:
matrix:
- BuildID: 0
CMAKE_GENERATOR: Visual Studio 12 2013
PlatformToolset: v120_xp
CMAKE_GENERATOR: Visual Studio 14 2015
PlatformToolset: v140_xp
QT_DIR: C:\Qt\5.9.5\msvc2015
- BuildID: 1
CMAKE_GENERATOR: Visual Studio 14 2015 Win64
PlatformToolset: v140_xp
QT_DIR: C:\Qt\5.9.5\msvc2015_64
before_build:
- git submodule update --init --recursive
build_script:
+8
View File
@@ -4,6 +4,7 @@ class BuildConfig {
[string]$PackageType
[string]$Toolset
[string]$SimdType
[string]$QtDir
[Bool]$SourcePackage
}
@@ -13,6 +14,7 @@ $NightlyConfigurations = @(
PackageType="Win64";
Toolset="v140_xp";
SimdType="SSE2";
QtDir="C:\Qt\5.9.5\msvc2015_64";
SourcePackage=$false;
},
[BuildConfig]@{
@@ -20,6 +22,7 @@ $NightlyConfigurations = @(
PackageType="Win32";
Toolset="v140_xp";
SimdType="SSE2";
QtDir="C:\Qt\5.9.5\msvc2015";
SourcePackage=$false;
}
)
@@ -29,6 +32,7 @@ $ReleaseConfigurations = @(
PackageType="Win32";
Toolset="v140_xp";
SimdType="SSE2";
QtDir="C:\Qt\5.9.5\msvc2015";
SourcePackage=$true;
}
[BuildConfig]@{
@@ -36,6 +40,7 @@ $ReleaseConfigurations = @(
PackageType="Win32-AVX";
Toolset="v140_xp";
SimdType="AVX";
QtDir="C:\Qt\5.9.5\msvc2015";
SourcePackage=$false;
}
[BuildConfig]@{
@@ -43,6 +48,7 @@ $ReleaseConfigurations = @(
PackageType="Win64";
Toolset="v140_xp";
SimdType="SSE2";
QtDir="C:\Qt\5.9.5\msvc2015_64";
SourcePackage=$false;
}
[BuildConfig]@{
@@ -50,6 +56,7 @@ $ReleaseConfigurations = @(
PackageType="Win64-AVX";
Toolset="v140_xp";
SimdType="AVX";
QtDir="C:\Qt\5.9.5\msvc2015_64";
SourcePackage=$false;
}
)
@@ -141,6 +148,7 @@ if ($DeployBuild) {
Push-AppveyorArtifact "$($PackageName)-builds-$($buildConfig.PackageType).zip"
} else {
cmake -DFSO_USE_SPEECH="ON" -DFSO_FATAL_WARNINGS="ON" -DFSO_USE_VOICEREC="ON" -DFSO_BUILD_TESTS="ON" -DMSVC_SIMD_INSTRUCTIONS=SSE2 `
-DFSO_BUILD_QTFRED=ON -DQT5_INSTALL_ROOT="$env:QT_DIR" -DFSO_BUILD_FRED2="ON" `
-G "$Env:CMAKE_GENERATOR" -T "$Env:PlatformToolset" ..
cmake --build . --config "$Env:CONFIGURATION" -- /verbosity:minimal
+1 -14
View File
@@ -2,20 +2,7 @@
if ([System.Convert]::ToBoolean($env:ReleaseBuild) -Or [System.Convert]::ToBoolean($env:NightlyBuild) -Or [System.Convert]::ToBoolean($env:TestBuild)) {
# Skip tests for deployment
exit 0
} else {
# Appveyor doesn't have OpenAL so copy our DLLs to the output FOLDER
$arch=""
if ($Env:CMAKE_GENERATOR -Match "Win64") {
$arch="win64"
} else {
$arch="win32"
}
$dllPath = "$Env:APPVEYOR_BUILD_FOLDER\lib\openal\libs\$arch\OpenAL32.dll"
$copyDestination = "$pwd\bin\$Env:CONFIGURATION\"
write "Copying OpenAL DLL..."
Copy-Item "$dllPath" "$copyDestination"
} else {
write "Running unit tests..."
# Run unit tests
&"$pwd\bin\$Env:CONFIGURATION\unittests.exe" --gtest_shuffle 2>&1
+8 -3
View File
@@ -6,6 +6,11 @@ mkdir -p build
cd build
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
if [ "$RELEASE_BUILD" = true ]; then
PARENT_DIR="$(basename $PWD)"
(cd .. && tar -czvf /tmp/builds/$PACKAGE_NAME-source-Unix.tar.gz --exclude-vcs "$PARENT_DIR")
fi
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
@@ -15,7 +20,7 @@ if [ "$TRAVIS_OS_NAME" = "linux" ]; then
export CXXFLAGS
export CFLAGS
CMAKE="cmake -G Ninja -DFSO_FATAL_WARNINGS=ON"
CMAKE="cmake -G Ninja -DFSO_FATAL_WARNINGS=ON $CMAKE_OPTIONS"
if [ "$BUILD_DEPLOYMENT" = true ]; then
for config in $BUILD_CONFIGS
do
@@ -27,12 +32,12 @@ if [ "$TRAVIS_OS_NAME" = "linux" ]; then
cd ..
done
else
eval $CMAKE -DCMAKE_BUILD_TYPE=$CONFIGURATION -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON ..
eval $CMAKE -DCMAKE_BUILD_TYPE=$CONFIGURATION -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON -DFSO_BUILD_QTFRED=ON ..
fi
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
if [ "$BUILD_DEPLOYMENT" = true ]; then
cmake -G "Xcode" -DFSO_FATAL_WARNINGS=ON -DFSO_INSTALL_DEBUG_FILES=ON -DCMAKE_INSTALL_PREFIX="/tmp/release" ..
else
cmake -G "Xcode" ..
cmake -G "Xcode" $CMAKE_OPTIONS ..
fi
fi
+1 -1
View File
@@ -49,7 +49,7 @@ if ([ "$RELEASE_BUILD" = true ] || [ "$NIGHTLY_BUILD" = true ] || [ "$TEST_BUILD
fi
if [ "$BUILD_DEPLOYMENT" = true ]; then
if ([ "$TRAVIS_OS_NAME" = "linux" ] && (! [[ "$CC" =~ ^gcc.*$ ]])); then
if ([ "$TRAVIS_OS_NAME" = "linux" ] && (! [[ "$CC" =~ ^gcc-5.*$ ]])); then
echo "Skipping non-release compiler";
exit 0;
fi
+141
View File
@@ -0,0 +1,141 @@
#!/usr/bin/env python
#
#===- clang-tidy-diff.py - ClangTidy Diff Checker ------------*- python -*--===#
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
#===------------------------------------------------------------------------===#
r"""
ClangTidy Diff Checker
======================
This script reads input from a unified diff, runs clang-tidy on all changed
files and outputs clang-tidy warnings in changed lines only. This is useful to
detect clang-tidy regressions in the lines touched by a specific patch.
Example usage for git/svn users:
git diff -U0 HEAD^ | clang-tidy-diff.py -p1
svn diff --diff-cmd=diff -x-U0 | \
clang-tidy-diff.py -fix -checks=-*,modernize-use-override
"""
import argparse
import json
import re
import subprocess
import sys
def main():
parser = argparse.ArgumentParser(description=
'Run clang-tidy against changed files, and '
'output diagnostics only for modified '
'lines.')
parser.add_argument('-clang-tidy-binary', metavar='PATH',
default='clang-tidy',
help='path to clang-tidy binary')
parser.add_argument('-p', metavar='NUM', default=0,
help='strip the smallest prefix containing P slashes')
parser.add_argument('-regex', metavar='PATTERN', default=None,
help='custom pattern selecting file paths to check '
'(case sensitive, overrides -iregex)')
parser.add_argument('-iregex', metavar='PATTERN', default=
r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm|inc)',
help='custom pattern selecting file paths to check '
'(case insensitive, overridden by -regex)')
parser.add_argument('-fix', action='store_true', default=False,
help='apply suggested fixes')
parser.add_argument('-checks',
help='checks filter, when not specified, use clang-tidy '
'default',
default='')
parser.add_argument('-path', dest='build_path',
help='Path used to read a compile command database.')
parser.add_argument('-extra-arg', dest='extra_arg',
action='append', default=[],
help='Additional argument to append to the compiler '
'command line.')
parser.add_argument('-extra-arg-before', dest='extra_arg_before',
action='append', default=[],
help='Additional argument to prepend to the compiler '
'command line.')
parser.add_argument('-quiet', action='store_true', default=False,
help='Run clang-tidy in quiet mode')
clang_tidy_args = []
argv = sys.argv[1:]
if '--' in argv:
clang_tidy_args.extend(argv[argv.index('--'):])
argv = argv[:argv.index('--')]
args = parser.parse_args(argv)
# Extract changed lines for each file.
filename = None
lines_by_file = {}
for line in sys.stdin:
match = re.search('^\+\+\+\ \"?(.*?/){%s}([^ \t\n\"]*)' % args.p, line)
if match:
filename = match.group(2)
if filename == None:
continue
if args.regex is not None:
if not re.match('^%s$' % args.regex, filename):
continue
else:
if not re.match('^%s$' % args.iregex, filename, re.IGNORECASE):
continue
match = re.search('^@@.*\+(\d+)(,(\d+))?', line)
if match:
start_line = int(match.group(1))
line_count = 1
if match.group(3):
line_count = int(match.group(3))
if line_count == 0:
continue
end_line = start_line + line_count - 1;
lines_by_file.setdefault(filename, []).append([start_line, end_line])
if len(lines_by_file) == 0:
print("No relevant changes found.")
sys.exit(0)
line_filter_json = json.dumps(
[{"name" : name, "lines" : lines_by_file[name]} for name in lines_by_file],
separators = (',', ':'))
quote = "";
if sys.platform == 'win32':
line_filter_json=re.sub(r'"', r'"""', line_filter_json)
else:
quote = "'";
# Run clang-tidy on files containing changes.
command = [args.clang_tidy_binary]
command.append('-line-filter=' + quote + line_filter_json + quote)
if args.fix:
command.append('-fix')
if args.checks != '':
command.append('-checks=' + quote + args.checks + quote)
if args.quiet:
command.append('-quiet')
if args.build_path is not None:
command.append('-p=%s' % args.build_path)
command.extend(lines_by_file.keys())
for arg in args.extra_arg:
command.append('-extra-arg=%s' % arg)
for arg in args.extra_arg_before:
command.append('-extra-arg-before=%s' % arg)
command.extend(clang_tidy_args)
sys.exit(subprocess.call(' '.join(command), shell=True))
if __name__ == '__main__':
main()
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -e
if ! git rev-list $TRAVIS_COMMIT_RANGE 2>1 >/dev/null; then
echo "\$TRAVIS_COMMIT_RANGE ($TRAVIS_COMMIT_RANGE) is not valid for this build (probably caused by a rebase)."
exit 0
fi
cd "$TRAVIS_BUILD_DIR"
echo "Running clang-tidy on changed files"
git diff -U0 --no-color $TRAVIS_COMMIT_RANGE | \
$TRAVIS_BUILD_DIR/ci/travis/clang-tidy-diff.py -path "$TRAVIS_BUILD_DIR/build" -p1 \
-regex 'code/.*$|freespace2/.*$|qtfred/.*$|test/src/.*$|build/.*$|tools/.*' \
-clang-tidy-binary /usr/bin/clang-tidy-4.0 2>/dev/null | \
tee clang-tidy-output.txt
if [[ -n $(grep "warning: " clang-tidy-output.txt) ]] || [[ -n $(grep "error: " clang-tidy-output.txt) ]]; then
echo "Errors or warnings were detected in the clang-tidy output!"
exit 1
else
echo -e "\033[1;32m\xE2\x9C\x93 passed:\033[0m clang-tidy test succeeded";
fi
+1 -1
View File
@@ -26,8 +26,8 @@ if [[ ! "$(curl -V)" == *"sftp"* ]]; then
cd ..
dpkg -l | grep curl
ls -al
sudo dpkg -i curl*.deb
sudo dpkg -i libcurl3*.deb
sudo dpkg -i curl*.deb
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
brew install curl --with-libssh2
export PATH="/usr/local/opt/curl/bin:$PATH"
+5 -7
View File
@@ -4,16 +4,14 @@ set -ex
FILENAME=
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
if [ ! -d "$HOME/cmake/bin" ]; then
if [ ! -d "$HOME/cmake-3.8/bin" ]; then
# If the cache does not currently contain CMake then download and install it
FILENAME=cmake-3.4.3-Linux-x86_64
mkdir -p $HOME/cmake-3.8/
mkdir -p $HOME/cmake/
wget -O /tmp/cmake.tar.gz --no-check-certificate https://www.cmake.org/files/v3.4/$FILENAME.tar.gz
tar -xzf /tmp/cmake.tar.gz -C $HOME/cmake/ --strip-components=1
wget -O /tmp/cmake.tar.gz --no-check-certificate https://cmake.org/files/v3.8/cmake-3.8.2-Linux-x86_64.tar.gz
tar -xzf /tmp/cmake.tar.gz -C $HOME/cmake-3.8/ --strip-components=1
fi
export PATH=$HOME/cmake/bin:$PATH
export PATH=$HOME/cmake-3.8/bin:$PATH
cd $HOME
-5
View File
@@ -4,11 +4,6 @@ set -ex
mkdir -p /tmp/builds
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
if [ "$RELEASE_BUILD" = true ]; then
PARENT_DIR="$(basename $PWD)"
(cd .. && tar cvf /tmp/builds/$PACKAGE_NAME-source-Unix.tar.gz --exclude-vcs "$PARENT_DIR")
fi
cd build
for config in $BUILD_CONFIGS
do
+8 -3
View File
@@ -5,10 +5,15 @@ set -e
cd build
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
ninja all
ninja -k 20 all
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
--suppressions="$TRAVIS_BUILD_DIR/ci/travis/valgrind.supp" ./bin/unittests --gtest_shuffle
if [ "$CONFIGURATION" = "Debug" ]; then
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
--suppressions="$TRAVIS_BUILD_DIR/ci/travis/valgrind.supp" ./bin/unittests --gtest_shuffle
else
./bin/unittests --gtest_shuffle
fi
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
cmake --build . --config "$CONFIGURATION" | tee build.log | xcpretty
XCODE_RET=${PIPESTATUS[0]}
+9 -1
View File
@@ -25,4 +25,12 @@
fun:_dl_init
fun:dl_open_worker
fun:_dl_catch_error
}
}
{
CLang Lua unitialized value error
Memcheck:Cond
...
fun:luaH_get
fun:lua_rawget
fun:_ZN12_GLOBAL__N_117ade_index_handlerEP9lua_State
}
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/sh
HERE=$(dirname $(readlink -f "${0}"))
export LD_LIBRARY_PATH="${HERE}"/lib:$PATH
export LD_LIBRARY_PATH="${HERE}"/lib:"$LD_LIBRARY_PATH"
"${HERE}"/bin/$<TARGET_FILE_NAME:Freespace2> $@
+3
View File
@@ -1,6 +1,9 @@
include(WriteCompilerDetectionHeader)
set(CMAKE_CXX_STANDARD_REQUIRED 11)
set(CMAKE_CXX_STANDARD 11)
set(REQUIRED_CXX_FEATURES cxx_rvalue_references cxx_nullptr)
get_property(CMAKE_CXX_KNOWN_FEATURES GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES)
+37
View File
@@ -0,0 +1,37 @@
option(ENABLE_CLANG_TIDY "Enable source code checking using clang-tidy" OFF)
find_program(
CLANG_TIDY_EXE
NAMES "clang-tidy"
DOC "Path to clang-tidy executable"
)
function(enable_clang_tidy target)
# Not enabled in this configuration
endfunction()
if(NOT ENABLE_CLANG_TIDY)
return()
endif()
if(NOT EXISTS "${CLANG_TIDY_EXE}")
message(SEND_ERROR "clang-tidy: Could not find clang-tidy executable (value of variable is \"${CLANG_TIDY_EXE}\".")
return()
endif()
if(CMAKE_VERSION VERSION_LESS "3.6.0")
message(SEND_ERROR "Clang-tidy support requires CMake 3.6")
return()
endif()
message(STATUS "clang-tidy: Using \"${CLANG_TIDY_EXE}\"")
function(enable_clang_tidy target)
SET(TIDY_OPTIONS "${CLANG_TIDY_EXE}")
if(FSO_FATAL_WARNINGS)
set(TIDY_OPTIONS "${TIDY_OPTIONS};-warnings-as-errors=*")
endif()
set_target_properties(${target} PROPERTIES CXX_CLANG_TIDY "${TIDY_OPTIONS}")
endfunction()
+8 -1
View File
@@ -27,6 +27,7 @@ int main( int argc, char* argv[] )
int SSE = false;
int SSE2 = false;
int AVX = false;
int AVX2 = false;
int info[4];
cpuid(info, 0);
@@ -40,8 +41,14 @@ int main( int argc, char* argv[] )
AVX = (info[2] & ((int)1 << 28)) != 0;
}
if (nIds >= 7){
cpuid(info,0x00000007);
AVX2 = (info[1] & ((int)1 << 5)) != 0;
}
if(AVX)
if (AVX2)
std::cout << "AVX2";
else if(AVX)
std::cout << "AVX";
else if(SSE2)
std::cout << "SSE2";
Submodule cmake/external/cotire deleted from 40a46bf2fb.
+4054
View File
File diff suppressed because it is too large. Load diff
+9
View File
@@ -0,0 +1,9 @@
#ifndef __FREDRC_H
#define __FREDRC_H
#define ABOUT_LINE_1 "FRED2_OPEN - FreeSpace Editor, Version @FSO_PRODUCT_VERSION_STRING@ OpenGL"
#define MAINFRAME_CONTENTS "FRED2_OPEN @FSO_PRODUCT_VERSION_STRING@ - FreeSpace2 Mission Editor\nUntitled\nFRED2\nFreeSpace2 Missions (*.fs2)\n.fs2\nFreeSpace2Mission\nFreeSpace2 Mission"
#endif // __FREDRC_H
+3 -1
View File
@@ -1,5 +1,7 @@
include(platformChecks)
include(Cxx11)
include(platformChecks)
CONFIGURE_FILE(${CMAKE_CURRENT_LIST_DIR}/project.h.in ${GENERATED_SOURCE_DIR}/project.h)
CONFIGURE_FILE(${CMAKE_CURRENT_LIST_DIR}/fred_rc.h.in ${GENERATED_SOURCE_DIR}/fred_rc.h)
+8 -2
View File
@@ -15,9 +15,9 @@ CHECK_INCLUDE_FILE_CXX("cxxabi.h" HAVE_CXXAPI_H)
CHECK_TYPE_SIZE("max_align_t" MAX_ALIGN_T)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(CMAKE_REQUIRED_FLAGS "-std=c++11") # required for g++ <= 5
endif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
endif()
set(CMAKE_EXTRA_INCLUDE_FILES "cstddef")
CHECK_TYPE_SIZE("std::max_align_t" STD_MAX_ALIGN_T LANGUAGE CXX)
@@ -25,6 +25,9 @@ set(CMAKE_EXTRA_INCLUDE_FILES "type_traits")
CHECK_TYPE_SIZE("std::is_trivially_copyable<int>" STD_IS_TRIVIALLY_COPYABLE LANGUAGE CXX)
set(CMAKE_EXTRA_INCLUDE_FILES)
CHECK_TYPE_SIZE("char32_t" CHAR32_T LANGUAGE CXX)
CHECK_TYPE_SIZE("U'b'" UNICODE_CHAR_LITERAL LANGUAGE CXX)
set(CMAKE_REQUIRED_FLAGS)
@@ -38,5 +41,8 @@ CHECK_FUNCTION_EXISTS(strlwr HAVE_STRLWR)
CHECK_INCLUDE_FILE("strings.h" HAVE_STRINGS_H)
check_symbol_exists(snprintf "stdio.h" HAVE_SNPRINTF)
check_symbol_exists(_snprintf "stdio.h" HAVE__SNPRINTF)
set(PLATFORM_CHECK_HEADER "${GENERATED_SOURCE_DIR}/platformChecks.h")
CONFIGURE_FILE(${CMAKE_CURRENT_LIST_DIR}/platformChecks.h.in "${PLATFORM_CHECK_HEADER}")
+7
View File
@@ -9,6 +9,7 @@
#cmakedefine HAVE_STD_MAX_ALIGN_T
#cmakedefine HAVE_STD_IS_TRIVIALLY_COPYABLE
#cmakedefine HAVE_STD_IS_TRIVIALLY_COPYABLE_ARRAY
#cmakedefine01 IS_64BIT
@@ -21,4 +22,10 @@
#cmakedefine01 HAVE_STRINGS_H
#cmakedefine01 HAVE_CHAR32_T
#cmakedefine01 HAVE_UNICODE_CHAR_LITERAL
#cmakedefine01 HAVE_SNPRINTF
#cmakedefine01 HAVE__SNPRINTF
#endif // __PLATFORM_CHECKS_H__
+1 -3
View File
@@ -73,14 +73,12 @@ set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wreturn-type")
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-char-subscripts")
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-unused-parameter")
check_cxx_compiler_flag(-Wshift-negative-value SUPPORTS_SHIFT_NEGATIVE_VALUE)
if(SUPPORTS_SHIFT_NEGATIVE_VALUE)
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-shift-negative-value")
endif()
set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable")
set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-parameter")
set(COMPILER_FLAGS_DEBUG "-O0 -g -Wshadow")
+13 -3
View File
@@ -85,9 +85,18 @@ set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wreturn-type")
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-deprecated -Wno-char-subscripts")
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-unused-parameter")
# These two warnings cause a lot of false-positives in the FSO code base
check_cxx_compiler_flag(-Wstringop-truncation SUPPORTS_STRINGOP_TRUNCATION)
if(SUPPORTS_STRINGOP_TRUNCATION)
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-stringop-truncation")
endif()
set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-but-set-variable -Wno-array-bounds -Wno-empty-body -Wno-clobbered")
check_cxx_compiler_flag(-Wstringop-overflow SUPPORTS_STRINGOP_OVERFLOW)
if(SUPPORTS_STRINGOP_TRUNCATION)
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-stringop-overflow")
endif()
set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-but-set-variable -Wno-array-bounds -Wno-empty-body -Wno-clobbered -Wno-unused-parameter")
set(COMPILER_FLAGS_DEBUG "-O0 -g -Wshadow")
@@ -105,6 +114,7 @@ set(CMAKE_EXE_LINKER_FLAGS "")
IF (MINGW)
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -static-libgcc -static-libstdc++ -Wl,--enable-auto-import")
target_compile_definitions(compiler INTERFACE __USE_MINGW_ANSI_STDIO=1)
ENDIF(MINGW)
if (SANITIZE_FLAGS)
@@ -131,4 +141,4 @@ if (FSO_FATAL_WARNINGS)
endif()
# Always define this to make sure that the fixed width format macros are available
target_compile_definitions(compiler INTERFACE __STDC_FORMAT_MACROS)
target_compile_definitions(compiler INTERFACE __STDC_FORMAT_MACROS=1)
+3 -1
View File
@@ -33,7 +33,9 @@ set(WARNING_FLAGS
/wd4311 # Disables warnings about casting pointer types to ints. The funny thing is these warnings can't be resolved, just disabled... - m!m
/wd4302 # Same as above - m!m
/wd4366 # The result of the unary '&' operator may be unaligned - m!m
/wd4592 # "symbol will be dynamically initialized" is being generated by a compiler bug, see https://stackoverflow.com/a/34027257 for an explanation - m!m
$<$<CONFIG:Release>:/wd4101> # In release mode there are unreferenced variables because debug needs them
/wd4995 # "'vsprintf': name was marked as #pragma deprecated" is being caused by our custom definition of vsprintf. I have no idea what causes this or how to fix it - m!m
)
target_compile_options(compiler INTERFACE ${WARNING_FLAGS})
@@ -88,7 +90,7 @@ ENDIF(MSVC_USE_RUNTIME_DLL)
INCLUDE(MSVCMultipleProcessCompile)
# Visual Studio supports compiling for multiple vector instruction sets
SET(POSSIBLE_INSTUCTION_SETS "" SSE SSE2 AVX)
SET(POSSIBLE_INSTUCTION_SETS "" SSE SSE2 AVX AVX2)
if (NOT DEFINED MSVC_SIMD_INSTRUCTIONS)
detect_simd_instructions(MSVC_DETECTED_SIMD_INSTRUCTIONS)
+44 -4
View File
@@ -10,7 +10,7 @@ FUNCTION(ADD_IMPORTED_LIB NAME INCLUDES LIBS)
target_link_libraries(${NAME} INTERFACE "${LIBS}")
target_include_directories(${NAME} INTERFACE "${INCLUDES}")
target_include_directories(${NAME} SYSTEM INTERFACE "${INCLUDES}")
ENDFUNCTION(ADD_IMPORTED_LIB)
MACRO(PKG_CONFIG_LIB_RESOLVE NAME OUTVAR)
@@ -141,10 +141,12 @@ macro(set_if_not_defined VAR VALUE)
endmacro(set_if_not_defined)
macro(configure_cotire target)
# Disable unity build as it doesn't work well for us
set_target_properties(${target} PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
if(ENABLE_COTIRE)
# Disable unity build as it doesn't work well for us
set_target_properties(${target} PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE)
cotire(${target})
cotire(${target})
endif()
endmacro(configure_cotire)
macro(add_target_copy_files)
@@ -195,3 +197,41 @@ function(suppress_warnings _target)
target_compile_options(${_target} PRIVATE "-w")
endif()
endfunction(suppress_warnings)
function(list_target_dependencies _target _out_var)
set(out_list)
set(work_libs ${_target})
list(LENGTH work_libs libs_length)
while(libs_length GREATER 0)
list(GET work_libs 0 current)
list(REMOVE_AT work_libs 0)
list(APPEND out_list ${current})
get_target_property(current_libs ${current} INTERFACE_LINK_LIBRARIES)
if(current_libs)
foreach(lib ${current_libs})
if (TARGET ${lib})
list(APPEND work_libs ${lib})
endif (TARGET ${lib})
endforeach(lib)
endif(current_libs)
list(LENGTH work_libs libs_length)
endwhile(libs_length GREATER 0)
list(REMOVE_DUPLICATES out_list)
set(${_out_var} ${out_list} PARENT_SCOPE)
endfunction(list_target_dependencies)
macro(add_file_folder FOLDER_NAME)
string(MAKE_C_IDENTIFIER "${FOLDER_NAME}" VARIABLE_NAME)
set(files_${VARIABLE_NAME} ${files_${VARIABLE_NAME}} ${ARGN})
string(REPLACE "/" "\\" FIXED_FOLDER_FILE "${FOLDER_NAME}")
source_group("${FIXED_FOLDER_FILE}" FILES ${ARGN})
set(source_files ${source_files} ${ARGN})
endmacro(add_file_folder)
+2 -2
View File
@@ -7,8 +7,8 @@ if (EXISTS "${PROJECT_SOURCE_DIR}/version_override.cmake")
endif()
set_if_not_defined(FSO_VERSION_MAJOR 3)
set_if_not_defined(FSO_VERSION_MINOR 7)
set_if_not_defined(FSO_VERSION_BUILD 5)
set_if_not_defined(FSO_VERSION_MINOR 8)
set_if_not_defined(FSO_VERSION_BUILD 1)
# A numeric revision e.g. the CI build number
set_if_not_defined(FSO_VERSION_REVISION 0)
+23 -5
View File
@@ -3,7 +3,7 @@ INCLUDE(source_groups.cmake)
INCLUDE(voice_rec.cmake)
ADD_LIBRARY(code STATIC ${file_root} ${VOICE_REC_FILES})
ADD_LIBRARY(code STATIC ${source_files} ${VOICE_REC_FILES})
target_compile_features(code PUBLIC ${REQUIRED_CXX_FEATURES})
@@ -21,7 +21,7 @@ TARGET_INCLUDE_DIRECTORIES(code PUBLIC ${GENERATED_SOURCE_DIR}/code)
target_link_libraries(code PUBLIC OpenGL)
TARGET_LINK_LIBRARIES(code PUBLIC ${OPENAL_LIBS})
TARGET_LINK_LIBRARIES(code PUBLIC openal)
TARGET_LINK_LIBRARIES(code PUBLIC ${LUA_LIBS})
TARGET_LINK_LIBRARIES(code PUBLIC ${PNG_LIBS})
TARGET_LINK_LIBRARIES(code PUBLIC ${JPEG_LIBS})
@@ -30,11 +30,17 @@ TARGET_LINK_LIBRARIES(code PUBLIC sdl2)
TARGET_LINK_LIBRARIES(code PUBLIC ffmpeg)
TARGET_LINK_LIBRARIES(code PUBLIC utfcpp)
TARGET_LINK_LIBRARIES(code PUBLIC platform)
TARGET_LINK_LIBRARIES(code PUBLIC compiler)
target_link_libraries(code PUBLIC md5)
target_link_libraries(code PUBLIC discord-rpc)
enable_clang_tidy(code)
IF (FSO_USE_SPEECH)
find_package(Speech REQUIRED)
target_link_libraries(code PUBLIC speech)
@@ -53,13 +59,25 @@ IF(FSO_BUILD_TOOLS)
ADD_SUBDIRECTORY(cfileextractor)
ENDIF(FSO_BUILD_TOOLS)
set_target_properties(code PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "prefix_header.h")
if (ENABLE_COTIRE)
set_target_properties(code PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${CMAKE_CURRENT_SOURCE_DIR}/prefix_header.h")
else()
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
target_compile_options(code PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${CMAKE_CURRENT_SOURCE_DIR}/prefix_header.h>")
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
target_compile_options(code PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:/FI ${CMAKE_CURRENT_SOURCE_DIR}/prefix_header.h>")
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
target_compile_options(code PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${CMAKE_CURRENT_SOURCE_DIR}/prefix_header.h>")
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
target_compile_options(code PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include${CMAKE_CURRENT_SOURCE_DIR}/prefix_header.h>")
ELSE()
MESSAGE("Unknown compiler for global includes. This will probably break the build.")
ENDIF()
endif()
include(util)
configure_cotire(code)
include(../cmake/Cxx11.cmake)
# Ensure that Xcode generates debug symbols on macOS for Debug builds
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS[variant=Debug] "YES")
set_target_properties(code PROPERTIES XCODE_ATTRIBUTE_COPY_PHASE_STRIP[variant=Debug] "NO")
+4 -4
View File
@@ -567,9 +567,9 @@ extern void ai_dock_with_object(object *docker, int docker_index, object *dockee
extern void ai_stay_still(object *still_objp, vec3d *view_pos);
extern void ai_do_default_behavior(object *obj);
extern void ai_start_waypoints(object *objp, waypoint_list *wp_list, int wp_flags);
extern void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hitpos, int shield_quadrant, vec3d *hit_normal);
extern void ai_ship_destroy(int shipnum, Ship::Exit_Flags method);
extern void ai_turn_towards_vector(vec3d *dest, object *objp, float frametime, float turn_time, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec = NULL, int sexp_flags = 0);
extern void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal);
extern void ai_ship_destroy(int shipnum);
extern void ai_turn_towards_vector(vec3d *dest, object *objp, float turn_time, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec = nullptr, int sexp_flags = 0);
extern void init_ai_object(int objnum);
extern void ai_init(void); // Call this one to parse ai.tbl.
extern void ai_level_init(void); // Call before each level to reset AI
@@ -622,7 +622,7 @@ extern float ai_path();
extern void evade_weapon();
extern int might_collide_with_ship(object *obj1, object *obj2, float dot_to_enemy, float dist_to_enemy, float duration);
extern int ai_fire_primary_weapon(object *objp); //changed to return weather it fired-Bobboau
extern int ai_fire_secondary_weapon(object *objp, int priority1 = -1, int priority2 = -1);
extern int ai_fire_secondary_weapon(object *objp);
extern float ai_get_weapon_dist(ship_weapon *swp);
extern void turn_towards_point(object *objp, vec3d *point, vec3d *slide_vec, float bank_override);
extern int ai_maybe_fire_afterburner(object *objp, ai_info *aip);
+1
View File
@@ -110,6 +110,7 @@ namespace AI {
Smart_subsystem_targeting_for_turrets,
Strict_turred_tagged_only_targeting,
Turrets_ignore_target_radius,
Use_actual_primary_range,
Use_additive_weapon_velocity,
Use_newtonian_dampening,
Use_only_single_fov_for_turrets,
+4 -1
View File
@@ -458,6 +458,8 @@ void parse_ai_profiles_tbl(const char *filename)
set_flag(profile, "$ai can slow down when attacking big ships:", AI::Profile_Flags::Ai_can_slow_down_attacking_big_ships);
set_flag(profile, "$use actual primary range:", AI::Profile_Flags::Use_actual_primary_range);
profile->bay_arrive_speed_mult = 1.0f;
profile->bay_depart_speed_mult = 1.0f;
if (optional_string("$bay arrive speed multiplier:")) {
@@ -498,7 +500,8 @@ void parse_ai_profiles_tbl(const char *filename)
}
// find next valid option
skip_to_start_of_string_either("$", "#");
if (!skip_to_start_of_string_either("$", "#"))
break;
saved_Mp = Mp;
}
}
+18 -24
View File
@@ -64,10 +64,11 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
void ai_big_avoid_ship();
int ai_big_maybe_follow_subsys_path(int do_dot_check=1);
void ai_big_strafe_position();
static int ai_big_strafe_maybe_retreat(const vec3d *target_pos);
extern int model_which_octant_distant_many( vec3d *pnt, int model_num,matrix *model_orient, vec3d * model_pos, polymodel **pm, int *octs);
extern void compute_desired_rvec(vec3d *rvec, vec3d *goal_pos, vec3d *cur_pos);
extern void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collide_pos, vec3d *collision_normal);
extern void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collision_normal);
// Called by ai_big_pick_attack_point.
@@ -631,7 +632,7 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
else
rvec = NULL;
ai_turn_towards_vector(enemy_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, rel_pos, 0.0f, 0, rvec);
ai_turn_towards_vector(enemy_pos, Pl_objp, sip->srotation_time, nullptr, rel_pos, 0.0f, 0, rvec);
// calc range of primary weapon
weapon_travel_dist = ai_get_weapon_dist(&Ships[Pl_objp->instance].weapons);
@@ -707,14 +708,14 @@ extern float set_secondary_fire_delay(ai_info *aip, ship *shipp, weapon_info *sw
extern void ai_choose_secondary_weapon(object *objp, ai_info *aip, object *en_objp);
extern int maybe_avoid_big_ship(object *objp, object *ignore_objp, ai_info *aip, vec3d *goal_point, float delta_time);
extern void maybe_cheat_fire_synaptic(object *objp, ai_info *aip);
extern void maybe_cheat_fire_synaptic(object *objp);
// Determine if Pl_objp should fire weapons at current target, based on input parameters
//
// dist_to_enemy => distance (in m) to attack point on current target
// dot_to_enemy => dot product between fvec of Pl_objp and vector from Pl_objp to attack point
//
void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy, vec3d *firing_pos, vec3d *enemy_pos, vec3d *enemy_vel)
static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
{
ai_info *aip;
ship_weapon *swp;
@@ -845,8 +846,6 @@ void ai_big_switch_to_chase_mode(ai_info *aip)
aip->submode_start_time = Missiontime;
}
extern int ai_big_strafe_maybe_retreat(float dist, vec3d *target_pos);
// Make object Pl_objp chase object En_objp, which is a big ship, not a small ship.
void ai_big_chase()
{
@@ -859,7 +858,7 @@ void ai_big_chase()
Assert(aip->mode == AIM_CHASE);
maybe_cheat_fire_synaptic(Pl_objp, aip);
maybe_cheat_fire_synaptic(Pl_objp);
ai_set_positions(Pl_objp, En_objp, aip, &player_pos, &enemy_pos);
@@ -882,7 +881,7 @@ void ai_big_chase()
dot_to_enemy = vm_vec_dot(&vec_to_enemy, &Pl_objp->orient.vec.fvec);
if (aip->ai_flags[AI::AI_Flags::Target_collision]) {
if ( ai_big_strafe_maybe_retreat(dist_to_enemy, &enemy_pos) ) {
if ( ai_big_strafe_maybe_retreat(&enemy_pos) ) {
aip->mode = AIM_STRAFE;
aip->submode_parm0 = Missiontime; // use parm0 as time strafe mode entered (i.e. MODE start time)
aip->submode = AIS_STRAFE_AVOID;
@@ -1045,7 +1044,7 @@ void ai_big_chase()
if ((dist_normal_to_enemy < ATTACK_COLLIDE_AVOID_DIST + speed_dist) || (time_to_enemy < ATTACK_COLLIDE_AVOID_TIME) ) {
// get away, simulate crsh recovery (don't use avoid)
// accelerate_ship(aip, -1.0f);
big_ship_collide_recover_start(Pl_objp, En_objp, &Pl_objp->pos, NULL);
big_ship_collide_recover_start(Pl_objp, En_objp, nullptr);
// aip->submode = SM_AVOID;
// aip->submode_start_time = Missiontime;
} else if ((dist_normal_to_enemy < ATTACK_COLLIDE_SLOW_DIST) || (time_to_enemy < ATTACK_COLLIDE_SLOW_TIME) ) {
@@ -1144,7 +1143,7 @@ void ai_big_chase()
// TODO: investigate why ships fire (and aren't close to hitting ship) when following a path near
// a big ship
if (aip->mode != AIM_EVADE && aip->path_start == -1 ) {
ai_big_maybe_fire_weapons(dist_to_enemy, dot_to_enemy, &player_pos, &predicted_enemy_pos, &En_objp->phys_info.vel);
ai_big_maybe_fire_weapons(dist_to_enemy, dot_to_enemy);
} else {
if (flFrametime < 1.0f)
aip->time_enemy_in_range *= (1.0f - flFrametime);
@@ -1153,11 +1152,6 @@ void ai_big_chase()
}
}
void ai_big_ship(object *objp)
{
// do nothing
}
// all three parms are output parameters
// Enemy object is En_objp
// pos => world pos of attack point
@@ -1228,7 +1222,7 @@ void ai_big_attack_get_data(vec3d *enemy_pos, float *dist_to_enemy, float *dot_t
// check to see if Pl_objp has gotten too close to attacking point.. if so, break off by entering
// AIS_STRAFE_RETREAT
int ai_big_strafe_maybe_retreat(float dist, vec3d *target_pos)
static int ai_big_strafe_maybe_retreat(const vec3d *target_pos)
{
ai_info *aip;
aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
@@ -1258,7 +1252,7 @@ int ai_big_strafe_maybe_retreat(float dist, vec3d *target_pos)
if (aip->ai_flags[AI::AI_Flags::Target_collision]) {
// use standard collision resolution
aip->ai_flags.remove(AI::AI_Flags::Target_collision);
big_ship_collide_recover_start(Pl_objp, En_objp, &Pl_objp->pos, NULL);
big_ship_collide_recover_start(Pl_objp, En_objp, nullptr);
} else {
// too close for comfort so fly to box point + 300
aip->submode = AIS_STRAFE_RETREAT1;
@@ -1298,12 +1292,12 @@ void ai_big_strafe_attack()
}
ai_big_attack_get_data(&target_pos, &target_dist, &target_dot);
if ( ai_big_strafe_maybe_retreat(target_dist, &target_pos) )
if ( ai_big_strafe_maybe_retreat(&target_pos) )
return;
if (aip->ai_flags[AI::AI_Flags::Kamikaze]) {
if (target_dist < 1200.0f) {
ai_turn_towards_vector(&target_pos, Pl_objp, flFrametime, Ship_info[Ships[Pl_objp->instance].ship_info_index].srotation_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&target_pos, Pl_objp, Ship_info[Ships[Pl_objp->instance].ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0);
accelerate_ship(aip, 1.0f);
if ((target_dist < 400.0f) && ai_maybe_fire_afterburner(Pl_objp, aip)) {
afterburners_start(Pl_objp);
@@ -1347,7 +1341,7 @@ void ai_big_strafe_attack()
}
// maybe fire weapons at target
ai_big_maybe_fire_weapons(target_dist, target_dot, &Pl_objp->pos, &En_objp->pos, &En_objp->phys_info.vel);
ai_big_maybe_fire_weapons(target_dist, target_dot);
turn_towards_point(Pl_objp, &target_pos, NULL, 0.0f);
fix last_hit = Missiontime - aip->last_hit_time;
@@ -1493,7 +1487,7 @@ void ai_big_strafe_glide_attack()
vm_vec_sub2(&target_pos, &En_objp->pos);
turn_towards_point(Pl_objp, &target_pos, NULL, 0.0f);
ai_big_maybe_fire_weapons(target_dist, target_dot, &Pl_objp->pos, &En_objp->pos, &En_objp->phys_info.vel);
ai_big_maybe_fire_weapons(target_dist, target_dot);
}
// if haven't been hit in quite a while, leave strafe mode
@@ -1517,7 +1511,7 @@ void ai_big_strafe_avoid()
mode_time = Missiontime - aip->submode_start_time;
ai_big_attack_get_data(&target_pos, &target_dist, &target_dot);
if ( ai_big_strafe_maybe_retreat(target_dist, &target_pos) )
if ( ai_big_strafe_maybe_retreat(&target_pos) )
return;
if ( mode_time > fl2f(0.5)) {
@@ -1704,7 +1698,7 @@ void ai_big_strafe()
//
// Check if weapon_objnum was fired by Pl_objp's target, and whether Pl_objp's target is a big ship, if
// so, enter AIM_STRAFE
int ai_big_maybe_enter_strafe_mode(object *pl_objp, int weapon_objnum, int consider_target_only)
int ai_big_maybe_enter_strafe_mode(const object *pl_objp, int weapon_objnum)
{
ai_info *aip;
ship_info *sip;
@@ -1778,7 +1772,7 @@ int ai_big_maybe_enter_strafe_mode(object *pl_objp, int weapon_objnum, int consi
// Consider attacking a turret, if a turret actually fired the weapon
// input: ship_objp => ship that will attack the turret
// weapon_objp =>
void ai_big_strafe_maybe_attack_turret(object *ship_objp, object *weapon_objp)
void ai_big_strafe_maybe_attack_turret(const object *ship_objp, const object *weapon_objp)
{
ai_info *aip;
object *parent_objp;
+2 -3
View File
@@ -17,14 +17,13 @@ struct ai_info;
struct vec3d;
class ship_subsys;
void ai_big_ship(object *objp);
void ai_big_chase();
void ai_big_subsys_path_cleanup(ai_info *aip);
// strafe functions
void ai_big_strafe();
int ai_big_maybe_enter_strafe_mode(object *objp, int weapon_objnum, int consider_target_only=0);
void ai_big_strafe_maybe_attack_turret(object *ship_objp, object *weapon_objp);
int ai_big_maybe_enter_strafe_mode(const object *objp, int weapon_objnum);
void ai_big_strafe_maybe_attack_turret(const object *ship_objp, const object *weapon_objp);
void ai_big_pick_attack_point(object *objp, object *attacker_objp, vec3d *attack_point, float fov=1.0f);
void ai_big_pick_attack_point_turret(object *objp, ship_subsys *ssp, vec3d *gpos, vec3d *gvec, vec3d *attack_point, float weapon_travel_dist, float fov=1.0f);
+82 -102
View File
@@ -68,7 +68,7 @@
#include "weapon/swarm.h"
#include "weapon/weapon.h"
#include <map>
#include <limits.h>
#include <climits>
#ifdef _MSC_VER
@@ -764,6 +764,8 @@ void parse_ai_class()
set_aic_flag(aicp, "$all ships manage shields:", AI::Profile_Flags::All_ships_manage_shields);
set_aic_flag(aicp, "$ai can slow down when attacking big ships:", AI::Profile_Flags::Ai_can_slow_down_attacking_big_ships);
set_aic_flag(aicp, "$use actual primary range:", AI::Profile_Flags::Use_actual_primary_range);
}
void reset_ai_class_names()
@@ -1132,7 +1134,7 @@ void ai_update_danger_weapon(int attacked_objnum, int weapon_objnum)
// If rvec != NULL, use it to match bank by calling vm_matrix_interpolate.
// (rvec defaults to NULL)
void ai_turn_towards_vector(vec3d *dest, object *objp, float frametime, float turn_time, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec, int sexp_flags)
void ai_turn_towards_vector(vec3d *dest, object *objp, float turn_time, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec, int sexp_flags)
{
matrix curr_orient;
vec3d vel_in, vel_out, desired_fvec, src;
@@ -1500,12 +1502,12 @@ void turn_towards_point(object *objp, vec3d *point, vec3d *slide_vec, float bank
if (aip->ai_flags[AI::AI_Flags::Formation_object, AI::AI_Flags::Formation_wing]) {
if (&Objects[aip->goal_objnum] != objp) {
float rotvel_z = objp->phys_info.rotvel.xyz.z;
ai_turn_towards_vector(point, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, slide_vec, NULL, bank_override, 0);
ai_turn_towards_vector(point, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, slide_vec, nullptr, bank_override, 0);
objp->phys_info.rotvel.xyz.z = rotvel_z;
}
} else {
// normal turn
ai_turn_towards_vector(point, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, slide_vec, NULL, bank_override, 0);
ai_turn_towards_vector(point, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, slide_vec, nullptr, bank_override, 0);
}
}
@@ -1520,7 +1522,7 @@ void turn_away_from_point(object *objp, vec3d *point, float bank_override)
vm_vec_sub(&opposite_point, &objp->pos, point);
vm_vec_add2(&opposite_point, &objp->pos);
ai_turn_towards_vector(&opposite_point, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, NULL, NULL, bank_override, AITTV_FAST);
ai_turn_towards_vector(&opposite_point, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, nullptr, nullptr, bank_override, AITTV_FAST);
}
@@ -3448,35 +3450,6 @@ float compute_time_to_enemy(float dist_to_enemy, object *pobjp)
return time_to_enemy + flFrametime;
}
// Stuff *dot and *tts.
// *dot is always computed. If dot is less than zero, the magnitude is
// incorrect, not having been divided by distance.
// If *dot is > 0.0f, then tts is computed. This is the time it will take object
// *objp to get to *pos, assuming it moves right at it.
void fds_aux(float *dot, float *tts, vec3d *pos, float dtime, object *objp)
{
vec3d v2s;
vm_vec_sub(&v2s, pos, &objp->pos);
*dot = vm_vec_dot(&v2s, &objp->orient.vec.fvec);
if (*dot > 0.0f) {
float dist;
dist = vm_vec_dist(&objp->pos, pos);
if (dist > 0.1f)
*dot /= dist;
else
*dot = 1.0f;
if (objp->phys_info.speed > 0.1f)
*tts = dist / objp->phys_info.speed;
else
*tts = dist * 100.0f;
}
}
// --------------------------------------------------------------------------
void ai_set_positions(object *pl_objp, object *en_objp, ai_info *aip, vec3d *player_pos, vec3d *enemy_pos)
{
@@ -3892,7 +3865,7 @@ float ai_path_0()
}
if (dist_to_goal > 0.1f)
ai_turn_towards_vector(&gcvp, Pl_objp, flFrametime, sip->srotation_time, slop_vec, NULL, 0.0f, 0);
ai_turn_towards_vector(&gcvp, Pl_objp, sip->srotation_time, slop_vec, nullptr, 0.0f, 0);
// Code to control speed is MUCH less forgiving in path following than in waypoint
// following. Must be very close to path or might hit objects.
@@ -4034,10 +4007,10 @@ float ai_path_1()
if (r <= 1.0f) {
vec3d midpoint;
vm_vec_avg3(&midpoint, &gcvp, &closest_point, &closest_point);
ai_turn_towards_vector(&midpoint, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0, prvec);
ai_turn_towards_vector(&midpoint, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0, prvec);
}
else {
ai_turn_towards_vector(&gcvp, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0, prvec);
ai_turn_towards_vector(&gcvp, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0, prvec);
}
}
@@ -4382,11 +4355,11 @@ void ai_fly_to_target_position(vec3d* target_pos, bool* pl_done_p=NULL, bool* pl
vm_vector_2_matrix(&Pl_objp->orient, &perp, NULL, NULL);
} else {
vm_vec_scale_add(&perp, &Pl_objp->pos, &Autopilot_flight_leader->phys_info.vel, 1000.0f);
ai_turn_towards_vector(&perp, Pl_objp, flFrametime, sip->srotation_time*3.0f*scale, slop_vec, NULL, 0.0f, 0);
ai_turn_towards_vector(&perp, Pl_objp, sip->srotation_time*3.0f*scale, slop_vec, nullptr, 0.0f, 0);
}
} else {
if (dist_to_goal > 0.1f) {
ai_turn_towards_vector(target_pos, Pl_objp, flFrametime, sip->srotation_time*3.0f*scale, slop_vec, NULL, 0.0f, 0);
ai_turn_towards_vector(target_pos, Pl_objp, sip->srotation_time*3.0f*scale, slop_vec, nullptr, 0.0f, 0);
}
}
@@ -5051,7 +5024,7 @@ void slide_face_ship()
dist = vm_vec_normalized_dir(&vec_from_enemy, &Pl_objp->pos, &En_objp->pos);
ai_turn_towards_vector(&En_objp->pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&En_objp->pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
dot_from_enemy = vm_vec_dot(&vec_from_enemy, &En_objp->orient.vec.fvec);
@@ -5234,7 +5207,7 @@ vec3d G_predicted_pos, G_fire_pos;
// Else
// Select Any ol' weapon.
// Returns primary_bank index.
int ai_select_primary_weapon_OLD(object *objp, object *other_objp, Weapon::Info_Flags flags)
static int ai_select_primary_weapon_OLD(const object *objp, Weapon::Info_Flags flags)
{
ship *shipp = &Ships[objp->instance];
ship_weapon *swp = &shipp->weapons;
@@ -5325,7 +5298,7 @@ int ai_select_primary_weapon(object *objp, object *other_objp, Weapon::Info_Flag
//not using the new AI, use the old version of this function instead.
if (!(Ai_info[shipp->ai_index].ai_profile_flags[AI::Profile_Flags::Smart_primary_weapon_selection]))
{
return ai_select_primary_weapon_OLD(objp, other_objp, flags);
return ai_select_primary_weapon_OLD(objp, flags);
}
Assert( shipp->ship_info_index >= 0 && shipp->ship_info_index < static_cast<int>(Ship_info.size()));
@@ -6051,8 +6024,7 @@ int check_ok_to_fire(int objnum, int target_objnum, weapon_info *wip)
// --------------------------------------------------------------------------
// Fire a secondary weapon.
// Maybe choose to fire a different one.
// priority1 and priority2 are optional parameters with defaults = -1
int ai_fire_secondary_weapon(object *objp, int priority1, int priority2)
int ai_fire_secondary_weapon(object *objp)
{
ship_weapon *swp;
ship *shipp;
@@ -6072,7 +6044,7 @@ int ai_fire_secondary_weapon(object *objp, int priority1, int priority2)
Assert( shipp->ship_info_index >= 0 && shipp->ship_info_index < static_cast<int>(Ship_info.size()));
// Select secondary weapon.
current_bank = swp->current_secondary_bank; //ai_select_secondary_weapon(objp, swp, priority1, priority2);
current_bank = swp->current_secondary_bank;
if (current_bank == -1) {
return rval;
@@ -6539,14 +6511,14 @@ void ai_chase_ct()
vm_vec_add2(&tvec, &Pl_objp->orient.vec.rvec);
}
ai_turn_towards_vector(&tvec, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&tvec, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
accelerate_ship(aip, 1.0f);
}
/**
* ATTACK submode handler for chase mode.
*/
void ai_chase_eb(ai_info *aip, ship_info *sip, vec3d *predicted_enemy_pos, float dist_to_enemy)
static void ai_chase_eb(ai_info *aip, ship_info *sip, vec3d *predicted_enemy_pos)
{
vec3d _pep;
float dot_to_enemy, dot_from_enemy;
@@ -6558,7 +6530,7 @@ void ai_chase_eb(ai_info *aip, ship_info *sip, vec3d *predicted_enemy_pos, float
if ((dot_to_enemy > dot_from_enemy + 0.1f) || (dot_to_enemy > 0.9f))
vm_vec_scale_add(&_pep, &Pl_objp->pos, &En_objp->orient.vec.fvec, 100.0f);
ai_turn_towards_vector(&_pep, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&_pep, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
accelerate_ship(aip, 0.0f);
}
@@ -6755,7 +6727,7 @@ void attack_set_accel(ai_info *aip, ship_info *sip, float dist_to_enemy, float d
// Pl_objp (aip) tries to get behind En_objp.
// New on 2/21/98: If this ship can move backwards and slide, maybe do that to get behind.
void get_behind_ship(ai_info *aip, ship_info *sip, float dist_to_enemy)
static void get_behind_ship(ai_info *aip, ship_info *sip)
{
vec3d new_pos;
float dot;
@@ -6764,7 +6736,7 @@ void get_behind_ship(ai_info *aip, ship_info *sip, float dist_to_enemy)
vm_vec_normalized_dir(&vec_from_enemy, &Pl_objp->pos, &En_objp->pos);
vm_vec_scale_add(&new_pos, &En_objp->pos, &En_objp->orient.vec.fvec, -100.0f); // Pick point 100 units behind.
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
dot = vm_vec_dot(&vec_from_enemy, &En_objp->orient.vec.fvec);
@@ -6783,7 +6755,7 @@ int avoid_player(object *objp, vec3d *goal_pos)
if (aip->ai_flags[AI::AI_Flags::Avoiding_small_ship]) {
ship_info *sip = &Ship_info[Ships[objp->instance].ship_info_index];
ai_turn_towards_vector(&aip->avoid_goal_point, objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&aip->avoid_goal_point, objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
accelerate_ship(aip, 0.5f);
return 1;
}
@@ -6981,7 +6953,7 @@ int maybe_avoid_big_ship(object *objp, object *ignore_objp, ai_info *aip, vec3d
vec3d v2g;
ai_turn_towards_vector(&aip->avoid_goal_point, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&aip->avoid_goal_point, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
vm_vec_normalized_dir(&v2g, &aip->avoid_goal_point, &Pl_objp->pos);
float dot = vm_vec_dot(&objp->orient.vec.fvec, &v2g);
float d2 = (1.0f + dot) * (1.0f + dot);
@@ -7073,7 +7045,7 @@ void ai_stealth_find()
}
}
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
return;
}
@@ -7083,9 +7055,9 @@ void ai_stealth_find()
if (dist_to_enemy > 500.0f) {
vec3d rvec;
compute_desired_rvec(&rvec, &new_pos, &Pl_objp->pos);
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0, &rvec);
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0, &rvec);
} else {
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
}
dot_from_enemy = -vm_vec_dot(&vec_to_enemy, &En_objp->orient.vec.fvec);
@@ -7213,7 +7185,7 @@ void ai_stealth_sweep()
return;
}
ai_turn_towards_vector(&goal_pt, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&goal_pt, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
float dot = 1.0f;
if (dist_to_goal < 100) {
@@ -7273,9 +7245,9 @@ void ai_chase_attack(ai_info *aip, ship_info *sip, vec3d *predicted_enemy_pos, f
if (dist_to_enemy > 500.0f) {
vec3d rvec;
compute_desired_rvec(&rvec, predicted_enemy_pos, &Pl_objp->pos);
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, rel_pos, bank_override, 0, &rvec);
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, rel_pos, bank_override, 0, &rvec);
} else {
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, rel_pos, bank_override, 0);
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, rel_pos, bank_override, 0);
}
attack_set_accel(aip, sip, dist_to_enemy, dot_to_enemy, dot_from_enemy);
@@ -7313,7 +7285,7 @@ void ai_chase_es(ai_info *aip, ship_info *sip)
float bank_override = Pl_objp->phys_info.speed;
ai_turn_towards_vector(&tvec, Pl_objp, flFrametime/2, sip->srotation_time, NULL, NULL, bank_override, 0);
ai_turn_towards_vector(&tvec, Pl_objp, sip->srotation_time, nullptr, nullptr, bank_override, 0);
accelerate_ship(aip, 1.0f);
}
@@ -7339,7 +7311,7 @@ void ai_chase_ga(ai_info *aip, ship_info *sip)
bank_override = Pl_objp->phys_info.speed;
ai_turn_towards_vector(&tvec, Pl_objp, flFrametime/2, sip->srotation_time, NULL, NULL, bank_override, 0);
ai_turn_towards_vector(&tvec, Pl_objp, sip->srotation_time, nullptr, nullptr, bank_override, 0);
accelerate_ship(aip, 2.0f);
@@ -8001,7 +7973,7 @@ void ai_cruiser_chase()
// kamikaze - ram and explode
if (aip->ai_flags[AI::AI_Flags::Kamikaze]) {
ai_turn_towards_vector(&En_objp->pos, Pl_objp, flFrametime, turn_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&En_objp->pos, Pl_objp, turn_time, nullptr, nullptr, 0.0f, 0);
accelerate_ship(aip, 1.0f);
}
@@ -8041,7 +8013,7 @@ void ai_cruiser_chase()
}
// now move as desired
ai_turn_towards_vector(&goal_pos, Pl_objp, flFrametime, turn_time, NULL, NULL, 0.0f, 0, rvecp);
ai_turn_towards_vector(&goal_pos, Pl_objp, turn_time, nullptr, nullptr, 0.0f, 0, rvecp);
accelerate_ship(aip, accel);
// maybe switch to new mode
@@ -8322,7 +8294,7 @@ void ai_chase()
break;
case SM_EVADE_BRAKE:
ai_chase_eb(aip, sip, &predicted_enemy_pos, dist_to_enemy);
ai_chase_eb(aip, sip, &predicted_enemy_pos);
break;
case SM_EVADE:
@@ -8334,7 +8306,7 @@ void ai_chase()
break;
case SM_GET_BEHIND:
get_behind_ship(aip, sip, dist_to_enemy);
get_behind_ship(aip, sip);
break;
case SM_GET_AWAY: // Used to get away from opponent to prevent endless circling.
@@ -8768,7 +8740,11 @@ void ai_chase()
scale = (scale - 0.6f) * 1.5f;
else
scale = 0.0f;
if (dist_to_enemy < pwip->max_speed * (1.0f + scale)) {
float range = pwip->max_speed * (1.0f + scale);
if (aip->ai_profile_flags[AI::Profile_Flags::Use_actual_primary_range]) {
range = std::min( {range, pwip->max_speed * pwip->lifetime, pwip->weapon_range} );
}
if (dist_to_enemy < range) {
if(ai_fire_primary_weapon(Pl_objp) == 1){
has_fired = 1;
}else{
@@ -9329,7 +9305,7 @@ float dock_orient_and_approach(object *docker_objp, int docker_index, object *do
{
float dot, accel;
float turn_time = Ship_info[Ships[docker_objp->instance].ship_info_index].srotation_time;
ai_turn_towards_vector(&goal_point, docker_objp, flFrametime, turn_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&goal_point, docker_objp, turn_time, nullptr, nullptr, 0.0f, 0);
dot = vm_vec_dot(&docker_objp->orient.vec.fvec, &away_vec);
accel = 0.1f;
@@ -9964,7 +9940,7 @@ void ai_big_guard()
}
// got the point, now let's go there
ai_turn_towards_vector(&goal_pt, Pl_objp, flFrametime, Ship_info[Ships[Pl_objp->instance].ship_info_index].srotation_time, NULL, NULL, 0.0f, 0);
ai_turn_towards_vector(&goal_pt, Pl_objp, Ship_info[Ships[Pl_objp->instance].ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0);
accelerate_ship(aip, 1.0f);
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (cur_guard_rad > 1.1f * max_guard_dist)) {
@@ -10088,7 +10064,7 @@ void ai_guard()
// quite far away, so try to go straight to
compute_desired_rvec(&rvec, &goal_point, &Pl_objp->pos);
ai_turn_towards_vector(&goal_point, Pl_objp, flFrametime, Ship_info[shipp->ship_info_index].srotation_time, NULL, NULL, 0.0f, 0, &rvec);
ai_turn_towards_vector(&goal_point, Pl_objp, Ship_info[shipp->ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0, &rvec);
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (accel_scale * (0.25f + dist_to_goal_point/700.0f) > 0.8f)) {
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
@@ -10395,6 +10371,7 @@ void ai_get_dock_goal_indexes(object *objp, ai_info *aip, ai_goal *aigp, object
case AIS_DOCK_2:
case AIS_DOCK_3:
Warning(LOCATION, "Normally dock indexes should be calculated for only AIS_DOCK_0 and AIS_UNDOCK_0. Trace out and debug.");
FALLTHROUGH;
case AIS_DOCK_0:
{
// get them from the active goal
@@ -10412,6 +10389,7 @@ void ai_get_dock_goal_indexes(object *objp, ai_info *aip, ai_goal *aigp, object
case AIS_UNDOCK_1:
case AIS_UNDOCK_2:
Warning(LOCATION, "Normally dock indexes should be calculated for only AIS_DOCK_0 and AIS_UNDOCK_0. Trace out and debug.");
FALLTHROUGH;
case AIS_UNDOCK_0:
{
// get them from the guy I'm docked to
@@ -10478,9 +10456,11 @@ void ai_cleanup_dock_mode_subjective(object *objp)
case AIS_UNDOCK_0:
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKED, docker_index, -1);
model_anim_start_type(goal_shipp, TRIGGER_TYPE_DOCKED, dockee_index, -1);
FALLTHROUGH;
case AIS_UNDOCK_1:
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKING_STAGE_3, docker_index, -1);
model_anim_start_type(goal_shipp, TRIGGER_TYPE_DOCKING_STAGE_3, dockee_index, -1);
FALLTHROUGH;
case AIS_UNDOCK_2:
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKING_STAGE_2, docker_index, -1);
model_anim_start_type(goal_shipp, TRIGGER_TYPE_DOCKING_STAGE_2, dockee_index, -1);
@@ -10490,9 +10470,11 @@ void ai_cleanup_dock_mode_subjective(object *objp)
case AIS_DOCK_4A:
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKED, docker_index, -1);
model_anim_start_type(goal_shipp, TRIGGER_TYPE_DOCKED, dockee_index, -1);
FALLTHROUGH;
case AIS_DOCK_3:
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKING_STAGE_3, docker_index, -1);
model_anim_start_type(goal_shipp, TRIGGER_TYPE_DOCKING_STAGE_3, dockee_index, -1);
FALLTHROUGH;
case AIS_DOCK_2:
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKING_STAGE_2, docker_index, -1);
model_anim_start_type(goal_shipp, TRIGGER_TYPE_DOCKING_STAGE_2, dockee_index, -1);
@@ -10707,8 +10689,8 @@ void ai_dock()
char *goal_ship_class_name = goal_sip->name;
char *goal_dock_path_name = model_get(goal_sip->model_num)->paths[aip->mp_index].name;
Warning(LOCATION, "Ship class %s has only %i points on dock path \"%s\". Recommended minimum number of points is 4. "\
"Docking along that path will look strange. You may wish to edit the model.", goal_ship_class_name, aip->path_length, goal_dock_path_name);
mprintf(("Ship class %s has only %i points on dock path \"%s\". Recommended minimum number of points is 4. "\
"Docking along that path will look strange. You may wish to edit the model.", goal_ship_class_name, aip->path_length, goal_dock_path_name));
}
aip->submode = AIS_DOCK_1;
@@ -10833,7 +10815,7 @@ void ai_dock()
if (aip->submode == AIS_DOCK_3) {
// Play a ship docking attach sound
snd_play_3d( &Snds[SND_DOCK_ATTACH], &Pl_objp->pos, &View_position );
snd_play_3d( gamesnd_get_game_sound(GameSounds::DOCK_ATTACH), &Pl_objp->pos, &View_position );
// start the dock animation
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKED, docker_index, 1);
@@ -10960,7 +10942,7 @@ void ai_dock()
ai_find_path(Pl_objp, OBJ_INDEX(goal_objp), path_num, 0);
// Play a ship docking detach sound
snd_play_3d( &Snds[SND_DOCK_DETACH], &Pl_objp->pos, &View_position );
snd_play_3d( gamesnd_get_game_sound(GameSounds::DOCK_DETACH), &Pl_objp->pos, &View_position );
aip->submode = AIS_UNDOCK_1;
aip->submode_start_time = Missiontime;
@@ -10980,7 +10962,7 @@ void ai_dock()
// play the depart sound, but only once, since this mode is called multiple times per frame
if ( !(aigp->flags[AI::Goal_Flags::Depart_sound_played]))
{
snd_play_3d( &Snds[SND_DOCK_DEPART], &Pl_objp->pos, &View_position );
snd_play_3d( gamesnd_get_game_sound(GameSounds::DOCK_DEPART), &Pl_objp->pos, &View_position );
aigp->flags.set(AI::Goal_Flags::Depart_sound_played);
}
@@ -11379,7 +11361,7 @@ float gwlr_1(object *objp, ai_info *aip)
/**
* Compute the largest radius of a ship forming on *objp's wing.
*/
float gwlr_object_1(object *objp, ai_info *aip)
static float gwlr_object_1(object *objp)
{
float max_radius;
object *o;
@@ -11412,7 +11394,7 @@ float get_wing_largest_radius(object *objp, int formation_object_flag)
aip = &Ai_info[shipp->ai_index];
if (formation_object_flag) {
return gwlr_object_1(objp, aip);
return gwlr_object_1(objp);
} else {
return gwlr_1(objp, aip);
}
@@ -12185,7 +12167,7 @@ void ai_maybe_launch_cmeasure(object *objp, ai_info *aip)
}
// --------------------------------------------------------------------------
void ai_preprocess_ignore_objnum(object *objp, ai_info *aip)
static void ai_preprocess_ignore_objnum(ai_info *aip)
{
if (aip->ai_flags[AI::AI_Flags::Temporary_ignore])
{
@@ -12376,6 +12358,7 @@ void ai_maybe_evade_locked_missile(object *objp, ai_info *aip)
case AIM_DOCK: // Ships in dock mode can evade iif they are not currently repairing or docked.
if (object_is_docked(objp) || (aip->ai_flags[AI::AI_Flags::Repairing, AI::AI_Flags::Being_repaired]))
break;
FALLTHROUGH;
case AIM_GUARD:
// If in guard mode and far away from guard object, don't pursue guy that hit me.
if ((aip->guard_objnum != -1) && (aip->guard_signature == Objects[aip->guard_objnum].signature)) {
@@ -12383,6 +12366,7 @@ void ai_maybe_evade_locked_missile(object *objp, ai_info *aip)
return;
}
}
FALLTHROUGH;
case AIM_EVADE:
case AIM_GET_BEHIND:
case AIM_STAY_NEAR:
@@ -13016,7 +13000,7 @@ void ai_execute_behavior(ai_info *aip)
ship *shipp = &Ships[aip->shipnum];
ship_info *sip = &Ship_info[shipp->ship_info_index];
if (strnicmp(shipp->ship_name, INSTRUCTOR_SHIP_NAME, strlen(INSTRUCTOR_SHIP_NAME))) {
if (strnicmp(shipp->ship_name, INSTRUCTOR_SHIP_NAME, strlen(INSTRUCTOR_SHIP_NAME)) != 0) {
if (sip->is_big_or_huge()) {
aip->mode = AIM_NONE;
} else {
@@ -13056,7 +13040,6 @@ void ai_execute_behavior(ai_info *aip)
case AIM_NONE:
break;
case AIM_BIGSHIP:
ai_big_ship(Pl_objp);
break;
case AIM_PATH: {
int path_num;
@@ -13433,7 +13416,7 @@ void ai_warp_out(object *objp)
// Return object index of weapon that could produce a shockwave that should be known about to *objp.
// Return nearest one.
int ai_find_shockwave_weapon(object *objp, ai_info *aip)
static int ai_find_shockwave_weapon(const object *objp)
{
missile_obj *mo;
float nearest_dist = 999999.9f;
@@ -13499,7 +13482,7 @@ void ai_announce_ship_dying(object *dying_objp)
// Return object index of weapon that could produce a shockwave that should be known about to *objp.
// Return nearest one.
int ai_find_shockwave_ship(object *objp, ai_info *aip)
static int ai_find_shockwave_ship(object *objp)
{
ship_obj *so;
float nearest_dist = 999999.9f;
@@ -13542,7 +13525,7 @@ int aas_1(object *objp, ai_info *aip, vec3d *safe_pos)
// If we don't currently know of a weapon to avoid, try to find one.
// If we can't find one, then clear the bit so we don't keep coming here.
if (aip->shockwave_object == -1) {
int shockwave_weapon = ai_find_shockwave_weapon(objp, aip);
int shockwave_weapon = ai_find_shockwave_weapon(objp);
if (shockwave_weapon == -1) {
aip->ai_flags.remove(AI::AI_Flags::Avoid_shockwave_weapon);
return 0;
@@ -13631,7 +13614,7 @@ int aas_1(object *objp, ai_info *aip, vec3d *safe_pos)
}
} else if (aip->ai_flags[AI::AI_Flags::Avoid_shockwave_ship]) {
if (aip->shockwave_object == -1) {
int shockwave_ship = ai_find_shockwave_ship(objp, aip);
int shockwave_ship = ai_find_shockwave_ship(objp);
if (shockwave_ship == -1) {
aip->ai_flags.remove(AI::AI_Flags::Avoid_shockwave_ship);
return 0;
@@ -13861,7 +13844,7 @@ int maybe_big_ship_collide_recover_frame(object *objp, ai_info *aip)
vec3d v2g;
if (aip->ai_flags[AI::AI_Flags::Big_ship_collide_recover_1]) {
ai_turn_towards_vector(&aip->big_recover_pos_1, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, NULL, NULL, 0.0f, 0, NULL);
ai_turn_towards_vector(&aip->big_recover_pos_1, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0, nullptr);
dist = vm_vec_normalized_dir(&v2g, &aip->big_recover_pos_1, &objp->pos);
dot = vm_vec_dot(&objp->orient.vec.fvec, &v2g);
accelerate_ship(aip, dot);
@@ -13875,7 +13858,7 @@ int maybe_big_ship_collide_recover_frame(object *objp, ai_info *aip)
return 1;
} else if (aip->ai_flags[AI::AI_Flags::Big_ship_collide_recover_2]) {
ai_turn_towards_vector(&aip->big_recover_pos_2, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, NULL, NULL, 0.0f, 0, NULL);
ai_turn_towards_vector(&aip->big_recover_pos_2, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0, nullptr);
dist = vm_vec_normalized_dir(&v2g, &aip->big_recover_pos_2, &objp->pos);
dot = vm_vec_dot(&objp->orient.vec.fvec, &v2g);
accelerate_ship(aip, dot);
@@ -13995,7 +13978,7 @@ void ai_frame(int objnum)
if (maybe_big_ship_collide_recover_frame(Pl_objp, aip))
return;
ai_preprocess_ignore_objnum(Pl_objp, aip);
ai_preprocess_ignore_objnum(aip);
target_objnum = set_target_objnum(aip, aip->target_objnum);
Assert(objnum != target_objnum);
@@ -14150,7 +14133,7 @@ void ai_frame(int objnum)
}
}
void ai_control_info_check( object *obj, ai_info *aip )
static void ai_control_info_check(ai_info *aip)
{
if(aip->ai_override_flags.none_set())
return;
@@ -14251,7 +14234,7 @@ void ai_process( object * obj, int ai_index, float frametime )
if (rfc == 1) {
// Wanderer - sexp based override goes here - only if rfc is valid though
ai_control_info_check(obj, aip);
ai_control_info_check(aip);
vec3d copy_desired_rotvel = obj->phys_info.rotvel;
physics_read_flying_controls( &obj->orient, &obj->phys_info, &AI_ci, frametime);
// if obj is in formation and not flight leader, don't update rotvel
@@ -14786,10 +14769,10 @@ int firing_aspect_seeking_bomb(object *objp)
return 0;
}
// *objp collided with big ship *big_objp at global point *collide_pos
// Make it fly away from the collision point.
// *objp collided with big ship *big_objp at some global point.
// Make it fly away from the collision point.
// collision_normal is NULL, when a collision is imminent and we just want to bug out.
void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collide_pos, vec3d *collision_normal)
void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collision_normal)
{
ai_info *aip;
@@ -14878,9 +14861,9 @@ void ai_update_lethality(object *pship_obj, object *other_obj, float damage)
/**
* Object *objp_ship was hit by either weapon *objp_weapon or collided into by ship hit_objp at point *hitpos.
* Object *objp_ship was hit by either weapon *objp_weapon or collided into by ship hit_objp
*/
void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hitpos, int shield_quadrant, vec3d *hit_normal)
void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal)
{
int hitter_objnum = -2;
object *objp_hitter = NULL;
@@ -14922,7 +14905,7 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hitpos, int shield_
// And the current object is _not_ a big ship
if (!Ship_info[Ships[objp_ship->instance].ship_info_index].is_big_or_huge()) {
// Recover from hitting a big ship. Note, if two big ships collide, they just pound away at each other. Oh well. Recovery looks dumb and it's very late.
big_ship_collide_recover_start(objp_ship, hit_objp, hitpos, hit_normal);
big_ship_collide_recover_start(objp_ship, hit_objp, hit_normal);
}
}
}
@@ -15059,7 +15042,7 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hitpos, int shield_
return;
if ( (hit_objp->type == OBJ_WEAPON) && !(aip->ai_flags[AI::AI_Flags::No_dynamic]) ) {
if ( ai_big_maybe_enter_strafe_mode(objp_ship, OBJ_INDEX(hit_objp), 1) )
if ( ai_big_maybe_enter_strafe_mode(objp_ship, OBJ_INDEX(hit_objp)) )
return;
}
break;
@@ -15179,10 +15162,7 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hitpos, int shield_
// Ship shipnum has been destroyed.
// Cleanup.
// the parameter 'method' is used to tell is this ship was destroyed or it departed normally.
// This function will get called in either case, and there are things that should be done if
// the ship actually gets destroyed which shouldn't get done if it departed.
void ai_ship_destroy(int shipnum, Ship::Exit_Flags method)
void ai_ship_destroy(int shipnum)
{
int objnum;
object *other_objp;
@@ -15433,7 +15413,7 @@ int ai_issue_rearm_request(object *requester_objp)
// we aren't able to do anything!
else {
Assert(result == 4);
Assertion(false, "This case should have already been caught by the is_support_allowed precheck!");
UNREACHABLE("This case should have already been caught by the is_support_allowed precheck!");
return -1;
}
}
@@ -15502,7 +15482,7 @@ int ai_return_path_num_from_dockbay(object *dockee_objp, int dockbay_index)
/**
* Actually go ahead and fire the synaptics.
*/
void cheat_fire_synaptic(object *objp, ship *shipp, ai_info *aip)
static void cheat_fire_synaptic(object *objp, ship *shipp)
{
ship_weapon *swp;
swp = &shipp->weapons;
@@ -15524,7 +15504,7 @@ void cheat_fire_synaptic(object *objp, ship *shipp, ai_info *aip)
// if they're near one or more enemies
// every so often
// fire a synaptic if they have one.
void maybe_cheat_fire_synaptic(object *objp, ai_info *aip)
void maybe_cheat_fire_synaptic(object *objp)
{
// Only do in subspace missions.
if (!(The_mission.flags[Mission::Mission_Flags::Subspace]))
@@ -15556,7 +15536,7 @@ void maybe_cheat_fire_synaptic(object *objp, ai_info *aip)
int count = num_nearby_fighters(iff_get_attackee_mask(obj_team(objp)), &objp->pos, 1500.0f);
if (count > 0)
cheat_fire_synaptic(objp, shipp, aip);
cheat_fire_synaptic(objp, shipp);
}
}
}
+4 -4
View File
@@ -125,7 +125,7 @@ const char *Ai_goal_text(int goal)
case AI_GOAL_REARM_REPAIR:
return XSTR( "rearm ", 484);
case AI_GOAL_FLY_TO_SHIP:
return XSTR( "rendezvous with ", -1);
return XSTR( "rendezvous with ", 1597);
}
// Avoid compiler warning
@@ -414,7 +414,7 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
if ( purge_ai_mode == AI_GOAL_CHASE_SHIP_CLASS ) {
// if the target of the purge goal is the same class of ship we are concerned about, then we have a match;
// if it is not, then we can continue (see standard ship check below)
if ( stricmp(purge_goal->target_name, Ship_info[Ships[ship_index].ship_info_index].name) )
if ( stricmp(purge_goal->target_name, Ship_info[Ships[ship_index].ship_info_index].name) != 0 )
continue;
}
// standard goals operating on either wings or ships
@@ -426,7 +426,7 @@ void ai_goal_purge_invalid_goals( ai_goal *aigp, ai_goal *goal_list, ai_info *ai
// don't match, we can continue; if the wing is valid, don't process if the wing numbers
// are different.
if ( purge_wing == -1 ) {
if ( stricmp(purge_goal->target_name, name ) )
if ( stricmp(purge_goal->target_name, name ) != 0 )
continue;
} else if ( purge_wing != wingnum )
continue;
@@ -1263,7 +1263,7 @@ void ai_add_wing_goal_sexp(int sexp, int type, int wingnum)
// this name can be a shipname or a wingname)
// docker_point and dockee_point are used for the AI_GOAL_DOCK command to tell two ships where to dock
// immediate means to process this order right away
void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int docker_point, int dockee_point, int immediate )
void ai_add_goal_ship_internal( ai_info *aip, int goal_type, char *name, int /*docker_point*/, int /*dockee_point*/, int immediate )
{
int gindex;
ai_goal *aigp;
+6 -6
View File
@@ -24,7 +24,7 @@
#include "weapon/swarm.h"
#include "weapon/weapon.h"
#include <limits.h>
#include <climits>
// How close a turret has to be point at its target before it
@@ -243,7 +243,7 @@ int bomb_headed_towards_ship(object *bomb_objp, object *ship_objp)
* @note All non-negative return values are expressed in what I like to call "widx"s.
* @return -1 if unable to find a weapon for the target at all.
*/
int turret_select_best_weapon(ship_subsys *turret, object *target)
int turret_select_best_weapon(ship_subsys *turret, object * /*target*/)
{
//TODO: Fill this out with extraodinary gun-picking algorithms
if(turret->weapons.num_primary_banks > 0)
@@ -2048,10 +2048,10 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
}
}
if ( wip->launch_snd != -1 ) {
if ( wip->launch_snd.isValid() ) {
// Don't play turret firing sound if turret sits on player ship... it gets annoying.
if ( parent_objnum != OBJ_INDEX(Player_obj) || (turret->flags[Ship::Subsystem_Flags::Play_sound_for_player]) ) {
snd_play_3d( &Snds[wip->launch_snd], turret_pos, &View_position );
snd_play_3d( gamesnd_get_game_sound(wip->launch_snd), turret_pos, &View_position );
}
}
}
@@ -2135,10 +2135,10 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
}
// maybe sound
if ( Weapon_info[tsi->weapon_class].launch_snd != -1 ) {
if ( Weapon_info[tsi->weapon_class].launch_snd.isValid() ) {
// Don't play turret firing sound if turret sits on player ship... it gets annoying.
if ( tsi->parent_objnum != OBJ_INDEX(Player_obj) ) {
snd_play_3d( &Snds[Weapon_info[tsi->weapon_class].launch_snd], &turret_pos, &View_position );
snd_play_3d( gamesnd_get_game_sound(Weapon_info[tsi->weapon_class].launch_snd), &turret_pos, &View_position );
}
}
+2 -2
View File
@@ -274,9 +274,9 @@ int anim_show_next_frame(anim_instance *instance, float frametime)
percent_through = instance->time_elapsed / time;
if(instance->direction == ANIM_DIRECT_FORWARD)
new_frame_num = instance->start_at - 1 + fl2i(percent_through * n_frames + 0.5f);
new_frame_num = instance->start_at - 1 + (int) lround(percent_through * n_frames);
else
new_frame_num = instance->start_at - 1 - fl2i(percent_through * n_frames + 0.5f);
new_frame_num = instance->start_at - 1 - (int) lround(percent_through * n_frames);
frame_save = instance->frame_num;
+16 -2
View File
@@ -512,7 +512,14 @@ int unpack_pixel(anim_instance *ai, ubyte *data, ubyte pix, int aabitmap, int bp
bit_16 = (ushort)pix;
break;
case 8:
bit_8 = pix;
// 8 bit-per-pixel aa bitmaps are a bit special since they only use value in the range [0, 15] where 15 wraps
// around back to 0. Since the rest of the code expects the value to be in the range [0, 255] the pixel value
// needs to be adjusted here. By muliplying the value with 17 the original range [0, 15] is mapped to [0, 255]
if (pix >= 15) {
bit_8 = 0;
} else {
bit_8 = (ubyte)(pix * 17);
}
break;
default:
Int3();
@@ -596,7 +603,14 @@ int unpack_pixel_count(anim_instance *ai, ubyte *data, ubyte pix, int count = 0,
bit_16 = (ushort)pix;
break;
case 8 :
bit_8 = pix;
// 8 bit-per-pixel aa bitmaps are a bit special since they only use value in the range [0, 15] where 15 wraps
// around back to 0. Since the rest of the code expects the value to be in the range [0, 255] the pixel value
// needs to be adjusted here. By muliplying the value with 17 the original range [0, 15] is mapped to [0, 255]
if (pix >= 15) {
bit_8 = 0;
} else {
bit_8 = (ubyte)(pix * 17);
}
break;
default :
Int3();
+41 -103
View File
@@ -76,7 +76,7 @@ float Asteroid_icon_closeup_zoom;
/**
* Force updating of pair stuff for asteroid *objp.
*/
void asteroid_update_collide(object *objp)
static void asteroid_update_collide(object *objp)
{
// Asteroid has wrapped, update collide objnum and flags
Asteroids[objp->instance].collide_objnum = -1;
@@ -87,7 +87,7 @@ void asteroid_update_collide(object *objp)
/**
* Clear out the ::Asteroid_obj_list
*/
void asteroid_obj_list_init()
static void asteroid_obj_list_init()
{
int i;
@@ -101,7 +101,7 @@ void asteroid_obj_list_init()
* Add a node from the Asteroid_obj_list.
* Only called from ::weapon_create()
*/
int asteroid_obj_list_add(int objnum)
static int asteroid_obj_list_add(int objnum)
{
int index;
@@ -123,7 +123,7 @@ int asteroid_obj_list_add(int objnum)
* Remove a node from the Asteroid_obj_list.
* Only called from ::weapon_delete()
*/
void asteroid_obj_list_remove(object * obj)
static void asteroid_obj_list_remove(object * obj)
{
int index = obj->instance;
@@ -138,7 +138,7 @@ void asteroid_obj_list_remove(object * obj)
/**
* Prevent speed from getting too huge so it's hard to catch up to an asteroid.
*/
float asteroid_cap_speed(int asteroid_info_index, float speed)
static float asteroid_cap_speed(int asteroid_info_index, float speed)
{
float max, double_max;
@@ -164,7 +164,7 @@ float asteroid_cap_speed(int asteroid_info_index, float speed)
* Sum together the following: 1 inside x, 2 inside y, 4 inside z
* inside only when sum = 7
*/
int asteroid_in_inner_bound_with_axes(asteroid_field *asfieldp, vec3d *pos, float delta)
static int asteroid_in_inner_bound_with_axes(asteroid_field *asfieldp, vec3d *pos, float delta)
{
Assert(asfieldp->has_inner_bound);
@@ -188,7 +188,7 @@ int asteroid_in_inner_bound_with_axes(asteroid_field *asfieldp, vec3d *pos, floa
* Check if asteroid is within inner bound
* @return 0 if not inside or no inner bound, 1 if inside inner bound
*/
int asteroid_in_inner_bound(asteroid_field *asfieldp, vec3d *pos, float delta) {
static int asteroid_in_inner_bound(asteroid_field *asfieldp, vec3d *pos, float delta) {
if (!asfieldp->has_inner_bound) {
return 0;
@@ -202,7 +202,7 @@ int asteroid_in_inner_bound(asteroid_field *asfieldp, vec3d *pos, float delta) {
*
* Moves to the other side of the inner box a distance delta from edge of box
*/
void inner_bound_pos_fixup(asteroid_field *asfieldp, vec3d *pos)
static void inner_bound_pos_fixup(asteroid_field *asfieldp, vec3d *pos)
{
if (!asteroid_in_inner_bound(asfieldp, pos, 0)) {
return;
@@ -446,7 +446,7 @@ void asteroid_sub_create(object *parent_objp, int asteroid_type, vec3d *relvec)
/**
* Load in an asteroid model
*/
void asteroid_load(int asteroid_info_index, int asteroid_subtype)
static void asteroid_load(int asteroid_info_index, int asteroid_subtype)
{
int i;
asteroid_info *asip;
@@ -487,26 +487,12 @@ void asteroid_load(int asteroid_info_index, int asteroid_subtype)
}
}
/**
* Randomly choose a debris model within the current group
*/
int get_debris_from_same_group(int index) {
int group_base, group_offset;
group_base = (index / NUM_DEBRIS_SIZES) * NUM_DEBRIS_SIZES;
group_offset = index - group_base;
// group base + offset
// offset is formed by adding 1 or 2 (since 3 in model group) and mapping back in the 0-2 range
return group_base + ((group_offset + rand()%(NUM_DEBRIS_SIZES-1) + 1) % NUM_DEBRIS_SIZES);
}
/**
* Returns a weight that depends on asteroid size.
*
* The weight is then used to determine the frequencty of different sizes of ship debris
*/
int get_debris_weight(int ship_debris_index)
static int get_debris_weight(int ship_debris_index)
{
int size = ship_debris_index % NUM_DEBRIS_SIZES;
switch (size)
@@ -626,7 +612,7 @@ void asteroid_create_all()
}
/**
* Init asteriod system for the level, called from ::game_level_init()
* Init asteroid system for the level, called from ::game_level_init()
*/
void asteroid_level_init()
{
@@ -645,7 +631,7 @@ void asteroid_level_init()
*
* @return !0 if asteroid should be wrapped, 0 otherwise.
*/
int asteroid_should_wrap(object *objp, asteroid_field *asfieldp)
static int asteroid_should_wrap(object *objp, asteroid_field *asfieldp)
{
if ( MULTIPLAYER_CLIENT )
return 0;
@@ -690,7 +676,7 @@ int asteroid_should_wrap(object *objp, asteroid_field *asfieldp)
/**
* Wrap an asteroid from one end of the asteroid field to the other
*/
void asteroid_wrap_pos(object *objp, asteroid_field *asfieldp)
static void asteroid_wrap_pos(object *objp, asteroid_field *asfieldp)
{
if (objp->pos.xyz.x < asfieldp->min_bound.xyz.x) {
objp->pos.xyz.x = asfieldp->max_bound.xyz.x + (objp->pos.xyz.x - asfieldp->min_bound.xyz.x);
@@ -727,7 +713,7 @@ void asteroid_wrap_pos(object *objp, asteroid_field *asfieldp)
*
* @return !0 if this asteroid is a target for any ship, otherwise return 0
*/
int asteroid_is_targeted(object *objp)
static int asteroid_is_targeted(object *objp)
{
ship_obj *so;
object *ship_objp;
@@ -748,7 +734,7 @@ int asteroid_is_targeted(object *objp)
/**
* Create an asteroid that will hit object *objp in delta_time seconds
*/
void asteroid_aim_at_target(object *objp, object *asteroid_objp, float delta_time)
static void asteroid_aim_at_target(object *objp, object *asteroid_objp, float delta_time)
{
vec3d predicted_center_pos;
vec3d rand_vec;
@@ -776,7 +762,7 @@ void asteroid_aim_at_target(object *objp, object *asteroid_objp, float delta_tim
*
* @param count asteroids already targeted on
*/
void maybe_throw_asteroid(int count)
static void maybe_throw_asteroid(int count)
{
if (!timestamp_elapsed(Next_asteroid_throw)) {
return;
@@ -850,7 +836,7 @@ void asteroid_delete( object * obj )
* See if we should reposition the asteroid.
* Only reposition if oustide the bounding volume and the player isn't looking towards the asteroid.
*/
void asteroid_maybe_reposition(object *objp, asteroid_field *asfieldp)
static void asteroid_maybe_reposition(object *objp, asteroid_field *asfieldp)
{
// passive field does not wrap
if (asfieldp->field_type == FT_PASSIVE) {
@@ -903,7 +889,7 @@ void asteroid_maybe_reposition(object *objp, asteroid_field *asfieldp)
}
}
void lerp(float *goal, float f1, float f2, float scale)
static void lerp(float *goal, float f1, float f2, float scale)
{
*goal = (f2 - f1) * scale + f1;
}
@@ -1207,7 +1193,7 @@ void asteroid_render(object * obj, model_draw_list *scene)
/**
* Create a normalized vector generally in the direction from *hitpos to other_obj->pos
*/
void asc_get_relvec(vec3d *relvec, object *other_obj, vec3d *hitpos)
static void asc_get_relvec(vec3d *relvec, object *other_obj, vec3d *hitpos)
{
vec3d tvec, rand_vec;
int count = 0;
@@ -1229,7 +1215,7 @@ void asc_get_relvec(vec3d *relvec, object *other_obj, vec3d *hitpos)
/**
* Return multiplier on asteroid radius for fireball
*/
float asteroid_get_fireball_scale_multiplier(int num)
static float asteroid_get_fireball_scale_multiplier(int num)
{
if (Asteroids[num].flags & AF_USED) {
asteroid_info *asip = &Asteroid_info[Asteroids[num].asteroid_type];
@@ -1258,7 +1244,7 @@ float asteroid_get_fireball_scale_multiplier(int num)
* Create asteroid explosion
* @return expected time for explosion anim to last, in seconds
*/
float asteroid_create_explosion(object *objp)
static float asteroid_create_explosion(object *objp)
{
int fireball_objnum;
float explosion_life, fireball_scale_multiplier;
@@ -1290,37 +1276,37 @@ float asteroid_create_explosion(object *objp)
/**
* Play sound when asteroid explodes
*/
void asteriod_explode_sound(object *objp, int type, int play_loud)
static void asteroid_explode_sound(object *objp, int type, int play_loud)
{
int sound_index = -1;
gamesnd_id sound_index;
float range_factor = 1.0f; // how many times sound should traver farther than normal
if (type % NUM_DEBRIS_SIZES <= 1)
{
sound_index = SND_ASTEROID_EXPLODE_SMALL;
sound_index = gamesnd_id(GameSounds::ASTEROID_EXPLODE_SMALL);
range_factor = 5.0;
}
else
{
sound_index = SND_ASTEROID_EXPLODE_LARGE;
sound_index = gamesnd_id(GameSounds::ASTEROID_EXPLODE_LARGE);
range_factor = 10.0f;
}
Assert(sound_index != -1);
Assert(sound_index.isValid());
if ( !play_loud ) {
range_factor = 1.0f;
}
snd_play_3d( &Snds[sound_index], &objp->pos, &Eye_position, objp->radius, NULL, 0, 1.0f, SND_PRIORITY_MUST_PLAY, NULL, range_factor );
snd_play_3d( gamesnd_get_game_sound(sound_index), &objp->pos, &Eye_position, objp->radius, NULL, 0, 1.0f, SND_PRIORITY_MUST_PLAY, NULL, range_factor );
}
/**
* Do the area effect for an asteroid exploding
*
* @param asteroid_objp object pointer to asteriod causing explosion
* @param asteroid_objp object pointer to asteroid causing explosion
*/
void asteroid_do_area_effect(object *asteroid_objp)
static void asteroid_do_area_effect(object *asteroid_objp)
{
object *ship_objp;
float damage, blast;
@@ -1382,7 +1368,7 @@ void asteroid_hit( object * pasteroid_obj, object * other_obj, vec3d * hitpos, f
explosion_life = asteroid_create_explosion(pasteroid_obj);
asteriod_explode_sound(pasteroid_obj, asp->asteroid_type, play_loud_collision);
asteroid_explode_sound(pasteroid_obj, asp->asteroid_type, play_loud_collision);
asteroid_do_area_effect(pasteroid_obj);
asp->final_death_time = timestamp( fl2i(explosion_life*1000.0f)/5 ); // Wait till 30% of vclip time before breaking the asteroid up.
@@ -1401,7 +1387,7 @@ void asteroid_hit( object * pasteroid_obj, object * other_obj, vec3d * hitpos, f
weapon_info *wip;
wip = &Weapon_info[Weapons[other_obj->instance].weapon_info_index];
// If the weapon didn't play any impact animation, play custom asteroid impact animation
if ( wip->impact_weapon_expl_effect < 0 ) {
if (!wip->impact_weapon_expl_effect.isValid()) {
particle::create( hitpos, &vmd_zero_vector, 0.0f, Asteroid_impact_explosion_radius, particle::PARTICLE_BITMAP, Asteroid_impact_explosion_ani );
}
}
@@ -1432,35 +1418,6 @@ void asteroid_level_close()
DCF_BOOL2(asteroids, Asteroids_enabled, "enables or disables asteroids", "Usage: asteroids [bool]\nTurns asteroid system on/off. If nothing passed, then toggles it.\n");
void hud_target_asteroid()
{
int i;
int start_index = 0, end_index = MAX_ASTEROIDS;
if (Player_ai->target_objnum != -1) {
if (Objects[Player_ai->target_objnum].type == OBJ_ASTEROID) {
start_index = Objects[Player_ai->target_objnum].instance+1;
end_index = start_index-1;
if (end_index < 0)
end_index = MAX_ASTEROIDS;
}
}
i = start_index;
while (i != end_index) {
if (i == MAX_ASTEROIDS)
i = 0;
if (Asteroids[i].flags & AF_USED) {
Assert(Objects[Asteroids[i].objnum].type == OBJ_ASTEROID);
set_target_objnum( Player_ai, Asteroids[i].objnum);
break;
}
i++;
}
}
/**
* Return the number of active asteroids
*/
@@ -1473,7 +1430,7 @@ int asteroid_count()
* See if asteroid should split up.
* We delay splitting up to allow the explosion animation to play for a bit.
*/
void asteroid_maybe_break_up(object *pasteroid_obj)
static void asteroid_maybe_break_up(object *pasteroid_obj)
{
asteroid *asp;
asteroid_info *asip;
@@ -1595,26 +1552,7 @@ void asteroid_maybe_break_up(object *pasteroid_obj)
}
}
int asteroid_get_random_in_cone(vec3d *pos, vec3d *dir, float ang, int danger)
{
int idx;
vec3d asteroid_dir;
// just pick the first asteroid which satisfies our condition
for(idx=0; idx<Num_asteroids; idx++){
vm_vec_sub(&asteroid_dir, &Objects[Asteroids[idx].objnum].pos, pos);
vm_vec_normalize_quick(&asteroid_dir);
// if it satisfies the condition
if(vm_vec_dot(dir, &asteroid_dir) >= ang){
return idx;
}
}
return -1;
}
void asteroid_test_collide(object *pasteroid_obj, object *pship_obj, mc_info *mc, bool lazy = false)
static void asteroid_test_collide(object *pasteroid_obj, object *pship_obj, mc_info *mc, bool lazy = false)
{
float asteroid_ray_dist;
vec3d asteroid_fvec, terminus;
@@ -1656,7 +1594,7 @@ void asteroid_test_collide(object *pasteroid_obj, object *pship_obj, mc_info *mc
*
* @return !0 if the asteroid will collide with the escort
*/
int asteroid_will_collide(object *pasteroid_obj, object *escort_objp)
static int asteroid_will_collide(object *pasteroid_obj, object *escort_objp)
{
mc_info mc;
mc_info_init(&mc);
@@ -1674,7 +1612,7 @@ int asteroid_will_collide(object *pasteroid_obj, object *escort_objp)
* Warn if asteroid on collision path with ship
* @return !0 if we should warn about asteroid hitting ship, otherwise return 0
*/
int asteroid_valid_ship_to_warn_collide(ship *shipp)
static int asteroid_valid_ship_to_warn_collide(ship *shipp)
{
if ( !(Ship_info[shipp->ship_info_index].is_big_or_huge()) ) {
return 0;
@@ -1696,7 +1634,7 @@ int asteroid_valid_ship_to_warn_collide(ship *shipp)
* See if asteroid will collide with a large ship on the escort list in the next
* ASTEROID_MIN_COLLIDE_TIME seconds.
*/
void asteroid_update_collide_flag(object *asteroid_objp)
static void asteroid_update_collide_flag(object *asteroid_objp)
{
int i, num_escorts, escort_objnum, will_collide=0;
ship *escort_shipp;
@@ -1735,7 +1673,7 @@ void asteroid_update_collide_flag(object *asteroid_objp)
/**
* Ensure that the collide objnum for the asteroid is still valid
*/
void asteroid_verify_collide_objnum(asteroid *asp)
static void asteroid_verify_collide_objnum(asteroid *asp)
{
if ( asp->collide_objnum >= 0 ) {
if ( Objects[asp->collide_objnum].signature != asp->collide_objsig ) {
@@ -1815,7 +1753,7 @@ float asteroid_time_to_impact(object *asteroid_objp)
/**
* Read in a single asteroid section from asteroid.tbl
*/
void asteroid_parse_section(asteroid_info *asip)
static void asteroid_parse_section(asteroid_info *asip)
{
required_string("$Name:");
stuff_string(asip->name, F_NAME, NAME_LENGTH);
@@ -1915,7 +1853,7 @@ to do with the debris of ships that explode, however these
are the same debris and asteroids that get flung at a ship
that is being protected.
*/
void asteroid_parse_tbl()
static void asteroid_parse_tbl()
{
char impact_ani_file[MAX_FILENAME_LEN];
@@ -2066,7 +2004,7 @@ void asteroid_parse_tbl()
/**
* Return number of asteroids expected to collide with a ship.
*/
int count_incident_asteroids()
static int count_incident_asteroids()
{
object *asteroid_objp;
int count;
@@ -2090,7 +2028,7 @@ int count_incident_asteroids()
* Pick object to throw asteroids at.
* Pick any capital or big ship inside the bounds of the asteroid field.
*/
int set_asteroid_throw_objnum()
static int set_asteroid_throw_objnum()
{
if (Asteroid_field.num_initial_asteroids < 1)
return -1;
-1
View File
@@ -163,7 +163,6 @@ int asteroid_collide_objnum(object *asteroid_objp);
float asteroid_time_to_impact(object *asteroid_objp);
void asteroid_show_brackets();
void asteroid_target_closest_danger();
int asteroid_get_random_in_cone(vec3d *pos, vec3d *dir, float ang, int danger = 0);
// need to extern for multiplayer
void asteroid_sub_create(object *parent_objp, int asteroid_type, vec3d *relvec);
+2 -2
View File
@@ -1231,7 +1231,7 @@ void send_autopilot_msg(char *msg, char *snd)
audio_handle = -1;
}
if (msg[0] != '\0' && strcmp(msg, "none"))
if (msg[0] != '\0' && strcmp(msg, "none") != 0)
change_message("autopilot builtin message", msg, -1, 0);
// load sound
@@ -1246,7 +1246,7 @@ void send_autopilot_msg(char *msg, char *snd)
audiostream_play(audio_handle, (Master_event_music_volume * aav_music_volume), 0);
}
if (msg[0] != '\0' && strcmp(msg, "none"))
if (msg[0] != '\0' && strcmp(msg, "none") != 0)
message_training_queue("autopilot builtin message", timestamp(0), 5); // display message for five seconds
}
+38 -9
View File
@@ -23,6 +23,16 @@
#include "bmpman/bmpman.h"
#include <array>
/**
* @brief Container class for graphics API specific bitmap data
*/
class gr_bitmap_info {
public:
virtual ~gr_bitmap_info() = 0;
};
union bm_extra_info {
struct {
// Stuff needed for animations
@@ -31,6 +41,7 @@ union bm_extra_info {
int keyframe; //!< used for animations -- keyframe info
float total_time; //!< used for animations -- total animation time (not always derived from num_frames/fps)
ubyte fps; //!< used for animations -- frames per second
bool is_array; //!< Flag for if all frames of an animation have the same size which means that it can be put into a texture array
struct {
// stuff for static animations
@@ -89,17 +100,35 @@ struct bitmap_entry {
#endif
};
extern bitmap_entry bm_bitmaps[MAX_BITMAPS];
struct bitmap_slot {
bitmap_entry entry;
gr_bitmap_info* gr_info = nullptr;
};
// image specific lock functions
void bm_lock_ani( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
void bm_lock_dds( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
void bm_lock_png( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
void bm_lock_apng( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
void bm_lock_jpg( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
void bm_lock_pcx( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
void bm_lock_tga( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
void bm_lock_user( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
void bm_lock_ani( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags );
void bm_lock_dds( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags );
void bm_lock_png( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags );
void bm_lock_apng( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags );
void bm_lock_jpg( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags );
void bm_lock_pcx( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags );
void bm_lock_tga( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags );
void bm_lock_user( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags );
const size_t BM_BLOCK_SIZE = 4096;
extern SCP_vector<std::array<bitmap_slot, BM_BLOCK_SIZE>> bm_blocks;
bitmap_slot* bm_get_slot(int handle, bool separate_ani_frames = true);
inline bitmap_entry* bm_get_entry(int handle, bool separate_ani_frames = true) {
return &bm_get_slot(handle, separate_ani_frames)->entry;
}
template<typename T>
T* bm_get_gr_info(int handle, bool separate_ani_frames = true) {
return static_cast<T*>(bm_get_slot(handle, separate_ani_frames)->gr_info);
}
#endif // __BM_INTERNAL_H__
+889 -732
View File
File diff suppressed because it is too large. Load diff
+74 -47
View File
@@ -32,21 +32,6 @@
* @{
*/
/**
* @brief How many bitmaps the game can handle
*
* @attention MAX_BITMAPS shouldn't need to be bumped again. With the fixed bm_release() and it's proper use even the
* largest missions should stay under this number. With the largest retail missions and wasteful content we should
* still have about 20% of the slots free. If it still goes over then it's something the artists need to fix.
* For instance the Terran Mara fighter, with -spec and -glow and using the Shinepack, needs 117 bitmap slots alone.
* 111 of those is just for the glowmaps. This number can be greatly reduced if the number of ani frames for another
* LOD than LOD0 has fewer or no ani frames. A 37 frame glow ani for LOD2 is little more than a waste of resources.
* Future reports of texture corruption should be initially approached with content as the cause and not code.
* If anything we could/should reduce MAX_BITMAPS in the future. Where it's at now should accomidate even the
* largest mods. -- Taylor
*/
#define MAX_BITMAPS 4750
// Flag positions for bitmap.flags
// ***** NOTE: bitmap.flags is an 8-bit value, no more BMP_TEX_* flags can be added unless the type is changed!! ******
#define BMP_AABITMAP (1<<0) //!< antialiased bitmap
@@ -56,6 +41,7 @@
#define BMP_TEX_DXT3 (1<<4) //!< dxt3 compressed 8r8g8b4a (32bit)
#define BMP_TEX_DXT5 (1<<5) //!< dxt5 compressed 8r8g8b8a (32bit)
#define BMP_TEX_CUBEMAP (1<<6) //!< a texture made for cubic environment map
#define BMP_MASK_BITMAP (1<<7) //!< a bitmap that will be used for masking mouse interaction. Typically not used in render operations
// Combined flags
#define BMP_TEX_COMP ( BMP_TEX_DXT1 | BMP_TEX_DXT3 | BMP_TEX_DXT5 ) //!< Compressed textures
@@ -112,6 +98,10 @@ struct bitmap
*/
};
// Forward definition for the graphics API
struct bitmap_entry;
struct bitmap_slot;
extern size_t bm_texture_ram; //!< how many bytes of textures are used.
extern int Bm_paging; //!< Bool type that indicates if BMPMAN is currently paging.
@@ -140,22 +130,6 @@ void bm_init();
*/
void bm_close();
/**
* Gets the cache slot of the bitmap indexed by handle.
*
* @details if the bitmap is an ani, gets the first frame
*
* @returns The cache slot index of the bitmap if handle is valid
*
* @note If the handle is invalid, an Assert() fails
*/
int bm_get_cache_slot(int bitmap_id, int separate_ani_frames);
/**
* @brief Gets the next available bitmap slot.
*/
int bm_get_next_handle();
#define BMP_FLAG_RENDER_TARGET_STATIC (1<<0)
#define BMP_FLAG_RENDER_TARGET_DYNAMIC (1<<1)
#define BMP_FLAG_CUBEMAP (1<<2)
@@ -409,13 +383,6 @@ void bm_get_filename(int bitmapnum, char *filename);
*/
const char *bm_get_filename(int handle);
/**
* @brief Loads all data for all bitmaps that have been requested to be loaded
*
* @note This function is not defined.
*/
void bm_gfx_load_all();
/**
* @brief Unloads all used bitmaps, should only ever be called by game_shutdown()
*
@@ -434,15 +401,6 @@ void bm_unload_all();
*/
void bm_get_palette(int handle, ubyte *pal, char *name);
/**
* @brief Hack to get a pixel from a bitmap
*
* @details only works good in 8bpp mode
*
* @note This function is not defined.
*/
void bm_gfx_get_pixel(int bitmap, float u, float v, ubyte *r, ubyte *g, ubyte *b);
/**
* @brief (DEBUG) Gets memory size, in bytes, of the locked bitmaps
*
@@ -698,4 +656,73 @@ bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int
*/
int bm_get_anim_frame(const int frame1_handle, float elapsed_time, const float divisor = 0.0f, const bool loop = false);
/**
* @brief Determines if the given handle could be used in a texture array
*
* @param handle The handle to query the value for
* @return @c true if all frames have the same size, @c false otherwise. Always returns @c true for single images
*/
bool bm_is_texture_array(const int handle);
/**
* @brief Gets the base frame of the specified animation
*
* @details The base frame is the frame of the animation that should be used to determine if two animation frames can be
* used in the same draw call. Use this if you want to optimize your draw calls to make use of texture arrays.
*
* @param handle The handle of the animation to check. This may also be a single frame bitmap
* @param num_frames Optionally return the number of frames in the animation
* @return The bitmap handle of the base frame or -1 on error
*/
int bm_get_base_frame(const int handle, int* num_frames = nullptr);
/**
* @brief Get the array index of the specified bitmap
*
* This should be used when passing the array index to the GPU (e.g. when building uniform structs or streaming particle
* data)
*
* @param handle The handle of the bitmap
* @return The index into the array
*/
int bm_get_array_index(const int handle);
/**
* @brief Counts how many slots are used in bm_bitmaps
*
* This needs to iterate through all the slots in order to determine whether or not they're used, so shouldn't be used frivolously.
*
* @return The number of used slots
*/
int bmpman_count_bitmaps();
/**
* @brief Counts how many slots are available to the bmpman system
*
* Since the number of slots is dynamic now, this should be used for determining the total amount of available slots at
* the moment.
*
* @warning This is entirely for debugging and logging purposes. It should not be used in actual engine code.
*
* @return The number of available slots
*/
int bmpman_count_available_slots();
/**
* @brief Checks if the given filename is a valid effect or texture file name
*
* @note At least one of @c single_frame or @c animation must be true since the result would make no sense otherwise. It
* is also valid to set both parmeters to @c true.
*
* @todo This currently just tries to load the file but could be improved by not actually loading the file in the future.
*
* @param file The file name to check
* @param single_frame If set to @c true then single frames are valid files
* @param animation If set to @c true then animations are valid files
* @return @c true if the file name is valid, @c false otherwise
*/
bool bm_validate_filename(const SCP_string& file, bool single_frame, bool animation);
SDL_Surface* bm_to_sdl_surface(int handle);
#endif
+4 -4
View File
@@ -2,7 +2,7 @@
#include "globalincs/alphacolors.h"
#include "globalincs/linklist.h"
#include "globalincs/systemvars.h" //VM_FREECAMERA etc
#include "graphics/font.h"
#include "graphics/matrix.h"
#include "hud/hud.h" //hud_get_draw
#include "math/vecmat.h"
#include "mod_table/mod_table.h"
@@ -245,12 +245,12 @@ void camera::set_rotation_facing(vec3d *in_target, float in_rotation_time, float
set_rotation(&temp_matrix, in_rotation_time, in_rotation_acceleration_time, in_rotation_deceleration_time);
}
void camera::set_rotation_velocity(angles *in_rotation_rate, float in_acceleration_time)
void camera::set_rotation_velocity(angles * /*in_rotation_rate*/, float /*in_acceleration_time*/)
{
Error(LOCATION, "This function is disabled until further notice.");
}
void camera::do_frame(float in_frametime)
void camera::do_frame(float /*in_frametime*/)
{
}
@@ -802,7 +802,7 @@ void subtitle::clone(const subtitle &sub)
post_shaded = sub.post_shaded;
}
const subtitle &subtitle::operator=(const subtitle &sub)
subtitle& subtitle::operator=(const subtitle &sub)
{
if (this != &sub) {
if (image_id != -1) {
+1 -1
View File
@@ -143,7 +143,7 @@ public:
~subtitle();
subtitle(const subtitle &sub) { clone(sub); }
const subtitle &operator=(const subtitle &sub);
subtitle& operator=(const subtitle &sub);
void do_frame(float frametime);
bool is_post_shaded( ) { return post_shaded; }
+106 -80
View File
@@ -10,10 +10,10 @@
#define _CFILE_INTERNAL
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cerrno>
#include <sys/stat.h>
#ifdef _WIN32
@@ -33,21 +33,21 @@
#include "cfile/cfilesystem.h"
#include "osapi/osapi.h"
#include "parse/encrypt.h"
#include "cfilesystem.h"
#include <limits>
char Cfile_root_dir[CFILE_ROOT_DIRECTORY_LEN] = "";
char Cfile_user_dir[CFILE_ROOT_DIRECTORY_LEN] = "";
#ifdef SCP_UNIX
char Cfile_user_dir_legacy[CFILE_ROOT_DIRECTORY_LEN] = "";
#endif
// During cfile_init, verify that Pathtypes[n].index == n for each item
// Each path must have a valid parent that can be tracable all the way back to the root
// Each path must have a valid parent that can be tracable all the way back to the root
// so that we can create directories when we need to.
//
// Please make sure extensions are all lower-case, or we'll break unix compatibility
//
// clang-format off
cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
// What type this is Path Extensions Parent type
{ CF_TYPE_INVALID, NULL, NULL, CF_TYPE_INVALID },
@@ -69,7 +69,7 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
{ CF_TYPE_VOICE_SPECIAL, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "special", ".wav .ogg", CF_TYPE_VOICE },
{ CF_TYPE_VOICE_TRAINING, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "training", ".wav .ogg", CF_TYPE_VOICE },
{ CF_TYPE_MUSIC, "data" DIR_SEPARATOR_STR "music", ".wav .ogg", CF_TYPE_DATA },
{ CF_TYPE_MOVIES, "data" DIR_SEPARATOR_STR "movies", ".mve .msb .ogg .mp4", CF_TYPE_DATA },
{ CF_TYPE_MOVIES, "data" DIR_SEPARATOR_STR "movies", ".mve .msb .ogg .mp4 .srt .webm .png",CF_TYPE_DATA },
{ CF_TYPE_INTERFACE, "data" DIR_SEPARATOR_STR "interface", ".pcx .ani .dds .tga .eff .png .jpg", CF_TYPE_DATA },
{ CF_TYPE_FONT, "data" DIR_SEPARATOR_STR "fonts", ".vf .ttf", CF_TYPE_DATA },
{ CF_TYPE_EFFECTS, "data" DIR_SEPARATOR_STR "effects", ".ani .eff .pcx .neb .tga .jpg .png .dds .sdr", CF_TYPE_DATA },
@@ -88,8 +88,9 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
{ CF_TYPE_INTEL_ANIMS, "data" DIR_SEPARATOR_STR "intelanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
{ CF_TYPE_SCRIPTS, "data" DIR_SEPARATOR_STR "scripts", ".lua .lc", CF_TYPE_DATA },
{ CF_TYPE_FICTION, "data" DIR_SEPARATOR_STR "fiction", ".txt", CF_TYPE_DATA },
{ CF_TYPE_FREDDOCS, "data" DIR_SEPARATOR_STR "freddocs", ".html", CF_TYPE_DATA },
};
// clang-format on
#define CFILE_STACK_MAX 8
@@ -109,6 +110,7 @@ static const char *Cfile_cdrom_dir = NULL;
static int cfget_cfile_block();
static CFILE *cf_open_fill_cfblock(const char* source, int line, FILE * fp, int type);
static CFILE *cf_open_packed_cfblock(const char* source, int line, FILE *fp, int type, size_t offset, size_t size);
static CFILE *cf_open_memory_fill_cfblock(const char* source, int line, const void* data, size_t size, int dir_type);
#if defined _WIN32
static CFILE *cf_open_mapped_fill_cfblock(const char* source, int line, HANDLE hFile, int type);
@@ -222,14 +224,8 @@ int cfile_init(const char *exe_dir, const char *cdrom_dir)
cfile_chdir(buf);
// set root directory
strncpy(Cfile_root_dir, buf, CFILE_ROOT_DIRECTORY_LEN-1);
strncpy(Cfile_user_dir, os_get_config_path().c_str(), CFILE_ROOT_DIRECTORY_LEN-1);
#ifdef SCP_UNIX
// Initialize path of old pilot files
extern const char* Osreg_user_dir_legacy;
snprintf(Cfile_user_dir_legacy, CFILE_ROOT_DIRECTORY_LEN-1, "%s/%s/", getenv("HOME"), Osreg_user_dir_legacy);
#endif
strcpy_s(Cfile_root_dir, buf);
strcpy_s(Cfile_user_dir, os_get_config_path().c_str());
for (i = 0; i < MAX_CFILE_BLOCKS; i++) {
Cfile_block_list[i].type = CFILE_BLOCK_UNUSED;
@@ -354,8 +350,7 @@ int cfile_push_chdir(int type)
return -1;
}
strncpy(Cfile_stack[Cfile_stack_pos++], OriginalDirectory,
CFILE_ROOT_DIRECTORY_LEN - 1);
strcpy_s(Cfile_stack[Cfile_stack_pos++], OriginalDirectory);
cf_create_default_path_string(dir, sizeof(dir) - 1, type, NULL);
@@ -465,7 +460,7 @@ char *cf_add_ext(const char *filename, const char *ext)
size_t elen = strlen(ext);
Assert(flen < MAX_PATH_LEN);
strcpy_s(path, filename);
if ((flen < 4) || stricmp(path + flen - elen, ext)) {
if ((flen < 4) || stricmp(path + flen - elen, ext) != 0) {
Assert(flen + elen < MAX_PATH_LEN);
strcat_s(path, ext);
}
@@ -478,17 +473,17 @@ char *cf_add_ext(const char *filename, const char *ext)
*
* @param filename Name of file to delete
* @param path_type Path type (CF_TYPE_xxx)
* @param location_flags Where to search for the location of the file to delete
*
* @return 0 on failure, 1 on success
*/
int cf_delete(const char *filename, int path_type)
int cf_delete(const char *filename, int path_type, uint32_t location_flags)
{
char longname[MAX_PATH_LEN];
Assert(CF_TYPE_SPECIFIED(path_type));
cf_create_default_path_string(longname, sizeof(longname) - 1,
path_type, filename);
cf_create_default_path_string(longname, sizeof(longname) - 1, path_type, filename, false, location_flags);
return (_unlink(longname) != -1);
}
@@ -514,12 +509,12 @@ int cf_access(const char *filename, int dir_type, int mode)
// If offset equates to boolean true, it was found in a VP and the logic will negate the function return
int cf_exists(const char *filename, int dir_type)
{
size_t offset = 1;
if ( (filename == NULL) || !strlen(filename) )
return 0;
return (cf_find_file_location(filename, dir_type, 0, NULL, NULL, &offset) && !offset);
auto find_res = cf_find_file_location(filename, dir_type);
return find_res.found && !find_res.offset;
}
// Goober5000
@@ -530,7 +525,7 @@ int cf_exists_full(const char *filename, int dir_type)
if ( (filename == NULL) || !strlen(filename) )
return 0;
return cf_find_file_location(filename, dir_type, 0, NULL, NULL, NULL);
return cf_find_file_location(filename, dir_type).found;
}
// same as the above, but with extension check
@@ -542,7 +537,7 @@ int cf_exists_full_ext(const char *filename, int dir_type, const int num_ext, co
if ( (num_ext <= 0) || (ext_list == NULL) )
return 0;
return (cf_find_file_location_ext(filename, num_ext, ext_list, dir_type, 0, NULL, NULL, NULL) != -1);
return cf_find_file_location_ext(filename, num_ext, ext_list, dir_type).found;
}
#ifdef _WIN32
@@ -559,7 +554,7 @@ void cf_attrib(const char *filename, int set, int clear, int dir_type)
fclose(fp);
DWORD z = GetFileAttributes(longname);
SetFileAttributes(longname, z | set & ~clear);
SetFileAttributes(longname, z | (set & ~clear));
}
}
@@ -616,7 +611,7 @@ static void mkdir_recursive(const char *path) {
// Creates the directory path if it doesn't exist. Even creates all its
// parent paths.
void cf_create_directory( int dir_type )
void cf_create_directory(int dir_type, uint32_t location_flags)
{
int num_dirs = 0;
int dir_tree[CF_MAX_PATH_TYPES];
@@ -638,7 +633,7 @@ void cf_create_directory( int dir_type )
int i;
for (i=num_dirs-1; i>=0; i-- ) {
cf_create_default_path_string( longname, sizeof(longname)-1, dir_tree[i], NULL );
cf_create_default_path_string(longname, sizeof(longname) - 1, dir_tree[i], nullptr, false, location_flags);
if (stat(longname, &statbuf) != 0) {
mprintf(( "CFILE: Creating new directory '%s'\n", longname ));
mkdir_recursive(longname);
@@ -665,14 +660,13 @@ extern int game_cd_changed();
// error ==> NULL
//
CFILE *_cfopen(const char* source, int line, const char *file_path, const char *mode, int type, int dir_type, bool localize)
CFILE* _cfopen(const char* source, int line, const char* file_path, const char* mode, int type, int dir_type,
bool localize, uint32_t location_flags)
{
/* Bobboau, what is this doing here? 31 is way too short... - Goober5000
if( strlen(file_path) > 31 )
Error(LOCATION, "file name %s too long, \nmust be less than 31 charicters", file_path);*/
char longname[_MAX_PATH];
if ( !cfile_inited ) {
Int3();
return NULL;
@@ -684,7 +678,7 @@ CFILE *_cfopen(const char* source, int line, const char *file_path, const char *
Assert( mode != NULL );
// Can only open read-only binary files in memory mapped mode.
if ( (type & CFILE_MEMORY_MAPPED) && strcmp(mode,"rb") ) {
if ( (type & CFILE_MEMORY_MAPPED) && strcmp(mode,"rb") != 0 ) {
Int3();
return NULL;
}
@@ -694,6 +688,8 @@ CFILE *_cfopen(const char* source, int line, const char *file_path, const char *
// the harddisk. No fancy packfile stuff here!
if ( strchr(mode,'w') || strchr(mode,'+') || strchr(mode,'a') ) {
char longname[_MAX_PATH];
// For write-only files, require a full path or a path type
#ifdef SCP_UNIX
if ( strpbrk(file_path, "/") ) {
@@ -707,9 +703,9 @@ CFILE *_cfopen(const char* source, int line, const char *file_path, const char *
Assert( dir_type != CF_TYPE_ANY );
// Create the directory if necessary
cf_create_directory( dir_type );
cf_create_directory(dir_type, location_flags);
cf_create_default_path_string( longname, sizeof(longname)-1, dir_type, file_path );
cf_create_default_path_string(longname, sizeof(longname) - 1, dir_type, file_path, false, location_flags);
}
Assert( !(type & CFILE_MEMORY_MAPPED) );
@@ -759,30 +755,29 @@ CFILE *_cfopen(const char* source, int line, const char *file_path, const char *
//================================================
// Search for file on disk, on cdrom, or in a packfile
size_t offset, size;
char copy_file_path[MAX_PATH_LEN]; // FIX change in memory from cf_find_file_location
strcpy_s(copy_file_path, file_path);
if ( cf_find_file_location( copy_file_path, dir_type, sizeof(longname) - 1, longname, &size, &offset, localize ) ) {
auto find_res = cf_find_file_location( copy_file_path, dir_type, localize, location_flags );
if ( find_res.found ) {
// Fount it, now create a cfile out of it
nprintf(("CFileDebug", "Requested file %s found at: %s\n", file_path, longname));
nprintf(("CFileDebug", "Requested file %s found at: %s\n", file_path, find_res.full_name.c_str()));
if ( type & CFILE_MEMORY_MAPPED ) {
// Can't open memory mapped files out of pack files
if ( offset == 0 ) {
// Can't open memory mapped files out of pack or memory files
if ( find_res.offset == 0 && find_res.data_ptr != nullptr ) {
#if defined _WIN32
HANDLE hFile;
hFile = CreateFile(longname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
hFile = CreateFile(find_res.full_name.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
return cf_open_mapped_fill_cfblock(source, line, hFile, dir_type);
}
#elif defined SCP_UNIX
FILE *fp = fopen( longname, "rb" );
FILE* fp = fopen(find_res.full_name.c_str(), "rb");
if (fp) {
return cf_open_mapped_fill_cfblock(source, line, fp, dir_type);
}
@@ -790,18 +785,9 @@ CFILE *_cfopen(const char* source, int line, const char *file_path, const char *
}
} else {
FILE *fp = fopen( longname, "rb" );
if ( fp ) {
if ( offset ) {
// Found it in a pack file
return cf_open_packed_cfblock(source, line, fp, dir_type, offset, size );
} else {
// Found it in a normal file
return cf_open_fill_cfblock(source, line, fp, dir_type);
}
}
// since cfopen_special already has all the code to handle the opening we can just use that here
return _cfopen_special(source, line, find_res.full_name.c_str(), mode, find_res.size, find_res.offset,
find_res.data_ptr, dir_type);
}
}
@@ -820,7 +806,7 @@ CFILE *_cfopen(const char* source, int line, const char *file_path, const char *
// returns: success ==> address of CFILE structure
// error ==> NULL
//
CFILE *_cfopen_special(const char* source, int line, const char *file_path, const char *mode, const size_t size, const size_t offset, int dir_type)
CFILE *_cfopen_special(const char* source, int line, const char *file_path, const char *mode, const size_t size, const size_t offset, const void* data, int dir_type)
{
if ( !cfile_inited) {
Int3();
@@ -836,19 +822,27 @@ CFILE *_cfopen_special(const char* source, int line, const char *file_path, cons
return NULL;
}
// "file_path" should already be a fully qualified path, so just try to open it
FILE *fp = fopen( file_path, "rb" );
if ( !fp )
return NULL;
if ( offset ) {
// it's in a pack file
return cf_open_packed_cfblock(source, line, fp, dir_type, offset, size);
} else {
// it's a normal file
return cf_open_fill_cfblock(source, line, fp, dir_type);
// In-Memory files are a bit different from normal files so we need to handle them separately
if (data != nullptr) {
return cf_open_memory_fill_cfblock(source, line, data, size, dir_type);
}
else {
// "file_path" should already be a fully qualified path, so just try to open it
FILE *fp = fopen(file_path, "rb");
if (fp) {
if (offset) {
// Found it in a pack file
return cf_open_packed_cfblock(source, line, fp, dir_type, offset, size);
}
else {
// Found it in a normal file
return cf_open_fill_cfblock(source, line, fp, dir_type);
}
}
}
return NULL;
}
@@ -901,7 +895,7 @@ static int cfget_cfile_block()
mprintf(("Out of cfile blocks! Currently opened files:\n"));
dump_opened_files();
Assertion(false, "There are no more free cfile blocks. This means that there are too many files opened by FSO.\n"
UNREACHABLE("There are no more free cfile blocks. This means that there are too many files opened by FSO.\n"
"This is probably caused by a programming or scripting error where a file does not get closed."); // out of free cfile blocks
return -1;
}
@@ -922,7 +916,7 @@ int cfclose( CFILE * cfile )
cb = &Cfile_block_list[cfile->id];
result = 0;
if ( cb->data ) {
if ( cb->data && cb->mem_mapped ) {
// close memory mapped file
#if defined _WIN32
result = UnmapViewOfFile((void*)cb->data);
@@ -936,7 +930,8 @@ int cfclose( CFILE * cfile )
// FIXME: result is wrong after munmap() but it is successful
//result = munmap(cb->data, cb->data_length);
//Assert(result);
munmap(cb->data, cb->data_length);
// This const_cast is safe since the pointer returned by mmap was also non-const
munmap(const_cast<void*>(cb->data), cb->data_length);
if ( cb->fp != NULL)
result = fclose(cb->fp);
#endif
@@ -996,6 +991,7 @@ static CFILE *cf_open_fill_cfblock(const char* source, int line, FILE *fp, int t
cfp->id = cfile_block_index;
cfp->version = 0;
cfbp->data = NULL;
cfbp->mem_mapped = false;
cfbp->fp = fp;
cfbp->dir_type = type;
cfbp->max_read_len = 0;
@@ -1038,6 +1034,7 @@ static CFILE *cf_open_packed_cfblock(const char* source, int line, FILE *fp, int
cfp->version = 0;
cfbp->data = NULL;
cfbp->fp = fp;
cfbp->mem_mapped = false;
cfbp->dir_type = type;
cfbp->max_read_len = 0;
@@ -1083,6 +1080,7 @@ static CFILE *cf_open_mapped_fill_cfblock(const char* source, int line, FILE *fp
cfp->version = 0;
cfbp->max_read_len = 0;
cfbp->fp = NULL;
cfbp->mem_mapped = true;
#if defined _WIN32
cfbp->hInFile = hFile;
#endif
@@ -1117,6 +1115,37 @@ static CFILE *cf_open_mapped_fill_cfblock(const char* source, int line, FILE *fp
}
}
static CFILE *cf_open_memory_fill_cfblock(const char* source, int line, const void* data, size_t size, int dir_type)
{
int cfile_block_index;
cfile_block_index = cfget_cfile_block();
if ( cfile_block_index == -1 ) {
return NULL;
}
else {
CFILE *cfp;
Cfile_block *cfbp;
cfbp = &Cfile_block_list[cfile_block_index];
cfp = &Cfile_list[cfile_block_index];
cfp->id = cfile_block_index;
cfp->version = 0;
cfbp->max_read_len = 0;
cfbp->fp = NULL;
cfbp->mem_mapped = false;
cfbp->dir_type = dir_type;
cfbp->source_file = source;
cfbp->line_num = line;
cf_init_lowlevel_read_code(cfp, 0, size, 0 );
cfbp->data = data;
return cfp;
}
}
int cf_get_dir_type(CFILE *cfile)
{
return Cfile_block_list[cfile->id].dir_type;
@@ -1127,7 +1156,7 @@ int cf_get_dir_type(CFILE *cfile)
//
//
void *cf_returndata(CFILE *cfile)
const void *cf_returndata(CFILE *cfile)
{
Assert(cfile != NULL);
Cfile_block *cb;
@@ -1418,9 +1447,7 @@ int cfilelength( CFILE * cfile )
cb = &Cfile_block_list[cfile->id];
// TODO: return length of memory mapped file
Assert( !cb->data );
Assert(cb->fp != NULL);
Assert( !cb->mem_mapped );
// cb->size gets set at cfopen
@@ -1519,7 +1546,6 @@ int cfputc(int c, CFILE *cfile)
return result;
}
// cfputs() writes a string to a file
//
// returns: success ==> non-negative value
+101 -24
View File
@@ -13,7 +13,7 @@
#define __CFILE_H__
#include <time.h>
#include <ctime>
#include "globalincs/pstypes.h"
#include <stdexcept>
@@ -78,8 +78,9 @@ typedef struct {
#define CF_TYPE_INTEL_ANIMS 34
#define CF_TYPE_SCRIPTS 35
#define CF_TYPE_FICTION 36
#define CF_TYPE_FREDDOCS 37
#define CF_MAX_PATH_TYPES 37 // Can be as high as you'd like //DTP; yeah but beware alot of things uses CF_MAX_PATH_TYPES
#define CF_MAX_PATH_TYPES 38 // Can be as high as you'd like //DTP; yeah but beware alot of things uses CF_MAX_PATH_TYPES
// TRUE if type is specified and valid
@@ -94,6 +95,64 @@ typedef struct {
#define CF_SORT_TIME 2
#define CF_SORT_REVERSE 3
/**
* @brief Contains a collection of flags for specifying from where a CFILE should be opened
*
* There are two types of flags. CF_LOCATION_GAME_ROOT and CF_LOCATION_USER_ROOT specify in which basic root directory
* CFile should search for files.
*
* The remaining flags control what type of location may be used for the operation. It's possible to restrict the
* location to the primary mod, the remaining mods or the top-level root directory.
*/
enum CFileLocationFlags {
CF_LOCATION_ROOT_GAME = 1 << 0, //!< The game root location. This is the location of the game data (e.g. FS2 retail)
/**
* @brief The user directories.
*
* If the engine is in portable mode then using this flag exclusively will result in a failure to open files!
*/
CF_LOCATION_ROOT_USER = 1 << 1,
/**
* @brief The memory root
*
* This contains all the built-in files available to the engine.
*/
CF_LOCATION_ROOT_MEMORY = 1 << 2,
/**
* @brief Mask for extracting root type from a location bit field
*/
CF_LOCATION_ROOT_MASK = 0xFFFF,
CF_LOCATION_TYPE_ROOT = 1 << 16, //!< The basic, top-level root location
/**
* @brief The primary mod location.
*
* This is the mod that appears first on the command line. If there are no mods then the root location is considered
* to be the primary mod
*/
CF_LOCATION_TYPE_PRIMARY_MOD = 1 << 17,
/**
* @brief The remaining mods.
*
* If there are no mods on the command line then this might not include any valid location.
*/
CF_LOCATION_TYPE_SECONDARY_MODS = 1 << 18,
/**
* @brief Bitmask for extracting the type from a location bit field
*/
CF_LOCATION_TYPE_MASK = 0xFFFF0000,
/**
* @brief A combination of all flags
*
* This should be used when the default behavior without any location filtering is desired.
*/
CF_LOCATION_ALL = CF_LOCATION_ROOT_MASK | CF_LOCATION_TYPE_MASK
};
#define cfread_fix(file) (fix)cfread_int(file)
#define cfwrite_fix(i,file) cfwrite_int(i,file)
@@ -110,9 +169,6 @@ extern const char *Get_file_list_child;
#define CFILE_ROOT_DIRECTORY_LEN 256
extern char Cfile_root_dir[CFILE_ROOT_DIRECTORY_LEN];
extern char Cfile_user_dir[CFILE_ROOT_DIRECTORY_LEN];
#ifdef SCP_UNIX
extern char Cfile_user_dir_legacy[CFILE_ROOT_DIRECTORY_LEN];
#endif
//================= LOW-LEVEL FUNCTIONS ==================
int cfile_init(const char *exe_dir, const char *cdrom_dir=NULL);
@@ -129,17 +185,16 @@ char *cf_add_ext(const char *filename, const char *ext);
// return CF_TYPE (directory location type) of a CFILE you called cfopen() successfully on.
int cf_get_dir_type(CFILE *cfile);
// Opens the file. If no path is given, use the extension to look into the
// default path. If mode is NULL, delete the file.
CFILE *_cfopen(const char* source_file, int line, const char *filename, const char *mode,
int type = CFILE_NORMAL, int dir_type = CF_TYPE_ANY, bool localize = false);
// default path. If mode is NULL, delete the file.
CFILE* _cfopen(const char* source_file, int line, const char* filename, const char* mode, int type = CFILE_NORMAL,
int dir_type = CF_TYPE_ANY, bool localize = false, uint32_t location_flags = CF_LOCATION_ALL);
#define cfopen(...) _cfopen(LOCATION, __VA_ARGS__) // Pass source location to the function
// like cfopen(), but it accepts a fully qualified path only (ie, the result of a cf_find_file_location() call)
// NOTE: only supports reading files!!
CFILE *_cfopen_special(const char* source_file, int line, const char *file_path, const char *mode,
const size_t size, const size_t offset, int dir_type = CF_TYPE_ANY);
const size_t size, const size_t offset, const void* data, int dir_type = CF_TYPE_ANY);
#define cfopen_special(...) _cfopen_special(LOCATION, __VA_ARGS__) // Pass source location to the function
// Flush the open file buffer
@@ -155,7 +210,7 @@ void cf_set_version( CFILE * cfile, int version );
void cf_set_max_read_len(CFILE *cfile, size_t len);
// Deletes a file. Returns 0 on error, 1 if successful
int cf_delete(const char *filename, int dir_type);
int cf_delete(const char *filename, int dir_type, uint32_t location_flags = CF_LOCATION_ALL);
// Same as _access function to read a file's access bits
int cf_access(const char *filename, int dir_type, int mode);
@@ -215,7 +270,7 @@ char *cfgets(char *buf, int n, CFILE *cfile);
int cfeof(CFILE *cfile);
// Return the data pointer associated with the CFILE structure (for memory mapped files)
void *cf_returndata(CFILE *cfile);
const void *cf_returndata(CFILE *cfile);
// get the 2 byte checksum of the passed filename - return 0 if operation failed, 1 if succeeded
int cf_chksum_short(const char *filename, ushort *chksum, int max_size = -1, int cf_type = CF_TYPE_ANY );
@@ -310,12 +365,26 @@ int cfwrite_string(const char *buf, CFILE *file);
*/
int cfwrite_string_len(const char *buf, CFILE *file);
int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *filter, int sort = CF_SORT_NONE, SCP_vector<file_list_info> *info = NULL );
int cf_get_file_list( int max, char **list, int type, const char *filter, int sort = CF_SORT_NONE, file_list_info *info = NULL );
int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char **list, int type, const char *filter, int sort = CF_SORT_NONE, file_list_info *info = NULL );
int cf_get_file_list(SCP_vector<SCP_string>& list, int pathtype, const char* filter, int sort = CF_SORT_NONE,
SCP_vector<file_list_info>* info = nullptr, uint32_t location_flags = CF_LOCATION_ALL);
int cf_get_file_list(int max, char** list, int type, const char* filter, int sort = CF_SORT_NONE,
file_list_info* info = nullptr, uint32_t location_flags = CF_LOCATION_ALL);
int cf_get_file_list_preallocated(int max, char arr[][MAX_FILENAME_LEN], char** list, int type, const char* filter,
int sort = CF_SORT_NONE, file_list_info* info = nullptr,
uint32_t location_flags = CF_LOCATION_ALL);
void cf_sort_filenames( int n, char **list, int sort, file_list_info *info = NULL );
void cf_sort_filenames( SCP_vector<SCP_string> &list, int sort, SCP_vector<file_list_info> *info = NULL );
struct CFileLocation {
bool found = false;
SCP_string full_name;
size_t size = 0;
size_t offset = 0;
const void* data_ptr = nullptr;
explicit CFileLocation(bool found_in = false) : found(found_in) {}
};
// Searches for a file. Follows all rules and precedence and searches
// CD's and pack files.
// Input: filespace - Filename & extension
@@ -325,7 +394,17 @@ void cf_sort_filenames( SCP_vector<SCP_string> &list, int sort, SCP_vector<file_
// size - File size
// offset - Offset into pack file. 0 if not a packfile.
// Returns: If not found returns 0.
int cf_find_file_location( const char *filespec, int pathtype, int max_out, char *pack_filename, size_t *size, size_t *offset, bool localize = false);
CFileLocation cf_find_file_location(const char* filespec, int pathtype, bool localize = false,
uint32_t location_flags = CF_LOCATION_ALL);
struct CFileLocationExt : public CFileLocation {
int extension_index = -1;
explicit CFileLocationExt(int extension_index_in = -1)
: CFileLocation(extension_index_in >= 0), extension_index(extension_index_in)
{
}
};
// Searches for a file. Follows all rules and precedence and searches
// CD's and pack files. Searches all locations in order for first filename using ext filter list.
@@ -339,7 +418,8 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
// offset - Offset into pack file. 0 if not a packfile.
// Returns: If not found returns -1, else returns offset into ext_list.
// (NOTE: This function is exponentially slow, so don't use it unless truely needed!!)
int cf_find_file_location_ext(const char *filename, const int ext_num, const char **ext_list, int pathtype, int max_out = 0, char *pack_filename = NULL, size_t *size = NULL, size_t *offset = NULL, bool localize = false);
CFileLocationExt cf_find_file_location_ext(const char* filename, const int ext_num, const char** ext_list, int pathtype,
bool localize = false);
// Functions to change directories
int cfile_chdir(const char *dir);
@@ -364,16 +444,13 @@ namespace cfile
{
}
cfile_error(const std::string &excuse) : m_excuse(excuse)
explicit cfile_error(const std::string &excuse) : m_excuse(excuse)
{
}
~cfile_error() throw()
{
}
~cfile_error() SCP_NOEXCEPT override {}
virtual const char *what() const throw()
{
const char *what() const SCP_NOEXCEPT override {
return m_excuse.c_str();
}
@@ -384,7 +461,7 @@ namespace cfile
class max_read_length : public cfile_error
{
public:
max_read_length(const std::string &excuse) : cfile_error(excuse)
explicit max_read_length(const std::string &excuse) : cfile_error(excuse)
{
}
+59 -41
View File
@@ -11,9 +11,9 @@
#define _CFILE_INTERNAL
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#ifdef _WIN32
#include <io.h>
@@ -74,18 +74,13 @@ int cfeof(CFILE *cfile)
Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
cb = &Cfile_block_list[cfile->id];
int result;
result = 0;
// cfeof() not supported for memory-mapped files
Assert( !cb->data );
Assert(cb->fp != NULL);
int result = 0;
#if defined(CHECK_POSITION) && !defined(NDEBUG)
auto raw_position = ftell(cb->fp) - cb->lib_offset;
Assert(raw_position == cb->raw_position);
if (cb->fp) {
auto raw_position = ftell(cb->fp) - cb->lib_offset;
Assert(raw_position == cb->raw_position);
}
#endif
if (cb->raw_position >= cb->size ) {
@@ -109,14 +104,11 @@ int cftell( CFILE * cfile )
Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
cb = &Cfile_block_list[cfile->id];
// Doesn't work for memory mapped files
Assert( !cb->data );
Assert(cb->fp != NULL);
#if defined(CHECK_POSITION) && !defined(NDEBUG)
auto raw_position = ftell(cb->fp) - cb->lib_offset;
Assert(raw_position == cb->raw_position);
if (cb->fp) {
auto raw_position = ftell(cb->fp) - cb->lib_offset;
Assert(raw_position == cb->raw_position);
}
#endif
// The rest of the code still uses ints, do an overflow check to detect cases where this fails
@@ -141,8 +133,7 @@ int cfseek( CFILE *cfile, int offset, int where )
// TODO: seek to offset in memory mapped file
Assert( !cb->data );
Assert( cb->fp != NULL );
Assert( !cb->mem_mapped );
size_t goal_position;
@@ -166,14 +157,22 @@ int cfseek( CFILE *cfile, int offset, int where )
// Make sure we don't seek beyond the end of the file
CAP(goal_position, cb->lib_offset, cb->lib_offset + cb->size);
int result = fseek(cb->fp, (long)goal_position, SEEK_SET );
Assertion(goal_position >= cb->lib_offset, "Invalid offset values detected while seeking! Goal was " SIZE_T_ARG ", lib_offset is " SIZE_T_ARG ".", goal_position, cb->lib_offset);
int result = 0;
if (cb->fp) {
// If we have a file pointer we can also seek in that file
result = fseek(cb->fp, (long)goal_position, SEEK_SET );
Assertion(goal_position >= cb->lib_offset, "Invalid offset values detected while seeking! Goal was " SIZE_T_ARG ", lib_offset is " SIZE_T_ARG ".", goal_position, cb->lib_offset);
}
// If we only have a data pointer this will do all the work
cb->raw_position = goal_position - cb->lib_offset;
Assertion(cb->raw_position <= cb->size, "Invalid raw_position value detected!");
#if defined(CHECK_POSITION) && !defined(NDEBUG)
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
Assert(tmp_offset==cb->raw_position);
if (cb->fp) {
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
Assert(tmp_offset == cb->raw_position);
}
#endif
return result;
@@ -197,13 +196,6 @@ int cfread(void *buf, int elsize, int nelem, CFILE *cfile)
Cfile_block *cb = &Cfile_block_list[cfile->id];
// cfread() not supported for memory-mapped files
if(cb->data != NULL)
{
Warning(LOCATION, "Writing is not supported for mem-mapped files");
return 0;
}
if ( (cb->raw_position+size) > cb->size ) {
Assertion(cb->raw_position <= cb->size, "Invalid raw_position value detected!");
size = cb->size - cb->raw_position;
@@ -222,15 +214,24 @@ int cfread(void *buf, int elsize, int nelem, CFILE *cfile)
}
}
size_t bytes_read = fread( buf, 1, size, cb->fp );
size_t bytes_read;
if (cb->data != nullptr) {
// This is a file from memory
bytes_read = size;
memcpy(buf, reinterpret_cast<const char*>(cb->data) + cb->raw_position, size);
} else {
bytes_read = fread( buf, 1, size, cb->fp );
}
if ( bytes_read > 0 ) {
cb->raw_position += bytes_read;
Assertion(cb->raw_position <= cb->size, "Invalid raw_position value detected!");
}
#if defined(CHECK_POSITION) && !defined(NDEBUG)
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
Assert(tmp_offset==cb->raw_position);
if (cb->fp) {
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
Assert(tmp_offset==cb->raw_position);
}
#endif
return (int)(bytes_read / elsize);
@@ -254,14 +255,31 @@ int cfread_lua_number(double *buf, CFILE *cfile)
return 0;
}
long orig_pos = ftell(cb->fp);
int items_read = fscanf(cb->fp, LUA_NUMBER_SCAN, buf);
cb->raw_position += ftell(cb->fp)-orig_pos;
size_t advance = 0;
int items_read;
if (cb->fp) {
long orig_pos = ftell(cb->fp);
items_read = fscanf(cb->fp, LUA_NUMBER_SCAN, buf);
advance = (size_t) (ftell(cb->fp)-orig_pos);
} else {
int read;
// %n returns the number of bytes currently read so we append that to the scan format at the end so it will return
// how many bytes we have consumed
items_read = sscanf(reinterpret_cast<const char*>(cb->data), LUA_NUMBER_SCAN "%n", buf, &read);
if (items_read == 2) {
// We need to correct the items read counter since we read one additional item
items_read = 1;
}
advance = (size_t) read;
}
cb->raw_position += advance;
Assertion(cb->raw_position <= cb->size, "Invalid raw_position value detected!");
#if defined(CHECK_POSITION) && !defined(NDEBUG)
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
Assert(tmp_offset==cb->raw_position);
if (cb->fp) {
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
Assert(tmp_offset==cb->raw_position);
}
#endif
return items_read;
+2 -1
View File
@@ -26,7 +26,8 @@ typedef struct Cfile_block {
int type; // CFILE_BLOCK_UNUSED, CFILE_BLOCK_USED
int dir_type; // directory location
FILE *fp; // File pointer if opening an individual file
void *data; // Pointer for memory-mapped file access. NULL if not mem-mapped.
const void *data; // Pointer for memory-mapped file access. NULL if not mem-mapped.
bool mem_mapped; // Flag for memory mapped files (if data is not null and this is false it means that it's an embedded file)
#ifdef _WIN32
HANDLE hInFile; // Handle from CreateFile()
HANDLE hMapFile; // Handle from CreateFileMapping()
+3 -3
View File
@@ -9,9 +9,9 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <string>
#include <algorithm>
+361 -190
View File
@@ -9,10 +9,10 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cerrno>
#include <sstream>
#include <algorithm>
@@ -37,15 +37,16 @@
#include "cfile/cfilesystem.h"
#include "cmdline/cmdline.h"
#include "globalincs/pstypes.h"
#include "def_files/def_files.h"
#include "localization/localize.h"
#include "osapi/osapi.h"
#include "parse/parselo.h"
#define CF_ROOTTYPE_PATH 0
#define CF_ROOTTYPE_PACK 1
// for a defined and specifically set location to get/send pilot/campaign files
SCP_string Pilot_file_path;
enum CfileRootType {
CF_ROOTTYPE_PATH = 0,
CF_ROOTTYPE_PACK = 1,
CF_ROOTTYPE_MEMORY = 2,
};
// Created by:
// specifying hard drive tree
@@ -53,8 +54,9 @@ SCP_string Pilot_file_path;
// specifying cd-rom tree
// searching for pack files on CD-rom tree
typedef struct cf_root {
char path[CF_MAX_PATHNAME_LENGTH]; // Contains something like c:\projects\freespace or c:\projects\freespace\freespace.vp
int roottype; // CF_ROOTTYPE_PATH = Path, CF_ROOTTYPE_PACK =Pack file
char path[CF_MAX_PATHNAME_LENGTH]; // Contains something like c:\projects\freespace or c:\projects\freespace\freespace.vp
int roottype; // CF_ROOTTYPE_PATH = Path, CF_ROOTTYPE_PACK =Pack file, CF_ROOTTYPE_MEMORY=In memory
uint32_t location_flags;
} cf_root;
// convenient type for sorting (see cf_build_pack_list())
@@ -79,13 +81,14 @@ static int Num_path_roots = 0;
// Created by searching all roots in order. This means Files is then sorted by precedence.
typedef struct cf_file {
char name_ext[CF_MAX_FILENAME_LENGTH]; // Filename and extension
int root_index; // Where in Roots this is located
int pathtype_index; // Where in Paths this is located
time_t write_time; // When it was last written
int size; // How big it is in bytes
int pack_offset; // For pack files, where it is at. 0 if not in a pack file. This can be used to tell if in a pack file.
char* real_name; // For real files, the full path
char name_ext[CF_MAX_FILENAME_LENGTH]; // Filename and extension
int root_index; // Where in Roots this is located
int pathtype_index; // Where in Paths this is located
time_t write_time; // When it was last written
int size; // How big it is in bytes
int pack_offset; // For pack files, where it is at. 0 if not in a pack file. This can be used to tell if in a pack file.
char* real_name; // For real files, the full path
const void* data; // For in-memory files, the data pointer
} cf_file;
#define CF_NUM_FILES_PER_BLOCK 512
@@ -342,9 +345,9 @@ void cf_build_pack_list( cf_root *root )
std::sort(temp_roots_sort, temp_roots_sort + temp_root_count, cf_packfile_sort_func);
// now insert them all into the real root list properly
cf_root *new_root;
for (i = 0; i < temp_root_count; i++) {
new_root = cf_create_root();
auto new_root = cf_create_root();
new_root->location_flags = root->location_flags;
strcpy_s( new_root->path, root->path );
#ifndef NDEBUG
@@ -373,10 +376,11 @@ static char normalize_directory_separator(char in)
return in;
}
static void cf_add_mod_roots(const char* rootDirectory)
static void cf_add_mod_roots(const char* rootDirectory, uint32_t basic_location)
{
if (Cmdline_mod)
{
bool primary = true;
for (const char* cur_pos=Cmdline_mod; strlen(cur_pos) != 0; cur_pos+= (strlen(cur_pos)+1))
{
SCP_stringstream ss;
@@ -400,9 +404,16 @@ static void cf_add_mod_roots(const char* rootDirectory)
cf_root* root = cf_create_root();
strncpy(root->path, rootPath.c_str(), CF_MAX_PATHNAME_LENGTH-1);
if (primary) {
root->location_flags = basic_location | CF_LOCATION_TYPE_PRIMARY_MOD;
} else {
root->location_flags = basic_location | CF_LOCATION_TYPE_SECONDARY_MODS;
}
root->roottype = CF_ROOTTYPE_PATH;
cf_build_pack_list(root);
primary = false;
}
}
}
@@ -420,10 +431,16 @@ void cf_build_root_list(const char *cdrom_dir)
#ifdef WIN32
// Nothing to do here, Windows uses the current directory as the base
#else
cf_add_mod_roots(Cfile_user_dir_legacy);
cf_add_mod_roots(os_get_legacy_user_dir(), CF_LOCATION_ROOT_USER);
root = cf_create_root();
strncpy(root->path, Cfile_user_dir_legacy, CF_MAX_PATHNAME_LENGTH - 1);
strncpy(root->path, os_get_legacy_user_dir(), CF_MAX_PATHNAME_LENGTH - 1);
root->location_flags |= CF_LOCATION_ROOT_USER | CF_LOCATION_TYPE_ROOT;
if (Cmdline_mod == nullptr || strlen(Cmdline_mod) <= 0) {
// If there are no mods then the root is the primary mod
root->location_flags |= CF_LOCATION_TYPE_PRIMARY_MOD;
}
// do we already have a slash? as in the case of a root directory install
if ((strlen(root->path) < (CF_MAX_PATHNAME_LENGTH - 1)) && (root->path[strlen(root->path) - 1] != DIR_SEPARATOR_CHAR)) {
@@ -431,10 +448,6 @@ void cf_build_root_list(const char *cdrom_dir)
}
root->roottype = CF_ROOTTYPE_PATH;
// If it wasn't set before, set the pilot path
if (Pilot_file_path.empty())
Pilot_file_path = root->path;
// Next, check any VP files under the current directory.
cf_build_pack_list(root);
#endif
@@ -444,13 +457,19 @@ void cf_build_root_list(const char *cdrom_dir)
{
// =========================================================================
// now look for mods under the users HOME directory to use before system ones
cf_add_mod_roots(Cfile_user_dir);
cf_add_mod_roots(Cfile_user_dir, CF_LOCATION_ROOT_USER);
// =========================================================================
// =========================================================================
// set users HOME directory as default for loading and saving files
root = cf_create_root();
strncpy(root->path, Cfile_user_dir, CF_MAX_PATHNAME_LENGTH - 1);
strcpy_s(root->path, Cfile_user_dir);
root->location_flags |= CF_LOCATION_ROOT_USER | CF_LOCATION_TYPE_ROOT;
if (Cmdline_mod == nullptr || strlen(Cmdline_mod) <= 0) {
// If there are no mods then the root is the primary mod
root->location_flags |= CF_LOCATION_TYPE_PRIMARY_MOD;
}
// do we already have a slash? as in the case of a root directory install
if ((strlen(root->path) < (CF_MAX_PATHNAME_LENGTH - 1)) && (root->path[strlen(root->path) - 1] != DIR_SEPARATOR_CHAR)) {
@@ -458,10 +477,6 @@ void cf_build_root_list(const char *cdrom_dir)
}
root->roottype = CF_ROOTTYPE_PATH;
// set the default player location to here
if (Pilot_file_path.empty())
Pilot_file_path = root->path;
// Next, check any VP files under the current directory.
cf_build_pack_list(root);
// =========================================================================
@@ -472,11 +487,17 @@ void cf_build_root_list(const char *cdrom_dir)
if ( !_getcwd(working_directory, CF_MAX_PATHNAME_LENGTH ) ) {
Error(LOCATION, "Can't get current working directory -- %d", errno );
}
cf_add_mod_roots(working_directory);
cf_add_mod_roots(working_directory, CF_LOCATION_ROOT_GAME);
root = cf_create_root();
root->location_flags |= CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT;
if (Cmdline_mod == nullptr || strlen(Cmdline_mod) <= 0) {
// If there are no mods then the root is the primary mod
root->location_flags |= CF_LOCATION_TYPE_PRIMARY_MOD;
}
strcpy_s(root->path, working_directory);
size_t path_len = strlen(root->path);
@@ -488,10 +509,6 @@ void cf_build_root_list(const char *cdrom_dir)
root->roottype = CF_ROOTTYPE_PATH;
// If the path wasn't set before use the working directory
if ( Pilot_file_path.empty() )
Pilot_file_path = root->path;
//======================================================
// Next, check any VP files under the current directory.
cf_build_pack_list(root);
@@ -510,6 +527,12 @@ void cf_build_root_list(const char *cdrom_dir)
}
// The final root is the in-memory root
root = cf_create_root();
root->location_flags = CF_LOCATION_ROOT_MEMORY | CF_LOCATION_TYPE_ROOT;
memset(root->path, 0, sizeof(root->path));
root->roottype = CF_ROOTTYPE_MEMORY;
}
// Given a lower case list of file extensions
@@ -639,7 +662,7 @@ void cf_search_root_path(int root_index)
struct dirent *dir = nullptr;
while ((dir = readdir (parentDirP)) != nullptr) {
if (stricmp(search_name, dir->d_name)) {
if (stricmp(search_name, dir->d_name) != 0) {
continue;
}
@@ -836,7 +859,48 @@ void cf_search_root_pack(int root_index)
mprintf(( "%i files\n", num_files ));
}
void cf_search_memory_root(int root_index) {
int num_files = 0;
mprintf(( "Searching memory root ... " ));
auto default_files = defaults_get_all();
for (auto& default_file : default_files) {
// Pure built in files have an empty path_type string
if (strlen(default_file.path_type) <= 0) {
// Ignore pure builtin files. They should only be accessible with defaults_get_file
continue;
}
int pathtype = -1;
for (int i = 0; i < CF_MAX_PATH_TYPES; ++i) {
if (Pathtypes[i].path == nullptr) {
continue;
}
if (!strcmp(Pathtypes[i].path, default_file.path_type)) {
pathtype = i;
break;
}
}
Assertion(pathtype != -1, "Default file '%s%s%s' does not use a valid path type!",
default_file.path_type,
DIR_SEPARATOR_STR,
default_file.filename);
cf_file *file = cf_create_file();
strcpy_s( file->name_ext, default_file.filename );
file->root_index = root_index;
file->pathtype_index = pathtype;
file->write_time = time(nullptr); // Just assume that memory files were last written to just now
file->size = (int)default_file.size;
file->data = default_file.data;
num_files++;
}
mprintf(( "%i files\n", num_files ));
}
void cf_build_file_list()
{
@@ -851,6 +915,8 @@ void cf_build_file_list()
cf_search_root_path(i);
} else if ( root->roottype == CF_ROOTTYPE_PACK ) {
cf_search_root_pack(i);
} else if (root->roottype == CF_ROOTTYPE_MEMORY) {
cf_search_memory_root(i);
}
}
@@ -924,15 +990,12 @@ void cf_free_secondary_filelist()
*
* @param filespec Filename & extension
* @param pathtype See CF_TYPE_ defines in CFILE.H
* @param max_out Maximum string length that should be stuffed into pack_filename
* @param pack_filename OUTPUT: Absolute path and filename of this file. Could be a packfile or the actual file.
* @param size OUTPUT: File size
* @param offset OUTPUT: Offset into pack file. 0 if not a packfile.
* @param localize Undertake localization
* @param location_flags Specifies where to search for the specified flag
*
* @return If not found returns 0.
* @return A structure which describes the found file
*/
int cf_find_file_location( const char *filespec, int pathtype, int max_out, char *pack_filename, size_t *size, size_t *offset, bool localize )
CFileLocation cf_find_file_location(const char* filespec, int pathtype, bool localize, uint32_t location_flags)
{
int i;
uint ui;
@@ -940,7 +1003,6 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
char longname[MAX_PATH_LEN];
Assert( (filespec != NULL) && (strlen(filespec) > 0) ); //-V805
Assert( (pack_filename == NULL) || (max_out > 1) );
// see if we have something other than just a filename
// our current rules say that any file that specifies a direct
@@ -956,16 +1018,15 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
#endif
FILE *fp = fopen(filespec, "rb" );
if (fp) {
if ( size ) *size = filelength(fileno(fp));
if ( offset ) *offset = 0;
if ( pack_filename ) {
strncpy( pack_filename, filespec, max_out );
}
CFileLocation res(true);
res.size = static_cast<size_t>(filelength(fileno(fp)));
res.offset = 0;
res.full_name = filespec;
fclose(fp);
return 1;
return res;
}
return 0; // If they give a full path, fail if not found.
return CFileLocation(); // If they give a full path, fail if not found.
}
// Search the hard drive for files first.
@@ -1004,43 +1065,39 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
}
if (cfs_slow_search) {
cf_create_default_path_string( longname, sizeof(longname)-1, search_order[ui], filespec, localize );
cf_create_default_path_string(longname, sizeof(longname) - 1, search_order[ui], filespec, localize,
location_flags);
#if defined _WIN32
_finddata_t findstruct;
intptr_t findhandle = _findfirst(longname, &findstruct);
if (findhandle != -1) {
if (size)
*size = findstruct.size;
CFileLocation res;
res.found = true;
res.size = static_cast<size_t>(findstruct.size);
_findclose(findhandle);
if (offset)
*offset = 0;
res.offset = 0;
res.full_name = longname;
if (pack_filename)
strncpy( pack_filename, longname, max_out );
return 1;
return res;
}
#endif
{
FILE *fp = fopen(longname, "rb" );
if (fp) {
if (size)
*size = filelength( fileno(fp) );
CFileLocation res(true);
res.size = static_cast<size_t>(filelength( fileno(fp) ));
fclose(fp);
if (offset)
*offset = 0;
res.offset = 0;
res.full_name = longname;
if (pack_filename)
strncpy(pack_filename, longname, max_out);
return 1;
return res;
}
}
}
@@ -1054,6 +1111,15 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
if ( (pathtype != CF_TYPE_ANY) && (pathtype != f->pathtype_index) )
continue;
if (location_flags != CF_LOCATION_ALL) {
// If a location flag was specified we need to check if the root of this file satisfies the request
auto root = cf_get_root(f->root_index);
if (!cf_check_location_flags(root->location_flags, location_flags)) {
// Root does not satisfy location flags
continue;
}
}
if (localize) {
// create localized filespec
@@ -1061,54 +1127,58 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
if ( lcl_add_dir_to_path_with_filename(longname, MAX_PATH_LEN - 1) ) {
if ( !stricmp(longname, f->name_ext) ) {
if (size)
*size = f->size;
CFileLocation res(true);
res.size = static_cast<size_t>(f->size);
res.offset = (size_t)f->pack_offset;
res.data_ptr = f->data;
if (offset)
*offset = (size_t)f->pack_offset;
if (f->data != nullptr) {
// This is an in-memory file so we just copy the pathtype name + file name
res.full_name = Pathtypes[f->pathtype_index].path;
res.full_name += DIR_SEPARATOR_STR;
res.full_name += f->name_ext;
} else if (f->pack_offset < 1) {
// This is a real file, return the actual file path
res.full_name = f->real_name;
} else {
// File is in a pack file
cf_root *r = cf_get_root(f->root_index);
if (pack_filename) {
if (f->pack_offset < 1) {
// This is a real file, return the actual file path
strncpy( pack_filename, f->real_name, max_out );
} else {
// File is in a pack file
cf_root *r = cf_get_root(f->root_index);
strncpy( pack_filename, r->path, max_out );
}
res.full_name = r->path;
}
return 1;
return res;
}
}
}
// file either not localized or localized version not found
if ( !stricmp(filespec, f->name_ext) ) {
if (size)
*size = f->size;
CFileLocation res(true);
res.size = static_cast<size_t>(f->size);
res.offset = (size_t)f->pack_offset;
res.data_ptr = f->data;
if (offset)
*offset = (size_t)f->pack_offset;
if (f->data != nullptr) {
// This is an in-memory file so we just copy the pathtype name + file name
res.full_name = Pathtypes[f->pathtype_index].path;
res.full_name += DIR_SEPARATOR_STR;
res.full_name += f->name_ext;
} else if (f->pack_offset < 1) {
// This is a real file, return the actual file path
res.full_name = f->real_name;
} else {
// File is in a pack file
cf_root *r = cf_get_root(f->root_index);
if (pack_filename) {
if (f->pack_offset < 1) {
// This is a real file, return the actual file path
strncpy( pack_filename, f->real_name, max_out );
} else {
// File is in a pack file
cf_root *r = cf_get_root(f->root_index);
strncpy( pack_filename, r->path, max_out );
}
res.full_name = r->path;
}
return 1;
return res;
}
}
return 0;
return CFileLocation();
}
// -- from parselo.cpp --
@@ -1125,14 +1195,11 @@ extern char *stristr(char *str, const char *substr);
* @param ext_list Extension filter list
* @param pathtype See CF_TYPE_ defines in CFILE.H
* @param max_out Maximum string length that should be stuffed into pack_filename
* @param pack_filename OUTPUT: Absolute path and filename of this file. Could be a packfile or the actual file.
* @param size OUTPUT: File size
* @param offset OUTPUT: Offset into pack file. 0 if not a packfile.
* @param localize Undertake localization
*
* @return If not found returns -1, else returns offset into ext_list.
* @return A structure containing information about the found file
*/
int cf_find_file_location_ext( const char *filename, const int ext_num, const char **ext_list, int pathtype, int max_out, char *pack_filename, size_t *size, size_t *offset, bool localize )
CFileLocationExt cf_find_file_location_ext( const char *filename, const int ext_num, const char **ext_list, int pathtype, bool localize)
{
int cur_ext, i;
uint ui;
@@ -1144,7 +1211,6 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
Assert( (filename != NULL) && (strlen(filename) < MAX_FILENAME_LEN) );
Assert( (ext_list != NULL) && (ext_num > 1) ); // if we are searching for just one ext
// then this is the wrong function to use
Assert( (pack_filename == NULL) || (max_out > 1) );
// if we have a full path already then fail. this function if for searching via filter only!
@@ -1154,7 +1220,7 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
if ( strpbrk(filename,"/\\:") ) { // do we have a full path already?
#endif
Int3();
return 0;
return CFileLocationExt();
}
// Search the hard drive for files first.
@@ -1212,38 +1278,35 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
#if defined _WIN32
_finddata_t findstruct;
intptr_t findhandle = _findfirst(longname, &findstruct);
if (findhandle != -1) {
if (size)
*size = findstruct.size;
CFileLocationExt res(cur_ext);
res.found = true;
res.size = static_cast<size_t>(findstruct.size);
_findclose(findhandle);
if (offset)
*offset = 0;
res.offset = 0;
res.full_name = longname;
if (pack_filename)
strncpy( pack_filename, longname, max_out );
return cur_ext;
return res;
}
#endif
{
FILE *fp = fopen(longname, "rb" );
if (fp) {
if (size)
*size = filelength( fileno(fp) );
CFileLocationExt res(cur_ext);
res.found = true;
res.size = static_cast<size_t>(filelength( fileno(fp) ));
fclose(fp);
if (offset)
*offset = 0;
res.offset = 0;
res.full_name = longname;
if (pack_filename)
strncpy(pack_filename, longname, max_out);
return cur_ext;
return res;
}
}
}
@@ -1284,7 +1347,7 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
continue;
// ... check that we match the base filename
if ( strnicmp(f->name_ext, filespec, filespec_len) )
if ( strnicmp(f->name_ext, filespec, filespec_len) != 0 )
continue;
// ... make sure that it's one of our supported types
@@ -1328,56 +1391,62 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
if ( lcl_add_dir_to_path_with_filename(longname, MAX_PATH_LEN - 1) ) {
if ( !stricmp(longname, f->name_ext) ) {
if (size)
*size = f->size;
CFileLocationExt res(cur_ext);
res.found = true;
res.size = static_cast<size_t>(f->size);
res.offset = (size_t)f->pack_offset;
res.data_ptr = f->data;
if (offset)
*offset = f->pack_offset;
if (f->data != nullptr) {
// This is an in-memory file so we just copy the pathtype name + file name
res.full_name = Pathtypes[f->pathtype_index].path;
res.full_name += DIR_SEPARATOR_STR;
res.full_name += f->name_ext;
} else if (f->pack_offset < 1) {
// This is a real file, return the actual file path
res.full_name = f->real_name;
} else {
// File is in a pack file
cf_root *r = cf_get_root(f->root_index);
if (pack_filename) {
if (f->pack_offset < 1) {
// This is a real file, return the actual file path
strncpy( pack_filename, f->real_name, max_out );
} else {
// File is in a pack file
cf_root *r = cf_get_root(f->root_index);
strncpy( pack_filename, r->path, max_out );
}
res.full_name = r->path;
}
// found it, so cleanup and return
file_list_index.clear();
return cur_ext;
return res;
}
}
}
// file either not localized or localized version not found
if ( !stricmp(filespec, f->name_ext) ) {
if (size)
*size = f->size;
CFileLocationExt res(cur_ext);
res.found = true;
res.size = static_cast<size_t>(f->size);
res.offset = (size_t)f->pack_offset;
res.data_ptr = f->data;
if (offset)
*offset = f->pack_offset;
if (f->data != nullptr) {
// This is an in-memory file so we just copy the pathtype name + file name
res.full_name = Pathtypes[f->pathtype_index].path;
res.full_name += DIR_SEPARATOR_STR;
res.full_name += f->name_ext;
} else if (f->pack_offset < 1) {
// This is a real file, return the actual file path
res.full_name = f->real_name;
} else {
// File is in a pack file
cf_root *r = cf_get_root(f->root_index);
if (pack_filename) {
if (f->pack_offset < 1) {
// This is a real file, return the actual file path
strncpy( pack_filename, f->real_name, max_out );
} else {
// File is in a pack file
cf_root *r = cf_get_root(f->root_index);
strncpy( pack_filename, r->path, max_out );
}
res.full_name = r->path;
}
// found it, so cleanup and return
file_list_index.clear();
return cur_ext;
return res;
}
// ok, we're still here, so strip off the extension again in order to
@@ -1388,7 +1457,7 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
}
}
return -1;
return CFileLocationExt();
}
@@ -1432,6 +1501,7 @@ int cf_matches_spec(const char *filespec, const char *filename)
int (*Get_file_list_filter)(const char *filename) = NULL;
const char *Get_file_list_child = NULL;
int Skip_packfile_search = 0;
bool Skip_memory_files = false;
static bool verify_file_list_child()
{
@@ -1486,7 +1556,8 @@ static int cf_file_already_in_list( SCP_vector<SCP_string> &list, const char *fi
// This one has a 'type', which is a CF_TYPE_* value. Because this specifies the directory
// location, 'filter' only needs to be the filter itself, with no path information.
// See above descriptions of cf_get_file_list() for more information about how it all works.
int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *filter, int sort, SCP_vector<file_list_info> *info )
int cf_get_file_list(SCP_vector<SCP_string>& list, int pathtype, const char* filter, int sort,
SCP_vector<file_list_info>* info, uint32_t location_flags)
{
char *ptr;
uint i;
@@ -1514,7 +1585,8 @@ int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *fi
}
#if defined _WIN32
cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, (char*)Get_file_list_child );
cf_create_default_path_string(filespec, sizeof(filespec) - 1, pathtype, (char*)Get_file_list_child, false,
location_flags);
strcat_s(filespec, DIR_SEPARATOR_STR);
strcat_s(filespec, filter);
@@ -1554,7 +1626,8 @@ int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *fi
}
#elif defined SCP_UNIX
cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, (char*)Get_file_list_child );
cf_create_default_path_string(filespec, sizeof(filespec) - 1, pathtype, (char*)Get_file_list_child, false,
location_flags);
DIR *dirp;
struct dirent *dir;
@@ -1567,8 +1640,10 @@ int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *fi
continue;
char fn[MAX_PATH];
snprintf(fn, MAX_PATH-1, "%s/%s", filespec, dir->d_name);
fn[MAX_PATH-1] = 0;
if (snprintf(fn, MAX_PATH, "%s/%s", filespec, dir->d_name) >= MAX_PATH) {
// Make sure the string is null terminated
fn[MAX_PATH-1] = 0;
}
struct stat buf;
if (stat(fn, &buf) == -1) {
@@ -1620,6 +1695,16 @@ int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *fi
continue;
}
if (location_flags != CF_LOCATION_ALL) {
// If a location flag was specified we need to check if the root of this file satisfies the request
auto root = cf_get_root(f->root_index);
if (!cf_check_location_flags(root->location_flags, location_flags)) {
// Root does not satisfy location flags
continue;
}
}
if ( !cf_matches_spec( filter,f->name_ext)) {
continue;
}
@@ -1633,6 +1718,11 @@ int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *fi
continue;
}
if (Skip_memory_files && f->data != nullptr) {
// If we want to skip memory files and this is a memory file then ignore it
continue;
}
if ( !Get_file_list_filter || (*Get_file_list_filter)(f->name_ext) ) {
//mprintf(( "Found '%s' in root %d path %d\n", f->name_ext, f->root_index, f->pathtype_index ));
@@ -1692,7 +1782,8 @@ int cf_file_already_in_list( int num_files, char **list, const char *filename )
// This one has a 'type', which is a CF_TYPE_* value. Because this specifies the directory
// location, 'filter' only needs to be the filter itself, with no path information.
// See above descriptions of cf_get_file_list() for more information about how it all works.
int cf_get_file_list( int max, char **list, int pathtype, const char *filter, int sort, file_list_info *info )
int cf_get_file_list(int max, char** list, int pathtype, const char* filter, int sort, file_list_info* info,
uint32_t location_flags)
{
char *ptr;
uint i;
@@ -1715,7 +1806,7 @@ int cf_get_file_list( int max, char **list, int pathtype, const char *filter, in
char filespec[MAX_PATH_LEN];
#if defined _WIN32
cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, filter );
cf_create_default_path_string(filespec, sizeof(filespec) - 1, pathtype, filter, false, location_flags);
_finddata_t find;
intptr_t find_handle;
@@ -1756,7 +1847,7 @@ int cf_get_file_list( int max, char **list, int pathtype, const char *filter, in
}
#elif defined SCP_UNIX
cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, NULL );
cf_create_default_path_string(filespec, sizeof(filespec) - 1, pathtype, nullptr, false, location_flags);
DIR *dirp;
struct dirent *dir;
@@ -1776,8 +1867,10 @@ int cf_get_file_list( int max, char **list, int pathtype, const char *filter, in
continue;
char fn[MAX_PATH];
snprintf(fn, MAX_PATH-1, "%s/%s", filespec, dir->d_name);
fn[MAX_PATH-1] = 0;
if (snprintf(fn, MAX_PATH, "%s/%s", filespec, dir->d_name) >= MAX_PATH) {
// Make sure the string is null terminated
fn[MAX_PATH-1] = 0;
}
struct stat buf;
if (stat(fn, &buf) == -1) {
@@ -1827,6 +1920,16 @@ int cf_get_file_list( int max, char **list, int pathtype, const char *filter, in
continue;
}
if (location_flags != CF_LOCATION_ALL) {
// If a location flag was specified we need to check if the root of this file satisfies the request
auto root = cf_get_root(f->root_index);
if (!cf_check_location_flags(root->location_flags, location_flags)) {
// Root does not satisfy location flags
continue;
}
}
if (num_files >= max)
break;
@@ -1843,6 +1946,11 @@ int cf_get_file_list( int max, char **list, int pathtype, const char *filter, in
continue;
}
if (Skip_memory_files && f->data != nullptr) {
// If we want to skip memory files and this is a memory file then ignore it
continue;
}
if ( !Get_file_list_filter || (*Get_file_list_filter)(f->name_ext) ) {
//mprintf(( "Found '%s' in root %d path %d\n", f->name_ext, f->root_index, f->pathtype_index ));
@@ -1905,7 +2013,8 @@ int cf_file_already_in_list_preallocated( int num_files, char arr[][MAX_FILENAME
// This one has a 'type', which is a CF_TYPE_* value. Because this specifies the directory
// location, 'filter' only needs to be the filter itself, with no path information.
// See above descriptions of cf_get_file_list() for more information about how it all works.
int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char **list, int pathtype, const char *filter, int sort, file_list_info *info )
int cf_get_file_list_preallocated(int max, char arr[][MAX_FILENAME_LEN], char** list, int pathtype, const char* filter,
int sort, file_list_info* info, uint32_t location_flags)
{
int num_files = 0, own_flag = 0;
@@ -1934,7 +2043,7 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
// Search the default directories
#if defined _WIN32
cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, filter );
cf_create_default_path_string(filespec, sizeof(filespec) - 1, pathtype, filter, false, location_flags);
intptr_t find_handle;
_finddata_t find;
@@ -1975,7 +2084,7 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
}
#elif defined SCP_UNIX
cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, NULL );
cf_create_default_path_string(filespec, sizeof(filespec) - 1, pathtype, nullptr, false, location_flags);
DIR *dirp;
struct dirent *dir;
@@ -1991,8 +2100,10 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
continue;
char fn[MAX_PATH];
snprintf(fn, MAX_PATH-1, "%s/%s", filespec, dir->d_name);
fn[MAX_PATH-1] = 0;
if (snprintf(fn, MAX_PATH, "%s/%s", filespec, dir->d_name) >= MAX_PATH) {
// Make sure the string is null terminated
fn[MAX_PATH-1] = 0;
}
struct stat buf;
if (stat(fn, &buf) == -1) {
@@ -2009,7 +2120,7 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
if ( !Get_file_list_filter || (*Get_file_list_filter)(dir->d_name) ) {
strncpy(arr[num_files], dir->d_name, MAX_FILENAME_LEN - 1 );
strcpy_s(arr[num_files], dir->d_name );
char *ptr = strrchr(arr[num_files], '.');
if ( ptr ) {
*ptr = 0;
@@ -2044,6 +2155,16 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
continue;
}
if (location_flags != CF_LOCATION_ALL) {
// If a location flag was specified we need to check if the root of this file satisfies the request
auto root = cf_get_root(f->root_index);
if (!cf_check_location_flags(root->location_flags, location_flags)) {
// Root does not satisfy location flags
continue;
}
}
if (num_files >= max)
break;
@@ -2061,6 +2182,11 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
continue;
}
if (Skip_memory_files && f->data != nullptr) {
// If we want to skip memory files and this is a memory file then ignore it
continue;
}
if ( !Get_file_list_filter || (*Get_file_list_filter)(f->name_ext) ) {
//mprintf(( "Found '%s' in root %d path %d\n", f->name_ext, f->root_index, f->pathtype_index ));
@@ -2105,7 +2231,8 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
// filename - optional, if set, tacks the filename onto end of path.
// Output: path - Fully qualified pathname.
//Returns 0 if the result would be too long (invalid result)
int cf_create_default_path_string(char *path, uint path_max, int pathtype, const char *filename, bool localize )
int cf_create_default_path_string(char* path, uint path_max, int pathtype, const char* filename, bool localize,
uint32_t location_flags)
{
#ifdef SCP_UNIX
if ( filename && strpbrk(filename,"/") ) {
@@ -2116,7 +2243,22 @@ int cf_create_default_path_string(char *path, uint path_max, int pathtype, const
strncpy( path, filename, path_max );
} else {
cf_root *root = cf_get_root(0);
cf_root* root = nullptr;
for (auto i = 0; i < Num_roots; ++i) {
auto current_root = cf_get_root(i);
if (current_root->roottype != CF_ROOTTYPE_PATH) {
// We want a "real" path here so only path roots are valid
continue;
}
if (cf_check_location_flags(current_root->location_flags, location_flags)) {
// We found a valid root
root = current_root;
break;
}
}
if (!root) {
Assert( filename != NULL );
@@ -2126,12 +2268,7 @@ int cf_create_default_path_string(char *path, uint path_max, int pathtype, const
Assert(CF_TYPE_SPECIFIED(pathtype));
// force a specific directory to search for player files
if ( (pathtype == CF_TYPE_PLAYERS) || (pathtype == CF_TYPE_SINGLE_PLAYERS) || (pathtype == CF_TYPE_MULTI_PLAYERS) ) {
strncpy(path, Pilot_file_path.c_str(), path_max);
} else {
strncpy(path, root->path, path_max);
}
strncpy(path, root->path, path_max);
strcat_s(path, path_max, Pathtypes[pathtype].path);
@@ -2177,7 +2314,8 @@ int cf_create_default_path_string(char *path, uint path_max, int pathtype, const
// filename - optional, if set, tacks the filename onto end of path.
// Output: path - Fully qualified pathname.
//Returns 0 if the result would be too long (invalid result)
int cf_create_default_path_string( SCP_string &path, int pathtype, const char *filename, bool localize )
int cf_create_default_path_string(SCP_string& path, int pathtype, const char* filename, bool /*localize*/,
uint32_t location_flags)
{
#ifdef SCP_UNIX
if ( filename && strpbrk(filename,"/") ) {
@@ -2188,7 +2326,22 @@ int cf_create_default_path_string( SCP_string &path, int pathtype, const char *f
path.assign(filename);
} else {
cf_root *root = cf_get_root(0);
cf_root* root = nullptr;
for (auto i = 0; i < Num_roots; ++i) {
auto current_root = cf_get_root(i);
if (current_root->roottype != CF_ROOTTYPE_PATH) {
// We want a "real" path here so only path roots are valid
continue;
}
if (cf_check_location_flags(current_root->location_flags, location_flags)) {
// We found a valid root
root = current_root;
break;
}
}
if (!root) {
Assert( filename != NULL );
@@ -2199,12 +2352,7 @@ int cf_create_default_path_string( SCP_string &path, int pathtype, const char *f
Assert(CF_TYPE_SPECIFIED(pathtype));
std::ostringstream s_path;
// force a specific directory to search for player files
if ( (pathtype == CF_TYPE_PLAYERS) || (pathtype == CF_TYPE_SINGLE_PLAYERS) || (pathtype == CF_TYPE_MULTI_PLAYERS) ) {
s_path << Pilot_file_path;
} else {
s_path << root->path;
}
s_path << root->path;
s_path << Pathtypes[pathtype].path;
@@ -2269,3 +2417,26 @@ void cfile_spew_pack_file_crcs()
fclose(out);
}
bool cf_check_location_flags(uint32_t check_flags, uint32_t desired_flags)
{
Assertion((check_flags & CF_LOCATION_ROOT_MASK) != 0, "check_flags must have a valid root value");
Assertion((check_flags & CF_LOCATION_TYPE_MASK) != 0, "check_flags must have a valid type value");
auto check_root = check_flags & CF_LOCATION_ROOT_MASK;
auto desired_root_flags = desired_flags & CF_LOCATION_ROOT_MASK;
// If the root part is not set then assume that every root matches
if (desired_root_flags != 0 && (check_root & desired_root_flags) == 0) {
return false;
}
auto check_type = check_flags & CF_LOCATION_TYPE_MASK;
auto desired_type_flags = desired_flags & CF_LOCATION_TYPE_MASK;
if (desired_type_flags != 0 && (check_type & desired_type_flags) == 0) {
return false;
}
return true;
}
+6 -2
View File
@@ -29,6 +29,8 @@ typedef struct cf_pathtype {
// During cfile_init, verify that Pathtypes[n].index == n for each item
extern cf_pathtype Pathtypes[CF_MAX_PATH_TYPES];
bool cf_check_location_flags(uint32_t check_flags, uint32_t desired_flags);
// Returns the default storage path for files given a
// particular pathtype. In other words, the path to
// the unpacked, non-cd'd, stored on hard drive path.
@@ -39,7 +41,9 @@ extern cf_pathtype Pathtypes[CF_MAX_PATH_TYPES];
// filename - optional, if set, tacks the filename onto end of path.
// Output: path - Fully qualified pathname.
//Returns 0 if result would be too long (invalid result)
int cf_create_default_path_string( char *path, uint path_max, int pathtype, const char *filename=NULL, bool localize = false);
int cf_create_default_path_string( SCP_string &path, int pathtype, const char *filename=NULL, bool localize = false );
int cf_create_default_path_string(char* path, uint path_max, int pathtype, const char* filename = nullptr,
bool localize = false, uint32_t location_flags = CF_LOCATION_ALL);
int cf_create_default_path_string(SCP_string& path, int pathtype, const char* filename = nullptr, bool localize = false,
uint32_t location_flags = CF_LOCATION_ALL);
#endif //_CFILESYSTEM_H
+313 -77
View File
@@ -23,6 +23,9 @@
#include "globalincs/pstypes.h"
#include "osapi/osapi.h"
#include "cfile/cfilesystem.h"
#include "sound/speech.h"
#include "sound/openal.h"
#include "io/joy.h"
#ifdef _WIN32
#include <io.h>
@@ -36,8 +39,11 @@
#include <dirent.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <jansson.h>
// Stupid windows workaround...
#ifdef MessageBox
@@ -60,6 +66,11 @@ const char *cmdline_arg_types[] =
"STRING",
};
enum class flag_output_type {
Binary,
Json_V1,
};
// variables
class cmdline_parm {
public:
@@ -78,6 +89,7 @@ public:
float get_float();
char *str();
bool check_if_args_is_valid();
bool has_param();
};
static cmdline_parm Parm_list(NULL, NULL, AT_NONE);
@@ -148,7 +160,6 @@ Flag exe_params[] =
{ "-noenv", "Disable environment maps", true, EASY_DEFAULT_MEM, EASY_MEM_ALL_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-env", },
{ "-nomotiondebris", "Disable motion debris", true, EASY_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nomotiondebris",},
{ "-noscalevid", "Disable scale-to-window for movies", true, 0, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noscalevid", },
{ "-missile_lighting", "Apply lighting to missiles" , true, EASY_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-missile_lighting", },
{ "-nonormal", "Disable normal maps", true, EASY_DEFAULT_MEM, EASY_MEM_ALL_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-normal" },
{ "-no_emissive_light", "Disable emissive light from ships", true, 0, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_emissive_light" },
{ "-noheight", "Disable height/parallax maps", true, EASY_DEFAULT_MEM, EASY_MEM_ALL_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-height" },
@@ -162,7 +173,6 @@ Flag exe_params[] =
{ "-no_deferred", "Disable Deferred Lighting", true, EASY_DEFAULT_MEM, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_deferred"},
{ "-enable_shadows", "Enable Shadows", true, EASY_MEM_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_shadows"},
{ "-no_vsync", "Disable vertical sync", true, 0, EASY_DEFAULT, "Game Speed", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_vsync", },
{ "-cache_bitmaps", "Cache bitmaps between missions", true, 0, EASY_DEFAULT_MEM, "Game Speed", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-cache_bitmaps", },
{ "-dualscanlines", "Add another pair of scanning lines", true, 0, EASY_DEFAULT, "HUD", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-dualscanlines", },
{ "-targetinfo", "Enable info next to target", true, 0, EASY_DEFAULT, "HUD", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-targetinfo", },
@@ -177,7 +187,6 @@ Flag exe_params[] =
{ "-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", },
{ "-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", },
{ "-snd_preload", "Preload mission game sounds", true, EASY_MEM_ALL_ON, EASY_DEFAULT_MEM, "Audio", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-snd_preload", },
{ "-nosound", "Disable all sound", false, 0, EASY_DEFAULT, "Audio", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nosound", },
{ "-nomusic", "Disable music", false, 0, EASY_DEFAULT, "Audio", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nomusic", },
{ "-no_enhanced_sound", "Disable enhanced sound", false, 0, EASY_DEFAULT, "Audio", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_enhanced_sound", },
@@ -205,7 +214,6 @@ Flag exe_params[] =
{ "-use_gldrawelements","Don't use glDrawRangeElements", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-use_gldrawelements", },
{ "-old_collision", "Use old collision detection system", true, EASY_DEFAULT, EASY_ALL_ON, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-old_collision", },
{ "-gl_finish", "Fix input lag on some ATI+Linux systems", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-gl_finish", },
{ "-no_batching", "Disable batched model rendering", true, 0, EASY_DEFAULT, "Troubleshoot", "", },
{ "-no_geo_effects", "Disable geometry shader for effects", true, 0, EASY_DEFAULT, "Troubleshoot", "", },
{ "-set_cpu_affinity", "Sets processor affinity to config value", true, 0, EASY_DEFAULT, "Troubleshoot", "", },
{ "-nograb", "Disables mouse grabbing", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nograb", },
@@ -218,6 +226,7 @@ Flag exe_params[] =
{ "-voicer", "Enable voice recognition", true, 0, EASY_DEFAULT, "Experimental", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-voicer", },
{ "-fps", "Show frames per second on HUD", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fps", },
{ "-bmpmanusage", "Show how many BMPMAN slots are in use", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-bmpmanusage", },
{ "-pos", "Show position of camera", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-pos", },
{ "-window", "Run in window", true, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-window", },
{ "-fullscreen_window", "Run in fullscreen window", false, 0, EASY_DEFAULT, "Dev Tool", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fullscreen_window", },
@@ -303,7 +312,6 @@ cmdline_parm spec_static_arg("-spec_static", "Adjusts suns contribution to specu
cmdline_parm spec_point_arg("-spec_point", "Adjusts laser weapons contribution to specular highlights", AT_FLOAT);
cmdline_parm spec_tube_arg("-spec_tube", "Adjusts beam weapons contribution to specular highlights", AT_FLOAT);
cmdline_parm ambient_factor_arg("-ambient_factor", "Adjusts ambient light applied to all parts of a ship", AT_INT); // Cmdline_ambient_factor
cmdline_parm missile_lighting_arg("-missile_lighting", NULL, AT_NONE); // Cmdline_missile_lighting
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
@@ -321,10 +329,10 @@ cmdline_parm fxaa_preset_arg("-fxaa_preset", "FXAA quality (0-9), requires -post
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 no_batching("-no_batching", 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
cmdline_parm anisotropy_level_arg("-anisotropic_filter", NULL, AT_INT);
float Cmdline_clip_dist = Default_min_draw_distance;
float Cmdline_fov = 0.75f;
@@ -332,7 +340,6 @@ float Cmdline_ogl_spec = 80.0f;
int Cmdline_ambient_factor = 128;
int Cmdline_env = 1;
int Cmdline_mipmap = 0;
int Cmdline_missile_lighting = 0;
int Cmdline_glow = 1;
int Cmdline_nomotiondebris = 0;
int Cmdline_noscalevid = 0;
@@ -349,17 +356,15 @@ int Cmdline_fxaa_preset = 6;
extern int Fxaa_preset_last_frame;
bool Cmdline_fb_explosions = 0;
bool Cmdline_fb_thrusters = false;
bool Cmdline_no_batching = false;
extern bool ls_force_off;
int Cmdline_shadow_quality = 0;
int Cmdline_no_deferred_lighting = 0;
int Cmdline_aniso_level = 0;
// Game Speed related
cmdline_parm cache_bitmaps_arg("-cache_bitmaps", NULL, AT_NONE); // Cmdline_cache_bitmaps
cmdline_parm no_fpscap("-no_fps_capping", "Don't limit frames-per-second", AT_NONE); // Cmdline_NoFPSCap
cmdline_parm no_vsync_arg("-no_vsync", NULL, AT_NONE); // Cmdline_no_vsync
int Cmdline_cache_bitmaps = 0; // caching of bitmaps between missions (faster loads, can hit swap on reload with <512 Meg RAM though) - taylor
int Cmdline_NoFPSCap = 0; // Disable FPS capping - kazan
int Cmdline_no_vsync = 0;
@@ -393,11 +398,9 @@ int Cmdline_stretch_menu = 0;
// Audio related
cmdline_parm query_speech_arg("-query_speech", NULL, AT_NONE); // Cmdline_query_speech
cmdline_parm snd_preload_arg("-snd_preload", NULL, AT_NONE); // Cmdline_snd_preload
cmdline_parm voice_recognition_arg("-voicer", NULL, AT_NONE); // Cmdline_voice_recognition
int Cmdline_query_speech = 0;
int Cmdline_snd_preload = 0; // preload game sounds during mission load
int Cmdline_voice_recognition = 0;
int Cmdline_no_enhanced_sound = 0;
@@ -472,6 +475,7 @@ cmdline_parm dis_weapons("-dis_weapons", NULL, AT_NONE); // Cmdline_dis_weapons
cmdline_parm noparseerrors_arg("-noparseerrors", NULL, AT_NONE); // Cmdline_noparseerrors -- turns off parsing errors -C
cmdline_parm extra_warn_arg("-extra_warn", "Enable 'extra' warnings", AT_NONE); // Cmdline_extra_warn
cmdline_parm fps_arg("-fps", NULL, AT_NONE); // Cmdline_show_fps
cmdline_parm bmpmanusage_arg("-bmpmanusage", NULL, AT_NONE); // Cmdline_bmpman_usage
cmdline_parm pos_arg("-pos", NULL, AT_NONE); // Cmdline_show_pos
cmdline_parm stats_arg("-stats", NULL, AT_NONE); // Cmdline_show_stats
cmdline_parm save_render_targets_arg("-save_render_target", NULL, AT_NONE); // Cmdline_save_render_targets
@@ -497,11 +501,13 @@ char *Cmdline_start_mission = NULL;
int Cmdline_old_collision_sys = 0;
int Cmdline_dis_collisions = 0;
int Cmdline_dis_weapons = 0;
bool Cmdline_output_sexp_info = false;
int Cmdline_noparseerrors = 0;
#ifdef Allow_NoWarn
int Cmdline_nowarn = 0; // turn warnings off in FRED
#endif
int Cmdline_extra_warn = 0;
int Cmdline_bmpman_usage = 0;
int Cmdline_show_pos = 0;
int Cmdline_show_stats = 0;
int Cmdline_save_render_targets = 0;
@@ -522,7 +528,7 @@ bool Cmdline_show_video_info = false;
bool Cmdline_debug_window = false;
// Other
cmdline_parm get_flags_arg("-get_flags", "Output the launcher flags file", AT_NONE);
cmdline_parm get_flags_arg("-get_flags", "Output the launcher flags file", AT_STRING);
cmdline_parm output_sexp_arg("-output_sexps", NULL, AT_NONE); //WMC - outputs all SEXPs to sexps.html
cmdline_parm output_scripting_arg("-output_scripting", NULL, AT_NONE); //WMC
@@ -535,6 +541,9 @@ cmdline_parm deprecated_tbp_arg("-tbp", "Deprecated", AT_NONE);
cmdline_parm deprecated_jpgtga_arg("-jpgtga", "Deprecated", AT_NONE);
cmdline_parm deprecated_htl_arg("-nohtl", "Deprecated", AT_NONE);
cmdline_parm deprecated_brieflighting_arg("-brief_lighting", "Deprecated", AT_NONE);
cmdline_parm deprecated_sndpreload_arg("-snd_preload", "Deprecated", AT_NONE);
cmdline_parm deprecated_missile_lighting_arg("-missile_lighting", "Deprecated", AT_NONE);
cmdline_parm deprecated_cache_bitmaps_arg("-cache_bitmaps", "Deprecated", AT_NONE);
int Cmdline_deprecated_spec = 0;
int Cmdline_deprecated_glow = 0;
@@ -544,6 +553,8 @@ int Cmdline_deprecated_tbp = 0;
int Cmdline_deprecated_jpgtga = 0;
int Cmdline_deprecated_nohtl = 0;
bool Cmdline_deprecated_brief_lighting = 0;
bool Cmdline_deprecated_missile_lighting = false;
bool Cmdline_deprecated_cache_bitmaps = false;
#ifndef NDEBUG
// NOTE: this assumes that os_init() has already been called but isn't a fatal error if it hasn't
@@ -609,6 +620,15 @@ void cmdline_debug_print_cmdline()
{
mprintf(("Deprecated flag '-brief_lighting' found. Please remove from your cmdline.\n"));
}
if (Cmdline_deprecated_missile_lighting)
{
mprintf(("Deprecated flag '-missile_lighting' found. Please remove from your cmdline.\n"));
}
if (Cmdline_deprecated_cache_bitmaps) {
mprintf(("Deprecated flag '-cache_bitmaps' found. Please remove from your cmdline.\n"));
}
}
#endif
@@ -801,7 +821,7 @@ void os_validate_parms(int argc, char *argv[])
size_t sp = 0;
for (parmp = GET_FIRST(&Parm_list); parmp !=END_OF_LIST(&Parm_list); parmp = GET_NEXT(parmp) ) {
// don't output deprecated flags
if (stricmp("deprecated", parmp->help)) {
if (stricmp("deprecated", parmp->help) != 0) {
sp = strlen(parmp->name);
if (parmp->arg_type != AT_NONE) {
atp = strlen(cmdline_arg_types[parmp->arg_type]);
@@ -1143,11 +1163,14 @@ char *cmdline_parm::str()
return args;
}
bool cmdline_parm::has_param() {
return args != nullptr;
}
#ifdef SCP_UNIX
// Return a vector with all filesystem names of "parent/dir" relative to parent.
// dir must not contain a slash.
static SCP_vector<SCP_string> unix_get_single_dir_names(SCP_string parent, SCP_string dir)
static SCP_vector<SCP_string> unix_get_single_dir_names(const SCP_string& parent, const SCP_string& dir)
{
SCP_vector<SCP_string> ret;
@@ -1170,7 +1193,7 @@ static SCP_vector<SCP_string> unix_get_single_dir_names(SCP_string parent, SCP_s
// Return a vector with all filesystem names of "parent/dir" relative to parent.
// Recurses to deal with slashes in dir.
static SCP_vector<SCP_string> unix_get_dir_names(SCP_string parent, SCP_string dir)
static SCP_vector<SCP_string> unix_get_dir_names(const SCP_string& parent, const SCP_string& dir)
{
size_t slash = dir.find_first_of("/\\");
@@ -1241,6 +1264,257 @@ static void handle_unix_modlist(char **modlist, size_t *len)
// external entry point into this modules
static json_t* json_get_v1() {
auto root = json_object();
{
auto version_obj = json_object();
json_object_set_new(version_obj, "full", json_string(FS_VERSION_FULL));
json_object_set_new(version_obj, "major", json_integer(FS_VERSION_MAJOR));
json_object_set_new(version_obj, "minor", json_integer(FS_VERSION_MINOR));
json_object_set_new(version_obj, "build", json_integer(FS_VERSION_BUILD));
json_object_set_new(version_obj, "has_revision", json_boolean(FS_VERSION_HAS_REVIS));
json_object_set_new(version_obj, "revision", json_integer(FS_VERSION_REVIS));
json_object_set_new(version_obj, "revision_str", json_string(FS_VERSION_REVIS_STR));
json_object_set_new(root, "version", version_obj);
}
{
auto easy_array = json_array();
for (auto& easy_flag : easy_flags) {
json_array_append_new(easy_array, json_string(easy_flag.name));
}
json_object_set_new(root, "easy_flags", easy_array);
}
{
auto flags_array = json_array();
for (auto& flag : exe_params) {
auto flag_obj = json_object();
json_object_set_new(flag_obj, "name", json_string(flag.name));
json_object_set_new(flag_obj, "description", json_string(flag.desc));
json_object_set_new(flag_obj, "fso_only", json_boolean(flag.fso_only));
json_object_set_new(flag_obj, "on_flags", json_integer(flag.on_flags));
json_object_set_new(flag_obj, "off_flags", json_integer(flag.off_flags));
json_object_set_new(flag_obj, "type", json_string(flag.type));
json_object_set_new(flag_obj, "web_url", json_string(flag.web_url));
json_array_append_new(flags_array, flag_obj);
}
json_object_set_new(root, "flags", flags_array);
}
{
auto caps_array = json_array();
json_array_append_new(caps_array, json_string("OpenAL"));
json_array_append_new(caps_array, json_string("No D3D"));
json_array_append_new(caps_array, json_string("New Sound"));
json_array_append_new(caps_array, json_string("SDL"));
json_object_set_new(root, "caps", caps_array);
}
{
auto voices_array = json_array();
auto voices = speech_enumerate_voices();
for (auto& voice : voices) {
json_array_append_new(voices_array, json_string(voice.c_str()));
}
json_object_set_new(root, "voices", voices_array);
}
{
auto resolution_array = json_array();
auto displays = gr_enumerate_displays();
for (auto& display : displays) {
auto display_obj = json_object();
json_object_set_new(display_obj, "index", json_integer(display.index));
json_object_set_new(display_obj, "name", json_string(display.name.c_str()));
json_object_set_new(display_obj, "x", json_integer(display.x));
json_object_set_new(display_obj, "y", json_integer(display.y));
json_object_set_new(display_obj, "width", json_integer(display.width));
json_object_set_new(display_obj, "height", json_integer(display.height));
auto modes_array = json_array();
for (auto& mode : display.video_modes) {
auto mode_obj = json_object();
json_object_set_new(mode_obj, "x", json_integer(mode.width));
json_object_set_new(mode_obj, "y", json_integer(mode.height));
json_object_set_new(mode_obj, "bits", json_integer(mode.bit_depth));
json_array_append_new(modes_array, mode_obj);
}
json_object_set_new(display_obj, "modes", modes_array);
json_array_append_new(resolution_array, display_obj);
}
json_object_set_new(root, "displays", resolution_array);
}
{
auto openal_obj = json_object();
auto openal_info = openal_get_platform_information();
json_object_set_new(openal_obj, "version_major", json_integer(openal_info.version_major));
json_object_set_new(openal_obj, "version_minor", json_integer(openal_info.version_minor));
json_object_set(openal_obj, "default_playback", json_string(openal_info.default_playback_device.c_str()));
json_object_set(openal_obj, "default_capture", json_string(openal_info.default_capture_device.c_str()));
{
auto playback_array = json_array();
for (auto& device : openal_info.playback_devices) {
json_array_append_new(playback_array, json_string(device.c_str()));
}
json_object_set_new(openal_obj, "playback_devices", playback_array);
}
{
auto capture_array = json_array();
for (auto& device : openal_info.capture_devices) {
json_array_append_new(capture_array, json_string(device.c_str()));
}
json_object_set_new(openal_obj, "capture_devices", capture_array);
}
{
auto efx_support_obj = json_object();
for (auto& pair : openal_info.efx_support) {
json_object_set_new(efx_support_obj, pair.first.c_str(), json_boolean(pair.second));
}
json_object_set_new(openal_obj, "efx_support", efx_support_obj);
}
json_object_set_new(root, "openal", openal_obj);
}
{
auto joystick_array = json_array();
auto joysticks = io::joystick::getJoystickInformations();
for (auto& info : joysticks) {
auto joystick_obj = json_object();
json_object_set_new(joystick_obj, "name", json_string(info.name.c_str()));
json_object_set_new(joystick_obj, "guid", json_string(info.guid.c_str()));
json_object_set_new(joystick_obj, "num_axes", json_integer(info.num_axes));
json_object_set_new(joystick_obj, "num_balls", json_integer(info.num_balls));
json_object_set_new(joystick_obj, "num_buttons", json_integer(info.num_buttons));
json_object_set_new(joystick_obj, "num_hats", json_integer(info.num_hats));
json_object_set_new(joystick_obj, "is_haptic", json_boolean(info.is_haptic));
json_array_append_new(joystick_array, joystick_obj);
}
json_object_set_new(root, "joysticks", joystick_array);
}
{
json_object_set_new(root, "pref_path", json_string(os_get_config_path().c_str()));
}
return root;
}
static void write_flags_file() {
FILE *fp = fopen("flags.lch","w");
if (fp == NULL) {
os::dialogs::Message(os::dialogs::MESSAGEBOX_ERROR, "Error creating flag list for launcher");
return;
}
int easy_flag_size = sizeof(EasyFlag);
int flag_size = sizeof(Flag);
int num_easy_flags = sizeof(easy_flags) / easy_flag_size;
int num_flags = sizeof(exe_params) / flag_size;
// Launcher will check its using structures of the same size
fwrite(&easy_flag_size, sizeof(int), 1, fp);
fwrite(&flag_size, sizeof(int), 1, fp);
fwrite(&num_easy_flags, sizeof(int), 1, fp);
fwrite(&easy_flags, sizeof(easy_flags), 1, fp);
fwrite(&num_flags, sizeof(int), 1, fp);
fwrite(&exe_params, sizeof(exe_params), 1, fp);
{
// cheap and bastardly cap check for builds
// (needs to be compatible with older Launchers, which means having
// this implies an OpenAL build for old Launchers)
ubyte build_caps = 0;
/* portej05 defined this always */
build_caps |= BUILD_CAPS_OPENAL;
build_caps |= BUILD_CAPS_NO_D3D;
build_caps |= BUILD_CAPS_NEW_SND;
build_caps |= BUILD_CAPS_SDL;
fwrite(&build_caps, 1, 1, fp);
}
fflush(fp);
fclose(fp);
}
static flag_output_type get_flags_output_type() {
Assertion(get_flags_arg.found(), "This function is only valid if -get_flags is present!");
if (!get_flags_arg.has_param()) {
// Default to binary mode
return flag_output_type::Binary;
}
SCP_string type(get_flags_arg.str());
if (type == "binary") {
return flag_output_type::Binary;
} else if (type == "json_v1") {
return flag_output_type::Json_V1;
} else {
// This is supposed to make it easy for the launcher to recognize an unsupported type
printf("OUTPUT TYPE NOT SUPPORTED!\n");
// Default to json in this case so that no flags.lch file is created
return flag_output_type::Json_V1;
}
}
static void write_flags() {
auto type = get_flags_output_type();
switch(type) {
case flag_output_type::Binary:
write_flags_file();
break;
case flag_output_type::Json_V1:
json_t* root = json_get_v1();
json_dumpf(root, stdout, JSON_INDENT(4));
json_decref(root);
break;
}
}
bool SetCmdlineParams()
// Sets externed variables used for communication cmdline information
{
@@ -1248,47 +1522,7 @@ bool SetCmdlineParams()
// DO THIS FIRST to avoid unrecognized flag warnings when just getting flag file
if ( get_flags_arg.found() ) {
FILE *fp = fopen("flags.lch","w");
if (fp == NULL) {
os::dialogs::Message(os::dialogs::MESSAGEBOX_ERROR, "Error creating flag list for launcher");
return false;
}
int easy_flag_size = sizeof(EasyFlag);
int flag_size = sizeof(Flag);
int num_easy_flags = sizeof(easy_flags) / easy_flag_size;
int num_flags = sizeof(exe_params) / flag_size;
// Launcher will check its using structures of the same size
fwrite(&easy_flag_size, sizeof(int), 1, fp);
fwrite(&flag_size, sizeof(int), 1, fp);
fwrite(&num_easy_flags, sizeof(int), 1, fp);
fwrite(&easy_flags, sizeof(easy_flags), 1, fp);
fwrite(&num_flags, sizeof(int), 1, fp);
fwrite(&exe_params, sizeof(exe_params), 1, fp);
{
// cheap and bastardly cap check for builds
// (needs to be compatible with older Launchers, which means having
// this implies an OpenAL build for old Launchers)
ubyte build_caps = 0;
/* portej05 defined this always */
build_caps |= BUILD_CAPS_OPENAL;
build_caps |= BUILD_CAPS_NO_D3D;
build_caps |= BUILD_CAPS_NEW_SND;
build_caps |= BUILD_CAPS_SDL;
fwrite(&build_caps, 1, 1, fp);
}
fflush(fp);
fclose(fp);
write_flags();
return false;
}
@@ -1541,6 +1775,11 @@ bool SetCmdlineParams()
Show_framerate = 1;
}
if (bmpmanusage_arg.found())
{
Cmdline_bmpman_usage = 1;
}
if(pos_arg.found())
{
Cmdline_show_pos = 1;
@@ -1667,7 +1906,7 @@ bool SetCmdlineParams()
Output_scripting_meta = true;
if (output_sexp_arg.found() ) {
output_sexps("sexps.html");
Cmdline_output_sexp_info = true;
}
if ( no_pbo_arg.found() )
@@ -1721,11 +1960,6 @@ bool SetCmdlineParams()
}
#endif
if ( snd_preload_arg.found() )
{
Cmdline_snd_preload = 1;
}
if ( env.found() ) {
Cmdline_env = 0;
}
@@ -1734,10 +1968,6 @@ bool SetCmdlineParams()
Cmdline_ballistic_gauge = 1;
}
if ( cache_bitmaps_arg.found() ) {
Cmdline_cache_bitmaps = 1;
}
if(old_collision_system.found())
Cmdline_old_collision_sys = 1;
@@ -1764,9 +1994,6 @@ bool SetCmdlineParams()
if ( rearm_timer_arg.found() )
Cmdline_rearm_timer = 1;
if ( missile_lighting_arg.found() )
Cmdline_missile_lighting = 1;
if ( save_render_targets_arg.found() )
Cmdline_save_render_targets = 1;
@@ -1801,11 +2028,6 @@ bool SetCmdlineParams()
Cmdline_fb_thrusters = true;
}
if ( no_batching.found() )
{
Cmdline_no_batching = true;
}
if ( postprocess_arg.found() )
{
Cmdline_postprocess = 1;
@@ -1841,6 +2063,11 @@ bool SetCmdlineParams()
Cmdline_no_deferred_lighting = 1;
}
if (anisotropy_level_arg.found())
{
Cmdline_aniso_level = anisotropy_level_arg.get_int();
}
if (frame_profile_write_file.found())
{
Cmdline_profile_write_file = true;
@@ -1926,6 +2153,15 @@ bool SetCmdlineParams()
Cmdline_deprecated_brief_lighting = 1;
}
if (deprecated_missile_lighting_arg.found())
{
Cmdline_deprecated_missile_lighting = true;
}
if (deprecated_cache_bitmaps_arg.found()) {
Cmdline_deprecated_cache_bitmaps = true;
}
return true;
}
+3 -4
View File
@@ -62,7 +62,6 @@ extern float static_point_factor;
extern float static_tube_factor;
extern int Cmdline_ambient_factor;
extern int Cmdline_env;
extern int Cmdline_missile_lighting;
extern int Cmdline_glow;
extern int Cmdline_nomotiondebris;
extern int Cmdline_noscalevid; // disables fit-to-window for movies - taylor
@@ -77,13 +76,12 @@ extern bool Cmdline_fxaa;
extern int Cmdline_fxaa_preset;
extern bool Cmdline_fb_explosions;
extern bool Cmdline_fb_thrusters;
extern bool Cmdline_no_batching;
extern int Cmdline_shadow_quality;
extern int Cmdline_no_deferred_lighting;
extern int Cmdline_no_emissive;
extern int Cmdline_aniso_level;
// Game Speed related
extern int Cmdline_cache_bitmaps;
extern int Cmdline_NoFPSCap;
extern int Cmdline_no_vsync;
@@ -104,7 +102,6 @@ extern int Cmdline_stretch_menu;
// Audio related
extern int Cmdline_query_speech;
extern int Cmdline_snd_preload;
extern int Cmdline_voice_recognition;
extern int Cmdline_no_enhanced_sound;
@@ -146,8 +143,10 @@ extern char *Cmdline_start_mission;
extern int Cmdline_old_collision_sys;
extern int Cmdline_dis_collisions;
extern int Cmdline_dis_weapons;
extern bool Cmdline_output_sexp_info;
extern int Cmdline_noparseerrors;
extern int Cmdline_extra_warn;
extern int Cmdline_bmpman_usage;
extern int Cmdline_show_pos;
extern int Cmdline_show_stats;
extern int Cmdline_save_render_targets;
+1 -1
View File
@@ -92,7 +92,7 @@ void cmeasure_maybe_alert_success(object *objp)
if ( objp->parent == OBJ_INDEX(Player_obj) ) {
hud_start_text_flash(XSTR("Evaded", 1430), 800);
snd_play(&Snds[ship_get_sound(Player_obj, SND_MISSILE_EVADED_POPUP)]);
snd_play(gamesnd_get_game_sound(ship_get_sound(Player_obj, GameSounds::MISSILE_EVADED_POPUP)));
} else if ( Objects[objp->parent].flags[Object::Object_Flags::Player_ship] ) {
send_countermeasure_success_packet( objp->parent );
}
+47 -47
View File
@@ -356,7 +356,7 @@ DCF_BOOL(show_controls_info, Show_controls_info);
static int Axes_origin[JOY_NUM_AXES];
static int joy_get_unscaled_reading(int raw, int axn)
static int joy_get_unscaled_reading(int raw)
{
int rng;
@@ -615,7 +615,7 @@ int control_config_undo_last()
int i, z, tab;
if (!Config_item_undo) {
gamesnd_play_iface(SND_GENERAL_FAIL);
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
return -1;
}
@@ -664,7 +664,7 @@ int control_config_undo_last()
free_undo_block();
control_config_conflict_check();
control_config_list_prepare();
gamesnd_play_iface(SND_USER_SELECT);
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
return 0;
}
@@ -715,7 +715,7 @@ int control_config_remove_binding()
config_item_undo *ptr;
if (Selected_line < 0) {
gamesnd_play_iface(SND_GENERAL_FAIL);
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
return -1;
}
@@ -723,7 +723,7 @@ int control_config_remove_binding()
if (z & JOY_AXIS) {
z &= ~JOY_AXIS;
if (Axis_map_to[z] < 0) {
gamesnd_play_iface(SND_GENERAL_FAIL);
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
return -1;
}
@@ -731,13 +731,13 @@ int control_config_remove_binding()
Axis_map_to[z] = -1;
control_config_conflict_check();
control_config_list_prepare();
gamesnd_play_iface(SND_USER_SELECT);
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
Selected_item = -1;
return 0;
}
if ((Control_config[z].joy_id < 0) && (Control_config[z].key_id < 0)) {
gamesnd_play_iface(SND_GENERAL_FAIL);
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
return -1;
}
@@ -755,7 +755,7 @@ int control_config_remove_binding()
control_config_conflict_check();
control_config_list_prepare();
gamesnd_play_iface(SND_USER_SELECT);
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
Selected_item = -1;
return 0;
}
@@ -766,7 +766,7 @@ int control_config_clear_other()
config_item_undo *ptr;
if (Selected_line < 0) {
gamesnd_play_iface(SND_GENERAL_FAIL);
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
return -1;
}
@@ -776,7 +776,7 @@ int control_config_clear_other()
z &= ~JOY_AXIS;
if (Axis_map_to[z] < 0) {
gamesnd_play_iface(SND_GENERAL_FAIL);
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
return -1;
}
@@ -787,7 +787,7 @@ int control_config_clear_other()
}
if (!total) {
gamesnd_play_iface(SND_GENERAL_FAIL);
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
return -1;
}
@@ -808,7 +808,7 @@ int control_config_clear_other()
}
control_config_conflict_check();
control_config_list_prepare();
gamesnd_play_iface(SND_USER_SELECT);
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
return 0;
}
@@ -820,12 +820,12 @@ int control_config_clear_other()
}
}
if (!total) {
gamesnd_play_iface(SND_GENERAL_FAIL);
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
return -1;
}
if ((Control_config[z].joy_id < 0) && (Control_config[z].key_id < 0)) {
gamesnd_play_iface(SND_GENERAL_FAIL);
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
return -1;
}
@@ -850,7 +850,7 @@ int control_config_clear_other()
}
control_config_conflict_check();
control_config_list_prepare();
gamesnd_play_iface(SND_USER_SELECT);
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
return 0;
}
@@ -867,7 +867,7 @@ int control_config_clear_all()
}
if (!total) {
gamesnd_play_iface(SND_GENERAL_FAIL);
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
return -1;
}
@@ -888,7 +888,7 @@ int control_config_clear_all()
control_config_conflict_check();
control_config_list_prepare();
gamesnd_play_iface(SND_RESET_PRESSED);
gamesnd_play_iface(InterfaceSounds::RESET_PRESSED);
return 0;
}
@@ -945,7 +945,7 @@ int control_config_do_reset()
}
if (!total && !cycling_presets) {
gamesnd_play_iface(SND_GENERAL_FAIL);
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
return -1;
}
@@ -981,7 +981,7 @@ int control_config_do_reset()
control_config_conflict_check();
control_config_list_prepare();
gamesnd_play_iface(SND_RESET_PRESSED);
gamesnd_play_iface(InterfaceSounds::RESET_PRESSED);
return 0;
}
@@ -1026,10 +1026,10 @@ void control_config_scroll_screen_up()
}
Selected_item = -1;
gamesnd_play_iface(SND_SCROLL);
gamesnd_play_iface(InterfaceSounds::SCROLL);
} else {
gamesnd_play_iface(SND_GENERAL_FAIL);
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
}
}
@@ -1042,10 +1042,10 @@ void control_config_scroll_line_up()
}
Selected_item = -1;
gamesnd_play_iface(SND_SCROLL);
gamesnd_play_iface(InterfaceSounds::SCROLL);
} else {
gamesnd_play_iface(SND_GENERAL_FAIL);
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
}
}
@@ -1059,10 +1059,10 @@ void control_config_scroll_screen_down()
}
Selected_item = -1;
gamesnd_play_iface(SND_SCROLL);
gamesnd_play_iface(InterfaceSounds::SCROLL);
} else {
gamesnd_play_iface(SND_GENERAL_FAIL);
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
}
}
@@ -1076,10 +1076,10 @@ void control_config_scroll_line_down()
}
Selected_item = -1;
gamesnd_play_iface(SND_SCROLL);
gamesnd_play_iface(InterfaceSounds::SCROLL);
} else {
gamesnd_play_iface(SND_GENERAL_FAIL);
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
}
}
@@ -1091,13 +1091,13 @@ void control_config_toggle_modifier(int bit)
Assert(!(z & JOY_AXIS));
k = Control_config[z].key_id;
if (k < 0) {
gamesnd_play_iface(SND_GENERAL_FAIL);
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
return;
}
control_config_bind_key(z, k ^ bit);
control_config_conflict_check();
gamesnd_play_iface(SND_USER_SELECT);
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
}
void control_config_toggle_invert()
@@ -1118,7 +1118,7 @@ void control_config_do_bind()
game_flush();
// if ((Selected_line < 0) || (Cc_lines[Selected_line].cc_index & JOY_AXIS)) {
if (Selected_line < 0) {
gamesnd_play_iface(SND_GENERAL_FAIL);
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
return;
}
@@ -1142,7 +1142,7 @@ void control_config_do_bind()
Search_mode = 0;
Last_key = -1;
Axis_override = -1;
gamesnd_play_iface(SND_USER_SELECT);
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
}
void control_config_do_search()
@@ -1166,7 +1166,7 @@ void control_config_do_search()
Binding_mode = 0;
Search_mode = 1;
Last_key = -1;
gamesnd_play_iface(SND_USER_SELECT);
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
}
void control_config_do_cancel(int fail = 0)
@@ -1189,9 +1189,9 @@ void control_config_do_cancel(int fail = 0)
Binding_mode = Search_mode = 0;
if (fail){
gamesnd_play_iface(SND_GENERAL_FAIL);
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
} else {
gamesnd_play_iface(SND_USER_SELECT);
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
}
}
@@ -1206,13 +1206,13 @@ int control_config_accept()
}
if (i < NUM_TABS) {
gamesnd_play_iface(SND_GENERAL_FAIL);
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
return -1;
}
hud_squadmsg_save_keys(); // rebuild map for saving/restoring keys in squadmsg mode
gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
gamesnd_play_iface(SND_COMMIT_PRESSED);
gamesnd_play_iface(InterfaceSounds::COMMIT_PRESSED);
return 0;
}
@@ -1237,7 +1237,7 @@ void control_config_button_pressed(int n)
Tab = n;
Scroll_offset = Selected_line = 0;
control_config_list_prepare();
gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
gamesnd_play_iface(InterfaceSounds::SCREEN_MODE_PRESSED);
break;
case BIND_BUTTON:
@@ -1250,17 +1250,17 @@ void control_config_button_pressed(int n)
case SHIFT_TOGGLE:
control_config_toggle_modifier(KEY_SHIFTED);
gamesnd_play_iface(SND_USER_SELECT);
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
break;
case ALT_TOGGLE:
control_config_toggle_modifier(KEY_ALTED);
gamesnd_play_iface(SND_USER_SELECT);
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
break;
case INVERT_AXIS:
control_config_toggle_invert();
gamesnd_play_iface(SND_USER_SELECT);
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
break;
case SCROLL_UP_BUTTON:
@@ -1281,7 +1281,7 @@ void control_config_button_pressed(int n)
case HELP_BUTTON:
launch_context_help();
gamesnd_play_iface(SND_HELP_PRESSED);
gamesnd_play_iface(InterfaceSounds::HELP_PRESSED);
break;
case RESET_BUTTON:
@@ -1799,7 +1799,7 @@ void control_config_do_frame(float frametime)
Scroll_offset = Selected_line = 0;
control_config_list_prepare();
gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
gamesnd_play_iface(InterfaceSounds::SCREEN_MODE_PRESSED);
break;
case KEY_TAB: // activate next tab
@@ -1810,7 +1810,7 @@ void control_config_do_frame(float frametime)
Scroll_offset = Selected_line = 0;
control_config_list_prepare();
gamesnd_play_iface(SND_SCREEN_MODE_PRESSED);
gamesnd_play_iface(InterfaceSounds::SCREEN_MODE_PRESSED);
break;
case KEY_LEFT:
@@ -1825,7 +1825,7 @@ void control_config_do_frame(float frametime)
}
}
gamesnd_play_iface(SND_SCROLL);
gamesnd_play_iface(InterfaceSounds::SCROLL);
break;
case KEY_RIGHT:
@@ -1837,7 +1837,7 @@ void control_config_do_frame(float frametime)
} else if (Selected_item > 1) {
Selected_item = -1;
}
gamesnd_play_iface(SND_SCROLL);
gamesnd_play_iface(InterfaceSounds::SCROLL);
break;
case KEY_BACKSP: // undo
@@ -1873,7 +1873,7 @@ void control_config_do_frame(float frametime)
Selected_item = 1;
}
gamesnd_play_iface(SND_USER_SELECT);
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
}
if (List_buttons[i].double_clicked()) {
@@ -2379,7 +2379,7 @@ void control_get_axes_readings(int *h, int *p, int *b, int *ta, int *tr)
*ta = 0;
if (Axis_map_to[3] >= 0) {
*ta = joy_get_unscaled_reading(axes_values[Axis_map_to[3]], Axis_map_to[3]);
*ta = joy_get_unscaled_reading(axes_values[Axis_map_to[3]]);
}
*tr = 0;
+5 -5
View File
@@ -7,8 +7,8 @@
*
*/
#include <stdio.h>
#include <stdarg.h>
#include <cstdio>
#include <cstdarg>
#include "cfile/cfile.h"
#include "controlconfig/controlsconfig.h"
@@ -201,7 +201,7 @@ config_item Control_config[CCFG_MAX + 1] = {
const char *Scan_code_text_german[] = {
"", "Esc", "1", "2", "3", "4", "5", "6",
"7", "8", "9", "0", "Akzent '", "Eszett", "R\x81""cktaste", "Tab",
"7", "8", "9", "0", "Akzent '", "Eszett", "R\x81""cktaste", "Tab", // NOLINT
"Q", "W", "E", "R", "T", "Z", "U", "I",
"O", "P", "\x9A", "+", "Eingabe", "Strg Links", "A", "S",
@@ -251,8 +251,8 @@ const char *Joy_button_text_german[] = {
};
const char *Scan_code_text_french[] = {
"", "\x90""chap", "1", "2", "3", "4", "5", "6",
"7", "8", "9", "0", "-", "=", "Fl\x82""che Ret.", "Tab",
"", "\x90""chap", "1", "2", "3", "4", "5", "6", // NOLINT
"7", "8", "9", "0", "-", "=", "Fl\x82""che Ret.", "Tab", // NOLINT
"Q", "W", "E", "R", "T", "Y", "U", "I",
"O", "P", "[", "]", "Entr\x82""e", "Ctrl Gauche", "A", "S",
+27
View File
@@ -3,6 +3,12 @@
#include <memory>
namespace cutscene {
FrameSize::FrameSize(size_t in_width, size_t in_height, size_t in_stride)
: width(in_width), height(in_height), stride(in_stride)
{
}
FrameSize::FrameSize() = default;
Decoder::Decoder() : m_decoding(true) {
}
@@ -14,6 +20,11 @@ bool Decoder::tryPopAudioData(AudioFramePtr& out) {
return res == queue_op_status::success;
}
bool Decoder::tryPopSubtitleData(SubtitleFramePtr& out) {
auto res = m_subtitleQueue->try_pull_front(out);
return res == queue_op_status::success;
}
bool Decoder::tryPopVideoFrame(VideoFramePtr& out) {
auto res = m_videoQueue->try_pull_front(out);
return res == queue_op_status::success;
@@ -24,6 +35,7 @@ void Decoder::initializeQueues(size_t queueSize) {
m_videoQueue.reset(new sync_bounded_queue<VideoFramePtr>(m_queueSize));
m_audioQueue.reset(new sync_bounded_queue<AudioFramePtr>(m_queueSize));
m_subtitleQueue.reset(new sync_bounded_queue<SubtitleFramePtr>(m_queueSize));
}
void Decoder::stopDecoder() {
@@ -31,6 +43,7 @@ void Decoder::stopDecoder() {
m_videoQueue->close();
m_audioQueue->close();
m_subtitleQueue->close();
}
bool Decoder::canPushAudioData() {
@@ -48,6 +61,20 @@ void Decoder::pushAudioData(AudioFramePtr&& data) {
}
}
bool Decoder::canPushSubtitleData() {
return !isSubtitleQueueFull();
}
void Decoder::pushSubtitleData(SubtitleFramePtr&& data) {
Assertion(data, "Invalid audio data passed!");
try {
m_subtitleQueue->push_back(std::move(data));
}
catch (sync_queue_is_closed&) {
// Ignore
}
}
bool Decoder::canPushVideoData() {
return !isVideoQueueFull();
}
+43 -13
View File
@@ -10,28 +10,26 @@ struct FrameSize {
size_t width = 0;
size_t height = 0;
size_t stride = 0;
FrameSize(size_t width, size_t in_height, size_t in_stride);
FrameSize();
};
class VideoFrame {
protected:
VideoFrame() {}
VideoFrame() = default;
public:
virtual ~VideoFrame() {}
public:
virtual ~VideoFrame() = default;
double frameTime = -1.0;
int id = -1;
FrameSize ySize;
FrameSize uvSize;
virtual size_t getPlaneNumber() = 0;
struct DataPointers {
ubyte* y;
ubyte* u;
ubyte* v;
};
virtual FrameSize getPlaneSize(size_t plane) = 0;
virtual DataPointers getDataPointers() = 0;
virtual void* getPlaneData(size_t plane) = 0;
};
/**
@@ -43,10 +41,19 @@ using FramePtr = std::unique_ptr<T>;
typedef std::unique_ptr<VideoFrame> VideoFramePtr;
enum class FramePixelFormat {
Invalid,
YUV420,
BGR,
BGRA
};
struct MovieProperties {
FrameSize size;
float fps = -1.0f;
FramePixelFormat pixelFormat = FramePixelFormat::Invalid;
};
struct AudioFrame {
@@ -58,6 +65,14 @@ struct AudioFrame {
};
typedef std::unique_ptr<AudioFrame> AudioFramePtr;
struct SubtitleFrame {
double displayStartTime = -1.0;
double displayEndTime = -1.0;
SCP_string text;
};
typedef std::unique_ptr<SubtitleFrame> SubtitleFramePtr;
/**
* @brief Abstract class for decoding a video or audio stream
*
@@ -68,6 +83,7 @@ class Decoder {
private:
std::unique_ptr<sync_bounded_queue<VideoFramePtr>> m_videoQueue;
std::unique_ptr<sync_bounded_queue<AudioFramePtr>> m_audioQueue;
std::unique_ptr<sync_bounded_queue<SubtitleFramePtr>> m_subtitleQueue;
bool m_decoding;
size_t m_queueSize = 0;
@@ -96,7 +112,7 @@ class Decoder {
* @brief Returns the properties of the video
* @return The properties
*/
virtual MovieProperties getProperties() = 0;
virtual MovieProperties getProperties() const = 0;
/**
* @brief Starts decoding the video
@@ -107,7 +123,9 @@ class Decoder {
* @brief Determines if the video has audio
* @return @c true if audio is included in the video
*/
virtual bool hasAudio() = 0;
virtual bool hasAudio() const = 0;
virtual bool hasSubtitles() const = 0;
/**
* @brief Ends decoding of the video file
@@ -122,6 +140,14 @@ class Decoder {
bool tryPopAudioData(AudioFramePtr&);
bool isSubtitleQueueFull() { return m_subtitleQueue->size() == m_queueSize; }
bool isSubtitleFrameAvailable() { return !m_subtitleQueue->empty(); }
size_t getSubtitleQueueSize() { return m_subtitleQueue->size(); }
bool tryPopSubtitleData(SubtitleFramePtr&);
bool isVideoQueueFull() { return m_videoQueue->size() == m_queueSize; }
bool isVideoFrameAvailable() { return !m_videoQueue->empty(); }
@@ -141,6 +167,10 @@ class Decoder {
void pushAudioData(AudioFramePtr&& data);
bool canPushSubtitleData();
void pushSubtitleData(SubtitleFramePtr&& data);
bool canPushVideoData();
void pushFrameData(VideoFramePtr&& frame);
+138
View File
@@ -0,0 +1,138 @@
#include "VideoPresenter.h"
#include "graphics/matrix.h"
using namespace cutscene;
using namespace cutscene::player;
namespace {
struct movie_vertex {
vec2d pos;
vec2d uv;
};
}
namespace cutscene {
namespace player {
VideoPresenter::VideoPresenter(const MovieProperties& props) : _properties(props)
{
GR_DEBUG_SCOPE("Init video");
_planeTextureHandles.fill(-1);
auto w = static_cast<int>(props.size.width);
auto h = static_cast<int>(props.size.height);
switch (props.pixelFormat) {
case FramePixelFormat::YUV420:
_planeTextureBuffers[0].reset(new uint8_t[w * h]);
_planeTextureHandles[0] = bm_create(8, w, h, _planeTextureBuffers[0].get(), BMP_AABITMAP);
_planeTextureBuffers[1].reset(new uint8_t[w / 2 * h / 2]);
_planeTextureHandles[1] = bm_create(8, w / 2, h / 2, _planeTextureBuffers[1].get(), BMP_AABITMAP);
_planeTextureBuffers[2].reset(new uint8_t[w / 2 * h / 2]);
_planeTextureHandles[2] = bm_create(8, w / 2, h / 2, _planeTextureBuffers[2].get(), BMP_AABITMAP);
material_set_movie(&_movie_material, _planeTextureHandles[0], _planeTextureHandles[1], _planeTextureHandles[2]);
break;
case FramePixelFormat::BGR:
_planeTextureBuffers[0].reset(new uint8_t[w * h * 3]);
_planeTextureHandles[0] = bm_create(24, w, h, _planeTextureBuffers[0].get(), 0);
material_set_unlit(&_rgb_material, _planeTextureHandles[0], 1.0f, false, false);
break;
case FramePixelFormat::BGRA:
_planeTextureBuffers[0].reset(new uint8_t[w * h * 4]);
_planeTextureHandles[0] = bm_create(32, w, h, _planeTextureBuffers[0].get(), 0);
material_set_unlit(&_rgb_material, _planeTextureHandles[0], 1.0f, true, false);
break;
default:
UNREACHABLE("Unhandled enum value!");
break;
}
}
VideoPresenter::~VideoPresenter() {
GR_DEBUG_SCOPE("Deinit video");
for (auto& handle : _planeTextureHandles) {
if (handle > 0) {
bm_release(handle);
handle = -1;
}
}
}
void VideoPresenter::uploadVideoFrame(const VideoFramePtr& frame) {
GR_DEBUG_SCOPE("Update video frame");
for (size_t i = 0; i < frame->getPlaneNumber(); ++i) {
auto size = frame->getPlaneSize(i);
auto data = frame->getPlaneData(i);
memcpy(_planeTextureBuffers[i].get(), data, size.stride * size.height);
int bpp = 0;
switch (_properties.pixelFormat) {
case FramePixelFormat::YUV420:
bpp = 8;
break;
case FramePixelFormat::BGR:
bpp = 24;
break;
case FramePixelFormat::BGRA:
bpp = 32;
break;
default:
UNREACHABLE("Unhandled enum value!");
break;
}
gr_update_texture(_planeTextureHandles[i], bpp, _planeTextureBuffers[i].get(), static_cast<int>(size.width),
static_cast<int>(size.height));
}
}
void VideoPresenter::displayFrame(float x1, float y1, float x2, float y2) {
GR_DEBUG_SCOPE("Draw video frame");
movie_vertex vertex_data[4];
vertex_data[0].pos.x = x1;
vertex_data[0].pos.y = y1;
vertex_data[0].uv.x = 0.0f;
vertex_data[0].uv.y = 0.0f;
vertex_data[1].pos.x = x1;
vertex_data[1].pos.y = y2;
vertex_data[1].uv.x = 0.0f;
vertex_data[1].uv.y = 1.0f;
vertex_data[2].pos.x = x2;
vertex_data[2].pos.y = y1;
vertex_data[2].uv.x = 1.0f;
vertex_data[2].uv.y = 0.0f;
vertex_data[3].pos.x = x2;
vertex_data[3].pos.y = y2;
vertex_data[3].uv.x = 1.0f;
vertex_data[3].uv.y = 1.0f;
// Use the immediate buffer for storing our data since that is exactly what we need
auto offset = gr_add_to_immediate_buffer(sizeof(vertex_data), vertex_data);
vertex_layout layout;
layout.add_vertex_component(vertex_format_data::POSITION2, sizeof(vertex_data[0]), offsetof(movie_vertex, pos));
layout.add_vertex_component(vertex_format_data::TEX_COORD2, sizeof(vertex_data[0]), offsetof(movie_vertex, uv));
if (_properties.pixelFormat == FramePixelFormat::YUV420) {
gr_render_movie(&_movie_material, PRIM_TYPE_TRISTRIP, &layout, 4, gr_immediate_buffer_handle, offset);
} else {
gr_render_primitives(&_rgb_material, PRIM_TYPE_TRISTRIP, &layout, 0, 4, gr_immediate_buffer_handle, offset);
}
}
}
}
+39
View File
@@ -0,0 +1,39 @@
#ifndef FS2_OPEN_OPENGLVIDEOPRESENTER_H
#define FS2_OPEN_OPENGLVIDEOPRESENTER_H
#include "globalincs/pstypes.h"
#include "graphics/2d.h"
#include "graphics/material.h"
#include "cutscene/Decoder.h"
#include <memory>
namespace cutscene {
namespace player {
class VideoPresenter {
MovieProperties _properties;
std::array<int, 3> _planeTextureHandles;
std::array<std::unique_ptr<uint8_t[]>, 3> _planeTextureBuffers;
movie_material _movie_material;
material _rgb_material; // Material used when a RGB/RGBA movie is played
public:
explicit VideoPresenter(const MovieProperties& props);
// Disallow copying
VideoPresenter(const VideoPresenter&) = delete;
VideoPresenter& operator=(const VideoPresenter&) = delete;
virtual ~VideoPresenter();
void uploadVideoFrame(const VideoFramePtr& frame);
void displayFrame(float x1, float y1, float x2, float y2);
};
}
}
#endif //FS2_OPEN_OPENGLVIDEOPRESENTER_H
+12 -12
View File
@@ -286,10 +286,10 @@ void cutscenes_screen_scroll_line_up()
if (Selected_line)
{
Selected_line--;
gamesnd_play_iface(SND_SCROLL);
gamesnd_play_iface(InterfaceSounds::SCROLL);
} else
gamesnd_play_iface(SND_GENERAL_FAIL);
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
if (Selected_line < Scroll_offset)
Scroll_offset = Selected_line;
@@ -302,10 +302,10 @@ void cutscenes_screen_scroll_line_down()
if (Selected_line < (int) Cutscene_list.size() - 1)
{
Selected_line++;
gamesnd_play_iface(SND_SCROLL);
gamesnd_play_iface(InterfaceSounds::SCROLL);
} else
gamesnd_play_iface(SND_GENERAL_FAIL);
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
h = Cutscene_list_coords[gr_screen.res][3] / gr_get_font_height();
if (Selected_line >= Scroll_offset + h)
@@ -328,11 +328,11 @@ void cutscenes_screen_scroll_screen_up()
Selected_line--;
}
gamesnd_play_iface(SND_SCROLL);
gamesnd_play_iface(InterfaceSounds::SCROLL);
} else
{
gamesnd_play_iface(SND_GENERAL_FAIL);
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
}
}
@@ -349,10 +349,10 @@ void cutscenes_screen_scroll_screen_down()
Selected_line = Scroll_offset;
}
gamesnd_play_iface(SND_SCROLL);
gamesnd_play_iface(InterfaceSounds::SCROLL);
} else
{
gamesnd_play_iface(SND_GENERAL_FAIL);
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
}
}
@@ -361,17 +361,17 @@ int cutscenes_screen_button_pressed(int n)
switch (n)
{
case TECH_DATABASE_BUTTON:
gamesnd_play_iface(SND_SWITCH_SCREENS);
gamesnd_play_iface(InterfaceSounds::SWITCH_SCREENS);
gameseq_post_event(GS_EVENT_TECH_MENU);
return 1;
case SIMULATOR_BUTTON:
gamesnd_play_iface(SND_SWITCH_SCREENS);
gamesnd_play_iface(InterfaceSounds::SWITCH_SCREENS);
gameseq_post_event(GS_EVENT_SIMULATOR_ROOM);
return 1;
case CREDITS_BUTTON:
gamesnd_play_iface(SND_SWITCH_SCREENS);
gamesnd_play_iface(InterfaceSounds::SWITCH_SCREENS);
gameseq_post_event(GS_EVENT_CREDITS);
return 1;
@@ -388,7 +388,7 @@ int cutscenes_screen_button_pressed(int n)
break;
case EXIT_BUTTON:
gamesnd_play_iface(SND_COMMIT_PRESSED);
gamesnd_play_iface(InterfaceSounds::COMMIT_PRESSED);
gameseq_post_event(GS_EVENT_MAIN_MENU);
game_flush();
break;
+3
View File
@@ -55,6 +55,9 @@ int resample_convert(SwrContext* ctx, uint8_t** output,
#ifdef WITH_LIBAV
return avresample_convert(ctx, output, out_plane_size, out_samples, input, in_plane_size, in_samples);
#else
(void)out_plane_size;
(void)in_plane_size;
return swr_convert(ctx, output, out_samples, (const uint8_t**) input, in_samples);
#endif
}
+3 -3
View File
@@ -25,11 +25,11 @@ class AudioDecoder: public FFMPEGStreamDecoder<AudioFrame> {
public:
explicit AudioDecoder(DecoderStatus* status);
virtual ~AudioDecoder();
~AudioDecoder() override;
virtual void decodePacket(AVPacket* packet) SCP_OVERRIDE;
void decodePacket(AVPacket* packet) override;
virtual void finishDecoding() SCP_OVERRIDE;
void finishDecoding() override;
};
}
}
+307 -28
View File
@@ -9,6 +9,10 @@
#include "cutscene/ffmpeg/AudioDecoder.h"
#include "cutscene/ffmpeg/VideoDecoder.h"
#include "cutscene/ffmpeg/SubtitleDecoder.h"
#include "FFMPEGDecoder.h"
#include "localization/localize.h"
using namespace libs::ffmpeg;
@@ -29,15 +33,18 @@ class AVPacketScope
}
};
const char* CHECKED_EXTENSIONS[] = {
"webm",
"mp4",
"ogg",
"mve"
};
const char* CHECKED_EXTENSIONS[] = {"webm", "mp4", "ogg",
"png", // This is designed to be used with APNG animations
"mve"};
const char* CHECKED_SUBT_EXTENSIONS[] = {"srt"};
double getFrameRate(AVStream* stream, AVCodecContext* codecCtx) {
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(58, 3, 102)
auto fps = av_q2d(stream->r_frame_rate);
#else
auto fps = av_q2d(av_stream_get_r_frame_rate(stream));
#endif
if (fps < 0.000001)
{
@@ -55,23 +62,111 @@ double getFrameRate(AVStream* stream, AVCodecContext* codecCtx) {
CodecContextParameters getCodecParameters(AVStream* stream) {
CodecContextParameters paras;
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
paras.width = stream->codecpar->width;
paras.height = stream->codecpar->height;
paras.width = stream->codecpar->width;
paras.height = stream->codecpar->height;
paras.pixel_format = (AVPixelFormat)stream->codecpar->format;
paras.channel_layout = stream->codecpar->channel_layout;
paras.sample_rate = stream->codecpar->sample_rate;
paras.audio_format = (AVSampleFormat)stream->codecpar->format;
paras.sample_rate = stream->codecpar->sample_rate;
paras.audio_format = (AVSampleFormat)stream->codecpar->format;
paras.codec_id = stream->codecpar->codec_id;
#else
paras.width = stream->codec->width;
paras.height = stream->codec->height;
paras.width = stream->codec->width;
paras.height = stream->codec->height;
paras.pixel_format = stream->codec->pix_fmt;
paras.channel_layout = stream->codec->channel_layout;
paras.sample_rate = stream->codec->sample_rate;
paras.audio_format = stream->codec->sample_fmt;
paras.sample_rate = stream->codec->sample_rate;
paras.audio_format = stream->codec->sample_fmt;
paras.codec_id = stream->codec->codec_id;
#endif
return paras;
return paras;
}
SCP_string normalizeLanguage(const char* langauge_name) {
if (!stricmp(langauge_name, "eng")) {
return "English";
}
if (!stricmp(langauge_name, "ger")) {
return "German";
}
if (!stricmp(langauge_name, "spa")) {
return "Spanish";
}
// Print to log so that we can find the actual value more easily later
mprintf(("FFmpeg log: Found unknown language value '%s'!\n", langauge_name));
// Default to english for everything else
return "English";
}
/**
* @brief Given a FFmpeg pixel format returns the format it should be converted to
* @param in_fmt The input format
* @return The output format
*/
AVPixelFormat getConversionFormat(AVPixelFormat in_fmt)
{
switch (in_fmt) {
case AV_PIX_FMT_RGB24:
case AV_PIX_FMT_BGR24:
case AV_PIX_FMT_BGR8:
case AV_PIX_FMT_BGR4:
case AV_PIX_FMT_BGR4_BYTE:
case AV_PIX_FMT_RGB8:
case AV_PIX_FMT_RGB4:
case AV_PIX_FMT_RGB4_BYTE:
case AV_PIX_FMT_RGB48BE:
case AV_PIX_FMT_RGB48LE:
case AV_PIX_FMT_RGB565BE:
case AV_PIX_FMT_RGB565LE:
case AV_PIX_FMT_RGB555BE:
case AV_PIX_FMT_RGB555LE:
case AV_PIX_FMT_BGR565BE:
case AV_PIX_FMT_BGR565LE:
case AV_PIX_FMT_BGR555BE:
case AV_PIX_FMT_BGR555LE:
case AV_PIX_FMT_RGB444LE:
case AV_PIX_FMT_RGB444BE:
case AV_PIX_FMT_BGR444LE:
case AV_PIX_FMT_BGR444BE:
case AV_PIX_FMT_BGR48BE:
case AV_PIX_FMT_BGR48LE:
case AV_PIX_FMT_0RGB:
case AV_PIX_FMT_RGB0:
case AV_PIX_FMT_0BGR:
case AV_PIX_FMT_BGR0:
return AV_PIX_FMT_BGR24;
case AV_PIX_FMT_RGBA64BE:
case AV_PIX_FMT_RGBA64LE:
case AV_PIX_FMT_BGRA64BE:
case AV_PIX_FMT_BGRA64LE:
case AV_PIX_FMT_ARGB:
case AV_PIX_FMT_RGBA:
case AV_PIX_FMT_ABGR:
case AV_PIX_FMT_BGRA:
return AV_PIX_FMT_BGRA;
default:
// Assume that everything else is converted to YUV 420
return AV_PIX_FMT_YUV420P;
}
}
FramePixelFormat getPixelFormat(AVPixelFormat fmt)
{
switch (fmt) {
case AV_PIX_FMT_BGR24:
return FramePixelFormat::BGR;
case AV_PIX_FMT_BGRA:
return FramePixelFormat::BGRA;
default:
return FramePixelFormat::YUV420;
}
}
}
@@ -118,7 +213,9 @@ std::unique_ptr<InputStream> openStream(const SCP_string& name) {
return input;
}
std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& stream) {
std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& stream,
std::unique_ptr<InputStream>& subt)
{
std::unique_ptr<DecoderStatus> status(new DecoderStatus());
auto ctx = stream->m_ctx->ctx();
@@ -140,7 +237,7 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& st
if (audioStream < 0) {
if (audioStream == AVERROR_STREAM_NOT_FOUND) {
mprintf(("FFmpeg: No audio stream found in file!\n"));
} else if (videoStream == AVERROR_DECODER_NOT_FOUND) {
} else if (audioStream == AVERROR_DECODER_NOT_FOUND) {
mprintf(("FFmpeg: Codec for audio stream could not be found!\n"));
} else {
mprintf(("FFmpeg: Unknown error while finding audio stream!\n"));
@@ -155,7 +252,54 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& st
status->audioStream = ctx->streams[audioStream];
}
status->videoCodecPars = getCodecParameters(status->videoStream);
if (subt) {
auto subtCtx = subt->m_ctx->ctx();
auto subtStream = av_find_best_stream(subtCtx, AVMEDIA_TYPE_SUBTITLE, -1, -1, nullptr, 0);
if (subtStream < 0) {
if (subtStream == AVERROR_STREAM_NOT_FOUND) {
mprintf(("FFmpeg: No subtitle stream found in subtitle file!\n"));
} else if (subtStream == AVERROR_DECODER_NOT_FOUND) {
mprintf(("FFmpeg: Codec for subtitle stream could not be found!\n"));
} else {
mprintf(("FFmpeg: Unknown error while finding subtitle stream!\n"));
}
} else {
status->subtitleStream = subtCtx->streams[subtStream];
status->externalSubtitles = true;
status->subtitleStreamIndex = subtStream;
}
}
if (status->subtitleStream == nullptr) {
// We don't have an external subtitle stream or loading from that file has failed
auto& current_language = Lcl_languages[Lcl_current_lang];
for (uint32_t i = 0; i < ctx->nb_streams; ++i) {
auto test_stream = ctx->streams[i];
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
auto& pars = test_stream->codecpar;
if (!(pars->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
continue;
}
#endif
AVDictionaryEntry* tag = nullptr;
if ((tag = av_dict_get(test_stream->metadata, "language", nullptr, 0)) == nullptr) {
continue;
}
auto normalized_language = normalizeLanguage(tag->value);
if (!stricmp(normalized_language.c_str(), current_language.lang_name)) {
status->subtitleStreamIndex = i;
status->subtitleStream = test_stream;
break;
}
}
}
status->videoCodecPars = getCodecParameters(status->videoStream);
int err;
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
@@ -213,6 +357,38 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& st
status->audioCodec->name ? status->audioCodec->name : "<Unknown>"));
}
if (status->subtitleStream != nullptr) {
// Not really sure if this makes sense for subtitles but it shouldn't break anything...
status->subtitleCodecPars = getCodecParameters(status->subtitleStream);
status->subtitleCodec = avcodec_find_decoder(status->subtitleCodecPars.codec_id);
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
status->subtitleCodecCtx = avcodec_alloc_context3(status->subtitleCodec);
err = avcodec_parameters_to_context(status->subtitleCodecCtx, status->subtitleStream->codecpar);
if (err < 0) {
char errorStr[512];
av_strerror(err, errorStr, sizeof(errorStr));
mprintf(("FFMPEG: Failed to copy context parameters! Error: %s\n", errorStr));
return nullptr;
}
#else
status->subtitleCodecCtx = status->subtitleStream->codec;
#endif
err = avcodec_open2(status->subtitleCodecCtx, status->subtitleCodec, nullptr);
if (err < 0) {
char errorStr[512];
av_strerror(err, errorStr, sizeof(errorStr));
mprintf(("FFMPEG: Failed to open subtitle codec! Error: %s\n", errorStr));
}
mprintf(("FFmpeg: Using subtitle codec %s (%s).\n",
status->subtitleCodec->long_name ? status->subtitleCodec->long_name : "<Unknown>",
status->subtitleCodec->name ? status->subtitleCodec->name : "<Unknown>"));
}
return status;
}
@@ -231,6 +407,28 @@ std::unique_ptr<InputStream> openInputStream(const SCP_string& name) {
return nullptr;
}
std::unique_ptr<InputStream> openSubtitleStream(const SCP_string& name)
{
auto& current_language = Lcl_languages[Lcl_current_lang];
for (auto ext : CHECKED_SUBT_EXTENSIONS) {
SCP_string fileName;
if (strlen(current_language.lang_ext) == 0) {
fileName = name + "." + ext;
} else {
fileName = name + "-" + current_language.lang_ext + "." + ext;
}
auto input = openStream(fileName);
if (input) {
return input;
}
}
return nullptr;
}
}
bool FFMPEGDecoder::initialize(const SCP_string& fileName) {
@@ -250,8 +448,10 @@ bool FFMPEGDecoder::initialize(const SCP_string& fileName) {
return false;
}
auto subt = openSubtitleStream(movieName);
// We now have a valid input stream, try to find the correct streams
auto status = initializeStatus(input);
auto status = initializeStatus(input, subt);
if (!status) {
return false;
}
@@ -261,28 +461,44 @@ bool FFMPEGDecoder::initialize(const SCP_string& fileName) {
// We're done, now just put the pointer into this
std::swap(m_input, input);
std::swap(m_subtitleInput, subt);
std::swap(m_status, status);
return true;
}
MovieProperties FFMPEGDecoder::getProperties() {
MovieProperties FFMPEGDecoder::getProperties() const
{
MovieProperties props;
props.size.width = static_cast<size_t>(m_status->videoCodecPars.width);
props.size.height = static_cast<size_t>(m_status->videoCodecPars.height);
props.fps = static_cast<float>(getFrameRate(m_status->videoStream, m_status->videoCodecCtx));
props.pixelFormat = getPixelFormat(getConversionFormat(m_status->videoCodecPars.pixel_format));
return props;
}
void FFMPEGDecoder::startDecoding() {
std::unique_ptr<VideoDecoder> videoDecoder(new VideoDecoder(m_status.get()));
std::unique_ptr<VideoDecoder> videoDecoder(new VideoDecoder(m_status.get(), getConversionFormat(m_status->videoCodecPars.pixel_format)));
std::unique_ptr<AudioDecoder> audioDecoder;
std::unique_ptr<SubtitleDecoder> subtitleDecoder;
if (hasAudio()) {
audioDecoder.reset(new AudioDecoder(m_status.get()));
}
if (hasSubtitles()) {
subtitleDecoder.reset(new SubtitleDecoder(m_status.get()));
}
std::unique_ptr<std::thread> subtitle_thread;
if (hasExternalSubtitle()) {
// Start a new thread for the subtitles since otherwise we would need to make sure that neither of the input
// streames starves while the other waits for more space in the queues
subtitle_thread.reset(
new std::thread([this, &subtitleDecoder]() { runSubtitleDecoder(subtitleDecoder.get()); }));
}
auto ctx = m_input->m_ctx->ctx();
AVPacket packet;
@@ -290,13 +506,13 @@ void FFMPEGDecoder::startDecoding() {
auto read_err = av_read_frame(ctx, &packet);
AVPacketScope scope(&packet);
if (avio_feof(ctx->pb) != 0) {
// EOF!!
break;
} else if (read_err < 0) {
if (read_err < 0) {
if (read_err == AVERROR_EOF) {
// Finished reading -> break out of loop
break;
} else if (avio_feof(ctx->pb) != 0) {
// Also EOF!
break;
} else {
// Some kind of other error, try to continue reading
char errorStr[512];
@@ -322,6 +538,13 @@ void FFMPEGDecoder::startDecoding() {
while ((ptr = audioDecoder->getFrame()) != nullptr) {
pushAudioData(std::move(ptr));
}
} else if (subtitleDecoder && packet.stream_index == m_status->subtitleStreamIndex) {
subtitleDecoder->decodePacket(&packet);
SubtitleFramePtr ptr;
while ((ptr = subtitleDecoder->getFrame()) != nullptr) {
pushSubtitleData(std::move(ptr));
}
}
}
@@ -342,12 +565,18 @@ void FFMPEGDecoder::startDecoding() {
}
}
if (subtitle_thread) {
subtitle_thread->join();
}
stopDecoder();
}
bool FFMPEGDecoder::hasAudio() {
return m_status->audioStreamIndex >= 0;
}
bool FFMPEGDecoder::hasAudio() const { return m_status->audioStreamIndex >= 0; }
bool FFMPEGDecoder::hasSubtitles() const { return m_status->subtitleStream != nullptr; }
bool FFMPEGDecoder::hasExternalSubtitle() const { return m_status->externalSubtitles; }
void FFMPEGDecoder::close() {
if (m_status) {
@@ -358,6 +587,56 @@ void FFMPEGDecoder::close() {
// This will delete the InputStream pointer and free all data
m_input = nullptr;
}
if (m_subtitleInput) {
m_subtitleInput = nullptr;
}
}
void FFMPEGDecoder::runSubtitleDecoder(SubtitleDecoder* decoder)
{
auto ctx = m_subtitleInput->m_ctx->ctx();
AVPacket packet;
while (isDecoding()) {
auto read_err = av_read_frame(ctx, &packet);
AVPacketScope scope(&packet);
if (read_err < 0) {
if (read_err == AVERROR_EOF) {
// Finished reading -> break out of loop
break;
} else if (avio_feof(ctx->pb) != 0) {
// Also EOF!
break;
} else {
// Some kind of other error, try to continue reading
char errorStr[512];
av_strerror(read_err, errorStr, sizeof(errorStr));
mprintf(("FFMPEG: Failed to read frame! Error: %s\n", errorStr));
// Skip packet
continue;
}
}
if (packet.stream_index == m_status->subtitleStreamIndex) {
decoder->decodePacket(&packet);
SubtitleFramePtr ptr;
while ((ptr = decoder->getFrame()) != nullptr) {
pushSubtitleData(std::move(ptr));
}
}
}
if (isDecoding()) {
// If we are still alive then read the last frames from the decoders
decoder->finishDecoding();
SubtitleFramePtr ptr;
while ((ptr = decoder->getFrame()) != nullptr) {
pushSubtitleData(std::move(ptr));
}
}
}
}
}
+17 -7
View File
@@ -8,26 +8,36 @@ struct InputStream;
struct DecoderStatus;
class SubtitleDecoder;
class FFMPEGDecoder: public Decoder {
private:
std::unique_ptr<InputStream> m_input;
std::unique_ptr<InputStream> m_subtitleInput;
std::unique_ptr<DecoderStatus> m_status;
public:
bool hasExternalSubtitle() const;
void runSubtitleDecoder(SubtitleDecoder* decoder);
public:
FFMPEGDecoder();
virtual ~FFMPEGDecoder();
~FFMPEGDecoder() override;
bool initialize(const SCP_string& fileName) SCP_OVERRIDE;
bool initialize(const SCP_string& fileName) override;
MovieProperties getProperties() SCP_OVERRIDE;
MovieProperties getProperties() const override;
void startDecoding() SCP_OVERRIDE;
void startDecoding() override;
bool hasAudio() SCP_OVERRIDE;
bool hasAudio() const override;
void close() SCP_OVERRIDE;
bool hasSubtitles() const override;
void close() override;
};
}
}
+135
View File
@@ -0,0 +1,135 @@
//
//
#include "SubtitleDecoder.h"
namespace {
double getFrameTime(int64_t pts, AVRational time_base) {
return pts * av_q2d(time_base);
}
}
namespace cutscene {
namespace ffmpeg {
SubtitleDecoder::SubtitleDecoder(cutscene::ffmpeg::DecoderStatus* status) : FFMPEGStreamDecoder(status) {
}
SubtitleDecoder::~SubtitleDecoder() {
}
void SubtitleDecoder::decodePacket(AVPacket* packet) {
int finishedFrame = 0;
AVSubtitle subtitle;
auto result = avcodec_decode_subtitle2(m_status->subtitleCodecCtx, &subtitle, &finishedFrame, packet);
if (result >= 0 && finishedFrame) {
pushSubtitleFrame(packet, &subtitle);
avsubtitle_free(&subtitle);
}
}
void SubtitleDecoder::finishDecoding() {
// Handle those decoders that have a delay
AVPacket nullPacket;
memset(&nullPacket, 0, sizeof(nullPacket));
nullPacket.data = nullptr;
nullPacket.size = 0;
AVSubtitle subtitle;
while (true) {
int finishedFrame = 1;
auto err = avcodec_decode_subtitle2(m_status->subtitleCodecCtx, &subtitle, &finishedFrame, &nullPacket);
if (err < 0 || !finishedFrame) {
break;
}
pushSubtitleFrame(&nullPacket, &subtitle);
avsubtitle_free(&subtitle);
}
}
void SubtitleDecoder::pushSubtitleFrame(AVPacket* packet, AVSubtitle* subtitle) {
if (subtitle->format != 1) {
// Non-text subtitles are not supported yet.
mprintf(("FFmpeg: Detected a non-text subtitle! This is not supported yet!\n"));
return;
}
if (subtitle->num_rects < 1) {
return;
}
int64_t pts = subtitle->pts;
if (pts == AV_NOPTS_VALUE) {
pts = packet->pts;
}
if (pts == AV_NOPTS_VALUE) {
// Still no valid timestamp...
return;
}
auto packet_time = getFrameTime(pts, m_status->subtitleStream->time_base);
auto start_time = packet_time + (subtitle->start_display_time / 1000.0);
auto end_time = packet_time + (subtitle->end_display_time / 1000.0);
if (subtitle->end_display_time == 0 && m_status->subtitleStream->time_base.num != 0) {
end_time = packet_time + getFrameTime(packet->duration, m_status->subtitleStream->time_base);
}
SCP_string processed_text;
// For now we only use the first subtitle rectangle
auto subtitle_rect = subtitle->rects[0];
if (subtitle_rect->type == SUBTITLE_BITMAP) {
// Same as above, non-text subtitles are not supported yet.
mprintf(("FFmpeg: Detected a non-text subtitle! This is not supported yet!\n"));
return;
} else if (subtitle_rect->type == SUBTITLE_TEXT) {
// Subtitle does not need to be processed any further
processed_text = subtitle_rect->text;
} else if (subtitle_rect->type == SUBTITLE_ASS) {
SCP_string ass_text = subtitle_rect->ass;
// We are not interested in any of the other information contained in the ASS line but we still need to figure
// out where our text starts
auto comma_pos = ass_text.find(',');
for (auto i = 0; i < 8 && comma_pos != SCP_string::npos; ++i) {
comma_pos = ass_text.find(',', comma_pos + 1);
}
Assertion(comma_pos != SCP_string::npos, "Received an ill-formed ASS line from FFmpeg! Text was '%s'.", subtitle_rect->ass);
// This + 1 is safe since comma_pos points to a valid character so the next character is at worst the end of the string
processed_text = ass_text.substr(comma_pos + 1);
// ASS has a special sequence for new lines that needs to be converted to an actual new line
auto newline_pos = processed_text.find("\\N");
while(newline_pos != SCP_string::npos) {
processed_text.replace(newline_pos, 2, "\n");
newline_pos = processed_text.find("\\N");
}
} else {
mprintf(("FFmpeg: Detected unknown subtitle name in movie!\n"));
return;
}
// Remove \r from string. Some subtitles use \r\n for line breaks and we only support \n
auto ret_pos = processed_text.find('\r');
while(ret_pos != SCP_string::npos) {
processed_text.erase(ret_pos, 1);
ret_pos = processed_text.find('\r');
}
SubtitleFramePtr frame(new SubtitleFrame());
frame->text = processed_text;
frame->displayStartTime = start_time;
frame->displayEndTime = end_time;
pushFrame(std::move(frame));
}
}
}
+24
View File
@@ -0,0 +1,24 @@
#pragma once
#include "cutscene/ffmpeg/internal.h"
#include "cutscene/ffmpeg/FFMPEGDecoder.h"
namespace cutscene {
namespace ffmpeg {
class SubtitleDecoder: public FFMPEGStreamDecoder<SubtitleFrame> {
public:
explicit SubtitleDecoder(DecoderStatus* status);
~SubtitleDecoder() override;
void decodePacket(AVPacket* packet) override;
void finishDecoding() override;
void pushSubtitleFrame(AVPacket* subtitle, AVSubtitle* pSubtitle);
};
}
}
+59 -63
View File
@@ -3,11 +3,9 @@
#include "tracing/tracing.h"
namespace {
const AVPixelFormat DESTINATION_FORMAT = AV_PIX_FMT_YUV420P;
SwsContext* getSWSContext(int width, int height, AVPixelFormat fmt) {
return sws_getContext(width, height, fmt, width, height, DESTINATION_FORMAT,
SWS_BILINEAR, nullptr, nullptr, nullptr);
SwsContext* getSWSContext(int width, int height, AVPixelFormat fmt, AVPixelFormat destination_fmt)
{
return sws_getContext(width, height, fmt, width, height, destination_fmt, SWS_BILINEAR, nullptr, nullptr, nullptr);
}
double getFrameTime(int64_t pts, AVRational time_base) {
@@ -18,34 +16,53 @@ double getFrameTime(int64_t pts, AVRational time_base) {
namespace cutscene {
namespace ffmpeg {
class FFMPEGVideoFrame: public VideoFrame {
public:
FFMPEGVideoFrame() : frame(nullptr) {
}
size_t _width;
size_t _height;
AVFrame* _frame;
virtual ~FFMPEGVideoFrame() {
if (frame != nullptr) {
av_freep(&frame->data[0]);
av_frame_free(&frame);
public:
FFMPEGVideoFrame(size_t width, size_t height, AVFrame* frame) : _width(width), _height(height), _frame(frame) {}
~FFMPEGVideoFrame() override {
if (_frame != nullptr) {
av_freep(&_frame->data[0]);
av_frame_free(&_frame);
}
}
virtual DataPointers getDataPointers() {
DataPointers ptrs;
ptrs.y = frame->data[0];
ptrs.u = frame->data[1];
ptrs.v = frame->data[2];
return ptrs;
size_t getPlaneNumber() override
{
switch (_frame->format) {
case AV_PIX_FMT_YUV420P:
// YUV data is planar
return 3;
default:
// Everything else is packed
return 1;
}
}
FrameSize getPlaneSize(size_t plane) override
{
switch (_frame->format) {
case AV_PIX_FMT_YUV420P: {
// YUV data is planar
auto width = plane > 0 ? _width / 2 : _width;
auto height = plane > 0 ? _height / 2 : _height;
AVFrame* frame;
return {width, height, (size_t)_frame->linesize[plane]};
}
default:
// Everything else is packed
return {_width, _height, (size_t)_frame->linesize[plane]};
}
}
void* getPlaneData(size_t plane) override { return _frame->data[plane]; }
};
VideoDecoder::VideoDecoder(DecoderStatus* status)
: FFMPEGStreamDecoder(status),
m_frameId(0) {
VideoDecoder::VideoDecoder(DecoderStatus* status, AVPixelFormat destination_fmt)
: FFMPEGStreamDecoder(status), m_frameId(0), m_destinationFormat(destination_fmt)
{
m_swsCtx = getSWSContext(m_status->videoCodecPars.width, m_status->videoCodecPars.height,
m_status->videoCodecPars.pixel_format);
m_status->videoCodecPars.pixel_format, destination_fmt);
}
VideoDecoder::~VideoDecoder() {
@@ -53,53 +70,32 @@ VideoDecoder::~VideoDecoder() {
}
void VideoDecoder::convertAndPushPicture(const AVFrame* frame) {
// Allocate a picture to hold the YUV data
// Allocate a picture to hold the destination data
AVFrame* yuvFrame = av_frame_alloc();
av_frame_copy(yuvFrame, frame);
yuvFrame->format = DESTINATION_FORMAT;
yuvFrame->format = m_destinationFormat;
av_image_alloc(yuvFrame->data,
yuvFrame->linesize,
m_status->videoCodecPars.width,
m_status->videoCodecPars.height,
DESTINATION_FORMAT,
1);
av_image_alloc(yuvFrame->data, yuvFrame->linesize, m_status->videoCodecPars.width, m_status->videoCodecPars.height,
m_destinationFormat, 1);
std::unique_ptr<FFMPEGVideoFrame> videoFramePtr(new FFMPEGVideoFrame());
if (m_status->videoCodecPars.pixel_format == DESTINATION_FORMAT) {
av_image_copy(yuvFrame->data,
yuvFrame->linesize,
(const uint8_t**) (frame->data),
frame->linesize,
DESTINATION_FORMAT,
m_status->videoCodecPars.width,
m_status->videoCodecPars.height);
if (m_status->videoCodecPars.pixel_format == m_destinationFormat) {
av_image_copy(yuvFrame->data, yuvFrame->linesize, (const uint8_t**)(frame->data), frame->linesize,
m_destinationFormat, m_status->videoCodecPars.width, m_status->videoCodecPars.height);
} else {
// Convert frame to YUV
sws_scale(
m_swsCtx,
(uint8_t const* const*) frame->data,
frame->linesize,
0,
m_status->videoCodecPars.height,
yuvFrame->data,
yuvFrame->linesize
);
// Convert frame to destination format
sws_scale(m_swsCtx, (uint8_t const* const*)frame->data, frame->linesize, 0, m_status->videoCodecPars.height,
yuvFrame->data, yuvFrame->linesize);
}
std::unique_ptr<FFMPEGVideoFrame> videoFramePtr(
new FFMPEGVideoFrame(static_cast<size_t>(m_status->videoCodecPars.width),
static_cast<size_t>(m_status->videoCodecPars.height), yuvFrame));
videoFramePtr->id = ++m_frameId;
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(58, 3, 102)
videoFramePtr->frameTime = getFrameTime(frame->best_effort_timestamp, m_status->videoStream->time_base);
#else
videoFramePtr->frameTime = getFrameTime(av_frame_get_best_effort_timestamp(frame), m_status->videoStream->time_base);
videoFramePtr->frame = yuvFrame;
videoFramePtr->ySize.height = static_cast<size_t>(m_status->videoCodecPars.height);
videoFramePtr->ySize.width = static_cast<size_t>(m_status->videoCodecPars.width);
videoFramePtr->ySize.stride = static_cast<size_t>(yuvFrame->linesize[0]);
// 420P means that the UV channels have half the width and height
videoFramePtr->uvSize.height = static_cast<size_t>(m_status->videoCodecPars.height / 2);
videoFramePtr->uvSize.width = static_cast<size_t>(m_status->videoCodecPars.width / 2);
videoFramePtr->uvSize.stride = static_cast<size_t>(yuvFrame->linesize[1]);
#endif
pushFrame(VideoFramePtr(videoFramePtr.release()));
}
+5 -4
View File
@@ -9,17 +9,18 @@ class VideoDecoder: public FFMPEGStreamDecoder<VideoFrame> {
private:
int m_frameId;
SwsContext* m_swsCtx;
AVPixelFormat m_destinationFormat;
void convertAndPushPicture(const AVFrame* frame);
public:
explicit VideoDecoder(DecoderStatus* status);
explicit VideoDecoder(DecoderStatus* status, AVPixelFormat destination_fmt);
virtual ~VideoDecoder();
~VideoDecoder() override;
virtual void decodePacket(AVPacket* packet) SCP_OVERRIDE;
void decodePacket(AVPacket* packet) override;
virtual void finishDecoding() SCP_OVERRIDE;
void finishDecoding() override;
};
}
}
+12
View File
@@ -30,6 +30,18 @@ DecoderStatus::~DecoderStatus() {
#endif
audioCodecCtx = nullptr;
}
subtitleStreamIndex = -1;
subtitleStream = nullptr;
subtitleCodec = nullptr;
if (subtitleCodecCtx != nullptr) {
avcodec_close(subtitleCodecCtx);
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
avcodec_free_context(&subtitleCodecCtx);
#endif
subtitleCodecCtx = nullptr;
}
}
} // namespace ffmpeg
+10
View File
@@ -16,6 +16,8 @@ struct CodecContextParameters {
uint64_t channel_layout = 0;
int sample_rate = -1;
AVSampleFormat audio_format = AV_SAMPLE_FMT_NONE;
AVCodecID codec_id = AV_CODEC_ID_NONE;
};
struct DecoderStatus {
@@ -31,6 +33,14 @@ struct DecoderStatus {
AVCodec* audioCodec = nullptr;
AVCodecContext* audioCodecCtx = nullptr;
// Subtitles are a bit different since they max come from a different file
bool externalSubtitles = false;
int subtitleStreamIndex = -1;
AVStream* subtitleStream = nullptr;
CodecContextParameters subtitleCodecPars;
AVCodec* subtitleCodec = nullptr;
AVCodecContext* subtitleCodecCtx = nullptr;
DecoderStatus();
~DecoderStatus();
+202 -1
View File
@@ -14,6 +14,7 @@
#endif
#include "globalincs/pstypes.h"
#include "globalincs/alphacolors.h"
#include "globalincs/systemvars.h"
#include "io/cursor.h"
#include "graphics/2d.h"
@@ -21,10 +22,205 @@
#include "cmdline/cmdline.h"
#include "cutscene/cutscenes.h" // cutscene_mark_viewable()
#include "cutscene/player.h" // cutscene_mark_viewable()
#include "tracing/categories.h"
#include "tracing/tracing.h"
#include "io/timer.h"
#include "io/key.h"
#include "mod_table/mod_table.h"
extern int Game_mode;
extern int Is_standalone;
namespace {
using namespace cutscene;
struct PlaybackState {
bool playing = true;
vec2d posTopLeft;
vec2d posBottomRight;
int subtitle_font = -1;
};
void processEvents(PlaybackState* state) {
io::mouse::CursorManager::get()->showCursor(false);
os_poll();
int k = key_inkey();
switch (k) {
case KEY_ESC:
case KEY_ENTER:
case KEY_SPACEBAR:
state->playing = false;
break;
default:
break;
}
}
template<typename... Args>
float print_string(float x, float y, const char* fmt, Args... params) {
SCP_string text;
sprintf(text, fmt, params...);
gr_string(x, y, text.c_str(), GR_RESIZE_NONE);
return y + font::get_current_font()->getHeight();
}
void showVideoInfo(const PlayerState& state) {
gr_set_color_fast(&Color_white);
font::set_font(font::FONT1);
float y = 200.f;
float x = 100.f;
y = print_string(x, y, "Movie FPS: %f", state.props.fps);
y = print_string(x, y, "Size: %dx%d", state.props.size.width, state.props.size.height);
y = gr_screen.max_h - 200.f;
size_t audio_queue_size = state.decoder->getAudioQueueSize();
if (state.hasAudio) {
ALint queued;
OpenAL_ErrorPrint(alGetSourcei(state.audioSid, AL_BUFFERS_QUEUED, &queued));
audio_queue_size += queued;
}
y = print_string(x, y, "Audio Queue size: " SIZE_T_ARG, audio_queue_size);
y = print_string(x, y, "Video Queue size: " SIZE_T_ARG, state.decoder->getVideoQueueSize());
y += font::get_current_font()->getHeight();
// Estimate the size of the video buffer
// We use YUV420p frames so one pixel uses 1.5 bytes of storage
size_t single_frame_size = (size_t) (state.props.size.width * state.props.size.height * 1.5);
size_t total_size = single_frame_size * state.decoder->getVideoQueueSize();
print_string(x, y, "Video buffer size: " SIZE_T_ARG "B", total_size);
}
void displayVideo(Player* player, PlaybackState* state) {
TRACE_SCOPE(tracing::CutsceneDrawVideoFrame);
GR_DEBUG_SCOPE("Display Video");
gr_clear();
player->draw(state->posTopLeft.x, state->posTopLeft.y, state->posBottomRight.x, state->posBottomRight.y);
auto subtitle = player->getCurrentSubtitle();
if (!subtitle.empty() && state->subtitle_font >= 0) {
gr_set_color_fast(&Color_bright_white);
font::set_font(state->subtitle_font);
int width;
int height;
gr_get_string_size(&width, &height, subtitle.c_str());
// Offset the subtitle by 20% of the viewport size from the bottom
auto y_offset = static_cast<int>((state->posBottomRight.y - state->posTopLeft.y) * 0.1);
auto center_x = (state->posBottomRight.x - state->posTopLeft.x) / 2;
auto text_x = center_x - width / 2;
auto text_y = state->posBottomRight.y - y_offset - height;
gr_string(text_x, text_y, subtitle.c_str(), GR_RESIZE_NONE);
}
if (Cmdline_show_video_info) {
showVideoInfo(player->getInternalState());
}
gr_flip();
}
void determine_display_positions(Player* player, PlaybackState* state) {
auto& props = player->getMovieProperties();
float screen_ratio = (float) gr_screen.center_w / (float) gr_screen.center_h;
float movie_ratio = (float) props.size.width / (float) props.size.height;
float scale_by;
if (screen_ratio > movie_ratio) {
scale_by = (float) gr_screen.center_h / (float) props.size.height;
} else {
scale_by = (float) gr_screen.center_w / (float) props.size.width;
}
float screenX;
float screenY;
if (!Cmdline_noscalevid && (scale_by != 1.0f)) {
screenX = ((gr_screen.center_w / 2.0f + gr_screen.center_offset_x) / scale_by) - (static_cast<int>(props.size.width) / 2.0f) + 0.5f;
screenY = ((gr_screen.center_h / 2.0f + gr_screen.center_offset_y) / scale_by) - (static_cast<int>(props.size.height) / 2.0f) + 0.5f;
} else {
// centers on 1024x768, fills on 640x480
screenX = i2fl(((gr_screen.center_w - static_cast<int>(props.size.width)) / 2) + gr_screen.center_offset_x);
screenY = i2fl(((gr_screen.center_h - static_cast<int>(props.size.height)) / 2) + gr_screen.center_offset_y);
}
// set additional values for screen width/height and UV coords
float screenXW = screenX + static_cast<int>(props.size.width);
float screenYH = screenY + static_cast<int>(props.size.height);
if (!Cmdline_noscalevid && (scale_by != 1.0f)) {
// Apply scaling
screenX *= scale_by;
screenY *= scale_by;
screenXW *= scale_by;
screenYH *= scale_by;
}
state->posTopLeft.x = screenX;
state->posTopLeft.y = screenY;
state->posBottomRight.x = screenXW;
state->posBottomRight.y = screenYH;
}
void initialize_player_state(Player* player, PlaybackState* state) {
determine_display_positions(player, state);
state->subtitle_font = font::FontManager::getFontIndex(Movie_subtitle_font);
if (state->subtitle_font < 0) {
Warning(LOCATION, "Failed to load subtitle font '%s'! Subtitles will be disabled.", Movie_subtitle_font.c_str());
}
}
void movie_display_loop(Player* player, PlaybackState* state) {
// Compute the maximum time we will sleep to make sure we can still maintain the movie FPS
// and not waste too much CPU time
// We will sleep at most half the time a frame would be displayed
auto sleepTime = static_cast<std::uint64_t>((1. / (4. * player->getMovieProperties().fps)) * 1000.);
auto lastDisplayTimestamp = timer_get_microseconds();
while (state->playing) {
TRACE_SCOPE(tracing::CutsceneStep);
auto timestamp = timer_get_microseconds();
auto passed = timestamp - lastDisplayTimestamp;
lastDisplayTimestamp = timestamp;
if (player->isPlaybackReady()) {
// Play as long as the player reports that there is more to display
state->playing = player->update(passed);
displayVideo(player, state);
}
processEvents(state);
if (passed < sleepTime) {
auto sleep = sleepTime - passed;
os_sleep(static_cast<uint>(sleep));
}
}
}
}
namespace movie {
// Play one movie
bool play(const char* name) {
@@ -57,7 +253,12 @@ bool play(const char* name) {
auto player = cutscene::Player::newPlayer(name);
if (player) {
player->startPlayback();
PlaybackState state;
initialize_player_state(player.get(), &state);
movie_display_loop(player.get(), &state);
player->stopPlayback();
} else {
// uh-oh, movie is invalid... Abory, Retry, Fail?
mprintf(("MOVIE ERROR: Found invalid movie! (%s)\n", name));
+106 -183
View File
@@ -1,7 +1,7 @@
#include "cutscene/player.h"
#include "cutscene/Decoder.h"
#include "cutscene/player/VideoPresenter.h"
#include "cutscene/VideoPresenter.h"
#include "cutscene/ffmpeg/FFMPEGDecoder.h"
#include "graphics/2d.h"
@@ -17,64 +17,22 @@
#include "io/key.h"
#include "io/timer.h"
#include "player.h"
#include "parse/parselo.h"
#include "cutscene/player/OpenGLVideoPresenter.h"
using namespace cutscene::player;
namespace cutscene {
struct PlayerState {
MovieProperties props;
Decoder* decoder = nullptr;
bool playing = true;
bool playbackHasBegun = false;
// Timing state
std::uint64_t playback_time = 0;
// Audio state
bool audioInited = false;
bool hasAudio = false;
ALuint audioSid = 0;
SCP_vector<ALuint> audioBuffers;
SCP_queue<ALuint> unqueuedAudioBuffers;
// Graphics state following
bool videoInited = false;
VideoFramePtr currentFrame;
VideoFramePtr nextFrame;
bool newFrameAdded = false;
std::unique_ptr<VideoPresenter> videoPresenter;
PlayerState() : decoder(nullptr), playing(true), playbackHasBegun(false),
playback_time(0),
audioInited(0), hasAudio(false), audioSid(0),
videoInited(false), newFrameAdded(false) {}
private:
PlayerState(const PlayerState&) SCP_DELETED_FUNCTION;
PlayerState& operator=(const PlayerState&) SCP_DELETED_FUNCTION;
};
}
namespace {
using namespace cutscene;
const int MAX_AUDIO_BUFFERS = 15;
Decoder* findDecoder(const SCP_string& name) {
std::unique_ptr<Decoder> findDecoder(const SCP_string& name) {
{
auto ffmpeg = new ffmpeg::FFMPEGDecoder();
std::unique_ptr<Decoder> ffmpeg(new ::cutscene::ffmpeg::FFMPEGDecoder());
if (ffmpeg->initialize(name)) {
return ffmpeg;
}
delete ffmpeg;
}
return nullptr;
@@ -93,7 +51,7 @@ void videoPlaybackInit(PlayerState* state) {
Assert(state != NULL);
if (gr_screen.mode == GR_OPENGL) {
state->videoPresenter.reset(new OpenGLVideoPresenter(state->props));
state->videoPresenter.reset(new VideoPresenter(state->props));
}
state->videoInited = true;
@@ -163,7 +121,7 @@ void processVideoData(PlayerState* state) {
return;
}
while(currentTime >= state->nextFrame->frameTime) {
while (currentTime >= state->nextFrame->frameTime) {
// Move the next frame to the current frame slot
state->currentFrame = std::move(state->nextFrame);
@@ -184,6 +142,34 @@ void processVideoData(PlayerState* state) {
}
}
void processSubtitleData(PlayerState* state) {
SubtitleFramePtr ptr;
while (state->decoder->tryPopSubtitleData(ptr)) {
// Take all subtitle frames from our queue
state->queued_subtitles.push(std::move(ptr));
}
if (state->currentSubtitle && playbackGetTime(state) <= state->currentSubtitle->displayEndTime) {
// We currently have a frame and it it still being displayed so there is nothing for us to do here
return;
}
// Subtitle has expired so we don't need it anymore
state->currentSubtitle = nullptr;
while(!state->queued_subtitles.empty()) {
// Take a look at the first entry and check if it's time to display it yet
auto& nextSubtitle = state->queued_subtitles.front();
if (playbackGetTime(state) >= nextSubtitle->displayStartTime) {
state->currentSubtitle = std::move(nextSubtitle);
state->queued_subtitles.pop();
} else {
// The next subtitle should not be displayed yet so we are done here
break;
}
}
}
bool processAudioData(PlayerState* state) {
TRACE_SCOPE(tracing::CutsceneProcessAudioData);
@@ -191,7 +177,7 @@ bool processAudioData(PlayerState* state) {
if (state->decoder->hasAudio()) {
// Even if we don't play the sound we still need to remove it from the queue
AudioFramePtr audioData;
while(state->decoder->tryPopAudioData(audioData)) {
while (state->decoder->tryPopAudioData(audioData)) {
// Intentionally left empty
}
}
@@ -216,7 +202,9 @@ bool processAudioData(PlayerState* state) {
ALenum format = (audioData->channels == 2) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16;
OpenAL_ErrorCheck(alBufferData(buffer, format, audioData->audioData.data(),
OpenAL_ErrorCheck(alBufferData(buffer,
format,
audioData->audioData.data(),
static_cast<ALsizei>(audioData->audioData.size() * sizeof(short)),
static_cast<ALsizei>(audioData->rate)), return false);
@@ -269,82 +257,10 @@ void videoPlaybackClose(PlayerState* state) {
state->videoInited = false;
}
template<typename... Args>
float print_string(float x, float y, const char* fmt, Args... params) {
SCP_string text;
sprintf(text, fmt, params...);
gr_string(x, y, text.c_str(), GR_RESIZE_NONE);
return y + font::get_current_font()->getHeight();
}
void showVideoInfo(PlayerState* state) {
gr_set_color_fast(&Color_white);
float y = 200.f;
float x = 100.f;
y = print_string(x, y, "Movie FPS: %f", state->props.fps);
y = print_string(x, y, "Size: %dx%d", state->props.size.width, state->props.size.height);
y = gr_screen.max_h - 200.f;
size_t audio_queue_size = state->decoder->getAudioQueueSize();
if (state->hasAudio) {
ALint queued;
OpenAL_ErrorPrint(alGetSourcei(state->audioSid, AL_BUFFERS_QUEUED, &queued));
audio_queue_size += queued;
}
y = print_string(x, y, "Audio Queue size: " SIZE_T_ARG, audio_queue_size);
y = print_string(x, y, "Video Queue size: " SIZE_T_ARG, state->decoder->getVideoQueueSize());
y += font::get_current_font()->getHeight();
// Estimate the size of the video buffer
// We use YUV420p frames so one pixel uses 1.5 bytes of storage
size_t single_frame_size = (size_t) (state->props.size.width * state->props.size.height * 1.5);
size_t total_size = single_frame_size * state->decoder->getVideoQueueSize();
print_string(x, y, "Video buffer size: " SIZE_T_ARG "B", total_size);
}
void displayVideo(PlayerState* state) {
if (!state->currentFrame) {
return;
}
TRACE_SCOPE(tracing::CutsceneDrawVideoFrame);
gr_clear();
if (state->videoPresenter) {
state->videoPresenter->displayFrame();
}
if (Cmdline_show_video_info) {
showVideoInfo(state);
}
gr_flip();
}
void processEvents(PlayerState* state) {
io::mouse::CursorManager::get()->showCursor(false);
os_poll();
int k = key_inkey();
switch (k) {
case KEY_ESC:
case KEY_ENTER:
case KEY_SPACEBAR:
state->playing = false;
break;
default:
break;
}
}
bool shouldBeginPlayback(Decoder* decoder) {
auto video = decoder->isVideoQueueFull();
auto audio = decoder->isAudioQueueFull();
auto subtitles = decoder->isSubtitleQueueFull();
// Wait until one of the queues is full, that should make sure
// that we have enough frames at the beginning of playback and that
@@ -352,92 +268,79 @@ bool shouldBeginPlayback(Decoder* decoder) {
// or video at the beginning
// Also only wait while the decoder is still working. Otherwise we will wait indefinitely if the video
// is very short.
return (audio || video) || !decoder->isDecoding();
return (audio || video || subtitles) || !decoder->isDecoding();
}
}
namespace cutscene {
Player::Player() {
Player::Player(std::unique_ptr<Decoder>&& decoder, bool enable_audio) : m_decoder(std::move(decoder))
{
Assertion(!m_state.videoInited,
"Internal State has been initialized before! Create a new player for replaying a movie.");
m_decoderThread.reset(new std::thread(std::bind(&Player::decoderThread, this)));
m_state.props = m_decoder->getProperties();
m_state.decoder = m_decoder.get();
videoPlaybackInit(&m_state);
if (enable_audio) {
audioPlaybackInit(&m_state);
}
}
Player::~Player() {
// If video is initialized it means that stopPlayback has not been called yet
if (m_state.videoInited) {
stopPlayback();
}
if (m_decoder) {
m_decoder->close();
}
}
void Player::processDecoderData(PlayerState* state) {
if (!state->playbackHasBegun) {
bool Player::processDecoderData() {
if (!m_state.playbackHasBegun) {
// Wait until video and audio are available
// If we don't have audio, don't wait for it (obviously...)
if (!shouldBeginPlayback(state->decoder)) {
return;
if (!shouldBeginPlayback(m_state.decoder)) {
return true;
}
state->playbackHasBegun = true;
m_state.playbackHasBegun = true;
}
TRACE_SCOPE(tracing::CutsceneProcessDecoder);
processVideoData(state);
processVideoData(&m_state);
auto audioPlaying = processAudioData(state);
processSubtitleData(&m_state);
auto audioPlaying = processAudioData(&m_state);
// Set the playing flag if the decoder is still active or there is still data available
auto decoding = m_decoder->isDecoding();
// Audio is pending if there is data left in the queue or of OpenAL is still playing audio
// Audio is pending if there is data left in the queue or if OpenAL is still playing audio
auto pendingAudio = (m_decoder->isAudioFrameAvailable() && m_decoder->hasAudio()) || audioPlaying;
auto pendingVideo = m_decoder->isVideoFrameAvailable();
state->playing = decoding || pendingAudio || pendingVideo;
return decoding || pendingAudio || pendingVideo;
}
void Player::startPlayback() {
m_decoderThread.reset(new std::thread(std::bind(&Player::decoderThread, this)));
PlayerState state;
state.props = m_decoder->getProperties();
state.decoder = m_decoder.get();
// Compute the maximum time we will sleep to make sure we can still maintain the movie FPS
// and not waste too much CPU time
// We will sleep at most half the time a frame would be displayed
auto sleepTime = static_cast<std::uint64_t>((1. / (4. * state.props.fps)) * 1000.);
videoPlaybackInit(&state);
audioPlaybackInit(&state);
auto lastDisplayTimestamp = timer_get_microseconds();
while (state.playing) {
TRACE_SCOPE(tracing::CutsceneStep);
processDecoderData(&state);
displayVideo(&state);
processEvents(&state);
auto timestamp = timer_get_microseconds();
auto passed = timestamp - lastDisplayTimestamp;
lastDisplayTimestamp = timestamp;
if (state.playbackHasBegun) {
state.playback_time += passed;
}
if (passed < sleepTime) {
auto sleep = sleepTime - passed;
os_sleep(static_cast<uint>(sleep));
}
bool Player::update(uint64_t diff_time_micro) {
if (m_state.playbackHasBegun) {
m_state.playback_time += diff_time_micro;
}
return processDecoderData();
}
void Player::stopPlayback() {
m_decoder->stopDecoder();
audioPlaybackClose(&state);
videoPlaybackClose(&state);
audioPlaybackClose(&m_state);
videoPlaybackClose(&m_state);
m_decoderThread->join();
}
@@ -452,7 +355,8 @@ void Player::decoderThread() {
}
}
std::unique_ptr<Player> Player::newPlayer(const SCP_string& name) {
std::unique_ptr<Player> Player::newPlayer(const SCP_string& name, bool enable_audio)
{
mprintf(("Creating player for movie '%s'.\n", name.c_str()));
auto decoder = findDecoder(name);
@@ -460,10 +364,29 @@ std::unique_ptr<Player> Player::newPlayer(const SCP_string& name) {
if (decoder == nullptr) {
return nullptr;
}
std::unique_ptr<Player> player(new Player());
player->m_decoder.reset(decoder);
return player;
return std::unique_ptr<Player>(new Player(std::move(decoder), enable_audio));
}
const PlayerState& Player::getInternalState() const {
return m_state;
}
const MovieProperties& Player::getMovieProperties() const {
return m_state.props;
}
void Player::draw(float x1, float y1, float x2, float y2) {
if (!m_state.currentFrame) {
return;
}
if (m_state.videoPresenter) {
m_state.videoPresenter->displayFrame(x1, y1, x2, y2);
}
}
SCP_string Player::getCurrentSubtitle() {
if (!m_state.currentSubtitle) {
return "";
} else {
return m_state.currentSubtitle->text;
}
}
bool Player::isPlaybackReady() const { return m_state.playbackHasBegun || shouldBeginPlayback(m_decoder.get()); }
}
+107 -17
View File
@@ -5,44 +5,134 @@
#include <thread>
#include "globalincs/pstypes.h"
#include "sound/openal.h"
#include "Decoder.h"
#include "VideoPresenter.h"
namespace cutscene {
class Decoder;
struct PlayerState;
struct PlayerState {
MovieProperties props;
Decoder* decoder = nullptr;
bool playbackHasBegun = false;
// Timing state
std::uint64_t playback_time = 0;
// Audio state
bool audioInited = false;
bool hasAudio = false;
ALuint audioSid = 0;
SCP_vector<ALuint> audioBuffers;
SCP_queue<ALuint> unqueuedAudioBuffers;
// Graphics state following
bool videoInited = false;
VideoFramePtr currentFrame;
VideoFramePtr nextFrame;
bool newFrameAdded = false;
std::unique_ptr<player::VideoPresenter> videoPresenter;
SCP_queue<SubtitleFramePtr> queued_subtitles;
SubtitleFramePtr currentSubtitle;
PlayerState() {
}
PlayerState(const PlayerState&) = delete;
PlayerState& operator=(const PlayerState&) = delete;
};
/**
* @brief A movie player
*/
class Player {
private:
private:
std::unique_ptr<Decoder> m_decoder;
std::unique_ptr<std::thread> m_decoderThread;
void processDecoderData(PlayerState* state);
PlayerState m_state;
private:
Player(const Player&) = delete;
bool processDecoderData();
private:
void decoderThread();
public:
Player();
public:
explicit Player(std::unique_ptr<Decoder>&& decoder, bool enable_audio = true);
~Player();
/**
* @brief Begin playing the previously selected movie
*/
void startPlayback();
Player(const Player&) = delete;
Player& operator=(const Player&) = delete;
/**
* @brief Creates a player
* The player is configured to play the movie with the specified name
* @param name The movie to play
* @return @c nullptr if the specified movie could not be opened, a valid Player pointer otherwise
*/
static std::unique_ptr<Player> newPlayer(const SCP_string& name);
* @brief Update the player and increase display timestamp by specified delta time
* @param diff_time_micro The time to increase the display timestamp in microseconds (not milliseconds!)
* @return @c true if there is more content to display. @c false if the player reached the end of the movie and has
* displayed the last frame.
*/
bool update(uint64_t diff_time_micro);
/**
* @brief Gives access to the internal state of the player
*
* @warning This should only be used for debugging purposed!
*
* @return A reference to the internal state
*/
const PlayerState& getInternalState() const;
/**
* @brief Gets the properties of the movie that this player is displaying
* @return A reference to the movie properties
*/
const MovieProperties& getMovieProperties() const;
/**
* @brief Determines if this player can start displaying video.
* @return true if the cutscene is ready, false otherwise
*/
bool isPlaybackReady() const;
/**
* @brief Draws the current movie frame at the specified coordinates.
*
* This may not draw anything if there is currently not a frame to display.
*
* @param x1 The X coordinate of the top left corner
* @param y1 The Y coordinate of the top left corner
* @param x2 The X coordinate of the bottom right corner
* @param y2 The Y coordinate of the bottom right corner
*/
void draw(float x1, float y1, float x2, float y2);
/**
* @brief Gets the subtitle text that should be displayed now
* @return The text, encoded in UTF-8
*/
SCP_string getCurrentSubtitle();
/**
* @brief Stops playback
*
* This is also automatically called when this instance is destroyed.
*/
void stopPlayback();
/**
* @brief Creates a player
* The player is configured to play the movie with the specified name
* @param name The movie to play
* @param enable_audio Enable audio for this player instance
* @return @c nullptr if the specified movie could not be opened, a valid Player pointer otherwise
*/
static std::unique_ptr<Player> newPlayer(const SCP_string& name, bool enable_audio = true);
};
}
@@ -1,223 +0,0 @@
#include "OpenGLVideoPresenter.h"
#include "graphics/opengl/gropenglstate.h"
#include "graphics/opengl/gropengltnl.h"
#include "graphics/opengl/gropengldraw.h"
using namespace cutscene;
using namespace cutscene::player;
namespace cutscene {
namespace player {
OpenGLVideoPresenter::OpenGLVideoPresenter(const MovieProperties& props) : _scaleVideo(false),
_ytex(0), _utex(0), _vtex(0) {
GR_DEBUG_SCOPE("Init video");
opengl_set_texture_target(GL_TEXTURE_2D);
_vertexBuffer = gr_create_vertex_buffer(true);
auto w = static_cast<int>(props.size.width);
auto h = static_cast<int>(props.size.height);
_sdr_handle = gr_maybe_create_shader(SDR_TYPE_VIDEO_PROCESS, 0);
glGenTextures(1, &_ytex);
glGenTextures(1, &_utex);
glGenTextures(1, &_vtex);
if (_ytex + _utex + _vtex == 0) {
throw std::runtime_error("Can't create a GL texture");
}
opengl_shader_set_current(_sdr_handle);
gr_set_lighting(false, false);
GL_state.SetAlphaBlendMode(ALPHA_BLEND_NONE);
GL_state.SetZbufferType(ZBUFFER_TYPE_NONE);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_texture_target);
GL_state.Texture.Enable(_ytex);
glTexParameteri(GL_texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// NOTE: using NULL instead of pixelbuf crashes some drivers, but then so does pixelbuf
glTexImage2D(GL_state.Texture.GetTarget(), 0, GL_RED, w, h, 0, GL_RED,
GL_UNSIGNED_BYTE, NULL);
GL_state.Texture.SetActiveUnit(1);
GL_state.Texture.SetTarget(GL_texture_target);
GL_state.Texture.Enable(_utex);
glTexParameteri(GL_texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// NOTE: using NULL instead of pixelbuf crashes some drivers, but then so does pixelbuf
glTexImage2D(GL_state.Texture.GetTarget(), 0, GL_RED, w / 2, h / 2, 0, GL_RED,
GL_UNSIGNED_BYTE, NULL);
GL_state.Texture.SetActiveUnit(2);
GL_state.Texture.SetTarget(GL_texture_target);
GL_state.Texture.Enable(_vtex);
glTexParameteri(GL_texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// NOTE: using NULL instead of pixelbuf crashes some drivers, but then so does pixelbuf
glTexImage2D(GL_state.Texture.GetTarget(), 0, GL_RED, w / 2, h / 2, 0, GL_RED,
GL_UNSIGNED_BYTE, NULL);
float screen_ratio = (float) gr_screen.center_w / (float) gr_screen.center_h;
float movie_ratio = (float) props.size.width / (float) props.size.height;
float scale_by;
if (screen_ratio > movie_ratio) {
scale_by = (float) gr_screen.center_h / (float) props.size.height;
} else {
scale_by = (float) gr_screen.center_w / (float) props.size.width;
}
// don't bother setting anything if we aren't going to need it
if (!Cmdline_noscalevid && (scale_by != 1.0f)) {
vec3d scale;
scale.xyz.x = scale_by;
scale.xyz.y = scale_by;
scale.xyz.z = -1.0f;
gr_push_scale_matrix(&scale);
_scaleVideo = true;
}
int screenX;
int screenY;
if (_scaleVideo) {
screenX = fl2i(((gr_screen.center_w / 2.0f + gr_screen.center_offset_x) / scale_by) - (static_cast<int>(props.size.width) / 2.0f) + 0.5f);
screenY = fl2i(((gr_screen.center_h / 2.0f + gr_screen.center_offset_y) / scale_by) - (static_cast<int>(props.size.height) / 2.0f) + 0.5f);
} else {
// centers on 1024x768, fills on 640x480
screenX = ((gr_screen.center_w - static_cast<int>(props.size.width)) / 2) + gr_screen.center_offset_x;
screenY = ((gr_screen.center_h - static_cast<int>(props.size.height)) / 2) + gr_screen.center_offset_y;
}
// set additional values for screen width/height and UV coords
int screenXW = screenX + static_cast<int>(props.size.width);
int screenYH = screenY + static_cast<int>(props.size.height);
Current_shader->program->Uniforms.setUniformi("ytex", 0);
Current_shader->program->Uniforms.setUniformi("utex", 1);
Current_shader->program->Uniforms.setUniformi("vtex", 2);
Current_shader->program->Uniforms.setUniformMatrix4f("projMatrix", GL_projection_matrix);
Current_shader->program->Uniforms.setUniformMatrix4f("modelViewMatrix", GL_model_view_matrix);
GLfloat glVertices[4][4] = {{0}};
glVertices[0][0] = (GLfloat)screenX;
glVertices[0][1] = (GLfloat)screenY;
glVertices[0][2] = 0.0f;
glVertices[0][3] = 0.0f;
glVertices[1][0] = (GLfloat)screenX;
glVertices[1][1] = (GLfloat)screenYH;
glVertices[1][2] = 0.0f;
glVertices[1][3] = 1.0f;
glVertices[2][0] = (GLfloat)screenXW;
glVertices[2][1] = (GLfloat)screenY;
glVertices[2][2] = 1.0f;
glVertices[2][3] = 0.0f;
glVertices[3][0] = (GLfloat)screenXW;
glVertices[3][1] = (GLfloat)screenYH;
glVertices[3][2] = 1.0f;
glVertices[3][3] = 1.0f;
_vertexLayout.add_vertex_component(vertex_format_data::POSITION2, sizeof(glVertices[0]), 0);
_vertexLayout.add_vertex_component(vertex_format_data::TEX_COORD, sizeof(glVertices[0]), sizeof(GLfloat) * 2);
gr_update_buffer_data(_vertexBuffer, sizeof(glVertices[0]) * 4, glVertices);
}
OpenGLVideoPresenter::~OpenGLVideoPresenter() {
GR_DEBUG_SCOPE("Deinit video");
if (_scaleVideo) {
gr_pop_scale_matrix();
}
gr_delete_buffer(_vertexBuffer);
_vertexBuffer = -1;
GL_state.Texture.Delete(_ytex);
GL_state.Texture.Delete(_utex);
GL_state.Texture.Delete(_vtex);
glDeleteTextures(1, &_ytex);
glDeleteTextures(1, &_utex);
glDeleteTextures(1, &_vtex);
opengl_set_texture_target();
_ytex = _utex = _vtex = 0;
opengl_shader_set_current();
}
void OpenGLVideoPresenter::uploadVideoFrame(const VideoFramePtr& frame) {
GR_DEBUG_SCOPE("Update video frame");
auto ptrs = frame->getDataPointers();
auto stride = static_cast<GLint>(frame->ySize.stride);
auto width = static_cast<GLint>(frame->ySize.width);
auto height = static_cast<GLint>(frame->ySize.height);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.Enable(_ytex);
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
glTexSubImage2D(GL_state.Texture.GetTarget(), 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE,
ptrs.y);
stride = static_cast<int>(frame->uvSize.stride);
width = static_cast<int>(frame->uvSize.width);
height = static_cast<int>(frame->uvSize.height);
GL_state.Texture.SetActiveUnit(1);
GL_state.Texture.Enable(_utex);
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
glTexSubImage2D(GL_state.Texture.GetTarget(), 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE,
ptrs.u);
GL_state.Texture.SetActiveUnit(2);
GL_state.Texture.Enable(_vtex);
glTexSubImage2D(GL_state.Texture.GetTarget(), 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE,
ptrs.v);
// Reset this back to default
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}
void OpenGLVideoPresenter::displayFrame() {
opengl_shader_set_current(_sdr_handle);
opengl_bind_buffer_object(_vertexBuffer);
opengl_bind_vertex_layout(_vertexLayout);
// Bind textures
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.Enable(_ytex);
GL_state.Texture.SetActiveUnit(1);
GL_state.Texture.Enable(_utex);
GL_state.Texture.SetActiveUnit(2);
GL_state.Texture.Enable(_vtex);
GR_DEBUG_SCOPE("Draw video frame");
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
}
}
@@ -1,38 +0,0 @@
#ifndef FS2_OPEN_OPENGLVIDEOPRESENTER_H
#define FS2_OPEN_OPENGLVIDEOPRESENTER_H
#include "globalincs/pstypes.h"
#include "cutscene/player/VideoPresenter.h"
#include <glad/glad.h>
#include <memory>
#include <graphics/2d.h>
namespace cutscene {
namespace player {
class OpenGLVideoPresenter: public VideoPresenter {
int _vertexBuffer = -1;
vertex_layout _vertexLayout;
int _sdr_handle = -1;
bool _scaleVideo = false;
GLuint _ytex = 0;
GLuint _utex = 0;
GLuint _vtex = 0;
public:
OpenGLVideoPresenter(const MovieProperties& props);
virtual ~OpenGLVideoPresenter();
virtual void uploadVideoFrame(const VideoFramePtr& frame) SCP_OVERRIDE;
virtual void displayFrame() SCP_OVERRIDE;
};
}
}
#endif //FS2_OPEN_OPENGLVIDEOPRESENTER_H
-21
View File
@@ -1,21 +0,0 @@
#ifndef FS2_OPEN_VIDEOPRESENTER_H
#define FS2_OPEN_VIDEOPRESENTER_H
#include "globalincs/pstypes.h"
#include "cutscene/Decoder.h"
namespace cutscene {
namespace player {
class VideoPresenter {
public:
virtual ~VideoPresenter() {}
virtual void uploadVideoFrame(const VideoFramePtr& frame) = 0;
virtual void displayFrame() = 0;
};
}
}
#endif //FS2_OPEN_VIDEOPRESENTER_H
+8 -8
View File
@@ -74,7 +74,7 @@ static void debris_start_death_roll(object *debris_obj, debris *debris_p)
// only play debris destroy sound if hull piece and it has been around for at least 2 seconds
if ( Missiontime > debris_p->time_started + 2*F1_0 ) {
snd_play_3d( &Snds[SND_MISSILE_IMPACT1], &debris_obj->pos, &View_position, debris_obj->radius );
snd_play_3d( gamesnd_get_game_sound(gamesnd_id(GameSounds::MISSILE_IMPACT1)), &debris_obj->pos, &View_position, debris_obj->radius );
}
}
@@ -238,7 +238,7 @@ void debris_process_post(object * obj, float frame_time)
radar_plot_object( obj );
if ( timestamp_elapsed(db->sound_delay) ) {
obj_snd_assign(objnum, SND_DEBRIS, &vmd_zero_vector, 0);
obj_snd_assign(objnum, GameSounds::DEBRIS, &vmd_zero_vector, 0);
db->sound_delay = 0;
}
} else {
@@ -324,19 +324,19 @@ void debris_process_post(object * obj, float frame_time)
//Play a sound effect
if ( lifetime > 750 ) {
// 1.00 second effect
snd_play_3d( &Snds[SND_DEBRIS_ARC_05], &snd_pos, &View_position, obj->radius );
snd_play_3d( gamesnd_get_game_sound(GameSounds::DEBRIS_ARC_05), &snd_pos, &View_position, obj->radius );
} else if ( lifetime > 500 ) {
// 0.75 second effect
snd_play_3d( &Snds[SND_DEBRIS_ARC_04], &snd_pos, &View_position, obj->radius );
snd_play_3d( gamesnd_get_game_sound(GameSounds::DEBRIS_ARC_04), &snd_pos, &View_position, obj->radius );
} else if ( lifetime > 250 ) {
// 0.50 second effect
snd_play_3d( &Snds[SND_DEBRIS_ARC_03], &snd_pos, &View_position, obj->radius );
snd_play_3d( gamesnd_get_game_sound(GameSounds::DEBRIS_ARC_03), &snd_pos, &View_position, obj->radius );
} else if ( lifetime > 100 ) {
// 0.25 second effect
snd_play_3d( &Snds[SND_DEBRIS_ARC_02], &snd_pos, &View_position, obj->radius );
snd_play_3d( gamesnd_get_game_sound(GameSounds::DEBRIS_ARC_02), &snd_pos, &View_position, obj->radius );
} else {
// 0.10 second effect
snd_play_3d( &Snds[SND_DEBRIS_ARC_01], &snd_pos, &View_position, obj->radius );
snd_play_3d( gamesnd_get_game_sound(GameSounds::DEBRIS_ARC_01), &snd_pos, &View_position, obj->radius );
}
}
}
@@ -693,7 +693,7 @@ object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d
* Alas, poor debris_obj got whacked. Fortunately, we know who did it, where and how hard, so we
* can do something about it.
*/
void debris_hit(object *debris_obj, object *other_obj, vec3d *hitpos, float damage)
void debris_hit(object *debris_obj, object * /*other_obj*/, vec3d *hitpos, float damage)
{
debris *debris_p = &Debris[debris_obj->instance];
+2 -2
View File
@@ -162,7 +162,7 @@ void dc_do_command(SCP_string *cmd_str)
try {
dc_commands[i]->func(); // Run the command!
} catch (errParseString err) {
} catch (const errParseString& err) {
dc_printf("Require string(s) not found: \n");
for (uint j = 0; j < err.expected_tokens.size(); ++j) {
dc_printf("%i: %s\n", j, err.expected_tokens[j].c_str());
@@ -170,7 +170,7 @@ void dc_do_command(SCP_string *cmd_str)
dc_printf("Found '%s' instead\n", err.found_token.c_str());
} catch (errParse err) {
} catch (const errParse& err) {
dc_printf("Invalid argument. Expected %s, found '%s'\n", token_str[err.expected_type], err.found_token.c_str());
}
+1 -1
View File
@@ -20,7 +20,7 @@
#include <cmath>
#include <cstdarg>
#include <cstring>
#include <limits.h>
#include <climits>
// ========================= LOCALS =========================
+541
View File
@@ -0,0 +1,541 @@
#include <nebula/neb.h>
#include <utility>
#include "decals/decals.h"
#include "graphics/2d.h"
#include "graphics/decal_draw_list.h"
#include "graphics/util/uniform_structs.h"
#include "parse/parselo.h"
#include "tracing/tracing.h"
#include "ship/ship.h"
namespace {
class DecalDefinition {
SCP_string _name;
SCP_string _diffuseFilename;
bool _loopDiffuse = true;
SCP_string _glowFilename;
bool _loopGlow = true;
SCP_string _normalMapFilename;
bool _loopNormal = true;
int _diffuseBitmap = -1;
int _glowBitmap = -1;
int _normalBitmap = -1;
public:
explicit DecalDefinition(SCP_string name) : _name(std::move(name)) {
}
~DecalDefinition() {
if (_diffuseBitmap >= 0) {
bm_release(_diffuseBitmap);
}
if (_glowBitmap >= 0) {
bm_release(_glowBitmap);
}
if (_normalBitmap >= 0) {
bm_release(_normalBitmap);
}
}
// Disallow copying
DecalDefinition(const DecalDefinition&) = delete;
DecalDefinition& operator=(const DecalDefinition&) = delete;
// Move constructor and operator
DecalDefinition(DecalDefinition&& other) SCP_NOEXCEPT {
*this = std::move(other); // Use operator implementation
}
DecalDefinition& operator=(DecalDefinition&& other) SCP_NOEXCEPT {
std::swap(_name, other._name);
std::swap(_diffuseFilename, other._diffuseFilename);
std::swap(_glowFilename, other._glowFilename);
std::swap(_normalMapFilename, other._normalMapFilename);
std::swap(_diffuseBitmap, other._diffuseBitmap);
std::swap(_glowBitmap, other._glowBitmap);
std::swap(_normalBitmap, other._normalBitmap);
std::swap(_loopDiffuse, other._loopDiffuse);
std::swap(_loopGlow, other._loopGlow);
std::swap(_loopNormal, other._loopNormal);
return *this;
}
void parse() {
if (optional_string("+Diffuse:")) {
stuff_string(_diffuseFilename, F_FILESPEC);
if (!bm_validate_filename(_diffuseFilename, true, true)) {
error_display(0, "Animation '%s' is not valid!", _diffuseFilename.c_str());
_diffuseFilename = "";
}
if (optional_string("+Loop:")) {
stuff_boolean(&_loopDiffuse);
}
}
if (optional_string("+Glow:")) {
stuff_string(_glowFilename, F_FILESPEC);
if (!bm_validate_filename(_glowFilename, true, true)) {
error_display(0, "Animation '%s' is not valid!", _glowFilename.c_str());
_glowFilename = "";
}
if (optional_string("+Loop:")) {
stuff_boolean(&_loopGlow);
}
}
if (optional_string("+Normal:")) {
stuff_string(_normalMapFilename, F_FILESPEC);
if (!bm_validate_filename(_normalMapFilename, true, true)) {
error_display(0, "Animation '%s' is not valid!", _normalMapFilename.c_str());
_normalMapFilename = "";
}
if (optional_string("+Loop:")) {
stuff_boolean(&_loopNormal);
}
}
}
void loadBitmaps() {
if (_diffuseBitmap == -1 && VALID_FNAME(_diffuseFilename)) {
_diffuseBitmap = bm_load_either(_diffuseFilename.c_str());
if (_diffuseBitmap == -1) {
Warning(LOCATION,
"Bitmap '%s' failed to load for decal definition %s!",
_diffuseFilename.c_str(),
_name.c_str());
}
}
if (_glowBitmap == -1 && VALID_FNAME(_glowFilename)) {
_glowBitmap = bm_load_either(_glowFilename.c_str());
if (_glowBitmap == -1) {
Warning(LOCATION,
"Bitmap '%s' failed to load for decal definition %s!",
_glowFilename.c_str(),
_name.c_str());
}
}
if (_normalBitmap == -1 && VALID_FNAME(_normalMapFilename)) {
_normalBitmap = bm_load_either(_normalMapFilename.c_str());
if (_normalBitmap == -1) {
Warning(LOCATION,
"Bitmap '%s' failed to load for decal definition %s!",
_normalMapFilename.c_str(),
_name.c_str());
}
}
}
void pageIn() {
if (_diffuseBitmap >= 0) {
bm_page_in_texture(_diffuseBitmap);
}
if (_glowBitmap >= 0) {
bm_page_in_texture(_glowBitmap);
}
if (_normalBitmap >= 0) {
bm_page_in_texture(_normalBitmap);
}
}
bool bitmapsLoaded() {
// Since both bitmap types are optional we need to check if either is loaded to determine if any bitmap is loaded
return _diffuseBitmap >= 0 || _glowBitmap >= 0 || _normalBitmap >= 0;
}
const SCP_string& getName() const {
return _name;
}
int getDiffuseBitmap() const {
return _diffuseBitmap;
}
int getGlowBitmap() const {
return _glowBitmap;
}
int getNormalBitmap() const {
return _normalBitmap;
}
bool isDiffuseLooping() const {
return _loopDiffuse;
}
bool isGlowLooping() const {
return _loopGlow;
}
bool isNormalLooping() const {
return _loopNormal;
}
};
SCP_vector<DecalDefinition> decalDefinitions;
// Variable to indicate if the system is able to work correctly on the current system
bool decal_system_active = true;
void parse_decals_table(const char* filename) {
try {
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
required_string("#Decals");
while (optional_string("$Decal:")) {
SCP_string name;
stuff_string(name, F_NAME);
DecalDefinition def(name);
def.parse();
decalDefinitions.push_back(std::move(def));
}
required_string("#End");
} catch (const parse::ParseException& e) {
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
return;
}
if (!gr_is_capable(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)) {
// 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)) {
// WWe 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"));
}
}
struct Decal {
int definition_handle = -1;
object_h object;
int submodel = -1;
float creation_time = -1.0f; //!< The mission time at which this decal was created
float lifetime = -1.0f; //!< The time this decal is active. When negative it never expires
vec3d position = vmd_zero_vector;
vec3d scale;
matrix orientation = vmd_identity_matrix;
Decal() {
vm_vec_make(&scale, 1.f, 1.f, 1.f);
}
bool isValid() {
if (!object.IsValid()) {
return false;
}
if (lifetime > 0.0f) {
if (f2fl(Missiontime) >= creation_time + lifetime) {
// Decal has expired
return false;
}
}
auto objp = object.objp;
if (objp->type == OBJ_SHIP) {
auto shipp = &Ships[objp->instance];
auto model_instance = model_get_instance(shipp->model_instance_num);
Assertion(submodel >= 0 && submodel < model_get(object_get_model(objp))->n_models,
"Invalid submodel number detected!");
auto smi = &model_instance->submodel[submodel];
if (smi->blown_off) {
return false;
}
}
return true;
}
};
SCP_vector<Decal> active_decals;
bool required_string_if_new(const char* token, bool new_entry) {
if (!new_entry) {
return optional_string(token) == 1;
}
required_string(token);
return true;
}
float clamp(float x, float min, float max) {
return std::min(std::max(x, min), max);
}
/**
* @brief Produces a smoothstep value as specified by the GLSL specification
* @param edge0
* @param edge1
* @param x
* @return
*/
float smoothstep(float edge0, float edge1, float x) {
auto t = clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
return t * t * (3.0f - 2.0f * t);
}
}
namespace decals {
void initialize() {
decalDefinitions.clear();
graphics::decal_draw_list::globalInit();
parse_modular_table(NOX("*-dcl.tbm"), parse_decals_table);
}
void shutdown() {
graphics::decal_draw_list::globalShutdown();
// Free allocated resources
decalDefinitions.clear();
}
int getDecalConfig(const SCP_string& name) {
int index = 0;
for (auto& def : decalDefinitions) {
if (!stricmp(def.getName().c_str(), name.c_str())) {
return index;
}
++index;
}
return -1;
}
void parseDecalReference(creation_info& dest_info, bool is_new_entry) {
SCP_string name;
stuff_string(name, F_NAME);
auto decalRef = getDecalConfig(name);
if (decalRef < 0) {
error_display(0, "Decal definition '%s' is unknown!", name.c_str());
}
dest_info.definition_handle = decalRef;
if (required_string_if_new("+Radius:", is_new_entry)) {
stuff_float(&dest_info.radius);
if (dest_info.radius <= 0.0f) {
error_display(0, "Invalid radius of %f! Must be a positive number.", dest_info.radius);
dest_info.radius = 1.0f;
}
}
if (required_string_if_new("+Lifetime:", is_new_entry)) {
if (optional_string("Eternal")) {
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);
}
}
}
void loadBitmaps(const creation_info& info) {
if (!decal_system_active) {
return;
}
// Silently ignore invalid definition handle since weapons use the default values if the decal option is not present
if (info.definition_handle < 0) {
return;
}
Assertion(info.definition_handle >= 0 && info.definition_handle < (int) decalDefinitions.size(),
"Invalid decal handle detected!");
auto& def = decalDefinitions[info.definition_handle];
def.loadBitmaps();
}
void pageInDecal(const creation_info& info) {
if (!decal_system_active) {
return;
}
// Silently ignore invalid definition handle since weapons use the default values if the decal option is not present
if (info.definition_handle < 0) {
return;
}
Assertion(info.definition_handle >= 0 && info.definition_handle < (int) decalDefinitions.size(),
"Invalid decal handle detected!");
decalDefinitions[info.definition_handle].pageIn();
}
void initializeMission() {
active_decals.clear();
}
matrix4 getDecalTransform(Decal& decal) {
Assertion(decal.object.objp->type == OBJ_SHIP, "Only ships are currently supported for decals!");
auto objp = decal.object.objp;
auto ship = &Ships[objp->instance];
vec3d worldPos;
model_instance_find_world_point(&worldPos,
&decal.position,
ship->model_instance_num,
decal.submodel,
&objp->orient,
&objp->pos);
vec3d worldDir;
model_instance_find_world_dir(&worldDir,
&decal.orientation.vec.fvec,
ship->model_instance_num,
decal.submodel,
&objp->orient);
vec3d worldUp;
model_instance_find_world_dir(&worldUp,
&decal.orientation.vec.fvec,
ship->model_instance_num,
decal.submodel,
&objp->orient);
matrix worldOrient;
vm_vector_2_matrix(&worldOrient, &worldDir, &worldUp);
// Apply scaling
worldOrient.a2d[0][0] *= decal.scale.xyz.x;
worldOrient.a2d[0][1] *= decal.scale.xyz.x;
worldOrient.a2d[0][2] *= decal.scale.xyz.x;
worldOrient.a2d[1][0] *= decal.scale.xyz.y;
worldOrient.a2d[1][1] *= decal.scale.xyz.y;
worldOrient.a2d[1][2] *= decal.scale.xyz.y;
worldOrient.a2d[2][0] *= decal.scale.xyz.z;
worldOrient.a2d[2][1] *= decal.scale.xyz.z;
worldOrient.a2d[2][2] *= decal.scale.xyz.z;
matrix4 mat4;
vm_matrix4_set_transform(&mat4, &worldOrient, &worldPos);
return mat4;
}
void renderAll() {
if (!decal_system_active) {
return;
}
// Clear out any invalid decals
for (auto iter = active_decals.begin(); iter != active_decals.end(); ++iter) {
if (!iter->isValid()) {
// if we're sitting on the very last element, popping-back will invalidate the iterator!
if (iter + 1 == active_decals.end()) {
active_decals.pop_back();
break;
}
*iter = active_decals.back();
active_decals.pop_back();
continue;
}
}
if (active_decals.empty()) {
return;
}
graphics::decal_draw_list draw_list;
auto mission_time = f2fl(Missiontime);
for (auto& decal : active_decals) {
int diffuse_bm = -1;
int glow_bm = -1;
int normal_bm = -1;
Assertion(decal.definition_handle >= 0 && decal.definition_handle < (int) decalDefinitions.size(),
"Invalid decal handle detected!");
auto& decalDef = decalDefinitions[decal.definition_handle];
auto decal_time = mission_time - decal.creation_time;
auto progress = decal_time / decal.lifetime;
float alpha = 1.0f;
if (progress > 0.8) {
// Fade the decal out for the last 20% of its lifetime
alpha = 1.0f - smoothstep(0.8f, 1.0f, progress);
}
if (decalDef.getDiffuseBitmap() >= 0) {
diffuse_bm = decalDef.getDiffuseBitmap()
+ bm_get_anim_frame(decalDef.getDiffuseBitmap(), decal_time, 0.0f, decalDef.isDiffuseLooping());
}
if (decalDef.getGlowBitmap() >= 0) {
glow_bm = decalDef.getGlowBitmap()
+ bm_get_anim_frame(decalDef.getGlowBitmap(), decal_time, 0.0f, decalDef.isGlowLooping());
}
if (decalDef.getNormalBitmap() >= 0) {
normal_bm = decalDef.getNormalBitmap()
+ bm_get_anim_frame(decalDef.getNormalBitmap(), decal_time, 0.0f, decalDef.isNormalLooping());
}
draw_list.add_decal(diffuse_bm, glow_bm, normal_bm, decal_time, getDecalTransform(decal), alpha);
}
draw_list.render();
}
void
addDecal(creation_info& info, object* host, int submodel, const vec3d& local_pos, const matrix& local_orient) {
if (!decal_system_active) {
return;
}
// Silently ignore invalid definition handle since weapons use the default values if the decal option is not present
if (info.definition_handle < 0) {
return;
}
Assertion(info.definition_handle >= 0 && info.definition_handle < (int) decalDefinitions.size(),
"Invalid decal handle detected!");
auto& def = decalDefinitions[info.definition_handle];
if (!def.bitmapsLoaded()) {
// If this decal was never used before then the bitmaps are not loaded so we need to do that here.
def.loadBitmaps();
}
Decal newDecal;
newDecal.definition_handle = info.definition_handle;
newDecal.object = object_h(host);
newDecal.submodel = submodel;
newDecal.creation_time = f2fl(Missiontime);
newDecal.lifetime = info.lifetime.next();
newDecal.position = local_pos;
newDecal.orientation = local_orient;
newDecal.scale.xyz.x = info.radius;
newDecal.scale.xyz.y = info.radius;
newDecal.scale.xyz.z = info.radius;
active_decals.push_back(newDecal);
}
}
+87
View File
@@ -0,0 +1,87 @@
#pragma once
#include "globalincs/pstypes.h"
#include "object/object.h"
#include "utils/RandomRange.h"
namespace decals {
/**
* @brief A reference to a decal definition
*/
typedef int DecalReference;
/**
* @brief A structure containing all information for creating a decal
*/
struct creation_info {
DecalReference definition_handle = -1;
float radius = -1.0f;
util::UniformFloatRange lifetime = ::util::UniformFloatRange(-1.0f);
};
/**
* @brief Initializes the global state of the decal system. Call once at game init.
*/
void initialize();
/**
* @brief Parses the information for a decal reference
*
* @details This function expects that the initial token has already been consumed by the parse system.
*
* @param dest_info The creation information struct to parse the information into
* @param is_new_entry Set to @c false if the currently parsed object used +nocreate
*/
void parseDecalReference(creation_info& dest_info, bool is_new_entry = true);
/**
* @brief Loads the bitmaps specified by the creation info into texture memory
*
* This should be called when the bitmaps of the object using this decal are loaded.
*
* @param info The creation information containing the decal definition handle
*/
void loadBitmaps(const creation_info& info);
/**
* @brief Page in the bitmap data of the specified creation information. Needs to be called after loadBitmaps
* @param info The information to page in
*/
void pageInDecal(const creation_info& info);
/**
* @brief Shut down the decal system. Must be called from game_shutdown
*/
void shutdown();
/**
* @brief Initialize the decal system for the mission. Must be called before every mission is started
*/
void initializeMission();
/**
* @brief Renders all currently active decals and removes invalid decals from the active list.
*/
void renderAll();
/**
* @brief Creates a new decal on the specified object at the specified location
*
* @param info The decal to create
* @param host The object host on which to create this decal. Must be a ship.
* @param submodel The submodel of the object model on which to create the decal.
* @param local_pos The position in the frame of reference of the submodel at which the decal should be created.
* @param local_orient The orientation of the decal in the frame of reference of the submodel. The forward vector of the
* orientation should look along the direction
*/
void addDecal(creation_info& info,
object* host,
int submodel,
const vec3d& local_pos,
const matrix& local_orient);
}
-3
View File
@@ -1,3 +0,0 @@
#ControlConfigOverride
#End
+18
View File
@@ -0,0 +1,18 @@
#include "gamma.sdr"
in vec4 fragTexCoord;
in vec4 fragColor;
out vec4 fragOut0;
uniform sampler2DArray baseMap;
uniform float intensity;
void main()
{
vec4 baseColor = texture(baseMap, fragTexCoord.xyz);
baseColor.rgb = srgb_to_linear(baseColor.rgb);
vec4 blendColor = vec4(srgb_to_linear(fragColor.rgb), fragColor.a);
fragOut0 = baseColor * blendColor * intensity;
}
+14
View File
@@ -0,0 +1,14 @@
in vec4 vertPosition;
in vec4 vertTexCoord;
in vec4 vertColor;
out vec4 fragTexCoord;
out vec4 fragColor;
uniform mat4 modelViewMatrix;
uniform mat4 projMatrix;
uniform vec4 color;
void main()
{
fragTexCoord = vec4(vertTexCoord.xyz, 0.0);
fragColor = vertColor * color;
gl_Position = projMatrix * modelViewMatrix * vertPosition;
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
+180
View File
@@ -0,0 +1,180 @@
// NOTE: The technique and some of this code is based on this tutorial:
// http://martindevans.me/game-development/2015/02/27/Drawing-Stuff-On-Other-Stuff-With-Deferred-Screenspace-Decals/
#include "lighting.sdr"
#include "normals.sdr"
#include "gamma.sdr"
out vec4 fragOut0; // Diffuse buffer
out vec4 fragOut1; // Normal buffer
out vec4 fragOut2; // Emissive buffer
uniform sampler2D gDepthBuffer;
uniform sampler2D gNormalBuffer;
uniform sampler2DArray diffuseMap;
uniform sampler2DArray glowMap;
uniform sampler2DArray normalMap;
layout (std140) uniform decalGlobalData {
mat4 viewMatrix;
mat4 projMatrix;
mat4 invViewMatrix;
mat4 invProjMatrix;
vec3 ambientLight;
vec2 viewportSize;
};
layout (std140) uniform decalInfoData {
mat4 model_matrix;
mat4 inv_model_matrix;
vec3 decal_direction;
float normal_angle_cutoff;
int diffuse_index;
int glow_index;
int normal_index;
float angle_fade_start;
float alpha_scale;
int diffuse_blend_mode;
int glow_blend_mode;
};
vec3 computeViewPosition(vec2 textureCoord) {
vec4 clipSpaceLocation;
vec2 normalizedCoord = textureCoord / viewportSize;
clipSpaceLocation.xy = normalizedCoord * 2.0f - 1.0f;
clipSpaceLocation.z = texelFetch(gDepthBuffer, ivec2(textureCoord), 0).r * 2.0f - 1.0f;
clipSpaceLocation.w = 1.0f;
vec4 homogenousLocation = invProjMatrix * clipSpaceLocation;
return homogenousLocation.xyz / homogenousLocation.w;
}
vec3 getPixelNormal(vec3 frag_position, vec2 tex_coord, inout float alpha, out vec3 binormal, out vec3 tangent) {
#ifdef USE_NORMAL_MAP
// If we can then we just use the existing normal buffer
vec3 normal = texelFetch(gNormalBuffer, ivec2(tex_coord), 0).xyz;
// If we use the normal map then we don't really need these values so we don't need to compute them here
binormal = vec3(0.0);
tangent = vec3(0.0);
#else
// Use some fancy screen-space derivates to determine the normal of the current pixel by looking at the surrounding pixels
vec3 pos_dx = dFdx(frag_position);
vec3 pos_dy = dFdy(frag_position);
vec3 normal = normalize(cross(pos_dx, pos_dy));
binormal = normalize(pos_dx);
tangent = normalize(pos_dy);
#endif
//Calculate angle between surface normal and decal direction
float angle = acos(dot(normal, decal_direction));
if (angle > normal_angle_cutoff) {
// The angle between surface normal and decal direction is too big
discard;
}
// Make a smooth alpha transition leading up to an edge
alpha = alpha * (1 - smoothstep(angle_fade_start, normal_angle_cutoff, angle));
return normal;
}
vec2 getDecalTexCoord(vec3 view_pos, inout float alpha) {
vec4 object_pos = inv_model_matrix * invViewMatrix * vec4(view_pos, 1.0);
bvec3 invalidComponents = greaterThan(abs(object_pos.xyz), vec3(0.5));
bvec4 nanComponents = isnan(object_pos); // nan can happen some times if we have an infinite depth value
if (any(invalidComponents) || any(nanComponents)) {
// Fragment is out of the box
discard;
}
// Fade out the texture when it gets close to the top or bottom of the decal box
alpha = alpha * (1.0 - smoothstep(0.4, 0.5, abs(object_pos.z)));
return object_pos.xy + 0.5;
}
void main() {
vec3 frag_position = computeViewPosition(gl_FragCoord.xy);
float alpha = alpha_scale;
vec2 tex_coord = getDecalTexCoord(frag_position, alpha);
vec3 binormal;
vec3 tangent;
vec3 normal = getPixelNormal(frag_position, gl_FragCoord.xy, alpha, binormal, tangent);
vec4 diffuse_out = vec4(0.0);
vec4 emissive_out = vec4(0.0, 0.0, 0.0, 0.0);
vec3 normal_out = vec3(0.0);
if (diffuse_index >= 0) {
// We have a valid diffuse map
vec4 color = texture(diffuseMap, vec3(tex_coord, float(diffuse_index)));
color.rgb = srgb_to_linear(color.rgb);
if (diffuse_blend_mode == 0) {
// Normal alpha blending
diffuse_out = vec4(color.rgb, color.a * alpha);
} else {
// Additive blending
diffuse_out = vec4(color.rgb * alpha, 1.0);
}
// The main model shader applies ambient lighting by drawing the ambient part of the texture into the emissive
// texture. We do the same here to make sure the decal material is applied correctly
if (glow_blend_mode == 0) {
// Normal alpha blending
emissive_out = vec4(color.rgb * ambientLight, color.a * alpha);
} else {
// Additive blending
emissive_out = vec4(alpha * color.rgb * ambientLight, 1.0);
}
}
if (glow_index >= 0) {
// We have a valid diffuse map
vec4 color = texture(glowMap, vec3(tex_coord, float(glow_index)));
color.rgb = srgb_to_linear(color.rgb) * GLOW_MAP_SRGB_MULTIPLIER;
color.rgb *= GLOW_MAP_INTENSITY;
if (glow_blend_mode == 0) {
// Normal alpha blending
emissive_out = vec4(color.rgb + emissive_out.rgb * emissive_out.a, color.a * alpha);
} else {
// Additive blending
emissive_out.rgb += color.rgb * alpha;
}
}
if (normal_index >= 0) {
vec3 decalNormal = unpackNormal(texture(normalMap, vec3(tex_coord, float(normal_index))).ag);
mat3 tangentToView;
tangentToView[0] = tangent;
tangentToView[1] = binormal;
tangentToView[2] = normal;
normal_out = tangentToView * decalNormal * alpha;
}
fragOut0 = diffuse_out;
fragOut1 = vec4(normal_out, 0.0);
fragOut2 = emissive_out;
}
+33
View File
@@ -0,0 +1,33 @@
in vec4 vertPosition;
layout (std140) uniform decalGlobalData {
mat4 viewMatrix;
mat4 projMatrix;
mat4 invViewMatrix;
mat4 invProjMatrix;
vec3 ambientLight;
vec2 viewportSize;
};
layout (std140) uniform decalInfoData {
mat4 model_matrix;
mat4 inv_model_matrix;
vec3 decal_direction;
float normal_angle_cutoff;
int diffuse_index;
int glow_index;
int normal_index;
float angle_fade_start;
float alpha_scale;
int diffuse_blend_mode;
int glow_blend_mode;
};
void main() {
gl_Position = projMatrix * viewMatrix * model_matrix * vertPosition;
}
@@ -1,18 +1,23 @@
#include "gamma.sdr"
in vec4 fragTexCoord;
in vec4 fragColor;
out vec4 fragOut0;
uniform sampler2D baseMap;
uniform sampler2DArray baseMap;
uniform int baseMapIndex;
uniform int alphaTexture;
uniform int noTexturing;
uniform int srgb;
uniform float intensity;
uniform float alphaThreshold;
#define SRGB_GAMMA 2.2
void main()
{
vec4 baseColor = texture(baseMap, fragTexCoord.xy);
vec4 baseColor = texture(baseMap, vec3(fragTexCoord.xy, float(baseMapIndex)));
if(alphaThreshold > baseColor.a) discard;
baseColor.rgb = (srgb == 1) ? pow(baseColor.rgb, vec3(SRGB_GAMMA)) : baseColor.rgb;
vec4 blendColor = (srgb == 1) ? vec4(pow(fragColor.rgb, vec3(SRGB_GAMMA)), fragColor.a) : fragColor;
baseColor.rgb = (srgb == 1) ? srgb_to_linear(baseColor.rgb) : baseColor.rgb;
vec4 blendColor = (srgb == 1) ? vec4(srgb_to_linear(fragColor.rgb), fragColor.a) : fragColor;
fragOut0 = mix(mix(baseColor * blendColor, vec4(blendColor.rgb, baseColor.r * blendColor.a), float(alphaTexture)), blendColor, float(noTexturing)) * intensity;
}
}
Loaded 100 of 1031 files, more files were not shown because too many files have changed in this diff. Show more