Compare commits

...
Author SHA1 Message Date
asarium 34bcb03ef8 Add text rendering using signed distance fonts
Signed distance fonts have the advantage that they can be used to apply
complicated effects at runtime without having to rerender the text on
the CPU. This would make it possible to add support for rendering the
outline of the text using a different color but this currently only
renders the text like before.
2017-12-19 13:22:50 +01: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
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 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
m!m b1b197cc9a Merge pull request #1440 from ln-zookeeper/asteroid_null_vec_fix
Fix for a null vector normalization
2017-08-21 09:54:09 +02:00
Lari Nieminen 941b7298cc Fix for a null vector normalization
If the asteroid split rules were used and the asteroid speed happened to be 0 (for example if the field has an average speed of 0), the code would try to normalize a null vector. Now, a random vector is chosen in those cases.
2017-08-21 10:09:18 +03: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
m!m 637a9621f1 Merge pull request #1436 from Goober5000/pr_922_followup
fix typo in AI flag conversion
2017-08-14 23:41:44 +02:00
Goober5000 70c5aa88f2 then again, we should really assert on both 2017-08-11 18:05:13 -04:00
Goober5000 1857f9b928 fix typo in AI flag conversion 2017-08-11 17:53:42 -04:00
asarium 90c23c007c Add config option for setting the FF strength 2017-08-10 10:09:02 +02:00
Fabian Woltermann fb4169ba9f Merge pull request #1429 from asarium/fix/ffEffectStrength
Lower Afterburner force feedback effect strength to previous levels
2017-08-08 14:35:35 +02:00
Fabian Woltermann 1448256140 Merge pull request #1430 from asarium/fix/nightlyDeploy
Fix Travis CI nightly deploy
2017-08-03 18:02:11 +02:00
asarium 7de592bf9b Fix Travis CI nightly deploy
I have no idea why this doesn't work anymore. I didn't even touch that
line when I added the test build stuff...
2017-08-03 17:18:48 +02:00
asarium 783852a115 Lower Afterburner force feedback effect strength to previous levels
This was suggested by taylor on the forums and should match the previous
values more closely.
2017-08-03 08:55:50 +02:00
Fabian Woltermann 84fd7123a5 Merge pull request #1420 from asarium/fix/1417
Restart spring effect after stopping all FF effects
2017-08-02 08:23:26 +02:00
m!m ff9d06cfe1 Merge pull request #1427 from The-E/weaponloadout_fix
Fix error message for failure to load mask file in weaponloadout
2017-07-28 10:16:46 +02:00
Fabian Woltermann a158029120 When loading the mask file fails, correctly report which file we were trying to load. 2017-07-27 22:53:33 +02:00
m!m 96e8d5b66e Merge pull request #1426 from Goober5000/issue_1425_fix
for backwards compatibility, check both no-collide and no_collide
2017-07-26 15:41:47 +02:00
asarium 85fd0b0498 Restart spring effect after stopping all FF effects
SDL_HapticStopAll stops all effects, including the spring effect so the
joystick goes limp after one mission (joy_ff_stop_effects gets called at
the end of each mission).

This restarts the spring effect which should fix that issue.

This fixes #1417.
2017-07-26 11:00:50 +02:00
Fabian Woltermann 5d3e6789e6 Merge pull request #1422 from asarium/build/ciTestBuilds
Add support for building test builds on the CI servers
2017-07-26 10:59:56 +02:00
Goober5000 b8e5a395dd for backwards compatibility, check both no-collide and no_collide 2017-07-25 18:44:41 -04:00
asarium 1a1c3df379 Add support for building test builds on the CI servers
Any branch starting with "test/" will cause test builds to be compiled
and uploaded to fs2downloads. This will only work for the main
repository since the secure variables for the FTP credentials only work
for that repository.
2017-07-25 11:37:11 +02:00
Fabian Woltermann 0dc0d67c76 Merge pull request #1421 from asarium/build/releaseSources
Build a compressed package of the source as part of a release
2017-07-24 15:29:16 +02:00
asarium 0edb360fc2 Build a compressed package of the source as part of a release
This package will include the externals which are not present in the
default GitHub export.
2017-07-24 10:53:40 +02:00
Fabian Woltermann 1743e5f5d4 Merge pull request #1419 from ln-zookeeper/on_ship_arrive_wing_fix
Fixed $On Ship Arrive hooks not firing on wing arrivals
2017-07-23 17:09:21 +02:00
MageKing17 ed3f07284d Merge pull request #1418 from The-E/shader_normal_fix
Fix bug in normal map rendering
2017-07-23 06:07:55 -07:00
Fabian Woltermann c1b222ffd5 Old calculation apparently correct, just needs clamping applied. 2017-07-22 20:25:52 +02:00
Fabian Woltermann 3503b9214b Remove unnecessary punctuation 2017-07-21 20:06:53 +02:00
Lari Nieminen aff8cc8095 Fixed $On Ship Arrive hooks not firing on wing arrivals 2017-07-20 16:13:20 +03:00
Fabian Woltermann 884581a836 Reapply the fix from https://github.com/scp-fs2open/fs2open.github.com/commit/8e0304a5 2017-07-20 12:20:44 +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
Fabian Woltermann 98af9dd903 Merge pull request #1404 from Goober5000/debug_sexp_tweak
minor enhancements to the debug sexp
2017-07-13 18:05:34 +02:00
m!m ea37b3cb17 Merge pull request #1411 from Goober5000/issue_1400_followup
use IS_VEC_NULL for floating point safety, plus a few minor touchups
2017-07-11 14:45:03 +02:00
Fabian Woltermann 3035a868ab Merge pull request #1401 from asarium/fix/ttfSpecialCharacters
Correctly apply scaling to TTF rendered strings
2017-07-09 20:48:12 +02:00
Goober5000 a88c50b6f2 per comments, allow variable replacement in plain strings as well 2017-07-09 14:31:36 -04:00
Goober5000 ac24ca9fd3 use IS_VEC_NULL for floating point safety, plus a few minor touchups 2017-07-09 14:11:42 -04:00
MageKing17 d085951767 Merge pull request #1400 from asarium/fix/fredInvalidIndex
Fix invalid indexing in object orientation editor
2017-07-09 03:42:04 -07:00
MageKing17 c3f19631ce Merge pull request #1402 from asarium/fix/profilingAssert
Discard non-main thread events for the frame profiler
2017-07-09 03:41:10 -07:00
m!m ca9eff3bc5 Merge pull request #1405 from MageKing17/bugfix/ani-unloading
Fix unloading streaming ANI files.
2017-07-09 12:36:55 +02:00
MageKing17 0a19616bc9 Correct inconsistency in anim_load() regarding memory-mapped files.
In commit 735f5e199b randomtiger changed how anim_load() worked in seemingly-bizarre ways, for reasons unclear to me. In brief, a condition's logic was reversed, a three-value enum was created of which only one value was used, and as a result loose files passed to anim_load() (and only loose files) would be opened as "memory-mapped", one consequence of which is that they'd keep a cfile block open until the corresponding call to anim_free() (which means that, if a mission had enough different loose animations, the cfile block limit could be reached). Since files in packfiles behaved the same way they always had (namely, being loaded into memory and then closed, thereby not taking up a cfile block), apparently nobody noticed the difference, and this inconsistent code has stayed for the past 13-and-a-half years.

This commit changes the condition after the one changed in the older commit so that they both match, then changes the enum so that the seemingly-meaningless third value is removed, and the other two values are swapped (and the default value of the file_mapped parameter to anim_load() changed) so that the original Volition behavior is restored.
2017-07-09 02:39:40 -07:00
m!m 255e9aa21e Merge pull request #1406 from asarium/build/nightlySFTP
Fix SFTP path and mac upload
2017-07-07 23:31:09 +02:00
asarium 550f459747 Fix SFTP path and mac upload 2017-07-07 18:03:07 +02:00
MageKing17 6da72bb1a0 Fix inverted order of unloading streaming ANI files.
When streaming an ANI file, first anim_load() is called, then init_anim_instance(). The latter increments the animation's instance_count. If anim_free() is called on an animation that still has instances, it refuses to free the animation. generic_anim_unload() first called anim_free(), then free_anim_instance().

The fact that ANI files would ever unload at all seems to be because some code would unload twice. I can only assume that, combined with the fact that the bug only applies to ANI files, explains how this bug went undetected since November of 2009 (commit b43417882f seems to be when it was added, from a quick glance at git blame).
2017-07-07 01:23:20 -07:00
MageKing17 c7fbefeb58 Remove potentially-harmful condition in message_mission_free_avi()
If we tell it to free up the animation, I think it should happen regardless of whether or not the HUD_TALKING_HEAD gauge is currently active or not. Also, unloading an animation shouldn't crash even if one wasn't loaded in the first place... and if it does, we should probably fix that instead of slapping a band-aid on the calling function.
2017-07-07 01:18:09 -07:00
Goober5000 98e316bca6 minor enhancements to the debug sexp 2017-07-07 01:25:54 -04:00
Cliff Gordon 78a1e5baab Merge pull request #1403 from asarium/build/nightlySFTP
Compile curl with SSH support for nightly deploy
2017-07-06 15:17:48 -05:00
asarium 080ce8419a Compile curl with SSH support for nightly deploy 2017-07-06 17:58:48 +02:00
asarium 06e9248079 Discard non-main thread events for the frame profiler
The old code is not able to handle multi-threaded events so this change
simply filters out all the events that originated from another thread.

This fixes an Assertion caused by an invalid event.
2017-07-06 10:10:52 +02:00
asarium e04c60ed6f Align special characters to the base line of the rendered string 2017-07-05 18:13:45 +02:00
asarium 81d9ca8e4a Correctly apply scaling to TTF rendered strings
This fixes weird misplaced special characters since the TTF strings
weren't rendered at the right position. This should fix that.

This fixes an issue reported on the forums by Novachen.
2017-07-05 09:09:38 +02:00
asarium bf2ca61e5a Fix invalid indexing in object orientation editor
This could happen if the user enabled "Point to" and selected "Object"
without having an object selected. This can only happen when there is
only one object in the mission so it's only a minor bug but still
something worth fixing.
2017-07-03 20:11:06 +02: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
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
Fabian Woltermann ffe647be79 Merge pull request #1393 from asarium/build/gitHubPrebuilts
Use GitHub prebuilt URL
2017-07-01 14:09:02 +02:00
Fabian Woltermann fff2e6d1fc Merge pull request #1394 from Goober5000/issue_1381_followup
Use the already-determined sexp argument type
2017-07-01 14:08:22 +02:00
Fabian Woltermann 23e46ae7c4 Merge pull request #1395 from Goober5000/issue_1256_followup
Better handling of positive/negative discrepancy as well as finding sexp node arguments
2017-07-01 14:07:57 +02:00
MageKing17 74d270270e Merge pull request #1397 from ngld/fix_shockwave_load
Fix "Error: Can't open model file <shockwave.pof>" on second mission load
2017-06-29 14:36:00 -07:00
ngld df69d195fe Fix "Error: Can't open model file <shockwave.pof>" on second mission load 2017-06-29 21:10:56 +02:00
Goober5000 6c871ac339 better handling of positive/negative discrepancy as well as finding sexp node arguments 2017-06-29 01:56:55 -04:00
Goober5000 24afebb808 instead of manually checking the sexp operator and argument number, just use the already-determined argument type 2017-06-28 19:10:14 -04:00
Fabian Woltermann 6aac8c7bde Merge pull request #1391 from asarium/fix/specialCharacterFontAssertion
Fix Assertion when default Volition font could not be found
2017-06-27 16:00:11 +02:00
asarium a2da77e14c Fix Assertion when default Volition font could not be found
Instead, this will now cause a Warning when the issue is detected while
parsing the table and an Error when it still occurs at runtime.
2017-06-27 11:56:20 +02:00
Fabian Woltermann 7ca6b679b7 Merge pull request #1390 from asarium/fix/luaWhitespace
Ignore leading whitespace for gr.drawString
2017-06-27 09:36:46 +02:00
asarium 3d6bbb0b9b Ignore leading whitespace for gr.drawString
This was reported by @AxemP who wanted to have leading tabs in a text
line. However, split_str removed those characters by default since it
ignores leading whitespace. To fix that unexpected behavior of
gr.drawString I added a new paramter to split_str which disabled
whitespace removal and enabled that flag for the scripting function.

That should not be a problem for existing scripts since the expected
behavior would be that leading whitespace remains in place and since we
have not received any bug reports about missing white space I'm going to
assume that no one has used the function like this before removed those
characters by default since it ignores leading whitespace. To fix that
unexpected behavior of gr.drawString I added a new paramter to split_str
which disabled whitespace removal and enabled that flag for the
scripting function.

That should not be a problem for existing scripts since the expected
behavior would be that leading whitespace remains in place and since we
have not received any bug reports about missing white space I'm going to
assume that no one has used the function like this before.
2017-06-25 17:19:40 +02:00
asarium a912956601 Use GitHub prebuilt URL 2017-06-24 13:33:09 +02:00
m!m a769a7ef87 Merge pull request #1388 from Goober5000/sexp_targeted_fix
fix an old Volition bug in the targeted sexp
2017-06-24 09:20:43 +02:00
m!m 991e09006e Merge pull request #1387 from Goober5000/small_error_msg_fix
Small improvement in error messages in stuff_int_list and mark_int_list
2017-06-24 09:17:01 +02:00
Goober5000 3e6c3f6f62 this actually affects subsystems too 2017-06-24 01:05:08 -04:00
Goober5000 2ee3dd70ea fix an old Volition bug in the targeted sexp 2017-06-24 00:56:25 -04:00
Goober5000 c259dfb9cd improve error messages 2017-06-23 23:32:57 -04:00
m!m 2947c7972d Merge pull request #1386 from MageKing17/bugfix/opengl-framebuffer-warning
Get rid of OpenGL warnings about the framebuffer being unsupported.
2017-06-22 08:44:39 +02:00
MageKing17 eda8c65b58 Get rid of OpenGL warnings about the framebuffer being unsupported.
At least on NVidia drivers, the medium-severity warning "Framebuffer unsupported. Framebuffer object Scene framebuffer is unsupported because the depth and stencil attachments are mismatched." would get repeatedly output to the debug log. @SamuelCho suggested this change, which gets rid of the warnings and doesn't appear to have introduced any graphical glitches.

Fixes #1382.
2017-06-21 14:50:41 -07:00
m!m 186f8ff5b9 Merge pull request #1376 from z64555/cleanup/lua_reporting
Adds LUA versioning and copyright info to the scripting.html output
2017-06-21 08:45:40 +02:00
m!m c86c4c3822 Merge pull request #1385 from MageKing17/bugfix/message-shipnum-ship-vanish
Avoid faulty assumption in message bracket code.
2017-06-21 08:42:22 +02:00
m!m bea9d56feb Merge pull request #1384 from MageKing17/bugfix/collision-group-sexp
Fix removing a collision group via SEXP.
2017-06-21 08:41:41 +02:00
Goober5000 dc6d2be515 Merge pull request #1381 from Goober5000/fix_default_operator_for_modify_variable
Fix handling of arguments for sexps that use variables
2017-06-21 01:49:31 -04:00
Tyler Blount 298ec5519c Merge pull request #1383 from MageKing17/bugfix/profiling-category-duplicate
Fix duplicate tracing/profiling category.
2017-06-20 21:02:24 -06:00
MageKing17 7025e3443e Avoid faulty assumption in message bracket code.
This assertion could apparently be hit if a ship was vanished (e.g. with ship-vanish) in the middle of talking. Rather than making the vanishing code aware of (and responsible for) Message_shipnum, it seemed simpler to just make hud_show_message_sender() clear the invalid shipnum itself.
2017-06-20 19:20:41 -07:00
Tyler Blount 88b87b86fc Merge pull request #1378 from asarium/fix/fredHasShields
Fix inverted "Has shields" flag in initial status dialog
2017-06-20 19:54:05 -06:00
asarium b34ca3cfed Fix handling of inconsistent values in initial status editor
The flagset changes probably broke this behavior by not respecting the "inconsistent" value set by the OnInit function when ships have inconsistent values for a specific flag. This should fix that and restore the 3.7.4 behavior.
2017-06-20 20:01:57 +02:00
z64555 1b2eece53a Adds LUA versioning info to the scripting.html output
* Credits roll now grabs the LUA copyright info from liblua, instead of being hardcoded
* Credits roll now has LUA version info as well
2017-06-20 08:22:25 -05:00
Goober5000 e8313fa577 fix handling of arguments for sexps that use variables 2017-06-19 20:04:15 -04:00
asarium 5a8454e956 Fix inverted "Has shields" flag in initial status dialog 2017-06-17 18:18:12 +02:00
MageKing17 f6b1eaa846 Fix duplicate tracing/profiling category.
Cutscene audio decoding was accidentally named "FFmpeg decode video", causing some minor problems in the profiling code (because the same name is used for actual video decoding, resulting in an assertion firing).
2017-06-15 16:16:29 -07:00
MageKing17 d20ff9b367 Fix removing a collision group via SEXP.
sexp_manipulate_colgroup() was using logical NOT when it should've been using bitwise NOT, meaning that removing any collision group would remove all collision groups.
2017-06-15 15:49:51 -07:00
MageKing17 a3ab30cd96 Merge pull request #1374 from TRBlount/fix/lua_weapon_team
Make l_weapon use IFFs in Team var
2017-06-14 15:22:52 -07:00
TRBlount 48f76f7cd1 Fix l_weapon Team set var logic 2017-06-13 20:31:51 -06:00
MageKing17 eb165123ac Merge pull request #1371 from MageKing17/bugfix/3d-framebuffer-shockwaves
Fix combining 3D shockwaves with framebuffer shockwaves.
2017-06-10 14:33:13 -07: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
MageKing17 c30ce55942 Fix combining 3D shockwaves with framebuffer shockwaves.
If framebuffer shockwaves were enabled and a 3D shockwave was created, FSO would use a hardcoded reference to the second slot of the Shockwave_info vector to generate the framebuffer shockwave for it. This only makes sense if and only if:
- the 3D shockwave command-line flag is also enabled
- the default 3D shockwave and default 2D shockwave are both present and loaded
- its the first mission of the session (because after that any shockwave not in the 0th index got unloaded)

I've changed the code so that which index the default 2D shockwave got loaded into gets tracked and used instead of a hardcoded index... and if both default shockwaves are loaded, the first two Shockwave_info indices are both kept between missions instead of just the first. This should allow framebuffer shockwaves to work with 3D shockwaves, regardless of whether or not it's the first mission of the session and whether or not a custom 2D shockwave was loaded (and happened to wind up at index 1). Slight downside in that missing the default 2D shockwave file, but having a custom 2D shockwave loaded, will now result in framebuffer shockwaves not being drawn at all, rather than using the custom 2D shockwave by accident; not sure that's really all that much of a problem, though.
2017-06-10 10:38:02 -07:00
m!m 9447d74da8 Merge pull request #1367 from Goober5000/invisible_beam_section_fix
Invisible beam section fix
2017-06-09 23:51:31 +02:00
Goober5000 043e6a79a8 remove debug conditions when we are not in debug mode 2017-06-09 12:55:32 -04:00
Goober5000 97416feb2a Merge pull request #1368 from asarium/fix/1366
Remove abort call from debug_int3
2017-06-09 12:48:27 -04:00
asarium aac3bbde8e Remove abort call from debug_int3
This fixes #1366.
2017-06-09 10:19:48 +02:00
Goober5000 8f3ef45fc9 don't remove invisible beam sections 2017-06-08 22:18:02 -04:00
Goober5000 762997fc7d copy over more verbose assertions from light_add_cone 2017-06-08 22:17:24 -04:00
MageKing17 43a46641eb Merge pull request #1364 from The-E/UnknownShips
Handle ships removed from play via ship-vanish correctly in ai goal processing
2017-06-05 20:58:40 -07:00
Fabian Woltermann 47bd990bca Handle ships removed from play via ship-vanish correctly in ai goal processing. 2017-06-05 15:00:10 +02:00
m!m ec3313ffea Merge pull request #1363 from MageKing17/bugfix/generic-anim-static-png
Reset generic animation type to BM_TYPE_NONE if APNG processing fails.
2017-06-04 09:40:27 +02:00
MageKing17 f2c099a7a9 Reset generic animation type to BM_TYPE_NONE if APNG processing fails.
Prior to APNG support, a regular non-animated PNG could be used as a still-frame command briefing animation. This started causing a crash when APNG support was added because any PNGs sent through generic_anim_stream() would get ga->type set to BM_TYPE_PNG, then sent through the APNG code... which would determine that they weren't APNGs, throw an ApngException, and generic_anim_stream() would return -1... except that BM_TYPE_PNG would still be set, so that when it later came time to render the still frame in generic_frame_render(), it would be sent through generic_anim_render_variable_frame_delay()... which expected a fully-formed APNG, tried to dereference ga->png.anim, and crashed.

This commit is a simple fix to reset ga->type to BM_TYPE_NONE if APNG processing fails, allowing the still-frame PNG to go through generic_anim_render_fixed_frame_delay(), the code path it used to take, and allowing it to display properly instead of crashing.
2017-06-03 22:07:52 -07:00
Fabian Woltermann e6c6cc3864 Merge pull request #1352 from asarium/feature/trackIr64bit
Use TrackIR DLL with 64 suffix when compiling a 64-bit build
2017-06-02 11:10:42 +02:00
m!m 5ee1b6d243 Merge pull request #1362 from MageKing17/cleanup/shockwave-vector-usage
Cleaning up the shockwave code's use of vectors and assertions.
2017-06-01 21:24:28 +02:00
MageKing17 3577c005e2 Merge pull request #1357 from asarium/fix/openglIncludes
Remove include of OpenGL header in non-OpenGL code
2017-06-01 12:11:09 -07:00
MageKing17 b2891bfe21 Merge pull request #1361 from MageKing17/bugfix/auto-convergence-min-distance
Allow "+Minimum Distance:" to actually work with automatic convergence.
2017-06-01 12:10:32 -07:00
MageKing17 82aa027d0d Cleaning up the shockwave code's use of vectors and assertions.
After someone tripped an assertion in the shockwave code which provided no details, I found some... questionable vector-related code. I changed all the code I could find that looped through the vector with iterator-based code, converted most Asserts into Assertions for more informative debugging, and added a couple Assertions to check previously-unchecked assumptions (which theoretically should never be tripped, but we'll see). A test build with the vector fixes resulted in the assertion no longer tripping so I'm fairly sure the improper erasure of the vector was causing problems (leftover data from a previous mission with a model number that no longer made sense because the model was unloaded).
2017-06-01 11:38:44 -07:00
MageKing17 902d40f3df Allow "+Minimum Distance:" to actually work with automatic convergence.
The gun convergence code would detect if the target was within the minimum distance and move the predicted target point farther away if so, but wouldn't also alter the dist_to_aim variable to match; since predicted_target_pos is used by the autoaim code while dist_to_aim is what automatic convergence uses, this meant automatic convergence didn't respect the minimum distance at all.

Looks like this was broken in 7bb10d8408.
2017-05-30 09:52:27 -07:00
m!m e82fc4ac2f Merge pull request #1359 from MageKing17/bugfix/rearm-loading-start-sounds
Allow rearm start sound effects to actually play.
2017-05-29 11:41:51 +02:00
MageKing17 71673241fd Allow rearm start sound effects to actually play.
SND_MISSILE_START_LOAD and SND_BALLISTIC_START_LOAD (indices 33 and 200, respectively) could never actually play due to a logic error (they checked that a variable was true and the loop was on the last bank, when those conditions being met earlier in the function set that same variable to false). As far as I can tell, this broke back in 2006 with commit f300716e93.
2017-05-29 01:40:13 -07:00
Fabian Woltermann f93cb23d43 Merge pull request #1358 from asarium/fix/fastDebugDebugging
Use correct variable when copying linker flags to fast debug
2017-05-29 09:48:36 +02:00
asarium 0415b69407 Use correct variable when copying linker flags to fast debug
This broke the release debugging flag for fast debug which should be
fixed by these changes.
2017-05-29 09:19:18 +02:00
asarium e4775948d7 Remove include of OpenGL header in non-OpenGL code 2017-05-28 10:35:33 +02:00
asarium 8958de35bc Use TrackIR DLL with 64 suffix when compiling a 64-bit build
This should make it possible to have both DLL version installed at the
same time without causing conflicts.

Combined with the new DLL, this will finally fix #974.
2017-05-18 10:52:25 +02:00
m!m c03dbea7ea Merge pull request #1349 from MageKing17/bugfix/avoid-rank-int3
Avoid Int3() when finding a rank with an out-of-order points value.
2017-05-18 09:11:12 +02:00
MageKing17 9107da8c9c Merge pull request #1351 from asarium/fix/1350
Readd warning dialog counting
2017-05-17 09:55:06 -07:00
MageKing17 1abb1833aa Avoid Int3() when finding a rank with an out-of-order points value.
There's a bit of debug code that checks to make sure all ranks are in ascending point order; if this check fails, FSO calls Int3() instead of trying to describe the problem. I've changed it to a Warning that actually explains the problem, so the modder can fix it.
2017-05-17 09:03:32 -07:00
asarium a2e70b8c5c Readd warning dialog counting
This fixes #1350.
2017-05-17 17:14:12 +02:00
Fabian Woltermann 1029de8073 Merge pull request #1348 from asarium/fix/hudReticleInt3
Remove unneded Int3 in hudreticle.cpp
2017-05-07 17:57:32 +02:00
asarium 3abcb24815 Remove unneded Int3 in hudreticle.cpp
The code works perfectly find without it and it causes issues with a
release campaign so there is no reason to keep it.
2017-05-07 17:20:48 +02:00
m!m 13d68bdfc6 Merge pull request #1347 from MageKing17/bugfix/cmdline-double-parse
Stop parsing cmdline_fso.cfg twice in legacy mode.
2017-05-06 12:05:19 +02:00
Fabian Woltermann de0bbaa4f6 Merge pull request #1339 from asarium/fix/mantis3195
Revert bad fix for Coverity issue
2017-05-06 11:35:39 +02:00
MageKing17 ce569d400e Stop parsing cmdline_fso.cfg twice in legacy mode.
os_init_cmdline() contains the legacy-mode codepath in a conditional, but then doesn't put the non-legacy mode code in an else branch, resulting in cmdline_fso.cfg getting processed twice, leading to e.g. every mod getting loaded twice (which can cause all kinds of issues). This just wraps the non-legacy code in an else branch so that FSO running in legacy mode won't do both.
2017-05-05 17:23:02 -07:00
MageKing17 adb94dc4d2 Merge pull request #1346 from The-E/anim_load_fix
Adds a small sanity check after reading an ani header
2017-05-05 01:17:36 -07:00
MageKing17 916082d910 Merge pull request #1345 from asarium/fix/1344
Save mission flags using correct format specifier
2017-05-05 01:16:36 -07:00
Fabian Woltermann e52f23d45d Adds a small sanity check after reading an ani header 2017-05-04 19:18:06 +02:00
asarium 2dfc086c94 Add unit test for checking numeric conversions 2017-05-02 11:47:21 +02:00
asarium 0a53aff061 Clean up flagset handling of numeric values
This renames the functions exposed by flagset so that it's clear that
64-bit values are returned. This also cleans up usages of wrong format
specified when that value is printed which caused some issues in the
past.

This should also fix #1336.
2017-05-02 10:28:29 +02:00
asarium 2dab381e88 Save mission flags using correct format specifier
The current version simply writes the flagset object as an integer to
the mission file which surely will cause issues.

This fixes #1344.
2017-05-02 09:57:19 +02:00
MageKing17 83514409f3 Merge pull request #1334 from asarium/fix/laserParticleEffect
Fix assertion when applying particle effect to laser
2017-04-26 09:57:08 -07:00
Cliff Gordon 340f39f44d Merge pull request #1343 from asarium/build/appveyorFTPKeys
Fix encrypted login data for appveyor FTP upload
2017-04-26 07:40:24 -05:00
m!m 418a944127 Merge pull request #1341 from chief1983/fix/solaris_math_h
Fix several issues blocking a Solaris compile
2017-04-26 10:19:33 +02:00
asarium 22180c0b45 Fix encrypted login data for appveyor FTP upload
I encrypted those values using my user instead of our SirKnightly
account which meant that the values failed to decrypt. These new values
were encrypted using the SirKnightly user which should allow Appveyor to
upload the nightly builds to our FTP servers.
2017-04-26 10:15:11 +02:00
Cliff Gordon 2949ca2628 Merge pull request #1342 from asarium/build/ftpNightlies
Upload nightly builds to FTP instead of BinTray
2017-04-25 13:54:43 -05:00
asarium dbf952e031 Upload nightly builds to FTP instead of BinTray
Since BinTray may be unreliable as our nightly host @chief1983 and I
decided that it would be best to return hosting to our dedeicated FTP
servers. These changes implement that together with a pending pull
request for the nightly script.
2017-04-25 19:55:34 +02:00
asarium 5b1285e608 Revert bad fix for Coverity issue
fa60c666bc tried to fix an issue reported
by Coverity which was an intentional "issue". This restores the original
behavior which will cause a new coverity issue which can be ignored.

This fixes Mantis 3195.
2017-04-24 11:16:11 +02:00
Cliff Gordon accbc1d25d See if this helps with the linking errors for libsocket and libnsl symbols. 2017-04-21 15:12:15 -05:00
Cliff Gordon 8acff8e02c Add the INTEL_LONG define that was added to the other two blocks last year but not to Solaris. 2017-04-21 14:26:13 -05:00
Cliff Gordon 89d13ab774 fix/solaris_math_h: Attempt to work around the version symbol conflict. 2017-04-21 14:08:54 -05:00
asarium c008dfc303 Fix assertion when applying particle effect to laser
The weapon state value of the weapon was updated after the particle
source was created so the source was always invalid which caused an
assertion.
2017-04-14 23:50:12 +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
406 changed files with 38217 additions and 11837 deletions

No files matched your search

-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
-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
+23 -14
View File
@@ -23,6 +23,19 @@ addons:
build_command: "ci/travis/script.sh"
# must match TRAVIS_BRANCH check below
branch_pattern: coverity_scan
env:
global:
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
# via the "travis encrypt" command using the project repo's public key
# also note that fork's don't get access to secure keys
# you have to test using a branch in the main repo
- secure: "C3wF967ZeliwwP1vC12EMIBOaC568n26Z/cPnwzn317ve59DWH3YSfPZVgvt08GzmaXITGGsJvPB+qxfGoKvQzYE4O1B73q81RpUe5pB3IhF+ThQ91VfQZIRJR5xEGJaLINUlHTTZGX5jxlkVO9wAcauVj/s3b8sQ3dvUZauPvk="
# These declarations set INDIEGAMES_USER and INDIEGAMES_PASSWORD for uploading nightly builds to the indiegames server
- secure: "lUuRu8XIi8MKNf1ebOfyC4iVEpPyASojJIDWXRo2bNqEF4ILAljXdkVeXeN6H5yKCHD52cxCNTtyePIG/o3p3QEuGSVud9bDS3D7LaQicLETGGrsw3l07U49gF2OKHXGopg0MzBbZUU9QmhoFTAe8t6PV9NDuEayYCheqvTqjZg="
- secure: "E/DHLYcPK/hBUqxBYYlUqp5sjgvIqY5A0qRHyQ4bmjsB+WB/Xx71bGCSiF7hk6lTxar1ZI1i5RAXXh9AIvNVaYAIdEOlCP+q3gvwCYuc5naZEKmkxlUCf0oEL4O9Fye93A/3VkFHuBdC1TGPYYf69m4W5r4367wWO9dPRIdWpJA="
# These declarations set FS2DOWNLOADS_USER and FS2DOWNLOADS_PASSWORD
- secure: "h6GbMX2jLsW1bS9fCM9fthOSJ1nfQQIRWi6EUH2p8u4NFLD5Bfi/C8JhQPKHUzyo3wvKkSHl+PsW7bgr1oXLusRwAur/dtv2N3imqvtbfIz305b00hZlsvbcYmQmUzQFSAdOGShK57JJ5aKQKccaUBP25KqB7Q+JaqBRdaMBS54="
- secure: "fUDAPAUUaaYZy8I4zU3SJ0JcK7aw4eb6eTdaEr7LyNyTMSfPgwY6P1MrbSQC0lJNQIUQ5ffjdxE5g7D7OYpoJF9L14ni4UY8t2QASt7kmpgcYihmjeuYy8FQXgmFG8CTxiWBPKTybZJ7voQcvIvRaNG7b2wM9PMfc5lRIondB6c="
deploy:
- provider: releases
api_key:
@@ -34,21 +47,19 @@ deploy:
condition: '"$RELEASE_BUILD" == true'
tags: true
- provider: bintray
user: sirknightly
key:
secure: "N/6QerkSgkt3elhJMeOyyHHjFri1Bi0GF0msucVCuTXVxMmq/E2XVldHT1TVfD7u6EUlkH5Tr+Aer5fXrrDfk2RZH1RXgQk1FYWUC+JY9dpD6AOtlffRfVHwhSMsZbuSt0sbDmHjnrFiGnxOFojBHpA/iTdZ4fvUl6Mg47hxaVI="
file: ci/bintray.json
- provider: script
script: bash ci/travis/ftp_deploy.sh
on:
condition: '"$NIGHTLY_BUILD" == true'
tags: true
env:
global:
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
# via the "travis encrypt" command using the project repo's public key
# also note that fork's don't get access to secure keys
# you have to test using a branch in the main repo
- secure: "C3wF967ZeliwwP1vC12EMIBOaC568n26Z/cPnwzn317ve59DWH3YSfPZVgvt08GzmaXITGGsJvPB+qxfGoKvQzYE4O1B73q81RpUe5pB3IhF+ThQ91VfQZIRJR5xEGJaLINUlHTTZGX5jxlkVO9wAcauVj/s3b8sQ3dvUZauPvk="
- provider: script
skip_cleanup: true
script: bash ci/travis/ftp_deploy.sh
on:
condition: $TEST_BUILD = true
all_branches: true
matrix:
include:
# note that gcc Debug MUST be 1st for Coverity
@@ -111,5 +122,3 @@ before_script:
- "./ci/travis/before_script.sh"
script:
- if [ "$BUILD_DEPLOYMENT" = true ] ; then ./ci/travis/release.sh ; else ./ci/travis/script.sh ; fi
before_deploy:
- "./ci/travis/before_deploy.sh"
+1 -1
View File
@@ -53,7 +53,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 "")
+32 -10
View File
@@ -25,15 +25,37 @@ deploy:
on:
ReleaseBuild: true # deploy on release push only
- provider: BinTray
username: sirknightly
api_key:
secure: 242iJ1rSVahaH+SskiwK2YcIVTO+yEOn5lRAvrBESHVfw6cqrSWfUROPp0Y6bxxX
subject: scp-fs2open
repo: FSO
package: nightly
version: $(VersionName)
publish: true
override: true
- provider: FTP
protocol: sftp
host: scp.indiegames.us
username:
secure: SFivQZfatqWHXK1ijYK3GQ==
password:
secure: q6Zk/412o1ri+NEya1dl1Q==
folder: public_html/builds/nightly/$(VersionName)
on:
NightlyBuild: true # deploy on nightly push only
- provider: FTP
protocol: ftp
host: swc.fs2downloads.com
username:
secure: EXg2ADoKzMduZF90ip2Q0g==
password:
secure: x0LL0uY9yBAQ7JTARhQ6AA==
folder: swc.fs2downloads.com/builds/nightly/$(VersionName)
beta: true
on:
NightlyBuild: true # deploy on nightly push only
- provider: FTP
protocol: ftp
host: swc.fs2downloads.com
username:
secure: EXg2ADoKzMduZF90ip2Q0g==
password:
secure: x0LL0uY9yBAQ7JTARhQ6AA==
folder: swc.fs2downloads.com/builds/test/$(VersionName)
beta: true
on:
TestBuild: true # deploy on test build push only
+34 -5
View File
@@ -4,6 +4,7 @@ class BuildConfig {
[string]$PackageType
[string]$Toolset
[string]$SimdType
[Bool]$SourcePackage
}
$NightlyConfigurations = @(
@@ -12,12 +13,14 @@ $NightlyConfigurations = @(
PackageType="Win64";
Toolset="v140_xp";
SimdType="SSE2";
SourcePackage=$false;
},
[BuildConfig]@{
Generator="Visual Studio 14 2015";
PackageType="Win32";
Toolset="v140_xp";
SimdType="SSE2";
SourcePackage=$false;
}
)
$ReleaseConfigurations = @(
@@ -26,24 +29,28 @@ $ReleaseConfigurations = @(
PackageType="Win32";
Toolset="v140_xp";
SimdType="SSE2";
SourcePackage=$true;
}
[BuildConfig]@{
Generator="Visual Studio 14 2015";
PackageType="Win32-AVX";
Toolset="v140_xp";
SimdType="AVX";
SourcePackage=$false;
}
[BuildConfig]@{
Generator="Visual Studio 14 2015 Win64";
PackageType="Win64";
Toolset="v140_xp";
SimdType="SSE2";
SourcePackage=$false;
}
[BuildConfig]@{
Generator="Visual Studio 14 2015 Win64";
PackageType="Win64-AVX";
Toolset="v140_xp";
SimdType="AVX";
SourcePackage=$false;
}
)
@@ -52,16 +59,21 @@ $BuildConfigurations = $null
# Default values
$ReleaseBuild = $false
$NightlyBuild = $false
$DeployBuild = $false
$TestBuild = $false
if ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^release_(.*)")) {
# Set to true to test either the release or the nightly part of this script
$ReleaseTest = $false
$NightlyTest = $false
$TestBuildTest = $false
if ($ReleaseTest -Or ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^release_(.*)"))) {
# Tag matches
$ReleaseBuild = $true
$PackageName = "fs2_open_$($matches[1])"
$BuildConfigurations = $ReleaseConfigurations
}
if ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^nightly_(.*)")) {
if ($NightlyTest -Or ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REPO_TAG_NAME" -match "^nightly_(.*)"))) {
# Tag matches
$NightlyBuild = $true
$PackageName = "nightly_$($matches[1])"
@@ -69,19 +81,31 @@ if ([System.Convert]::ToBoolean($env:APPVEYOR_REPO_TAG) -And ("$env:APPVEYOR_REP
$BuildConfigurations = $NightlyConfigurations
}
if ($TestBuildTest -Or ([System.Convert]::ToInt32($env:APPVEYOR_PULL_REQUEST_NUMBER) -le 0 -And ("$env:APPVEYOR_REPO_BRANCH" -match "^test\/(.*)"))) {
# Tag matches
$TestBuild = $true
$PackageName = "test_$($matches[1])"
Set-AppveyorBuildVariable 'VersionName' "$($matches[1])"
$BuildConfigurations = $NightlyConfigurations
# Override the revision string so that the builds are named correctly
[System.IO.File]::WriteAllLines("$env:APPVEYOR_BUILD_FOLDER/version_override.cmake", "set(FSO_VERSION_REVISION_STR $env:VersionName)")
}
# Multiply by 2 so that we can add 0 or 1 for debug or release Configs
$buildID = [convert]::ToInt32($env:BuildID) * 2
if ($Env:Configuration -eq "Release") {
$buildID = $buildID + 1
}
Write-Host "$buildID"
if ($ReleaseBuild -Or $NightlyBuild) {
$DeployBuild = $false
if ($ReleaseBuild -Or $NightlyBuild -Or $TestBuild) {
$DeployBuild = $true
}
Set-AppveyorBuildVariable 'ReleaseBuild' "$ReleaseBuild"
Set-AppveyorBuildVariable 'NightlyBuild' "$NightlyBuild"
Set-AppveyorBuildVariable 'TestBuild' "$TestBuild"
New-Item build -type directory
Set-Location -Path build
@@ -94,6 +118,11 @@ if ($DeployBuild) {
}
$buildConfig = $BuildConfigurations[$buildID]
if ($buildConfig.SourcePackage -eq $True) {
7z a -xr'!.git' "$($PackageName)-source-Win.zip" "$env:APPVEYOR_BUILD_FOLDER"
Push-AppveyorArtifact "$($PackageName)-source-Win.zip"
}
cmake -DCMAKE_INSTALL_PREFIX="$env:APPVEYOR_BUILD_FOLDER/../install" -DFSO_USE_SPEECH="ON" `
-DFSO_USE_VOICEREC="ON" -DMSVC_SIMD_INSTRUCTIONS="$($buildConfig.SimdType)" `
+2 -15
View File
@@ -1,21 +1,8 @@
if ([System.Convert]::ToBoolean($env:ReleaseBuild) -Or [System.Convert]::ToBoolean($env:NightlyBuild)) {
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
+5
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"
+20 -1
View File
@@ -2,6 +2,8 @@
RELEASE_BUILD=false
NIGHTLY_BUILD=false
TEST_BUILD=false
BUILD_DEPLOYMENT=false
BUILD_CONFIGS="Release FastDebug"
VERSION_NAME=""
@@ -9,10 +11,12 @@ PACKAGE_NAME=""
RELEASE_PATTERN="^release_(.*)$"
NIGHTLY_PATTERN="^nightly_(.*)$"
TEST_BUILD_PATTERN="^test\/(.*)$"
# These are for testing
NIGHTLY_TEST=false
RELEASE_TEST=false
TEST_BUILD_TEST=false
if [ "$RELEASE_TEST" = true ] || [[ "$TRAVIS_TAG" =~ $RELEASE_PATTERN ]]; then
echo "This is a release tag!";
@@ -25,8 +29,22 @@ if [ "$NIGHTLY_TEST" = true ] || [[ "$TRAVIS_TAG" =~ $NIGHTLY_PATTERN ]]; then
VERSION_NAME="${BASH_REMATCH[1]}";
PACKAGE_NAME="nightly_${BASH_REMATCH[1]}";
fi
if [ "$TEST_BUILD_TEST" = true ] || [[ "$TRAVIS_PULL_REQUEST" == "false" && "$TRAVIS_BRANCH" =~ $TEST_BUILD_PATTERN ]]; then
echo "This is a test build branch!";
TEST_BUILD=true;
if [ "$TEST_BUILD_TEST" = true ]; then
VERSION_NAME="test";
PACKAGE_NAME="test_test";
else
VERSION_NAME="${BASH_REMATCH[1]}";
PACKAGE_NAME="test_${BASH_REMATCH[1]}";
fi
if ([ "$RELEASE_BUILD" = true ] || [ "$NIGHTLY_BUILD" = true ]); then
# Override the revision string so that the builds are named correctly
echo "set(FSO_VERSION_REVISION_STR $VERSION_NAME)" > "$TRAVIS_BUILD_DIR/version_override.cmake"
fi
if ([ "$RELEASE_BUILD" = true ] || [ "$NIGHTLY_BUILD" = true ] || [ "$TEST_BUILD" = true ]); then
BUILD_DEPLOYMENT=true;
fi
@@ -44,6 +62,7 @@ fi
export RELEASE_BUILD
export NIGHTLY_BUILD
export TEST_BUILD
export BUILD_DEPLOYMENT
export BUILD_CONFIGS
export VERSION_NAME
+54
View File
@@ -0,0 +1,54 @@
#!/usr/bin/env bash
set -e
set -u
if [[ ! "$(curl -V)" == *"sftp"* ]]; then
# Before
echo "Before:"
curl -V
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
# Since the Travis CI people are not capable of enabling SSH/SCP support for their libcurl we need to build that manually...
# These commands are based on the tutorial from here: http://zeroset.mnim.org/2013/03/14/sftp-support-for-curl-in-ubuntu-12-10-quantal-quetzal-and-later/
mkdir /tmp/curl
cd /tmp/curl
sudo apt-get update
sudo apt-get install build-essential debhelper libssh2-1-dev libgnutls-dev libidn11-dev libkrb5-dev libldap2-dev libnss3-dev librtmp-dev libtool openssh-server quilt
apt-get source curl
sudo apt-get build-dep curl
cd curl-*
export DEB_BUILD_OPTIONS="nocheck"
sudo dpkg-buildpackage -uc -us -j"$(grep -c ^processor /proc/cpuinfo)"
cd ..
dpkg -l | grep curl
ls -al
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"
fi
# After
echo "After:"
curl -V
fi
cd /tmp/builds
for file in *; do
if [ "$TEST_BUILD" = true ]; then
# Upload to fs2downloads
curl -k "ftp://swc.fs2downloads.com/swc.fs2downloads.com/builds/test/$VERSION_NAME/" --user "$FS2DOWNLOADS_USER:$FS2DOWNLOADS_PASSWORD" -T "$file" --ftp-create-dirs
else
# Upload to indiegames
curl -k "sftp://scp.indiegames.us/~/public_html/builds/nightly/$VERSION_NAME/" --user "$INDIEGAMES_USER:$INDIEGAMES_PASSWORD" -T "$file" --ftp-create-dirs
# Upload to fs2downloads
curl -k "ftp://swc.fs2downloads.com/swc.fs2downloads.com/builds/nightly/$VERSION_NAME/" --user "$FS2DOWNLOADS_USER:$FS2DOWNLOADS_PASSWORD" -T "$file" --ftp-create-dirs
fi
done
+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)
+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)
+16
View File
@@ -1,2 +1,18 @@
target_compile_definitions(platform INTERFACE SCP_SOLARIS)
find_library(SOCKET_LIB socket)
if (NOT SOCKET_LIB)
message(FATAL_ERROR "Couldn't find libsocket! Please install it and rerun the configuration.")
else()
target_link_libraries(platform INTERFACE "${SOCKET_LIB}")
endif()
find_library(NSL_LIB nsl)
if (NOT NSL_LIB)
message(FATAL_ERROR "Couldn't find libnsl! Please install it and rerun the configuration.")
else()
target_link_libraries(platform INTERFACE "${NSL_LIB}")
endif()
+5 -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)
+4
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,7 @@
#cmakedefine01 HAVE_STRINGS_H
#cmakedefine01 HAVE_CHAR32_T
#cmakedefine01 HAVE_UNICODE_CHAR_LITERAL
#endif // __PLATFORM_CHECKS_H__
+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)
+1 -1
View File
@@ -20,7 +20,7 @@ ENDIF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
# Copy release settings to FastDebug
set(CMAKE_C_FLAGS_FASTDEBUG "${CMAKE_C_FLAGS_RELEASE}")
set(CMAKE_CXX_FLAGS_FASTDEBUG "${CMAKE_CXX_FLAGS_RELEASE}")
set(CMAKE_EXE_LINKER_FLAGS_FASTDEBUG "${CMAKE_EXE_LINKER_RELEASE}")
set(CMAKE_EXE_LINKER_FLAGS_FASTDEBUG "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
set(CMAKE_STATIC_LINKER_FLAGS_FASTDEBUG "${CMAKE_STATIC_LINKER_FLAGS_RELEASE}")
if (MSVC)
+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)
+3 -3
View File
@@ -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,6 +30,8 @@ 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)
@@ -58,8 +60,6 @@ set_target_properties(code PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "prefix_head
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")
+14 -6
View File
@@ -3814,7 +3814,7 @@ float ai_path_0()
int path_num;
Assert(aip->active_goal >= 0);
ai_goal *aigp = &aip->goals[aip->active_goal];
Assert(aigp->flags[AI::Goal_Flags::Dockee_index_valid] || aigp->flags[AI::Goal_Flags::Docker_index_valid]);
Assert(aigp->flags[AI::Goal_Flags::Dockee_index_valid] && aigp->flags[AI::Goal_Flags::Docker_index_valid]);
path_num = ai_return_path_num_from_dockbay(&Objects[aip->goal_objnum], aigp->dockee.index);
ai_find_path(Pl_objp, aip->goal_objnum, path_num, 0);
@@ -3957,7 +3957,7 @@ float ai_path_1()
int path_num;
Assert(aip->active_goal >= 0);
ai_goal *aigp = &aip->goals[aip->active_goal];
Assert(aigp->flags[AI::Goal_Flags::Dockee_index_valid] || aigp->flags[AI::Goal_Flags::Docker_index_valid]);
Assert(aigp->flags[AI::Goal_Flags::Dockee_index_valid] && aigp->flags[AI::Goal_Flags::Docker_index_valid]);
path_num = ai_return_path_num_from_dockbay(&Objects[aip->goal_objnum], aigp->dockee.index);
ai_find_path(Pl_objp, aip->goal_objnum, path_num, 0);
@@ -10395,11 +10395,12 @@ 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
Assert(aigp != NULL);
Assert(aigp->flags[AI::Goal_Flags::Dockee_index_valid] || aigp->flags[AI::Goal_Flags::Docker_index_valid]);
Assert(aigp->flags[AI::Goal_Flags::Dockee_index_valid] && aigp->flags[AI::Goal_Flags::Docker_index_valid]);
docker_index = aigp->docker.index;
dockee_index = aigp->dockee.index;
Assert(docker_index >= 0);
@@ -10412,6 +10413,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 +10480,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 +10494,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);
@@ -10833,7 +10839,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(SND_DOCK_ATTACH), &Pl_objp->pos, &View_position );
// start the dock animation
model_anim_start_type(shipp, TRIGGER_TYPE_DOCKED, docker_index, 1);
@@ -10960,7 +10966,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(SND_DOCK_DETACH), &Pl_objp->pos, &View_position );
aip->submode = AIS_UNDOCK_1;
aip->submode_start_time = Missiontime;
@@ -10980,7 +10986,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(SND_DOCK_DEPART), &Pl_objp->pos, &View_position );
aigp->flags.set(AI::Goal_Flags::Depart_sound_played);
}
@@ -12376,6 +12382,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 +12390,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:
+1 -1
View File
@@ -1640,7 +1640,7 @@ int ai_mission_goal_achievable( int objnum, ai_goal *aigp )
}
else
{
Int3(); // get ALLENDER
mprintf(("Potentially incorrect behaviour in AI goal for ship %s: Ship %s could not be found among currently active, departed, or yet-to-arrive ships.\nPlease check the mission file.\n", Ships[objp->instance].ship_name, aigp->target_name));
status = SHIP_STATUS_UNKNOWN;
}
}
+2 -2
View File
@@ -2051,7 +2051,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
if ( wip->launch_snd != -1 ) {
// 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 );
}
}
}
@@ -2138,7 +2138,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
if ( Weapon_info[tsi->weapon_class].launch_snd != -1 ) {
// 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 );
}
}
+10 -1
View File
@@ -733,6 +733,10 @@ anim *anim_load(const char *real_filename, int cf_dir_type, int file_mapped)
anim_read_header(ptr, fp);
if (ptr->width < 0 || ptr->height < 0) {
Error(LOCATION, "Ani file %s has a faulty header and cannot be loaded.", name);
}
if(ptr->num_keys > 0){
ptr->keys = (key_frame*)vm_malloc(sizeof(key_frame) * ptr->num_keys);
Assert(ptr->keys != NULL);
@@ -761,7 +765,7 @@ anim *anim_load(const char *real_filename, int cf_dir_type, int file_mapped)
}
// couldn't memory-map file... must be in a packfile, so stream manually
if ( file_mapped && !ptr->cfile_ptr ) {
if ( file_mapped == PAGE_FROM_MEM && !ptr->cfile_ptr ) {
ptr->flags &= ~ANF_MEM_MAPPED;
ptr->flags |= ANF_STREAMED;
ptr->cfile_ptr = cfopen(name, "rb", CFILE_NORMAL, cf_dir_type);
@@ -969,6 +973,11 @@ void anim_display_info(char *real_filename)
}
anim_read_header(&A, fp);
if (A.width < 0 || A.height < 0) {
Error(LOCATION, "Ani file %s has a faulty header and cannot be loaded.", filename);
}
// read the keyframe frame nums and offsets
key_frame_nums = (int*)vm_malloc(sizeof(int)*A.num_keys);
Assert(key_frame_nums != NULL);
+3 -4
View File
@@ -40,9 +40,8 @@ typedef struct {
enum
{
PAGE_FROM_MEM = 0,
PAGE_FROM_DISK = 1,
PAGE_FROM_DISK_FORCED = 2
PAGE_FROM_DISK = 0,
PAGE_FROM_MEM = 1
};
extern int Anim_paused;
@@ -59,7 +58,7 @@ int anim_stop_playing(anim_instance* anim_instance);
int anim_show_next_frame(anim_instance *instance, float frametime);
void anim_release_all_instances(int screen_id = 0);
void anim_release_render_instance(anim_instance* instance);
anim *anim_load(const char *name, int cf_dir_type = CF_TYPE_ANY, int file_mapped = PAGE_FROM_MEM);
anim *anim_load(const char *name, int cf_dir_type = CF_TYPE_ANY, int file_mapped = PAGE_FROM_DISK);
int anim_free(anim *ptr);
int anim_playing(anim_instance *ai);
int anim_write_frames_out(char *filename);
+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();
+7 -3
View File
@@ -1312,7 +1312,7 @@ void asteriod_explode_sound(object *objp, int type, int 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 );
}
/**
@@ -1568,8 +1568,12 @@ void asteroid_maybe_break_up(object *pasteroid_obj)
vec3d tempv = dir_vec;
vm_vec_random_cone(&dir_vec, &tempv, (360.0f / total_roids / 2));
// Make the roid inherit half of the parent's velocity
vm_vec_copy_normalize(&parent_vel, &pasteroid_obj->phys_info.vel);
// Make the roid inherit half of parent's directional movement
if (!IS_VEC_NULL(&pasteroid_obj->phys_info.vel)) {
vm_vec_copy_normalize(&parent_vel, &pasteroid_obj->phys_info.vel);
} else {
vm_vec_rand_vec_quick(&parent_vel);
}
vm_vec_scale(&parent_vel, 0.5f);
// Make the hit position affect the direction, but only a little
+2 -1
View File
@@ -31,6 +31,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,7 +90,7 @@ struct bitmap_entry {
#endif
};
extern bitmap_entry bm_bitmaps[MAX_BITMAPS];
extern bitmap_entry* bm_bitmaps;
// image specific lock functions
void bm_lock_ani( int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int bpp, ubyte flags );
+127 -30
View File
@@ -24,6 +24,7 @@
#include "debugconsole/console.h"
#include "globalincs/systemvars.h"
#include "graphics/2d.h"
#include "graphics/matrix.h"
#include "graphics/grinternal.h"
#include "io/key.h"
#include "io/timer.h"
@@ -83,17 +84,19 @@ const int BM_ANI_NUM_TYPES = sizeof(bm_ani_type_list) / sizeof(bm_ani_type_list[
void(*bm_set_components)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a) = NULL;
void(*bm_set_components_32)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a) = NULL;
int MAX_BITMAPS = DEFAULT_MAX_BITMAPS;
// --------------------------------------------------------------------------------------------------------------------
// Declaration of protected variables (defined in cmdline.cpp).
extern int Cmdline_cache_bitmaps;
// --------------------------------------------------------------------------------------------------------------------
// Definition of public variables (declared as extern in bm_internal.h).
bitmap_entry bm_bitmaps[MAX_BITMAPS];
bitmap_entry* bm_bitmaps = nullptr;
// --------------------------------------------------------------------------------------------------------------------
// Definition of private variables at file scope (static).
static int bm_inited = 0;
static bool bm_inited = false;
static uint Bm_next_signature = 0x1234;
static int bm_next_handle = 1;
static int Bm_low_mem = 0;
@@ -480,7 +483,11 @@ void bm_close() {
for (i = 0; i<MAX_BITMAPS; i++) {
bm_free_data(i); // clears flags, bbp, data, etc
}
bm_inited = 0;
if (bm_bitmaps != nullptr) {
delete[] bm_bitmaps;
bm_bitmaps = nullptr;
}
bm_inited = false;
}
}
@@ -491,7 +498,7 @@ int bm_create(int bpp, int w, int h, void *data, int flags) {
Assert((bpp == 16) || (bpp == 24) || (bpp == 32));
}
if (!bm_inited) bm_init();
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
int n = -1;
@@ -871,7 +878,7 @@ int bm_get_info(int handle, int *w, int * h, ubyte * flags, int *nframes, int *f
if (h) *h = bmp->h;
if (flags) *flags = bmp->flags;
if (bm_is_anim(bitmapnum) == true) {
if (bm_is_anim(bitmapnum)) {
if (nframes) {
*nframes = bm_bitmaps[bitmapnum].info.ani.num_frames;
}
@@ -942,7 +949,7 @@ void bm_get_palette(int handle, ubyte *pal, char *name) {
}
uint bm_get_signature(int handle) {
if (!bm_inited) bm_init();
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
int bitmapnum = handle % MAX_BITMAPS;
Assertion(bm_bitmaps[bitmapnum].handle == handle, "Invalid bitmap handle %d passed to bm_get_signature().\nThis might be due to an invalid animation somewhere else.\n", handle); // INVALID BITMAP HANDLE!
@@ -967,7 +974,7 @@ int bm_get_tcache_type(int num) {
}
BM_TYPE bm_get_type(int handle) {
if (!bm_inited) bm_init();
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
int bitmapnum = handle % MAX_BITMAPS;
Assertion(bm_bitmaps[bitmapnum].handle == handle, "Invalid bitmap handle %d passed to bm_get_type().\nThis might be due to an invalid animation somewhere else.\n", handle); // INVALID BITMAP HANDLE!
@@ -989,16 +996,17 @@ bool bm_has_alpha_channel(int handle) {
}
void bm_init() {
Assertion(!bm_inited, "bmpman cannot be initialized more than once!");
int i;
mprintf(("Size of bitmap info = " SIZE_T_ARG " KB\n", sizeof(bm_bitmaps) / 1024));
mprintf(("Size of bitmap extra info = " SIZE_T_ARG " bytes\n", sizeof(bm_extra_info)));
if (!bm_inited) {
bm_inited = 1;
atexit(bm_close);
if (bm_bitmaps == nullptr) {
bm_bitmaps = new bitmap_entry[MAX_BITMAPS];
}
mprintf(("Size of bitmap info = " SIZE_T_ARG " KB\n", (sizeof(bm_bitmaps[0]) * MAX_BITMAPS) / 1024));
mprintf(("Size of bitmap extra info = " SIZE_T_ARG " bytes\n", sizeof(bm_extra_info)));
for (i = 0; i<MAX_BITMAPS; i++) {
bm_bitmaps[i].filename[0] = '\0';
bm_bitmaps[i].type = BM_TYPE_NONE;
@@ -1022,6 +1030,8 @@ void bm_init() {
bm_free_data(i); // clears flags, bbp, data, etc
}
bm_inited = true;
}
int bm_is_compressed(int num) {
@@ -1203,8 +1213,7 @@ int bm_load(const char *real_filename) {
CFILE *img_cfp = NULL;
int handle = -1;
if (!bm_inited)
bm_init();
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
// if no file was passed then get out now
if ((real_filename == NULL) || (strlen(real_filename) <= 0))
@@ -1509,8 +1518,7 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
size_t img_size = 0;
char clean_name[MAX_FILENAME_LEN];
if (!bm_inited)
bm_init();
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
// set output param defaults before going any further
if (nframes != nullptr)
@@ -1619,6 +1627,10 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
#endif
anim_read_header(&the_anim, img_cfp);
if (the_anim.width < 0 || the_anim.height < 0) {
Error(LOCATION, "Ani file %s has a faulty header and cannot be loaded.", real_filename);
}
anim_frames = the_anim.total_frames;
anim_fps = the_anim.fps;
if (anim_fps == 0) {
@@ -1697,6 +1709,8 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
}
int first_handle = bm_get_next_handle();
// if all images of the animation have the same size then we can use a texture array
bool is_array = true;
for (i = 0; i < anim_frames; i++) {
memset(&bm_bitmaps[n + i], 0, sizeof(bitmap_entry));
@@ -1783,8 +1797,39 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
bm_bitmaps[n + i].info.ani.apng.is_apng = false;
}
if (bm_bitmaps[n].bm.w != bm_bitmaps[n + i].bm.w || bm_bitmaps[n].bm.h != bm_bitmaps[n + i].bm.h) {
// We found a frame with a different size than the first frame -> this can't be used as a texture array
is_array = false;
Warning(LOCATION, "Animation '%s' has images that are of different sizes (currently at frame %d)."
"Performance could be improved by making all images the same size.", filename, i + 1);
}
if (bm_bitmaps[n].comp_type != bm_bitmaps[n + i].comp_type) {
// Different compression type
is_array = false;
Warning(LOCATION, "Animation '%s' has images that are of different compression formats (currently at frame %d)."
"Performance could be improved by making all images the same compression format.", filename, i + 1);
}
if (bm_bitmaps[n].bm.true_bpp != bm_bitmaps[n + i].bm.true_bpp) {
// We found a frame with an incompatible pixel format
is_array = false;
Warning(LOCATION, "Animation '%s' has images that are of different pixel formats (currently at frame %d)."
"Performance could be improved by making all images the same pixel format.", filename, i + 1);
}
if (bm_bitmaps[n].num_mipmaps != bm_bitmaps[n + i].num_mipmaps) {
// We found a frame with a different number of mipmaps
is_array = false;
Warning(LOCATION, "Animation '%s' has images that have a different number of mipmaps (currently at frame %d)."
"Performance could be improved by giving all frames the same number of mipmaps.", filename, i + 1);
}
}
// Set array flag of first frame
bm_bitmaps[n].info.ani.is_array = is_array;
if (nframes != nullptr)
*nframes = anim_frames;
@@ -1893,7 +1938,7 @@ bitmap * bm_lock(int handle, int bpp, ubyte flags, bool nodebug) {
bitmap *bmp;
bitmap_entry *be;
if (!bm_inited) bm_init();
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
int bitmapnum = handle % MAX_BITMAPS;
@@ -2235,6 +2280,9 @@ void bm_lock_jpg(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int b
// Unload any existing data
bm_free_data(bitmapnum);
// JPEG actually only support 24 bits per pixel so we enforce that here
bpp = 24;
d_size = (bpp >> 3);
// allocate bitmap data
@@ -2295,7 +2343,7 @@ void bm_lock_pcx(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int b
// this will populate filename[] whether it's EFF or not
EFF_FILENAME_CHECK;
pcx_error = pcx_read_bitmap(filename, data, NULL, (bpp >> 3), (flags & BMP_AABITMAP), 0, be->dir_type);
pcx_error = pcx_read_bitmap(filename, data, NULL, (bpp >> 3), (flags & BMP_AABITMAP), (flags & BMP_MASK_BITMAP) != 0, be->dir_type);
if (pcx_error != PCX_ERROR_NONE) {
mprintf(("Couldn't load PCX!!! (%s)\n", filename));
@@ -2374,7 +2422,7 @@ void bm_lock_tga(int handle, int bitmapnum, bitmap_entry *be, bitmap *bmp, int b
Assert(byte_size);
Assert(be->mem_taken > 0);
data = (ubyte*)bm_malloc(bitmapnum, be->mem_taken);
data = (ubyte*)bm_malloc(bitmapnum, static_cast<size_t>(bmp->w * bmp->h * byte_size));
if (data) {
memset(data, 0, be->mem_taken);
@@ -2459,8 +2507,7 @@ int bm_make_render_target(int width, int height, int flags) {
int bpp = 32;
int size = 0;
if (!bm_inited)
bm_init();
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
// Find an open slot (starting from the end)
for (n = -1, i = MAX_BITMAPS - 1; i >= 0; i--) {
@@ -2833,12 +2880,16 @@ int bm_release(int handle, int clear_render_targets) {
}
// be sure that all frames of an ani are unloaded - taylor
if (bm_is_anim(n) == true) {
if (bm_is_anim(n)) {
int i, first = be->info.ani.first_frame, total = bm_bitmaps[first].info.ani.num_frames;
// The graphics system requires that the bitmap information for the whole animation is still valid when the data
// is freed so we first free all the data and then clear the bitmaps data
for (i = 0; i < total; i++) {
bm_free_data(first + i, true); // clears flags, bbp, data, etc
}
for (i = 0; i < total; i++) {
memset(&bm_bitmaps[first + i], 0, sizeof(bitmap_entry));
bm_bitmaps[first + i].type = BM_TYPE_NONE;
@@ -2887,8 +2938,7 @@ int bm_release(int handle, int clear_render_targets) {
}
int bm_reload(int bitmap_handle, const char* filename) {
if (!bm_inited)
bm_init();
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
// if no file was passed then get out now
if ((filename == NULL) || (strlen(filename) <= 0))
@@ -3068,10 +3118,7 @@ bool bm_set_render_target(int handle, int face) {
gr_reset_clip();
if (gr_screen.mode == GR_OPENGL) {
extern void opengl_setup_viewport();
opengl_setup_viewport();
}
gr_setup_viewport();
return true;
}
@@ -3201,7 +3248,7 @@ int bm_unload_fast(int handle, int clear_render_targets) {
void bm_unlock(int handle) {
bitmap_entry *be;
if (!bm_inited) bm_init();
Assertion(bm_inited, "bmpman must be initialized before this function can be called!");
int bitmapnum = handle % MAX_BITMAPS;
@@ -3257,3 +3304,53 @@ int find_block_of(int n)
return -1;
}
bool bm_is_texture_array(const int handle) {
int bitmapnum = handle % MAX_BITMAPS;
if (!bm_is_anim(bitmapnum)) {
return true;
}
// This will return the index of the first animation frame
int n = bm_get_cache_slot(handle, 0);
bitmap_entry *be = &bm_bitmaps[n];
return be->info.ani.is_array;
}
int bm_get_base_frame(const int handle, int* num_frames) {
// If the bitmap is no animation then num_frames will still be at least 1
auto animation_begin = bm_get_info(handle, nullptr, nullptr, nullptr, num_frames);
if (animation_begin < 0) {
// Some kind of error
return -1;
}
if (!bm_is_texture_array(animation_begin)) {
// If this is not a texture array then we just treat it like a single frame animation
animation_begin = handle;
if (num_frames != nullptr) {
*num_frames = 1;
}
}
return animation_begin;
}
int bm_get_array_index(const int handle) {
return handle - bm_get_base_frame(handle, nullptr);
}
int bmpman_count_bitmaps() {
if (!bm_inited)
return -1;
int total_bitmaps = 0;
for (int i = 0; i < MAX_BITMAPS; i++) {
if (bm_bitmaps[i].type != BM_TYPE_NONE) {
total_bitmaps++;
}
}
return total_bitmaps;
}
+45 -2
View File
@@ -33,7 +33,7 @@
*/
/**
* @brief How many bitmaps the game can handle
* @brief How many bitmaps the game can handle by default
*
* @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
@@ -45,7 +45,9 @@
* 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
#define DEFAULT_MAX_BITMAPS 4750
extern int MAX_BITMAPS;
// 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!! ******
@@ -56,6 +58,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
@@ -698,4 +701,44 @@ 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();
#endif
+1 -1
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"
+1
View File
@@ -88,6 +88,7 @@ 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 },
};
+2 -1
View File
@@ -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
+12 -6
View File
@@ -1567,8 +1567,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) {
@@ -1776,8 +1778,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) {
@@ -1991,8 +1995,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) {
+288 -70
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>
@@ -38,6 +41,9 @@
#include <string.h>
#include <stdlib.h>
#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);
@@ -177,7 +189,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", },
@@ -218,6 +229,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", },
@@ -393,11 +405,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 +482,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
@@ -502,6 +513,7 @@ int Cmdline_noparseerrors = 0;
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 +534,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 +547,7 @@ 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);
int Cmdline_deprecated_spec = 0;
int Cmdline_deprecated_glow = 0;
@@ -987,32 +1000,32 @@ void os_init_cmdline(int argc, char *argv[])
delete[] buf;
fclose(fp);
}
}
} else {
// parse user specific cmdline_fso config file (will supersede options in global file)
fp = fopen(os_get_config_path("data/cmdline_fso.cfg").c_str(), "rt");
// parse user specific cmdline_fso config file (will supersede options in global file)
fp = fopen(os_get_config_path("data/cmdline_fso.cfg").c_str(), "rt");
// if the file exists, get a single line, and deal with it
if ( fp ) {
char *buf, *p;
// if the file exists, get a single line, and deal with it
if ( fp ) {
char *buf, *p;
auto len = static_cast<int>(filelength( fileno(fp) )) + 2;
buf = new char [len];
auto len = static_cast<int>(filelength( fileno(fp) )) + 2;
buf = new char [len];
if (fgets(buf, len-1, fp) != nullptr)
{
// replace the newline character with a NULL
if ( (p = strrchr(buf, '\n')) != NULL ) {
*p = '\0';
}
if (fgets(buf, len-1, fp) != nullptr)
{
// replace the newline character with a NULL
if ( (p = strrchr(buf, '\n')) != NULL ) {
*p = '\0';
// append a space for the os_parse_parms() check
strcat_s(buf, len, " ");
os_process_cmdline(buf);
}
// append a space for the os_parse_parms() check
strcat_s(buf, len, " ");
os_process_cmdline(buf);
delete [] buf;
fclose(fp);
}
delete [] buf;
fclose(fp);
}
} // If cmdline included PARSE_COMMAND_LINE_STRING
@@ -1143,6 +1156,9 @@ 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.
@@ -1241,6 +1257,248 @@ 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);
}
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 +1506,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 +1759,11 @@ bool SetCmdlineParams()
Show_framerate = 1;
}
if (bmpmanusage_arg.found())
{
Cmdline_bmpman_usage = 1;
}
if(pos_arg.found())
{
Cmdline_show_pos = 1;
@@ -1721,11 +1944,6 @@ bool SetCmdlineParams()
}
#endif
if ( snd_preload_arg.found() )
{
Cmdline_snd_preload = 1;
}
if ( env.found() ) {
Cmdline_env = 0;
}
+1 -1
View File
@@ -104,7 +104,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;
@@ -148,6 +147,7 @@ extern int Cmdline_dis_collisions;
extern int Cmdline_dis_weapons;
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, SND_MISSILE_EVADED_POPUP)));
} else if ( Objects[objp->parent].flags[Object::Object_Flags::Player_ship] ) {
send_countermeasure_success_packet( objp->parent );
}
+21
View File
@@ -14,6 +14,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 +29,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 +37,7 @@ void Decoder::stopDecoder() {
m_videoQueue->close();
m_audioQueue->close();
m_subtitleQueue->close();
}
bool Decoder::canPushAudioData() {
@@ -48,6 +55,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();
}
+23
View File
@@ -58,6 +58,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 +76,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;
@@ -109,6 +118,8 @@ class Decoder {
*/
virtual bool hasAudio() = 0;
virtual bool hasSubtitles() = 0;
/**
* @brief Ends decoding of the video file
*/
@@ -122,6 +133,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 +160,10 @@ class Decoder {
void pushAudioData(AudioFramePtr&& data);
bool canPushSubtitleData();
void pushSubtitleData(SubtitleFramePtr&& data);
bool canPushVideoData();
void pushFrameData(VideoFramePtr&& frame);
+95
View File
@@ -0,0 +1,95 @@
#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) {
GR_DEBUG_SCOPE("Init video");
auto w = static_cast<int>(props.size.width);
auto h = static_cast<int>(props.size.height);
// Create buffer textures
_yTexBuffer.reset(new uint8_t[w * h]);
_ytex = bm_create(8, w, h, _yTexBuffer.get(), BMP_AABITMAP);
_uTexBuffer.reset(new uint8_t[w / 2 * h / 2]);
_utex = bm_create(8, w / 2, h / 2, _uTexBuffer.get(), BMP_AABITMAP);
_vTexBuffer.reset(new uint8_t[w / 2 * h / 2]);
_vtex = bm_create(8, w / 2, h / 2, _vTexBuffer.get(), BMP_AABITMAP);
material_set_movie(&_render_material, _ytex, _utex, _vtex);
}
VideoPresenter::~VideoPresenter() {
GR_DEBUG_SCOPE("Deinit video");
bm_release(_ytex);
bm_release(_utex);
bm_release(_vtex);
_ytex = _utex = _vtex = -1;
}
void VideoPresenter::uploadVideoFrame(const VideoFramePtr& frame) {
GR_DEBUG_SCOPE("Update video frame");
auto ptrs = frame->getDataPointers();
memcpy(_yTexBuffer.get(), ptrs.y, frame->ySize.stride * frame->ySize.height);
memcpy(_uTexBuffer.get(), ptrs.u, frame->uvSize.stride * frame->uvSize.height);
memcpy(_vTexBuffer.get(), ptrs.v, frame->uvSize.stride * frame->uvSize.height);
gr_update_texture(_ytex, 8, _yTexBuffer.get(), (int) frame->ySize.width, (int) frame->ySize.height);
gr_update_texture(_utex, 8, _uTexBuffer.get(), (int) frame->uvSize.width, (int) frame->uvSize.height);
gr_update_texture(_vtex, 8, _vTexBuffer.get(), (int) frame->uvSize.width, (int) frame->uvSize.height);
}
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]), offset + offsetof(movie_vertex, pos));
layout.add_vertex_component(vertex_format_data::TEX_COORD2, sizeof(vertex_data[0]), offset + offsetof(movie_vertex, uv));
gr_render_movie(&_render_material, PRIM_TYPE_TRISTRIP, &layout, 4, gr_immediate_buffer_handle);
}
}
}
+42
View File
@@ -0,0 +1,42 @@
#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 {
int _ytex = -1;
std::unique_ptr<uint8_t[]> _yTexBuffer;
int _utex = -1;
std::unique_ptr<uint8_t[]> _uTexBuffer;
int _vtex = -1;
std::unique_ptr<uint8_t[]> _vTexBuffer;
movie_material _render_material;
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
+96 -2
View File
@@ -9,6 +9,9 @@
#include "cutscene/ffmpeg/AudioDecoder.h"
#include "cutscene/ffmpeg/VideoDecoder.h"
#include "cutscene/ffmpeg/SubtitleDecoder.h"
#include "localization/localize.h"
using namespace libs::ffmpeg;
@@ -62,6 +65,8 @@ CodecContextParameters getCodecParameters(AVStream* stream) {
paras.channel_layout = stream->codecpar->channel_layout;
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;
@@ -70,9 +75,29 @@ CodecContextParameters getCodecParameters(AVStream* stream) {
paras.channel_layout = stream->codec->channel_layout;
paras.sample_rate = stream->codec->sample_rate;
paras.audio_format = stream->codec->sample_fmt;
paras.codec_id = stream->codec->codec_id;
#endif
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";
}
}
namespace cutscene {
@@ -155,7 +180,30 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& st
status->audioStream = ctx->streams[audioStream];
}
status->videoCodecPars = getCodecParameters(status->videoStream);
auto& current_language = Lcl_languages[Lcl_current_lang];
for (uint32_t i = 0; i < ctx->nb_streams; ++i) {
auto test_stream = ctx->streams[i];
auto& pars = test_stream->codecpar;
if (!(pars->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
continue;
}
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 +261,37 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& st
status->audioCodec->name ? status->audioCodec->name : "<Unknown>"));
}
if (status->subtitleStreamIndex >= 0) {
// 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;
}
@@ -279,10 +358,14 @@ void FFMPEGDecoder::startDecoding() {
std::unique_ptr<VideoDecoder> videoDecoder(new VideoDecoder(m_status.get()));
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()));
}
auto ctx = m_input->m_ctx->ctx();
AVPacket packet;
@@ -322,7 +405,14 @@ 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));
}
}
}
if (isDecoding()) {
@@ -349,6 +439,10 @@ bool FFMPEGDecoder::hasAudio() {
return m_status->audioStreamIndex >= 0;
}
bool FFMPEGDecoder::hasSubtitles() {
return m_status->subtitleStreamIndex >= 0;
}
void FFMPEGDecoder::close() {
if (m_status) {
m_status = nullptr;
+2
View File
@@ -27,6 +27,8 @@ class FFMPEGDecoder: public Decoder {
bool hasAudio() SCP_OVERRIDE;
bool hasSubtitles() SCP_OVERRIDE;
void close() SCP_OVERRIDE;
};
}
+117
View File
@@ -0,0 +1,117 @@
//
//
#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() {
}
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);
virtual ~SubtitleDecoder();
virtual void decodePacket(AVPacket* packet) SCP_OVERRIDE;
virtual void finishDecoding() SCP_OVERRIDE;
void pushSubtitleFrame(AVPacket* subtitle, AVSubtitle* pSubtitle);
};
}
}
+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
+8
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,12 @@ struct DecoderStatus {
AVCodec* audioCodec = nullptr;
AVCodecContext* audioCodecCtx = nullptr;
int subtitleStreamIndex = -1;
AVStream* subtitleStream = nullptr;
CodecContextParameters subtitleCodecPars;
AVCodec* subtitleCodec = nullptr;
AVCodecContext* subtitleCodecCtx = nullptr;
DecoderStatus();
~DecoderStatus();
+200 -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,203 @@
#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;
// 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 +251,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));
+96 -176
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"
@@ -19,62 +19,19 @@
#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 ffmpeg::FFMPEGDecoder());
if (ffmpeg->initialize(name)) {
return ffmpeg;
}
delete ffmpeg;
}
return nullptr;
@@ -93,7 +50,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 +120,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 +141,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 +176,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 +201,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 +256,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 +267,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) : m_decoder(std::move(decoder)) {
initPlayback();
}
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() {
void Player::initPlayback() {
Assertion(!m_state.videoInited, "Internal State has been initialized before! Create a new player for replaying a movie.");
m_decoderThread.reset(new std::thread(std::bind(&Player::decoderThread, this)));
PlayerState state;
state.props = m_decoder->getProperties();
state.decoder = m_decoder.get();
m_state.props = m_decoder->getProperties();
m_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(&m_state);
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));
}
audioPlaybackInit(&m_state);
}
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();
}
@@ -460,10 +362,28 @@ std::unique_ptr<Player> Player::newPlayer(const SCP_string& name) {
if (decoder == nullptr) {
return nullptr;
}
return std::unique_ptr<Player>(new Player(std::move(decoder)));
}
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;
}
std::unique_ptr<Player> player(new Player());
player->m_decoder.reset(decoder);
return player;
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;
}
}
}
+89 -8
View File
@@ -5,11 +5,48 @@
#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
@@ -20,22 +57,66 @@ class Player {
std::unique_ptr<std::thread> m_decoderThread;
void processDecoderData(PlayerState* state);
PlayerState m_state;
bool processDecoderData();
private:
Player(const Player&) = delete;
void decoderThread();
void initPlayback();
public:
Player();
explicit Player(std::unique_ptr<Decoder>&& decoder);
~Player();
Player(const Player&) = delete;
Player& operator=(const Player&) = delete;
/**
* @brief Begin playing the previously selected movie
*/
void startPlayback();
* @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 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);
SCP_string getCurrentSubtitle();
/**
* @brief Stops playback
*
* This is also automatically called when this instance is destroyed.
*/
void stopPlayback();
/**
* @brief Creates a player
@@ -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
+6 -6
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(SND_MISSILE_IMPACT1), &debris_obj->pos, &View_position, debris_obj->radius );
}
}
@@ -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(SND_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(SND_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(SND_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(SND_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(SND_DEBRIS_ARC_01), &snd_pos, &View_position, obj->radius );
}
}
}
+15
View File
@@ -0,0 +1,15 @@
in vec4 fragTexCoord;
in vec4 fragColor;
out vec4 fragOut0;
uniform sampler2DArray baseMap;
uniform float intensity;
#define SRGB_GAMMA 2.2
void main()
{
vec4 baseColor = texture(baseMap, fragTexCoord.xyz);
baseColor.rgb = pow(baseColor.rgb, vec3(SRGB_GAMMA));
vec4 blendColor = vec4(pow(fragColor.rgb, vec3(SRGB_GAMMA)), 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;
}
+19
View File
@@ -0,0 +1,19 @@
in vec4 fragTexCoord;
in vec4 fragColor;
out vec4 fragOut0;
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, 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;
fragOut0 = mix(mix(baseColor * blendColor, vec4(blendColor.rgb, baseColor.r * blendColor.a), float(alphaTexture)), blendColor, float(noTexturing)) * intensity;
}
+19 -9
View File
@@ -1,21 +1,31 @@
in vec3 beamVec;
in vec3 lightPosition;
out vec4 fragOut0;
uniform sampler2D ColorBuffer;
uniform sampler2D NormalBuffer;
uniform sampler2D PositionBuffer;
uniform sampler2D SpecBuffer;
uniform float specFactor;
uniform float invScreenWidth;
uniform float invScreenHeight;
uniform int lightType;
uniform float lightRadius;
uniform vec3 diffuseLightColor;
uniform vec3 specLightColor;
uniform float coneAngle;
uniform float coneInnerAngle;
uniform bool dualCone;
uniform vec3 coneDir;
layout (std140) uniform lightData {
vec3 diffuseLightColor;
float coneAngle;
vec3 specLightColor;
float coneInnerAngle;
vec3 coneDir;
bool dualCone;
vec3 scale;
float lightRadius;
int lightType;
};
#define SPEC_INTENSITY_POINT 5.3 // Point light
#define SPEC_INTENSITY_DIRECTIONAL 3.0 // Directional light
@@ -93,4 +103,4 @@ void main()
vec4 fragmentColor = vec4(color * (diffuseLightColor * NdotL * attenuation), 1.0);
fragmentColor.rgb += SpecularBlinnPhong(specColor.rgb, lightDir, normal.xyz, halfVec, exp2(10.0 * gloss + 1.0), fresnel, NdotL).rgb * specLightColor * attenuation;
fragOut0 = max(fragmentColor, vec4(0.0));
}
}
+18 -3
View File
@@ -1,8 +1,23 @@
in vec4 vertPosition;
uniform mat4 modelViewMatrix;
uniform mat4 projMatrix;
uniform vec3 scale;
uniform int lightType;
layout (std140) uniform lightData {
vec3 diffuseLightColor;
float coneAngle;
vec3 specLightColor;
float coneInnerAngle;
vec3 coneDir;
bool dualCone;
vec3 scale;
float lightRadius;
int lightType;
};
out vec3 lightPosition;
out vec3 beamVec;
void main()
@@ -11,4 +26,4 @@ void main()
lightPosition = modelViewMatrix[3].xyz;
if(lightType == 1)
beamVec = vec3(modelViewMatrix * vec4(0.0, 0.0, -scale.z, 0.0));
}
}
+3 -3
View File
@@ -2,7 +2,7 @@ in vec4 fragTexCoord;
in vec4 fragColor;
in float fragOffset;
out vec4 fragOut0;
uniform sampler2D baseMap;
uniform sampler2DArray baseMap;
uniform sampler2D depthMap;
uniform float window_width;
uniform float window_height;
@@ -11,10 +11,10 @@ uniform sampler2D frameBuffer;
void main()
{
vec2 depthCoord = vec2(gl_FragCoord.x / window_width, gl_FragCoord.y / window_height);
vec4 fragmentColor = texture(baseMap, fragTexCoord.xy) * fragColor.a;
vec4 fragmentColor = texture(baseMap, fragTexCoord.xyz) * fragColor.a;
vec2 distortion = texture(distMap, fragTexCoord.xy+vec2(0.0, fragOffset)).rg;
float alpha = clamp(dot(fragmentColor.rgb,vec3(0.3333))*10.0,0.0,1.0);
distortion = ((distortion - 0.5) * 0.01) * alpha;
fragOut0 = texture(frameBuffer,depthCoord+distortion);
fragOut0.a = alpha;
}
}
+2 -2
View File
@@ -12,6 +12,6 @@ void main()
{
gl_Position = projMatrix * modelViewMatrix * vertPosition;
fragOffset = vertRadius * use_offset;
fragTexCoord = vertTexCoord;
fragTexCoord = vec4(vertTexCoord.xyz, 0.0);
fragColor = vertColor;
}
}
-10
View File
@@ -1,10 +0,0 @@
in vec4 fragTexCoord;
in vec4 fragColor;
out vec4 fragOut0;
uniform sampler2D baseMap;
uniform int textured;
void main()
{
vec4 fragmentColor = mix(fragColor, texture(baseMap, fragTexCoord.xy)*fragColor.a, (float)textured);
fragOut0 = fragmentColor;
}
+3 -3
View File
@@ -1,4 +1,4 @@
uniform sampler2D baseMap;
uniform sampler2DArray baseMap;
uniform sampler2D depthMap;
uniform float window_width;
uniform float window_height;
@@ -15,7 +15,7 @@ out vec4 fragOut0;
#define SRGB_GAMMA 2.2
void main()
{
vec4 fragmentColor = texture(baseMap, fragTexCoord.xy);
vec4 fragmentColor = texture(baseMap, fragTexCoord.xyz);
fragmentColor.rgb = mix(fragmentColor.rgb, pow(fragmentColor.rgb, vec3(SRGB_GAMMA)), float(srgb));
fragmentColor *= mix(fragColor, vec4(pow(fragColor.rgb, vec3(SRGB_GAMMA)), fragColor.a), float(srgb));
vec2 offset = vec2(fragRadius * abs(0.5 - fragTexCoord.x) * 2.0, fragRadius * abs(0.5 - fragTexCoord.y) * 2.0);
@@ -43,4 +43,4 @@ void main()
fragmentColor.rgb *= (srgb == 1) ? 1.5 : 1.0;
fragmentColor = (blend_alpha == 1) ? vec4(fragmentColor.rgb, fragmentColor.a * intensity) : vec4(fragmentColor.rgb * intensity, fragmentColor.a);
fragOut0 = max(fragmentColor, vec4(0.0));
}
}
+6 -5
View File
@@ -3,6 +3,7 @@ layout (triangle_strip, max_vertices = 4) out;
in vec3 geoUvec[];
in float geoRadius[];
in vec4 geoColor[];
in float geoArrayIndex[];
out float fragRadius;
out vec4 fragPosition;
out vec4 fragTexCoord;
@@ -18,7 +19,7 @@ void main(void)
pos = (gl_in[0].gl_Position - vec4(geoRadius[0] * up_vec, 0.0) - vec4(geoRadius[0] * right_vec, 0.0));
gl_Position = projMatrix * pos;
fragPosition = pos;
fragTexCoord = vec4(0.0, 0.0, 0.0, 0.0);
fragTexCoord = vec4(0.0, 0.0, geoArrayIndex[0], 0.0);
fragRadius = geoRadius[0];
fragColor = geoColor[0];
EmitVertex();
@@ -26,7 +27,7 @@ void main(void)
pos = (gl_in[0].gl_Position - vec4(geoRadius[0] * up_vec, 0.0) + vec4(geoRadius[0] * right_vec, 0.0));
gl_Position = projMatrix * pos;
fragPosition = pos;
fragTexCoord = vec4(0.0, 1.0, 0.0, 0.0);
fragTexCoord = vec4(0.0, 1.0, geoArrayIndex[0], 0.0);
fragRadius = geoRadius[0];
fragColor = geoColor[0];
EmitVertex();
@@ -34,7 +35,7 @@ void main(void)
pos = (gl_in[0].gl_Position + vec4(geoRadius[0] * up_vec, 0.0) - vec4(geoRadius[0] * right_vec, 0.0));
gl_Position = projMatrix * pos;
fragPosition = pos;
fragTexCoord = vec4(1.0, 0.0, 0.0, 0.0);
fragTexCoord = vec4(1.0, 0.0, geoArrayIndex[0], 0.0);
fragRadius = geoRadius[0];
fragColor = geoColor[0];
EmitVertex();
@@ -42,9 +43,9 @@ void main(void)
pos = (gl_in[0].gl_Position + vec4(geoRadius[0] * up_vec, 0.0) + vec4(geoRadius[0] * right_vec, 0.0));
gl_Position = projMatrix * pos;
fragPosition = pos;
fragTexCoord = vec4(1.0, 1.0, 0.0, 0.0);
fragTexCoord = vec4(1.0, 1.0, geoArrayIndex[0], 0.0);
fragRadius = geoRadius[0];
fragColor = geoColor[0];
EmitVertex();
EndPrimitive();
}
}
+4 -2
View File
@@ -7,6 +7,7 @@ in float vertRadius;
out vec3 geoUvec;
out float geoRadius;
out vec4 geoColor;
out float geoArrayIndex;
#else
out float fragRadius;
out vec4 fragPosition;
@@ -26,14 +27,15 @@ void main()
geoUvec = vertUvec;
gl_Position = modelViewMatrix * vertPosition;
geoColor = vertColor;
geoArrayIndex = vertTexCoord.z;
#else
fragRadius = vertRadius;
gl_Position = projMatrix * modelViewMatrix * vertPosition;
fragPosition = modelViewMatrix * vertPosition;
fragTexCoord = vertTexCoord;
fragTexCoord = vec4(vertTexCoord.xyz, 0.0);
fragColor = vertColor;
#endif
#ifdef FLAG_EFFECT_DISTORTION
fragOffset = vertRadius * use_offset;
#endif
}
}
+115 -78
View File
@@ -2,88 +2,131 @@
#define LT_DIRECTIONAL 0
#define LT_POINT 1
#define LT_TUBE 2
uniform vec4 color;
#ifdef FLAG_LIGHT
uniform vec4 lightPosition[MAX_LIGHTS];
uniform vec3 lightDirection[MAX_LIGHTS];
uniform vec3 lightDiffuseColor[MAX_LIGHTS];
uniform vec3 lightSpecColor[MAX_LIGHTS];
uniform int lightType[MAX_LIGHTS];
uniform float lightAttenuation[MAX_LIGHTS];
uniform int n_lights;
uniform float defaultGloss;
uniform vec3 ambientFactor;
uniform vec3 diffuseFactor;
uniform vec3 emissionFactor;
#endif
struct model_light {
vec4 position;
vec3 diffuse_color;
int light_type;
vec3 spec_color;
float attenuation;
vec3 direction;
};
layout (std140) uniform modelData {
mat4 modelViewMatrix;
mat4 modelMatrix;
mat4 viewMatrix;
mat4 projMatrix;
mat4 textureMatrix;
mat4 shadow_mv_matrix;
mat4 shadow_proj_matrix[4];
mat4 envMatrix;
vec4 color;
model_light lights[MAX_LIGHTS];
float extrudeWidth;
float fogStart;
float fogScale;
int buffer_matrix_offset;
vec4 clip_equation;
float thruster_scale;
bool use_clip_plane;
int n_lights;
float defaultGloss;
vec3 ambientFactor;
int desaturate;
vec3 diffuseFactor;
int blend_alpha;
vec3 emissionFactor;
bool overrideDiffuse;
vec3 diffuseClr;
bool overrideGlow;
vec3 glowClr;
bool overrideSpec;
vec3 specClr;
bool alphaGloss;
bool gammaSpec;
bool envGloss;
bool alpha_spec;
int effect_num;
vec4 fogColor;
vec3 base_color;
float anim_timer;
vec3 stripe_color;
float vpwidth;
float vpheight;
bool team_glow_enabled;
float znear;
float zfar;
float veryneardist;
float neardist;
float middist;
float fardist;
vec2 normalAlphaMinMax;
int sBasemapIndex;
int sGlowmapIndex;
int sSpecmapIndex;
int sNormalmapIndex;
int sAmbientmapIndex;
int sMiscmapIndex;
};
#ifdef FLAG_DIFFUSE_MAP
uniform sampler2D sBasemap;
uniform int desaturate;
uniform int blend_alpha;
uniform bool overrideDiffuse;
uniform vec3 diffuseClr;
uniform sampler2DArray sBasemap;
#endif
#ifdef FLAG_GLOW_MAP
uniform sampler2D sGlowmap;
uniform bool overrideGlow;
uniform vec3 glowClr;
uniform sampler2DArray sGlowmap;
#endif
#ifdef FLAG_SPEC_MAP
uniform sampler2D sSpecmap;
uniform bool overrideSpec;
uniform vec3 specClr;
uniform bool alphaGloss;
uniform bool gammaSpec;
uniform sampler2DArray sSpecmap;
#endif
#ifdef FLAG_ENV_MAP
uniform samplerCube sEnvmap;
uniform bool envGloss;
uniform bool alpha_spec;
in vec3 fragEnvReflect;
#endif
#ifdef FLAG_NORMAL_MAP
uniform sampler2D sNormalmap;
uniform sampler2DArray sNormalmap;
in mat3 fragTangentMatrix;
#endif
#ifdef FLAG_AMBIENT_MAP
uniform sampler2D sAmbientmap;
uniform sampler2DArray sAmbientmap;
#endif
#ifdef FLAG_FOG
uniform vec4 fogColor;
in float fragFogDist;
#endif
#ifdef FLAG_ANIMATED
uniform sampler2D sFramebuffer;
uniform int effect_num;
uniform float anim_timer;
uniform float vpwidth;
uniform float vpheight;
#endif
#ifdef FLAG_TRANSFORM
in float fragNotVisible;
#endif
#ifdef FLAG_TEAMCOLOR
uniform vec3 base_color;
uniform vec3 stripe_color;
uniform bool team_glow_enabled;
vec2 teamMask = vec2(0.0, 0.0);
#endif
#ifdef FLAG_MISC_MAP
uniform sampler2D sMiscmap;
uniform sampler2DArray sMiscmap;
#endif
#ifdef FLAG_SHADOWS
in vec4 fragShadowUV[4];
in vec4 fragShadowPos;
uniform sampler2DArray shadow_map;
uniform float znear;
uniform float zfar;
uniform float veryneardist;
uniform float neardist;
uniform float middist;
uniform float fardist;
#endif
#ifdef FLAG_NORMAL_ALPHA
uniform vec2 normalAlphaMinMax;
#endif
#define SPEC_INTENSITY_POINT 5.3 // Point light
#define SPEC_INTENSITY_DIRECTIONAL 3.0 // Directional light
@@ -210,26 +253,26 @@ vec3 SpecularBlinnPhong(vec3 specColor, vec3 light, vec3 normal, vec3 halfVec, f
#ifdef FLAG_LIGHT
void GetLightInfo(int i, out vec3 lightDir, out float attenuation)
{
lightDir = normalize(lightPosition[i].xyz);
lightDir = normalize(lights[i].position.xyz);
attenuation = 1.0;
if (lightType[i] != LT_DIRECTIONAL) {
if (lights[i].light_type != LT_DIRECTIONAL) {
// Positional light source
float dist = distance(lightPosition[i].xyz, fragPosition.xyz);
lightDir = (lightPosition[i].xyz - fragPosition.xyz);
float dist = distance(lights[i].position.xyz, fragPosition.xyz);
lightDir = (lights[i].position.xyz - fragPosition.xyz);
if (lightType[i] == LT_TUBE) { // Tube light
float beamlength = length(lightDirection[i]);
vec3 beamDir = normalize(lightDirection[i]);
if (lights[i].light_type == LT_TUBE) { // Tube light
float beamlength = length(lights[i].direction);
vec3 beamDir = normalize(lights[i].direction);
// Get nearest point on line
float neardist = dot(fragPosition.xyz - lightPosition[i].xyz, beamDir);
float neardist = dot(fragPosition.xyz - lights[i].position.xyz, beamDir);
// Move back from the endpoint of the beam along the beam by the distance we calculated
vec3 nearest = lightPosition[i].xyz - beamDir * abs(neardist);
vec3 nearest = lights[i].position.xyz - beamDir * abs(neardist);
lightDir = nearest - fragPosition.xyz;
dist = length(lightDir);
}
lightDir = normalize(lightDir);
attenuation = 1.0 / (1.0 + lightAttenuation[i] * dist);
attenuation = 1.0 / (1.0 + lights[i].attenuation * dist);
}
}
vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial, float gloss, float fresnel, float shadow, float aoFactor)
@@ -239,10 +282,7 @@ vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial,
vec3 lightDiffuse = vec3(0.0, 0.0, 0.0);
vec3 lightSpecular = vec3(0.0, 0.0, 0.0);
#pragma optionNV unroll all
for (int i = 0; i < MAX_LIGHTS; ++i) {
if (i > n_lights)
break;
for (int i = 0; i < n_lights; ++i) {
if(i > 0) {
shadow = 1.0;
}
@@ -254,17 +294,14 @@ vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial,
vec3 halfVec = normalize(lightDir + eyeDir);
float NdotL = max(dot(normal, lightDir), 0.0);
// Ambient, Diffuse, and Specular
lightDiffuse += (lightDiffuseColor[i].rgb * diffuseFactor * NdotL * attenuation) * shadow;
lightSpecular += lightSpecColor[i] * SpecularBlinnPhong(specularMaterial, lightDir, normal, halfVec, exp2(10.0 * gloss + 1.0), fresnel, NdotL) * attenuation * shadow;
lightDiffuse += (lights[i].diffuse_color.rgb * diffuseFactor * NdotL * attenuation) * shadow;
lightSpecular += lights[i].spec_color * SpecularBlinnPhong(specularMaterial, lightDir, normal, halfVec, exp2(10.0 * gloss + 1.0), fresnel, NdotL) * attenuation * shadow;
}
return diffuseMaterial * (lightAmbient + lightDiffuse) + lightSpecular;
}
#endif
void main()
{
#ifdef FLAG_TRANSFORM
if(fragNotVisible >= 0.9) { discard; }
#endif
#ifdef FLAG_SHADOW_MAP
// need depth and depth squared for variance shadow maps
fragOut0 = vec4(fragPosition.z, fragPosition.z * fragPosition.z * VARIANCE_SHADOW_SCALE_INV, 0.0, 1.0);
@@ -283,15 +320,15 @@ void main()
#ifdef FLAG_AMBIENT_MAP
// red channel is ambient occlusion factor which only affects ambient lighting.
// green is cavity occlusion factor which only affects diffuse and specular lighting.
aoFactors = texture(sAmbientmap, texCoord).xy;
aoFactors = texture(sAmbientmap, vec3(texCoord, float(sAmbientmapIndex))).xy;
#endif
vec3 unitNormal = normalize(fragNormal);
vec3 normal = unitNormal;
#ifdef FLAG_NORMAL_MAP
// Normal map - convert from DXT5nm
vec2 normalSample;
normal.rg = normalSample = (texture(sNormalmap, texCoord).ag * 2.0) - 1.0;
normal.b = sqrt(1.0 - dot(normal.rg, normal.rg));
normal.rg = normalSample = (texture(sNormalmap, vec3(texCoord, float(sNormalmapIndex))).ag * 2.0) - 1.0;
normal.b = clamp(sqrt(1.0 - dot(normal.rg, normal.rg)), 0.0001, 1.0);
normal = fragTangentMatrix * normal;
float norm = length(normal);
// prevent breaking of normal maps
@@ -312,7 +349,7 @@ void main()
diffuseTexCoord = texCoord + distort*(1.0-anim_timer);
}
#endif
baseColor = texture(sBasemap, diffuseTexCoord);
baseColor = texture(sBasemap, vec3(diffuseTexCoord, float(sBasemapIndex)));
if ( blend_alpha == 0 && baseColor.a < 0.95 ) discard; // if alpha blending is not on, discard transparent pixels
// premultiply alpha if blend_alpha is 1. assume that our blend function is srcColor + (1-Alpha)*destColor.
// if blend_alpha is 2, assume blend func is additive and don't modify color
@@ -324,7 +361,7 @@ void main()
baseColor.rgb = pow(baseColor.rgb, vec3(SRGB_GAMMA));
#endif
#ifdef FLAG_SPEC_MAP
specColor = texture(sSpecmap, texCoord);
specColor = texture(sSpecmap, vec3(texCoord, float(sSpecmapIndex)));
if(alphaGloss) glossData = specColor.a;
if(overrideSpec) {
specColor.rgb = specClr;
@@ -343,7 +380,7 @@ void main()
#ifdef FLAG_MISC_MAP
#ifdef FLAG_TEAMCOLOR
vec4 teamMask = vec4(0.0, 0.0, 0.0, 0.0);
teamMask = texture(sMiscmap, texCoord);
teamMask = texture(sMiscmap, vec3(texCoord, float(sMiscmapIndex)));
vec3 base = max(base_color - vec3(0.5), vec3(0.0));
vec3 stripe = max(stripe_color - vec3(0.5), vec3(0.0));
baseColor.rgb += (base * teamMask.x) + (stripe * teamMask.y);
@@ -376,7 +413,7 @@ void main()
baseColor.rgb += envColour.rgb * FresnelLazarovEnv(specColor.rgb, eyeDir, normal, glossData);
#endif
#ifdef FLAG_GLOW_MAP
vec3 glowColor = texture(sGlowmap, texCoord).rgb;
vec3 glowColor = texture(sGlowmap, vec3(texCoord, float(sGlowmapIndex))).rgb;
if(overrideGlow) glowColor = glowClr;
#ifdef FLAG_HDR
glowColor = pow(glowColor, vec3(SRGB_GAMMA)) * 3.0f;
+107 -12
View File
@@ -1,35 +1,130 @@
#extension GL_ARB_gpu_shader5: enable
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;
uniform mat4 shadow_proj_matrix[4];
#ifdef GL_ARB_gpu_shader5
layout(invocations = 4) in;
#endif
#define MAX_LIGHTS 8
struct model_light {
vec4 position;
vec3 diffuse_color;
int light_type;
vec3 spec_color;
float attenuation;
vec3 direction;
};
layout (std140) uniform modelData {
mat4 modelViewMatrix;
mat4 modelMatrix;
mat4 viewMatrix;
mat4 projMatrix;
mat4 textureMatrix;
mat4 shadow_mv_matrix;
mat4 shadow_proj_matrix[4];
mat4 envMatrix;
vec4 color;
model_light lights[MAX_LIGHTS];
float extrudeWidth;
float fogStart;
float fogScale;
int buffer_matrix_offset;
vec4 clip_equation;
float thruster_scale;
bool use_clip_plane;
int n_lights;
float defaultGloss;
vec3 ambientFactor;
int desaturate;
vec3 diffuseFactor;
int blend_alpha;
vec3 emissionFactor;
bool overrideDiffuse;
vec3 diffuseClr;
bool overrideGlow;
vec3 glowClr;
bool overrideSpec;
vec3 specClr;
bool alphaGloss;
bool gammaSpec;
bool envGloss;
bool alpha_spec;
int effect_num;
vec4 fogColor;
vec3 base_color;
float anim_timer;
vec3 stripe_color;
float vpwidth;
float vpheight;
bool team_glow_enabled;
float znear;
float zfar;
float veryneardist;
float neardist;
float middist;
float fardist;
vec2 normalAlphaMinMax;
int sBasemapIndex;
int sGlowmapIndex;
int sSpecmapIndex;
int sNormalmapIndex;
int sAmbientmapIndex;
int sMiscmapIndex;
};
#if !defined(GL_ARB_gpu_shader5)
in float geoInstance[];
#endif
in vec3 geoNormal[];
in vec4 geoTexCoord[];
out vec4 fragPosition;
out vec3 fragNormal;
out vec4 fragTexCoord;
#ifdef FLAG_TRANSFORM
in float geoNotVisible[];
out float fragNotVisible;
#endif
void main(void)
{
#ifdef GL_ARB_gpu_shader5
int instanceID = gl_InvocationID;
#else
int instanceID = int(geoInstance[0]);
for(int vert = 0; vert < gl_in.length(); vert++)
#endif
for(int vert = 0; vert < gl_in.length(); vert++)
{
gl_Position = shadow_proj_matrix[instanceID] * gl_in[vert].gl_Position;
if(gl_Position.z < -1.0)
gl_Position.z = -1.0;
fragPosition = gl_in[vert].gl_Position;
fragPosition = gl_in[vert].gl_Position;
fragNormal = geoNormal[vert];
fragTexCoord = geoTexCoord[vert];
gl_Layer = instanceID;
#ifdef FLAG_TRANSFORM
fragNotVisible = geoNotVisible[0];
#endif
#ifdef FLAG_CLIP
#if defined(FLAG_CLIP) || defined(FLAG_TRANSFORM)
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
#endif
EmitVertex();
}
EndPrimitive();
}
}
+113 -41
View File
@@ -1,41 +1,117 @@
#extension GL_ARB_gpu_shader5: enable
#define MAX_LIGHTS 8
struct model_light {
vec4 position;
vec3 diffuse_color;
int light_type;
vec3 spec_color;
float attenuation;
vec3 direction;
};
layout (std140) uniform modelData {
mat4 modelViewMatrix;
mat4 modelMatrix;
mat4 viewMatrix;
mat4 projMatrix;
mat4 textureMatrix;
mat4 shadow_mv_matrix;
mat4 shadow_proj_matrix[4];
mat4 envMatrix;
vec4 color;
model_light lights[MAX_LIGHTS];
float extrudeWidth;
float fogStart;
float fogScale;
int buffer_matrix_offset;
vec4 clip_equation;
float thruster_scale;
bool use_clip_plane;
int n_lights;
float defaultGloss;
vec3 ambientFactor;
int desaturate;
vec3 diffuseFactor;
int blend_alpha;
vec3 emissionFactor;
bool overrideDiffuse;
vec3 diffuseClr;
bool overrideGlow;
vec3 glowClr;
bool overrideSpec;
vec3 specClr;
bool alphaGloss;
bool gammaSpec;
bool envGloss;
bool alpha_spec;
int effect_num;
vec4 fogColor;
vec3 base_color;
float anim_timer;
vec3 stripe_color;
float vpwidth;
float vpheight;
bool team_glow_enabled;
float znear;
float zfar;
float veryneardist;
float neardist;
float middist;
float fardist;
vec2 normalAlphaMinMax;
int sBasemapIndex;
int sGlowmapIndex;
int sSpecmapIndex;
int sNormalmapIndex;
int sAmbientmapIndex;
int sMiscmapIndex;
};
in vec4 vertPosition;
in vec4 vertTexCoord;
in vec3 vertNormal;
in vec4 vertTangent;
in float vertModelID;
uniform mat4 modelViewMatrix;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projMatrix;
uniform mat4 textureMatrix;
uniform vec4 color;
#ifdef FLAG_NORMAL_EXTRUDE
uniform float extrudeWidth;
#endif
#ifdef FLAG_ENV_MAP
uniform mat4 envMatrix;
out vec3 fragEnvReflect;
#endif
#ifdef FLAG_NORMAL_MAP
out mat3 fragTangentMatrix;
#endif
#ifdef FLAG_FOG
uniform float fogStart;
uniform float fogScale;
out float fragFogDist;
#endif
#ifdef FLAG_TRANSFORM
uniform samplerBuffer transform_tex;
uniform int buffer_matrix_offset;
#ifdef FLAG_SHADOW_MAP
out float geoNotVisible;
#else
out float fragNotVisible;
#endif
#endif
#ifdef FLAG_SHADOW_MAP
#if !defined(GL_ARB_gpu_shader5)
out float geoInstance;
uniform mat4 shadow_proj_matrix[4];
#endif
out vec3 geoNormal;
out vec4 geoTexCoord;
#else
@@ -44,27 +120,18 @@ out vec3 fragNormal;
out vec4 fragTexCoord;
#endif
#ifdef FLAG_SHADOWS
uniform mat4 shadow_mv_matrix;
uniform mat4 shadow_proj_matrix[4];
out vec4 fragShadowUV[4];
out vec4 fragShadowPos;
#endif
#ifdef FLAG_THRUSTER
uniform float thruster_scale;
#endif
#ifdef FLAG_CLIP
uniform int use_clip_plane;
uniform vec4 clip_equation;
#endif
#ifdef FLAG_TRANSFORM
#define TEXELS_PER_MATRIX 4
void getModelTransform(inout mat4 transform, out float invisible, int id, int matrix_offset)
void getModelTransform(inout mat4 transform, out bool invisible, int id, int matrix_offset)
{
transform[0] = texelFetch(transform_tex, (matrix_offset + id) * TEXELS_PER_MATRIX);
transform[1] = texelFetch(transform_tex, (matrix_offset + id) * TEXELS_PER_MATRIX + 1);
transform[2] = texelFetch(transform_tex, (matrix_offset + id) * TEXELS_PER_MATRIX + 2);
transform[3] = texelFetch(transform_tex, (matrix_offset + id) * TEXELS_PER_MATRIX + 3);
invisible = transform[3].w;
invisible = transform[3].w >= 0.9;
transform[3].w = 1.0;
}
#endif
@@ -88,13 +155,10 @@ void main()
mat4 orient = mat4(1.0);
mat4 scale = mat4(1.0);
#ifdef FLAG_TRANSFORM
float invisible;
getModelTransform(orient, invisible, int(vertModelID), buffer_matrix_offset);
#ifdef FLAG_SHADOW_MAP
geoNotVisible = invisible;
#else
fragNotVisible = invisible;
#endif
bool clipModel;
getModelTransform(orient, clipModel, int(vertModelID), buffer_matrix_offset);
#else
bool clipModel = false;
#endif
texCoord = textureMatrix * vertTexCoord;
vec4 vertex = vertPosition;
@@ -108,11 +172,15 @@ void main()
position = modelViewMatrix * orient * vertex;
#ifdef FLAG_SHADOW_MAP
gl_Position = position;
#if !defined(GL_ARB_gpu_shader5)
#ifdef APPLE
geoInstance = float(gl_InstanceIDARB);
geoInstance = float(gl_InstanceIDARB);
#else
geoInstance = float(gl_InstanceID);
geoInstance = float(gl_InstanceID);
#endif
#endif
#else
gl_Position = projMatrix * position;
#endif
@@ -141,11 +209,15 @@ void main()
fragFogDist = clamp((gl_Position.z - fogStart) * 0.75 * fogScale, 0.0, 1.0);
#endif
#ifdef FLAG_CLIP
if(use_clip_plane == 1) {
if (clipModel) {
gl_ClipDistance[0] = -1.0;
} else if(use_clip_plane) {
gl_ClipDistance[0] = dot(clip_equation, modelMatrix * orient * vertex);
} else {
gl_ClipDistance[0] = -1.0f;
gl_ClipDistance[0] = 1.0;
}
#elif defined(FLAG_TRANSFORM)
gl_ClipDistance[0] = clipModel ? -1.0 : 1.0;
#endif
#ifndef FLAG_SHADOW_MAP
fragPosition = position;
+108
View File
@@ -0,0 +1,108 @@
// Enabled at all times but the define is kept here in case this should be configurable in the future
#define EDGE_AA
layout(std140) uniform NanoVGUniformData {
mat3 scissorMat;
mat3 paintMat;
vec4 innerCol;
vec4 outerCol;
vec2 scissorExt;
vec2 scissorScale;
vec2 extent;
float radius;
float feather;
float strokeMult;
float strokeThr;
int texType;
int type;
vec2 viewSize;
int texArrayIndex;
};
uniform sampler2DArray nvg_tex;
in vec2 ftcoord;
in vec2 fpos;
out vec4 outColor;
float sdroundrect(vec2 pt, vec2 ext, float rad) {
vec2 ext2 = ext - vec2(rad,rad);
vec2 d = abs(pt) - ext2;
return min(max(d.x,d.y),0.0) + length(max(d,0.0)) - rad;
}
// Scissoring
float scissorMask(vec2 p) {
vec2 sc = (abs((scissorMat * vec3(p,1.0)).xy) - scissorExt);
sc = vec2(0.5,0.5) - sc * scissorScale;
return clamp(sc.x,0.0,1.0) * clamp(sc.y,0.0,1.0);
}
#ifdef EDGE_AA
// Stroke - from [0..1] to clipped pyramid, where the slope is 1px.
float strokeMask() {
return min(1.0, (1.0-abs(ftcoord.x*2.0-1.0))*strokeMult) * min(1.0, ftcoord.y);
}
#endif
// The value the distance field has when the pixel is exactly on the edge. This needs to match the values in fontstash.h!
const float ON_EDGE_DISTANCE = 180.0 / 255.0;
void main(void) {
vec4 result;
float scissor = scissorMask(fpos);
#ifdef EDGE_AA
float strokeAlpha = strokeMask();
#else
float strokeAlpha = 1.0;
#endif
#ifdef EDGE_AA
if (strokeAlpha < strokeThr) {
discard;
}
#endif
if (type == 0) { // Gradient
// Calculate gradient color using box gradient
vec2 pt = (paintMat * vec3(fpos,1.0)).xy;
float d = clamp((sdroundrect(pt, extent, radius) + feather*0.5) / feather, 0.0, 1.0);
vec4 color = mix(innerCol,outerCol,d);
// Combine alpha
color *= strokeAlpha * scissor;
result = color;
} else if (type == 1) { // Image
// Calculate color fron texture
vec2 pt = (paintMat * vec3(fpos,1.0)).xy / extent;
vec4 color = texture(nvg_tex, vec3(pt, float(texArrayIndex)));
// Apply color tint and alpha.
if (texType == 1) color = vec4(color.xyz*color.w,color.w);
if (texType == 2) color = vec4(color.r);
color *= innerCol;
// Combine alpha
color *= strokeAlpha * scissor;
result = color;
} else if (type == 2) { // Stencil fill
result = vec4(1,1,1,1);
} else if (type == 3) { // Textured tris
vec4 color = texture(nvg_tex, vec3(ftcoord, float(texArrayIndex)));
if (texType == 1) color = vec4(color.xyz*color.w,color.w); if (texType == 2) color = vec4(color.x); color *= scissor;
result = color * innerCol;
} else if (type == 4) { // Distance vector text
vec4 color = texture(nvg_tex, vec3(ftcoord, float(texArrayIndex)));
float dist = color.r;
float width = fwidth(dist) / 2.0;
float alpha = smoothstep(ON_EDGE_DISTANCE - width, ON_EDGE_DISTANCE + width, dist);
color = innerCol * alpha;
result = color * scissor;
}
outColor = result;
}
+37
View File
@@ -0,0 +1,37 @@
layout(std140) uniform NanoVGUniformData {
mat3 scissorMat;
mat3 paintMat;
vec4 innerCol;
vec4 outerCol;
vec2 scissorExt;
vec2 scissorScale;
vec2 extent;
float radius;
float feather;
float strokeMult;
float strokeThr;
int texType;
int type;
vec2 viewSize;
int texArrayIndex;
};
in vec2 vertPosition;
in vec2 vertTexCoord;
out vec2 ftcoord;
out vec2 fpos;
void main(void) {
ftcoord = vertTexCoord;
fpos = vertPosition;
gl_Position = vec4(2.0*vertPosition.x/viewSize.x - 1.0, 1.0 - 2.0*vertPosition.y/viewSize.y, 0, 1);
}
+3 -6
View File
@@ -2,17 +2,14 @@ in vec4 fragTexCoord;
in vec4 fragColor;
out vec4 fragOut0;
uniform sampler2D baseMap;
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);
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;
fragOut0 = mix(mix(baseColor * blendColor, vec4(blendColor.rgb, baseColor.r * blendColor.a), float(alphaTexture)), blendColor, float(noTexturing)) * intensity;
}
fragOut0 = mix(baseColor * blendColor, blendColor, float(noTexturing));
}
+7 -1
View File
@@ -26,6 +26,9 @@ uniform float cutoff;
#ifdef FLAG_DITH
uniform float dither;
#endif
#ifdef FLAG_TINT
uniform vec3 tint;
#endif
uniform sampler2D blurred_tex;
uniform sampler2D depth_tex;
void main()
@@ -98,7 +101,10 @@ void main()
float downsampling_factor = 4;
float bias = 0.5;
color_out.rgb = floor(color_out.rgb * downsampling_factor + bias) / downsampling_factor;
#endif
#ifdef FLAG_TINT
color_out.rgb += tint;
#endif
color_out.a = 1.0;
fragOut0 = color_out;
}
}
+4 -3
View File
@@ -1,7 +1,8 @@
in vec4 fragImpactUV;
in float fragNormOffset;
uniform vec4 color;
uniform sampler2D shieldMap;
uniform sampler2DArray shieldMap;
uniform int shieldMapIndex;
uniform int srgb;
out vec4 fragOut0;
#define SRGB_GAMMA 2.2
@@ -10,9 +11,9 @@ void main()
{
if(fragNormOffset < 0.0) discard;
if(fragImpactUV.x < 0.0 || fragImpactUV.x > 1.0 || fragImpactUV.y < 0.0 || fragImpactUV.y > 1.0) discard;
vec4 shieldColor = texture(shieldMap, fragImpactUV.xy);
vec4 shieldColor = texture(shieldMap, vec3(fragImpactUV.xy, float(shieldMapIndex)));
shieldColor.rgb = (srgb == 1) ? pow(shieldColor.rgb, vec3(SRGB_GAMMA)) * EMISSIVE_GAIN : shieldColor.rgb;
vec4 blendColor = color;
blendColor.rgb = (srgb == 1) ? pow(blendColor.rgb, vec3(SRGB_GAMMA)) * EMISSIVE_GAIN : blendColor.rgb;
fragOut0 = shieldColor * blendColor;
}
}
+8 -5
View File
@@ -1,13 +1,16 @@
in vec4 fragTexCoord;
out vec4 fragOut0;
uniform sampler2D ytex;
uniform sampler2D utex;
uniform sampler2D vtex;
uniform sampler2DArray ytex;
uniform sampler2DArray utex;
uniform sampler2DArray vtex;
void main()
{
vec3 val = vec3(texture(ytex, fragTexCoord.st).r - 0.0625, texture(utex, fragTexCoord.st).r - 0.5, texture(vtex, fragTexCoord.st).r - 0.5);
float y = texture(ytex, vec3(fragTexCoord.st, 0.0)).r;
float u = texture(utex, vec3(fragTexCoord.st, 0.0)).r;
float v = texture(vtex, vec3(fragTexCoord.st, 0.0)).r;
vec3 val = vec3(y - 0.0625, u - 0.5, v - 0.5);
fragOut0.r = dot(val, vec3(1.1640625, 0.0, 1.59765625));
fragOut0.g = dot(val, vec3(1.1640625, -0.390625, -0.8125));
fragOut0.b = dot(val, vec3(1.1640625, 2.015625, 0.0));
fragOut0.a = 1.0;
}
}
+2 -2
View File
@@ -87,7 +87,7 @@ void fireball_play_warphole_open_sound(int ship_class, fireball *fb)
}
}
snd_play_3d(&Snds[sound_index], &fireball_objp->pos, &Eye_position, fireball_objp->radius, NULL, 0, 1.0f, SND_PRIORITY_DOUBLE_INSTANCE, NULL, range_multiplier); // play warp sound effect
snd_play_3d(gamesnd_get_game_sound(sound_index), &fireball_objp->pos, &Eye_position, fireball_objp->radius, NULL, 0, 1.0f, SND_PRIORITY_DOUBLE_INSTANCE, NULL, range_multiplier); // play warp sound effect
}
/**
@@ -111,7 +111,7 @@ void fireball_play_warphole_close_sound(fireball *fb)
return;
}
snd_play_3d(&Snds[sound_index], &fireball_objp->pos, &Eye_position, fireball_objp->radius); // play warp sound effect
snd_play_3d(gamesnd_get_game_sound(sound_index), &fireball_objp->pos, &Eye_position, fireball_objp->radius); // play warp sound effect
}
/**
+87 -1
View File
@@ -27,12 +27,21 @@
#include <unistd.h>
#include <cerrno>
#include <sys/ioctl.h>
#include <signal.h>
#ifdef SCP_SOLARIS
#include <sys/filio.h>
#endif
#include <ctype.h>
#define WSAGetLastError() (errno)
#define RESTART(syscall) \
({ \
__typeof__(syscall) _res; \
do \
_res = syscall; \
while (_res == -1 && errno == EINTR); \
_res; \
})
#else
#include <windows.h>
#include <process.h>
@@ -109,6 +118,18 @@ int FS2NetD_ConnectToServer(const char *host, const char *port)
ulong arg = 1;
ioctlsocket(mySocket, FIONBIO, &arg);
// Where SO_NOSIGPIPE is defined (currently OS X):
// prevent SIGPIPE, which is generated when sending after receiver disconnected
// on other *nix use MSG_NOSIGNAL flag when sending data, or, failing that, use signal masking
// see FS2NetD_SendData()
#if defined(SCP_UNIX) && defined(SO_NOSIGPIPE)
int nosigpipe = 1;
if (setsockopt(mySocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nosigpipe, sizeof(nosigpipe)) == -1) {
my_error = errno;
ml_printf("FS2NetD ERROR: Couldn't set SO_NOSIGPIPE on socket (\"%s\")!", strerror(my_error));
}
#endif // SCP_UNIX && SO_NOSIGPIPE
// blasted MS, probably need to use getaddrinfo() here for Win32, but I
// want to keep this as clean and simple as possible and that means
// using an actual standard :)
@@ -237,9 +258,74 @@ int FS2NetD_SendData(char *buffer, int blen)
{
int flags = 0;
// on Unix with MSG_NOSIGNAL, prevent SIGPIPE, which is generated if receiver has disconnected
// the MSG_NOSIGNAL flag doesn't work on OS X or Solaris
// on OS X, use setsockopt() with SO_NOSIGPIPE instead, see above
#if defined(SCP_UNIX) && defined(MSG_NOSIGNAL)
flags |= MSG_NOSIGNAL;
#endif // SCP_UNIX && MSG_NOSIGNAL
socklen_t to_len = sizeof(sockaddr);
return sendto(mySocket, buffer, blen, flags, (sockaddr*)&FS2NetD_addr, to_len);
// Borrowed from Kroki:
// https://github.com/kroki/XProbes/blob/1447f3d93b6dbf273919af15e59f35cca58fcc23/src/libxprobes.c#L156
#if defined(SCP_UNIX) && !defined(MSG_NOSIGNAL) && !defined(SO_NOSIGPIPE)
/*
We want to ignore possible SIGPIPE that we can generate on write.
SIGPIPE is delivered *synchronously* and *only* to the thread
doing the write. So if it is reported as already pending (which
means the thread blocks it), then we do nothing: if we generate
SIGPIPE, it will be merged with the pending one (there's no
queuing), and that suits us well. If it is not pending, we block
it in this thread (and we avoid changing signal action, because it
is per-process).
*/
sigset_t pending;
sigset_t sigpipe_mask;
bool sigpipe_pending;
bool sigpipe_unblock;
sigemptyset(&pending);
sigpending(&pending);
sigpipe_pending = sigismember(&pending, SIGPIPE);
if (!sigpipe_pending) {
sigset_t blocked;
sigemptyset(&blocked);
pthread_sigmask(SIG_BLOCK, &sigpipe_mask, &blocked);
/* Maybe is was blocked already? */
sigpipe_unblock = ! sigismember(&blocked, SIGPIPE);
}
#endif /* defined(SCP_UNIX) && ! defined(MSG_NOSIGNAL) && ! defined(SO_NOSIGPIPE) */
auto sent_chars = sendto(mySocket, buffer, blen, flags, (sockaddr*)&FS2NetD_addr, to_len);
#if defined(SCP_UNIX) && !defined(MSG_NOSIGNAL) && !defined(SO_NOSIGPIPE)
/*
If SIGPIPE was pending already we do nothing. Otherwise, if it
become pending (i.e., we generated it), then we sigwait() it (thus
clearing pending status). Then we unblock SIGPIPE, but only if it
were us who blocked it.
*/
if (!sigpipe_pending) {
sigemptyset(&pending);
sigpending(&pending);
if (sigismember(&pending, SIGPIPE)) {
/*
Protect ourselves from a situation when SIGPIPE was sent
by the user to the whole process, and was delivered to
other thread before we had a chance to wait for it.
*/
static const struct timespec nowait = { 0, 0 };
RESTART(sigtimedwait(&sigpipe_mask, NULL, &nowait));
}
if (sigpipe_unblock) {
pthread_sigmask(SIG_UNBLOCK, &sigpipe_mask, NULL);
}
}
#endif /* defined(SCP_UNIX) && ! defined(MSG_NOSIGNAL) && ! defined(SO_NOSIGPIPE) */
return sent_chars;
}
bool FS2NetD_DataReady()
+5 -4
View File
@@ -1186,7 +1186,9 @@ void parse_soundtrack()
}
//Track doesn't exist and has nocreate, so don't create it
Assertion(skip_to_start_of_string_either("#SoundTrack Start", "#Menu Music Start") || skip_to_string("#SoundTrack End"), "Couldn't find #Soundtrack Start, #Menu Music Start or #Soundtrack End. Music.tbl or -mus.tbm is invalid.\n");
if ( !skip_to_start_of_string_either("#SoundTrack Start", "#Menu Music Start") && !skip_to_string("#SoundTrack End")) {
error_display(1, "Couldn't find #Soundtrack Start, #Menu Music Start or #Soundtrack End.");
}
return;
}
@@ -1281,7 +1283,7 @@ void parse_soundtrack()
}
//We're done here.
//required_string("#SoundTrack End");
required_string("#SoundTrack End");
// Goober5000 - set the valid flag according to whether we can load all our patterns
@@ -1370,12 +1372,11 @@ void event_music_parse_musictbl(const char *filename)
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
while ( skip_to_start_of_string_either("#Soundtrack Start", "#Menu Music Start", NULL ) )
while ( check_for_string("#Soundtrack Start") || check_for_string("#Menu Music Start") )
{
if ( optional_string("#Soundtrack Start") )
{
parse_soundtrack( );
required_string("#Soundtrack End");
}
if ( optional_string("#Menu Music Start") )
{
+245 -52
View File
@@ -263,7 +263,7 @@ void gamesnd_play_iface(int n)
if (Snds_iface_handle[n] >= 0)
snd_stop(Snds_iface_handle[n]);
Snds_iface_handle[n] = snd_play(&Snds_iface[n]);
Snds_iface_handle[n] = snd_play(gamesnd_get_interface_sound(n));
}
/**
@@ -310,16 +310,22 @@ int gamesnd_get_by_name(const char* name)
int i = 0;
for(SCP_vector<game_snd>::iterator snd = Snds.begin(); snd != Snds.end(); ++snd)
{
char *p = strrchr( snd->filename, '.' );
if (snd->sound_entries.size() != 1) {
// Ignore game sounds with more than one sound entry
continue;
}
auto& entry = snd->sound_entries.front();
char *p = strrchr( entry.filename, '.' );
if(p == NULL)
{
if(!stricmp(snd->filename, name))
if(!stricmp(entry.filename, name))
{
index = i;
break;
}
}
else if(!strnicmp(snd->filename, name, p-snd->filename))
else if(!strnicmp(entry.filename, name, p - entry.filename))
{
index = i;
break;
@@ -344,16 +350,22 @@ int gamesnd_get_by_iface_name(const char* name)
int i = 0;
for(SCP_vector<game_snd>::iterator snd = Snds_iface.begin(); snd != Snds_iface.end(); ++snd)
{
char *p = strrchr( snd->filename, '.' );
if (snd->sound_entries.size() != 1) {
// Ignore game sounds with more than one sound entry
continue;
}
auto& entry = snd->sound_entries.front();
char *p = strrchr( entry.filename, '.' );
if(p == NULL)
{
if(!stricmp(snd->filename, name))
if(!stricmp(entry.filename, name))
{
index = i;
break;
}
}
else if(!strnicmp(snd->filename, name, p-snd->filename))
else if(!strnicmp(entry.filename, name, p - entry.filename))
{
index = i;
break;
@@ -515,10 +527,12 @@ void gamesnd_preload_common_sounds()
Assert( Snds.size() <= INT_MAX );
for (SCP_vector<game_snd>::iterator gs = Snds.begin(); gs != Snds.end(); ++gs) {
if ( gs->filename[0] != 0 && strnicmp(gs->filename, NOX("none.wav"), 4) ) {
if ( gs->preload ) {
game_busy( NOX("** preloading common game sounds **") ); // Animate loading cursor... does nothing if loading screen not active.
gs->id = snd_load(&(*gs));
if ( gs->preload ) {
for (auto& entry : gs->sound_entries) {
if ( entry.filename[0] != 0 && strnicmp(entry.filename, NOX("none.wav"), 4) ) {
game_busy( NOX("** preloading common game sounds **") ); // Animate loading cursor... does nothing if loading screen not active.
entry.id = snd_load(&entry, gs->flags);
}
}
}
}
@@ -534,10 +548,12 @@ void gamesnd_load_gameplay_sounds()
Assert( Snds.size() <= INT_MAX );
for (SCP_vector<game_snd>::iterator gs = Snds.begin(); gs != Snds.end(); ++gs) {
if ( gs->filename[0] != 0 && strnicmp(gs->filename, NOX("none.wav"), 4) ) {
if ( !gs->preload ) { // don't try to load anything that's already preloaded
game_busy( NOX("** preloading gameplay sounds **") ); // Animate loading cursor... does nothing if loading screen not active.
gs->id = snd_load(&(*gs));
if ( !gs->preload ) { // don't try to load anything that's already preloaded
for (auto& entry : gs->sound_entries) {
if (entry.filename[0] != 0 && strnicmp(entry.filename, NOX("none.wav"), 4)) {
game_busy(NOX("** preloading gameplay sounds **")); // Animate loading cursor... does nothing if loading screen not active.
entry.id = snd_load(&entry, gs->flags);
}
}
}
}
@@ -550,9 +566,11 @@ void gamesnd_unload_gameplay_sounds()
{
Assert( Snds.size() <= INT_MAX );
for (SCP_vector<game_snd>::iterator gs = Snds.begin(); gs != Snds.end(); ++gs) {
if ( gs->id != -1 ) {
snd_unload( gs->id );
gs->id = -1;
for (auto& entry : gs->sound_entries) {
if (entry.id != -1) {
snd_unload(entry.id);
entry.id = -1;
}
}
}
}
@@ -567,8 +585,10 @@ void gamesnd_load_interface_sounds()
Assert( Snds_iface.size() < INT_MAX );
for (SCP_vector<game_snd>::iterator si = Snds_iface.begin(); si != Snds_iface.end(); ++si) {
if ( si->filename[0] != 0 && strnicmp(si->filename, NOX("none.wav"), 4) ) {
si->id = snd_load(&(*si));
for (auto& entry : si->sound_entries) {
if ( entry.filename[0] != 0 && strnicmp(entry.filename, NOX("none.wav"), 4) ) {
entry.id = snd_load(&entry, si->flags);
}
}
}
}
@@ -580,10 +600,12 @@ void gamesnd_unload_interface_sounds()
{
Assert( Snds_iface.size() < INT_MAX );
for (SCP_vector<game_snd>::iterator si = Snds_iface.begin(); si != Snds_iface.end(); ++si) {
if ( si->id != -1 ) {
snd_unload( si->id );
si->id = -1;
si->id_sig = -1;
for (auto& entry : si->sound_entries) {
if ( entry.id != -1 ) {
snd_unload( entry.id );
entry.id = -1;
entry.id_sig = -1;
}
}
}
}
@@ -593,11 +615,15 @@ void parse_gamesnd_old(game_snd* gs)
int is_3d;
int temp;
stuff_string(gs->filename, F_NAME, MAX_FILENAME_LEN, ",");
// An old sound is just a single entry sound set
gs->sound_entries.resize(1);
auto& entry = gs->sound_entries.back();
if (!stricmp(gs->filename, NOX("empty")))
stuff_string(entry.filename, F_NAME, MAX_FILENAME_LEN, ",");
if (!stricmp(entry.filename, NOX("empty")))
{
gs->filename[0] = 0;
entry.filename[0] = 0;
advance_to_eoln(NULL);
return;
}
@@ -610,7 +636,9 @@ void parse_gamesnd_old(game_snd* gs)
gs->preload = true;
}
stuff_float(&gs->default_volume);
float default_volume;
stuff_float(&default_volume);
gs->volume_range = util::UniformFloatRange(default_volume);
stuff_int(&is_3d);
@@ -626,7 +654,7 @@ void parse_gamesnd_old(game_snd* gs)
gs->max = 0;
// silly retail, not abiding by its own format...
if (!stricmp(gs->filename, "l_hit.wav") || !stricmp(gs->filename, "m_hit.wav"))
if (!stricmp(entry.filename, "l_hit.wav") || !stricmp(entry.filename, "m_hit.wav"))
{
int temp_min, temp_max;
@@ -636,7 +664,7 @@ void parse_gamesnd_old(game_snd* gs)
ignore_gray_space();
if (stuff_int_optional(&temp_max, true) == 2)
{
mprintf(("Dutifully converting retail sound %s, '%s' to a 3D sound...\n", gs->name.c_str(), gs->filename));
mprintf(("Dutifully converting retail sound %s, '%s' to a 3D sound...\n", gs->name.c_str(), entry.filename));
is_3d = 1;
gs->flags |= GAME_SND_USE_DS3D;
@@ -647,11 +675,14 @@ void parse_gamesnd_old(game_snd* gs)
}
}
// Default pitch is 1.0
gs->pitch_range = util::UniformFloatRange(1.0f);
// check for extra values per Mantis #2408
ignore_gray_space();
if (stuff_int_optional(&temp, true) == 2)
{
Warning(LOCATION, "Unexpected extra value %d found for sound '%s' (filename '%s')! Check the format of the sounds.tbl (or .tbm) entry.", temp, gs->name.c_str(), gs->filename);
Warning(LOCATION, "Unexpected extra value %d found for sound '%s' (filename '%s')! Check the format of the sounds.tbl (or .tbm) entry.", temp, gs->name.c_str(), entry.filename);
}
advance_to_eoln(NULL);
@@ -703,28 +734,32 @@ bool required_string_no_create(const char* token, bool no_create)
return true;
}
void parse_gamesnd_new(game_snd* gs, bool no_create)
{
char name[MAX_FILENAME_LEN];
// New extended format found
stuff_string(name, F_NAME, MAX_FILENAME_LEN);
if (!stricmp(name, NOX("empty")))
{
gs->filename[0] = 0;
return;
static GameSoundCycleType parse_cycle_type() {
if (optional_string("Sequential")) {
return GameSoundCycleType::Sequential;
} else if (optional_string("Random")) {
return GameSoundCycleType::Random;
} else {
error_display(0, "Failed to parse sound cycle type. Expected 'sequential' or 'random'. Got [%.32s]", next_tokens());
// Ignore everything until the end of the line. That should hopefully skip the bad token.
advance_to_eoln(nullptr);
return GameSoundCycleType::Sequential;
}
}
// If the name _doesn't_ match <same> put it into gs->filename;
if (stricmp(name, "<same>"))
{
strcpy_s(gs->filename, name);
}
else if (!no_create)
{
// Throw an error if <same> was specified but we are creating a new entry
error_display(1, "'<same>' is only allowed if +nocreate was specified!");
return;
void parse_gamesnd_soundset(game_snd* gs, bool no_create) {
// If this gets called then we just saw "+Entry:" so we can begin processing the first entry immediately
do {
// For now there is no way to change an existing entry so ever +Entry statement creates a new sound entry
gs->sound_entries.resize(gs->sound_entries.size() + 1);
auto& entry = gs->sound_entries.back();
stuff_string(entry.filename, F_NAME, MAX_FILENAME_LEN);
} while (optional_string("+Entry:"));
if (required_string_no_create("+Cycle type:", no_create)) {
gs->cycle_type = parse_cycle_type();
}
if (required_string_no_create("+Preload:", no_create))
@@ -734,7 +769,7 @@ void parse_gamesnd_new(game_snd* gs, bool no_create)
if (required_string_no_create("+Volume:", no_create))
{
stuff_float(&gs->default_volume);
gs->volume_range = util::parseUniformRange(0.0f, 1.0f);
}
if (optional_string("+3D Sound:"))
@@ -781,6 +816,109 @@ void parse_gamesnd_new(game_snd* gs, bool no_create)
error_display(1, "Invalid enhanced sound limit: %d\n", temp_limit);
}
}
if (optional_string("+Pitch:")) {
gs->pitch_range = util::parseUniformRange(0.0001f);
} else if (!no_create) {
// Default pitch is 1.0
gs->pitch_range = util::UniformFloatRange(1.0f);
}
}
void parse_gamesnd_new(game_snd* gs, bool no_create)
{
game_snd_entry* entry = nullptr;
if (!no_create) {
gs->sound_entries.resize(1);
entry = &gs->sound_entries.back();
} else {
if (gs->sound_entries.size() != 1) {
error_display(1, "The SCP syntax cannot be used to modify an existing sound that has more than one entry! Use the soundset syntax for adding new entries.");
}
entry = &gs->sound_entries.back();
}
char name[MAX_FILENAME_LEN];
// New extended format found
stuff_string(name, F_NAME, MAX_FILENAME_LEN);
if (!stricmp(name, NOX("empty")))
{
entry->filename[0] = 0;
return;
}
// If the name _doesn't_ match <same> put it into gs->filename;
if (stricmp(name, "<same>"))
{
strcpy_s(entry->filename, name);
}
else if (!no_create)
{
// Throw an error if <same> was specified but we are creating a new entry
error_display(1, "'<same>' is only allowed if +nocreate was specified!");
return;
}
if (required_string_no_create("+Preload:", no_create))
{
stuff_boolean(&gs->preload);
}
if (required_string_no_create("+Volume:", no_create))
{
float default_volume;
stuff_float(&default_volume);
gs->volume_range = util::UniformFloatRange(default_volume);
}
if (optional_string("+3D Sound:"))
{
gs->flags |= GAME_SND_USE_DS3D;
required_string("+Attenuation start:");
stuff_int(&gs->min);
required_string("+Attenuation end:");
stuff_int(&gs->max);
}
else
{
gs->min = 0;
gs->max = 0;
}
// jg18 - enhanced sound parameters
if (optional_string("+Priority:"))
{
SCP_string priority_string;
stuff_string(priority_string, F_NAME);
EnhancedSoundPriority priority = convert_to_enhanced_priority(priority_string.c_str());
if (priority != SND_ENHANCED_PRIORITY_INVALID)
{
gs->enhanced_sound_data.priority= priority;
}
// else case not needed since conversion function displays message on error
}
if (optional_string("+Limit:"))
{
int temp_limit;
stuff_int(&temp_limit);
if ((temp_limit > 0) && (static_cast<uint>(temp_limit) <= SND_ENHANCED_MAX_LIMIT))
{
gs->enhanced_sound_data.limit = (unsigned int)temp_limit;
}
else
{
error_display(1, "Invalid enhanced sound limit: %d\n", temp_limit);
}
}
// Default pitch is 1.0
gs->pitch_range = util::UniformFloatRange(1.0f);
}
void gamesnd_parse_entry(game_snd *gs, bool no_create, SCP_vector<game_snd> *lookupVector)
@@ -820,6 +958,8 @@ void gamesnd_parse_entry(game_snd *gs, bool no_create, SCP_vector<game_snd> *loo
if (optional_string("+Filename:"))
{
parse_gamesnd_new(gs, no_create);
} else if (optional_string("+Entry:")) {
parse_gamesnd_soundset(gs, no_create);
}
else
{
@@ -1161,3 +1301,56 @@ void gamesnd_play_error_beep()
{
gamesnd_play_iface(SND_GENERAL_FAIL);
}
game_snd* gamesnd_get_game_sound(int handle) {
Assertion(handle >= 0 && handle < (int) Snds.size(), "Invalid game sound handle %d detected!", handle);
return &Snds[handle];
}
game_snd* gamesnd_get_interface_sound(int handle) {
Assertion(handle >= 0 && handle < (int) Snds_iface.size(), "Invalid interface sound handle %d detected!", handle);
return &Snds_iface[handle];
}
bool gamesnd_game_sound_valid(int sound) {
return sound >= 0 && sound < (int) Snds.size();
}
bool gamesnd_interface_sound_valid(int sound) {
return sound >= 0 && sound < (int) Snds_iface.size();
}
float gamesnd_get_max_duration(game_snd* gs) {
int max_length = 0;
for (auto& entry : gs->sound_entries) {
Assertion(entry.id != -1, "Game sound must be loaded to determine maximum duration!");
max_length = std::max(max_length, snd_get_duration(entry.id));
}
return max_length / gs->pitch_range.max();
}
game_snd_entry* gamesnd_choose_entry(game_snd* gs) {
Assertion(!gs->sound_entries.empty(), "No sound entries found in game sound! This may not happen!");
size_t index = 0;
switch(gs->cycle_type) {
case GameSoundCycleType::Random:
if (gs->sound_entries.size() == 1) {
index = 0;
} else {
index = util::UniformRange<size_t>(0, gs->sound_entries.size() - 1).next();
}
break;
case GameSoundCycleType::Sequential:
if (gs->last_entry_index == std::numeric_limits<size_t>::max()) {
// If this is the first time we must return the first sound to keep everything consistent
index = 0;
} else {
index = (gs->last_entry_index + 1) % gs->sound_entries.size();
}
break;
}
gs->last_entry_index = index;
return &gs->sound_entries[index];
}
+49 -3
View File
@@ -49,9 +49,6 @@ void parse_sound_list(const char* tag, SCP_vector<int>& destination, const char*
// this is a callback, so it needs to be a real function
void common_play_highlight_sound();
extern SCP_vector<game_snd> Snds;
extern SCP_vector<game_snd> Snds_iface;
/**
* symbolic names for misc. game sounds.
*
@@ -356,4 +353,53 @@ enum InterfaceSoundsIndex {
MIN_INTERFACE_SOUNDS =70 //!< MIN_INTERFACE_SOUNDS
};
/**
* @brief Gets a pointer to the game sound with the specified handle
* @param handle The sound handle
* @return The game sound handle
*/
game_snd* gamesnd_get_game_sound(int handle);
/**
* @brief Gets a pointer to the interface sound with the specified handle
* @param handle The sound handle
* @return The interface sound handle
*/
game_snd* gamesnd_get_interface_sound(int handle);
/**
* @brief Checks if the given sound handle is a valid game sound handle
* @param sound The handle to check
* @return @c true if the handle is valid
*/
bool gamesnd_game_sound_valid(int sound);
/**
* @brief Checks if the given sound handle is a valid interface sound handle
* @param sound The handle to check
* @return @c true if the handle is valid
*/
bool gamesnd_interface_sound_valid(int sound);
/**
* @brief Determines the maximum time this game sound may take to be played.
*
* @details Use this instead of snd_get_duration since a game sound may have multiple sounds with different durations.
* This function also accounts for pitch changes which also changes the length of a sound.
*
* @param gs The game sound to check
* @return The length of the sound in milliseconds
*/
float gamesnd_get_max_duration(game_snd* gs);
/**
* @brief Chooses a sound entry for the specified game sound according to the rules specified by the game data
*
* @warning The returned pointer is temporary and may not be valid forever. Do no store this pointer anywhere!
*
* @param gs The game sound to choose the entry from
* @return The chosen entry
*/
game_snd_entry* gamesnd_choose_entry(game_snd* gs);
#endif
+2 -2
View File
@@ -123,8 +123,8 @@ class flagset {
bool any_set() { return values.any(); }
bool none_set() { return values.none(); }
void from_long(std::uint64_t num) { values = num; }
std::uint64_t to_long() const { return values.to_ulong(); }
void from_u64(std::uint64_t num) { values = (unsigned long) num; }
std::uint64_t to_u64() const { return (std::uint64_t) values.to_ulong(); }
};
#define FLAG_LIST(Type) enum class Type : size_t
+31 -11
View File
@@ -75,11 +75,22 @@ typedef struct vec4 {
};
} vec4;
struct bvec4 {
bool x;
bool y;
bool z;
bool w;
};
// sometimes, you just need some integers
typedef struct ivec3 {
int x, y, z;
} ivec3;
struct ivec2 {
int x, y;
};
/** Represents a point in 3d space.
Note: this is a struct, not a class, so no member functions. */
@@ -318,6 +329,7 @@ const size_t INVALID_SIZE = static_cast<size_t>(-1);
#ifdef SCP_SOLARIS // Solaris
#define INTEL_INT(x) x
#define INTEL_LONG(x) x
#define INTEL_SHORT(x) x
#define INTEL_FLOAT(x) (*x)
#elif BYTE_ORDER == BIG_ENDIAN
@@ -425,10 +437,8 @@ public:
SCP_string dump_stacktrace();
// DEBUG compile time catch for dangerous uses of memset/memcpy/memmove
// would prefer std::is_trivially_copyable but it's not supported by gcc yet
// ref: http://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html
#ifndef NDEBUG
#if SCP_COMPILER_CXX_STATIC_ASSERT && SCP_COMPILER_CXX_AUTO_TYPE
#if SCP_COMPILER_CXX_AUTO_TYPE && SCP_COMPILER_CXX_STATIC_ASSERT && defined(HAVE_STD_IS_TRIVIALLY_COPYABLE)
// feature support seems to be: gcc clang msvc
// auto 4.4 2.9 2010
// std::is_trivial 4.5 ? 2012 (2010 only duplicates std::is_pod)
@@ -443,10 +453,20 @@ SCP_string dump_stacktrace();
// Put into std to be compatible with code that uses std::mem*
namespace std
{
// This is a separate check which also checks if arrays are trivially copyable since Visual Studio 2013 thinks they are not
#if SCP_COMPILER_IS_MSVC && _MSC_VER <= 1800
template<typename T>
using trivial_check = std::is_trivial<T>;
#else
template<typename T>
using trivial_check = std::is_trivially_copyable<T>;
#endif
template<typename T>
void *memset_if_trivial_else_error(T *memset_data, int ch, size_t count)
{
static_assert(std::is_trivial<T>::value, "memset on non-trivial object");
static_assert(trivial_check<T>::value, "memset on non-trivial object");
return ptr_memset(memset_data, ch, count);
}
@@ -464,8 +484,8 @@ namespace std
template<typename T, typename U>
void *memcpy_if_trivial_else_error(T *memcpy_dest, U *src, size_t count)
{
static_assert(std::is_trivial<T>::value, "memcpy on non-trivial object T");
static_assert(std::is_trivial<U>::value, "memcpy on non-trivial object U");
static_assert(trivial_check<T>::value, "memcpy on non-trivial object T");
static_assert(trivial_check<U>::value, "memcpy on non-trivial object U");
return ptr_memcpy(memcpy_dest, src, count);
}
@@ -480,20 +500,20 @@ namespace std
template<typename U>
void *memcpy_if_trivial_else_error(void *memcpy_dest, U *memcpy_src, size_t count)
{
static_assert(std::is_trivial<U>::value, "memcpy on non-trivial object U");
static_assert(trivial_check<U>::value, "memcpy on non-trivial object U");
return ptr_memcpy(memcpy_dest, memcpy_src, count);
}
template<typename T>
void *memcpy_if_trivial_else_error(T *memcpy_dest, void *memcpy_src, size_t count)
{
static_assert(std::is_trivial<T>::value, "memcpy on non-trivial object T");
static_assert(trivial_check<T>::value, "memcpy on non-trivial object T");
return ptr_memcpy(memcpy_dest, memcpy_src, count);
}
template<typename T>
void *memcpy_if_trivial_else_error(T *memcpy_dest, const void *memcpy_src, size_t count)
{
static_assert(std::is_trivial<T>::value, "memcpy on non-trivial object T");
static_assert(trivial_check<T>::value, "memcpy on non-trivial object T");
return ptr_memcpy(memcpy_dest, memcpy_src, count);
}
@@ -509,8 +529,8 @@ namespace std
template<typename T, typename U>
void *memmove_if_trivial_else_error(T *memmove_dest, U *memmove_src, size_t count)
{
static_assert(std::is_trivial<T>::value, "memmove on non-trivial object T");
static_assert(std::is_trivial<U>::value, "memmove on non-trivial object U");
static_assert(trivial_check<T>::value, "memmove on non-trivial object T");
static_assert(trivial_check<U>::value, "memmove on non-trivial object U");
return ptr_memmove(memmove_dest, memmove_src, count);
}
}
+8
View File
@@ -67,3 +67,11 @@
#define unlikely(x) __builtin_expect((long) !!(x), 0L)
#define USED_VARIABLE __attribute__((used))
#if __has_cpp_attribute(fallthough)
#define FALLTHROUGH [[fallthrough]]
#elif __has_cpp_attribute(clang::fallthough)
#define FALLTHROUGH [[clang::fallthrough]]
#else
#define FALLTHROUGH
#endif
+7
View File
@@ -51,3 +51,10 @@
* This can be used to ensure that a static variable is present even if it isn't referenced in the translation unit
*/
#define USED_VARIABLE
/**
* @brief For use in a case statement which falls through
*
* Some compilers issue a warning if a fallthrough is detected. This define can be used to suppress that warning.
*/
#define FALLTHROUGH
+7 -1
View File
@@ -65,4 +65,10 @@
#define likely(x) __builtin_expect((long) !!(x), 1L)
#define unlikely(x) __builtin_expect((long) !!(x), 0L)
#define USED_VARIABLE __attribute__((used))
#define USED_VARIABLE __attribute__((used))
#if SCP_COMPILER_VERSION_MAJOR >= 7
#define FALLTHROUGH [[fallthrough]]
#else
#define FALLTHROUGH
#endif
+7 -1
View File
@@ -62,4 +62,10 @@
#define __STDC_FORMAT_MACROS 1
#define USED_VARIABLE __attribute__((used))
#define USED_VARIABLE __attribute__((used))
#if SCP_COMPILER_VERSION_MAJOR >= 7
#define FALLTHROUGH [[fallthough]]
#else
#define FALLTHROUGH
#endif
+2
View File
@@ -85,3 +85,5 @@
#define unlikely(x)
#define USED_VARIABLE
#define FALLTHROUGH
+117 -72
View File
@@ -5,85 +5,130 @@
* or otherwise commercially exploit the source or things you created based on the
* source.
*
*/
*/
#include "globalincs/pstypes.h"
#include "globalincs/version.h"
namespace version
{
bool check_at_least(int major, int minor, int build, int revision)
{
if (FS_VERSION_MAJOR < major)
{
return false;
}
if (FS_VERSION_MAJOR > major)
{
// Major is greater than the given version => the rest doesn't matter
return true;
}
// major is now equal to our major version
if (FS_VERSION_MINOR < minor)
{
return false;
}
if (FS_VERSION_MINOR > minor)
{
// Minor is greater than the given version => the rest doesn't matter
return true;
}
// minor is now equal to our minor version
if (FS_VERSION_BUILD < build)
{
return false;
}
if (FS_VERSION_BUILD > build)
{
// build is greater than the given version => the rest doesn't matter
return true;
}
// build is now equal to our build version
if (revision == 0)
{
// Special case, if there is no revision info, skip it
return true;
}
if (FS_VERSION_REVIS == 0)
{
// Special case, when there is no revision ignore it
return true;
}
if (FS_VERSION_REVIS < revision)
{
return false;
}
if (FS_VERSION_REVIS > revision)
{
// build is greater than the given version => the rest doesn't matter
return true;
}
// revision is now equal to our revision version
#include "parse/parselo.h"
namespace gameversion {
bool check_at_least(const version& v) {
return get_executable_version() >= v;
}
SCP_string format_version(const version& v) {
SCP_stringstream ss;
ss << v.major << "." << v.minor << "." << v.build;
if (v.revision != 0) {
ss << "." << v.revision;
}
return ss.str();
}
version parse_version() {
version v;
required_string("+Major:");
stuff_int(&v.major);
required_string("+Minor:");
stuff_int(&v.minor);
required_string("+Build:");
stuff_int(&v.build);
if (optional_string("+Revision:")) {
stuff_int(&v.revision);
}
return v;
}
version get_executable_version() {
version v;
v.major = FS_VERSION_MAJOR;
v.minor = FS_VERSION_MINOR;
v.build = FS_VERSION_BUILD;
v.revision = FS_VERSION_REVIS;
return v;
}
version::version(int major_in, int minor_in, int build_in, int revision_in) :
major(major_in), minor(minor_in), build(build_in), revision(revision_in) {
}
bool version::operator<(const version& v) const {
if (major < v.major) {
return true;
}
if (major > v.major) {
// Major is greater than the given version => the rest doesn't matter
return false;
}
// major is now equal to our major version
if (minor < v.minor) {
return true;
}
if (minor > v.minor) {
// Minor is greater than the given version => the rest doesn't matter
return false;
}
// minor is now equal to our minor version
if (build < v.build) {
return true;
}
if (build > v.build) {
// build is greater than the given version => the rest doesn't matter
return false;
}
// build is now equal to our build version
if (revision == 0 || v.revision == 0) {
// Special case, if there is no revision info, then the versions are equal which means they are not less than each other
return false;
}
if (revision < v.revision) {
return true;
}
if (revision > v.revision) {
// build is greater than the given version => the rest doesn't matter
return false;
}
SCP_string format_version(int major, int minor, int build, int revision)
{
SCP_stringstream ss;
ss << major << "." << minor << "." << build;
if (revision != 0)
{
ss << "." << revision;
// revision is now equal to our revision version
return false;
}
bool version::operator==(const version& other) const {
if (major == other.major && minor == other.minor && build == other.build) {
if (revision == 0 || other.revision == 0) {
// Zero revisions always means that these are equal
return true;
}
return ss.str();
return revision == other.revision;
}
return false;
}
bool version::operator>(const version& other) const {
return other < *this;
}
bool version::operator<=(const version& other) const {
return !(other < *this);
}
bool version::operator>=(const version& other) const {
return !(*this < other);
}
bool version::operator!=(const version& other) const {
return !(*this == other);
}
}
+50 -24
View File
@@ -5,7 +5,7 @@
* or otherwise commercially exploit the source or things you created based on the
* source.
*
*/
*/
@@ -36,29 +36,55 @@
#include "project.h"
namespace version
{
/**
* @brief Checks if the current version is at least the given version
*
* @param major The major version to check
* @param minor The minor version to check
* @param build The build version to check
* @param revision The revision version to check
*
* @returns @c true when we are at least the given version, @c false otherwise
*/
bool check_at_least(int major, int minor, int build, int revision);
/**
* @brief Returns the string representation of the passed version
* @param major The major version to format
* @param minor The minor version to format
* @param build The build version to format
* @param revision The revision version to format
* @returns A string representation of the version number
*/
SCP_string format_version(int major, int minor, int build, int revision);
// The GCC POSIX headers seem to think defining a common word like "major" is a good idea...
// FYI, no it isn't.
#ifdef major
#undef major
#endif
#ifdef minor
#undef minor
#endif
namespace gameversion {
struct version {
int major = 0;
int minor = 0;
int build = 0;
int revision = 0;
version() {}
version(int major, int minor, int build, int revision);
bool operator<(const version& other) const;
bool operator==(const version& other) const;
bool operator!=(const version& other) const;
bool operator>(const version& rhs) const;
bool operator<=(const version& rhs) const;
bool operator>=(const version& rhs) const;
};
version parse_version();
version get_executable_version();
/**
* @brief Checks if the current version is at least the given version
*
* @param v The version to check
*
* @returns @c true when we are at least the given version, @c false otherwise
*/
bool check_at_least(const version& v);
/**
* @brief Returns the string representation of the passed version
* @param major The version to format
* @returns A string representation of the version number
*/
SCP_string format_version(const version& v);
}
#endif
+185 -34
View File
@@ -22,6 +22,8 @@
#include "gamesequence/gamesequence.h" //WMC - for scripting hooks in gr_flip()
#include "globalincs/systemvars.h"
#include "graphics/2d.h"
#include "graphics/matrix.h"
#include "graphics/light.h"
#include "graphics/font.h"
#include "graphics/grbatch.h"
#include "graphics/grinternal.h"
@@ -29,6 +31,8 @@
#include "graphics/opengl/gropengldraw.h"
#include "graphics/grstub.h"
#include "graphics/paths/PathRenderer.h"
#include "graphics/util/UniformBuffer.h"
#include "graphics/util/UniformBufferManager.h"
#include "io/keycontrol.h" // m!m
#include "io/timer.h"
#include "osapi/osapi.h"
@@ -36,6 +40,7 @@
#include "parse/parselo.h"
#include "render/3d.h"
#include "tracing/tracing.h"
#include "utils/boost/hash_combine.h"
#if ( SDL_VERSION_ATLEAST(1, 2, 7) )
#include "SDL_cpuinfo.h"
@@ -96,6 +101,11 @@ float Gr_save_menu_zoomed_offset_X = 0.0f, Gr_save_menu_zoomed_offset_Y = 0.0f;
bool Save_custom_screen_size;
// Forward definitions
static void uniform_buffer_managers_init();
static void uniform_buffer_managers_deinit();
static void uniform_buffer_managers_retire_buffers();
void gr_set_screen_scale(int w, int h, int zoom_w, int zoom_h, int max_w, int max_h, int center_w, int center_h, bool force_stretch)
{
bool do_zoom = zoom_w > 0 && zoom_h > 0 && (zoom_w != w || zoom_h != h);
@@ -634,9 +644,16 @@ void gr_close()
if ( !Gr_inited ) {
return;
}
// Cleanup uniform buffer managers
uniform_buffer_managers_deinit();
font::close();
gr_light_shutdown();
graphics::paths::PathRenderer::shutdown();
switch (gr_screen.mode) {
case GR_OPENGL:
gr_opengl_cleanup(true);
@@ -649,6 +666,8 @@ void gr_close()
Int3(); // Invalid graphics mode
}
bm_close();
Gr_inited = 0;
}
@@ -742,10 +761,7 @@ void gr_screen_resize(int width, int height)
gr_screen.save_max_w_unscaled_zoomed = gr_screen.max_w_unscaled_zoomed;
gr_screen.save_max_h_unscaled_zoomed = gr_screen.max_h_unscaled_zoomed;
if (gr_screen.mode == GR_OPENGL) {
extern void opengl_setup_viewport();
opengl_setup_viewport();
}
gr_setup_viewport();
}
int gr_get_resolution_class(int width, int height)
@@ -828,6 +844,7 @@ static bool gr_init_sub(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, i
gr_screen.bytes_per_pixel= depth / 8;
gr_screen.rendering_to_texture = -1;
gr_screen.envmap_render_target = -1;
gr_screen.line_width = 1.0f;
gr_screen.mode = mode;
gr_screen.res = res;
gr_screen.aspect = 1.0f; // Normal PC screen
@@ -1050,14 +1067,19 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
return false;
}
mprintf(("Initializing path renderer...\n"));
graphics::paths::PathRenderer::init();
gr_light_init();
gr_set_palette_internal(Gr_current_palette_name, NULL, 0);
bm_init();
io::mouse::CursorManager::init();
mprintf(("Initializing path renderer...\n"));
graphics::paths::PathRenderer::init();
// Initialize uniform buffer managers
uniform_buffer_managers_init();
bool missing_installation = false;
if (!running_unittests && Web_cursor == nullptr) {
if (Is_standalone) {
@@ -2074,34 +2096,6 @@ void gr_shield_icon(coord2d coords[6], int resize_mode)
g3_render_shield_icon(&gr_screen.current_color, coords, resize_mode);
}
void gr_rect(int x, int y, int w, int h, int resize_mode)
{
if (gr_screen.mode == GR_STUB) {
return;
}
g3_render_colored_rect(&gr_screen.current_color, x, y, w, h, resize_mode);
}
void gr_shade(int x, int y, int w, int h, int resize_mode)
{
int r, g, b, a;
if (gr_screen.mode == GR_STUB) {
return;
}
r = (int)gr_screen.current_shader.r;
g = (int)gr_screen.current_shader.g;
b = (int)gr_screen.current_shader.b;
a = (int)gr_screen.current_shader.c;
color clr;
gr_init_alphacolor(&clr, r, g, b, a);
g3_render_colored_rect(&clr, x, y, w, h, resize_mode);
}
void gr_set_bitmap(int bitmap_num, int alphablend_mode, int bitblt_mode, float alpha)
{
gr_screen.current_alpha = alpha;
@@ -2123,6 +2117,11 @@ void gr_flip(bool execute_scripting)
Script_system.EndFrame();
}
gr_reset_immediate_buffer();
// Use this opportunity for retiring the uniform buffers
uniform_buffer_managers_retire_buffers();
gr_screen.gf_flip();
}
@@ -2242,3 +2241,155 @@ void gr_print_timestamp(int x, int y, fix timestamp, int resize_mode)
gr_string(x, y, time, resize_mode);
}
static std::unique_ptr<graphics::util::UniformBufferManager>
uniform_buffer_managers[static_cast<size_t>(uniform_block_type::NUM_BLOCK_TYPES)];
static void uniform_buffer_managers_init() {
for (size_t i = 0; i < static_cast<size_t>(uniform_block_type::NUM_BLOCK_TYPES); ++i) {
auto enumVal = static_cast<uniform_block_type>(i);
uniform_buffer_managers[i].reset(new graphics::util::UniformBufferManager(enumVal));
}
}
static void uniform_buffer_managers_deinit() {
for (auto& manager: uniform_buffer_managers) {
manager.reset();
}
}
static void uniform_buffer_managers_retire_buffers() {
GR_DEBUG_SCOPE("Retiring unused uniform buffers");
for (auto& manager: uniform_buffer_managers) {
manager->retireBuffers();
}
}
graphics::util::UniformBuffer* gr_get_uniform_buffer(uniform_block_type type) {
return uniform_buffer_managers[static_cast<size_t>(type)]->getBuffer();
}
SCP_vector<DisplayData> gr_enumerate_displays()
{
// It seems that linux cannot handle having the video subsystem inited
// too late
if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
return SCP_vector<DisplayData>();
}
SCP_vector<DisplayData> data;
auto num_displays = SDL_GetNumVideoDisplays();
for (auto i = 0; i < num_displays; ++i) {
DisplayData display;
display.index = i;
SDL_Rect bounds;
if (SDL_GetDisplayBounds(i, &bounds) == 0) {
display.x = bounds.x;
display.y = bounds.y;
display.width = bounds.w;
display.height = bounds.h;
}
auto name = SDL_GetDisplayName(i);
if (name != nullptr) {
display.name = name;
}
auto num_mods = SDL_GetNumDisplayModes(i);
for (auto j = 0; j < num_mods; ++j) {
SDL_DisplayMode mode;
if (SDL_GetDisplayMode(i, j, &mode) != 0) {
continue;
}
VideoModeData videoMode;
videoMode.width = mode.w;
videoMode.height = mode.h;
int sdlBits = SDL_BITSPERPIXEL(mode.format);
if (SDL_ISPIXELFORMAT_ALPHA(mode.format)) {
videoMode.bit_depth = sdlBits;
} else {
// Fix a few values
if (sdlBits == 24) {
videoMode.bit_depth = 32;
} else if (sdlBits == 15) {
videoMode.bit_depth = 16;
} else {
videoMode.bit_depth = sdlBits;
}
}
display.video_modes.push_back(videoMode);
}
data.push_back(display);
}
SDL_QuitSubSystem(SDL_INIT_VIDEO);
return data;
}
namespace std {
size_t hash<vertex_format_data>::operator()(const vertex_format_data& data) const {
size_t seed = 0;
boost::hash_combine(seed, (size_t)data.format_type);
boost::hash_combine(seed, data.offset);
boost::hash_combine(seed, data.stride);
return seed;
}
size_t hash<vertex_layout>::operator()(const vertex_layout& data) const {
return data.hash();
}
}
bool vertex_layout::resident_vertex_format(vertex_format_data::vertex_format format_type) const {
return ( Vertex_mask & vertex_format_data::mask(format_type) ) ? true : false;
}
void vertex_layout::add_vertex_component(vertex_format_data::vertex_format format_type, size_t stride, size_t offset) {
// A stride value of 0 is not handled consistently by the graphics API so we must enforce that that does not happen
Assertion(stride != 0, "The stride of a vertex component may not be zero!");
if ( resident_vertex_format(format_type) ) {
// we already have a vertex component of this format type
return;
}
if (Vertex_mask == 0) {
// This is the first element so we need to initialize the global stride here
Vertex_stride = stride;
}
Assertion(Vertex_stride == stride, "The strides of all elements must be the same in a vertex layout!");
Vertex_mask |= (1 << format_type);
Vertex_components.push_back(vertex_format_data(format_type, stride, offset));
}
bool vertex_layout::operator==(const vertex_layout& other) const {
if (Vertex_mask != other.Vertex_mask) {
return false;
}
if (Vertex_components.size() != other.Vertex_components.size()) {
return false;
}
return std::equal(Vertex_components.cbegin(),
Vertex_components.cend(),
other.Vertex_components.cbegin());
}
size_t vertex_layout::hash() const {
size_t seed = 0;
boost::hash_combine(seed, Vertex_mask);
for (auto& comp : Vertex_components) {
boost::hash_combine(seed, comp);
}
return seed;
}
+207 -263
View File
@@ -5,7 +5,7 @@
* or otherwise commercially exploit the source or things you created based on the
* source.
*
*/
*/
@@ -13,7 +13,7 @@
#define _GRAPHICS_H
#include "graphics/grinternal.h"
#include <osapi/osapi.h>
#include "osapi/osapi.h"
#include "bmpman/bmpman.h"
#include "cfile/cfile.h"
#include "globalincs/pstypes.h"
@@ -22,6 +22,13 @@
#include "math/vecmat.h"
#include "io/cursor.h"
// Forward definition
namespace graphics {
namespace util {
class UniformBuffer;
}
}
extern const float Default_min_draw_distance;
extern const float Default_max_draw_distance;
extern float Min_draw_distance;
@@ -37,9 +44,12 @@ class model_material;
class particle_material;
class distortion_material;
class shield_material;
class movie_material;
class batched_bitmap_material;
class nanovg_material;
class transform_stack {
matrix4 Current_transform;
SCP_vector<matrix4> Stack;
public:
@@ -100,7 +110,7 @@ public:
vm_matrix4_x_matrix4(&Current_transform, &current_transform_copy, &new_transform);
Stack.push_back(Current_transform);
}
void pop()
{
if ( Stack.size() > 1 ) {
@@ -109,6 +119,10 @@ public:
Current_transform = Stack.back();
}
size_t depth() {
return Stack.size();
}
};
enum primitive_type {
@@ -138,8 +152,11 @@ enum shader_type {
SDR_TYPE_DEFERRED_LIGHTING,
SDR_TYPE_DEFERRED_CLEAR,
SDR_TYPE_VIDEO_PROCESS,
SDR_TYPE_PASSTHROUGH_RENDER,
SDR_TYPE_PASSTHROUGH_RENDER, //!< Shader for doing the old style fixed-function rendering. Only used internally, use SDR_TYPE_DEFAULT_MATERIAL.
SDR_TYPE_SHIELD_DECAL,
SDR_TYPE_BATCHED_BITMAP,
SDR_TYPE_DEFAULT_MATERIAL,
SDR_TYPE_NANOVG,
NUM_SHADER_TYPES
};
@@ -172,6 +189,16 @@ enum shader_type {
#define SDR_FLAG_BLUR_HORIZONTAL (1<<0)
#define SDR_FLAG_BLUR_VERTICAL (1<<1)
#define SDR_FLAG_NANOVG_EDGE_AA (1<<0)
enum class uniform_block_type {
Lights = 0,
ModelData = 1,
NanoVGData = 2,
NUM_BLOCK_TYPES
};
struct vertex_format_data
{
enum vertex_format {
@@ -181,74 +208,59 @@ struct vertex_format_data
SCREEN_POS,
COLOR3,
COLOR4,
TEX_COORD,
TEX_COORD2,
TEX_COORD3,
NORMAL,
TANGENT,
MODEL_ID,
RADIUS,
UVEC
UVEC,
};
vertex_format format_type;
size_t stride;
void *data_src;
int offset;
size_t offset;
vertex_format_data(vertex_format i_format_type, size_t i_stride, void *i_data_src) :
format_type(i_format_type), stride(i_stride), data_src(i_data_src), offset(-1) {}
vertex_format_data(vertex_format i_format_type, size_t i_stride, int i_offset) :
format_type(i_format_type), stride(i_stride), data_src(NULL), offset(i_offset) {}
vertex_format_data(vertex_format i_format_type, size_t i_stride, size_t i_offset) :
format_type(i_format_type), stride(i_stride), offset(i_offset) {}
static inline uint mask(vertex_format v_format) { return 1 << v_format; }
};
bool operator==(const vertex_format_data& other) const {
return format_type == other.format_type && stride == other.stride && offset == other.offset;
}
};
class vertex_layout
{
SCP_vector<vertex_format_data> Vertex_components;
uint Vertex_mask;
uint Vertex_mask = 0;
size_t Vertex_stride = 0;
public:
vertex_layout(): Vertex_mask(0) {}
vertex_layout() {}
vertex_layout(void* init_ptr): Vertex_mask(0) {}
size_t get_num_vertex_components() const { return Vertex_components.size(); }
size_t get_num_vertex_components() { return Vertex_components.size(); }
vertex_format_data* get_vertex_component(size_t index) { return &Vertex_components[index]; }
const vertex_format_data* get_vertex_component(size_t index) const { return &Vertex_components[index]; }
bool resident_vertex_format(vertex_format_data::vertex_format format_type)
{
return ( Vertex_mask & vertex_format_data::mask(format_type) ) ? true : false;
}
bool resident_vertex_format(vertex_format_data::vertex_format format_type) const;
void add_vertex_component(vertex_format_data::vertex_format format_type, void* src)
{
add_vertex_component(format_type, 0, src);
}
void add_vertex_component(vertex_format_data::vertex_format format_type, size_t stride, size_t offset);
void add_vertex_component(vertex_format_data::vertex_format format_type, size_t stride, void* src)
{
if ( resident_vertex_format(format_type) ) {
// we already have a vertex component of this format type
return;
}
size_t get_vertex_stride() { return Vertex_stride; }
Vertex_mask |= (1 << format_type);
Vertex_components.push_back(vertex_format_data(format_type, stride, src));
}
bool operator==(const vertex_layout& other) const;
void add_vertex_component(vertex_format_data::vertex_format format_type, size_t stride, int offset)
{
if ( resident_vertex_format(format_type) ) {
// we already have a vertex component of this format type
return;
}
Vertex_mask |= (1 << format_type);
Vertex_components.push_back(vertex_format_data(format_type, stride, offset));
}
size_t hash() const;
};
namespace std {
template<> struct hash<vertex_format_data> {
size_t operator()(const vertex_format_data& data) const;
};
template<> struct hash<vertex_layout> {
size_t operator()(const vertex_layout& data) const;
};
}
typedef enum gr_capability {
CAPABILITY_ENVIRONMENT_MAP,
@@ -264,6 +276,10 @@ typedef enum gr_capability {
CAPABILITY_TIMESTAMP_QUERY,
} gr_capability;
enum class gr_property {
UNIFORM_BUFFER_OFFSET_ALIGNMENT
};
// stencil buffering stuff
extern int gr_stencil_mode;
@@ -372,7 +388,7 @@ public:
{
return index;
}
uint i_first, i_last;
void release()
@@ -412,7 +428,7 @@ public:
index = NULL;
}
}
// Copy-constructor
buffer_data(const buffer_data& other)
{
@@ -425,17 +441,17 @@ public:
} else {
index = NULL;
}
flags = other.flags;
texture = other.texture;
n_verts = other.n_verts;
i_first = other.i_first;
i_last = other.i_last;
index_offset = other.index_offset;
}
// Copy-assignment operator
buffer_data& operator=(const buffer_data& rhs)
{
@@ -452,19 +468,19 @@ public:
index[i] = rhs.index[i];
}
}
flags = rhs.flags;
texture = rhs.texture;
n_verts = rhs.n_verts;
i_first = rhs.i_first;
i_last = rhs.i_last;
index_offset = rhs.index_offset;
}
return *this;
}
// Destructor
~buffer_data()
{
@@ -520,8 +536,8 @@ public:
};
struct indexed_vertex_source {
float *Vertex_list; // interleaved array
ubyte *Index_list;
void *Vertex_list;
void *Index_list;
int Vbuffer_handle;
int Ibuffer_handle;
@@ -554,6 +570,23 @@ enum class QueryType {
Timestamp
};
enum class BufferType {
Vertex,
Index,
Uniform
};
enum class BufferUsageHint {
Static,
Dynamic,
Streaming
};
/**
* @brief Type of a graphics sync object
*/
typedef void* gr_sync;
typedef struct screen {
uint signature; // changes when mode or palette or width or height changes
int max_w, max_h; // Width and height
@@ -604,13 +637,11 @@ typedef struct screen {
int envmap_render_target;
float line_width;
//switch onscreen, offscreen
void (*gf_flip)();
// Flash the screen
void (*gf_flash)( int r, int g, int b );
void (*gf_flash_alpha)(int r, int g, int b, int a);
// sets the clipping region
void (*gf_set_clip)(int x, int y, int w, int h, int resize_mode);
@@ -620,43 +651,9 @@ typedef struct screen {
// clears entire clipping region to current color
void (*gf_clear)();
// void (*gf_bitmap)(int x, int y, int resize_mode);
void (*gf_bitmap_ex)(int x, int y, int w, int h, int sx, int sy, int resize_mode);
void (*gf_aabitmap)(int x, int y, int resize_mode, bool mirror);
void (*gf_aabitmap_ex)(int x, int y, int w, int h, int sx, int sy, int resize_mode, bool mirror);
void(*gf_string)(float x, float y, const char * text, int resize_mode, int length);
// Draw a gradient line... x1,y1 is bright, x2,y2 is transparent.
void (*gf_gradient)(int x1, int y1, int x2, int y2, int resize_mode);
void (*gf_circle)(int x, int y, int r, int resize_mode);
void (*gf_unfilled_circle)(int x, int y, int r, int resize_mode);
void (*gf_arc)(int x, int y, float r, float angle_start, float angle_end, bool fill, int resize_mode);
void (*gf_curve)(int x, int y, int r, int direction, int resize_mode);
// Integer line. Used to draw a fast but pixely line.
void (*gf_line)(int x1, int y1, int x2, int y2, int resize_mode);
// Draws an antialiased line is the current color is an
// alphacolor, otherwise just draws a fast line. This
// gets called internally by g3_draw_line. This assumes
// the vertex's are already clipped, so call g3_draw_line
// not this if you have two 3d points.
void (*gf_aaline)(vertex *v1, vertex *v2);
void (*gf_pixel)( int x, int y, int resize_mode );
// dumps the current screen to a file
void (*gf_print_screen)(const char * filename);
// Call once before rendering anything.
void (*gf_start_frame)();
// Call after rendering is over.
void (*gf_stop_frame)();
// Retrieves the zbuffer mode.
int (*gf_zbuffer_get)();
@@ -673,24 +670,24 @@ typedef struct screen {
void (*gf_stencil_clear)();
int (*gf_alpha_mask_set)(int mode, float alpha);
// Saves screen. Returns an id you pass to restore and free.
int (*gf_save_screen)();
// Resets clip region and copies entire saved screen to the screen.
void (*gf_restore_screen)(int id);
// Frees up a saved screen.
void (*gf_free_screen)(int id);
// Sets the gamma
void (*gf_set_gamma)(float gamma);
// grab a region of the screen. assumes data is large enough
void (*gf_get_region)(int front, int w, int h, ubyte *data);
// set fog attributes
void (*gf_fog_set)(int fog_mode, int r, int g, int b, float fog_near, float fog_far);
void (*gf_fog_set)(int fog_mode, int r, int g, int b, float fog_near, float fog_far);
// poly culling
int (*gf_set_cull)(int cull);
@@ -720,36 +717,15 @@ typedef struct screen {
void (*gf_set_texture_addressing)(int);
int (*gf_create_vertex_buffer)(bool static_buffer);
int (*gf_create_index_buffer)(bool static_buffer);
int (*gf_create_buffer)(BufferType type, BufferUsageHint usage);
void (*gf_delete_buffer)(int handle);
void (*gf_update_buffer_data)(int handle, size_t size, void* data);
void (*gf_update_buffer_data_offset)(int handle, size_t offset, size_t size, void* data);
void (*gf_update_transform_buffer)(void* data, size_t size);
void (*gf_set_transform_buffer_offset)(size_t offset);
void (*gf_render_stream_buffer)(int buffer_handle, size_t offset, size_t n_verts, int flags);
//the projection matrix; fov, aspect ratio, near, far
void (*gf_set_proj_matrix)(float, float, float, float);
void (*gf_end_proj_matrix)();
//the view matrix
void (*gf_set_view_matrix)(const vec3d*, const matrix*);
void (*gf_end_view_matrix)();
//object scaleing
void (*gf_push_scale_matrix)(const vec3d*);
void (*gf_pop_scale_matrix)();
//object position and orientation
void (*gf_start_instance_matrix)(const vec3d*, const matrix*);
void (*gf_start_angles_instance_matrix)(const vec3d*, const angles*);
void (*gf_end_instance_matrix)();
void (*gf_set_light)(light*);
void (*gf_reset_lighting)();
void (*gf_set_ambient_light)(int,int,int);
// postprocessing effects
void (*gf_post_process_set_effect)(const char*, int);
void (*gf_post_process_set_effect)(const char*, int, const vec3d*);
void (*gf_post_process_set_defaults)();
void (*gf_post_process_begin)();
@@ -765,24 +741,18 @@ typedef struct screen {
void (*gf_scene_texture_end)();
void (*gf_copy_effect_texture)();
void (*gf_lighting)(bool,bool);
void (*gf_start_clip_plane)();
void (*gf_end_clip_plane)();
void (*gf_zbias)(int zbias);
void (*gf_set_fill_mode)(int);
void (*gf_set_texture_panning)(float u, float v, bool enable);
void (*gf_set_line_width)(float width);
void (*gf_sphere)(material *material_def, float rad);
int (*gf_maybe_create_shader)(shader_type type, unsigned int flags);
void (*gf_clear_states)();
void (*gf_update_texture)(int bitmap_handle, int bpp, const ubyte* data, int width, int height);
void (*gf_get_bitmap_from_texture)(void* data_out, int bitmap_num);
@@ -792,14 +762,15 @@ typedef struct screen {
// new drawing functions
void (*gf_render_model)(model_material* material_info, indexed_vertex_source *vert_source, vertex_buffer* bufferp, size_t texi);
void (*gf_render_shield_impact)(shield_material *material_info, primitive_type prim_type, vertex_layout *layout, int buffer_handle, int n_verts);
void (*gf_render_primitives)(material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
void (*gf_render_primitives_immediate)(material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, void* data, int size);
void (*gf_render_primitives)(material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle, size_t buffer_offset);
void (*gf_render_primitives_particle)(particle_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
void (*gf_render_primitives_distortion)(distortion_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
void (*gf_render_primitives_2d)(material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
void (*gf_render_primitives_2d_immediate)(material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, void* data, int size);
void (*gf_render_movie)(movie_material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, int buffer);
void (*gf_render_primitives_batched)(batched_bitmap_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
void (*gf_render_nanovg)(nanovg_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
bool (*gf_is_capable)(gr_capability capability);
bool (*gf_get_property)(gr_property property, void* destination);
void (*gf_push_debug_group)(const char* name);
void (*gf_pop_debug_group)();
@@ -812,6 +783,14 @@ typedef struct screen {
std::unique_ptr<os::Viewport> (*gf_create_viewport)(const os::ViewPortProperties& props);
void (*gf_use_viewport)(os::Viewport* view);
void (*gf_bind_uniform_buffer)(uniform_block_type bind_point, size_t offset, size_t size, int buffer);
gr_sync (*gf_sync_fence)();
bool (*gf_sync_wait)(gr_sync sync, uint64_t timeoutns);
void (*gf_sync_delete)(gr_sync sync);
void (*gf_set_viewport)(int x, int y, int width, int height);
} screen;
// handy macro
@@ -823,7 +802,7 @@ typedef struct screen {
// # Software Re-added by Kazan --- THIS HAS TO STAY -- It is used by standalone!
#define GR_DEFAULT (-1) // set to use default settings
#define GR_STUB (100)
#define GR_STUB (100)
#define GR_OPENGL (104) // Use OpenGl hardware renderer
// resolution constants - always keep resolutions in ascending order and starting from 0
@@ -917,71 +896,8 @@ __inline void gr_set_clip(int x, int y, int w, int h, int resize_mode=GR_RESIZE_
void gr_set_bitmap(int bitmap_num, int alphablend = GR_ALPHABLEND_NONE, int bitbltmode = GR_BITBLT_MODE_NORMAL, float alpha = 1.0f);
#define gr_clear GR_CALL(gr_screen.gf_clear)
__inline void gr_aabitmap(int x, int y, int resize_mode = GR_RESIZE_FULL, bool mirror = false)
{
(*gr_screen.gf_aabitmap)(x,y,resize_mode,mirror);
}
__inline void gr_aabitmap_ex(int x, int y, int w, int h, int sx, int sy, int resize_mode = GR_RESIZE_FULL, bool mirror = false)
{
(*gr_screen.gf_aabitmap_ex)(x,y,w,h,sx,sy,resize_mode,mirror);
}
__inline void gr_bitmap_ex(int x, int y, int w, int h, int sx, int sy, int resize_mode = GR_RESIZE_FULL)
{
(*gr_screen.gf_bitmap_ex)(x, y, w, h, sx, sy, resize_mode);
}
void gr_shield_icon(coord2d coords[6], const int resize_mode = GR_RESIZE_FULL);
void gr_rect(int x, int y, int w, int h, int resize_mode = GR_RESIZE_FULL);
void gr_shade(int x, int y, int w, int h, int resize_mode = GR_RESIZE_FULL);
__inline void gr_string(float x, float y, const char* string, int resize_mode = GR_RESIZE_FULL, int length = -1)
{
(*gr_screen.gf_string)(x, y, string, resize_mode, length);
}
__inline void gr_string(int x, int y, const char* string, int resize_mode = GR_RESIZE_FULL, int length = -1)
{
gr_string(i2fl(x), i2fl(y), string, resize_mode, length);
}
__inline void gr_circle(int xc, int yc, int d, int resize_mode = GR_RESIZE_FULL)
{
(*gr_screen.gf_circle)(xc,yc,d,resize_mode);
}
__inline void gr_unfilled_circle(int xc, int yc, int d, int resize_mode = GR_RESIZE_FULL)
{
(*gr_screen.gf_unfilled_circle)(xc,yc,d,resize_mode);
}
__inline void gr_arc(int xc, int yc, float r, float angle_start, float angle_end, bool fill, int resize_mode = GR_RESIZE_FULL)
{
(*gr_screen.gf_arc)(xc,yc,r,angle_start,angle_end,fill,resize_mode);
}
#define gr_curve GR_CALL(gr_screen.gf_curve)
__inline void gr_line(int x1, int y1, int x2, int y2, int resize_mode = GR_RESIZE_FULL)
{
(*gr_screen.gf_line)(x1, y1, x2, y2, resize_mode);
}
#define gr_aaline GR_CALL(gr_screen.gf_aaline)
__inline void gr_pixel(int x, int y, int resize_mode = GR_RESIZE_FULL)
{
(*gr_screen.gf_pixel)(x, y, resize_mode);
}
__inline void gr_gradient(int x1, int y1, int x2, int y2, int resize_mode = GR_RESIZE_FULL)
{
(*gr_screen.gf_gradient)(x1, y1, x2, y2, resize_mode);
}
#define gr_flash GR_CALL(gr_screen.gf_flash)
#define gr_flash_alpha GR_CALL(gr_screen.gf_flash_alpha)
#define gr_zbuffer_get GR_CALL(gr_screen.gf_zbuffer_get)
#define gr_zbuffer_set GR_CALL(gr_screen.gf_zbuffer_set)
@@ -1025,43 +941,24 @@ __inline void gr_fog_set(int fog_mode, int r, int g, int b, float fog_near = -1.
#define gr_bm_page_in_start GR_CALL(*gr_screen.gf_bm_page_in_start)
#define gr_bm_data GR_CALL(*gr_screen.gf_bm_data)
#define gr_bm_make_render_target GR_CALL(*gr_screen.gf_bm_make_render_target)
#define gr_bm_make_render_target GR_CALL(*gr_screen.gf_bm_make_render_target)
__inline int gr_bm_set_render_target(int n, int face = -1)
{
return (*gr_screen.gf_bm_set_render_target)(n, face);
}
#define gr_set_texture_addressing GR_CALL(*gr_screen.gf_set_texture_addressing)
#define gr_set_texture_addressing GR_CALL(*gr_screen.gf_set_texture_addressing)
__inline int gr_create_vertex_buffer(bool static_buffer = false)
inline int gr_create_buffer(BufferType type, BufferUsageHint usage)
{
return (*gr_screen.gf_create_vertex_buffer)(static_buffer);
}
__inline int gr_create_index_buffer(bool static_buffer = false)
{
return (*gr_screen.gf_create_index_buffer)(static_buffer);
return (*gr_screen.gf_create_buffer)(type, usage);
}
#define gr_delete_buffer GR_CALL(*gr_screen.gf_delete_buffer)
#define gr_update_buffer_data GR_CALL(*gr_screen.gf_update_buffer_data)
#define gr_update_buffer_data_offset GR_CALL(*gr_screen.gf_update_buffer_data_offset)
#define gr_update_transform_buffer GR_CALL(*gr_screen.gf_update_transform_buffer)
#define gr_set_transform_buffer_offset GR_CALL(*gr_screen.gf_set_transform_buffer_offset)
#define gr_set_proj_matrix GR_CALL(*gr_screen.gf_set_proj_matrix)
#define gr_end_proj_matrix GR_CALL(*gr_screen.gf_end_proj_matrix)
#define gr_set_view_matrix GR_CALL(*gr_screen.gf_set_view_matrix)
#define gr_end_view_matrix GR_CALL(*gr_screen.gf_end_view_matrix)
#define gr_push_scale_matrix GR_CALL(*gr_screen.gf_push_scale_matrix)
#define gr_pop_scale_matrix GR_CALL(*gr_screen.gf_pop_scale_matrix)
#define gr_start_instance_matrix GR_CALL(*gr_screen.gf_start_instance_matrix)
#define gr_start_angles_instance_matrix GR_CALL(*gr_screen.gf_start_angles_instance_matrix)
#define gr_end_instance_matrix GR_CALL(*gr_screen.gf_end_instance_matrix)
#define gr_set_light GR_CALL(*gr_screen.gf_set_light)
#define gr_reset_lighting GR_CALL(*gr_screen.gf_reset_lighting)
#define gr_set_ambient_light GR_CALL(*gr_screen.gf_set_ambient_light)
#define gr_scene_texture_begin GR_CALL(*gr_screen.gf_scene_texture_begin)
#define gr_scene_texture_end GR_CALL(*gr_screen.gf_scene_texture_end)
@@ -1080,14 +977,8 @@ inline void gr_post_process_restore_zbuffer() {
#define gr_deferred_lighting_end GR_CALL(*gr_screen.gf_deferred_lighting_end)
#define gr_deferred_lighting_finish GR_CALL(*gr_screen.gf_deferred_lighting_finish)
#define gr_set_lighting GR_CALL(*gr_screen.gf_lighting)
#define gr_start_clip GR_CALL(*gr_screen.gf_start_clip_plane)
#define gr_end_clip GR_CALL(*gr_screen.gf_end_clip_plane)
#define gr_zbias GR_CALL(*gr_screen.gf_zbias)
#define gr_set_fill_mode GR_CALL(*gr_screen.gf_set_fill_mode)
#define gr_set_texture_panning GR_CALL(*gr_screen.gf_set_texture_panning)
#define gr_set_line_width GR_CALL(*gr_screen.gf_set_line_width)
@@ -1105,14 +996,9 @@ inline void gr_post_process_restore_zbuffer() {
#define gr_shadow_map_end GR_CALL(*gr_screen.gf_shadow_map_end)
#define gr_render_shield_impact GR_CALL(*gr_screen.gf_render_shield_impact)
__inline void gr_render_primitives(material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle = -1)
__inline void gr_render_primitives(material* material_info, primitive_type prim_type, vertex_layout* layout, int vert_offset, int n_verts, int buffer_handle = -1, size_t buffer_offset = 0)
{
(*gr_screen.gf_render_primitives)(material_info, prim_type, layout, offset, n_verts, buffer_handle);
}
__inline void gr_render_primitives_immediate(material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, void* data, int size)
{
(*gr_screen.gf_render_primitives_immediate)(material_info, prim_type, layout, n_verts, data, size);
(*gr_screen.gf_render_primitives)(material_info, prim_type, layout, vert_offset, n_verts, buffer_handle, buffer_offset);
}
__inline void gr_render_primitives_particle(particle_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle = -1)
@@ -1120,19 +1006,24 @@ __inline void gr_render_primitives_particle(particle_material* material_info, pr
(*gr_screen.gf_render_primitives_particle)(material_info, prim_type, layout, offset, n_verts, buffer_handle);
}
__inline void gr_render_primitives_batched(batched_bitmap_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle = -1)
{
(*gr_screen.gf_render_primitives_batched)(material_info, prim_type, layout, offset, n_verts, buffer_handle);
}
__inline void gr_render_nanovg(nanovg_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle)
{
(*gr_screen.gf_render_nanovg)(material_info, prim_type, layout, offset, n_verts, buffer_handle);
}
__inline void gr_render_primitives_distortion(distortion_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle = -1)
{
(*gr_screen.gf_render_primitives_distortion)(material_info, prim_type, layout, offset, n_verts, buffer_handle);
}
__inline void gr_render_primitives_2d(material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle = -1)
inline void gr_render_movie(movie_material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, int buffer)
{
(*gr_screen.gf_render_primitives_2d)(material_info, prim_type, layout, offset, n_verts, buffer_handle);
}
__inline void gr_render_primitives_2d_immediate(material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, void* data, int size)
{
(*gr_screen.gf_render_primitives_2d_immediate)(material_info, prim_type, layout, n_verts, data, size);
(*gr_screen.gf_render_movie)(material_info, prim_type, layout, n_verts, buffer);
}
__inline void gr_render_model(model_material* material_info, indexed_vertex_source *vert_source, vertex_buffer* bufferp, size_t texi)
@@ -1145,6 +1036,11 @@ __inline bool gr_is_capable(gr_capability capability)
return (*gr_screen.gf_is_capable)(capability);
}
inline bool gr_get_property(gr_property property, void* destination)
{
return (*gr_screen.gf_get_property)(property, destination);
}
inline void gr_push_debug_group(const char* name)
{
(*gr_screen.gf_push_debug_group)(name);
@@ -1186,6 +1082,23 @@ inline std::unique_ptr<os::Viewport> gr_create_viewport(const os::ViewPortProper
inline void gr_use_viewport(os::Viewport* view) {
(*gr_screen.gf_use_viewport)(view);
}
inline void gr_set_viewport(int x, int y, int width, int height) {
(*gr_screen.gf_set_viewport)(x, y, width, height);
}
inline void gr_bind_uniform_buffer(uniform_block_type bind_point, size_t offset, size_t size, int buffer) {
(*gr_screen.gf_bind_uniform_buffer)(bind_point, offset, size, buffer);
}
inline gr_sync gr_sync_fence() {
return (*gr_screen.gf_sync_fence)();
}
inline bool gr_sync_wait(gr_sync sync, uint64_t timeoutns) {
return (*gr_screen.gf_sync_wait)(sync, timeoutns);
}
inline void gr_sync_delete(gr_sync sync) {
(*gr_screen.gf_sync_delete)(sync);
}
// color functions
void gr_get_color( int *r, int *g, int b );
@@ -1199,17 +1112,17 @@ void gr_create_shader(shader *shade, ubyte r, ubyte g, ubyte b, ubyte c);
void gr_set_shader(shader *shade);
uint gr_determine_model_shader_flags(
bool lighting,
bool fog,
bool textured,
bool in_shadow_map,
bool thruster_scale,
bool lighting,
bool fog,
bool textured,
bool in_shadow_map,
bool thruster_scale,
bool transform,
bool team_color_set,
int tmap_flags,
int spec_map,
int glow_map,
int normal_map,
int tmap_flags,
int spec_map,
int glow_map,
int normal_map,
int height_map,
int ambient_map,
int env_map,
@@ -1231,14 +1144,14 @@ void gr_opengl_update_texture(int bitmap_handle, int bpp, const ubyte* data, int
// Moreover, it is _really_ intended for use with 45 degree angles.
void gr_pline_special(SCP_vector<vec3d> *pts, int thickness,int resize_mode=GR_RESIZE_FULL);
#define VB_FLAG_POSITION (1<<0)
#define VB_FLAG_POSITION (1<<0)
#define VB_FLAG_RHW (1<<1) //incompatable with the next normal
#define VB_FLAG_NORMAL (1<<2)
#define VB_FLAG_DIFUSE (1<<3)
#define VB_FLAG_SPECULAR (1<<4)
#define VB_FLAG_NORMAL (1<<2)
#define VB_FLAG_DIFUSE (1<<3)
#define VB_FLAG_SPECULAR (1<<4)
#define VB_FLAG_UV1 (1<<5) //how many UV coords, only use one of these
#define VB_FLAG_UV2 (1<<6)
#define VB_FLAG_UV3 (1<<7)
#define VB_FLAG_UV2 (1<<6)
#define VB_FLAG_UV3 (1<<7)
#define VB_FLAG_UV4 (1<<8)
#define VB_FLAG_TANGENT (1<<9)
#define VB_FLAG_LARGE_INDEX (1<<10)
@@ -1275,4 +1188,35 @@ class DebugScope {
#define GR_DEBUG_SCOPE(name) do {} while(0)
#endif
enum AnimatedShader {
ANIMATED_SHADER_LOADOUTSELECT_FS1= 0,
ANIMATED_SHADER_LOADOUTSELECT_FS2= 1,
ANIMATED_SHADER_CLOAK = 2,
};
graphics::util::UniformBuffer* gr_get_uniform_buffer(uniform_block_type type);
struct VideoModeData {
uint32_t width = 0;
uint32_t height = 0;
uint32_t bit_depth = 0;
};
struct DisplayData {
uint32_t index;
SCP_string name;
int32_t x = 0;
int32_t y = 0;
int32_t width = 0;
int32_t height = 0;
SCP_vector<VideoModeData> video_modes;
};
SCP_vector<DisplayData> gr_enumerate_displays();
// Include this last to make the 2D rendering function available everywhere
#include "graphics/render.h"
#endif
+18 -5
View File
@@ -226,6 +226,7 @@ int generic_anim_stream(generic_anim *ga, const bool cache)
mprintf(("Failed to load apng: %s\n", e.what() ));
delete ga->png.anim;
ga->png.anim = nullptr;
ga->type = BM_TYPE_NONE;
return -1;
}
nprintf(("apng", "apng read OK (%ix%i@%i) duration (%f)\n", ga->png.anim->w, ga->png.anim->h,
@@ -250,13 +251,19 @@ int generic_anim_stream(generic_anim *ga, const bool cache)
if ( p )
*p = 0;
char frame_name[MAX_FILENAME_LEN];
snprintf(frame_name, MAX_FILENAME_LEN, "%s_0000", ga->filename);
if (snprintf(frame_name, MAX_FILENAME_LEN, "%s_0000", ga->filename) >= MAX_FILENAME_LEN) {
// Make sure the string is null terminated
frame_name[MAX_FILENAME_LEN - 1] = '\0';
}
ga->bitmap_id = bm_load(frame_name);
if(ga->bitmap_id < 0) {
mprintf(("Cannot find first frame for eff streaming. eff Filename: %s", ga->filename));
return -1;
}
snprintf(frame_name, MAX_FILENAME_LEN, "%s_0001", ga->filename);
if (snprintf(frame_name, MAX_FILENAME_LEN, "%s_0001", ga->filename) >= MAX_FILENAME_LEN) {
// Make sure the string is null terminated
frame_name[MAX_FILENAME_LEN - 1] = '\0';
}
ga->eff.next_frame = bm_load(frame_name);
bm_get_info(ga->bitmap_id, &ga->width, &ga->height);
ga->previous_frame = 0;
@@ -322,8 +329,8 @@ void generic_anim_unload(generic_anim *ga)
if(ga->num_frames > 0) {
if(ga->streaming) {
if(ga->type == BM_TYPE_ANI) {
anim_free(ga->ani.animation);
free_anim_instance(ga->ani.instance);
anim_free(ga->ani.animation);
}
if(ga->type == BM_TYPE_EFF) {
if(ga->eff.next_frame >= 0)
@@ -368,7 +375,10 @@ void generic_render_eff_stream(generic_anim *ga)
mprintf(("frame: %d\n", ga->current_frame));
#endif
char frame_name[MAX_FILENAME_LEN];
snprintf(frame_name, MAX_FILENAME_LEN, "%s_%.4d", ga->filename, ga->current_frame);
if (snprintf(frame_name, MAX_FILENAME_LEN, "%s_%.4d", ga->filename, ga->current_frame) >= MAX_FILENAME_LEN) {
// Make sure the string is null terminated
frame_name[MAX_FILENAME_LEN - 1] = '\0';
}
if(bm_reload(ga->eff.next_frame, frame_name) == ga->eff.next_frame)
{
bitmap* next_frame_bmp = bm_lock(ga->eff.next_frame, bpp, (bpp==8)?BMP_AABITMAP:BMP_TEX_NONCOMP, true);
@@ -378,7 +388,10 @@ void generic_render_eff_stream(generic_anim *ga)
bm_unload(ga->eff.next_frame, 0, true);
if (ga->current_frame == ga->num_frames-1)
{
snprintf(frame_name, MAX_FILENAME_LEN, "%s_0001", ga->filename);
if (snprintf(frame_name, MAX_FILENAME_LEN, "%s_0001", ga->filename) >= MAX_FILENAME_LEN) {
// Make sure the string is null terminated
frame_name[MAX_FILENAME_LEN - 1] = '\0';
}
bm_reload(ga->eff.next_frame, frame_name);
}
}
-2
View File
@@ -11,8 +11,6 @@
#include "globalincs/pstypes.h"
#include "graphics/2d.h"
#include "graphics/grbatch.h"
#include "graphics/opengl/gropengldraw.h"
#include "graphics/opengl/gropenglstate.h"
#include "render/3d.h"
geometry_batcher::~geometry_batcher()
-6
View File
@@ -69,10 +69,4 @@ typedef enum gr_zbuffer_type {
ZBUFFER_TYPE_DEFAULT
} gr_zbuffer_type;
typedef enum gr_stencil_type {
STENCIL_TYPE_NONE,
STENCIL_TYPE_READ,
STENCIL_TYPE_WRITE
} gr_stencil_type;
#endif
+30 -200
View File
@@ -23,12 +23,7 @@ uint gr_stub_lock()
return 1;
}
int gr_stub_create_vertex_buffer(bool static_buffer)
{
return -1;
}
int gr_stub_create_index_buffer(bool static_buffer)
int gr_stub_create_buffer(BufferType, BufferUsageHint)
{
return -1;
}
@@ -62,37 +57,10 @@ void gr_set_fill_mode_stub(int mode)
{
}
void gr_stub_aabitmap_ex(int x,int y,int w,int h,int sx,int sy,int resize_mode,bool mirror)
{
}
void gr_stub_aabitmap(int x, int y,int resize_mode, bool mirror)
{
}
void gr_stub_aaline(vertex *v1, vertex *v2)
{
}
void gr_stub_activate(int active)
{
}
void gr_stub_bitmap_ex(int x, int y, int w, int h, int sx, int sy, int resize_mode)
{
}
void gr_stub_bitmap(int x, int y)
{
}
void gr_stub_circle( int xc, int yc, int d, int resize_mode )
{
}
void gr_stub_unfilled_circle( int xc, int yc, int d, int resize_mode )
{
}
void gr_stub_cleanup(int minimize)
{
@@ -102,34 +70,6 @@ void gr_stub_clear()
{
}
void gr_stub_curve(int xc, int yc, int r, int direction, int resize_mode)
{
}
void gr_stub_end_clip_plane()
{
}
void gr_stub_end_instance_matrix()
{
}
void gr_stub_end_projection_matrix()
{
}
void gr_stub_end_view_matrix()
{
}
void gr_stub_flash_alpha(int r, int g, int b, int a)
{
}
void gr_stub_flash(int r, int g, int b)
{
}
void gr_stub_flip()
{
}
@@ -146,22 +86,6 @@ void gr_stub_get_region(int front, int w, int h, ubyte *data)
{
}
void gr_stub_gradient(int x1,int y1,int x2,int y2, int resize_mode)
{
}
void gr_stub_line(int x1,int y1,int x2,int y2, int resize_mode = GR_RESIZE_NONE)
{
}
void gr_stub_pixel(int x, int y, int resize_mode)
{
}
void gr_stub_pop_scale_matrix()
{
}
void gr_stub_pop_texture_matrix(int unit)
{
}
@@ -174,10 +98,6 @@ void gr_stub_print_screen(const char *filename)
{
}
void gr_stub_push_scale_matrix(const vec3d *scale_factor)
{
}
void gr_stub_push_texture_matrix(int unit)
{
}
@@ -190,10 +110,6 @@ void gr_stub_reset_clip()
{
}
void gr_stub_reset_lighting()
{
}
void gr_stub_restore_screen(int id)
{
}
@@ -204,7 +120,10 @@ void gr_stub_save_mouse_area(int x, int y, int w, int h)
void gr_stub_update_buffer_data(int handle, size_t size, void* data)
{
}
void gr_stub_update_buffer_data_offset(int handle, size_t offset, size_t size, void* data)
{
}
void gr_stub_update_transform_buffer(void* data, size_t size)
@@ -212,15 +131,6 @@ void gr_stub_update_transform_buffer(void* data, size_t size)
}
void gr_stub_set_transform_buffer_offset(size_t offset)
{
}
void gr_stub_render_stream_buffer(int buffer_handle, size_t offset, size_t n_verts, int flags)
{
}
void gr_stub_set_clear_color(int r, int g, int b)
{
}
@@ -243,18 +153,6 @@ void gr_stub_set_gamma(float gamma)
{
}
void gr_stub_set_lighting(bool set, bool state)
{
}
void gr_stub_set_light(light *light)
{
}
void gr_stub_set_projection_matrix(float fov, float aspect, float z_near, float z_far)
{
}
void gr_stub_set_tex_env_scale(float scale)
{
}
@@ -263,26 +161,6 @@ void gr_stub_set_texture_addressing(int mode)
{
}
void gr_stub_set_view_matrix(const vec3d *pos, const matrix* orient)
{
}
void gr_stub_start_clip_plane()
{
}
void gr_stub_start_instance_angles(const vec3d *pos, const angles *rotation)
{
}
void gr_stub_start_instance_matrix(const vec3d *offset, const matrix *rotation)
{
}
void gr_stub_string( float sx, float sy, const char *s, int resize_mode = GR_RESIZE_NONE, int length = -1)
{
}
void gr_stub_stuff_fog_coord(vertex *v)
{
}
@@ -321,7 +199,7 @@ int gr_stub_alpha_mask_set(int mode, float alpha)
{
}*/
void gr_stub_post_process_set_effect(const char *name, int x)
void gr_stub_post_process_set_effect(const char *name, int x, const vec3d *rgb)
{
}
@@ -369,14 +247,6 @@ void gr_stub_deferred_lighting_finish()
{
}
void gr_stub_set_ambient_light(int red, int green, int blue)
{
}
void gr_stub_set_texture_panning(float u, float v, bool enable)
{
}
void gr_stub_set_line_width(float width)
{
}
@@ -451,22 +321,7 @@ void gr_stub_render_model(model_material* material_info, indexed_vertex_source *
}
void gr_stub_render_primitives(material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle)
{
}
void gr_stub_render_primitives_immediate(material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, void* data, int size)
{
}
void gr_stub_render_primitives_2d(material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle)
{
}
void gr_stub_render_primitives_2d_immediate(material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, void* data, int size)
void gr_stub_render_primitives(material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle, size_t buffer_offset)
{
}
@@ -479,6 +334,21 @@ void gr_stub_render_primitives_particle(particle_material* material_info, primit
void gr_stub_render_primitives_distortion(distortion_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle)
{
}
void gr_stub_render_movie(movie_material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, int buffer)
{
}
void gr_stub_render_nanovg(nanovg_material* material_info,
primitive_type prim_type,
vertex_layout* layout,
int offset,
int n_verts,
int buffer_handle) {
}
void gr_stub_render_primitives_batched(batched_bitmap_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle)
{
}
bool gr_stub_is_capable(gr_capability capability)
@@ -547,29 +417,12 @@ bool gr_stub_init()
gr_screen.gf_reset_clip = gr_stub_reset_clip;
gr_screen.gf_clear = gr_stub_clear;
// gr_screen.gf_bitmap = gr_stub_bitmap;
gr_screen.gf_bitmap_ex = gr_stub_bitmap_ex;
gr_screen.gf_aabitmap = gr_stub_aabitmap;
gr_screen.gf_aabitmap_ex = gr_stub_aabitmap_ex;
// gr_screen.gf_rect = gr_stub_rect;
// gr_screen.gf_shade = gr_stub_shade;
gr_screen.gf_string = gr_stub_string;
gr_screen.gf_circle = gr_stub_circle;
gr_screen.gf_unfilled_circle = gr_stub_unfilled_circle;
gr_screen.gf_curve = gr_stub_curve;
gr_screen.gf_line = gr_stub_line;
gr_screen.gf_aaline = gr_stub_aaline;
gr_screen.gf_pixel = gr_stub_pixel;
gr_screen.gf_gradient = gr_stub_gradient;
gr_screen.gf_print_screen = gr_stub_print_screen;
gr_screen.gf_flash = gr_stub_flash;
gr_screen.gf_flash_alpha = gr_stub_flash_alpha;
gr_screen.gf_zbuffer_get = gr_stub_zbuffer_get;
gr_screen.gf_zbuffer_set = gr_stub_zbuffer_set;
gr_screen.gf_zbuffer_clear = gr_stub_zbuffer_clear;
@@ -613,25 +466,13 @@ bool gr_stub_init()
gr_screen.gf_set_texture_addressing = gr_stub_set_texture_addressing;
gr_screen.gf_zbias = gr_stub_zbias_stub;
gr_screen.gf_set_fill_mode = gr_set_fill_mode_stub;
gr_screen.gf_set_texture_panning = gr_stub_set_texture_panning;
gr_screen.gf_create_vertex_buffer = gr_stub_create_vertex_buffer;
gr_screen.gf_create_index_buffer = gr_stub_create_index_buffer;
gr_screen.gf_create_buffer = gr_stub_create_buffer;
gr_screen.gf_delete_buffer = gr_stub_delete_buffer;
gr_screen.gf_update_transform_buffer = gr_stub_update_transform_buffer;
gr_screen.gf_update_buffer_data = gr_stub_update_buffer_data;
gr_screen.gf_set_transform_buffer_offset = gr_stub_set_transform_buffer_offset;
gr_screen.gf_render_stream_buffer = gr_stub_render_stream_buffer;
gr_screen.gf_start_instance_matrix = gr_stub_start_instance_matrix;
gr_screen.gf_end_instance_matrix = gr_stub_end_instance_matrix;
gr_screen.gf_start_angles_instance_matrix = gr_stub_start_instance_angles;
gr_screen.gf_set_light = gr_stub_set_light;
gr_screen.gf_reset_lighting = gr_stub_reset_lighting;
gr_screen.gf_set_ambient_light = gr_stub_set_ambient_light;
gr_screen.gf_update_buffer_data_offset = gr_stub_update_buffer_data_offset;
gr_screen.gf_post_process_set_effect = gr_stub_post_process_set_effect;
gr_screen.gf_post_process_set_defaults = gr_stub_post_process_set_defaults;
@@ -649,20 +490,6 @@ bool gr_stub_init()
gr_screen.gf_deferred_lighting_end = gr_stub_deferred_lighting_end;
gr_screen.gf_deferred_lighting_finish = gr_stub_deferred_lighting_finish;
gr_screen.gf_start_clip_plane = gr_stub_start_clip_plane;
gr_screen.gf_end_clip_plane = gr_stub_end_clip_plane;
gr_screen.gf_lighting = gr_stub_set_lighting;
gr_screen.gf_set_proj_matrix = gr_stub_set_projection_matrix;
gr_screen.gf_end_proj_matrix = gr_stub_end_projection_matrix;
gr_screen.gf_set_view_matrix = gr_stub_set_view_matrix;
gr_screen.gf_end_view_matrix = gr_stub_end_view_matrix;
gr_screen.gf_push_scale_matrix = gr_stub_push_scale_matrix;
gr_screen.gf_pop_scale_matrix = gr_stub_pop_scale_matrix;
gr_screen.gf_set_line_width = gr_stub_set_line_width;
gr_screen.gf_sphere = gr_stub_draw_sphere;
@@ -681,13 +508,14 @@ bool gr_stub_init()
gr_screen.gf_render_model = gr_stub_render_model;
gr_screen.gf_render_primitives = gr_stub_render_primitives;
gr_screen.gf_render_primitives_immediate = gr_stub_render_primitives_immediate;
gr_screen.gf_render_primitives_2d = gr_stub_render_primitives_2d;
gr_screen.gf_render_primitives_2d_immediate = gr_stub_render_primitives_2d_immediate;
gr_screen.gf_render_primitives_particle = gr_stub_render_primitives_particle;
gr_screen.gf_render_primitives_distortion = gr_stub_render_primitives_distortion;
gr_screen.gf_render_movie = gr_stub_render_movie;
gr_screen.gf_render_nanovg = gr_stub_render_nanovg;
gr_screen.gf_render_primitives_batched = gr_stub_render_primitives_batched;
gr_screen.gf_is_capable = gr_stub_is_capable;
gr_screen.gf_get_property = [](gr_property,void*) { return false; };
gr_screen.gf_push_debug_group = gr_stub_push_debug_group;
gr_screen.gf_pop_debug_group = gr_stub_pop_debug_group;
@@ -704,5 +532,7 @@ bool gr_stub_init()
gr_screen.gf_use_viewport = [](os::Viewport*) {
};
gr_screen.gf_bind_uniform_buffer = [](uniform_block_type, size_t, size_t, int) {};
return true;
}
+383
View File
@@ -0,0 +1,383 @@
/*
* Copyright (C) Volition, Inc. 1999. All rights reserved.
*
* All source code herein is the property of Volition, Inc. You may not sell
* or otherwise commercially exploit the source or things you created based on the
* source.
*
*/
#include <math/bitarray.h>
#include "cmdline/cmdline.h"
#include "globalincs/pstypes.h"
#include "graphics/2d.h"
#include "light.h"
#include "matrix.h"
#include "render/3d.h"
// Structures
struct gr_light
{
vec4 Ambient;
vec4 Diffuse;
vec4 Specular;
// light position
vec4 Position;
// spotlight direction (for tube lights)
vec3d SpotDir;
float SpotExp, SpotCutOff;
float ConstantAtten, LinearAtten, QuadraticAtten;
bool occupied;
int type;
};
// Variables
gr_light* gr_lights = NULL;
graphics::model_light gr_light_uniforms[graphics::MAX_UNIFORM_LIGHTS];
int Num_active_gr_lights = 0;
// OGL defaults
const float gr_light_color[4] = { 0.8f, 0.8f, 0.8f, 1.0f };
const float gr_light_zero[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
const float gr_light_emission[4] = { 0.09f, 0.09f, 0.09f, 1.0f };
float gr_light_ambient[4] = { 0.47f, 0.47f, 0.47f, 1.0f };
void FSLight2GLLight(light* FSLight, gr_light* GLLight) {
GLLight->Ambient.xyzw.x = 0.0f;
GLLight->Ambient.xyzw.y = 0.0f;
GLLight->Ambient.xyzw.z = 0.0f;
GLLight->Ambient.xyzw.w = 1.0f;
GLLight->Diffuse.xyzw.x = FSLight->r * FSLight->intensity;
GLLight->Diffuse.xyzw.y = FSLight->g * FSLight->intensity;
GLLight->Diffuse.xyzw.z = FSLight->b * FSLight->intensity;
GLLight->Diffuse.xyzw.w = 1.0f;
GLLight->Specular.xyzw.x = FSLight->spec_r * FSLight->intensity;
GLLight->Specular.xyzw.y = FSLight->spec_g * FSLight->intensity;
GLLight->Specular.xyzw.z = FSLight->spec_b * FSLight->intensity;
GLLight->Specular.xyzw.w = 1.0f;
GLLight->type = FSLight->type;
// GL default values...
// spot direction
GLLight->SpotDir.xyz.x = 0.0f;
GLLight->SpotDir.xyz.y = 0.0f;
GLLight->SpotDir.xyz.z = -1.0f;
// spot exponent
GLLight->SpotExp = Cmdline_ogl_spec * 0.5f;
// spot cutoff
GLLight->SpotCutOff = 180.0f; // special value, light in all directions
// defaults to disable attenuation
GLLight->ConstantAtten = 1.0f;
GLLight->LinearAtten = 0.0f;
GLLight->QuadraticAtten = 0.0f;
// position
GLLight->Position.xyzw.x = FSLight->vec.xyz.x;
GLLight->Position.xyzw.y = FSLight->vec.xyz.y;
GLLight->Position.xyzw.z = FSLight->vec.xyz.z; // flipped axis for FS2
GLLight->Position.xyzw.w = 1.0f;
switch (FSLight->type) {
case LT_POINT: {
// this crap still needs work...
GLLight->ConstantAtten = 1.0f;
GLLight->LinearAtten = (1.0f / MAX(FSLight->rada, FSLight->radb)) * 1.25f;
GLLight->Specular.xyzw.x *= static_point_factor;
GLLight->Specular.xyzw.y *= static_point_factor;
GLLight->Specular.xyzw.z *= static_point_factor;
break;
}
case LT_TUBE: {
GLLight->ConstantAtten = 1.0f;
GLLight->LinearAtten = (1.0f / MAX(FSLight->rada, FSLight->radb)) * 1.25f;
GLLight->QuadraticAtten = (1.0f / MAX(FSLight->rada_squared, FSLight->radb_squared)) * 1.25f;
GLLight->Specular.xyzw.x *= static_tube_factor;
GLLight->Specular.xyzw.y *= static_tube_factor;
GLLight->Specular.xyzw.z *= static_tube_factor;
GLLight->Position.xyzw.x = FSLight->vec2.xyz.x; // Valathil: Use endpoint of tube as light position
GLLight->Position.xyzw.y = FSLight->vec2.xyz.y;
GLLight->Position.xyzw.z = FSLight->vec2.xyz.z;
GLLight->Position.xyzw.w = 1.0f;
// Valathil: When using shaders pass the beam direction (not normalized IMPORTANT for calculation of tube)
vec3d a;
vm_vec_sub(&a, &FSLight->vec2, &FSLight->vec);
GLLight->SpotDir.xyz.x = a.xyz.x;
GLLight->SpotDir.xyz.y = a.xyz.y;
GLLight->SpotDir.xyz.z = a.xyz.z;
GLLight->SpotCutOff = 90.0f; // Valathil: So shader dectects tube light
break;
}
case LT_DIRECTIONAL: {
GLLight->Position.xyzw.x = -FSLight->vec.xyz.x;
GLLight->Position.xyzw.y = -FSLight->vec.xyz.y;
GLLight->Position.xyzw.z = -FSLight->vec.xyz.z;
GLLight->Position.xyzw.w = 0.0f; // This is a direction so the w part must be 0
GLLight->Specular.xyzw.x *= static_light_factor;
GLLight->Specular.xyzw.y *= static_light_factor;
GLLight->Specular.xyzw.z *= static_light_factor;
break;
}
case LT_CONE:
break;
default:
Int3();
break;
}
}
static void set_light(int light_num, gr_light* ltp) {
Assert(light_num < (int)graphics::MAX_UNIFORM_LIGHTS);
vm_vec_transform(&gr_light_uniforms[light_num].position, &ltp->Position, &gr_view_matrix);
vm_vec_transform(&gr_light_uniforms[light_num].direction, &ltp->SpotDir, &gr_view_matrix, false);
gr_light_uniforms[light_num].diffuse_color = vm_vec4_to_vec3(ltp->Diffuse);
gr_light_uniforms[light_num].spec_color = vm_vec4_to_vec3(ltp->Specular);
gr_light_uniforms[light_num].light_type = ltp->type;
gr_light_uniforms[light_num].attenuation = ltp->LinearAtten;
}
static bool sort_active_lights(const gr_light& la, const gr_light& lb) {
// directional lights always go first
if ((la.type != LT_DIRECTIONAL) && (lb.type == LT_DIRECTIONAL)) {
return false;
} else if ((la.type == LT_DIRECTIONAL) && (lb.type != LT_DIRECTIONAL)) {
return true;
}
// tube lights go next, they are generally large and intense
if ((la.type != LT_TUBE) && (lb.type == LT_TUBE)) {
return false;
} else if ((la.type == LT_TUBE) && (lb.type != LT_TUBE)) {
return true;
}
// everything else is sorted by linear atten (light size)
// NOTE: smaller atten is larger light radius!
if (la.LinearAtten > lb.LinearAtten) {
return false;
} else if (la.LinearAtten < lb.LinearAtten) {
return true;
}
// as one extra check, if we're still here, go with overall brightness of light
float la_value = la.Diffuse.xyzw.x + la.Diffuse.xyzw.y + la.Diffuse.xyzw.z;
float lb_value = lb.Diffuse.xyzw.x + lb.Diffuse.xyzw.y + lb.Diffuse.xyzw.z;
if (la_value < lb_value) {
return false;
} else if (la_value > lb_value) {
return true;
}
// the two are equal
return false;
}
static void pre_render_init_lights() {
// sort the lights to try and get the most visible lights on the first pass
std::sort(gr_lights, gr_lights + Num_active_gr_lights, sort_active_lights);
}
void gr_set_light(light* fs_light) {
if (Num_active_gr_lights >= MAX_LIGHTS) {
return;
}
//if (fs_light->type == LT_POINT)
// return;
// init the light
FSLight2GLLight(fs_light, &gr_lights[Num_active_gr_lights]);
gr_lights[Num_active_gr_lights++].occupied = true;
}
void gr_set_center_alpha(int type) {
if (!type) {
return;
}
if (Num_active_gr_lights == MAX_LIGHTS) {
return;
}
gr_light glight;
vec3d dir;
vm_vec_sub(&dir, &Eye_position, &Object_position);
vm_vec_normalize(&dir);
if (type == 1) {
glight.Diffuse.xyzw.x = 0.0f;
glight.Diffuse.xyzw.y = 0.0f;
glight.Diffuse.xyzw.z = 0.0f;
glight.Ambient.xyzw.x = gr_screen.current_alpha;
glight.Ambient.xyzw.y = gr_screen.current_alpha;
glight.Ambient.xyzw.z = gr_screen.current_alpha;
} else {
glight.Diffuse.xyzw.x = gr_screen.current_alpha;
glight.Diffuse.xyzw.y = gr_screen.current_alpha;
glight.Diffuse.xyzw.z = gr_screen.current_alpha;
glight.Ambient.xyzw.x = 0.0f;
glight.Ambient.xyzw.y = 0.0f;
glight.Ambient.xyzw.z = 0.0f;
}
glight.type = type;
glight.Specular.xyzw.x = 0.0f;
glight.Specular.xyzw.y = 0.0f;
glight.Specular.xyzw.z = 0.0f;
glight.Specular.xyzw.w = 0.0f;
glight.Ambient.xyzw.w = 1.0f;
glight.Diffuse.xyzw.w = 1.0f;
glight.Position.xyzw.x = -dir.xyz.x;
glight.Position.xyzw.y = -dir.xyz.y;
glight.Position.xyzw.z = -dir.xyz.z;
glight.Position.xyzw.w = 0.0f;
// defaults
glight.SpotDir.xyz.x = 0.0f;
glight.SpotDir.xyz.y = 0.0f;
glight.SpotDir.xyz.z = -1.0f;
glight.SpotExp = Cmdline_ogl_spec * 0.5f;
glight.SpotCutOff = 180.0f;
glight.ConstantAtten = 1.0f;
glight.LinearAtten = 0.0f;
glight.QuadraticAtten = 0.0f;
glight.occupied = false;
// first light
memcpy(&gr_lights[Num_active_gr_lights], &glight, sizeof(gr_light));
gr_lights[Num_active_gr_lights++].occupied = true;
// second light
glight.Position.xyzw.x = dir.xyz.x;
glight.Position.xyzw.y = dir.xyz.y;
glight.Position.xyzw.z = dir.xyz.z;
memcpy(&gr_lights[Num_active_gr_lights], &glight, sizeof(gr_light));
gr_lights[Num_active_gr_lights++].occupied = true;
}
void gr_reset_lighting() {
int i;
for (i = 0; i < (int)graphics::MAX_UNIFORM_LIGHTS; i++) {
gr_lights[i].occupied = false;
}
Num_active_gr_lights = 0;
}
static void calculate_ambient_factor() {
float amb_user = 0.0f;
// assuming that the default is "128", just skip this if not a user setting
if (Cmdline_ambient_factor == 128) {
return;
}
amb_user = (float) ((Cmdline_ambient_factor * 2) - 255) / 255.0f;
// set the ambient light
gr_light_ambient[0] += amb_user;
gr_light_ambient[1] += amb_user;
gr_light_ambient[2] += amb_user;
CLAMP(gr_light_ambient[0], 0.02f, 1.0f);
CLAMP(gr_light_ambient[1], 0.02f, 1.0f);
CLAMP(gr_light_ambient[2], 0.02f, 1.0f);
gr_light_ambient[3] = 1.0f;
}
void gr_light_shutdown() {
if (gr_lights != NULL) {
vm_free(gr_lights);
gr_lights = NULL;
}
}
void gr_light_init() {
calculate_ambient_factor();
// allocate memory for enabled lights
if (gr_lights == NULL) {
gr_lights = (gr_light*) vm_malloc(MAX_LIGHTS * sizeof(gr_light), memory::quiet_alloc);
}
if (gr_lights == NULL) {
Error(LOCATION, "Unable to allocate memory for lights!\n");
}
memset(gr_lights, 0, MAX_LIGHTS * sizeof(gr_light));
}
void gr_set_lighting(bool set, bool state) {
if (!state) {
return;
}
//Valathil: Sort lights by priority
extern bool Deferred_lighting;
if (!Deferred_lighting) {
pre_render_init_lights();
}
int i = 0;
for (i = 0; i < (int)graphics::MAX_UNIFORM_LIGHTS; i++) {
if (i >= Num_active_gr_lights) {
break;
}
if (gr_lights[i].occupied) {
set_light(i, &gr_lights[i]);
}
}
gr_light zero;
memset(&zero, 0, sizeof(gr_light));
zero.Position.xyzw.x = 1.0f;
// make sure that we turn off any lights that we aren't using right now
for (; i < (int)graphics::MAX_UNIFORM_LIGHTS; i++) {
set_light(i, &zero);
}
}
void gr_set_ambient_light(int red, int green, int blue) {
gr_light_ambient[0] = i2fl(red) / 255.0f;
gr_light_ambient[1] = i2fl(green) / 255.0f;
gr_light_ambient[2] = i2fl(blue) / 255.0f;
gr_light_ambient[3] = 1.0f;
calculate_ambient_factor();
}
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include "globalincs/pstypes.h"
#include "lighting/lighting.h"
#include "graphics/util/uniform_structs.h"
//Variables
extern graphics::model_light gr_light_uniforms[graphics::MAX_UNIFORM_LIGHTS];
//Variables
extern int Num_active_gr_lights;
extern const float gr_light_color[4];
extern const float gr_light_zero[4];
extern const float gr_light_emission[4];
extern float gr_light_ambient[4];
//Functions
void gr_set_light(light *fs_light);
void gr_reset_lighting();
void gr_set_lighting(bool set, bool state);
void gr_set_center_alpha(int type);
void gr_set_ambient_light(int red, int green, int blue);
void gr_light_init();
void gr_light_shutdown();
Loaded 100 of 406 files, more files were not shown because too many files have changed in this diff. Show more