mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-08 07:28:22 -10:00
Compare commits
217
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b01036723 | ||
|
|
8a2641181f | ||
|
|
36e8c3b623 | ||
|
|
1c2a136ef7 | ||
|
|
72272cb8cf | ||
|
|
4062f59128 | ||
|
|
24ab091671 | ||
|
|
7cd17205b5 | ||
|
|
d58bd7db69 | ||
|
|
ce11936e56 | ||
|
|
feda97c148 | ||
|
|
a0e85e7ef5 | ||
|
|
6939403262 | ||
|
|
33e8703555 | ||
|
|
8a87d20415 | ||
|
|
b324d2892c | ||
|
|
54bd7e3963 | ||
|
|
b2230f723b | ||
|
|
f75dafde4a | ||
|
|
d70f92e782 | ||
|
|
d7e042b38a | ||
|
|
941a0c3c8a | ||
|
|
edc6b94f7f | ||
|
|
1182a485ac | ||
|
|
3cd2c40331 | ||
|
|
c13cb44df4 | ||
|
|
aede65107b | ||
|
|
197767ce94 | ||
|
|
7924c66d37 | ||
|
|
3106191cea | ||
|
|
8c4ec9b91c | ||
|
|
5bfcd1d063 | ||
|
|
923265988c | ||
|
|
c485ed8199 | ||
|
|
4353d4d47f | ||
|
|
da65a66932 | ||
|
|
7df8313b8b | ||
|
|
187affe004 | ||
|
|
f29cc2ef86 | ||
|
|
97e15ca135 | ||
|
|
868418c100 | ||
|
|
e413b10ce1 | ||
|
|
bdd740eabd | ||
|
|
d24e3c9295 | ||
|
|
13be144495 | ||
|
|
8857c4561a | ||
|
|
af4a2555db | ||
|
|
ae2c4ef098 | ||
|
|
6e509868d2 | ||
|
|
d0bc3cf91d | ||
|
|
10079c88cd | ||
|
|
3aacb6cb42 | ||
|
|
b434776d53 | ||
|
|
20925f23cc | ||
|
|
64a9e3d03a | ||
|
|
fe01372f46 | ||
|
|
7134e22322 | ||
|
|
fac618c7f0 | ||
|
|
b333104f45 | ||
|
|
c0401c24e5 | ||
|
|
2ded9aa35d | ||
|
|
ad54f588bb | ||
|
|
a64ebca805 | ||
|
|
69781cec25 | ||
|
|
137457e570 | ||
|
|
b7f3ba3660 | ||
|
|
bf6cfe61d7 | ||
|
|
990838051a | ||
|
|
597104c479 | ||
|
|
2ee5d21a10 | ||
|
|
8c1d3492eb | ||
|
|
ba5fcb971a | ||
|
|
5359b12b4f | ||
|
|
0fb7345617 | ||
|
|
a34ca578ba | ||
|
|
7f03ac31ae | ||
|
|
25b396f6a0 | ||
|
|
c6e2f94d0b | ||
|
|
9de8d45f19 | ||
|
|
7f5168e9d6 | ||
|
|
490c5d8357 | ||
|
|
011ca4bb85 | ||
|
|
a4f499ce8c | ||
|
|
5578588894 | ||
|
|
dbee42bdec | ||
|
|
783e4b5ab2 | ||
|
|
cea27244dc | ||
|
|
09084395a5 | ||
|
|
886b14e595 | ||
|
|
2fca5fd965 | ||
|
|
69cb4f0136 | ||
|
|
76d36b1c5f | ||
|
|
bf37a36e89 | ||
|
|
6750f0a4cc | ||
|
|
06a21a0f9b | ||
|
|
3d653bd770 | ||
|
|
db3d92732f | ||
|
|
4fbc0d02fa | ||
|
|
c6f75e7d14 | ||
|
|
8f4d2a27db | ||
|
|
c4bb136d80 | ||
|
|
ea2656e75f | ||
|
|
d70672d7bc | ||
|
|
ccc727a148 | ||
|
|
87ac2ca6a3 | ||
|
|
e8bd6b3929 | ||
|
|
4e7756d29f | ||
|
|
fd96dd287d | ||
|
|
dea5fd9f30 | ||
|
|
5ebf48b9b0 | ||
|
|
2dc2c0643f | ||
|
|
e761d8a8e9 | ||
|
|
36b97487c6 | ||
|
|
367825b1e0 | ||
|
|
8f5a364345 | ||
|
|
07a15286b4 | ||
|
|
8e4deb0454 | ||
|
|
aed44067df | ||
|
|
83844222c4 | ||
|
|
ba5233e33b | ||
|
|
b0bb660eb2 | ||
|
|
74f258a9b3 | ||
|
|
d7d3b8c8e2 | ||
|
|
90aeb3651c | ||
|
|
6ee7679dd6 | ||
|
|
5baae08bdf | ||
|
|
646fb64c2f | ||
|
|
7544f321d6 | ||
|
|
b2ff79fb38 | ||
|
|
94c1cf65b3 | ||
|
|
0ce2908ce6 | ||
|
|
32fbe572e4 | ||
|
|
fb0ff8f1d0 | ||
|
|
2cef1d4aa1 | ||
|
|
9dfb8faea3 | ||
|
|
9651e7dca6 | ||
|
|
51557d3aa3 | ||
|
|
521a9b9461 | ||
|
|
130057c64a | ||
|
|
f63e18957b | ||
|
|
df0be20d22 | ||
|
|
cee37e7a2f | ||
|
|
90e16ffed2 | ||
|
|
c2a52174ba | ||
|
|
e389f7669d | ||
|
|
20681f1550 | ||
|
|
be8ea029da | ||
|
|
3dbcebb56e | ||
|
|
37453ae229 | ||
|
|
9d907c99fe | ||
|
|
490ef52b85 | ||
|
|
cf1cc5e862 | ||
|
|
fc0105141b | ||
|
|
9878b48dd3 | ||
|
|
af99fee8fc | ||
|
|
1cc09d5b8b | ||
|
|
d5c5cc6eb3 | ||
|
|
b5bb5097b9 | ||
|
|
f87e5bf318 | ||
|
|
48667f0cbd | ||
|
|
66637ef5cb | ||
|
|
3b2b58e2cc | ||
|
|
d5282ca697 | ||
|
|
6a099d2adc | ||
|
|
6aa1f4899f | ||
|
|
4ec7d21965 | ||
|
|
bd5a4c4348 | ||
|
|
9135a01b1d | ||
|
|
032579923e | ||
|
|
8c1e753991 | ||
|
|
6a4c74084e | ||
|
|
3799ce7d2f | ||
|
|
2e213d5c97 | ||
|
|
0c17177a1e | ||
|
|
93ced64c6f | ||
|
|
4020b7c594 | ||
|
|
13b26fd59f | ||
|
|
15bda8c4ac | ||
|
|
39ab45dc7c | ||
|
|
16a19783ae | ||
|
|
b1bc4ef44f | ||
|
|
08e664a93a | ||
|
|
aeee05c8dd | ||
|
|
1fb3a65a90 | ||
|
|
d53dc195ee | ||
|
|
5b8880daa7 | ||
|
|
b0fc9cb31a | ||
|
|
323354295f | ||
|
|
b1881a700d | ||
|
|
357cd76252 | ||
|
|
30e70db561 | ||
|
|
2c106f8c4b | ||
|
|
73bfb7a97e | ||
|
|
4bead819f9 | ||
|
|
268828f092 | ||
|
|
1614384a6a | ||
|
|
29b6af84cc | ||
|
|
cafee143c4 | ||
|
|
6e21c8a736 | ||
|
|
bb56958dfc | ||
|
|
120750ebd2 | ||
|
|
3430a1c438 | ||
|
|
1dc2e848cd | ||
|
|
305429bf8b | ||
|
|
ae149b6061 | ||
|
|
429858d02e | ||
|
|
1448277c29 | ||
|
|
61c533559b | ||
|
|
e92121bed4 | ||
|
|
f7b0f93c00 | ||
|
|
758ca86f6f | ||
|
|
6406e2fbd4 | ||
|
|
18c2dbbde9 | ||
|
|
ef6c5d4da7 | ||
|
|
cb960a3416 | ||
|
|
194d944108 | ||
|
|
9ac97f2422 |
No files matched your search
@@ -0,0 +1,99 @@
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: true
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlinesLeft: false
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 120
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
|
||||
IncludeCategories:
|
||||
- Regex: '^(<.*\.(h|hh|hpp)>)$' # Includes of external libraries
|
||||
Priority: 4
|
||||
- Regex: '^(<.*>)$' # standard library includes (won't match deprecated C headers)
|
||||
Priority: 5
|
||||
- Regex: '^"[^/]*\.(h)"$' # Local includes
|
||||
Priority: 1
|
||||
- Regex: '^".*\.(h)"$' # standard engine includes
|
||||
Priority: 2
|
||||
- Regex: '.*' # Catch all in case something is unhandled above
|
||||
Priority: 3
|
||||
IncludeIsMainRegex: '$'
|
||||
IndentCaseLabels: false
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Left
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
TabWidth: 4
|
||||
UseTab: ForIndentation
|
||||
...
|
||||
|
||||
@@ -3,6 +3,7 @@ Checks: "-*,\
|
||||
modernize-*,\
|
||||
-modernize-raw-string-literal,\
|
||||
-modernize-use-using,\
|
||||
-modernize-make-unique,\
|
||||
performance-*,\
|
||||
-performance-type-promotion-in-math-fn,\
|
||||
misc-*,\
|
||||
|
||||
+4
-4
@@ -76,14 +76,14 @@ matrix:
|
||||
- *global_deps
|
||||
- g++-5
|
||||
- os: linux
|
||||
env: CONFIGURATION="Debug" CC=gcc-7 CXX=g++-7
|
||||
env: CONFIGURATION="Debug" CC=gcc-8 CXX=g++-8
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-trusty'
|
||||
packages:
|
||||
- g++-7
|
||||
- g++-8
|
||||
- *global_deps
|
||||
- os: linux
|
||||
env: CONFIGURATION="Debug" CC=clang-4.0 CXX=clang++-4.0 CMAKE_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
|
||||
@@ -115,14 +115,14 @@ matrix:
|
||||
- *global_deps
|
||||
- g++-5
|
||||
- os: linux
|
||||
env: CONFIGURATION="Release" CC=gcc-7 CXX=g++-7
|
||||
env: CONFIGURATION="Release" CC=gcc-8 CXX=g++-8
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt571-trusty'
|
||||
packages:
|
||||
- g++-7
|
||||
- g++-8
|
||||
- *global_deps
|
||||
- os: linux
|
||||
env: CONFIGURATION="Release" CC=clang-4.0 CXX=clang++-4.0
|
||||
|
||||
+7
-2
@@ -7,8 +7,13 @@ cd build
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
ninja -k 20 all
|
||||
|
||||
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
|
||||
--suppressions="$TRAVIS_BUILD_DIR/ci/travis/valgrind.supp" ./bin/unittests --gtest_shuffle
|
||||
|
||||
if [ "$CONFIGURATION" = "Debug" ]; then
|
||||
valgrind --leak-check=full --error-exitcode=1 --gen-suppressions=all \
|
||||
--suppressions="$TRAVIS_BUILD_DIR/ci/travis/valgrind.supp" ./bin/unittests --gtest_shuffle
|
||||
else
|
||||
./bin/unittests --gtest_shuffle
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
cmake --build . --config "$CONFIGURATION" | tee build.log | xcpretty
|
||||
XCODE_RET=${PIPESTATUS[0]}
|
||||
|
||||
@@ -25,4 +25,12 @@
|
||||
fun:_dl_init
|
||||
fun:dl_open_worker
|
||||
fun:_dl_catch_error
|
||||
}
|
||||
}
|
||||
{
|
||||
CLang Lua unitialized value error
|
||||
Memcheck:Cond
|
||||
...
|
||||
fun:luaH_get
|
||||
fun:lua_rawget
|
||||
fun:_ZN12_GLOBAL__N_117ade_index_handlerEP9lua_State
|
||||
}
|
||||
@@ -85,6 +85,17 @@ set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wreturn-type")
|
||||
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-deprecated -Wno-char-subscripts")
|
||||
|
||||
# These two warnings cause a lot of false-positives in the FSO code base
|
||||
check_cxx_compiler_flag(-Wstringop-truncation SUPPORTS_STRINGOP_TRUNCATION)
|
||||
if(SUPPORTS_STRINGOP_TRUNCATION)
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-stringop-truncation")
|
||||
endif()
|
||||
|
||||
check_cxx_compiler_flag(-Wstringop-overflow SUPPORTS_STRINGOP_OVERFLOW)
|
||||
if(SUPPORTS_STRINGOP_TRUNCATION)
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Wno-stringop-overflow")
|
||||
endif()
|
||||
|
||||
set(COMPILER_FLAGS_RELEASE "-O2 -Wno-unused-variable -Wno-unused-but-set-variable -Wno-array-bounds -Wno-empty-body -Wno-clobbered -Wno-unused-parameter")
|
||||
|
||||
set(COMPILER_FLAGS_DEBUG "-O0 -g -Wshadow")
|
||||
|
||||
@@ -225,3 +225,13 @@ function(list_target_dependencies _target _out_var)
|
||||
list(REMOVE_DUPLICATES out_list)
|
||||
set(${_out_var} ${out_list} PARENT_SCOPE)
|
||||
endfunction(list_target_dependencies)
|
||||
|
||||
macro(add_file_folder FOLDER_NAME)
|
||||
string(MAKE_C_IDENTIFIER "${FOLDER_NAME}" VARIABLE_NAME)
|
||||
set(files_${VARIABLE_NAME} ${files_${VARIABLE_NAME}} ${ARGN})
|
||||
|
||||
string(REPLACE "/" "\\" FIXED_FOLDER_FILE "${FOLDER_NAME}")
|
||||
|
||||
source_group("${FIXED_FOLDER_FILE}" FILES ${ARGN})
|
||||
set(source_files ${source_files} ${ARGN})
|
||||
endmacro(add_file_folder)
|
||||
+3
-1
@@ -3,7 +3,7 @@ INCLUDE(source_groups.cmake)
|
||||
|
||||
INCLUDE(voice_rec.cmake)
|
||||
|
||||
ADD_LIBRARY(code STATIC ${file_root} ${VOICE_REC_FILES})
|
||||
ADD_LIBRARY(code STATIC ${source_files} ${VOICE_REC_FILES})
|
||||
|
||||
target_compile_features(code PUBLIC ${REQUIRED_CXX_FEATURES})
|
||||
|
||||
@@ -37,6 +37,8 @@ TARGET_LINK_LIBRARIES(code PUBLIC compiler)
|
||||
|
||||
target_link_libraries(code PUBLIC md5)
|
||||
|
||||
target_link_libraries(code PUBLIC discord-rpc)
|
||||
|
||||
enable_clang_tidy(code)
|
||||
|
||||
IF (FSO_USE_SPEECH)
|
||||
|
||||
+4
-4
@@ -567,9 +567,9 @@ extern void ai_dock_with_object(object *docker, int docker_index, object *dockee
|
||||
extern void ai_stay_still(object *still_objp, vec3d *view_pos);
|
||||
extern void ai_do_default_behavior(object *obj);
|
||||
extern void ai_start_waypoints(object *objp, waypoint_list *wp_list, int wp_flags);
|
||||
extern void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hitpos, int shield_quadrant, vec3d *hit_normal);
|
||||
extern void ai_ship_destroy(int shipnum, Ship::Exit_Flags method);
|
||||
extern void ai_turn_towards_vector(vec3d *dest, object *objp, float frametime, float turn_time, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec = NULL, int sexp_flags = 0);
|
||||
extern void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal);
|
||||
extern void ai_ship_destroy(int shipnum);
|
||||
extern void ai_turn_towards_vector(vec3d *dest, object *objp, float turn_time, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec = nullptr, int sexp_flags = 0);
|
||||
extern void init_ai_object(int objnum);
|
||||
extern void ai_init(void); // Call this one to parse ai.tbl.
|
||||
extern void ai_level_init(void); // Call before each level to reset AI
|
||||
@@ -622,7 +622,7 @@ extern float ai_path();
|
||||
extern void evade_weapon();
|
||||
extern int might_collide_with_ship(object *obj1, object *obj2, float dot_to_enemy, float dist_to_enemy, float duration);
|
||||
extern int ai_fire_primary_weapon(object *objp); //changed to return weather it fired-Bobboau
|
||||
extern int ai_fire_secondary_weapon(object *objp, int priority1 = -1, int priority2 = -1);
|
||||
extern int ai_fire_secondary_weapon(object *objp);
|
||||
extern float ai_get_weapon_dist(ship_weapon *swp);
|
||||
extern void turn_towards_point(object *objp, vec3d *point, vec3d *slide_vec, float bank_override);
|
||||
extern int ai_maybe_fire_afterburner(object *objp, ai_info *aip);
|
||||
|
||||
@@ -110,6 +110,7 @@ namespace AI {
|
||||
Smart_subsystem_targeting_for_turrets,
|
||||
Strict_turred_tagged_only_targeting,
|
||||
Turrets_ignore_target_radius,
|
||||
Use_actual_primary_range,
|
||||
Use_additive_weapon_velocity,
|
||||
Use_newtonian_dampening,
|
||||
Use_only_single_fov_for_turrets,
|
||||
|
||||
@@ -458,6 +458,8 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
set_flag(profile, "$ai can slow down when attacking big ships:", AI::Profile_Flags::Ai_can_slow_down_attacking_big_ships);
|
||||
|
||||
set_flag(profile, "$use actual primary range:", AI::Profile_Flags::Use_actual_primary_range);
|
||||
|
||||
profile->bay_arrive_speed_mult = 1.0f;
|
||||
profile->bay_depart_speed_mult = 1.0f;
|
||||
if (optional_string("$bay arrive speed multiplier:")) {
|
||||
|
||||
+18
-24
@@ -64,10 +64,11 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
|
||||
void ai_big_avoid_ship();
|
||||
int ai_big_maybe_follow_subsys_path(int do_dot_check=1);
|
||||
void ai_big_strafe_position();
|
||||
static int ai_big_strafe_maybe_retreat(const vec3d *target_pos);
|
||||
|
||||
extern int model_which_octant_distant_many( vec3d *pnt, int model_num,matrix *model_orient, vec3d * model_pos, polymodel **pm, int *octs);
|
||||
extern void compute_desired_rvec(vec3d *rvec, vec3d *goal_pos, vec3d *cur_pos);
|
||||
extern void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collide_pos, vec3d *collision_normal);
|
||||
extern void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collision_normal);
|
||||
|
||||
|
||||
// Called by ai_big_pick_attack_point.
|
||||
@@ -631,7 +632,7 @@ void ai_big_chase_attack(ai_info *aip, ship_info *sip, vec3d *enemy_pos, float d
|
||||
else
|
||||
rvec = NULL;
|
||||
|
||||
ai_turn_towards_vector(enemy_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, rel_pos, 0.0f, 0, rvec);
|
||||
ai_turn_towards_vector(enemy_pos, Pl_objp, sip->srotation_time, nullptr, rel_pos, 0.0f, 0, rvec);
|
||||
|
||||
// calc range of primary weapon
|
||||
weapon_travel_dist = ai_get_weapon_dist(&Ships[Pl_objp->instance].weapons);
|
||||
@@ -707,14 +708,14 @@ extern float set_secondary_fire_delay(ai_info *aip, ship *shipp, weapon_info *sw
|
||||
extern void ai_choose_secondary_weapon(object *objp, ai_info *aip, object *en_objp);
|
||||
extern int maybe_avoid_big_ship(object *objp, object *ignore_objp, ai_info *aip, vec3d *goal_point, float delta_time);
|
||||
|
||||
extern void maybe_cheat_fire_synaptic(object *objp, ai_info *aip);
|
||||
extern void maybe_cheat_fire_synaptic(object *objp);
|
||||
|
||||
// Determine if Pl_objp should fire weapons at current target, based on input parameters
|
||||
//
|
||||
// dist_to_enemy => distance (in m) to attack point on current target
|
||||
// dot_to_enemy => dot product between fvec of Pl_objp and vector from Pl_objp to attack point
|
||||
//
|
||||
void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy, vec3d * /*firing_pos*/, vec3d * /*enemy_pos*/, vec3d * /*enemy_vel*/)
|
||||
static void ai_big_maybe_fire_weapons(float dist_to_enemy, float dot_to_enemy)
|
||||
{
|
||||
ai_info *aip;
|
||||
ship_weapon *swp;
|
||||
@@ -845,8 +846,6 @@ void ai_big_switch_to_chase_mode(ai_info *aip)
|
||||
aip->submode_start_time = Missiontime;
|
||||
}
|
||||
|
||||
extern int ai_big_strafe_maybe_retreat(float dist, vec3d *target_pos);
|
||||
|
||||
// Make object Pl_objp chase object En_objp, which is a big ship, not a small ship.
|
||||
void ai_big_chase()
|
||||
{
|
||||
@@ -859,7 +858,7 @@ void ai_big_chase()
|
||||
|
||||
Assert(aip->mode == AIM_CHASE);
|
||||
|
||||
maybe_cheat_fire_synaptic(Pl_objp, aip);
|
||||
maybe_cheat_fire_synaptic(Pl_objp);
|
||||
|
||||
ai_set_positions(Pl_objp, En_objp, aip, &player_pos, &enemy_pos);
|
||||
|
||||
@@ -882,7 +881,7 @@ void ai_big_chase()
|
||||
dot_to_enemy = vm_vec_dot(&vec_to_enemy, &Pl_objp->orient.vec.fvec);
|
||||
|
||||
if (aip->ai_flags[AI::AI_Flags::Target_collision]) {
|
||||
if ( ai_big_strafe_maybe_retreat(dist_to_enemy, &enemy_pos) ) {
|
||||
if ( ai_big_strafe_maybe_retreat(&enemy_pos) ) {
|
||||
aip->mode = AIM_STRAFE;
|
||||
aip->submode_parm0 = Missiontime; // use parm0 as time strafe mode entered (i.e. MODE start time)
|
||||
aip->submode = AIS_STRAFE_AVOID;
|
||||
@@ -1045,7 +1044,7 @@ void ai_big_chase()
|
||||
if ((dist_normal_to_enemy < ATTACK_COLLIDE_AVOID_DIST + speed_dist) || (time_to_enemy < ATTACK_COLLIDE_AVOID_TIME) ) {
|
||||
// get away, simulate crsh recovery (don't use avoid)
|
||||
// accelerate_ship(aip, -1.0f);
|
||||
big_ship_collide_recover_start(Pl_objp, En_objp, &Pl_objp->pos, NULL);
|
||||
big_ship_collide_recover_start(Pl_objp, En_objp, nullptr);
|
||||
// aip->submode = SM_AVOID;
|
||||
// aip->submode_start_time = Missiontime;
|
||||
} else if ((dist_normal_to_enemy < ATTACK_COLLIDE_SLOW_DIST) || (time_to_enemy < ATTACK_COLLIDE_SLOW_TIME) ) {
|
||||
@@ -1144,7 +1143,7 @@ void ai_big_chase()
|
||||
// TODO: investigate why ships fire (and aren't close to hitting ship) when following a path near
|
||||
// a big ship
|
||||
if (aip->mode != AIM_EVADE && aip->path_start == -1 ) {
|
||||
ai_big_maybe_fire_weapons(dist_to_enemy, dot_to_enemy, &player_pos, &predicted_enemy_pos, &En_objp->phys_info.vel);
|
||||
ai_big_maybe_fire_weapons(dist_to_enemy, dot_to_enemy);
|
||||
} else {
|
||||
if (flFrametime < 1.0f)
|
||||
aip->time_enemy_in_range *= (1.0f - flFrametime);
|
||||
@@ -1153,11 +1152,6 @@ void ai_big_chase()
|
||||
}
|
||||
}
|
||||
|
||||
void ai_big_ship(object * /*objp*/)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
// all three parms are output parameters
|
||||
// Enemy object is En_objp
|
||||
// pos => world pos of attack point
|
||||
@@ -1228,7 +1222,7 @@ void ai_big_attack_get_data(vec3d *enemy_pos, float *dist_to_enemy, float *dot_t
|
||||
|
||||
// check to see if Pl_objp has gotten too close to attacking point.. if so, break off by entering
|
||||
// AIS_STRAFE_RETREAT
|
||||
int ai_big_strafe_maybe_retreat(float /*dist*/, vec3d *target_pos)
|
||||
static int ai_big_strafe_maybe_retreat(const vec3d *target_pos)
|
||||
{
|
||||
ai_info *aip;
|
||||
aip = &Ai_info[Ships[Pl_objp->instance].ai_index];
|
||||
@@ -1258,7 +1252,7 @@ int ai_big_strafe_maybe_retreat(float /*dist*/, vec3d *target_pos)
|
||||
if (aip->ai_flags[AI::AI_Flags::Target_collision]) {
|
||||
// use standard collision resolution
|
||||
aip->ai_flags.remove(AI::AI_Flags::Target_collision);
|
||||
big_ship_collide_recover_start(Pl_objp, En_objp, &Pl_objp->pos, NULL);
|
||||
big_ship_collide_recover_start(Pl_objp, En_objp, nullptr);
|
||||
} else {
|
||||
// too close for comfort so fly to box point + 300
|
||||
aip->submode = AIS_STRAFE_RETREAT1;
|
||||
@@ -1298,12 +1292,12 @@ void ai_big_strafe_attack()
|
||||
}
|
||||
|
||||
ai_big_attack_get_data(&target_pos, &target_dist, &target_dot);
|
||||
if ( ai_big_strafe_maybe_retreat(target_dist, &target_pos) )
|
||||
if ( ai_big_strafe_maybe_retreat(&target_pos) )
|
||||
return;
|
||||
|
||||
if (aip->ai_flags[AI::AI_Flags::Kamikaze]) {
|
||||
if (target_dist < 1200.0f) {
|
||||
ai_turn_towards_vector(&target_pos, Pl_objp, flFrametime, Ship_info[Ships[Pl_objp->instance].ship_info_index].srotation_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&target_pos, Pl_objp, Ship_info[Ships[Pl_objp->instance].ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
accelerate_ship(aip, 1.0f);
|
||||
if ((target_dist < 400.0f) && ai_maybe_fire_afterburner(Pl_objp, aip)) {
|
||||
afterburners_start(Pl_objp);
|
||||
@@ -1347,7 +1341,7 @@ void ai_big_strafe_attack()
|
||||
}
|
||||
|
||||
// maybe fire weapons at target
|
||||
ai_big_maybe_fire_weapons(target_dist, target_dot, &Pl_objp->pos, &En_objp->pos, &En_objp->phys_info.vel);
|
||||
ai_big_maybe_fire_weapons(target_dist, target_dot);
|
||||
turn_towards_point(Pl_objp, &target_pos, NULL, 0.0f);
|
||||
|
||||
fix last_hit = Missiontime - aip->last_hit_time;
|
||||
@@ -1493,7 +1487,7 @@ void ai_big_strafe_glide_attack()
|
||||
vm_vec_sub2(&target_pos, &En_objp->pos);
|
||||
|
||||
turn_towards_point(Pl_objp, &target_pos, NULL, 0.0f);
|
||||
ai_big_maybe_fire_weapons(target_dist, target_dot, &Pl_objp->pos, &En_objp->pos, &En_objp->phys_info.vel);
|
||||
ai_big_maybe_fire_weapons(target_dist, target_dot);
|
||||
}
|
||||
|
||||
// if haven't been hit in quite a while, leave strafe mode
|
||||
@@ -1517,7 +1511,7 @@ void ai_big_strafe_avoid()
|
||||
mode_time = Missiontime - aip->submode_start_time;
|
||||
|
||||
ai_big_attack_get_data(&target_pos, &target_dist, &target_dot);
|
||||
if ( ai_big_strafe_maybe_retreat(target_dist, &target_pos) )
|
||||
if ( ai_big_strafe_maybe_retreat(&target_pos) )
|
||||
return;
|
||||
|
||||
if ( mode_time > fl2f(0.5)) {
|
||||
@@ -1704,7 +1698,7 @@ void ai_big_strafe()
|
||||
//
|
||||
// Check if weapon_objnum was fired by Pl_objp's target, and whether Pl_objp's target is a big ship, if
|
||||
// so, enter AIM_STRAFE
|
||||
int ai_big_maybe_enter_strafe_mode(object *pl_objp, int weapon_objnum, int /*consider_target_only*/)
|
||||
int ai_big_maybe_enter_strafe_mode(const object *pl_objp, int weapon_objnum)
|
||||
{
|
||||
ai_info *aip;
|
||||
ship_info *sip;
|
||||
@@ -1778,7 +1772,7 @@ int ai_big_maybe_enter_strafe_mode(object *pl_objp, int weapon_objnum, int /*co
|
||||
// Consider attacking a turret, if a turret actually fired the weapon
|
||||
// input: ship_objp => ship that will attack the turret
|
||||
// weapon_objp =>
|
||||
void ai_big_strafe_maybe_attack_turret(object *ship_objp, object *weapon_objp)
|
||||
void ai_big_strafe_maybe_attack_turret(const object *ship_objp, const object *weapon_objp)
|
||||
{
|
||||
ai_info *aip;
|
||||
object *parent_objp;
|
||||
|
||||
+2
-3
@@ -17,14 +17,13 @@ struct ai_info;
|
||||
struct vec3d;
|
||||
class ship_subsys;
|
||||
|
||||
void ai_big_ship(object *objp);
|
||||
void ai_big_chase();
|
||||
void ai_big_subsys_path_cleanup(ai_info *aip);
|
||||
|
||||
// strafe functions
|
||||
void ai_big_strafe();
|
||||
int ai_big_maybe_enter_strafe_mode(object *objp, int weapon_objnum, int consider_target_only=0);
|
||||
void ai_big_strafe_maybe_attack_turret(object *ship_objp, object *weapon_objp);
|
||||
int ai_big_maybe_enter_strafe_mode(const object *objp, int weapon_objnum);
|
||||
void ai_big_strafe_maybe_attack_turret(const object *ship_objp, const object *weapon_objp);
|
||||
void ai_big_pick_attack_point(object *objp, object *attacker_objp, vec3d *attack_point, float fov=1.0f);
|
||||
void ai_big_pick_attack_point_turret(object *objp, ship_subsys *ssp, vec3d *gpos, vec3d *gvec, vec3d *attack_point, float weapon_travel_dist, float fov=1.0f);
|
||||
|
||||
|
||||
+69
-97
@@ -764,6 +764,8 @@ void parse_ai_class()
|
||||
set_aic_flag(aicp, "$all ships manage shields:", AI::Profile_Flags::All_ships_manage_shields);
|
||||
|
||||
set_aic_flag(aicp, "$ai can slow down when attacking big ships:", AI::Profile_Flags::Ai_can_slow_down_attacking_big_ships);
|
||||
|
||||
set_aic_flag(aicp, "$use actual primary range:", AI::Profile_Flags::Use_actual_primary_range);
|
||||
}
|
||||
|
||||
void reset_ai_class_names()
|
||||
@@ -1132,7 +1134,7 @@ void ai_update_danger_weapon(int attacked_objnum, int weapon_objnum)
|
||||
|
||||
// If rvec != NULL, use it to match bank by calling vm_matrix_interpolate.
|
||||
// (rvec defaults to NULL)
|
||||
void ai_turn_towards_vector(vec3d *dest, object *objp, float /*frametime*/, float turn_time, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec, int sexp_flags)
|
||||
void ai_turn_towards_vector(vec3d *dest, object *objp, float turn_time, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec, int sexp_flags)
|
||||
{
|
||||
matrix curr_orient;
|
||||
vec3d vel_in, vel_out, desired_fvec, src;
|
||||
@@ -1500,12 +1502,12 @@ void turn_towards_point(object *objp, vec3d *point, vec3d *slide_vec, float bank
|
||||
if (aip->ai_flags[AI::AI_Flags::Formation_object, AI::AI_Flags::Formation_wing]) {
|
||||
if (&Objects[aip->goal_objnum] != objp) {
|
||||
float rotvel_z = objp->phys_info.rotvel.xyz.z;
|
||||
ai_turn_towards_vector(point, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, slide_vec, NULL, bank_override, 0);
|
||||
ai_turn_towards_vector(point, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, slide_vec, nullptr, bank_override, 0);
|
||||
objp->phys_info.rotvel.xyz.z = rotvel_z;
|
||||
}
|
||||
} else {
|
||||
// normal turn
|
||||
ai_turn_towards_vector(point, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, slide_vec, NULL, bank_override, 0);
|
||||
ai_turn_towards_vector(point, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, slide_vec, nullptr, bank_override, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1520,7 +1522,7 @@ void turn_away_from_point(object *objp, vec3d *point, float bank_override)
|
||||
vm_vec_sub(&opposite_point, &objp->pos, point);
|
||||
vm_vec_add2(&opposite_point, &objp->pos);
|
||||
|
||||
ai_turn_towards_vector(&opposite_point, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, NULL, NULL, bank_override, AITTV_FAST);
|
||||
ai_turn_towards_vector(&opposite_point, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, nullptr, nullptr, bank_override, AITTV_FAST);
|
||||
}
|
||||
|
||||
|
||||
@@ -3448,35 +3450,6 @@ float compute_time_to_enemy(float dist_to_enemy, object *pobjp)
|
||||
return time_to_enemy + flFrametime;
|
||||
}
|
||||
|
||||
// Stuff *dot and *tts.
|
||||
// *dot is always computed. If dot is less than zero, the magnitude is
|
||||
// incorrect, not having been divided by distance.
|
||||
// If *dot is > 0.0f, then tts is computed. This is the time it will take object
|
||||
// *objp to get to *pos, assuming it moves right at it.
|
||||
void fds_aux(float *dot, float *tts, vec3d *pos, float /*dtime*/, object *objp)
|
||||
{
|
||||
vec3d v2s;
|
||||
|
||||
vm_vec_sub(&v2s, pos, &objp->pos);
|
||||
*dot = vm_vec_dot(&v2s, &objp->orient.vec.fvec);
|
||||
|
||||
if (*dot > 0.0f) {
|
||||
float dist;
|
||||
|
||||
dist = vm_vec_dist(&objp->pos, pos);
|
||||
|
||||
if (dist > 0.1f)
|
||||
*dot /= dist;
|
||||
else
|
||||
*dot = 1.0f;
|
||||
|
||||
if (objp->phys_info.speed > 0.1f)
|
||||
*tts = dist / objp->phys_info.speed;
|
||||
else
|
||||
*tts = dist * 100.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
void ai_set_positions(object *pl_objp, object *en_objp, ai_info *aip, vec3d *player_pos, vec3d *enemy_pos)
|
||||
{
|
||||
@@ -3892,7 +3865,7 @@ float ai_path_0()
|
||||
}
|
||||
|
||||
if (dist_to_goal > 0.1f)
|
||||
ai_turn_towards_vector(&gcvp, Pl_objp, flFrametime, sip->srotation_time, slop_vec, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&gcvp, Pl_objp, sip->srotation_time, slop_vec, nullptr, 0.0f, 0);
|
||||
|
||||
// Code to control speed is MUCH less forgiving in path following than in waypoint
|
||||
// following. Must be very close to path or might hit objects.
|
||||
@@ -4034,10 +4007,10 @@ float ai_path_1()
|
||||
if (r <= 1.0f) {
|
||||
vec3d midpoint;
|
||||
vm_vec_avg3(&midpoint, &gcvp, &closest_point, &closest_point);
|
||||
ai_turn_towards_vector(&midpoint, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0, prvec);
|
||||
ai_turn_towards_vector(&midpoint, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0, prvec);
|
||||
}
|
||||
else {
|
||||
ai_turn_towards_vector(&gcvp, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0, prvec);
|
||||
ai_turn_towards_vector(&gcvp, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0, prvec);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4382,11 +4355,11 @@ void ai_fly_to_target_position(vec3d* target_pos, bool* pl_done_p=NULL, bool* pl
|
||||
vm_vector_2_matrix(&Pl_objp->orient, &perp, NULL, NULL);
|
||||
} else {
|
||||
vm_vec_scale_add(&perp, &Pl_objp->pos, &Autopilot_flight_leader->phys_info.vel, 1000.0f);
|
||||
ai_turn_towards_vector(&perp, Pl_objp, flFrametime, sip->srotation_time*3.0f*scale, slop_vec, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&perp, Pl_objp, sip->srotation_time*3.0f*scale, slop_vec, nullptr, 0.0f, 0);
|
||||
}
|
||||
} else {
|
||||
if (dist_to_goal > 0.1f) {
|
||||
ai_turn_towards_vector(target_pos, Pl_objp, flFrametime, sip->srotation_time*3.0f*scale, slop_vec, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(target_pos, Pl_objp, sip->srotation_time*3.0f*scale, slop_vec, nullptr, 0.0f, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5051,7 +5024,7 @@ void slide_face_ship()
|
||||
|
||||
dist = vm_vec_normalized_dir(&vec_from_enemy, &Pl_objp->pos, &En_objp->pos);
|
||||
|
||||
ai_turn_towards_vector(&En_objp->pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&En_objp->pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
|
||||
dot_from_enemy = vm_vec_dot(&vec_from_enemy, &En_objp->orient.vec.fvec);
|
||||
|
||||
@@ -5234,7 +5207,7 @@ vec3d G_predicted_pos, G_fire_pos;
|
||||
// Else
|
||||
// Select Any ol' weapon.
|
||||
// Returns primary_bank index.
|
||||
int ai_select_primary_weapon_OLD(object *objp, object * /*other_objp*/, Weapon::Info_Flags flags)
|
||||
static int ai_select_primary_weapon_OLD(const object *objp, Weapon::Info_Flags flags)
|
||||
{
|
||||
ship *shipp = &Ships[objp->instance];
|
||||
ship_weapon *swp = &shipp->weapons;
|
||||
@@ -5325,7 +5298,7 @@ int ai_select_primary_weapon(object *objp, object *other_objp, Weapon::Info_Flag
|
||||
//not using the new AI, use the old version of this function instead.
|
||||
if (!(Ai_info[shipp->ai_index].ai_profile_flags[AI::Profile_Flags::Smart_primary_weapon_selection]))
|
||||
{
|
||||
return ai_select_primary_weapon_OLD(objp, other_objp, flags);
|
||||
return ai_select_primary_weapon_OLD(objp, flags);
|
||||
}
|
||||
|
||||
Assert( shipp->ship_info_index >= 0 && shipp->ship_info_index < static_cast<int>(Ship_info.size()));
|
||||
@@ -6051,8 +6024,7 @@ int check_ok_to_fire(int objnum, int target_objnum, weapon_info *wip)
|
||||
// --------------------------------------------------------------------------
|
||||
// Fire a secondary weapon.
|
||||
// Maybe choose to fire a different one.
|
||||
// priority1 and priority2 are optional parameters with defaults = -1
|
||||
int ai_fire_secondary_weapon(object *objp, int /*priority1*/, int /*priority2*/)
|
||||
int ai_fire_secondary_weapon(object *objp)
|
||||
{
|
||||
ship_weapon *swp;
|
||||
ship *shipp;
|
||||
@@ -6072,7 +6044,7 @@ int ai_fire_secondary_weapon(object *objp, int /*priority1*/, int /*priority2*
|
||||
Assert( shipp->ship_info_index >= 0 && shipp->ship_info_index < static_cast<int>(Ship_info.size()));
|
||||
|
||||
// Select secondary weapon.
|
||||
current_bank = swp->current_secondary_bank; //ai_select_secondary_weapon(objp, swp, priority1, priority2);
|
||||
current_bank = swp->current_secondary_bank;
|
||||
|
||||
if (current_bank == -1) {
|
||||
return rval;
|
||||
@@ -6539,14 +6511,14 @@ void ai_chase_ct()
|
||||
vm_vec_add2(&tvec, &Pl_objp->orient.vec.rvec);
|
||||
}
|
||||
|
||||
ai_turn_towards_vector(&tvec, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&tvec, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
accelerate_ship(aip, 1.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* ATTACK submode handler for chase mode.
|
||||
*/
|
||||
void ai_chase_eb(ai_info *aip, ship_info *sip, vec3d *predicted_enemy_pos, float /*dist_to_enemy*/)
|
||||
static void ai_chase_eb(ai_info *aip, ship_info *sip, vec3d *predicted_enemy_pos)
|
||||
{
|
||||
vec3d _pep;
|
||||
float dot_to_enemy, dot_from_enemy;
|
||||
@@ -6558,7 +6530,7 @@ void ai_chase_eb(ai_info *aip, ship_info *sip, vec3d *predicted_enemy_pos, float
|
||||
if ((dot_to_enemy > dot_from_enemy + 0.1f) || (dot_to_enemy > 0.9f))
|
||||
vm_vec_scale_add(&_pep, &Pl_objp->pos, &En_objp->orient.vec.fvec, 100.0f);
|
||||
|
||||
ai_turn_towards_vector(&_pep, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&_pep, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
|
||||
accelerate_ship(aip, 0.0f);
|
||||
}
|
||||
@@ -6755,7 +6727,7 @@ void attack_set_accel(ai_info *aip, ship_info *sip, float dist_to_enemy, float d
|
||||
|
||||
// Pl_objp (aip) tries to get behind En_objp.
|
||||
// New on 2/21/98: If this ship can move backwards and slide, maybe do that to get behind.
|
||||
void get_behind_ship(ai_info *aip, ship_info *sip, float /*dist_to_enemy*/)
|
||||
static void get_behind_ship(ai_info *aip, ship_info *sip)
|
||||
{
|
||||
vec3d new_pos;
|
||||
float dot;
|
||||
@@ -6764,7 +6736,7 @@ void get_behind_ship(ai_info *aip, ship_info *sip, float /*dist_to_enemy*/)
|
||||
vm_vec_normalized_dir(&vec_from_enemy, &Pl_objp->pos, &En_objp->pos);
|
||||
|
||||
vm_vec_scale_add(&new_pos, &En_objp->pos, &En_objp->orient.vec.fvec, -100.0f); // Pick point 100 units behind.
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
|
||||
dot = vm_vec_dot(&vec_from_enemy, &En_objp->orient.vec.fvec);
|
||||
|
||||
@@ -6783,7 +6755,7 @@ int avoid_player(object *objp, vec3d *goal_pos)
|
||||
if (aip->ai_flags[AI::AI_Flags::Avoiding_small_ship]) {
|
||||
ship_info *sip = &Ship_info[Ships[objp->instance].ship_info_index];
|
||||
|
||||
ai_turn_towards_vector(&aip->avoid_goal_point, objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&aip->avoid_goal_point, objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
accelerate_ship(aip, 0.5f);
|
||||
return 1;
|
||||
}
|
||||
@@ -6981,7 +6953,7 @@ int maybe_avoid_big_ship(object *objp, object *ignore_objp, ai_info *aip, vec3d
|
||||
|
||||
vec3d v2g;
|
||||
|
||||
ai_turn_towards_vector(&aip->avoid_goal_point, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&aip->avoid_goal_point, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
vm_vec_normalized_dir(&v2g, &aip->avoid_goal_point, &Pl_objp->pos);
|
||||
float dot = vm_vec_dot(&objp->orient.vec.fvec, &v2g);
|
||||
float d2 = (1.0f + dot) * (1.0f + dot);
|
||||
@@ -7073,7 +7045,7 @@ void ai_stealth_find()
|
||||
}
|
||||
}
|
||||
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -7083,9 +7055,9 @@ void ai_stealth_find()
|
||||
if (dist_to_enemy > 500.0f) {
|
||||
vec3d rvec;
|
||||
compute_desired_rvec(&rvec, &new_pos, &Pl_objp->pos);
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0, &rvec);
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0, &rvec);
|
||||
} else {
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
}
|
||||
|
||||
dot_from_enemy = -vm_vec_dot(&vec_to_enemy, &En_objp->orient.vec.fvec);
|
||||
@@ -7213,7 +7185,7 @@ void ai_stealth_sweep()
|
||||
return;
|
||||
}
|
||||
|
||||
ai_turn_towards_vector(&goal_pt, Pl_objp, flFrametime, sip->srotation_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&goal_pt, Pl_objp, sip->srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
|
||||
float dot = 1.0f;
|
||||
if (dist_to_goal < 100) {
|
||||
@@ -7273,9 +7245,9 @@ void ai_chase_attack(ai_info *aip, ship_info *sip, vec3d *predicted_enemy_pos, f
|
||||
if (dist_to_enemy > 500.0f) {
|
||||
vec3d rvec;
|
||||
compute_desired_rvec(&rvec, predicted_enemy_pos, &Pl_objp->pos);
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, rel_pos, bank_override, 0, &rvec);
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, rel_pos, bank_override, 0, &rvec);
|
||||
} else {
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, flFrametime, sip->srotation_time, NULL, rel_pos, bank_override, 0);
|
||||
ai_turn_towards_vector(&new_pos, Pl_objp, sip->srotation_time, nullptr, rel_pos, bank_override, 0);
|
||||
}
|
||||
|
||||
attack_set_accel(aip, sip, dist_to_enemy, dot_to_enemy, dot_from_enemy);
|
||||
@@ -7313,7 +7285,7 @@ void ai_chase_es(ai_info *aip, ship_info *sip)
|
||||
|
||||
float bank_override = Pl_objp->phys_info.speed;
|
||||
|
||||
ai_turn_towards_vector(&tvec, Pl_objp, flFrametime/2, sip->srotation_time, NULL, NULL, bank_override, 0);
|
||||
ai_turn_towards_vector(&tvec, Pl_objp, sip->srotation_time, nullptr, nullptr, bank_override, 0);
|
||||
accelerate_ship(aip, 1.0f);
|
||||
}
|
||||
|
||||
@@ -7339,7 +7311,7 @@ void ai_chase_ga(ai_info *aip, ship_info *sip)
|
||||
|
||||
bank_override = Pl_objp->phys_info.speed;
|
||||
|
||||
ai_turn_towards_vector(&tvec, Pl_objp, flFrametime/2, sip->srotation_time, NULL, NULL, bank_override, 0);
|
||||
ai_turn_towards_vector(&tvec, Pl_objp, sip->srotation_time, nullptr, nullptr, bank_override, 0);
|
||||
|
||||
accelerate_ship(aip, 2.0f);
|
||||
|
||||
@@ -8001,7 +7973,7 @@ void ai_cruiser_chase()
|
||||
|
||||
// kamikaze - ram and explode
|
||||
if (aip->ai_flags[AI::AI_Flags::Kamikaze]) {
|
||||
ai_turn_towards_vector(&En_objp->pos, Pl_objp, flFrametime, turn_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&En_objp->pos, Pl_objp, turn_time, nullptr, nullptr, 0.0f, 0);
|
||||
accelerate_ship(aip, 1.0f);
|
||||
}
|
||||
|
||||
@@ -8041,7 +8013,7 @@ void ai_cruiser_chase()
|
||||
}
|
||||
|
||||
// now move as desired
|
||||
ai_turn_towards_vector(&goal_pos, Pl_objp, flFrametime, turn_time, NULL, NULL, 0.0f, 0, rvecp);
|
||||
ai_turn_towards_vector(&goal_pos, Pl_objp, turn_time, nullptr, nullptr, 0.0f, 0, rvecp);
|
||||
accelerate_ship(aip, accel);
|
||||
|
||||
// maybe switch to new mode
|
||||
@@ -8322,7 +8294,7 @@ void ai_chase()
|
||||
break;
|
||||
|
||||
case SM_EVADE_BRAKE:
|
||||
ai_chase_eb(aip, sip, &predicted_enemy_pos, dist_to_enemy);
|
||||
ai_chase_eb(aip, sip, &predicted_enemy_pos);
|
||||
break;
|
||||
|
||||
case SM_EVADE:
|
||||
@@ -8334,7 +8306,7 @@ void ai_chase()
|
||||
break;
|
||||
|
||||
case SM_GET_BEHIND:
|
||||
get_behind_ship(aip, sip, dist_to_enemy);
|
||||
get_behind_ship(aip, sip);
|
||||
break;
|
||||
|
||||
case SM_GET_AWAY: // Used to get away from opponent to prevent endless circling.
|
||||
@@ -8768,7 +8740,11 @@ void ai_chase()
|
||||
scale = (scale - 0.6f) * 1.5f;
|
||||
else
|
||||
scale = 0.0f;
|
||||
if (dist_to_enemy < pwip->max_speed * (1.0f + scale)) {
|
||||
float range = pwip->max_speed * (1.0f + scale);
|
||||
if (aip->ai_profile_flags[AI::Profile_Flags::Use_actual_primary_range]) {
|
||||
range = std::min( {range, pwip->max_speed * pwip->lifetime, pwip->weapon_range} );
|
||||
}
|
||||
if (dist_to_enemy < range) {
|
||||
if(ai_fire_primary_weapon(Pl_objp) == 1){
|
||||
has_fired = 1;
|
||||
}else{
|
||||
@@ -9329,7 +9305,7 @@ float dock_orient_and_approach(object *docker_objp, int docker_index, object *do
|
||||
{
|
||||
float dot, accel;
|
||||
float turn_time = Ship_info[Ships[docker_objp->instance].ship_info_index].srotation_time;
|
||||
ai_turn_towards_vector(&goal_point, docker_objp, flFrametime, turn_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&goal_point, docker_objp, turn_time, nullptr, nullptr, 0.0f, 0);
|
||||
|
||||
dot = vm_vec_dot(&docker_objp->orient.vec.fvec, &away_vec);
|
||||
accel = 0.1f;
|
||||
@@ -9964,7 +9940,7 @@ void ai_big_guard()
|
||||
}
|
||||
|
||||
// got the point, now let's go there
|
||||
ai_turn_towards_vector(&goal_pt, Pl_objp, flFrametime, Ship_info[Ships[Pl_objp->instance].ship_info_index].srotation_time, NULL, NULL, 0.0f, 0);
|
||||
ai_turn_towards_vector(&goal_pt, Pl_objp, Ship_info[Ships[Pl_objp->instance].ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0);
|
||||
accelerate_ship(aip, 1.0f);
|
||||
|
||||
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (cur_guard_rad > 1.1f * max_guard_dist)) {
|
||||
@@ -10088,7 +10064,7 @@ void ai_guard()
|
||||
|
||||
// quite far away, so try to go straight to
|
||||
compute_desired_rvec(&rvec, &goal_point, &Pl_objp->pos);
|
||||
ai_turn_towards_vector(&goal_point, Pl_objp, flFrametime, Ship_info[shipp->ship_info_index].srotation_time, NULL, NULL, 0.0f, 0, &rvec);
|
||||
ai_turn_towards_vector(&goal_point, Pl_objp, Ship_info[shipp->ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0, &rvec);
|
||||
|
||||
if ((aip->ai_flags[AI::AI_Flags::Free_afterburner_use]) && !(shipp->flags[Ship::Ship_Flags::Afterburner_locked]) && (accel_scale * (0.25f + dist_to_goal_point/700.0f) > 0.8f)) {
|
||||
if (ai_maybe_fire_afterburner(Pl_objp, aip)) {
|
||||
@@ -10713,8 +10689,8 @@ void ai_dock()
|
||||
char *goal_ship_class_name = goal_sip->name;
|
||||
char *goal_dock_path_name = model_get(goal_sip->model_num)->paths[aip->mp_index].name;
|
||||
|
||||
Warning(LOCATION, "Ship class %s has only %i points on dock path \"%s\". Recommended minimum number of points is 4. "\
|
||||
"Docking along that path will look strange. You may wish to edit the model.", goal_ship_class_name, aip->path_length, goal_dock_path_name);
|
||||
mprintf(("Ship class %s has only %i points on dock path \"%s\". Recommended minimum number of points is 4. "\
|
||||
"Docking along that path will look strange. You may wish to edit the model.", goal_ship_class_name, aip->path_length, goal_dock_path_name));
|
||||
}
|
||||
|
||||
aip->submode = AIS_DOCK_1;
|
||||
@@ -11385,7 +11361,7 @@ float gwlr_1(object *objp, ai_info *aip)
|
||||
/**
|
||||
* Compute the largest radius of a ship forming on *objp's wing.
|
||||
*/
|
||||
float gwlr_object_1(object *objp, ai_info * /*aip*/)
|
||||
static float gwlr_object_1(object *objp)
|
||||
{
|
||||
float max_radius;
|
||||
object *o;
|
||||
@@ -11418,7 +11394,7 @@ float get_wing_largest_radius(object *objp, int formation_object_flag)
|
||||
aip = &Ai_info[shipp->ai_index];
|
||||
|
||||
if (formation_object_flag) {
|
||||
return gwlr_object_1(objp, aip);
|
||||
return gwlr_object_1(objp);
|
||||
} else {
|
||||
return gwlr_1(objp, aip);
|
||||
}
|
||||
@@ -12191,7 +12167,7 @@ void ai_maybe_launch_cmeasure(object *objp, ai_info *aip)
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
void ai_preprocess_ignore_objnum(object * /*objp*/, ai_info *aip)
|
||||
static void ai_preprocess_ignore_objnum(ai_info *aip)
|
||||
{
|
||||
if (aip->ai_flags[AI::AI_Flags::Temporary_ignore])
|
||||
{
|
||||
@@ -13064,7 +13040,6 @@ void ai_execute_behavior(ai_info *aip)
|
||||
case AIM_NONE:
|
||||
break;
|
||||
case AIM_BIGSHIP:
|
||||
ai_big_ship(Pl_objp);
|
||||
break;
|
||||
case AIM_PATH: {
|
||||
int path_num;
|
||||
@@ -13441,7 +13416,7 @@ void ai_warp_out(object *objp)
|
||||
|
||||
// Return object index of weapon that could produce a shockwave that should be known about to *objp.
|
||||
// Return nearest one.
|
||||
int ai_find_shockwave_weapon(object *objp, ai_info * /*aip*/)
|
||||
static int ai_find_shockwave_weapon(const object *objp)
|
||||
{
|
||||
missile_obj *mo;
|
||||
float nearest_dist = 999999.9f;
|
||||
@@ -13507,7 +13482,7 @@ void ai_announce_ship_dying(object *dying_objp)
|
||||
|
||||
// Return object index of weapon that could produce a shockwave that should be known about to *objp.
|
||||
// Return nearest one.
|
||||
int ai_find_shockwave_ship(object *objp, ai_info * /*aip*/)
|
||||
static int ai_find_shockwave_ship(object *objp)
|
||||
{
|
||||
ship_obj *so;
|
||||
float nearest_dist = 999999.9f;
|
||||
@@ -13550,7 +13525,7 @@ int aas_1(object *objp, ai_info *aip, vec3d *safe_pos)
|
||||
// If we don't currently know of a weapon to avoid, try to find one.
|
||||
// If we can't find one, then clear the bit so we don't keep coming here.
|
||||
if (aip->shockwave_object == -1) {
|
||||
int shockwave_weapon = ai_find_shockwave_weapon(objp, aip);
|
||||
int shockwave_weapon = ai_find_shockwave_weapon(objp);
|
||||
if (shockwave_weapon == -1) {
|
||||
aip->ai_flags.remove(AI::AI_Flags::Avoid_shockwave_weapon);
|
||||
return 0;
|
||||
@@ -13639,7 +13614,7 @@ int aas_1(object *objp, ai_info *aip, vec3d *safe_pos)
|
||||
}
|
||||
} else if (aip->ai_flags[AI::AI_Flags::Avoid_shockwave_ship]) {
|
||||
if (aip->shockwave_object == -1) {
|
||||
int shockwave_ship = ai_find_shockwave_ship(objp, aip);
|
||||
int shockwave_ship = ai_find_shockwave_ship(objp);
|
||||
if (shockwave_ship == -1) {
|
||||
aip->ai_flags.remove(AI::AI_Flags::Avoid_shockwave_ship);
|
||||
return 0;
|
||||
@@ -13869,7 +13844,7 @@ int maybe_big_ship_collide_recover_frame(object *objp, ai_info *aip)
|
||||
vec3d v2g;
|
||||
|
||||
if (aip->ai_flags[AI::AI_Flags::Big_ship_collide_recover_1]) {
|
||||
ai_turn_towards_vector(&aip->big_recover_pos_1, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, NULL, NULL, 0.0f, 0, NULL);
|
||||
ai_turn_towards_vector(&aip->big_recover_pos_1, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0, nullptr);
|
||||
dist = vm_vec_normalized_dir(&v2g, &aip->big_recover_pos_1, &objp->pos);
|
||||
dot = vm_vec_dot(&objp->orient.vec.fvec, &v2g);
|
||||
accelerate_ship(aip, dot);
|
||||
@@ -13883,7 +13858,7 @@ int maybe_big_ship_collide_recover_frame(object *objp, ai_info *aip)
|
||||
return 1;
|
||||
|
||||
} else if (aip->ai_flags[AI::AI_Flags::Big_ship_collide_recover_2]) {
|
||||
ai_turn_towards_vector(&aip->big_recover_pos_2, objp, flFrametime, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, NULL, NULL, 0.0f, 0, NULL);
|
||||
ai_turn_towards_vector(&aip->big_recover_pos_2, objp, Ship_info[Ships[objp->instance].ship_info_index].srotation_time, nullptr, nullptr, 0.0f, 0, nullptr);
|
||||
dist = vm_vec_normalized_dir(&v2g, &aip->big_recover_pos_2, &objp->pos);
|
||||
dot = vm_vec_dot(&objp->orient.vec.fvec, &v2g);
|
||||
accelerate_ship(aip, dot);
|
||||
@@ -14003,7 +13978,7 @@ void ai_frame(int objnum)
|
||||
if (maybe_big_ship_collide_recover_frame(Pl_objp, aip))
|
||||
return;
|
||||
|
||||
ai_preprocess_ignore_objnum(Pl_objp, aip);
|
||||
ai_preprocess_ignore_objnum(aip);
|
||||
target_objnum = set_target_objnum(aip, aip->target_objnum);
|
||||
|
||||
Assert(objnum != target_objnum);
|
||||
@@ -14158,7 +14133,7 @@ void ai_frame(int objnum)
|
||||
}
|
||||
}
|
||||
|
||||
void ai_control_info_check( object * /*obj*/, ai_info *aip )
|
||||
static void ai_control_info_check(ai_info *aip)
|
||||
{
|
||||
if(aip->ai_override_flags.none_set())
|
||||
return;
|
||||
@@ -14259,7 +14234,7 @@ void ai_process( object * obj, int ai_index, float frametime )
|
||||
|
||||
if (rfc == 1) {
|
||||
// Wanderer - sexp based override goes here - only if rfc is valid though
|
||||
ai_control_info_check(obj, aip);
|
||||
ai_control_info_check(aip);
|
||||
vec3d copy_desired_rotvel = obj->phys_info.rotvel;
|
||||
physics_read_flying_controls( &obj->orient, &obj->phys_info, &AI_ci, frametime);
|
||||
// if obj is in formation and not flight leader, don't update rotvel
|
||||
@@ -14794,10 +14769,10 @@ int firing_aspect_seeking_bomb(object *objp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// *objp collided with big ship *big_objp at global point *collide_pos
|
||||
// Make it fly away from the collision point.
|
||||
// *objp collided with big ship *big_objp at some global point.
|
||||
// Make it fly away from the collision point.
|
||||
// collision_normal is NULL, when a collision is imminent and we just want to bug out.
|
||||
void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d * /*collide_pos*/, vec3d *collision_normal)
|
||||
void big_ship_collide_recover_start(object *objp, object *big_objp, vec3d *collision_normal)
|
||||
{
|
||||
ai_info *aip;
|
||||
|
||||
@@ -14886,9 +14861,9 @@ void ai_update_lethality(object *pship_obj, object *other_obj, float damage)
|
||||
|
||||
|
||||
/**
|
||||
* Object *objp_ship was hit by either weapon *objp_weapon or collided into by ship hit_objp at point *hitpos.
|
||||
* Object *objp_ship was hit by either weapon *objp_weapon or collided into by ship hit_objp
|
||||
*/
|
||||
void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hitpos, int /*shield_quadrant*/, vec3d *hit_normal)
|
||||
void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal)
|
||||
{
|
||||
int hitter_objnum = -2;
|
||||
object *objp_hitter = NULL;
|
||||
@@ -14930,7 +14905,7 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hitpos, int /*shie
|
||||
// And the current object is _not_ a big ship
|
||||
if (!Ship_info[Ships[objp_ship->instance].ship_info_index].is_big_or_huge()) {
|
||||
// Recover from hitting a big ship. Note, if two big ships collide, they just pound away at each other. Oh well. Recovery looks dumb and it's very late.
|
||||
big_ship_collide_recover_start(objp_ship, hit_objp, hitpos, hit_normal);
|
||||
big_ship_collide_recover_start(objp_ship, hit_objp, hit_normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15067,7 +15042,7 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hitpos, int /*shie
|
||||
return;
|
||||
|
||||
if ( (hit_objp->type == OBJ_WEAPON) && !(aip->ai_flags[AI::AI_Flags::No_dynamic]) ) {
|
||||
if ( ai_big_maybe_enter_strafe_mode(objp_ship, OBJ_INDEX(hit_objp), 1) )
|
||||
if ( ai_big_maybe_enter_strafe_mode(objp_ship, OBJ_INDEX(hit_objp)) )
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@@ -15187,10 +15162,7 @@ void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hitpos, int /*shie
|
||||
|
||||
// Ship shipnum has been destroyed.
|
||||
// Cleanup.
|
||||
// the parameter 'method' is used to tell is this ship was destroyed or it departed normally.
|
||||
// This function will get called in either case, and there are things that should be done if
|
||||
// the ship actually gets destroyed which shouldn't get done if it departed.
|
||||
void ai_ship_destroy(int shipnum, Ship::Exit_Flags /*method*/)
|
||||
void ai_ship_destroy(int shipnum)
|
||||
{
|
||||
int objnum;
|
||||
object *other_objp;
|
||||
@@ -15441,7 +15413,7 @@ int ai_issue_rearm_request(object *requester_objp)
|
||||
// we aren't able to do anything!
|
||||
else {
|
||||
Assert(result == 4);
|
||||
Assertion(false, "This case should have already been caught by the is_support_allowed precheck!");
|
||||
UNREACHABLE("This case should have already been caught by the is_support_allowed precheck!");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -15510,7 +15482,7 @@ int ai_return_path_num_from_dockbay(object *dockee_objp, int dockbay_index)
|
||||
/**
|
||||
* Actually go ahead and fire the synaptics.
|
||||
*/
|
||||
void cheat_fire_synaptic(object *objp, ship *shipp, ai_info * /*aip*/)
|
||||
static void cheat_fire_synaptic(object *objp, ship *shipp)
|
||||
{
|
||||
ship_weapon *swp;
|
||||
swp = &shipp->weapons;
|
||||
@@ -15532,7 +15504,7 @@ void cheat_fire_synaptic(object *objp, ship *shipp, ai_info * /*aip*/)
|
||||
// if they're near one or more enemies
|
||||
// every so often
|
||||
// fire a synaptic if they have one.
|
||||
void maybe_cheat_fire_synaptic(object *objp, ai_info *aip)
|
||||
void maybe_cheat_fire_synaptic(object *objp)
|
||||
{
|
||||
// Only do in subspace missions.
|
||||
if (!(The_mission.flags[Mission::Mission_Flags::Subspace]))
|
||||
@@ -15564,7 +15536,7 @@ void maybe_cheat_fire_synaptic(object *objp, ai_info *aip)
|
||||
int count = num_nearby_fighters(iff_get_attackee_mask(obj_team(objp)), &objp->pos, 1500.0f);
|
||||
|
||||
if (count > 0)
|
||||
cheat_fire_synaptic(objp, shipp, aip);
|
||||
cheat_fire_synaptic(objp, shipp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -125,7 +125,7 @@ const char *Ai_goal_text(int goal)
|
||||
case AI_GOAL_REARM_REPAIR:
|
||||
return XSTR( "rearm ", 484);
|
||||
case AI_GOAL_FLY_TO_SHIP:
|
||||
return XSTR( "rendezvous with ", -1);
|
||||
return XSTR( "rendezvous with ", 1597);
|
||||
}
|
||||
|
||||
// Avoid compiler warning
|
||||
|
||||
@@ -1387,7 +1387,7 @@ void asteroid_hit( object * pasteroid_obj, object * other_obj, vec3d * hitpos, f
|
||||
weapon_info *wip;
|
||||
wip = &Weapon_info[Weapons[other_obj->instance].weapon_info_index];
|
||||
// If the weapon didn't play any impact animation, play custom asteroid impact animation
|
||||
if ( wip->impact_weapon_expl_effect < 0 ) {
|
||||
if (!wip->impact_weapon_expl_effect.isValid()) {
|
||||
particle::create( hitpos, &vmd_zero_vector, 0.0f, Asteroid_impact_explosion_radius, particle::PARTICLE_BITMAP, Asteroid_impact_explosion_ani );
|
||||
}
|
||||
}
|
||||
|
||||
+16
-23
@@ -591,7 +591,7 @@ int bm_create(int bpp, int w, int h, void *data, int flags) {
|
||||
|
||||
memset(entry, 0, sizeof(bitmap_entry));
|
||||
|
||||
sprintf(entry->filename, "TMP%dx%d+%d", w, h, bpp);
|
||||
sprintf_safe(entry->filename, "TMP%dx%d+%d", w, h, bpp);
|
||||
entry->type = BM_TYPE_USER;
|
||||
entry->comp_type = BM_TYPE_NONE;
|
||||
entry->palette_checksum = 0;
|
||||
@@ -1155,7 +1155,7 @@ static int bm_load_info(BM_TYPE type, const char *filename, CFILE *img_cfp, int
|
||||
}
|
||||
}
|
||||
else {
|
||||
Assertion(false, "Unknown file type specified! This is probably a coding error.");
|
||||
UNREACHABLE("Unknown file type specified! This is probably a coding error.");
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -1253,7 +1253,7 @@ int bm_load(const char *real_filename) {
|
||||
|
||||
// Mark the slot as filled, because cf_read might load a new bitmap
|
||||
// into this slot.
|
||||
strncpy(entry->filename, filename, MAX_FILENAME_LEN - 1);
|
||||
strcpy_s(entry->filename, filename);
|
||||
entry->type = type;
|
||||
entry->comp_type = c_type;
|
||||
entry->signature = Bm_next_signature++;
|
||||
@@ -1681,7 +1681,7 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
|
||||
|
||||
if (type == BM_TYPE_EFF) {
|
||||
entry->info.ani.eff.type = eff_type;
|
||||
sprintf(entry->info.ani.eff.filename, "%s_%.4d", clean_name, i);
|
||||
sprintf_safe(entry->info.ani.eff.filename, "%s_%.4d", clean_name, i);
|
||||
|
||||
// bm_load_info() returns non-0 on failure
|
||||
if (bm_load_info(eff_type, entry->info.ani.eff.filename,
|
||||
@@ -1744,13 +1744,13 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
|
||||
entry->load_count++;
|
||||
|
||||
if (i == 0) {
|
||||
sprintf(entry->filename, "%s", filename);
|
||||
sprintf_safe(entry->filename, "%s", filename);
|
||||
} else {
|
||||
if (type == BM_TYPE_PNG) {
|
||||
sprintf(entry->filename, "%s_%04d", filename, i);
|
||||
sprintf_safe(entry->filename, "%s_%04d", filename, i);
|
||||
}
|
||||
else {
|
||||
sprintf(entry->filename, "%s[%d]", filename, i);
|
||||
sprintf_safe(entry->filename, "%s[%d]", filename, i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1876,24 +1876,19 @@ int bm_load_sub_fast(const char *real_filename, int *handle, int dir_type, bool
|
||||
}
|
||||
|
||||
int bm_load_sub_slow(const char *real_filename, const int num_ext, const char **ext_list, CFILE **img_cfp, int dir_type) {
|
||||
char full_path[MAX_PATH];
|
||||
size_t size = 0, offset = 0;
|
||||
int rval = -1;
|
||||
const void* file_data = nullptr;
|
||||
|
||||
rval = cf_find_file_location_ext(real_filename, num_ext, ext_list, dir_type, sizeof(full_path) - 1, full_path, &size, &offset, 0, &file_data);
|
||||
auto res = cf_find_file_location_ext(real_filename, num_ext, ext_list, dir_type, false);
|
||||
|
||||
// could not be found, or is invalid for some reason
|
||||
if ((rval < 0) || (rval >= num_ext))
|
||||
if (!res.found)
|
||||
return -1;
|
||||
|
||||
CFILE *test = cfopen_special(full_path, "rb", size, offset, file_data, dir_type);
|
||||
CFILE *test = cfopen_special(res.full_name.c_str(), "rb", res.size, res.offset, res.data_ptr, dir_type);
|
||||
|
||||
if (test != NULL) {
|
||||
if (img_cfp != NULL)
|
||||
*img_cfp = test;
|
||||
|
||||
return rval;
|
||||
return res.extension_index;
|
||||
}
|
||||
|
||||
// umm, that's not good...
|
||||
@@ -2385,7 +2380,7 @@ void bm_lock_png(int handle, bitmap_slot *bs, bitmap *bmp, int /*bpp*/, ubyte /*
|
||||
|
||||
void bm_lock_tga(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags) {
|
||||
ubyte *data = NULL;
|
||||
int d_size, byte_size;
|
||||
int byte_size;
|
||||
char filename[MAX_FILENAME_LEN];
|
||||
|
||||
auto be = &bs->entry;
|
||||
@@ -2393,6 +2388,8 @@ void bm_lock_tga(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags)
|
||||
// Unload any existing data
|
||||
bm_free_data(bs);
|
||||
|
||||
bpp = be->bm.true_bpp;
|
||||
|
||||
if (Is_standalone) {
|
||||
Assert(bpp == 8);
|
||||
} else {
|
||||
@@ -2409,7 +2406,6 @@ void bm_lock_tga(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags)
|
||||
|
||||
if (data) {
|
||||
memset(data, 0, be->mem_taken);
|
||||
d_size = byte_size;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
@@ -2429,7 +2425,7 @@ void bm_lock_tga(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ubyte flags)
|
||||
// this will populate filename[] whether it's EFF or not
|
||||
EFF_FILENAME_CHECK;
|
||||
|
||||
tga_error = targa_read_bitmap(filename, data, NULL, d_size, be->dir_type);
|
||||
tga_error = targa_read_bitmap(filename, data, nullptr, byte_size, be->dir_type);
|
||||
|
||||
if (tga_error != TARGA_ERROR_NONE) {
|
||||
bm_free_data(bs);
|
||||
@@ -2526,7 +2522,7 @@ int bm_make_render_target(int width, int height, int flags) {
|
||||
|
||||
entry->type = (flags & BMP_FLAG_RENDER_TARGET_STATIC) ? BM_TYPE_RENDER_TARGET_STATIC : BM_TYPE_RENDER_TARGET_DYNAMIC;
|
||||
entry->signature = Bm_next_signature++;
|
||||
sprintf(entry->filename, "RT_%dx%d+%d", w, h, bpp);
|
||||
sprintf_safe(entry->filename, "RT_%dx%d+%d", w, h, bpp);
|
||||
entry->bm.w = (short)w;
|
||||
entry->bm.h = (short)h;
|
||||
entry->bm.rowsize = (short)w;
|
||||
@@ -2589,9 +2585,6 @@ void bm_page_in_start() {
|
||||
for (auto& slot : block) {
|
||||
auto& entry = slot.entry;
|
||||
|
||||
if (!Cmdline_cache_bitmaps && (entry.type != BM_TYPE_NONE)) {
|
||||
bm_unload_fast(entry.handle);
|
||||
}
|
||||
entry.preloaded = 0;
|
||||
entry.preload_count = 0;
|
||||
#ifdef BMPMAN_NDEBUG
|
||||
|
||||
+75
-87
@@ -33,70 +33,64 @@
|
||||
#include "cfile/cfilesystem.h"
|
||||
#include "osapi/osapi.h"
|
||||
#include "parse/encrypt.h"
|
||||
#include "cfilesystem.h"
|
||||
|
||||
|
||||
#include <limits>
|
||||
|
||||
char Cfile_root_dir[CFILE_ROOT_DIRECTORY_LEN] = "";
|
||||
char Cfile_user_dir[CFILE_ROOT_DIRECTORY_LEN] = "";
|
||||
#ifdef SCP_UNIX
|
||||
char Cfile_user_dir_legacy[CFILE_ROOT_DIRECTORY_LEN] = "";
|
||||
#endif
|
||||
|
||||
// During cfile_init, verify that Pathtypes[n].index == n for each item
|
||||
// Each path must have a valid parent that can be tracable all the way back to the root
|
||||
// Each path must have a valid parent that can be tracable all the way back to the root
|
||||
// so that we can create directories when we need to.
|
||||
//
|
||||
// Please make sure extensions are all lower-case, or we'll break unix compatibility
|
||||
//
|
||||
cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
|
||||
// What type this is Path Extensions Parent
|
||||
// type
|
||||
{CF_TYPE_INVALID, NULL, NULL, CF_TYPE_INVALID},
|
||||
// Root must be index 1!!
|
||||
{CF_TYPE_ROOT, "", ".mve .ogg", CF_TYPE_ROOT},
|
||||
{CF_TYPE_DATA, "data", ".cfg .txt", CF_TYPE_ROOT},
|
||||
{CF_TYPE_MAPS, "data" DIR_SEPARATOR_STR "maps", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA},
|
||||
{CF_TYPE_TEXT, "data" DIR_SEPARATOR_STR "text", ".txt .net", CF_TYPE_DATA},
|
||||
{CF_TYPE_MODELS, "data" DIR_SEPARATOR_STR "models", ".pof", CF_TYPE_DATA},
|
||||
{CF_TYPE_TABLES, "data" DIR_SEPARATOR_STR "tables", ".tbl .tbm", CF_TYPE_DATA},
|
||||
{CF_TYPE_SOUNDS, "data" DIR_SEPARATOR_STR "sounds", ".wav .ogg", CF_TYPE_DATA},
|
||||
{CF_TYPE_SOUNDS_8B22K, "data" DIR_SEPARATOR_STR "sounds" DIR_SEPARATOR_STR "8b22k", ".wav .ogg", CF_TYPE_SOUNDS},
|
||||
{CF_TYPE_SOUNDS_16B11K, "data" DIR_SEPARATOR_STR "sounds" DIR_SEPARATOR_STR "16b11k", ".wav .ogg", CF_TYPE_SOUNDS},
|
||||
{CF_TYPE_VOICE, "data" DIR_SEPARATOR_STR "voice", "", CF_TYPE_DATA},
|
||||
{CF_TYPE_VOICE_BRIEFINGS, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "briefing", ".wav .ogg",
|
||||
CF_TYPE_VOICE},
|
||||
{CF_TYPE_VOICE_CMD_BRIEF, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "command_briefings", ".wav .ogg",
|
||||
CF_TYPE_VOICE},
|
||||
{CF_TYPE_VOICE_DEBRIEFINGS, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "debriefing", ".wav .ogg",
|
||||
CF_TYPE_VOICE},
|
||||
{CF_TYPE_VOICE_PERSONAS, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "personas", ".wav .ogg", CF_TYPE_VOICE},
|
||||
{CF_TYPE_VOICE_SPECIAL, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "special", ".wav .ogg", CF_TYPE_VOICE},
|
||||
{CF_TYPE_VOICE_TRAINING, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "training", ".wav .ogg", CF_TYPE_VOICE},
|
||||
{CF_TYPE_MUSIC, "data" DIR_SEPARATOR_STR "music", ".wav .ogg", CF_TYPE_DATA},
|
||||
{CF_TYPE_MOVIES, "data" DIR_SEPARATOR_STR "movies", ".mve .msb .ogg .mp4 .srt", CF_TYPE_DATA},
|
||||
{CF_TYPE_INTERFACE, "data" DIR_SEPARATOR_STR "interface", ".pcx .ani .dds .tga .eff .png .jpg", CF_TYPE_DATA},
|
||||
{CF_TYPE_FONT, "data" DIR_SEPARATOR_STR "fonts", ".vf .ttf", CF_TYPE_DATA},
|
||||
{CF_TYPE_EFFECTS, "data" DIR_SEPARATOR_STR "effects", ".ani .eff .pcx .neb .tga .jpg .png .dds .sdr", CF_TYPE_DATA},
|
||||
{CF_TYPE_HUD, "data" DIR_SEPARATOR_STR "hud", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA},
|
||||
{CF_TYPE_PLAYERS, "data" DIR_SEPARATOR_STR "players", ".hcf", CF_TYPE_DATA},
|
||||
{CF_TYPE_PLAYER_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "images", ".pcx .png .dds",
|
||||
CF_TYPE_PLAYERS},
|
||||
{CF_TYPE_SQUAD_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "squads", ".pcx .png .dds",
|
||||
CF_TYPE_PLAYERS},
|
||||
{CF_TYPE_SINGLE_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "single", ".pl2 .cs2 .plr .csg .css",
|
||||
CF_TYPE_PLAYERS},
|
||||
{CF_TYPE_MULTI_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "multi", ".plr", CF_TYPE_PLAYERS},
|
||||
{CF_TYPE_CACHE, "data" DIR_SEPARATOR_STR "cache", ".clr .tmp .bx", CF_TYPE_DATA}, // clr=cached color
|
||||
{CF_TYPE_MULTI_CACHE, "data" DIR_SEPARATOR_STR "multidata", ".pcx .png .dds .fs2 .txt", CF_TYPE_DATA},
|
||||
{CF_TYPE_MISSIONS, "data" DIR_SEPARATOR_STR "missions", ".fs2 .fc2 .ntl .ssv", CF_TYPE_DATA},
|
||||
{CF_TYPE_CONFIG, "data" DIR_SEPARATOR_STR "config", ".cfg .tbl .tbm .xml .csv", CF_TYPE_DATA},
|
||||
{CF_TYPE_DEMOS, "data" DIR_SEPARATOR_STR "demos", ".fsd", CF_TYPE_DATA},
|
||||
{CF_TYPE_CBANIMS, "data" DIR_SEPARATOR_STR "cbanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA},
|
||||
{CF_TYPE_INTEL_ANIMS, "data" DIR_SEPARATOR_STR "intelanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA},
|
||||
{CF_TYPE_SCRIPTS, "data" DIR_SEPARATOR_STR "scripts", ".lua .lc", CF_TYPE_DATA},
|
||||
{CF_TYPE_FICTION, "data" DIR_SEPARATOR_STR "fiction", ".txt", CF_TYPE_DATA},
|
||||
{CF_TYPE_FREDDOCS, "data" DIR_SEPARATOR_STR "freddocs", ".html", CF_TYPE_DATA},
|
||||
// clang-format off
|
||||
cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
|
||||
// What type this is Path Extensions Parent type
|
||||
{ CF_TYPE_INVALID, NULL, NULL, CF_TYPE_INVALID },
|
||||
// Root must be index 1!!
|
||||
{ CF_TYPE_ROOT, "", ".mve .ogg", CF_TYPE_ROOT },
|
||||
{ CF_TYPE_DATA, "data", ".cfg .txt", CF_TYPE_ROOT },
|
||||
{ CF_TYPE_MAPS, "data" DIR_SEPARATOR_STR "maps", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
|
||||
{ CF_TYPE_TEXT, "data" DIR_SEPARATOR_STR "text", ".txt .net", CF_TYPE_DATA },
|
||||
{ CF_TYPE_MODELS, "data" DIR_SEPARATOR_STR "models", ".pof", CF_TYPE_DATA },
|
||||
{ CF_TYPE_TABLES, "data" DIR_SEPARATOR_STR "tables", ".tbl .tbm", CF_TYPE_DATA },
|
||||
{ CF_TYPE_SOUNDS, "data" DIR_SEPARATOR_STR "sounds", ".wav .ogg", CF_TYPE_DATA },
|
||||
{ CF_TYPE_SOUNDS_8B22K, "data" DIR_SEPARATOR_STR "sounds" DIR_SEPARATOR_STR "8b22k", ".wav .ogg", CF_TYPE_SOUNDS },
|
||||
{ CF_TYPE_SOUNDS_16B11K, "data" DIR_SEPARATOR_STR "sounds" DIR_SEPARATOR_STR "16b11k", ".wav .ogg", CF_TYPE_SOUNDS },
|
||||
{ CF_TYPE_VOICE, "data" DIR_SEPARATOR_STR "voice", "", CF_TYPE_DATA },
|
||||
{ CF_TYPE_VOICE_BRIEFINGS, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "briefing", ".wav .ogg", CF_TYPE_VOICE },
|
||||
{ CF_TYPE_VOICE_CMD_BRIEF, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "command_briefings", ".wav .ogg", CF_TYPE_VOICE },
|
||||
{ CF_TYPE_VOICE_DEBRIEFINGS, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "debriefing", ".wav .ogg", CF_TYPE_VOICE },
|
||||
{ CF_TYPE_VOICE_PERSONAS, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "personas", ".wav .ogg", CF_TYPE_VOICE },
|
||||
{ CF_TYPE_VOICE_SPECIAL, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "special", ".wav .ogg", CF_TYPE_VOICE },
|
||||
{ CF_TYPE_VOICE_TRAINING, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "training", ".wav .ogg", CF_TYPE_VOICE },
|
||||
{ CF_TYPE_MUSIC, "data" DIR_SEPARATOR_STR "music", ".wav .ogg", CF_TYPE_DATA },
|
||||
{ CF_TYPE_MOVIES, "data" DIR_SEPARATOR_STR "movies", ".mve .msb .ogg .mp4 .srt .webm .png",CF_TYPE_DATA },
|
||||
{ CF_TYPE_INTERFACE, "data" DIR_SEPARATOR_STR "interface", ".pcx .ani .dds .tga .eff .png .jpg", CF_TYPE_DATA },
|
||||
{ CF_TYPE_FONT, "data" DIR_SEPARATOR_STR "fonts", ".vf .ttf", CF_TYPE_DATA },
|
||||
{ CF_TYPE_EFFECTS, "data" DIR_SEPARATOR_STR "effects", ".ani .eff .pcx .neb .tga .jpg .png .dds .sdr", CF_TYPE_DATA },
|
||||
{ CF_TYPE_HUD, "data" DIR_SEPARATOR_STR "hud", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
|
||||
{ CF_TYPE_PLAYERS, "data" DIR_SEPARATOR_STR "players", ".hcf", CF_TYPE_DATA },
|
||||
{ CF_TYPE_PLAYER_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "images", ".pcx .png .dds", CF_TYPE_PLAYERS },
|
||||
{ CF_TYPE_SQUAD_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "squads", ".pcx .png .dds", CF_TYPE_PLAYERS },
|
||||
{ CF_TYPE_SINGLE_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "single", ".pl2 .cs2 .plr .csg .css", CF_TYPE_PLAYERS },
|
||||
{ CF_TYPE_MULTI_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "multi", ".plr", CF_TYPE_PLAYERS },
|
||||
{ CF_TYPE_CACHE, "data" DIR_SEPARATOR_STR "cache", ".clr .tmp .bx", CF_TYPE_DATA }, //clr=cached color
|
||||
{ CF_TYPE_MULTI_CACHE, "data" DIR_SEPARATOR_STR "multidata", ".pcx .png .dds .fs2 .txt", CF_TYPE_DATA },
|
||||
{ CF_TYPE_MISSIONS, "data" DIR_SEPARATOR_STR "missions", ".fs2 .fc2 .ntl .ssv", CF_TYPE_DATA },
|
||||
{ CF_TYPE_CONFIG, "data" DIR_SEPARATOR_STR "config", ".cfg .tbl .tbm .xml .csv", CF_TYPE_DATA },
|
||||
{ CF_TYPE_DEMOS, "data" DIR_SEPARATOR_STR "demos", ".fsd", CF_TYPE_DATA },
|
||||
{ CF_TYPE_CBANIMS, "data" DIR_SEPARATOR_STR "cbanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
|
||||
{ CF_TYPE_INTEL_ANIMS, "data" DIR_SEPARATOR_STR "intelanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
|
||||
{ CF_TYPE_SCRIPTS, "data" DIR_SEPARATOR_STR "scripts", ".lua .lc", CF_TYPE_DATA },
|
||||
{ CF_TYPE_FICTION, "data" DIR_SEPARATOR_STR "fiction", ".txt", CF_TYPE_DATA },
|
||||
{ CF_TYPE_FREDDOCS, "data" DIR_SEPARATOR_STR "freddocs", ".html", CF_TYPE_DATA },
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
#define CFILE_STACK_MAX 8
|
||||
|
||||
@@ -230,14 +224,8 @@ int cfile_init(const char *exe_dir, const char *cdrom_dir)
|
||||
cfile_chdir(buf);
|
||||
|
||||
// set root directory
|
||||
strncpy(Cfile_root_dir, buf, CFILE_ROOT_DIRECTORY_LEN-1);
|
||||
strncpy(Cfile_user_dir, os_get_config_path().c_str(), CFILE_ROOT_DIRECTORY_LEN-1);
|
||||
|
||||
#ifdef SCP_UNIX
|
||||
// Initialize path of old pilot files
|
||||
extern const char* Osreg_user_dir_legacy;
|
||||
snprintf(Cfile_user_dir_legacy, CFILE_ROOT_DIRECTORY_LEN-1, "%s/%s/", getenv("HOME"), Osreg_user_dir_legacy);
|
||||
#endif
|
||||
strcpy_s(Cfile_root_dir, buf);
|
||||
strcpy_s(Cfile_user_dir, os_get_config_path().c_str());
|
||||
|
||||
for (i = 0; i < MAX_CFILE_BLOCKS; i++) {
|
||||
Cfile_block_list[i].type = CFILE_BLOCK_UNUSED;
|
||||
@@ -362,8 +350,7 @@ int cfile_push_chdir(int type)
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(Cfile_stack[Cfile_stack_pos++], OriginalDirectory,
|
||||
CFILE_ROOT_DIRECTORY_LEN - 1);
|
||||
strcpy_s(Cfile_stack[Cfile_stack_pos++], OriginalDirectory);
|
||||
|
||||
cf_create_default_path_string(dir, sizeof(dir) - 1, type, NULL);
|
||||
|
||||
@@ -486,17 +473,17 @@ char *cf_add_ext(const char *filename, const char *ext)
|
||||
*
|
||||
* @param filename Name of file to delete
|
||||
* @param path_type Path type (CF_TYPE_xxx)
|
||||
* @param location_flags Where to search for the location of the file to delete
|
||||
*
|
||||
* @return 0 on failure, 1 on success
|
||||
*/
|
||||
int cf_delete(const char *filename, int path_type)
|
||||
int cf_delete(const char *filename, int path_type, uint32_t location_flags)
|
||||
{
|
||||
char longname[MAX_PATH_LEN];
|
||||
|
||||
Assert(CF_TYPE_SPECIFIED(path_type));
|
||||
|
||||
cf_create_default_path_string(longname, sizeof(longname) - 1,
|
||||
path_type, filename);
|
||||
cf_create_default_path_string(longname, sizeof(longname) - 1, path_type, filename, false, location_flags);
|
||||
|
||||
return (_unlink(longname) != -1);
|
||||
}
|
||||
@@ -522,12 +509,12 @@ int cf_access(const char *filename, int dir_type, int mode)
|
||||
// If offset equates to boolean true, it was found in a VP and the logic will negate the function return
|
||||
int cf_exists(const char *filename, int dir_type)
|
||||
{
|
||||
size_t offset = 1;
|
||||
|
||||
if ( (filename == NULL) || !strlen(filename) )
|
||||
return 0;
|
||||
|
||||
return (cf_find_file_location(filename, dir_type, 0, NULL, NULL, &offset) && !offset);
|
||||
auto find_res = cf_find_file_location(filename, dir_type);
|
||||
|
||||
return find_res.found && !find_res.offset;
|
||||
}
|
||||
|
||||
// Goober5000
|
||||
@@ -538,7 +525,7 @@ int cf_exists_full(const char *filename, int dir_type)
|
||||
if ( (filename == NULL) || !strlen(filename) )
|
||||
return 0;
|
||||
|
||||
return cf_find_file_location(filename, dir_type, 0, NULL, NULL, NULL);
|
||||
return cf_find_file_location(filename, dir_type).found;
|
||||
}
|
||||
|
||||
// same as the above, but with extension check
|
||||
@@ -550,7 +537,7 @@ int cf_exists_full_ext(const char *filename, int dir_type, const int num_ext, co
|
||||
if ( (num_ext <= 0) || (ext_list == NULL) )
|
||||
return 0;
|
||||
|
||||
return (cf_find_file_location_ext(filename, num_ext, ext_list, dir_type, 0, NULL, NULL, NULL) != -1);
|
||||
return cf_find_file_location_ext(filename, num_ext, ext_list, dir_type).found;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -624,7 +611,7 @@ static void mkdir_recursive(const char *path) {
|
||||
|
||||
// Creates the directory path if it doesn't exist. Even creates all its
|
||||
// parent paths.
|
||||
void cf_create_directory( int dir_type )
|
||||
void cf_create_directory(int dir_type, uint32_t location_flags)
|
||||
{
|
||||
int num_dirs = 0;
|
||||
int dir_tree[CF_MAX_PATH_TYPES];
|
||||
@@ -646,7 +633,7 @@ void cf_create_directory( int dir_type )
|
||||
int i;
|
||||
|
||||
for (i=num_dirs-1; i>=0; i-- ) {
|
||||
cf_create_default_path_string( longname, sizeof(longname)-1, dir_tree[i], NULL );
|
||||
cf_create_default_path_string(longname, sizeof(longname) - 1, dir_tree[i], nullptr, false, location_flags);
|
||||
if (stat(longname, &statbuf) != 0) {
|
||||
mprintf(( "CFILE: Creating new directory '%s'\n", longname ));
|
||||
mkdir_recursive(longname);
|
||||
@@ -673,14 +660,13 @@ extern int game_cd_changed();
|
||||
// error ==> NULL
|
||||
//
|
||||
|
||||
CFILE *_cfopen(const char* source, int line, const char *file_path, const char *mode, int type, int dir_type, bool localize)
|
||||
CFILE* _cfopen(const char* source, int line, const char* file_path, const char* mode, int type, int dir_type,
|
||||
bool localize, uint32_t location_flags)
|
||||
{
|
||||
/* Bobboau, what is this doing here? 31 is way too short... - Goober5000
|
||||
if( strlen(file_path) > 31 )
|
||||
Error(LOCATION, "file name %s too long, \nmust be less than 31 charicters", file_path);*/
|
||||
|
||||
char longname[_MAX_PATH];
|
||||
|
||||
if ( !cfile_inited ) {
|
||||
Int3();
|
||||
return NULL;
|
||||
@@ -702,6 +688,8 @@ CFILE *_cfopen(const char* source, int line, const char *file_path, const char *
|
||||
// the harddisk. No fancy packfile stuff here!
|
||||
|
||||
if ( strchr(mode,'w') || strchr(mode,'+') || strchr(mode,'a') ) {
|
||||
char longname[_MAX_PATH];
|
||||
|
||||
// For write-only files, require a full path or a path type
|
||||
#ifdef SCP_UNIX
|
||||
if ( strpbrk(file_path, "/") ) {
|
||||
@@ -715,9 +703,9 @@ CFILE *_cfopen(const char* source, int line, const char *file_path, const char *
|
||||
Assert( dir_type != CF_TYPE_ANY );
|
||||
|
||||
// Create the directory if necessary
|
||||
cf_create_directory( dir_type );
|
||||
cf_create_directory(dir_type, location_flags);
|
||||
|
||||
cf_create_default_path_string( longname, sizeof(longname)-1, dir_type, file_path );
|
||||
cf_create_default_path_string(longname, sizeof(longname) - 1, dir_type, file_path, false, location_flags);
|
||||
}
|
||||
Assert( !(type & CFILE_MEMORY_MAPPED) );
|
||||
|
||||
@@ -767,30 +755,29 @@ CFILE *_cfopen(const char* source, int line, const char *file_path, const char *
|
||||
//================================================
|
||||
// Search for file on disk, on cdrom, or in a packfile
|
||||
|
||||
size_t offset, size;
|
||||
char copy_file_path[MAX_PATH_LEN]; // FIX change in memory from cf_find_file_location
|
||||
strcpy_s(copy_file_path, file_path);
|
||||
|
||||
const void* file_data = nullptr;
|
||||
if ( cf_find_file_location( copy_file_path, dir_type, sizeof(longname) - 1, longname, &size, &offset, localize, &file_data ) ) {
|
||||
auto find_res = cf_find_file_location( copy_file_path, dir_type, localize, location_flags );
|
||||
if ( find_res.found ) {
|
||||
|
||||
// Fount it, now create a cfile out of it
|
||||
nprintf(("CFileDebug", "Requested file %s found at: %s\n", file_path, longname));
|
||||
|
||||
nprintf(("CFileDebug", "Requested file %s found at: %s\n", file_path, find_res.full_name.c_str()));
|
||||
|
||||
if ( type & CFILE_MEMORY_MAPPED ) {
|
||||
|
||||
// Can't open memory mapped files out of pack or memory files
|
||||
if ( offset == 0 && file_data != nullptr ) {
|
||||
if ( find_res.offset == 0 && find_res.data_ptr != nullptr ) {
|
||||
#if defined _WIN32
|
||||
HANDLE hFile;
|
||||
|
||||
hFile = CreateFile(longname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
hFile = CreateFile(find_res.full_name.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (hFile != INVALID_HANDLE_VALUE) {
|
||||
return cf_open_mapped_fill_cfblock(source, line, hFile, dir_type);
|
||||
}
|
||||
#elif defined SCP_UNIX
|
||||
FILE *fp = fopen( longname, "rb" );
|
||||
FILE* fp = fopen(find_res.full_name.c_str(), "rb");
|
||||
if (fp) {
|
||||
return cf_open_mapped_fill_cfblock(source, line, fp, dir_type);
|
||||
}
|
||||
@@ -799,7 +786,8 @@ CFILE *_cfopen(const char* source, int line, const char *file_path, const char *
|
||||
|
||||
} else {
|
||||
// since cfopen_special already has all the code to handle the opening we can just use that here
|
||||
return _cfopen_special(source, line, longname, mode, size, offset, file_data, dir_type);
|
||||
return _cfopen_special(source, line, find_res.full_name.c_str(), mode, find_res.size, find_res.offset,
|
||||
find_res.data_ptr, dir_type);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -907,7 +895,7 @@ static int cfget_cfile_block()
|
||||
mprintf(("Out of cfile blocks! Currently opened files:\n"));
|
||||
dump_opened_files();
|
||||
|
||||
Assertion(false, "There are no more free cfile blocks. This means that there are too many files opened by FSO.\n"
|
||||
UNREACHABLE("There are no more free cfile blocks. This means that there are too many files opened by FSO.\n"
|
||||
"This is probably caused by a programming or scripting error where a file does not get closed."); // out of free cfile blocks
|
||||
return -1;
|
||||
}
|
||||
|
||||
+92
-13
@@ -95,6 +95,64 @@ typedef struct {
|
||||
#define CF_SORT_TIME 2
|
||||
#define CF_SORT_REVERSE 3
|
||||
|
||||
/**
|
||||
* @brief Contains a collection of flags for specifying from where a CFILE should be opened
|
||||
*
|
||||
* There are two types of flags. CF_LOCATION_GAME_ROOT and CF_LOCATION_USER_ROOT specify in which basic root directory
|
||||
* CFile should search for files.
|
||||
*
|
||||
* The remaining flags control what type of location may be used for the operation. It's possible to restrict the
|
||||
* location to the primary mod, the remaining mods or the top-level root directory.
|
||||
*/
|
||||
enum CFileLocationFlags {
|
||||
CF_LOCATION_ROOT_GAME = 1 << 0, //!< The game root location. This is the location of the game data (e.g. FS2 retail)
|
||||
/**
|
||||
* @brief The user directories.
|
||||
*
|
||||
* If the engine is in portable mode then using this flag exclusively will result in a failure to open files!
|
||||
*/
|
||||
CF_LOCATION_ROOT_USER = 1 << 1,
|
||||
|
||||
/**
|
||||
* @brief The memory root
|
||||
*
|
||||
* This contains all the built-in files available to the engine.
|
||||
*/
|
||||
CF_LOCATION_ROOT_MEMORY = 1 << 2,
|
||||
|
||||
/**
|
||||
* @brief Mask for extracting root type from a location bit field
|
||||
*/
|
||||
CF_LOCATION_ROOT_MASK = 0xFFFF,
|
||||
|
||||
CF_LOCATION_TYPE_ROOT = 1 << 16, //!< The basic, top-level root location
|
||||
/**
|
||||
* @brief The primary mod location.
|
||||
*
|
||||
* This is the mod that appears first on the command line. If there are no mods then the root location is considered
|
||||
* to be the primary mod
|
||||
*/
|
||||
CF_LOCATION_TYPE_PRIMARY_MOD = 1 << 17,
|
||||
/**
|
||||
* @brief The remaining mods.
|
||||
*
|
||||
* If there are no mods on the command line then this might not include any valid location.
|
||||
*/
|
||||
CF_LOCATION_TYPE_SECONDARY_MODS = 1 << 18,
|
||||
|
||||
/**
|
||||
* @brief Bitmask for extracting the type from a location bit field
|
||||
*/
|
||||
CF_LOCATION_TYPE_MASK = 0xFFFF0000,
|
||||
|
||||
/**
|
||||
* @brief A combination of all flags
|
||||
*
|
||||
* This should be used when the default behavior without any location filtering is desired.
|
||||
*/
|
||||
CF_LOCATION_ALL = CF_LOCATION_ROOT_MASK | CF_LOCATION_TYPE_MASK
|
||||
};
|
||||
|
||||
#define cfread_fix(file) (fix)cfread_int(file)
|
||||
#define cfwrite_fix(i,file) cfwrite_int(i,file)
|
||||
|
||||
@@ -111,9 +169,6 @@ extern const char *Get_file_list_child;
|
||||
#define CFILE_ROOT_DIRECTORY_LEN 256
|
||||
extern char Cfile_root_dir[CFILE_ROOT_DIRECTORY_LEN];
|
||||
extern char Cfile_user_dir[CFILE_ROOT_DIRECTORY_LEN];
|
||||
#ifdef SCP_UNIX
|
||||
extern char Cfile_user_dir_legacy[CFILE_ROOT_DIRECTORY_LEN];
|
||||
#endif
|
||||
|
||||
//================= LOW-LEVEL FUNCTIONS ==================
|
||||
int cfile_init(const char *exe_dir, const char *cdrom_dir=NULL);
|
||||
@@ -130,11 +185,10 @@ char *cf_add_ext(const char *filename, const char *ext);
|
||||
// return CF_TYPE (directory location type) of a CFILE you called cfopen() successfully on.
|
||||
int cf_get_dir_type(CFILE *cfile);
|
||||
|
||||
|
||||
// Opens the file. If no path is given, use the extension to look into the
|
||||
// default path. If mode is NULL, delete the file.
|
||||
CFILE *_cfopen(const char* source_file, int line, const char *filename, const char *mode,
|
||||
int type = CFILE_NORMAL, int dir_type = CF_TYPE_ANY, bool localize = false);
|
||||
// default path. If mode is NULL, delete the file.
|
||||
CFILE* _cfopen(const char* source_file, int line, const char* filename, const char* mode, int type = CFILE_NORMAL,
|
||||
int dir_type = CF_TYPE_ANY, bool localize = false, uint32_t location_flags = CF_LOCATION_ALL);
|
||||
#define cfopen(...) _cfopen(LOCATION, __VA_ARGS__) // Pass source location to the function
|
||||
|
||||
// like cfopen(), but it accepts a fully qualified path only (ie, the result of a cf_find_file_location() call)
|
||||
@@ -156,7 +210,7 @@ void cf_set_version( CFILE * cfile, int version );
|
||||
void cf_set_max_read_len(CFILE *cfile, size_t len);
|
||||
|
||||
// Deletes a file. Returns 0 on error, 1 if successful
|
||||
int cf_delete(const char *filename, int dir_type);
|
||||
int cf_delete(const char *filename, int dir_type, uint32_t location_flags = CF_LOCATION_ALL);
|
||||
|
||||
// Same as _access function to read a file's access bits
|
||||
int cf_access(const char *filename, int dir_type, int mode);
|
||||
@@ -311,12 +365,26 @@ int cfwrite_string(const char *buf, CFILE *file);
|
||||
*/
|
||||
int cfwrite_string_len(const char *buf, CFILE *file);
|
||||
|
||||
int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *filter, int sort = CF_SORT_NONE, SCP_vector<file_list_info> *info = NULL );
|
||||
int cf_get_file_list( int max, char **list, int type, const char *filter, int sort = CF_SORT_NONE, file_list_info *info = NULL );
|
||||
int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char **list, int type, const char *filter, int sort = CF_SORT_NONE, file_list_info *info = NULL );
|
||||
int cf_get_file_list(SCP_vector<SCP_string>& list, int pathtype, const char* filter, int sort = CF_SORT_NONE,
|
||||
SCP_vector<file_list_info>* info = nullptr, uint32_t location_flags = CF_LOCATION_ALL);
|
||||
int cf_get_file_list(int max, char** list, int type, const char* filter, int sort = CF_SORT_NONE,
|
||||
file_list_info* info = nullptr, uint32_t location_flags = CF_LOCATION_ALL);
|
||||
int cf_get_file_list_preallocated(int max, char arr[][MAX_FILENAME_LEN], char** list, int type, const char* filter,
|
||||
int sort = CF_SORT_NONE, file_list_info* info = nullptr,
|
||||
uint32_t location_flags = CF_LOCATION_ALL);
|
||||
void cf_sort_filenames( int n, char **list, int sort, file_list_info *info = NULL );
|
||||
void cf_sort_filenames( SCP_vector<SCP_string> &list, int sort, SCP_vector<file_list_info> *info = NULL );
|
||||
|
||||
struct CFileLocation {
|
||||
bool found = false;
|
||||
SCP_string full_name;
|
||||
size_t size = 0;
|
||||
size_t offset = 0;
|
||||
const void* data_ptr = nullptr;
|
||||
|
||||
explicit CFileLocation(bool found_in = false) : found(found_in) {}
|
||||
};
|
||||
|
||||
// Searches for a file. Follows all rules and precedence and searches
|
||||
// CD's and pack files.
|
||||
// Input: filespace - Filename & extension
|
||||
@@ -326,7 +394,17 @@ void cf_sort_filenames( SCP_vector<SCP_string> &list, int sort, SCP_vector<file_
|
||||
// size - File size
|
||||
// offset - Offset into pack file. 0 if not a packfile.
|
||||
// Returns: If not found returns 0.
|
||||
int cf_find_file_location( const char *filespec, int pathtype, int max_out, char *pack_filename, size_t *size, size_t *offset, bool localize = false, const void** data_out = nullptr);
|
||||
CFileLocation cf_find_file_location(const char* filespec, int pathtype, bool localize = false,
|
||||
uint32_t location_flags = CF_LOCATION_ALL);
|
||||
|
||||
struct CFileLocationExt : public CFileLocation {
|
||||
int extension_index = -1;
|
||||
|
||||
explicit CFileLocationExt(int extension_index_in = -1)
|
||||
: CFileLocation(extension_index_in >= 0), extension_index(extension_index_in)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Searches for a file. Follows all rules and precedence and searches
|
||||
// CD's and pack files. Searches all locations in order for first filename using ext filter list.
|
||||
@@ -340,7 +418,8 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
|
||||
// offset - Offset into pack file. 0 if not a packfile.
|
||||
// Returns: If not found returns -1, else returns offset into ext_list.
|
||||
// (NOTE: This function is exponentially slow, so don't use it unless truely needed!!)
|
||||
int cf_find_file_location_ext(const char *filename, const int ext_num, const char **ext_list, int pathtype, int max_out = 0, char *pack_filename = NULL, size_t *size = NULL, size_t *offset = NULL, bool localize = false, const void** data_out = nullptr);
|
||||
CFileLocationExt cf_find_file_location_ext(const char* filename, const int ext_num, const char** ext_list, int pathtype,
|
||||
bool localize = false);
|
||||
|
||||
// Functions to change directories
|
||||
int cfile_chdir(const char *dir);
|
||||
|
||||
+263
-209
@@ -48,9 +48,6 @@ enum CfileRootType {
|
||||
CF_ROOTTYPE_MEMORY = 2,
|
||||
};
|
||||
|
||||
// for a defined and specifically set location to get/send pilot/campaign files
|
||||
SCP_string Pilot_file_path;
|
||||
|
||||
// Created by:
|
||||
// specifying hard drive tree
|
||||
// searching for pack files on hard drive // Found by searching all known paths
|
||||
@@ -59,6 +56,7 @@ SCP_string Pilot_file_path;
|
||||
typedef struct cf_root {
|
||||
char path[CF_MAX_PATHNAME_LENGTH]; // Contains something like c:\projects\freespace or c:\projects\freespace\freespace.vp
|
||||
int roottype; // CF_ROOTTYPE_PATH = Path, CF_ROOTTYPE_PACK =Pack file, CF_ROOTTYPE_MEMORY=In memory
|
||||
uint32_t location_flags;
|
||||
} cf_root;
|
||||
|
||||
// convenient type for sorting (see cf_build_pack_list())
|
||||
@@ -347,9 +345,9 @@ void cf_build_pack_list( cf_root *root )
|
||||
std::sort(temp_roots_sort, temp_roots_sort + temp_root_count, cf_packfile_sort_func);
|
||||
|
||||
// now insert them all into the real root list properly
|
||||
cf_root *new_root;
|
||||
for (i = 0; i < temp_root_count; i++) {
|
||||
new_root = cf_create_root();
|
||||
auto new_root = cf_create_root();
|
||||
new_root->location_flags = root->location_flags;
|
||||
strcpy_s( new_root->path, root->path );
|
||||
|
||||
#ifndef NDEBUG
|
||||
@@ -378,10 +376,11 @@ static char normalize_directory_separator(char in)
|
||||
return in;
|
||||
}
|
||||
|
||||
static void cf_add_mod_roots(const char* rootDirectory)
|
||||
static void cf_add_mod_roots(const char* rootDirectory, uint32_t basic_location)
|
||||
{
|
||||
if (Cmdline_mod)
|
||||
{
|
||||
bool primary = true;
|
||||
for (const char* cur_pos=Cmdline_mod; strlen(cur_pos) != 0; cur_pos+= (strlen(cur_pos)+1))
|
||||
{
|
||||
SCP_stringstream ss;
|
||||
@@ -405,9 +404,16 @@ static void cf_add_mod_roots(const char* rootDirectory)
|
||||
cf_root* root = cf_create_root();
|
||||
|
||||
strncpy(root->path, rootPath.c_str(), CF_MAX_PATHNAME_LENGTH-1);
|
||||
if (primary) {
|
||||
root->location_flags = basic_location | CF_LOCATION_TYPE_PRIMARY_MOD;
|
||||
} else {
|
||||
root->location_flags = basic_location | CF_LOCATION_TYPE_SECONDARY_MODS;
|
||||
}
|
||||
|
||||
root->roottype = CF_ROOTTYPE_PATH;
|
||||
cf_build_pack_list(root);
|
||||
|
||||
primary = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -425,10 +431,16 @@ void cf_build_root_list(const char *cdrom_dir)
|
||||
#ifdef WIN32
|
||||
// Nothing to do here, Windows uses the current directory as the base
|
||||
#else
|
||||
cf_add_mod_roots(Cfile_user_dir_legacy);
|
||||
cf_add_mod_roots(os_get_legacy_user_dir(), CF_LOCATION_ROOT_USER);
|
||||
|
||||
root = cf_create_root();
|
||||
strncpy(root->path, Cfile_user_dir_legacy, CF_MAX_PATHNAME_LENGTH - 1);
|
||||
strncpy(root->path, os_get_legacy_user_dir(), CF_MAX_PATHNAME_LENGTH - 1);
|
||||
|
||||
root->location_flags |= CF_LOCATION_ROOT_USER | CF_LOCATION_TYPE_ROOT;
|
||||
if (Cmdline_mod == nullptr || strlen(Cmdline_mod) <= 0) {
|
||||
// If there are no mods then the root is the primary mod
|
||||
root->location_flags |= CF_LOCATION_TYPE_PRIMARY_MOD;
|
||||
}
|
||||
|
||||
// do we already have a slash? as in the case of a root directory install
|
||||
if ((strlen(root->path) < (CF_MAX_PATHNAME_LENGTH - 1)) && (root->path[strlen(root->path) - 1] != DIR_SEPARATOR_CHAR)) {
|
||||
@@ -436,10 +448,6 @@ void cf_build_root_list(const char *cdrom_dir)
|
||||
}
|
||||
root->roottype = CF_ROOTTYPE_PATH;
|
||||
|
||||
// If it wasn't set before, set the pilot path
|
||||
if (Pilot_file_path.empty())
|
||||
Pilot_file_path = root->path;
|
||||
|
||||
// Next, check any VP files under the current directory.
|
||||
cf_build_pack_list(root);
|
||||
#endif
|
||||
@@ -449,13 +457,19 @@ void cf_build_root_list(const char *cdrom_dir)
|
||||
{
|
||||
// =========================================================================
|
||||
// now look for mods under the users HOME directory to use before system ones
|
||||
cf_add_mod_roots(Cfile_user_dir);
|
||||
cf_add_mod_roots(Cfile_user_dir, CF_LOCATION_ROOT_USER);
|
||||
// =========================================================================
|
||||
|
||||
// =========================================================================
|
||||
// set users HOME directory as default for loading and saving files
|
||||
root = cf_create_root();
|
||||
strncpy(root->path, Cfile_user_dir, CF_MAX_PATHNAME_LENGTH - 1);
|
||||
strcpy_s(root->path, Cfile_user_dir);
|
||||
|
||||
root->location_flags |= CF_LOCATION_ROOT_USER | CF_LOCATION_TYPE_ROOT;
|
||||
if (Cmdline_mod == nullptr || strlen(Cmdline_mod) <= 0) {
|
||||
// If there are no mods then the root is the primary mod
|
||||
root->location_flags |= CF_LOCATION_TYPE_PRIMARY_MOD;
|
||||
}
|
||||
|
||||
// do we already have a slash? as in the case of a root directory install
|
||||
if ((strlen(root->path) < (CF_MAX_PATHNAME_LENGTH - 1)) && (root->path[strlen(root->path) - 1] != DIR_SEPARATOR_CHAR)) {
|
||||
@@ -463,10 +477,6 @@ void cf_build_root_list(const char *cdrom_dir)
|
||||
}
|
||||
root->roottype = CF_ROOTTYPE_PATH;
|
||||
|
||||
// set the default player location to here
|
||||
if (Pilot_file_path.empty())
|
||||
Pilot_file_path = root->path;
|
||||
|
||||
// Next, check any VP files under the current directory.
|
||||
cf_build_pack_list(root);
|
||||
// =========================================================================
|
||||
@@ -477,11 +487,17 @@ void cf_build_root_list(const char *cdrom_dir)
|
||||
if ( !_getcwd(working_directory, CF_MAX_PATHNAME_LENGTH ) ) {
|
||||
Error(LOCATION, "Can't get current working directory -- %d", errno );
|
||||
}
|
||||
|
||||
cf_add_mod_roots(working_directory);
|
||||
|
||||
cf_add_mod_roots(working_directory, CF_LOCATION_ROOT_GAME);
|
||||
|
||||
root = cf_create_root();
|
||||
|
||||
|
||||
root->location_flags |= CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT;
|
||||
if (Cmdline_mod == nullptr || strlen(Cmdline_mod) <= 0) {
|
||||
// If there are no mods then the root is the primary mod
|
||||
root->location_flags |= CF_LOCATION_TYPE_PRIMARY_MOD;
|
||||
}
|
||||
|
||||
strcpy_s(root->path, working_directory);
|
||||
|
||||
size_t path_len = strlen(root->path);
|
||||
@@ -493,10 +509,6 @@ void cf_build_root_list(const char *cdrom_dir)
|
||||
|
||||
root->roottype = CF_ROOTTYPE_PATH;
|
||||
|
||||
// If the path wasn't set before use the working directory
|
||||
if ( Pilot_file_path.empty() )
|
||||
Pilot_file_path = root->path;
|
||||
|
||||
//======================================================
|
||||
// Next, check any VP files under the current directory.
|
||||
cf_build_pack_list(root);
|
||||
@@ -517,6 +529,7 @@ void cf_build_root_list(const char *cdrom_dir)
|
||||
|
||||
// The final root is the in-memory root
|
||||
root = cf_create_root();
|
||||
root->location_flags = CF_LOCATION_ROOT_MEMORY | CF_LOCATION_TYPE_ROOT;
|
||||
memset(root->path, 0, sizeof(root->path));
|
||||
root->roottype = CF_ROOTTYPE_MEMORY;
|
||||
|
||||
@@ -977,15 +990,12 @@ void cf_free_secondary_filelist()
|
||||
*
|
||||
* @param filespec Filename & extension
|
||||
* @param pathtype See CF_TYPE_ defines in CFILE.H
|
||||
* @param max_out Maximum string length that should be stuffed into pack_filename
|
||||
* @param pack_filename OUTPUT: Absolute path and filename of this file. Could be a packfile or the actual file.
|
||||
* @param size OUTPUT: File size
|
||||
* @param offset OUTPUT: Offset into pack file. 0 if not a packfile.
|
||||
* @param localize Undertake localization
|
||||
* @param location_flags Specifies where to search for the specified flag
|
||||
*
|
||||
* @return If not found returns 0.
|
||||
* @return A structure which describes the found file
|
||||
*/
|
||||
int cf_find_file_location( const char *filespec, int pathtype, int max_out, char *pack_filename, size_t *size, size_t *offset, bool localize, const void** data_out )
|
||||
CFileLocation cf_find_file_location(const char* filespec, int pathtype, bool localize, uint32_t location_flags)
|
||||
{
|
||||
int i;
|
||||
uint ui;
|
||||
@@ -993,7 +1003,6 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
|
||||
char longname[MAX_PATH_LEN];
|
||||
|
||||
Assert( (filespec != NULL) && (strlen(filespec) > 0) ); //-V805
|
||||
Assert( (pack_filename == NULL) || (max_out > 1) );
|
||||
|
||||
// see if we have something other than just a filename
|
||||
// our current rules say that any file that specifies a direct
|
||||
@@ -1009,16 +1018,15 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
|
||||
#endif
|
||||
FILE *fp = fopen(filespec, "rb" );
|
||||
if (fp) {
|
||||
if ( size ) *size = filelength(fileno(fp));
|
||||
if ( offset ) *offset = 0;
|
||||
if ( pack_filename ) {
|
||||
strncpy( pack_filename, filespec, max_out );
|
||||
}
|
||||
CFileLocation res(true);
|
||||
res.size = static_cast<size_t>(filelength(fileno(fp)));
|
||||
res.offset = 0;
|
||||
res.full_name = filespec;
|
||||
fclose(fp);
|
||||
return 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0; // If they give a full path, fail if not found.
|
||||
return CFileLocation(); // If they give a full path, fail if not found.
|
||||
}
|
||||
|
||||
// Search the hard drive for files first.
|
||||
@@ -1057,43 +1065,39 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
|
||||
}
|
||||
|
||||
if (cfs_slow_search) {
|
||||
cf_create_default_path_string( longname, sizeof(longname)-1, search_order[ui], filespec, localize );
|
||||
cf_create_default_path_string(longname, sizeof(longname) - 1, search_order[ui], filespec, localize,
|
||||
location_flags);
|
||||
|
||||
#if defined _WIN32
|
||||
_finddata_t findstruct;
|
||||
|
||||
intptr_t findhandle = _findfirst(longname, &findstruct);
|
||||
if (findhandle != -1) {
|
||||
if (size)
|
||||
*size = findstruct.size;
|
||||
CFileLocation res;
|
||||
res.found = true;
|
||||
res.size = static_cast<size_t>(findstruct.size);
|
||||
|
||||
_findclose(findhandle);
|
||||
|
||||
if (offset)
|
||||
*offset = 0;
|
||||
res.offset = 0;
|
||||
res.full_name = longname;
|
||||
|
||||
if (pack_filename)
|
||||
strncpy( pack_filename, longname, max_out );
|
||||
|
||||
return 1;
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
{
|
||||
FILE *fp = fopen(longname, "rb" );
|
||||
|
||||
if (fp) {
|
||||
if (size)
|
||||
*size = filelength( fileno(fp) );
|
||||
CFileLocation res(true);
|
||||
res.size = static_cast<size_t>(filelength( fileno(fp) ));
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if (offset)
|
||||
*offset = 0;
|
||||
res.offset = 0;
|
||||
res.full_name = longname;
|
||||
|
||||
if (pack_filename)
|
||||
strncpy(pack_filename, longname, max_out);
|
||||
|
||||
return 1;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1107,6 +1111,15 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
|
||||
if ( (pathtype != CF_TYPE_ANY) && (pathtype != f->pathtype_index) )
|
||||
continue;
|
||||
|
||||
if (location_flags != CF_LOCATION_ALL) {
|
||||
// If a location flag was specified we need to check if the root of this file satisfies the request
|
||||
auto root = cf_get_root(f->root_index);
|
||||
|
||||
if (!cf_check_location_flags(root->location_flags, location_flags)) {
|
||||
// Root does not satisfy location flags
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (localize) {
|
||||
// create localized filespec
|
||||
@@ -1114,70 +1127,58 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
|
||||
|
||||
if ( lcl_add_dir_to_path_with_filename(longname, MAX_PATH_LEN - 1) ) {
|
||||
if ( !stricmp(longname, f->name_ext) ) {
|
||||
if (size)
|
||||
*size = f->size;
|
||||
CFileLocation res(true);
|
||||
res.size = static_cast<size_t>(f->size);
|
||||
res.offset = (size_t)f->pack_offset;
|
||||
res.data_ptr = f->data;
|
||||
|
||||
if (offset)
|
||||
*offset = (size_t)f->pack_offset;
|
||||
if (f->data != nullptr) {
|
||||
// This is an in-memory file so we just copy the pathtype name + file name
|
||||
res.full_name = Pathtypes[f->pathtype_index].path;
|
||||
res.full_name += DIR_SEPARATOR_STR;
|
||||
res.full_name += f->name_ext;
|
||||
} else if (f->pack_offset < 1) {
|
||||
// This is a real file, return the actual file path
|
||||
res.full_name = f->real_name;
|
||||
} else {
|
||||
// File is in a pack file
|
||||
cf_root *r = cf_get_root(f->root_index);
|
||||
|
||||
if (data_out)
|
||||
*data_out = f->data;
|
||||
|
||||
if (pack_filename) {
|
||||
if (f->data != nullptr) {
|
||||
// This is an in-memory file so we just copy the pathtype name + file name
|
||||
strncpy(pack_filename, Pathtypes[f->pathtype_index].path, max_out);
|
||||
strncat(pack_filename, DIR_SEPARATOR_STR, max_out);
|
||||
strncat(pack_filename, f->name_ext, max_out);
|
||||
} else if (f->pack_offset < 1) {
|
||||
// This is a real file, return the actual file path
|
||||
strncpy( pack_filename, f->real_name, max_out );
|
||||
} else {
|
||||
// File is in a pack file
|
||||
cf_root *r = cf_get_root(f->root_index);
|
||||
|
||||
strncpy( pack_filename, r->path, max_out );
|
||||
}
|
||||
res.full_name = r->path;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// file either not localized or localized version not found
|
||||
if ( !stricmp(filespec, f->name_ext) ) {
|
||||
if (size)
|
||||
*size = f->size;
|
||||
CFileLocation res(true);
|
||||
res.size = static_cast<size_t>(f->size);
|
||||
res.offset = (size_t)f->pack_offset;
|
||||
res.data_ptr = f->data;
|
||||
|
||||
if (offset)
|
||||
*offset = (size_t)f->pack_offset;
|
||||
if (f->data != nullptr) {
|
||||
// This is an in-memory file so we just copy the pathtype name + file name
|
||||
res.full_name = Pathtypes[f->pathtype_index].path;
|
||||
res.full_name += DIR_SEPARATOR_STR;
|
||||
res.full_name += f->name_ext;
|
||||
} else if (f->pack_offset < 1) {
|
||||
// This is a real file, return the actual file path
|
||||
res.full_name = f->real_name;
|
||||
} else {
|
||||
// File is in a pack file
|
||||
cf_root *r = cf_get_root(f->root_index);
|
||||
|
||||
if (data_out)
|
||||
*data_out = f->data;
|
||||
|
||||
if (pack_filename) {
|
||||
if (f->data != nullptr) {
|
||||
// This is an in-memory file so we just copy the pathtype name + file name
|
||||
strncpy(pack_filename, Pathtypes[f->pathtype_index].path, max_out);
|
||||
strncat(pack_filename, DIR_SEPARATOR_STR, max_out);
|
||||
strncat(pack_filename, f->name_ext, max_out);
|
||||
} else if (f->pack_offset < 1) {
|
||||
// This is a real file, return the actual file path
|
||||
strncpy( pack_filename, f->real_name, max_out );
|
||||
} else {
|
||||
// File is in a pack file
|
||||
cf_root *r = cf_get_root(f->root_index);
|
||||
|
||||
strncpy( pack_filename, r->path, max_out );
|
||||
}
|
||||
res.full_name = r->path;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return CFileLocation();
|
||||
}
|
||||
|
||||
// -- from parselo.cpp --
|
||||
@@ -1194,14 +1195,11 @@ extern char *stristr(char *str, const char *substr);
|
||||
* @param ext_list Extension filter list
|
||||
* @param pathtype See CF_TYPE_ defines in CFILE.H
|
||||
* @param max_out Maximum string length that should be stuffed into pack_filename
|
||||
* @param pack_filename OUTPUT: Absolute path and filename of this file. Could be a packfile or the actual file.
|
||||
* @param size OUTPUT: File size
|
||||
* @param offset OUTPUT: Offset into pack file. 0 if not a packfile.
|
||||
* @param localize Undertake localization
|
||||
*
|
||||
* @return If not found returns -1, else returns offset into ext_list.
|
||||
* @return A structure containing information about the found file
|
||||
*/
|
||||
int cf_find_file_location_ext( const char *filename, const int ext_num, const char **ext_list, int pathtype, int max_out, char *pack_filename, size_t *size, size_t *offset, bool localize, const void** data_out)
|
||||
CFileLocationExt cf_find_file_location_ext( const char *filename, const int ext_num, const char **ext_list, int pathtype, bool localize)
|
||||
{
|
||||
int cur_ext, i;
|
||||
uint ui;
|
||||
@@ -1213,7 +1211,6 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
|
||||
Assert( (filename != NULL) && (strlen(filename) < MAX_FILENAME_LEN) );
|
||||
Assert( (ext_list != NULL) && (ext_num > 1) ); // if we are searching for just one ext
|
||||
// then this is the wrong function to use
|
||||
Assert( (pack_filename == NULL) || (max_out > 1) );
|
||||
|
||||
|
||||
// if we have a full path already then fail. this function if for searching via filter only!
|
||||
@@ -1223,7 +1220,7 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
|
||||
if ( strpbrk(filename,"/\\:") ) { // do we have a full path already?
|
||||
#endif
|
||||
Int3();
|
||||
return 0;
|
||||
return CFileLocationExt();
|
||||
}
|
||||
|
||||
// Search the hard drive for files first.
|
||||
@@ -1281,44 +1278,35 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
|
||||
|
||||
#if defined _WIN32
|
||||
_finddata_t findstruct;
|
||||
|
||||
intptr_t findhandle = _findfirst(longname, &findstruct);
|
||||
if (findhandle != -1) {
|
||||
if (size)
|
||||
*size = findstruct.size;
|
||||
|
||||
if (data_out)
|
||||
*data_out = nullptr;
|
||||
CFileLocationExt res(cur_ext);
|
||||
res.found = true;
|
||||
res.size = static_cast<size_t>(findstruct.size);
|
||||
|
||||
_findclose(findhandle);
|
||||
|
||||
if (offset)
|
||||
*offset = 0;
|
||||
res.offset = 0;
|
||||
res.full_name = longname;
|
||||
|
||||
if (pack_filename)
|
||||
strncpy( pack_filename, longname, max_out );
|
||||
|
||||
return cur_ext;
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
{
|
||||
FILE *fp = fopen(longname, "rb" );
|
||||
|
||||
if (fp) {
|
||||
if (size)
|
||||
*size = filelength( fileno(fp) );
|
||||
|
||||
if (data_out)
|
||||
*data_out = nullptr;
|
||||
CFileLocationExt res(cur_ext);
|
||||
res.found = true;
|
||||
res.size = static_cast<size_t>(filelength( fileno(fp) ));
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if (offset)
|
||||
*offset = 0;
|
||||
res.offset = 0;
|
||||
res.full_name = longname;
|
||||
|
||||
if (pack_filename)
|
||||
strncpy(pack_filename, longname, max_out);
|
||||
|
||||
return cur_ext;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1403,76 +1391,62 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
|
||||
|
||||
if ( lcl_add_dir_to_path_with_filename(longname, MAX_PATH_LEN - 1) ) {
|
||||
if ( !stricmp(longname, f->name_ext) ) {
|
||||
if (size)
|
||||
*size = f->size;
|
||||
CFileLocationExt res(cur_ext);
|
||||
res.found = true;
|
||||
res.size = static_cast<size_t>(f->size);
|
||||
res.offset = (size_t)f->pack_offset;
|
||||
res.data_ptr = f->data;
|
||||
|
||||
if (offset)
|
||||
*offset = f->pack_offset;
|
||||
if (f->data != nullptr) {
|
||||
// This is an in-memory file so we just copy the pathtype name + file name
|
||||
res.full_name = Pathtypes[f->pathtype_index].path;
|
||||
res.full_name += DIR_SEPARATOR_STR;
|
||||
res.full_name += f->name_ext;
|
||||
} else if (f->pack_offset < 1) {
|
||||
// This is a real file, return the actual file path
|
||||
res.full_name = f->real_name;
|
||||
} else {
|
||||
// File is in a pack file
|
||||
cf_root *r = cf_get_root(f->root_index);
|
||||
|
||||
if (data_out)
|
||||
*data_out = f->data;
|
||||
|
||||
if (pack_filename) {
|
||||
if (f->data != nullptr) {
|
||||
// This is an in-memory file so we just copy the pathtype name + file name
|
||||
strncpy(pack_filename, Pathtypes[f->pathtype_index].path, max_out);
|
||||
strncat(pack_filename, DIR_SEPARATOR_STR, max_out);
|
||||
strncat(pack_filename, f->name_ext, max_out);
|
||||
}
|
||||
else if (f->pack_offset < 1) {
|
||||
// This is a real file, return the actual file path
|
||||
strncpy(pack_filename, f->real_name, max_out);
|
||||
}
|
||||
else {
|
||||
// File is in a pack file
|
||||
cf_root *r = cf_get_root(f->root_index);
|
||||
|
||||
strncpy(pack_filename, r->path, max_out);
|
||||
}
|
||||
res.full_name = r->path;
|
||||
}
|
||||
|
||||
// found it, so cleanup and return
|
||||
file_list_index.clear();
|
||||
|
||||
return cur_ext;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// file either not localized or localized version not found
|
||||
if ( !stricmp(filespec, f->name_ext) ) {
|
||||
if (size)
|
||||
*size = f->size;
|
||||
CFileLocationExt res(cur_ext);
|
||||
res.found = true;
|
||||
res.size = static_cast<size_t>(f->size);
|
||||
res.offset = (size_t)f->pack_offset;
|
||||
res.data_ptr = f->data;
|
||||
|
||||
if (offset)
|
||||
*offset = f->pack_offset;
|
||||
if (f->data != nullptr) {
|
||||
// This is an in-memory file so we just copy the pathtype name + file name
|
||||
res.full_name = Pathtypes[f->pathtype_index].path;
|
||||
res.full_name += DIR_SEPARATOR_STR;
|
||||
res.full_name += f->name_ext;
|
||||
} else if (f->pack_offset < 1) {
|
||||
// This is a real file, return the actual file path
|
||||
res.full_name = f->real_name;
|
||||
} else {
|
||||
// File is in a pack file
|
||||
cf_root *r = cf_get_root(f->root_index);
|
||||
|
||||
if (data_out)
|
||||
*data_out = f->data;
|
||||
|
||||
if (pack_filename) {
|
||||
if (f->data != nullptr) {
|
||||
// This is an in-memory file so we just copy the pathtype name + file name
|
||||
strncpy(pack_filename, Pathtypes[f->pathtype_index].path, max_out);
|
||||
strncat(pack_filename, DIR_SEPARATOR_STR, max_out);
|
||||
strncat(pack_filename, f->name_ext, max_out);
|
||||
}
|
||||
else if (f->pack_offset < 1) {
|
||||
// This is a real file, return the actual file path
|
||||
strncpy(pack_filename, f->real_name, max_out);
|
||||
}
|
||||
else {
|
||||
// File is in a pack file
|
||||
cf_root *r = cf_get_root(f->root_index);
|
||||
|
||||
strncpy(pack_filename, r->path, max_out);
|
||||
}
|
||||
res.full_name = r->path;
|
||||
}
|
||||
|
||||
// found it, so cleanup and return
|
||||
file_list_index.clear();
|
||||
|
||||
return cur_ext;
|
||||
return res;
|
||||
}
|
||||
|
||||
// ok, we're still here, so strip off the extension again in order to
|
||||
@@ -1483,7 +1457,7 @@ int cf_find_file_location_ext( const char *filename, const int ext_num, const ch
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
return CFileLocationExt();
|
||||
}
|
||||
|
||||
|
||||
@@ -1582,7 +1556,8 @@ static int cf_file_already_in_list( SCP_vector<SCP_string> &list, const char *fi
|
||||
// This one has a 'type', which is a CF_TYPE_* value. Because this specifies the directory
|
||||
// location, 'filter' only needs to be the filter itself, with no path information.
|
||||
// See above descriptions of cf_get_file_list() for more information about how it all works.
|
||||
int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *filter, int sort, SCP_vector<file_list_info> *info )
|
||||
int cf_get_file_list(SCP_vector<SCP_string>& list, int pathtype, const char* filter, int sort,
|
||||
SCP_vector<file_list_info>* info, uint32_t location_flags)
|
||||
{
|
||||
char *ptr;
|
||||
uint i;
|
||||
@@ -1610,7 +1585,8 @@ int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *fi
|
||||
}
|
||||
|
||||
#if defined _WIN32
|
||||
cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, (char*)Get_file_list_child );
|
||||
cf_create_default_path_string(filespec, sizeof(filespec) - 1, pathtype, (char*)Get_file_list_child, false,
|
||||
location_flags);
|
||||
strcat_s(filespec, DIR_SEPARATOR_STR);
|
||||
strcat_s(filespec, filter);
|
||||
|
||||
@@ -1650,7 +1626,8 @@ int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *fi
|
||||
}
|
||||
|
||||
#elif defined SCP_UNIX
|
||||
cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, (char*)Get_file_list_child );
|
||||
cf_create_default_path_string(filespec, sizeof(filespec) - 1, pathtype, (char*)Get_file_list_child, false,
|
||||
location_flags);
|
||||
|
||||
DIR *dirp;
|
||||
struct dirent *dir;
|
||||
@@ -1718,6 +1695,16 @@ int cf_get_file_list( SCP_vector<SCP_string> &list, int pathtype, const char *fi
|
||||
continue;
|
||||
}
|
||||
|
||||
if (location_flags != CF_LOCATION_ALL) {
|
||||
// If a location flag was specified we need to check if the root of this file satisfies the request
|
||||
auto root = cf_get_root(f->root_index);
|
||||
|
||||
if (!cf_check_location_flags(root->location_flags, location_flags)) {
|
||||
// Root does not satisfy location flags
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !cf_matches_spec( filter,f->name_ext)) {
|
||||
continue;
|
||||
}
|
||||
@@ -1795,7 +1782,8 @@ int cf_file_already_in_list( int num_files, char **list, const char *filename )
|
||||
// This one has a 'type', which is a CF_TYPE_* value. Because this specifies the directory
|
||||
// location, 'filter' only needs to be the filter itself, with no path information.
|
||||
// See above descriptions of cf_get_file_list() for more information about how it all works.
|
||||
int cf_get_file_list( int max, char **list, int pathtype, const char *filter, int sort, file_list_info *info )
|
||||
int cf_get_file_list(int max, char** list, int pathtype, const char* filter, int sort, file_list_info* info,
|
||||
uint32_t location_flags)
|
||||
{
|
||||
char *ptr;
|
||||
uint i;
|
||||
@@ -1818,7 +1806,7 @@ int cf_get_file_list( int max, char **list, int pathtype, const char *filter, in
|
||||
char filespec[MAX_PATH_LEN];
|
||||
|
||||
#if defined _WIN32
|
||||
cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, filter );
|
||||
cf_create_default_path_string(filespec, sizeof(filespec) - 1, pathtype, filter, false, location_flags);
|
||||
|
||||
_finddata_t find;
|
||||
intptr_t find_handle;
|
||||
@@ -1859,7 +1847,7 @@ int cf_get_file_list( int max, char **list, int pathtype, const char *filter, in
|
||||
}
|
||||
|
||||
#elif defined SCP_UNIX
|
||||
cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, NULL );
|
||||
cf_create_default_path_string(filespec, sizeof(filespec) - 1, pathtype, nullptr, false, location_flags);
|
||||
|
||||
DIR *dirp;
|
||||
struct dirent *dir;
|
||||
@@ -1932,6 +1920,16 @@ int cf_get_file_list( int max, char **list, int pathtype, const char *filter, in
|
||||
continue;
|
||||
}
|
||||
|
||||
if (location_flags != CF_LOCATION_ALL) {
|
||||
// If a location flag was specified we need to check if the root of this file satisfies the request
|
||||
auto root = cf_get_root(f->root_index);
|
||||
|
||||
if (!cf_check_location_flags(root->location_flags, location_flags)) {
|
||||
// Root does not satisfy location flags
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_files >= max)
|
||||
break;
|
||||
|
||||
@@ -2015,7 +2013,8 @@ int cf_file_already_in_list_preallocated( int num_files, char arr[][MAX_FILENAME
|
||||
// This one has a 'type', which is a CF_TYPE_* value. Because this specifies the directory
|
||||
// location, 'filter' only needs to be the filter itself, with no path information.
|
||||
// See above descriptions of cf_get_file_list() for more information about how it all works.
|
||||
int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char **list, int pathtype, const char *filter, int sort, file_list_info *info )
|
||||
int cf_get_file_list_preallocated(int max, char arr[][MAX_FILENAME_LEN], char** list, int pathtype, const char* filter,
|
||||
int sort, file_list_info* info, uint32_t location_flags)
|
||||
{
|
||||
int num_files = 0, own_flag = 0;
|
||||
|
||||
@@ -2044,7 +2043,7 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
|
||||
|
||||
// Search the default directories
|
||||
#if defined _WIN32
|
||||
cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, filter );
|
||||
cf_create_default_path_string(filespec, sizeof(filespec) - 1, pathtype, filter, false, location_flags);
|
||||
|
||||
intptr_t find_handle;
|
||||
_finddata_t find;
|
||||
@@ -2085,7 +2084,7 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
|
||||
}
|
||||
|
||||
#elif defined SCP_UNIX
|
||||
cf_create_default_path_string( filespec, sizeof(filespec)-1, pathtype, NULL );
|
||||
cf_create_default_path_string(filespec, sizeof(filespec) - 1, pathtype, nullptr, false, location_flags);
|
||||
|
||||
DIR *dirp;
|
||||
struct dirent *dir;
|
||||
@@ -2121,7 +2120,7 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
|
||||
|
||||
if ( !Get_file_list_filter || (*Get_file_list_filter)(dir->d_name) ) {
|
||||
|
||||
strncpy(arr[num_files], dir->d_name, MAX_FILENAME_LEN - 1 );
|
||||
strcpy_s(arr[num_files], dir->d_name );
|
||||
char *ptr = strrchr(arr[num_files], '.');
|
||||
if ( ptr ) {
|
||||
*ptr = 0;
|
||||
@@ -2156,6 +2155,16 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
|
||||
continue;
|
||||
}
|
||||
|
||||
if (location_flags != CF_LOCATION_ALL) {
|
||||
// If a location flag was specified we need to check if the root of this file satisfies the request
|
||||
auto root = cf_get_root(f->root_index);
|
||||
|
||||
if (!cf_check_location_flags(root->location_flags, location_flags)) {
|
||||
// Root does not satisfy location flags
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_files >= max)
|
||||
|
||||
break;
|
||||
@@ -2222,7 +2231,8 @@ int cf_get_file_list_preallocated( int max, char arr[][MAX_FILENAME_LEN], char *
|
||||
// filename - optional, if set, tacks the filename onto end of path.
|
||||
// Output: path - Fully qualified pathname.
|
||||
//Returns 0 if the result would be too long (invalid result)
|
||||
int cf_create_default_path_string(char *path, uint path_max, int pathtype, const char *filename, bool localize )
|
||||
int cf_create_default_path_string(char* path, uint path_max, int pathtype, const char* filename, bool localize,
|
||||
uint32_t location_flags)
|
||||
{
|
||||
#ifdef SCP_UNIX
|
||||
if ( filename && strpbrk(filename,"/") ) {
|
||||
@@ -2233,7 +2243,22 @@ int cf_create_default_path_string(char *path, uint path_max, int pathtype, const
|
||||
strncpy( path, filename, path_max );
|
||||
|
||||
} else {
|
||||
cf_root *root = cf_get_root(0);
|
||||
cf_root* root = nullptr;
|
||||
|
||||
for (auto i = 0; i < Num_roots; ++i) {
|
||||
auto current_root = cf_get_root(i);
|
||||
|
||||
if (current_root->roottype != CF_ROOTTYPE_PATH) {
|
||||
// We want a "real" path here so only path roots are valid
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cf_check_location_flags(current_root->location_flags, location_flags)) {
|
||||
// We found a valid root
|
||||
root = current_root;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!root) {
|
||||
Assert( filename != NULL );
|
||||
@@ -2243,12 +2268,7 @@ int cf_create_default_path_string(char *path, uint path_max, int pathtype, const
|
||||
|
||||
Assert(CF_TYPE_SPECIFIED(pathtype));
|
||||
|
||||
// force a specific directory to search for player files
|
||||
if ( (pathtype == CF_TYPE_PLAYERS) || (pathtype == CF_TYPE_SINGLE_PLAYERS) || (pathtype == CF_TYPE_MULTI_PLAYERS) ) {
|
||||
strncpy(path, Pilot_file_path.c_str(), path_max);
|
||||
} else {
|
||||
strncpy(path, root->path, path_max);
|
||||
}
|
||||
strncpy(path, root->path, path_max);
|
||||
|
||||
strcat_s(path, path_max, Pathtypes[pathtype].path);
|
||||
|
||||
@@ -2294,7 +2314,8 @@ int cf_create_default_path_string(char *path, uint path_max, int pathtype, const
|
||||
// filename - optional, if set, tacks the filename onto end of path.
|
||||
// Output: path - Fully qualified pathname.
|
||||
//Returns 0 if the result would be too long (invalid result)
|
||||
int cf_create_default_path_string( SCP_string &path, int pathtype, const char *filename, bool /*localize*/ )
|
||||
int cf_create_default_path_string(SCP_string& path, int pathtype, const char* filename, bool /*localize*/,
|
||||
uint32_t location_flags)
|
||||
{
|
||||
#ifdef SCP_UNIX
|
||||
if ( filename && strpbrk(filename,"/") ) {
|
||||
@@ -2305,7 +2326,22 @@ int cf_create_default_path_string( SCP_string &path, int pathtype, const char *f
|
||||
path.assign(filename);
|
||||
|
||||
} else {
|
||||
cf_root *root = cf_get_root(0);
|
||||
cf_root* root = nullptr;
|
||||
|
||||
for (auto i = 0; i < Num_roots; ++i) {
|
||||
auto current_root = cf_get_root(i);
|
||||
|
||||
if (current_root->roottype != CF_ROOTTYPE_PATH) {
|
||||
// We want a "real" path here so only path roots are valid
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cf_check_location_flags(current_root->location_flags, location_flags)) {
|
||||
// We found a valid root
|
||||
root = current_root;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!root) {
|
||||
Assert( filename != NULL );
|
||||
@@ -2316,12 +2352,7 @@ int cf_create_default_path_string( SCP_string &path, int pathtype, const char *f
|
||||
Assert(CF_TYPE_SPECIFIED(pathtype));
|
||||
std::ostringstream s_path;
|
||||
|
||||
// force a specific directory to search for player files
|
||||
if ( (pathtype == CF_TYPE_PLAYERS) || (pathtype == CF_TYPE_SINGLE_PLAYERS) || (pathtype == CF_TYPE_MULTI_PLAYERS) ) {
|
||||
s_path << Pilot_file_path;
|
||||
} else {
|
||||
s_path << root->path;
|
||||
}
|
||||
s_path << root->path;
|
||||
|
||||
s_path << Pathtypes[pathtype].path;
|
||||
|
||||
@@ -2386,3 +2417,26 @@ void cfile_spew_pack_file_crcs()
|
||||
|
||||
fclose(out);
|
||||
}
|
||||
|
||||
bool cf_check_location_flags(uint32_t check_flags, uint32_t desired_flags)
|
||||
{
|
||||
Assertion((check_flags & CF_LOCATION_ROOT_MASK) != 0, "check_flags must have a valid root value");
|
||||
Assertion((check_flags & CF_LOCATION_TYPE_MASK) != 0, "check_flags must have a valid type value");
|
||||
|
||||
auto check_root = check_flags & CF_LOCATION_ROOT_MASK;
|
||||
auto desired_root_flags = desired_flags & CF_LOCATION_ROOT_MASK;
|
||||
|
||||
// If the root part is not set then assume that every root matches
|
||||
if (desired_root_flags != 0 && (check_root & desired_root_flags) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto check_type = check_flags & CF_LOCATION_TYPE_MASK;
|
||||
auto desired_type_flags = desired_flags & CF_LOCATION_TYPE_MASK;
|
||||
|
||||
if (desired_type_flags != 0 && (check_type & desired_type_flags) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -29,6 +29,8 @@ typedef struct cf_pathtype {
|
||||
// During cfile_init, verify that Pathtypes[n].index == n for each item
|
||||
extern cf_pathtype Pathtypes[CF_MAX_PATH_TYPES];
|
||||
|
||||
bool cf_check_location_flags(uint32_t check_flags, uint32_t desired_flags);
|
||||
|
||||
// Returns the default storage path for files given a
|
||||
// particular pathtype. In other words, the path to
|
||||
// the unpacked, non-cd'd, stored on hard drive path.
|
||||
@@ -39,7 +41,9 @@ extern cf_pathtype Pathtypes[CF_MAX_PATH_TYPES];
|
||||
// filename - optional, if set, tacks the filename onto end of path.
|
||||
// Output: path - Fully qualified pathname.
|
||||
//Returns 0 if result would be too long (invalid result)
|
||||
int cf_create_default_path_string( char *path, uint path_max, int pathtype, const char *filename=NULL, bool localize = false);
|
||||
int cf_create_default_path_string( SCP_string &path, int pathtype, const char *filename=NULL, bool localize = false );
|
||||
int cf_create_default_path_string(char* path, uint path_max, int pathtype, const char* filename = nullptr,
|
||||
bool localize = false, uint32_t location_flags = CF_LOCATION_ALL);
|
||||
int cf_create_default_path_string(SCP_string& path, int pathtype, const char* filename = nullptr, bool localize = false,
|
||||
uint32_t location_flags = CF_LOCATION_ALL);
|
||||
|
||||
#endif //_CFILESYSTEM_H
|
||||
@@ -173,7 +173,6 @@ Flag exe_params[] =
|
||||
{ "-no_deferred", "Disable Deferred Lighting", true, EASY_DEFAULT_MEM, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_deferred"},
|
||||
{ "-enable_shadows", "Enable Shadows", true, EASY_MEM_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_shadows"},
|
||||
{ "-no_vsync", "Disable vertical sync", true, 0, EASY_DEFAULT, "Game Speed", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_vsync", },
|
||||
{ "-cache_bitmaps", "Cache bitmaps between missions", true, 0, EASY_DEFAULT_MEM, "Game Speed", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-cache_bitmaps", },
|
||||
|
||||
{ "-dualscanlines", "Add another pair of scanning lines", true, 0, EASY_DEFAULT, "HUD", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-dualscanlines", },
|
||||
{ "-targetinfo", "Enable info next to target", true, 0, EASY_DEFAULT, "HUD", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-targetinfo", },
|
||||
@@ -363,11 +362,9 @@ int Cmdline_no_deferred_lighting = 0;
|
||||
int Cmdline_aniso_level = 0;
|
||||
|
||||
// Game Speed related
|
||||
cmdline_parm cache_bitmaps_arg("-cache_bitmaps", NULL, AT_NONE); // Cmdline_cache_bitmaps
|
||||
cmdline_parm no_fpscap("-no_fps_capping", "Don't limit frames-per-second", AT_NONE); // Cmdline_NoFPSCap
|
||||
cmdline_parm no_vsync_arg("-no_vsync", NULL, AT_NONE); // Cmdline_no_vsync
|
||||
|
||||
int Cmdline_cache_bitmaps = 0; // caching of bitmaps between missions (faster loads, can hit swap on reload with <512 Meg RAM though) - taylor
|
||||
int Cmdline_NoFPSCap = 0; // Disable FPS capping - kazan
|
||||
int Cmdline_no_vsync = 0;
|
||||
|
||||
@@ -546,6 +543,7 @@ cmdline_parm deprecated_htl_arg("-nohtl", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_brieflighting_arg("-brief_lighting", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_sndpreload_arg("-snd_preload", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_missile_lighting_arg("-missile_lighting", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_cache_bitmaps_arg("-cache_bitmaps", "Deprecated", AT_NONE);
|
||||
|
||||
int Cmdline_deprecated_spec = 0;
|
||||
int Cmdline_deprecated_glow = 0;
|
||||
@@ -556,6 +554,7 @@ int Cmdline_deprecated_jpgtga = 0;
|
||||
int Cmdline_deprecated_nohtl = 0;
|
||||
bool Cmdline_deprecated_brief_lighting = 0;
|
||||
bool Cmdline_deprecated_missile_lighting = false;
|
||||
bool Cmdline_deprecated_cache_bitmaps = false;
|
||||
|
||||
#ifndef NDEBUG
|
||||
// NOTE: this assumes that os_init() has already been called but isn't a fatal error if it hasn't
|
||||
@@ -626,6 +625,10 @@ void cmdline_debug_print_cmdline()
|
||||
{
|
||||
mprintf(("Deprecated flag '-missile_lighting' found. Please remove from your cmdline.\n"));
|
||||
}
|
||||
|
||||
if (Cmdline_deprecated_cache_bitmaps) {
|
||||
mprintf(("Deprecated flag '-cache_bitmaps' found. Please remove from your cmdline.\n"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1965,10 +1968,6 @@ bool SetCmdlineParams()
|
||||
Cmdline_ballistic_gauge = 1;
|
||||
}
|
||||
|
||||
if ( cache_bitmaps_arg.found() ) {
|
||||
Cmdline_cache_bitmaps = 1;
|
||||
}
|
||||
|
||||
if(old_collision_system.found())
|
||||
Cmdline_old_collision_sys = 1;
|
||||
|
||||
@@ -2159,6 +2158,10 @@ bool SetCmdlineParams()
|
||||
Cmdline_deprecated_missile_lighting = true;
|
||||
}
|
||||
|
||||
if (deprecated_cache_bitmaps_arg.found()) {
|
||||
Cmdline_deprecated_cache_bitmaps = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,6 @@ extern int Cmdline_no_emissive;
|
||||
extern int Cmdline_aniso_level;
|
||||
|
||||
// Game Speed related
|
||||
extern int Cmdline_cache_bitmaps;
|
||||
extern int Cmdline_NoFPSCap;
|
||||
extern int Cmdline_no_vsync;
|
||||
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
#include <memory>
|
||||
|
||||
namespace cutscene {
|
||||
FrameSize::FrameSize(size_t in_width, size_t in_height, size_t in_stride)
|
||||
: width(in_width), height(in_height), stride(in_stride)
|
||||
{
|
||||
}
|
||||
FrameSize::FrameSize() = default;
|
||||
|
||||
Decoder::Decoder() : m_decoding(true) {
|
||||
}
|
||||
|
||||
|
||||
+18
-11
@@ -10,28 +10,26 @@ struct FrameSize {
|
||||
size_t width = 0;
|
||||
size_t height = 0;
|
||||
size_t stride = 0;
|
||||
|
||||
FrameSize(size_t width, size_t in_height, size_t in_stride);
|
||||
FrameSize();
|
||||
};
|
||||
|
||||
class VideoFrame {
|
||||
protected:
|
||||
VideoFrame() {}
|
||||
VideoFrame() = default;
|
||||
|
||||
public:
|
||||
virtual ~VideoFrame() {}
|
||||
public:
|
||||
virtual ~VideoFrame() = default;
|
||||
|
||||
double frameTime = -1.0;
|
||||
int id = -1;
|
||||
|
||||
FrameSize ySize;
|
||||
FrameSize uvSize;
|
||||
virtual size_t getPlaneNumber() = 0;
|
||||
|
||||
struct DataPointers {
|
||||
ubyte* y;
|
||||
ubyte* u;
|
||||
ubyte* v;
|
||||
};
|
||||
virtual FrameSize getPlaneSize(size_t plane) = 0;
|
||||
|
||||
virtual DataPointers getDataPointers() = 0;
|
||||
virtual void* getPlaneData(size_t plane) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -43,10 +41,19 @@ using FramePtr = std::unique_ptr<T>;
|
||||
|
||||
typedef std::unique_ptr<VideoFrame> VideoFramePtr;
|
||||
|
||||
enum class FramePixelFormat {
|
||||
Invalid,
|
||||
YUV420,
|
||||
BGR,
|
||||
BGRA
|
||||
};
|
||||
|
||||
struct MovieProperties {
|
||||
FrameSize size;
|
||||
|
||||
float fps = -1.0f;
|
||||
|
||||
FramePixelFormat pixelFormat = FramePixelFormat::Invalid;
|
||||
};
|
||||
|
||||
struct AudioFrame {
|
||||
|
||||
@@ -14,46 +14,85 @@ struct movie_vertex {
|
||||
|
||||
namespace cutscene {
|
||||
namespace player {
|
||||
VideoPresenter::VideoPresenter(const MovieProperties& props) {
|
||||
VideoPresenter::VideoPresenter(const MovieProperties& props) : _properties(props)
|
||||
{
|
||||
GR_DEBUG_SCOPE("Init video");
|
||||
|
||||
_planeTextureHandles.fill(-1);
|
||||
|
||||
auto w = static_cast<int>(props.size.width);
|
||||
auto h = static_cast<int>(props.size.height);
|
||||
|
||||
// Create buffer textures
|
||||
_yTexBuffer.reset(new uint8_t[w * h]);
|
||||
_ytex = bm_create(8, w, h, _yTexBuffer.get(), BMP_AABITMAP);
|
||||
switch (props.pixelFormat) {
|
||||
case FramePixelFormat::YUV420:
|
||||
_planeTextureBuffers[0].reset(new uint8_t[w * h]);
|
||||
_planeTextureHandles[0] = bm_create(8, w, h, _planeTextureBuffers[0].get(), BMP_AABITMAP);
|
||||
|
||||
_uTexBuffer.reset(new uint8_t[w / 2 * h / 2]);
|
||||
_utex = bm_create(8, w / 2, h / 2, _uTexBuffer.get(), BMP_AABITMAP);
|
||||
_planeTextureBuffers[1].reset(new uint8_t[w / 2 * h / 2]);
|
||||
_planeTextureHandles[1] = bm_create(8, w / 2, h / 2, _planeTextureBuffers[1].get(), BMP_AABITMAP);
|
||||
|
||||
_vTexBuffer.reset(new uint8_t[w / 2 * h / 2]);
|
||||
_vtex = bm_create(8, w / 2, h / 2, _vTexBuffer.get(), BMP_AABITMAP);
|
||||
_planeTextureBuffers[2].reset(new uint8_t[w / 2 * h / 2]);
|
||||
_planeTextureHandles[2] = bm_create(8, w / 2, h / 2, _planeTextureBuffers[2].get(), BMP_AABITMAP);
|
||||
|
||||
material_set_movie(&_render_material, _ytex, _utex, _vtex);
|
||||
material_set_movie(&_movie_material, _planeTextureHandles[0], _planeTextureHandles[1], _planeTextureHandles[2]);
|
||||
break;
|
||||
case FramePixelFormat::BGR:
|
||||
_planeTextureBuffers[0].reset(new uint8_t[w * h * 3]);
|
||||
_planeTextureHandles[0] = bm_create(24, w, h, _planeTextureBuffers[0].get(), 0);
|
||||
|
||||
material_set_unlit(&_rgb_material, _planeTextureHandles[0], 1.0f, false, false);
|
||||
break;
|
||||
case FramePixelFormat::BGRA:
|
||||
_planeTextureBuffers[0].reset(new uint8_t[w * h * 4]);
|
||||
_planeTextureHandles[0] = bm_create(32, w, h, _planeTextureBuffers[0].get(), 0);
|
||||
|
||||
material_set_unlit(&_rgb_material, _planeTextureHandles[0], 1.0f, true, false);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE("Unhandled enum value!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VideoPresenter::~VideoPresenter() {
|
||||
GR_DEBUG_SCOPE("Deinit video");
|
||||
|
||||
bm_release(_ytex);
|
||||
bm_release(_utex);
|
||||
bm_release(_vtex);
|
||||
|
||||
_ytex = _utex = _vtex = -1;
|
||||
for (auto& handle : _planeTextureHandles) {
|
||||
if (handle > 0) {
|
||||
bm_release(handle);
|
||||
handle = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPresenter::uploadVideoFrame(const VideoFramePtr& frame) {
|
||||
GR_DEBUG_SCOPE("Update video frame");
|
||||
auto ptrs = frame->getDataPointers();
|
||||
|
||||
memcpy(_yTexBuffer.get(), ptrs.y, frame->ySize.stride * frame->ySize.height);
|
||||
memcpy(_uTexBuffer.get(), ptrs.u, frame->uvSize.stride * frame->uvSize.height);
|
||||
memcpy(_vTexBuffer.get(), ptrs.v, frame->uvSize.stride * frame->uvSize.height);
|
||||
for (size_t i = 0; i < frame->getPlaneNumber(); ++i) {
|
||||
auto size = frame->getPlaneSize(i);
|
||||
auto data = frame->getPlaneData(i);
|
||||
|
||||
gr_update_texture(_ytex, 8, _yTexBuffer.get(), (int) frame->ySize.width, (int) frame->ySize.height);
|
||||
gr_update_texture(_utex, 8, _uTexBuffer.get(), (int) frame->uvSize.width, (int) frame->uvSize.height);
|
||||
gr_update_texture(_vtex, 8, _vTexBuffer.get(), (int) frame->uvSize.width, (int) frame->uvSize.height);
|
||||
memcpy(_planeTextureBuffers[i].get(), data, size.stride * size.height);
|
||||
|
||||
int bpp = 0;
|
||||
switch (_properties.pixelFormat) {
|
||||
case FramePixelFormat::YUV420:
|
||||
bpp = 8;
|
||||
break;
|
||||
case FramePixelFormat::BGR:
|
||||
bpp = 24;
|
||||
break;
|
||||
case FramePixelFormat::BGRA:
|
||||
bpp = 32;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE("Unhandled enum value!");
|
||||
break;
|
||||
}
|
||||
|
||||
gr_update_texture(_planeTextureHandles[i], bpp, _planeTextureBuffers[i].get(), static_cast<int>(size.width),
|
||||
static_cast<int>(size.height));
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPresenter::displayFrame(float x1, float y1, float x2, float y2) {
|
||||
@@ -85,10 +124,14 @@ void VideoPresenter::displayFrame(float x1, float y1, float x2, float y2) {
|
||||
auto offset = gr_add_to_immediate_buffer(sizeof(vertex_data), vertex_data);
|
||||
|
||||
vertex_layout layout;
|
||||
layout.add_vertex_component(vertex_format_data::POSITION2, sizeof(vertex_data[0]), offset + offsetof(movie_vertex, pos));
|
||||
layout.add_vertex_component(vertex_format_data::TEX_COORD2, sizeof(vertex_data[0]), offset + offsetof(movie_vertex, uv));
|
||||
layout.add_vertex_component(vertex_format_data::POSITION2, sizeof(vertex_data[0]), offsetof(movie_vertex, pos));
|
||||
layout.add_vertex_component(vertex_format_data::TEX_COORD2, sizeof(vertex_data[0]), offsetof(movie_vertex, uv));
|
||||
|
||||
gr_render_movie(&_render_material, PRIM_TYPE_TRISTRIP, &layout, 4, gr_immediate_buffer_handle);
|
||||
if (_properties.pixelFormat == FramePixelFormat::YUV420) {
|
||||
gr_render_movie(&_movie_material, PRIM_TYPE_TRISTRIP, &layout, 4, gr_immediate_buffer_handle, offset);
|
||||
} else {
|
||||
gr_render_primitives(&_rgb_material, PRIM_TYPE_TRISTRIP, &layout, 0, 4, gr_immediate_buffer_handle, offset);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,16 +12,13 @@ namespace cutscene {
|
||||
namespace player {
|
||||
|
||||
class VideoPresenter {
|
||||
int _ytex = -1;
|
||||
std::unique_ptr<uint8_t[]> _yTexBuffer;
|
||||
MovieProperties _properties;
|
||||
|
||||
int _utex = -1;
|
||||
std::unique_ptr<uint8_t[]> _uTexBuffer;
|
||||
std::array<int, 3> _planeTextureHandles;
|
||||
std::array<std::unique_ptr<uint8_t[]>, 3> _planeTextureBuffers;
|
||||
|
||||
int _vtex = -1;
|
||||
std::unique_ptr<uint8_t[]> _vTexBuffer;
|
||||
|
||||
movie_material _render_material;
|
||||
movie_material _movie_material;
|
||||
material _rgb_material; // Material used when a RGB/RGBA movie is played
|
||||
public:
|
||||
explicit VideoPresenter(const MovieProperties& props);
|
||||
|
||||
|
||||
@@ -33,17 +33,18 @@ class AVPacketScope
|
||||
}
|
||||
};
|
||||
|
||||
const char* CHECKED_EXTENSIONS[] = {
|
||||
"webm",
|
||||
"mp4",
|
||||
"ogg",
|
||||
"mve"
|
||||
};
|
||||
const char* CHECKED_EXTENSIONS[] = {"webm", "mp4", "ogg",
|
||||
"png", // This is designed to be used with APNG animations
|
||||
"mve"};
|
||||
|
||||
const char *CHECKED_SUBT_EXTENSIONS[] = {"srt"};
|
||||
const char* CHECKED_SUBT_EXTENSIONS[] = {"srt"};
|
||||
|
||||
double getFrameRate(AVStream* stream, AVCodecContext* codecCtx) {
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(58, 3, 102)
|
||||
auto fps = av_q2d(stream->r_frame_rate);
|
||||
#else
|
||||
auto fps = av_q2d(av_stream_get_r_frame_rate(stream));
|
||||
#endif
|
||||
|
||||
if (fps < 0.000001)
|
||||
{
|
||||
@@ -58,7 +59,7 @@ double getFrameRate(AVStream* stream, AVCodecContext* codecCtx) {
|
||||
return fps;
|
||||
}
|
||||
|
||||
CodecContextParameters getCodecParameters(AVStream *stream) {
|
||||
CodecContextParameters getCodecParameters(AVStream* stream) {
|
||||
CodecContextParameters paras;
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
paras.width = stream->codecpar->width;
|
||||
@@ -84,7 +85,7 @@ CodecContextParameters getCodecParameters(AVStream *stream) {
|
||||
return paras;
|
||||
}
|
||||
|
||||
SCP_string normalizeLanguage(const char *langauge_name) {
|
||||
SCP_string normalizeLanguage(const char* langauge_name) {
|
||||
if (!stricmp(langauge_name, "eng")) {
|
||||
return "English";
|
||||
}
|
||||
@@ -101,6 +102,72 @@ SCP_string normalizeLanguage(const char *langauge_name) {
|
||||
// Default to english for everything else
|
||||
return "English";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Given a FFmpeg pixel format returns the format it should be converted to
|
||||
* @param in_fmt The input format
|
||||
* @return The output format
|
||||
*/
|
||||
AVPixelFormat getConversionFormat(AVPixelFormat in_fmt)
|
||||
{
|
||||
switch (in_fmt) {
|
||||
case AV_PIX_FMT_RGB24:
|
||||
case AV_PIX_FMT_BGR24:
|
||||
case AV_PIX_FMT_BGR8:
|
||||
case AV_PIX_FMT_BGR4:
|
||||
case AV_PIX_FMT_BGR4_BYTE:
|
||||
case AV_PIX_FMT_RGB8:
|
||||
case AV_PIX_FMT_RGB4:
|
||||
case AV_PIX_FMT_RGB4_BYTE:
|
||||
case AV_PIX_FMT_RGB48BE:
|
||||
case AV_PIX_FMT_RGB48LE:
|
||||
case AV_PIX_FMT_RGB565BE:
|
||||
case AV_PIX_FMT_RGB565LE:
|
||||
case AV_PIX_FMT_RGB555BE:
|
||||
case AV_PIX_FMT_RGB555LE:
|
||||
case AV_PIX_FMT_BGR565BE:
|
||||
case AV_PIX_FMT_BGR565LE:
|
||||
case AV_PIX_FMT_BGR555BE:
|
||||
case AV_PIX_FMT_BGR555LE:
|
||||
case AV_PIX_FMT_RGB444LE:
|
||||
case AV_PIX_FMT_RGB444BE:
|
||||
case AV_PIX_FMT_BGR444LE:
|
||||
case AV_PIX_FMT_BGR444BE:
|
||||
case AV_PIX_FMT_BGR48BE:
|
||||
case AV_PIX_FMT_BGR48LE:
|
||||
case AV_PIX_FMT_0RGB:
|
||||
case AV_PIX_FMT_RGB0:
|
||||
case AV_PIX_FMT_0BGR:
|
||||
case AV_PIX_FMT_BGR0:
|
||||
return AV_PIX_FMT_BGR24;
|
||||
|
||||
case AV_PIX_FMT_RGBA64BE:
|
||||
case AV_PIX_FMT_RGBA64LE:
|
||||
case AV_PIX_FMT_BGRA64BE:
|
||||
case AV_PIX_FMT_BGRA64LE:
|
||||
case AV_PIX_FMT_ARGB:
|
||||
case AV_PIX_FMT_RGBA:
|
||||
case AV_PIX_FMT_ABGR:
|
||||
case AV_PIX_FMT_BGRA:
|
||||
return AV_PIX_FMT_BGRA;
|
||||
|
||||
default:
|
||||
// Assume that everything else is converted to YUV 420
|
||||
return AV_PIX_FMT_YUV420P;
|
||||
}
|
||||
}
|
||||
|
||||
FramePixelFormat getPixelFormat(AVPixelFormat fmt)
|
||||
{
|
||||
switch (fmt) {
|
||||
case AV_PIX_FMT_BGR24:
|
||||
return FramePixelFormat::BGR;
|
||||
case AV_PIX_FMT_BGRA:
|
||||
return FramePixelFormat::BGRA;
|
||||
default:
|
||||
return FramePixelFormat::YUV420;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace cutscene {
|
||||
@@ -146,8 +213,9 @@ std::unique_ptr<InputStream> openStream(const SCP_string& name) {
|
||||
return input;
|
||||
}
|
||||
|
||||
std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream> &stream,
|
||||
std::unique_ptr<InputStream> &subt) {
|
||||
std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream>& stream,
|
||||
std::unique_ptr<InputStream>& subt)
|
||||
{
|
||||
std::unique_ptr<DecoderStatus> status(new DecoderStatus());
|
||||
|
||||
auto ctx = stream->m_ctx->ctx();
|
||||
@@ -205,18 +273,18 @@ std::unique_ptr<DecoderStatus> initializeStatus(std::unique_ptr<InputStream> &st
|
||||
|
||||
if (status->subtitleStream == nullptr) {
|
||||
// We don't have an external subtitle stream or loading from that file has failed
|
||||
auto ¤t_language = Lcl_languages[Lcl_current_lang];
|
||||
auto& current_language = Lcl_languages[Lcl_current_lang];
|
||||
for (uint32_t i = 0; i < ctx->nb_streams; ++i) {
|
||||
auto test_stream = ctx->streams[i];
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(57, 24, 255)
|
||||
auto &pars = test_stream->codecpar;
|
||||
auto& pars = test_stream->codecpar;
|
||||
|
||||
if (!(pars->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
AVDictionaryEntry *tag = nullptr;
|
||||
AVDictionaryEntry* tag = nullptr;
|
||||
if ((tag = av_dict_get(test_stream->metadata, "language", nullptr, 0)) == nullptr) {
|
||||
continue;
|
||||
}
|
||||
@@ -340,8 +408,9 @@ std::unique_ptr<InputStream> openInputStream(const SCP_string& name) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<InputStream> openSubtitleStream(const SCP_string &name) {
|
||||
auto ¤t_language = Lcl_languages[Lcl_current_lang];
|
||||
std::unique_ptr<InputStream> openSubtitleStream(const SCP_string& name)
|
||||
{
|
||||
auto& current_language = Lcl_languages[Lcl_current_lang];
|
||||
|
||||
for (auto ext : CHECKED_SUBT_EXTENSIONS) {
|
||||
SCP_string fileName;
|
||||
@@ -397,18 +466,21 @@ bool FFMPEGDecoder::initialize(const SCP_string& fileName) {
|
||||
return true;
|
||||
}
|
||||
|
||||
MovieProperties FFMPEGDecoder::getProperties() const {
|
||||
MovieProperties FFMPEGDecoder::getProperties() const
|
||||
{
|
||||
MovieProperties props;
|
||||
props.size.width = static_cast<size_t>(m_status->videoCodecPars.width);
|
||||
props.size.height = static_cast<size_t>(m_status->videoCodecPars.height);
|
||||
|
||||
props.fps = static_cast<float>(getFrameRate(m_status->videoStream, m_status->videoCodecCtx));
|
||||
|
||||
props.pixelFormat = getPixelFormat(getConversionFormat(m_status->videoCodecPars.pixel_format));
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
void FFMPEGDecoder::startDecoding() {
|
||||
std::unique_ptr<VideoDecoder> videoDecoder(new VideoDecoder(m_status.get()));
|
||||
std::unique_ptr<VideoDecoder> videoDecoder(new VideoDecoder(m_status.get(), getConversionFormat(m_status->videoCodecPars.pixel_format)));
|
||||
|
||||
std::unique_ptr<AudioDecoder> audioDecoder;
|
||||
std::unique_ptr<SubtitleDecoder> subtitleDecoder;
|
||||
@@ -520,7 +592,8 @@ void FFMPEGDecoder::close() {
|
||||
m_subtitleInput = nullptr;
|
||||
}
|
||||
}
|
||||
void FFMPEGDecoder::runSubtitleDecoder(SubtitleDecoder *decoder) {
|
||||
void FFMPEGDecoder::runSubtitleDecoder(SubtitleDecoder* decoder)
|
||||
{
|
||||
auto ctx = m_subtitleInput->m_ctx->ctx();
|
||||
AVPacket packet;
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ class FFMPEGDecoder: public Decoder {
|
||||
|
||||
bool hasExternalSubtitle() const;
|
||||
|
||||
void runSubtitleDecoder(SubtitleDecoder *decoder);
|
||||
void runSubtitleDecoder(SubtitleDecoder* decoder);
|
||||
|
||||
public:
|
||||
FFMPEGDecoder();
|
||||
|
||||
@@ -3,11 +3,9 @@
|
||||
#include "tracing/tracing.h"
|
||||
|
||||
namespace {
|
||||
const AVPixelFormat DESTINATION_FORMAT = AV_PIX_FMT_YUV420P;
|
||||
|
||||
SwsContext* getSWSContext(int width, int height, AVPixelFormat fmt) {
|
||||
return sws_getContext(width, height, fmt, width, height, DESTINATION_FORMAT,
|
||||
SWS_BILINEAR, nullptr, nullptr, nullptr);
|
||||
SwsContext* getSWSContext(int width, int height, AVPixelFormat fmt, AVPixelFormat destination_fmt)
|
||||
{
|
||||
return sws_getContext(width, height, fmt, width, height, destination_fmt, SWS_BILINEAR, nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
double getFrameTime(int64_t pts, AVRational time_base) {
|
||||
@@ -18,34 +16,53 @@ double getFrameTime(int64_t pts, AVRational time_base) {
|
||||
namespace cutscene {
|
||||
namespace ffmpeg {
|
||||
class FFMPEGVideoFrame: public VideoFrame {
|
||||
public:
|
||||
FFMPEGVideoFrame() : frame(nullptr) {
|
||||
}
|
||||
size_t _width;
|
||||
size_t _height;
|
||||
AVFrame* _frame;
|
||||
|
||||
public:
|
||||
FFMPEGVideoFrame(size_t width, size_t height, AVFrame* frame) : _width(width), _height(height), _frame(frame) {}
|
||||
|
||||
~FFMPEGVideoFrame() override {
|
||||
if (frame != nullptr) {
|
||||
av_freep(&frame->data[0]);
|
||||
av_frame_free(&frame);
|
||||
if (_frame != nullptr) {
|
||||
av_freep(&_frame->data[0]);
|
||||
av_frame_free(&_frame);
|
||||
}
|
||||
}
|
||||
|
||||
DataPointers getDataPointers() override {
|
||||
DataPointers ptrs;
|
||||
ptrs.y = frame->data[0];
|
||||
ptrs.u = frame->data[1];
|
||||
ptrs.v = frame->data[2];
|
||||
|
||||
return ptrs;
|
||||
size_t getPlaneNumber() override
|
||||
{
|
||||
switch (_frame->format) {
|
||||
case AV_PIX_FMT_YUV420P:
|
||||
// YUV data is planar
|
||||
return 3;
|
||||
default:
|
||||
// Everything else is packed
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
FrameSize getPlaneSize(size_t plane) override
|
||||
{
|
||||
switch (_frame->format) {
|
||||
case AV_PIX_FMT_YUV420P: {
|
||||
// YUV data is planar
|
||||
auto width = plane > 0 ? _width / 2 : _width;
|
||||
auto height = plane > 0 ? _height / 2 : _height;
|
||||
|
||||
AVFrame* frame;
|
||||
return {width, height, (size_t)_frame->linesize[plane]};
|
||||
}
|
||||
default:
|
||||
// Everything else is packed
|
||||
return {_width, _height, (size_t)_frame->linesize[plane]};
|
||||
}
|
||||
}
|
||||
void* getPlaneData(size_t plane) override { return _frame->data[plane]; }
|
||||
};
|
||||
|
||||
VideoDecoder::VideoDecoder(DecoderStatus* status)
|
||||
: FFMPEGStreamDecoder(status),
|
||||
m_frameId(0) {
|
||||
VideoDecoder::VideoDecoder(DecoderStatus* status, AVPixelFormat destination_fmt)
|
||||
: FFMPEGStreamDecoder(status), m_frameId(0), m_destinationFormat(destination_fmt)
|
||||
{
|
||||
m_swsCtx = getSWSContext(m_status->videoCodecPars.width, m_status->videoCodecPars.height,
|
||||
m_status->videoCodecPars.pixel_format);
|
||||
m_status->videoCodecPars.pixel_format, destination_fmt);
|
||||
}
|
||||
|
||||
VideoDecoder::~VideoDecoder() {
|
||||
@@ -53,53 +70,32 @@ VideoDecoder::~VideoDecoder() {
|
||||
}
|
||||
|
||||
void VideoDecoder::convertAndPushPicture(const AVFrame* frame) {
|
||||
// Allocate a picture to hold the YUV data
|
||||
// Allocate a picture to hold the destination data
|
||||
AVFrame* yuvFrame = av_frame_alloc();
|
||||
av_frame_copy(yuvFrame, frame);
|
||||
yuvFrame->format = DESTINATION_FORMAT;
|
||||
yuvFrame->format = m_destinationFormat;
|
||||
|
||||
av_image_alloc(yuvFrame->data,
|
||||
yuvFrame->linesize,
|
||||
m_status->videoCodecPars.width,
|
||||
m_status->videoCodecPars.height,
|
||||
DESTINATION_FORMAT,
|
||||
1);
|
||||
av_image_alloc(yuvFrame->data, yuvFrame->linesize, m_status->videoCodecPars.width, m_status->videoCodecPars.height,
|
||||
m_destinationFormat, 1);
|
||||
|
||||
std::unique_ptr<FFMPEGVideoFrame> videoFramePtr(new FFMPEGVideoFrame());
|
||||
|
||||
if (m_status->videoCodecPars.pixel_format == DESTINATION_FORMAT) {
|
||||
av_image_copy(yuvFrame->data,
|
||||
yuvFrame->linesize,
|
||||
(const uint8_t**) (frame->data),
|
||||
frame->linesize,
|
||||
DESTINATION_FORMAT,
|
||||
m_status->videoCodecPars.width,
|
||||
m_status->videoCodecPars.height);
|
||||
if (m_status->videoCodecPars.pixel_format == m_destinationFormat) {
|
||||
av_image_copy(yuvFrame->data, yuvFrame->linesize, (const uint8_t**)(frame->data), frame->linesize,
|
||||
m_destinationFormat, m_status->videoCodecPars.width, m_status->videoCodecPars.height);
|
||||
} else {
|
||||
// Convert frame to YUV
|
||||
sws_scale(
|
||||
m_swsCtx,
|
||||
(uint8_t const* const*) frame->data,
|
||||
frame->linesize,
|
||||
0,
|
||||
m_status->videoCodecPars.height,
|
||||
yuvFrame->data,
|
||||
yuvFrame->linesize
|
||||
);
|
||||
// Convert frame to destination format
|
||||
sws_scale(m_swsCtx, (uint8_t const* const*)frame->data, frame->linesize, 0, m_status->videoCodecPars.height,
|
||||
yuvFrame->data, yuvFrame->linesize);
|
||||
}
|
||||
|
||||
std::unique_ptr<FFMPEGVideoFrame> videoFramePtr(
|
||||
new FFMPEGVideoFrame(static_cast<size_t>(m_status->videoCodecPars.width),
|
||||
static_cast<size_t>(m_status->videoCodecPars.height), yuvFrame));
|
||||
videoFramePtr->id = ++m_frameId;
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(58, 3, 102)
|
||||
videoFramePtr->frameTime = getFrameTime(frame->best_effort_timestamp, m_status->videoStream->time_base);
|
||||
#else
|
||||
videoFramePtr->frameTime = getFrameTime(av_frame_get_best_effort_timestamp(frame), m_status->videoStream->time_base);
|
||||
videoFramePtr->frame = yuvFrame;
|
||||
|
||||
videoFramePtr->ySize.height = static_cast<size_t>(m_status->videoCodecPars.height);
|
||||
videoFramePtr->ySize.width = static_cast<size_t>(m_status->videoCodecPars.width);
|
||||
videoFramePtr->ySize.stride = static_cast<size_t>(yuvFrame->linesize[0]);
|
||||
|
||||
// 420P means that the UV channels have half the width and height
|
||||
videoFramePtr->uvSize.height = static_cast<size_t>(m_status->videoCodecPars.height / 2);
|
||||
videoFramePtr->uvSize.width = static_cast<size_t>(m_status->videoCodecPars.width / 2);
|
||||
videoFramePtr->uvSize.stride = static_cast<size_t>(yuvFrame->linesize[1]);
|
||||
#endif
|
||||
|
||||
pushFrame(VideoFramePtr(videoFramePtr.release()));
|
||||
}
|
||||
|
||||
@@ -9,11 +9,12 @@ class VideoDecoder: public FFMPEGStreamDecoder<VideoFrame> {
|
||||
private:
|
||||
int m_frameId;
|
||||
SwsContext* m_swsCtx;
|
||||
AVPixelFormat m_destinationFormat;
|
||||
|
||||
void convertAndPushPicture(const AVFrame* frame);
|
||||
|
||||
public:
|
||||
explicit VideoDecoder(DecoderStatus* status);
|
||||
explicit VideoDecoder(DecoderStatus* status, AVPixelFormat destination_fmt);
|
||||
|
||||
~VideoDecoder() override;
|
||||
|
||||
|
||||
@@ -202,10 +202,12 @@ void movie_display_loop(Player* player, PlaybackState* state) {
|
||||
auto passed = timestamp - lastDisplayTimestamp;
|
||||
lastDisplayTimestamp = timestamp;
|
||||
|
||||
// Play as long as the player reports that there is more to display
|
||||
state->playing = player->update(passed);
|
||||
if (player->isPlaybackReady()) {
|
||||
// Play as long as the player reports that there is more to display
|
||||
state->playing = player->update(passed);
|
||||
|
||||
displayVideo(player, state);
|
||||
displayVideo(player, state);
|
||||
}
|
||||
|
||||
processEvents(state);
|
||||
|
||||
|
||||
+21
-18
@@ -17,6 +17,7 @@
|
||||
#include "io/key.h"
|
||||
#include "io/timer.h"
|
||||
|
||||
#include "player.h"
|
||||
#include "parse/parselo.h"
|
||||
|
||||
using namespace cutscene::player;
|
||||
@@ -28,7 +29,7 @@ const int MAX_AUDIO_BUFFERS = 15;
|
||||
|
||||
std::unique_ptr<Decoder> findDecoder(const SCP_string& name) {
|
||||
{
|
||||
std::unique_ptr<Decoder> ffmpeg(new ffmpeg::FFMPEGDecoder());
|
||||
std::unique_ptr<Decoder> ffmpeg(new ::cutscene::ffmpeg::FFMPEGDecoder());
|
||||
if (ffmpeg->initialize(name)) {
|
||||
return ffmpeg;
|
||||
}
|
||||
@@ -272,8 +273,21 @@ bool shouldBeginPlayback(Decoder* decoder) {
|
||||
}
|
||||
|
||||
namespace cutscene {
|
||||
Player::Player(std::unique_ptr<Decoder>&& decoder) : m_decoder(std::move(decoder)) {
|
||||
initPlayback();
|
||||
Player::Player(std::unique_ptr<Decoder>&& decoder, bool enable_audio) : m_decoder(std::move(decoder))
|
||||
{
|
||||
Assertion(!m_state.videoInited,
|
||||
"Internal State has been initialized before! Create a new player for replaying a movie.");
|
||||
|
||||
m_decoderThread.reset(new std::thread(std::bind(&Player::decoderThread, this)));
|
||||
|
||||
m_state.props = m_decoder->getProperties();
|
||||
m_state.decoder = m_decoder.get();
|
||||
|
||||
videoPlaybackInit(&m_state);
|
||||
|
||||
if (enable_audio) {
|
||||
audioPlaybackInit(&m_state);
|
||||
}
|
||||
}
|
||||
|
||||
Player::~Player() {
|
||||
@@ -315,19 +329,6 @@ bool Player::processDecoderData() {
|
||||
|
||||
return decoding || pendingAudio || pendingVideo;
|
||||
}
|
||||
|
||||
void Player::initPlayback() {
|
||||
Assertion(!m_state.videoInited, "Internal State has been initialized before! Create a new player for replaying a movie.");
|
||||
|
||||
m_decoderThread.reset(new std::thread(std::bind(&Player::decoderThread, this)));
|
||||
|
||||
m_state.props = m_decoder->getProperties();
|
||||
m_state.decoder = m_decoder.get();
|
||||
|
||||
videoPlaybackInit(&m_state);
|
||||
|
||||
audioPlaybackInit(&m_state);
|
||||
}
|
||||
bool Player::update(uint64_t diff_time_micro) {
|
||||
if (m_state.playbackHasBegun) {
|
||||
m_state.playback_time += diff_time_micro;
|
||||
@@ -354,7 +355,8 @@ void Player::decoderThread() {
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Player> Player::newPlayer(const SCP_string& name) {
|
||||
std::unique_ptr<Player> Player::newPlayer(const SCP_string& name, bool enable_audio)
|
||||
{
|
||||
mprintf(("Creating player for movie '%s'.\n", name.c_str()));
|
||||
|
||||
auto decoder = findDecoder(name);
|
||||
@@ -362,7 +364,7 @@ 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)));
|
||||
return std::unique_ptr<Player>(new Player(std::move(decoder), enable_audio));
|
||||
}
|
||||
const PlayerState& Player::getInternalState() const {
|
||||
return m_state;
|
||||
@@ -386,4 +388,5 @@ SCP_string Player::getCurrentSubtitle() {
|
||||
return m_state.currentSubtitle->text;
|
||||
}
|
||||
}
|
||||
bool Player::isPlaybackReady() const { return m_state.playbackHasBegun || shouldBeginPlayback(m_decoder.get()); }
|
||||
}
|
||||
+21
-12
@@ -52,7 +52,7 @@ struct PlayerState {
|
||||
* @brief A movie player
|
||||
*/
|
||||
class Player {
|
||||
private:
|
||||
private:
|
||||
std::unique_ptr<Decoder> m_decoder;
|
||||
|
||||
std::unique_ptr<std::thread> m_decoderThread;
|
||||
@@ -61,13 +61,11 @@ class Player {
|
||||
|
||||
bool processDecoderData();
|
||||
|
||||
private:
|
||||
private:
|
||||
void decoderThread();
|
||||
|
||||
void initPlayback();
|
||||
|
||||
public:
|
||||
explicit Player(std::unique_ptr<Decoder>&& decoder);
|
||||
public:
|
||||
explicit Player(std::unique_ptr<Decoder>&& decoder, bool enable_audio = true);
|
||||
|
||||
~Player();
|
||||
|
||||
@@ -97,6 +95,12 @@ class Player {
|
||||
*/
|
||||
const MovieProperties& getMovieProperties() const;
|
||||
|
||||
/**
|
||||
* @brief Determines if this player can start displaying video.
|
||||
* @return true if the cutscene is ready, false otherwise
|
||||
*/
|
||||
bool isPlaybackReady() const;
|
||||
|
||||
/**
|
||||
* @brief Draws the current movie frame at the specified coordinates.
|
||||
*
|
||||
@@ -109,6 +113,10 @@ class Player {
|
||||
*/
|
||||
void draw(float x1, float y1, float x2, float y2);
|
||||
|
||||
/**
|
||||
* @brief Gets the subtitle text that should be displayed now
|
||||
* @return The text, encoded in UTF-8
|
||||
*/
|
||||
SCP_string getCurrentSubtitle();
|
||||
|
||||
/**
|
||||
@@ -119,11 +127,12 @@ class Player {
|
||||
void stopPlayback();
|
||||
|
||||
/**
|
||||
* @brief Creates a player
|
||||
* The player is configured to play the movie with the specified name
|
||||
* @param name The movie to play
|
||||
* @return @c nullptr if the specified movie could not be opened, a valid Player pointer otherwise
|
||||
*/
|
||||
static std::unique_ptr<Player> newPlayer(const SCP_string& name);
|
||||
* @brief Creates a player
|
||||
* The player is configured to play the movie with the specified name
|
||||
* @param name The movie to play
|
||||
* @param enable_audio Enable audio for this player instance
|
||||
* @return @c nullptr if the specified movie could not be opened, a valid Player pointer otherwise
|
||||
*/
|
||||
static std::unique_ptr<Player> newPlayer(const SCP_string& name, bool enable_audio = true);
|
||||
};
|
||||
}
|
||||
@@ -33,7 +33,7 @@ layout (std140) uniform modelData {
|
||||
|
||||
model_light lights[MAX_LIGHTS];
|
||||
|
||||
float extrudeWidth;
|
||||
float outlineWidth;
|
||||
float fogStart;
|
||||
float fogScale;
|
||||
int buffer_matrix_offset;
|
||||
@@ -105,11 +105,6 @@ in VertexOutput {
|
||||
#endif
|
||||
#ifdef FLAG_FOG
|
||||
float fogDist;
|
||||
#endif
|
||||
#ifdef WORKAROUND_CLIPPING_PLANES
|
||||
#ifdef FLAG_TRANSFORM
|
||||
float notVisible;
|
||||
#endif
|
||||
#endif
|
||||
vec4 position;
|
||||
vec3 normal;
|
||||
@@ -215,11 +210,6 @@ vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial,
|
||||
|
||||
void main()
|
||||
{
|
||||
#ifdef WORKAROUND_CLIPPING_PLANES
|
||||
#ifdef FLAG_TRANSFORM
|
||||
if(vertIn.notVisible >= 0.9) { discard; }
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
// need depth and depth squared for variance shadow maps
|
||||
fragOut0 = vec4(vertIn.position.z, vertIn.position.z * vertIn.position.z * VARIANCE_SHADOW_SCALE_INV, 0.0, 1.0);
|
||||
@@ -426,6 +416,7 @@ void main()
|
||||
// emissive colors won't be added later when we are using forward rendering so we need to do that here
|
||||
baseColor.rgb += emissiveColor.rgb;
|
||||
#endif
|
||||
|
||||
fragOut0 = baseColor;
|
||||
#ifdef FLAG_DEFERRED
|
||||
fragOut1 = vec4(vertIn.position.xyz, 1.0);
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
#extension GL_ARB_gpu_shader5: enable
|
||||
|
||||
#ifdef FLAG_THICK_OUTLINE
|
||||
layout (triangles) in;
|
||||
// For every triangle line we generate 2 triangles which can be done with 4 vertices so in total we will need 12 vertices
|
||||
layout (triangle_strip, max_vertices = 12) out;
|
||||
#else
|
||||
layout (triangles) in;
|
||||
layout (triangle_strip, max_vertices = 3) out;
|
||||
#ifdef GL_ARB_gpu_shader5
|
||||
#endif
|
||||
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
#ifdef GL_ARB_gpu_shader5
|
||||
layout(invocations = 4) in;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define MAX_LIGHTS 8
|
||||
@@ -33,7 +42,7 @@ layout (std140) uniform modelData {
|
||||
|
||||
model_light lights[MAX_LIGHTS];
|
||||
|
||||
float extrudeWidth;
|
||||
float outlineWidth;
|
||||
float fogStart;
|
||||
float fogScale;
|
||||
int buffer_matrix_offset;
|
||||
@@ -106,15 +115,13 @@ in VertexOutput {
|
||||
#ifdef FLAG_FOG
|
||||
float fogDist;
|
||||
#endif
|
||||
#ifdef WORKAROUND_CLIPPING_PLANES
|
||||
#ifdef FLAG_TRANSFORM
|
||||
float notVisible;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
#if !defined(GL_ARB_gpu_shader5)
|
||||
float instance;
|
||||
#endif
|
||||
#ifdef FLAG_TRANSFORM
|
||||
float clipModel;
|
||||
#endif
|
||||
#else
|
||||
vec4 position;
|
||||
#endif
|
||||
@@ -135,11 +142,6 @@ out VertexOutput {
|
||||
#endif
|
||||
#ifdef FLAG_FOG
|
||||
float fogDist;
|
||||
#endif
|
||||
#ifdef WORKAROUND_CLIPPING_PLANES
|
||||
#ifdef FLAG_TRANSFORM
|
||||
float notVisible;
|
||||
#endif
|
||||
#endif
|
||||
vec4 position;
|
||||
vec3 normal;
|
||||
@@ -150,6 +152,7 @@ out VertexOutput {
|
||||
#endif
|
||||
} vertOut;
|
||||
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
void main(void)
|
||||
{
|
||||
#ifdef GL_ARB_gpu_shader5
|
||||
@@ -159,14 +162,25 @@ void main(void)
|
||||
#endif
|
||||
for(int vert = 0; vert < gl_in.length(); vert++)
|
||||
{
|
||||
#ifdef FLAG_TRANSFORM
|
||||
if (vertIn[vert].clipModel > 0.9) {
|
||||
// If the model was clipped in the vertex shader then we do not apply the shadow projection matrix here
|
||||
gl_Position = gl_in[vert].gl_Position;
|
||||
} else {
|
||||
gl_Position = shadow_proj_matrix[instanceID] * gl_in[vert].gl_Position;
|
||||
}
|
||||
#else
|
||||
gl_Position = shadow_proj_matrix[instanceID] * gl_in[vert].gl_Position;
|
||||
#endif
|
||||
if(gl_Position.z < -1.0)
|
||||
gl_Position.z = -1.0;
|
||||
|
||||
vertOut.position = gl_in[vert].gl_Position;
|
||||
vertOut.normal = vertIn[vert].normal;
|
||||
vertOut.texCoord = vertIn[vert].texCoord;
|
||||
|
||||
gl_Layer = instanceID;
|
||||
|
||||
#ifdef FLAG_ENV_MAP
|
||||
vertOut.envReflect = vertIn[vert].envReflect;
|
||||
#endif
|
||||
@@ -183,19 +197,66 @@ void main(void)
|
||||
vertOut.shadowUV[3] = vertIn[vert].shadowUV[3];
|
||||
vertOut.shadowPos = vertIn[vert].shadowPos;
|
||||
#endif
|
||||
#ifdef WORKAROUND_CLIPPING_PLANES
|
||||
#ifdef FLAG_TRANSFORM
|
||||
vertOut.notVisible = vertIn[vert].notVisible;
|
||||
#endif
|
||||
#ifdef FLAG_CLIP
|
||||
#if defined(FLAG_CLIP)
|
||||
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
|
||||
#endif
|
||||
#else
|
||||
#if defined(FLAG_CLIP) || defined(FLAG_TRANSFORM)
|
||||
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
|
||||
#endif
|
||||
#endif
|
||||
EmitVertex();
|
||||
}
|
||||
EndPrimitive();
|
||||
}
|
||||
#elif defined(FLAG_THICK_OUTLINE)
|
||||
const vec2 pixelOffsetDir[4] = vec2[](
|
||||
vec2(0.0, 1.0),
|
||||
vec2(1.0, 1.0),
|
||||
vec2(1.0, -1.0),
|
||||
vec2(0.0, -1.0)
|
||||
);
|
||||
void main(void)
|
||||
{
|
||||
for(int vert = 0; vert < gl_in.length(); vert++)
|
||||
{
|
||||
int nextVert = (vert + 1) % gl_in.length();
|
||||
vec4 clip = gl_in[vert].gl_Position;
|
||||
vec4 diff = gl_in[nextVert].gl_Position - clip; // vector from vert to the next vertex in the list
|
||||
vec2 normal = normalize(vec2(diff.y, -diff.x)); // Computing the normal of a 2D vector is actually rather simple...
|
||||
for (int lineVert = 0; lineVert < 4; ++lineVert)
|
||||
{
|
||||
// This is the pixel offset along the normal axis
|
||||
vec2 yOffPixel = pixelOffsetDir[lineVert].y * normal * (outlineWidth / 2.0);
|
||||
// This is the offset of the vertex along the vector between this vertex and the next one in the triangle
|
||||
vec2 xOff = pixelOffsetDir[lineVert].x * diff.xy;
|
||||
|
||||
// This is the final offset in clip space
|
||||
vec2 finalOffset = xOff + yOffPixel * vec2(vpwidth, vpheight) * clip.w;
|
||||
|
||||
gl_Position = vec4(clip.xyz + vec3(finalOffset, 0.0), clip.w);
|
||||
vertOut.position = vertIn[vert].position;
|
||||
vertOut.normal = vertIn[vert].normal;
|
||||
vertOut.texCoord = vertIn[vert].texCoord;
|
||||
|
||||
#ifdef FLAG_ENV_MAP
|
||||
vertOut.envReflect = vertIn[vert].envReflect;
|
||||
#endif
|
||||
#ifdef FLAG_NORMAL_MAP
|
||||
vertOut.tangentMatrix = vertIn[vert].tangentMatrix;
|
||||
#endif
|
||||
#ifdef FLAG_FOG
|
||||
vertOut.fogDist = vertIn[vert].fogDist;
|
||||
#endif
|
||||
#ifdef FLAG_SHADOWS
|
||||
vertOut.shadowUV[0] = vertIn[vert].shadowUV[0];
|
||||
vertOut.shadowUV[1] = vertIn[vert].shadowUV[1];
|
||||
vertOut.shadowUV[2] = vertIn[vert].shadowUV[2];
|
||||
vertOut.shadowUV[3] = vertIn[vert].shadowUV[3];
|
||||
vertOut.shadowPos = vertIn[vert].shadowPos;
|
||||
#endif
|
||||
#if defined(FLAG_CLIP)
|
||||
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
|
||||
#endif
|
||||
EmitVertex();
|
||||
}
|
||||
|
||||
EndPrimitive();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -36,7 +36,7 @@ layout (std140) uniform modelData {
|
||||
|
||||
model_light lights[MAX_LIGHTS];
|
||||
|
||||
float extrudeWidth;
|
||||
float outlineWidth;
|
||||
float fogStart;
|
||||
float fogScale;
|
||||
int buffer_matrix_offset;
|
||||
@@ -113,15 +113,15 @@ out VertexOutput {
|
||||
#ifdef FLAG_FOG
|
||||
float fogDist;
|
||||
#endif
|
||||
#ifdef WORKAROUND_CLIPPING_PLANES
|
||||
#ifdef FLAG_TRANSFORM
|
||||
float notVisible;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
#if !defined(GL_ARB_gpu_shader5)
|
||||
float instance;
|
||||
#endif
|
||||
#ifdef FLAG_TRANSFORM
|
||||
// This flag is needed to let the geometry shader know that it doesn't need to apply the
|
||||
// shadow projection to gl_Position
|
||||
float clipModel;
|
||||
#endif
|
||||
#else
|
||||
vec4 position;
|
||||
#endif
|
||||
@@ -152,19 +152,9 @@ void main()
|
||||
vec4 texCoord;
|
||||
mat4 orient = mat4(1.0);
|
||||
mat4 scale = mat4(1.0);
|
||||
#ifdef WORKAROUND_CLIPPING_PLANES
|
||||
#ifdef FLAG_TRANSFORM
|
||||
#ifdef FLAG_TRANSFORM
|
||||
bool clipModel;
|
||||
getModelTransform(orient, clipModel, int(vertModelID), buffer_matrix_offset);
|
||||
vertOut.notVisible = clipModel ? 1.0 : 0.0;
|
||||
#endif
|
||||
#else
|
||||
#ifdef FLAG_TRANSFORM
|
||||
bool clipModel;
|
||||
getModelTransform(orient, clipModel, int(vertModelID), buffer_matrix_offset);
|
||||
#else
|
||||
bool clipModel = false;
|
||||
#endif
|
||||
#endif
|
||||
texCoord = textureMatrix * vertTexCoord;
|
||||
vec4 vertex = vertPosition;
|
||||
@@ -188,9 +178,6 @@ void main()
|
||||
#else
|
||||
gl_Position = projMatrix * position;
|
||||
#endif
|
||||
#ifdef FLAG_NORMAL_EXTRUDE
|
||||
gl_Position.xy += (mat3(projMatrix) * normal.xyz).xy * gl_Position.z * extrudeWidth;
|
||||
#endif
|
||||
#ifdef FLAG_SHADOWS
|
||||
vec4 shadowPos = shadow_mv_matrix * modelMatrix * orient * vertPosition;
|
||||
vertOut.shadowPos = shadow_mv_matrix * modelMatrix * orient * vertPosition;
|
||||
@@ -213,31 +200,28 @@ void main()
|
||||
#ifdef FLAG_FOG
|
||||
vertOut.fogDist = clamp((gl_Position.z - fogStart) * 0.75 * fogScale, 0.0, 1.0);
|
||||
#endif
|
||||
#ifdef WORKAROUND_CLIPPING_PLANES
|
||||
if(use_clip_plane) {
|
||||
gl_ClipDistance[0] = dot(clip_equation, modelMatrix * orient * vertex);
|
||||
} else {
|
||||
gl_ClipDistance[0] = 1.0;
|
||||
}
|
||||
#else
|
||||
#ifdef FLAG_CLIP
|
||||
#ifdef FLAG_TRANSFORM
|
||||
if (clipModel) {
|
||||
gl_ClipDistance[0] = -1.0;
|
||||
} else if(use_clip_plane) {
|
||||
// Clip this model by moving all vertices outside the clip volume
|
||||
gl_Position = vec4(vec3(-2.0), 1.0);
|
||||
}
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
vertOut.clipModel = clipModel ? 1.0 : 0.0;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef FLAG_CLIP
|
||||
if(use_clip_plane) {
|
||||
gl_ClipDistance[0] = dot(clip_equation, modelMatrix * orient * vertex);
|
||||
} else {
|
||||
gl_ClipDistance[0] = 1.0;
|
||||
}
|
||||
#elif defined(FLAG_TRANSFORM)
|
||||
gl_ClipDistance[0] = clipModel ? -1.0 : 1.0;
|
||||
#endif
|
||||
#endif
|
||||
#ifndef FLAG_SHADOW_MAP
|
||||
#ifndef FLAG_SHADOW_MAP
|
||||
vertOut.position = position;
|
||||
vertOut.normal = normal;
|
||||
vertOut.texCoord = texCoord;
|
||||
#else
|
||||
#else
|
||||
vertOut.normal = normal;
|
||||
vertOut.texCoord = texCoord;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
local exts = {
|
||||
"",
|
||||
".lua",
|
||||
".lc"
|
||||
}
|
||||
|
||||
local function cfileLoader(name)
|
||||
local file = nil
|
||||
|
||||
for i,v in ipairs(exts) do
|
||||
local real_name = name .. v
|
||||
file = cf.openFile(real_name, "r", "data/scripts")
|
||||
|
||||
if (file:isValid()) then
|
||||
name = real_name
|
||||
break;
|
||||
end
|
||||
end
|
||||
|
||||
if (file == nil or not file:isValid()) then
|
||||
return "Module '" .. name .. "' is not known by the CFile system"
|
||||
end
|
||||
|
||||
local content = file:read("*a")
|
||||
file:close()
|
||||
|
||||
local func, err = loadstring(content, name)
|
||||
|
||||
if err then
|
||||
return err
|
||||
end
|
||||
|
||||
return func
|
||||
end
|
||||
|
||||
table.insert(package.loaders, 2, cfileLoader)
|
||||
@@ -5,7 +5,7 @@ IF(MSVC)
|
||||
set(RES_CONTENT)
|
||||
set(ARRAY_ELEMENTS)
|
||||
|
||||
FOREACH(file ${file_root_def_files_files})
|
||||
FOREACH(file ${default_files_files})
|
||||
set(INPUT_NAME "${CMAKE_CURRENT_SOURCE_DIR}/${file}")
|
||||
SET(OUTPUT "${GENERATED_SOURCE_DIR}/code/${file}")
|
||||
file(RELATIVE_PATH RELATIVE_FILE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/def_files" "${INPUT_NAME}")
|
||||
@@ -39,7 +39,7 @@ else()
|
||||
set(INCLUDE_LIST)
|
||||
set(ARRAY_ELEMENTS)
|
||||
|
||||
FOREACH(file ${file_root_def_files_files})
|
||||
FOREACH(file ${default_files_files})
|
||||
set(INPUT_NAME "${CMAKE_CURRENT_SOURCE_DIR}/${file}")
|
||||
SET(OUTPUT "${GENERATED_SOURCE_DIR}/code/${file}")
|
||||
file(RELATIVE_PATH RELATIVE_FILE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/def_files" "${INPUT_NAME}")
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
#include "events.h"
|
||||
|
||||
namespace events {
|
||||
|
||||
util::event<void> EngineUpdate;
|
||||
|
||||
util::event<void> EngineShutdown;
|
||||
|
||||
util::event<void, int, int> GameLeaveState;
|
||||
|
||||
util::event<void, int, int> GameEnterState;
|
||||
|
||||
util::event<void, const char*> GameMissionLoad;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils/event.h"
|
||||
|
||||
namespace events {
|
||||
|
||||
extern util::event<void> EngineUpdate;
|
||||
|
||||
extern util::event<void> EngineShutdown;
|
||||
|
||||
extern util::event<void, int, int> GameLeaveState;
|
||||
|
||||
extern util::event<void, int, int> GameEnterState;
|
||||
|
||||
extern util::event<void, const char*> GameMissionLoad;
|
||||
}
|
||||
@@ -1101,7 +1101,7 @@ void fs2netd_store_stats()
|
||||
if (Duplicate_login_detected) {
|
||||
Duplicate_login_detected = false;
|
||||
multi_display_chat_msg( XSTR("<Duplicate login detected - stats have been tossed>", 1582), 0, 0 );
|
||||
ml_string( XSTR("<Duplicate login detected - stats have been tossed>", 1583) );
|
||||
ml_string( XSTR("<Duplicate login detected - stats have been tossed>", 1582) );
|
||||
fs2netd_store_stats_results();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -483,7 +483,7 @@ void parse_helptbl(const char *filename)
|
||||
break;
|
||||
case 4: // $end
|
||||
default:
|
||||
Assertion(false, "This should never happen.\n");
|
||||
UNREACHABLE("This should never happen.\n");
|
||||
break;
|
||||
}
|
||||
} // end while
|
||||
|
||||
+14
-14
@@ -19,7 +19,7 @@
|
||||
|
||||
SCP_vector<game_snd> Snds;
|
||||
SCP_vector<game_snd> Snds_iface;
|
||||
SCP_vector<int> Snds_iface_handle;
|
||||
SCP_vector<sound_handle> Snds_iface_handle;
|
||||
|
||||
// jg18 - default priorities and limits for retail gameplay sounds
|
||||
static const int NUM_RETAIL_GAMEPLAY_SOUNDS = 192; // indices 0-191, from retail sounds.tbl
|
||||
@@ -260,7 +260,7 @@ void gamesnd_add_retail_default_enhanced_sound_data()
|
||||
|
||||
void gamesnd_play_iface(interface_snd_id n)
|
||||
{
|
||||
if (Snds_iface_handle[n.value()] >= 0)
|
||||
if (Snds_iface_handle[n.value()].isValid())
|
||||
snd_stop(Snds_iface_handle[n.value()]);
|
||||
|
||||
Snds_iface_handle[n.value()] = snd_play(gamesnd_get_interface_sound(n));
|
||||
@@ -565,9 +565,9 @@ void gamesnd_unload_gameplay_sounds()
|
||||
Assert( Snds.size() <= INT_MAX );
|
||||
for (SCP_vector<game_snd>::iterator gs = Snds.begin(); gs != Snds.end(); ++gs) {
|
||||
for (auto& entry : gs->sound_entries) {
|
||||
if (entry.id != -1) {
|
||||
if (entry.id.isValid()) {
|
||||
snd_unload(entry.id);
|
||||
entry.id = -1;
|
||||
entry.id = sound_load_id::invalid();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -599,9 +599,9 @@ void gamesnd_unload_interface_sounds()
|
||||
Assert( Snds_iface.size() < INT_MAX );
|
||||
for (SCP_vector<game_snd>::iterator si = Snds_iface.begin(); si != Snds_iface.end(); ++si) {
|
||||
for (auto& entry : si->sound_entries) {
|
||||
if ( entry.id != -1 ) {
|
||||
if (entry.id.isValid()) {
|
||||
snd_unload( entry.id );
|
||||
entry.id = -1;
|
||||
entry.id = sound_load_id::invalid();
|
||||
entry.id_sig = -1;
|
||||
}
|
||||
}
|
||||
@@ -617,6 +617,9 @@ void parse_gamesnd_old(game_snd* gs)
|
||||
gs->sound_entries.resize(1);
|
||||
auto& entry = gs->sound_entries.back();
|
||||
|
||||
// Default pitch is 1.0. This is set here in case we don't have a valid file name
|
||||
gs->pitch_range = util::UniformFloatRange(1.0f);
|
||||
|
||||
stuff_string(entry.filename, F_NAME, MAX_FILENAME_LEN, ",");
|
||||
|
||||
if (!stricmp(entry.filename, NOX("empty")))
|
||||
@@ -673,9 +676,6 @@ void parse_gamesnd_old(game_snd* gs)
|
||||
}
|
||||
}
|
||||
|
||||
// Default pitch is 1.0
|
||||
gs->pitch_range = util::UniformFloatRange(1.0f);
|
||||
|
||||
// check for extra values per Mantis #2408
|
||||
ignore_gray_space();
|
||||
if (stuff_int_optional(&temp, true) == 2)
|
||||
@@ -840,6 +840,9 @@ void parse_gamesnd_new(game_snd* gs, bool no_create)
|
||||
// New extended format found
|
||||
stuff_string(name, F_NAME, MAX_FILENAME_LEN);
|
||||
|
||||
// Default pitch is 1.0. This is set here in case we don't have a valid file name
|
||||
gs->pitch_range = util::UniformFloatRange(1.0f);
|
||||
|
||||
if (!stricmp(name, NOX("empty")))
|
||||
{
|
||||
entry->filename[0] = 0;
|
||||
@@ -914,9 +917,6 @@ void parse_gamesnd_new(game_snd* gs, bool no_create)
|
||||
error_display(1, "Invalid enhanced sound limit: %d\n", temp_limit);
|
||||
}
|
||||
}
|
||||
|
||||
// Default pitch is 1.0
|
||||
gs->pitch_range = util::UniformFloatRange(1.0f);
|
||||
}
|
||||
|
||||
void gamesnd_parse_entry(game_snd *gs, bool no_create, SCP_vector<game_snd> *lookupVector)
|
||||
@@ -1197,7 +1197,7 @@ void parse_sound_table(const char* filename)
|
||||
if (gamesnd_parse_line(&tempSound, "$Name:", &Snds_iface))
|
||||
{
|
||||
Snds_iface.push_back(game_snd(tempSound));
|
||||
Snds_iface_handle.push_back(-1);
|
||||
Snds_iface_handle.push_back(sound_handle::invalid());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1322,7 +1322,7 @@ float gamesnd_get_max_duration(game_snd* gs) {
|
||||
int max_length = 0;
|
||||
|
||||
for (auto& entry : gs->sound_entries) {
|
||||
if (entry.id < 0) {
|
||||
if (!entry.id.isValid()) {
|
||||
// Lazily load unloaded sound entries when required
|
||||
entry.id = snd_load(&entry, gs->flags);
|
||||
}
|
||||
|
||||
@@ -578,7 +578,7 @@ void parse_everything_else(const char *filename)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Assertion(false, "MageKing17 made a coding error somewhere, and you should laugh at him (and report this error).\n");
|
||||
UNREACHABLE("MageKing17 made a coding error somewhere, and you should laugh at him (and report this error).\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,3 +81,12 @@
|
||||
#define CLANG_ANALYZER_NORETURN
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define UNREACHABLE(msg, ...) \
|
||||
do { \
|
||||
os::dialogs::Error(__FILE__, __LINE__, msg, ##__VA_ARGS__); \
|
||||
} while (false)
|
||||
#else
|
||||
#define UNREACHABLE(msg, ...) __builtin_unreachable()
|
||||
#endif
|
||||
@@ -63,3 +63,10 @@
|
||||
* @brief Specifies that an analyzer should consider this function as no-return
|
||||
*/
|
||||
#define CLANG_ANALYZER_NORETURN
|
||||
|
||||
/**
|
||||
* @brief Specifies that the code at which point this macro appears at is unreachable
|
||||
* @param msg The message to display in debug mode
|
||||
* @param ... Format arguments for the message
|
||||
*/
|
||||
#define UNREACHABLE(msg, ...)
|
||||
@@ -72,3 +72,12 @@
|
||||
#endif
|
||||
|
||||
#define CLANG_ANALYZER_NORETURN
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define UNREACHABLE(msg, ...) \
|
||||
do { \
|
||||
os::dialogs::Error(__FILE__, __LINE__, msg, ##__VA_ARGS__); \
|
||||
} while (false)
|
||||
#else
|
||||
#define UNREACHABLE(msg, ...) __builtin_unreachable()
|
||||
#endif
|
||||
@@ -69,3 +69,12 @@
|
||||
#endif
|
||||
|
||||
#define CLANG_ANALYZER_NORETURN
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define UNREACHABLE(msg, ...) \
|
||||
do { \
|
||||
os::dialogs::Error(__FILE__, __LINE__, msg, ##__VA_ARGS__); \
|
||||
} while (false)
|
||||
#else
|
||||
#define UNREACHABLE(msg, ...) __builtin_unreachable()
|
||||
#endif
|
||||
@@ -82,3 +82,13 @@
|
||||
#define FALLTHROUGH
|
||||
|
||||
#define CLANG_ANALYZER_NORETURN
|
||||
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define UNREACHABLE(msg, ...) \
|
||||
do { \
|
||||
os::dialogs::Error(__FILE__, __LINE__, msg, ##__VA_ARGS__); \
|
||||
} while (false)
|
||||
#else
|
||||
#define UNREACHABLE(msg, ...) __assume(false)
|
||||
#endif
|
||||
@@ -19,17 +19,17 @@
|
||||
|
||||
#include "cmdline/cmdline.h"
|
||||
#include "debugconsole/console.h"
|
||||
#include "gamesequence/gamesequence.h" //WMC - for scripting hooks in gr_flip()
|
||||
#include "gamesequence/gamesequence.h" //WMC - for scripting hooks in gr_flip()
|
||||
#include "globalincs/systemvars.h"
|
||||
#include "graphics/2d.h"
|
||||
#include "graphics/matrix.h"
|
||||
#include "graphics/light.h"
|
||||
#include "graphics/font.h"
|
||||
#include "graphics/grbatch.h"
|
||||
#include "graphics/grinternal.h"
|
||||
#include "graphics/grstub.h"
|
||||
#include "graphics/light.h"
|
||||
#include "graphics/matrix.h"
|
||||
#include "graphics/opengl/gropengl.h"
|
||||
#include "graphics/opengl/gropengldraw.h"
|
||||
#include "graphics/grstub.h"
|
||||
#include "graphics/paths/PathRenderer.h"
|
||||
#include "graphics/util/GPUMemoryHeap.h"
|
||||
#include "graphics/util/UniformBuffer.h"
|
||||
@@ -37,9 +37,10 @@
|
||||
#include "io/keycontrol.h" // m!m
|
||||
#include "io/timer.h"
|
||||
#include "osapi/osapi.h"
|
||||
#include "scripting/scripting.h"
|
||||
#include "parse/parselo.h"
|
||||
#include "popup/popup.h"
|
||||
#include "render/3d.h"
|
||||
#include "scripting/scripting.h"
|
||||
#include "tracing/tracing.h"
|
||||
#include "utils/boost/hash_combine.h"
|
||||
|
||||
@@ -2152,8 +2153,7 @@ void gr_set_bitmap(int bitmap_num, int alphablend_mode, int bitblt_mode, float a
|
||||
void gr_flip(bool execute_scripting)
|
||||
{
|
||||
// m!m avoid running CHA_ONFRAME when the "Quit mission" popup is shown. See mantis 2446 for reference
|
||||
if (execute_scripting && !quit_mission_popup_shown)
|
||||
{
|
||||
if (execute_scripting && !popup_active()) {
|
||||
TRACE_SCOPE(tracing::LuaOnFrame);
|
||||
|
||||
//WMC - Do conditional hooks. Yippee!
|
||||
|
||||
+39
-39
@@ -186,7 +186,7 @@ enum shader_type {
|
||||
#define SDR_FLAG_MODEL_HDR (1<<18)
|
||||
#define SDR_FLAG_MODEL_AMBIENT_MAP (1<<19)
|
||||
#define SDR_FLAG_MODEL_NORMAL_ALPHA (1<<20)
|
||||
#define SDR_FLAG_MODEL_NORMAL_EXTRUDE (1<<21)
|
||||
#define SDR_FLAG_MODEL_THICK_OUTLINES (1<<21) // Renders the model geometry as an outline with configurable line width
|
||||
|
||||
#define SDR_FLAG_PARTICLE_POINT_GEN (1<<0)
|
||||
|
||||
@@ -776,7 +776,7 @@ typedef struct screen {
|
||||
void (*gf_render_primitives)(material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle, size_t buffer_offset);
|
||||
void (*gf_render_primitives_particle)(particle_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
|
||||
void (*gf_render_primitives_distortion)(distortion_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
|
||||
void (*gf_render_movie)(movie_material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, int buffer);
|
||||
void (*gf_render_movie)(movie_material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, int buffer, size_t buffer_offset);
|
||||
void (*gf_render_primitives_batched)(batched_bitmap_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
|
||||
void (*gf_render_nanovg)(nanovg_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
|
||||
void (*gf_render_decals)(decal_material* material_info, primitive_type prim_type, vertex_layout* layout, int num_elements, const indexed_vertex_source& buffers);
|
||||
@@ -942,67 +942,67 @@ void gr_shield_icon(coord2d coords[6], const int resize_mode = GR_RESIZE_FULL);
|
||||
|
||||
|
||||
// Here be the bitmap functions
|
||||
#define gr_bm_free_data GR_CALL(*gr_screen.gf_bm_free_data)
|
||||
#define gr_bm_create GR_CALL(*gr_screen.gf_bm_create)
|
||||
#define gr_bm_init GR_CALL(*gr_screen.gf_bm_init)
|
||||
#define gr_bm_page_in_start GR_CALL(*gr_screen.gf_bm_page_in_start)
|
||||
#define gr_bm_data GR_CALL(*gr_screen.gf_bm_data)
|
||||
#define gr_bm_free_data GR_CALL(gr_screen.gf_bm_free_data)
|
||||
#define gr_bm_create GR_CALL(gr_screen.gf_bm_create)
|
||||
#define gr_bm_init GR_CALL(gr_screen.gf_bm_init)
|
||||
#define gr_bm_page_in_start GR_CALL(gr_screen.gf_bm_page_in_start)
|
||||
#define gr_bm_data GR_CALL(gr_screen.gf_bm_data)
|
||||
|
||||
#define gr_bm_make_render_target GR_CALL(*gr_screen.gf_bm_make_render_target)
|
||||
#define gr_bm_make_render_target GR_CALL(gr_screen.gf_bm_make_render_target)
|
||||
|
||||
__inline int gr_bm_set_render_target(int n, int face = -1)
|
||||
{
|
||||
return (*gr_screen.gf_bm_set_render_target)(n, face);
|
||||
}
|
||||
|
||||
#define gr_set_texture_addressing GR_CALL(*gr_screen.gf_set_texture_addressing)
|
||||
#define gr_set_texture_addressing GR_CALL(gr_screen.gf_set_texture_addressing)
|
||||
|
||||
inline int gr_create_buffer(BufferType type, BufferUsageHint usage)
|
||||
{
|
||||
return (*gr_screen.gf_create_buffer)(type, usage);
|
||||
}
|
||||
|
||||
#define gr_delete_buffer GR_CALL(*gr_screen.gf_delete_buffer)
|
||||
#define gr_update_buffer_data GR_CALL(*gr_screen.gf_update_buffer_data)
|
||||
#define gr_update_buffer_data_offset GR_CALL(*gr_screen.gf_update_buffer_data_offset)
|
||||
#define gr_update_transform_buffer GR_CALL(*gr_screen.gf_update_transform_buffer)
|
||||
#define gr_delete_buffer GR_CALL(gr_screen.gf_delete_buffer)
|
||||
#define gr_update_buffer_data GR_CALL(gr_screen.gf_update_buffer_data)
|
||||
#define gr_update_buffer_data_offset GR_CALL(gr_screen.gf_update_buffer_data_offset)
|
||||
#define gr_update_transform_buffer GR_CALL(gr_screen.gf_update_transform_buffer)
|
||||
|
||||
#define gr_scene_texture_begin GR_CALL(*gr_screen.gf_scene_texture_begin)
|
||||
#define gr_scene_texture_end GR_CALL(*gr_screen.gf_scene_texture_end)
|
||||
#define gr_copy_effect_texture GR_CALL(*gr_screen.gf_copy_effect_texture)
|
||||
#define gr_scene_texture_begin GR_CALL(gr_screen.gf_scene_texture_begin)
|
||||
#define gr_scene_texture_end GR_CALL(gr_screen.gf_scene_texture_end)
|
||||
#define gr_copy_effect_texture GR_CALL(gr_screen.gf_copy_effect_texture)
|
||||
|
||||
#define gr_post_process_set_effect GR_CALL(*gr_screen.gf_post_process_set_effect)
|
||||
#define gr_post_process_set_defaults GR_CALL(*gr_screen.gf_post_process_set_defaults)
|
||||
#define gr_post_process_begin GR_CALL(*gr_screen.gf_post_process_begin)
|
||||
#define gr_post_process_end GR_CALL(*gr_screen.gf_post_process_end)
|
||||
#define gr_post_process_save_zbuffer GR_CALL(*gr_screen.gf_post_process_save_zbuffer)
|
||||
#define gr_post_process_set_effect GR_CALL(gr_screen.gf_post_process_set_effect)
|
||||
#define gr_post_process_set_defaults GR_CALL(gr_screen.gf_post_process_set_defaults)
|
||||
#define gr_post_process_begin GR_CALL(gr_screen.gf_post_process_begin)
|
||||
#define gr_post_process_end GR_CALL(gr_screen.gf_post_process_end)
|
||||
#define gr_post_process_save_zbuffer GR_CALL(gr_screen.gf_post_process_save_zbuffer)
|
||||
inline void gr_post_process_restore_zbuffer() {
|
||||
gr_screen.gf_post_process_restore_zbuffer();
|
||||
}
|
||||
|
||||
#define gr_deferred_lighting_begin GR_CALL(*gr_screen.gf_deferred_lighting_begin)
|
||||
#define gr_deferred_lighting_end GR_CALL(*gr_screen.gf_deferred_lighting_end)
|
||||
#define gr_deferred_lighting_finish GR_CALL(*gr_screen.gf_deferred_lighting_finish)
|
||||
#define gr_deferred_lighting_begin GR_CALL(gr_screen.gf_deferred_lighting_begin)
|
||||
#define gr_deferred_lighting_end GR_CALL(gr_screen.gf_deferred_lighting_end)
|
||||
#define gr_deferred_lighting_finish GR_CALL(gr_screen.gf_deferred_lighting_finish)
|
||||
|
||||
#define gr_zbias GR_CALL(*gr_screen.gf_zbias)
|
||||
#define gr_set_fill_mode GR_CALL(*gr_screen.gf_set_fill_mode)
|
||||
#define gr_zbias GR_CALL(gr_screen.gf_zbias)
|
||||
#define gr_set_fill_mode GR_CALL(gr_screen.gf_set_fill_mode)
|
||||
|
||||
#define gr_set_line_width GR_CALL(*gr_screen.gf_set_line_width)
|
||||
#define gr_set_line_width GR_CALL(gr_screen.gf_set_line_width)
|
||||
|
||||
#define gr_sphere GR_CALL(*gr_screen.gf_sphere)
|
||||
#define gr_sphere GR_CALL(gr_screen.gf_sphere)
|
||||
|
||||
#define gr_maybe_create_shader GR_CALL(*gr_screen.gf_maybe_create_shader)
|
||||
#define gr_recompile_all_shaders GR_CALL(*gr_screen.gf_recompile_all_shaders)
|
||||
#define gr_set_animated_effect GR_CALL(*gr_screen.gf_set_animated_effect)
|
||||
#define gr_maybe_create_shader GR_CALL(gr_screen.gf_maybe_create_shader)
|
||||
#define gr_recompile_all_shaders GR_CALL(gr_screen.gf_recompile_all_shaders)
|
||||
#define gr_set_animated_effect GR_CALL(gr_screen.gf_set_animated_effect)
|
||||
|
||||
#define gr_clear_states GR_CALL(*gr_screen.gf_clear_states)
|
||||
#define gr_clear_states GR_CALL(gr_screen.gf_clear_states)
|
||||
|
||||
#define gr_update_texture GR_CALL(*gr_screen.gf_update_texture)
|
||||
#define gr_get_bitmap_from_texture GR_CALL(*gr_screen.gf_get_bitmap_from_texture)
|
||||
#define gr_update_texture GR_CALL(gr_screen.gf_update_texture)
|
||||
#define gr_get_bitmap_from_texture GR_CALL(gr_screen.gf_get_bitmap_from_texture)
|
||||
|
||||
#define gr_shadow_map_start GR_CALL(*gr_screen.gf_shadow_map_start)
|
||||
#define gr_shadow_map_end GR_CALL(*gr_screen.gf_shadow_map_end)
|
||||
#define gr_render_shield_impact GR_CALL(*gr_screen.gf_render_shield_impact)
|
||||
#define gr_shadow_map_start GR_CALL(gr_screen.gf_shadow_map_start)
|
||||
#define gr_shadow_map_end GR_CALL(gr_screen.gf_shadow_map_end)
|
||||
#define gr_render_shield_impact GR_CALL(gr_screen.gf_render_shield_impact)
|
||||
|
||||
__inline void gr_render_primitives(material* material_info, primitive_type prim_type, vertex_layout* layout, int vert_offset, int n_verts, int buffer_handle = -1, size_t buffer_offset = 0)
|
||||
{
|
||||
@@ -1029,9 +1029,9 @@ __inline void gr_render_primitives_distortion(distortion_material* material_info
|
||||
(*gr_screen.gf_render_primitives_distortion)(material_info, prim_type, layout, offset, n_verts, buffer_handle);
|
||||
}
|
||||
|
||||
inline void gr_render_movie(movie_material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, int buffer)
|
||||
inline void gr_render_movie(movie_material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, int buffer, size_t buffer_offset = 0)
|
||||
{
|
||||
(*gr_screen.gf_render_movie)(material_info, prim_type, layout, n_verts, buffer);
|
||||
(*gr_screen.gf_render_movie)(material_info, prim_type, layout, n_verts, buffer, buffer_offset);
|
||||
}
|
||||
|
||||
__inline void gr_render_model(model_material* material_info, indexed_vertex_source *vert_source, vertex_buffer* bufferp, size_t texi)
|
||||
|
||||
@@ -158,32 +158,28 @@ int generic_anim_stream(generic_anim *ga, const bool cache)
|
||||
{
|
||||
CFILE *img_cfp = NULL;
|
||||
int anim_fps = 0;
|
||||
char full_path[MAX_PATH];
|
||||
size_t size = 0, offset = 0;
|
||||
const void* file_data = nullptr;
|
||||
const int NUM_TYPES = 3;
|
||||
const ubyte type_list[NUM_TYPES] = {BM_TYPE_EFF, BM_TYPE_ANI, BM_TYPE_PNG};
|
||||
const char *ext_list[NUM_TYPES] = {".eff", ".ani", ".png"};
|
||||
int rval = -1;
|
||||
int bpp;
|
||||
|
||||
ga->type = BM_TYPE_NONE;
|
||||
|
||||
rval = cf_find_file_location_ext(ga->filename, NUM_TYPES, ext_list, CF_TYPE_ANY, sizeof(full_path) - 1, full_path, &size, &offset, 0, &file_data);
|
||||
auto res = cf_find_file_location_ext(ga->filename, NUM_TYPES, ext_list, CF_TYPE_ANY, false);
|
||||
|
||||
// could not be found, or is invalid for some reason
|
||||
if ( (rval < 0) || (rval >= NUM_TYPES) )
|
||||
if ( !res.found )
|
||||
return -1;
|
||||
|
||||
//make sure we can open it
|
||||
img_cfp = cfopen_special(full_path, "rb", size, offset, file_data, CF_TYPE_ANY);
|
||||
img_cfp = cfopen_special(res.full_name.c_str(), "rb", res.size, res.offset, res.data_ptr, CF_TYPE_ANY);
|
||||
|
||||
if (img_cfp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcat_s(ga->filename, ext_list[rval]);
|
||||
ga->type = type_list[rval];
|
||||
strcat_s(ga->filename, ext_list[res.extension_index]);
|
||||
ga->type = type_list[res.extension_index];
|
||||
//seek to the end
|
||||
cfseek(img_cfp, 0, CF_SEEK_END);
|
||||
|
||||
|
||||
@@ -335,7 +335,7 @@ void gr_stub_render_primitives_distortion(distortion_material* /*material_info*
|
||||
{
|
||||
|
||||
}
|
||||
void gr_stub_render_movie(movie_material* /*material_info*/, primitive_type /*prim_type*/, vertex_layout* /*layout*/, int /*n_verts*/, int /*buffer*/)
|
||||
void gr_stub_render_movie(movie_material* /*material_info*/, primitive_type /*prim_type*/, vertex_layout* /*layout*/, int /*n_verts*/, int /*buffer*/, size_t /*buffer_offset*/)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
+12
-23
@@ -635,27 +635,6 @@ float model_material::get_normal_alpha_max() const
|
||||
return Normal_alpha_max;
|
||||
}
|
||||
|
||||
void model_material::set_normal_extrude(float width)
|
||||
{
|
||||
Normal_extrude = true;
|
||||
Normal_extrude_width = width;
|
||||
}
|
||||
|
||||
void model_material::set_normal_extrude()
|
||||
{
|
||||
Normal_extrude = false;
|
||||
}
|
||||
|
||||
bool model_material::is_normal_extrude_active() const
|
||||
{
|
||||
return Normal_extrude;
|
||||
}
|
||||
|
||||
float model_material::get_normal_extrude_width() const
|
||||
{
|
||||
return Normal_extrude_width;
|
||||
}
|
||||
|
||||
void model_material::set_fog(int r, int g, int b, float _near, float _far)
|
||||
{
|
||||
Fog_params.enabled = true;
|
||||
@@ -681,6 +660,16 @@ const model_material::fog& model_material::get_fog() const
|
||||
return Fog_params;
|
||||
}
|
||||
|
||||
void model_material::set_outline_thickness(float thickness) {
|
||||
Outline_thickness = thickness;
|
||||
}
|
||||
float model_material::get_outline_thickness() const {
|
||||
return Outline_thickness;
|
||||
}
|
||||
bool model_material::uses_thick_outlines() const {
|
||||
return Outline_thickness > 0.0f;
|
||||
}
|
||||
|
||||
uint model_material::get_shader_flags() const
|
||||
{
|
||||
uint Shader_flags = 0;
|
||||
@@ -768,8 +757,8 @@ uint model_material::get_shader_flags() const
|
||||
Shader_flags |= SDR_FLAG_MODEL_NORMAL_ALPHA;
|
||||
}
|
||||
|
||||
if ( Normal_extrude ) {
|
||||
Shader_flags |= SDR_FLAG_MODEL_NORMAL_EXTRUDE;
|
||||
if ( uses_thick_outlines() ) {
|
||||
Shader_flags |= SDR_FLAG_MODEL_THICK_OUTLINES;
|
||||
}
|
||||
|
||||
return Shader_flags;
|
||||
|
||||
@@ -200,10 +200,10 @@ class model_material : public material
|
||||
float Normal_alpha_min = 0.0f;
|
||||
float Normal_alpha_max = 1.0f;
|
||||
|
||||
bool Normal_extrude = false;
|
||||
float Normal_extrude_width = -1.0f;
|
||||
|
||||
fog Fog_params;
|
||||
|
||||
float Outline_thickness = -1.0f;
|
||||
|
||||
public:
|
||||
model_material();
|
||||
|
||||
@@ -246,10 +246,9 @@ public:
|
||||
float get_normal_alpha_min() const;
|
||||
float get_normal_alpha_max() const;
|
||||
|
||||
void set_normal_extrude(float width);
|
||||
void set_normal_extrude();
|
||||
bool is_normal_extrude_active() const;
|
||||
float get_normal_extrude_width() const;
|
||||
void set_outline_thickness(float thickness = -1.0f);
|
||||
float get_outline_thickness() const;
|
||||
bool uses_thick_outlines() const;
|
||||
|
||||
void set_batching(bool enabled);
|
||||
bool is_batched() const;
|
||||
|
||||
@@ -137,7 +137,7 @@ GLenum get_gl_shader_stage(opengl::ShaderStage stage) {
|
||||
case opengl::STAGE_FRAGMENT:
|
||||
return GL_FRAGMENT_SHADER;
|
||||
default:
|
||||
Assertion(false, "Unhandled shader type found!");
|
||||
UNREACHABLE("Unhandled shader type found!");
|
||||
return GL_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "math/floating.h"
|
||||
#include "model/model.h"
|
||||
#include "nebula/neb.h"
|
||||
#include "libs/renderdoc/renderdoc.h"
|
||||
#include "osapi/osapi.h"
|
||||
#include "osapi/osregistry.h"
|
||||
#include "render/3d.h"
|
||||
@@ -90,7 +91,8 @@ static GLenum GL_read_format = GL_BGRA;
|
||||
|
||||
GLuint GL_vao = 0;
|
||||
|
||||
bool GL_workaround_clipping_planes = false;
|
||||
SCP_string GL_implementation_id;
|
||||
SCP_vector<GLint> GL_binary_formats;
|
||||
|
||||
static std::unique_ptr<os::OpenGLContext> GL_context = nullptr;
|
||||
|
||||
@@ -1365,19 +1367,6 @@ static void init_extensions() {
|
||||
}
|
||||
}
|
||||
|
||||
static void opengl_do_workaround_checks() {
|
||||
auto vendor = glGetString(GL_VENDOR);
|
||||
|
||||
if (strstr((const char*) vendor, "NVIDIA")) {
|
||||
// Nvidia has some weird issues with clipping planes. Check #1579 for more information.
|
||||
GL_workaround_clipping_planes = true;
|
||||
mprintf((" Applying clipping plane workaround for NVIDIA hardware.\n"));
|
||||
} else {
|
||||
// Assume everone else has proper support for this
|
||||
GL_workaround_clipping_planes = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool gr_opengl_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps)
|
||||
{
|
||||
if (GL_initted) {
|
||||
@@ -1390,6 +1379,9 @@ bool gr_opengl_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps)
|
||||
gr_screen.max_h,
|
||||
gr_screen.bits_per_pixel ));
|
||||
|
||||
// Load the RenderDoc API if available before doing anything with OpenGL
|
||||
renderdoc::loadApi();
|
||||
|
||||
graphic_operations = std::move(graphicsOps);
|
||||
|
||||
if ( opengl_init_display_device() ) {
|
||||
@@ -1446,7 +1438,20 @@ bool gr_opengl_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps)
|
||||
mprintf(( " OpenGL Version : %s\n", glGetString(GL_VERSION) ));
|
||||
mprintf(( "\n" ));
|
||||
|
||||
opengl_do_workaround_checks();
|
||||
// Build a string identifier for this OpenGL implementation
|
||||
GL_implementation_id.clear();
|
||||
GL_implementation_id += reinterpret_cast<const char*>(glGetString(GL_VENDOR));
|
||||
GL_implementation_id += "\n";
|
||||
GL_implementation_id += reinterpret_cast<const char*>(glGetString(GL_RENDERER));
|
||||
GL_implementation_id += "\n";
|
||||
GL_implementation_id += reinterpret_cast<const char*>(glGetString(GL_VERSION));
|
||||
GL_implementation_id += "\n";
|
||||
GL_implementation_id += reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||
|
||||
GLint formats = 0;
|
||||
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &formats);
|
||||
GL_binary_formats.resize(formats);
|
||||
glGetIntegerv(GL_PROGRAM_BINARY_FORMATS, GL_binary_formats.data());
|
||||
|
||||
if (Cmdline_fullscreen_window || Cmdline_window) {
|
||||
opengl_go_windowed();
|
||||
|
||||
@@ -58,6 +58,7 @@ extern GLuint GL_vao;
|
||||
|
||||
extern float GL_alpha_threshold;
|
||||
|
||||
extern bool GL_workaround_clipping_planes; //!< If set then clipping planes can not be used for batched model rendering
|
||||
extern SCP_string GL_implementation_id;
|
||||
extern SCP_vector<GLint> GL_binary_formats;
|
||||
|
||||
#endif
|
||||
@@ -188,6 +188,9 @@ void gr_opengl_deferred_lighting_finish()
|
||||
light_data->lightDir.xyz.x = view_dir.xyzw.x;
|
||||
light_data->lightDir.xyz.y = view_dir.xyzw.y;
|
||||
light_data->lightDir.xyz.z = view_dir.xyzw.z;
|
||||
|
||||
vm_vec_scale(&light_data->specLightColor, static_light_factor);
|
||||
|
||||
first_directional = false;
|
||||
break;
|
||||
case Light_Type::Cone:
|
||||
@@ -199,6 +202,9 @@ void gr_opengl_deferred_lighting_finish()
|
||||
case Light_Type::Point:
|
||||
light_data->diffuseLightColor = diffuse;
|
||||
light_data->specLightColor = spec;
|
||||
|
||||
vm_vec_scale(&light_data->specLightColor, static_point_factor);
|
||||
|
||||
light_data->lightRadius = MAX(l.rada, l.radb) * 1.25f;
|
||||
light_data->scale.xyz.x = MAX(l.rada, l.radb) * 1.28f;
|
||||
light_data->scale.xyz.y = MAX(l.rada, l.radb) * 1.28f;
|
||||
@@ -217,10 +223,15 @@ void gr_opengl_deferred_lighting_finish()
|
||||
light_data->scale.xyz.y = l.radb * 1.53f;
|
||||
light_data->scale.xyz.z = length;
|
||||
|
||||
vm_vec_scale(&light_data->specLightColor, static_tube_factor);
|
||||
|
||||
// Tube lights consist of two different types of lights with almost the same properties
|
||||
light_data = uniformAligner.addTypedElement<deferred_light_data>();
|
||||
light_data->diffuseLightColor = diffuse;
|
||||
light_data->specLightColor = spec;
|
||||
|
||||
vm_vec_scale(&light_data->specLightColor, static_tube_factor);
|
||||
|
||||
light_data->lightRadius = l.radb * 1.5f;
|
||||
light_data->lightType = LT_POINT;
|
||||
|
||||
|
||||
@@ -786,18 +786,16 @@ void gr_opengl_render_primitives_distortion(distortion_material* material_info,
|
||||
GL_CHECK_FOR_ERRORS("start of gr_opengl_render_primitives_distortion()");
|
||||
}
|
||||
|
||||
void gr_opengl_render_movie(movie_material* material_info,
|
||||
primitive_type prim_type,
|
||||
vertex_layout* layout,
|
||||
int n_verts,
|
||||
int buffer) {
|
||||
void gr_opengl_render_movie(movie_material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts,
|
||||
int buffer, size_t buffer_offset)
|
||||
{
|
||||
GR_DEBUG_SCOPE("Render movie frame");
|
||||
|
||||
gr_set_2d_matrix();
|
||||
|
||||
opengl_tnl_set_material_movie(material_info);
|
||||
|
||||
opengl_render_primitives(prim_type, layout, n_verts, buffer, 0, 0);
|
||||
opengl_render_primitives(prim_type, layout, n_verts, buffer, 0, buffer_offset);
|
||||
|
||||
gr_end_2d_matrix();
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ void gr_opengl_render_primitives(material* material_info, primitive_type prim_ty
|
||||
void gr_opengl_render_primitives_particle(particle_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
|
||||
void gr_opengl_render_primitives_batched(batched_bitmap_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
|
||||
void gr_opengl_render_primitives_distortion(distortion_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
|
||||
void gr_opengl_render_movie(movie_material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, int buffer);
|
||||
void gr_opengl_render_movie(movie_material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, int buffer, size_t buffer_offset);
|
||||
void gr_opengl_render_nanovg(nanovg_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, int buffer_handle);
|
||||
void gr_opengl_render_decals(decal_material* material_info, primitive_type prim_type, vertex_layout* layout, int num_elements, const indexed_vertex_source& binding);
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ void gr_opengl_query_value(int obj, QueryType type) {
|
||||
glQueryCounter(slot.name, GL_TIMESTAMP);
|
||||
break;
|
||||
default:
|
||||
Assertion(false, "Unhandled enum value!");
|
||||
UNREACHABLE("Unhandled enum value!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "cfile/cfile.h"
|
||||
#include "cmdline/cmdline.h"
|
||||
#include "def_files/def_files.h"
|
||||
#include "graphics/2d.h"
|
||||
@@ -213,9 +214,9 @@ static opengl_shader_variant_t GL_shader_variants[] = {
|
||||
{ },
|
||||
"Normal Alpha" },
|
||||
|
||||
{ SDR_TYPE_MODEL, false, SDR_FLAG_MODEL_NORMAL_EXTRUDE, "FLAG_NORMAL_EXTRUDE",
|
||||
{ SDR_TYPE_MODEL, true, SDR_FLAG_MODEL_THICK_OUTLINES, "FLAG_THICK_OUTLINE",
|
||||
{ },
|
||||
"Normal Extrusion" },
|
||||
"Thick outlines" },
|
||||
|
||||
{ SDR_TYPE_EFFECT_PARTICLE, true, SDR_FLAG_PARTICLE_POINT_GEN, "FLAG_EFFECT_GEOMETRY",
|
||||
{ opengl_vert_attrib::UVEC },
|
||||
@@ -337,19 +338,20 @@ void opengl_shader_shutdown()
|
||||
GL_shader.clear();
|
||||
}
|
||||
|
||||
static SCP_string opengl_shader_get_header(shader_type type_id, int flags) {
|
||||
static SCP_string opengl_shader_get_header(shader_type type_id, int flags, bool has_geo_shader) {
|
||||
SCP_stringstream sflags;
|
||||
|
||||
sflags << "#version " << GLSL_version << " core\n";
|
||||
|
||||
if (GL_workaround_clipping_planes) {
|
||||
sflags << "#define WORKAROUND_CLIPPING_PLANES\n";
|
||||
}
|
||||
|
||||
if (Detail.lighting < 3) {
|
||||
sflags << "#define FLAG_LIGHT_MODEL_BLINN_PHONG\n";
|
||||
}
|
||||
|
||||
if (has_geo_shader) {
|
||||
// If there is a geometry shader then we define a special preprocessor symbol to make writing shaders easier
|
||||
sflags << "#define HAS_GEOMETRY_SHADER\n";
|
||||
}
|
||||
|
||||
if (type_id == SDR_TYPE_POST_PROCESS_MAIN || type_id == SDR_TYPE_POST_PROCESS_LIGHTSHAFTS || type_id == SDR_TYPE_POST_PROCESS_FXAA) {
|
||||
// ignore looking for variants. main post process, lightshafts, and FXAA shaders need special headers to be hacked in
|
||||
opengl_post_shader_header(sflags, type_id, flags);
|
||||
@@ -476,9 +478,9 @@ static SCP_string handle_includes(const char* filename, const SCP_string& origin
|
||||
return output.str();
|
||||
}
|
||||
|
||||
static SCP_vector<SCP_string> opengl_get_shader_content(shader_type type_id, const char* filename, int flags, shader_stage) {
|
||||
static SCP_vector<SCP_string> opengl_get_shader_content(shader_type type_id, const char* filename, int flags, bool has_geo_shader) {
|
||||
SCP_vector<SCP_string> parts;
|
||||
parts.push_back(opengl_shader_get_header(type_id, flags));
|
||||
parts.push_back(opengl_shader_get_header(type_id, flags, has_geo_shader));
|
||||
|
||||
parts.push_back(handle_includes(filename, opengl_load_shader(filename)));
|
||||
|
||||
@@ -505,6 +507,9 @@ static SCP_string get_shader_hash(const SCP_vector<SCP_string>& vert,
|
||||
md5.update(reinterpret_cast<const char*>(&i), sizeof(i));
|
||||
}
|
||||
|
||||
md5.update(GL_implementation_id.data(),
|
||||
(MD5::size_type)GL_implementation_id.size() * sizeof(SCP_string::value_type));
|
||||
|
||||
md5.finalize();
|
||||
|
||||
return md5.hexdigest();
|
||||
@@ -532,7 +537,8 @@ static bool load_cached_shader_binary(opengl::ShaderProgram* program, const SCP_
|
||||
auto metadata = base_filename + ".json";
|
||||
auto binary = base_filename + ".bin";
|
||||
|
||||
auto metadata_fp = cfopen(metadata.c_str(), "rb", CFILE_NORMAL, CF_TYPE_CACHE);
|
||||
auto metadata_fp = cfopen(metadata.c_str(), "rb", CFILE_NORMAL, CF_TYPE_CACHE, false,
|
||||
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
|
||||
if (!metadata_fp) {
|
||||
nprintf(("ShaderCache", "Metadata file does not exist.\n"));
|
||||
return false;
|
||||
@@ -559,7 +565,22 @@ static bool load_cached_shader_binary(opengl::ShaderProgram* program, const SCP_
|
||||
auto binary_format = (GLenum) format;
|
||||
json_decref(metadata_root);
|
||||
|
||||
auto binary_fp = cfopen(binary.c_str(), "rb", CFILE_NORMAL, CF_TYPE_CACHE);
|
||||
bool supported = false;
|
||||
for (auto supported_fmt : GL_binary_formats) {
|
||||
if ((GLenum)supported_fmt == binary_format) {
|
||||
supported = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!supported) {
|
||||
// This can happen in case an implementation stops supporting a particular binary format
|
||||
nprintf(("ShaderCache", "Unsupported binary format %d encountered in shader cache.\n", binary_format));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto binary_fp = cfopen(binary.c_str(), "rb", CFILE_NORMAL, CF_TYPE_CACHE, false,
|
||||
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
|
||||
if (!binary_fp) {
|
||||
nprintf(("ShaderCache", "Binary file does not exist.\n"));
|
||||
return false;
|
||||
@@ -622,7 +643,8 @@ static void cache_program_binary(GLuint program, const SCP_string& hash) {
|
||||
auto metadata_name = base_filename + ".json";
|
||||
auto binary_name = base_filename + ".bin";
|
||||
|
||||
auto metadata_fp = cfopen(metadata_name.c_str(), "wb", CFILE_NORMAL, CF_TYPE_CACHE);
|
||||
auto metadata_fp = cfopen(metadata_name.c_str(), "wb", CFILE_NORMAL, CF_TYPE_CACHE, false,
|
||||
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
|
||||
if (!metadata_fp) {
|
||||
mprintf(("Could not open shader cache metadata file!\n"));
|
||||
return;
|
||||
@@ -637,7 +659,8 @@ static void cache_program_binary(GLuint program, const SCP_string& hash) {
|
||||
cfclose(metadata_fp);
|
||||
json_decref(metadata);
|
||||
|
||||
auto binary_fp = cfopen(binary_name.c_str(), "wb", CFILE_NORMAL, CF_TYPE_CACHE);
|
||||
auto binary_fp = cfopen(binary_name.c_str(), "wb", CFILE_NORMAL, CF_TYPE_CACHE, false,
|
||||
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
|
||||
if (!binary_fp) {
|
||||
mprintf(("Could not open shader cache binary file!\n"));
|
||||
return;
|
||||
@@ -690,13 +713,13 @@ void opengl_compile_shader_actual(shader_type sdr, const uint &flags, opengl_sha
|
||||
}
|
||||
}
|
||||
|
||||
auto vert_content = opengl_get_shader_content(sdr_info->type_id, sdr_info->vert, flags, SDR_STAGE_VERTEX);
|
||||
auto frag_content = opengl_get_shader_content(sdr_info->type_id, sdr_info->frag, flags, SDR_STAGE_FRAGMENT);
|
||||
auto vert_content = opengl_get_shader_content(sdr_info->type_id, sdr_info->vert, flags, use_geo_sdr);
|
||||
auto frag_content = opengl_get_shader_content(sdr_info->type_id, sdr_info->frag, flags, use_geo_sdr);
|
||||
SCP_vector<SCP_string> geom_content;
|
||||
|
||||
if (use_geo_sdr) {
|
||||
// read geometry shader
|
||||
geom_content = opengl_get_shader_content(sdr_info->type_id, sdr_info->geo, flags, SDR_STAGE_GEOMETRY);
|
||||
geom_content = opengl_get_shader_content(sdr_info->type_id, sdr_info->geo, flags, use_geo_sdr);
|
||||
}
|
||||
|
||||
auto shader_hash = get_shader_hash(vert_content, geom_content, frag_content);
|
||||
@@ -835,6 +858,62 @@ void gr_opengl_recompile_all_shaders(const std::function<void(size_t, size_t)>&
|
||||
}
|
||||
}
|
||||
|
||||
static void opengl_purge_shader_cache_type(const char* ext) {
|
||||
|
||||
SCP_string filter("*.");
|
||||
filter += ext;
|
||||
|
||||
// Previously the cache files were stored in the mod directory. Since we have a better system now, those files
|
||||
// should be cleaned out. This is only needed if we have a mod directory since otherwise we would delete the actual
|
||||
// cache files
|
||||
if (Cmdline_mod != nullptr && strlen(Cmdline_mod) > 0) {
|
||||
SCP_vector<SCP_string> cache_files;
|
||||
cf_get_file_list(cache_files, CF_TYPE_CACHE, filter.c_str(), CF_SORT_NONE, nullptr,
|
||||
CF_LOCATION_TYPE_PRIMARY_MOD | CF_LOCATION_TYPE_SECONDARY_MODS);
|
||||
|
||||
for (auto& file : cache_files) {
|
||||
cf_delete((file + "." + ext).c_str(), CF_TYPE_CACHE,
|
||||
CF_LOCATION_TYPE_PRIMARY_MOD | CF_LOCATION_TYPE_SECONDARY_MODS);
|
||||
}
|
||||
}
|
||||
|
||||
SCP_vector<SCP_string> cache_files;
|
||||
SCP_vector<file_list_info> file_info;
|
||||
cf_get_file_list(cache_files, CF_TYPE_CACHE, filter.c_str(), CF_SORT_NONE, &file_info,
|
||||
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
|
||||
|
||||
Assertion(cache_files.size() == file_info.size(),
|
||||
"cf_get_file_list returned different sizes for file names and file informations!");
|
||||
|
||||
const auto TIMEOUT = 2.0 * 30.0 * 24.0 * 60.0 * 60.0; // purge timeout in seconds which is ~2 months
|
||||
const SCP_string PREFIX = "ogl_shader-";
|
||||
|
||||
auto now = std::time(nullptr);
|
||||
for (size_t i = 0; i < cache_files.size(); ++i) {
|
||||
auto& name = cache_files[i];
|
||||
auto write_time = file_info[i].write_time;
|
||||
|
||||
if (name.compare(0, PREFIX.size(), PREFIX) != 0) {
|
||||
// Not an OpenGL cache file
|
||||
continue;
|
||||
}
|
||||
|
||||
auto diff = std::difftime(now, write_time);
|
||||
|
||||
if (diff > TIMEOUT) {
|
||||
auto full_name = name + "." + ext;
|
||||
|
||||
cf_delete(full_name.c_str(), CF_TYPE_CACHE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void opengl_purge_old_shader_cache()
|
||||
{
|
||||
opengl_purge_shader_cache_type("json");
|
||||
opengl_purge_shader_cache_type("bin");
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the shader system. Creates a 1x1 texture that can be used as a fallback texture when framebuffer support is missing.
|
||||
* Also compiles the shaders used for particle rendering.
|
||||
@@ -859,6 +938,8 @@ void opengl_shader_init()
|
||||
// Reserve 32 shader slots. This should cover most use cases in real life.
|
||||
GL_shader.reserve(32);
|
||||
|
||||
opengl_purge_old_shader_cache();
|
||||
|
||||
// compile effect shaders
|
||||
gr_opengl_maybe_create_shader(SDR_TYPE_EFFECT_PARTICLE, 0);
|
||||
gr_opengl_maybe_create_shader(SDR_TYPE_EFFECT_PARTICLE, SDR_FLAG_PARTICLE_POINT_GEN);
|
||||
|
||||
@@ -106,7 +106,7 @@ static GLenum convertBufferType(BufferType type) {
|
||||
case BufferType::Uniform:
|
||||
return GL_UNIFORM_BUFFER;
|
||||
default:
|
||||
Assertion(false, "Unhandled enum value!");
|
||||
UNREACHABLE("Unhandled enum value!");
|
||||
return GL_INVALID_ENUM;
|
||||
}
|
||||
}
|
||||
@@ -120,7 +120,7 @@ static GLenum convertUsageHint(BufferUsageHint usage) {
|
||||
case BufferUsageHint::Streaming:
|
||||
return GL_STREAM_DRAW;
|
||||
default:
|
||||
Assertion(false, "Unhandled enum value!");
|
||||
UNREACHABLE("Unhandled enum value!");
|
||||
return GL_INVALID_ENUM;
|
||||
}
|
||||
}
|
||||
@@ -144,7 +144,7 @@ static GLenum convertStencilOp(const StencilOperation stencil_op) {
|
||||
case StencilOperation::Invert:
|
||||
return GL_INVERT;
|
||||
default:
|
||||
Assertion(false, "Unhandled enum value encountered!");
|
||||
UNREACHABLE("Unhandled enum value encountered!");
|
||||
return GL_NONE;
|
||||
}
|
||||
}
|
||||
@@ -177,7 +177,7 @@ static GLenum convertComparisionFunction(ComparisionFunction func) {
|
||||
mode = GL_NOTEQUAL;
|
||||
break;
|
||||
default:
|
||||
Assertion(false, "Unhandled comparision function value!");
|
||||
UNREACHABLE("Unhandled comparision function value!");
|
||||
mode = GL_ALWAYS;
|
||||
break;
|
||||
}
|
||||
@@ -758,18 +758,10 @@ void opengl_tnl_set_model_material(model_material *material_info)
|
||||
|
||||
GL_state.Texture.SetShaderMode(GL_TRUE);
|
||||
|
||||
if (GL_workaround_clipping_planes) {
|
||||
if (Current_shader->flags & SDR_FLAG_MODEL_CLIP) {
|
||||
GL_state.ClipDistance(0, true);
|
||||
} else {
|
||||
GL_state.ClipDistance(0, false);
|
||||
}
|
||||
if (Current_shader->flags & SDR_FLAG_MODEL_CLIP) {
|
||||
GL_state.ClipDistance(0, true);
|
||||
} else {
|
||||
if (Current_shader->flags & SDR_FLAG_MODEL_CLIP || Current_shader->flags & SDR_FLAG_MODEL_TRANSFORM) {
|
||||
GL_state.ClipDistance(0, true);
|
||||
} else {
|
||||
GL_state.ClipDistance(0, false);
|
||||
}
|
||||
GL_state.ClipDistance(0, false);
|
||||
}
|
||||
|
||||
uint32_t array_index;
|
||||
|
||||
@@ -270,6 +270,12 @@ void NanoVGRenderer::renderFill(NVGpaint* paint,
|
||||
const float* bounds,
|
||||
const NVGpath* paths,
|
||||
int npaths) {
|
||||
if (npaths <= 0) {
|
||||
// Ignore irrelevant render calls
|
||||
mprintf(("NanoVG asked us to render filled triangles but no paths were supplied!\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto call = addDrawCall();
|
||||
|
||||
call->type = CallType::Fill;
|
||||
@@ -331,6 +337,12 @@ void NanoVGRenderer::renderFill(NVGpaint* paint,
|
||||
}
|
||||
}
|
||||
void NanoVGRenderer::renderTriangles(NVGpaint* paint, NVGscissor* scissor, const NVGvertex* verts, int nverts) {
|
||||
if (nverts <= 0) {
|
||||
// Ignore irrelevant render calls
|
||||
mprintf(("NanoVG asked us to render triangles but no vertices were supplied!\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
_vertices.insert(_vertices.end(), verts, verts + nverts);
|
||||
|
||||
auto call = addDrawCall();
|
||||
@@ -354,6 +366,12 @@ void NanoVGRenderer::renderStroke(NVGpaint* paint,
|
||||
float strokeWidth,
|
||||
const NVGpath* paths,
|
||||
int npaths) {
|
||||
if (npaths <= 0) {
|
||||
// Ignore irrelevant render calls
|
||||
mprintf(("NanoVG asked us to render stroke triangles but no paths were supplied!\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
auto call = addDrawCall();
|
||||
|
||||
call->type = CallType::Stroke;
|
||||
|
||||
@@ -1333,13 +1333,15 @@ int fonsTextIterNext(FONScontext* stash, FONStextIter* iter, FONSquad* quad)
|
||||
{
|
||||
FONSglyph* glyph = NULL;
|
||||
const char* str = iter->next;
|
||||
unsigned int last_dec_status = FONS_UTF8_ACCEPT;
|
||||
iter->str = iter->next;
|
||||
|
||||
if (str == iter->end)
|
||||
return 0;
|
||||
|
||||
for (; str != iter->end; str++) {
|
||||
if (fons__decutf8(&iter->utf8state, &iter->codepoint, *(const unsigned char*)str))
|
||||
last_dec_status = fons__decutf8(&iter->utf8state, &iter->codepoint, *(const unsigned char*)str);
|
||||
if (last_dec_status)
|
||||
continue;
|
||||
str++;
|
||||
// Get glyph and quad
|
||||
@@ -1353,6 +1355,12 @@ int fonsTextIterNext(FONScontext* stash, FONStextIter* iter, FONSquad* quad)
|
||||
}
|
||||
iter->next = str;
|
||||
|
||||
if (last_dec_status) {
|
||||
// If we are here then the iterator reached the end of the string and UTF-8 encoding failed
|
||||
// In this case we do not have a valid code point so we need to return false
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -2316,12 +2316,12 @@ float nvgText(NVGcontext* ctx, float x, float y, const char* string, const char*
|
||||
while (fonsTextIterNext(ctx->fs, &iter, &q)) {
|
||||
float c[4*2];
|
||||
if (iter.prevGlyphIndex == -1) { // can not retrieve glyph?
|
||||
if (!nvg__allocTextAtlas(ctx))
|
||||
break; // no memory :(
|
||||
if (nverts != 0) {
|
||||
nvg__renderText(ctx, verts, nverts);
|
||||
nverts = 0;
|
||||
}
|
||||
if (!nvg__allocTextAtlas(ctx))
|
||||
break; // no memory :(
|
||||
iter = prevIter;
|
||||
fonsTextIterNext(ctx->fs, &iter, &q); // try again
|
||||
if (iter.prevGlyphIndex == -1) // still can not find glyph?
|
||||
|
||||
@@ -47,11 +47,11 @@ void convert_model_material(model_uniform_data* data_out,
|
||||
|
||||
data_out->color = material.get_color();
|
||||
|
||||
data_out->vpwidth = 1.0f / i2fl(gr_screen.max_w);
|
||||
data_out->vpheight = 1.0f / i2fl(gr_screen.max_h);
|
||||
if (shader_flags & SDR_FLAG_MODEL_ANIMATED) {
|
||||
data_out->anim_timer = material.get_animated_effect_time();
|
||||
data_out->effect_num = material.get_animated_effect();
|
||||
data_out->vpwidth = 1.0f / i2fl(gr_screen.max_w);
|
||||
data_out->vpheight = 1.0f / i2fl(gr_screen.max_h);
|
||||
}
|
||||
|
||||
if (shader_flags & SDR_FLAG_MODEL_CLIP) {
|
||||
@@ -267,8 +267,8 @@ void convert_model_material(model_uniform_data* data_out,
|
||||
data_out->normalAlphaMinMax.y = material.get_normal_alpha_max();
|
||||
}
|
||||
|
||||
if (shader_flags & SDR_FLAG_MODEL_NORMAL_EXTRUDE) {
|
||||
data_out->extrudeWidth = material.get_normal_extrude_width();
|
||||
if ( shader_flags & SDR_FLAG_MODEL_THICK_OUTLINES ) {
|
||||
data_out->outlineWidth = material.get_outline_thickness();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ BufferType getBufferType(GpuHeap heap_type) {
|
||||
return BufferType::Index;
|
||||
case GpuHeap::NUM_VALUES:
|
||||
default:
|
||||
Assertion(false, "Invalid heap type detected!");
|
||||
UNREACHABLE("Invalid heap type detected!");
|
||||
return BufferType::Vertex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ size_t getElementSize(uniform_block_type type) {
|
||||
return sizeof(graphics::decal_info);
|
||||
case uniform_block_type::NUM_BLOCK_TYPES:
|
||||
default:
|
||||
Assertion(false, "Invalid block type encountered!");
|
||||
UNREACHABLE("Invalid block type encountered!");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ size_t getHeaderSize(uniform_block_type type) {
|
||||
return 0;
|
||||
case uniform_block_type::NUM_BLOCK_TYPES:
|
||||
default:
|
||||
Assertion(false, "Invalid block type encountered!");
|
||||
UNREACHABLE("Invalid block type encountered!");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ struct model_uniform_data {
|
||||
|
||||
model_light lights[MAX_UNIFORM_LIGHTS];
|
||||
|
||||
float extrudeWidth;
|
||||
float outlineWidth;
|
||||
float fogStart;
|
||||
float fogScale;
|
||||
int buffer_matrix_offset;
|
||||
|
||||
+12
-12
@@ -85,7 +85,7 @@ int HUD_disable_except_messages = 0;
|
||||
color HUD_color_defaults[HUD_NUM_COLOR_LEVELS]; // array of colors with different alpha blending
|
||||
color HUD_color_debug; // grey debug text shown on HUD
|
||||
|
||||
static int Player_engine_snd_loop = -1;
|
||||
static sound_handle Player_engine_snd_loop = sound_handle::invalid();
|
||||
|
||||
// HUD render frame offsets
|
||||
float HUD_offset_x = 0.0f;
|
||||
@@ -1420,7 +1420,7 @@ void hud_update_frame(float /*frametime*/)
|
||||
}
|
||||
|
||||
if (Player_ai->target_objnum == -1) {
|
||||
if ( Target_static_looping != -1 ) {
|
||||
if (Target_static_looping.isValid()) {
|
||||
snd_stop(Target_static_looping);
|
||||
}
|
||||
return;
|
||||
@@ -1810,9 +1810,9 @@ void hud_render_gauges(int cockpit_display_num)
|
||||
*/
|
||||
void hud_stop_looped_engine_sounds()
|
||||
{
|
||||
if ( Player_engine_snd_loop > -1 ) {
|
||||
if (Player_engine_snd_loop.isValid()) {
|
||||
snd_stop(Player_engine_snd_loop);
|
||||
Player_engine_snd_loop = -1;
|
||||
Player_engine_snd_loop = sound_handle::invalid();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1831,9 +1831,9 @@ void update_throttle_sound()
|
||||
float percent_throttle;
|
||||
|
||||
if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
|
||||
if(Player_engine_snd_loop != -1){
|
||||
if (Player_engine_snd_loop.isValid()) {
|
||||
snd_stop(Player_engine_snd_loop);
|
||||
Player_engine_snd_loop = -1;
|
||||
Player_engine_snd_loop = sound_handle::invalid();
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -1851,16 +1851,16 @@ void update_throttle_sound()
|
||||
percent_throttle = Player_obj->phys_info.fspeed / Ships[Player_obj->instance].current_max_speed;
|
||||
}
|
||||
|
||||
if ( percent_throttle != last_percent_throttle || Player_engine_snd_loop == -1 ) {
|
||||
if (percent_throttle != last_percent_throttle || !Player_engine_snd_loop.isValid()) {
|
||||
|
||||
if ( percent_throttle < ZERO_PERCENT ) {
|
||||
if ( Player_engine_snd_loop > -1 ) {
|
||||
if (Player_engine_snd_loop.isValid()) {
|
||||
snd_stop(Player_engine_snd_loop); // Backslash - otherwise, long engine loops keep playing
|
||||
Player_engine_snd_loop = -1;
|
||||
Player_engine_snd_loop = sound_handle::invalid();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( Player_engine_snd_loop == -1 ){
|
||||
if (!Player_engine_snd_loop.isValid()) {
|
||||
Player_engine_snd_loop = snd_play_looping( gamesnd_get_game_sound(ship_get_sound(Player_obj, GameSounds::ENGINE)), 0.0f , -1, -1, percent_throttle * ENGINE_MAX_VOL, FALSE);
|
||||
} else {
|
||||
// The sound may have been trashed at the low-level if sound channel overflow.
|
||||
@@ -1869,7 +1869,7 @@ void update_throttle_sound()
|
||||
snd_set_volume(Player_engine_snd_loop, percent_throttle * ENGINE_MAX_VOL);
|
||||
}
|
||||
else {
|
||||
Player_engine_snd_loop = -1;
|
||||
Player_engine_snd_loop = sound_handle::invalid();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2895,7 +2895,7 @@ void HudGaugeSupport::render(float /*frametime*/)
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(outstr, "Waiting...");
|
||||
strcpy_s(outstr, XSTR("Waiting...", 1603));
|
||||
}
|
||||
}
|
||||
renderStringAlignCenter(position[0], position[1] + text_val_offset_y, w, outstr);
|
||||
|
||||
@@ -153,7 +153,7 @@ void parse_ssm(const char *filename)
|
||||
s.shape = SSM_SHAPE_SPHERE;
|
||||
break;
|
||||
default:
|
||||
Assertion(false, "Impossible return value from required_string_one_of(); get a coder!\n");
|
||||
UNREACHABLE("Impossible return value from required_string_one_of(); get a coder!\n");
|
||||
}
|
||||
} else {
|
||||
s.shape = SSM_SHAPE_CIRCLE;
|
||||
@@ -224,7 +224,7 @@ void ssm_get_random_start_pos(vec3d *out, vec3d *start, matrix *orient, size_t s
|
||||
switch (s->shape) {
|
||||
case SSM_SHAPE_SPHERE:
|
||||
// get a random vector in a sphere around the target
|
||||
vm_vec_random_in_sphere(&temp, start, orient, radius, 1);
|
||||
vm_vec_random_in_sphere(&temp, start, radius, 1);
|
||||
break;
|
||||
case SSM_SHAPE_CIRCLE:
|
||||
// get a random vector in the circle of the firing plane
|
||||
@@ -235,7 +235,7 @@ void ssm_get_random_start_pos(vec3d *out, vec3d *start, matrix *orient, size_t s
|
||||
vm_vec_scale_add(&temp, start, &orient->vec.fvec, radius);
|
||||
break;
|
||||
default:
|
||||
Assertion(false, "Unknown shape '%d' in SSM type #" SIZE_T_ARG " ('%s'). This should not be possible; get a coder!\n", s->shape, ssm_index, s->name);
|
||||
UNREACHABLE("Unknown shape '%d' in SSM type #" SIZE_T_ARG " ('%s'). This should not be possible; get a coder!\n", s->shape, ssm_index, s->name);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -1013,7 +1013,7 @@ void HudGaugeBrackets::renderBoundingBrackets(int x1, int y1, int x2, int y2, in
|
||||
tinfo_name = XSTR("Debris", 348);
|
||||
break;
|
||||
case OBJ_WEAPON:
|
||||
strcpy_s(temp_name, Weapon_info[Weapons[t_objp->instance].weapon_info_index].name);
|
||||
strcpy_s(temp_name, Weapon_info[Weapons[t_objp->instance].weapon_info_index].get_display_string());
|
||||
end_string_at_first_hash_symbol(temp_name);
|
||||
tinfo_name = temp_name;
|
||||
break;
|
||||
|
||||
@@ -1642,7 +1642,8 @@ void hud_config_as_player()
|
||||
void hud_config_color_save(char *name)
|
||||
{
|
||||
int idx;
|
||||
CFILE *out = cfopen(name, "wt", CFILE_NORMAL, CF_TYPE_PLAYERS);
|
||||
CFILE* out = cfopen(name, "wt", CFILE_NORMAL, CF_TYPE_PLAYERS, false,
|
||||
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
|
||||
char vals[255] = "";
|
||||
|
||||
// bad
|
||||
@@ -1843,7 +1844,8 @@ void hud_config_color_init()
|
||||
|
||||
// get a list of all hcf files
|
||||
memset(HC_filenames, 0, sizeof(char*) * MAX_HCF_FILES);
|
||||
HC_num_files = cf_get_file_list(MAX_HCF_FILES, HC_filenames, CF_TYPE_PLAYERS, "*.hcf", CF_SORT_NAME);
|
||||
HC_num_files = cf_get_file_list(MAX_HCF_FILES, HC_filenames, CF_TYPE_PLAYERS, "*.hcf", CF_SORT_NAME, nullptr,
|
||||
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
|
||||
}
|
||||
|
||||
void hud_config_color_close()
|
||||
|
||||
@@ -372,7 +372,7 @@ void HudGaugeEscort::renderIcon(int x, int y, int index)
|
||||
}
|
||||
|
||||
// print out ship name
|
||||
strcpy_s(buf, sp->ship_name);
|
||||
strcpy_s(buf, sp->get_display_string());
|
||||
font::force_fit_string(buf, 255, ship_name_max_width);
|
||||
|
||||
end_string_at_first_hash_symbol(buf);
|
||||
|
||||
+11
-11
@@ -36,8 +36,8 @@ vec3d lock_world_pos;
|
||||
|
||||
static float Lock_start_dist;
|
||||
|
||||
int Missile_track_loop = -1;
|
||||
int Missile_lock_loop = -1;
|
||||
sound_handle Missile_track_loop = sound_handle::invalid();
|
||||
sound_handle Missile_lock_loop = sound_handle::invalid();
|
||||
|
||||
int Lock_target_box_width[GR_NUM_RESOLUTIONS] = {
|
||||
19,
|
||||
@@ -606,9 +606,9 @@ void hud_do_lock_indicator(float frametime)
|
||||
return;
|
||||
|
||||
if (Player_ai->current_target_is_locked) {
|
||||
if ( Missile_track_loop > -1 ) {
|
||||
if (Missile_track_loop.isValid()) {
|
||||
snd_stop(Missile_track_loop);
|
||||
Missile_track_loop = -1;
|
||||
Missile_track_loop = sound_handle::invalid();
|
||||
|
||||
if (wip->hud_locked_snd.isValid())
|
||||
{
|
||||
@@ -622,9 +622,9 @@ void hud_do_lock_indicator(float frametime)
|
||||
}
|
||||
else {
|
||||
Player_ai->ai_flags.set(AI::AI_Flags::Seek_lock); // set this flag so multiplayer's properly track lock on other ships
|
||||
if ( Missile_lock_loop != -1 && snd_is_playing(Missile_lock_loop) ) {
|
||||
if (Missile_lock_loop.isValid() && snd_is_playing(Missile_lock_loop)) {
|
||||
snd_stop(Missile_lock_loop);
|
||||
Missile_lock_loop = -1;
|
||||
Missile_lock_loop = sound_handle::invalid();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -840,7 +840,7 @@ void hud_calculate_lock_position(float frametime)
|
||||
accumulated_y_pixels -= int_portion;
|
||||
}
|
||||
|
||||
if ( Missile_track_loop == -1 ) {
|
||||
if (!Missile_track_loop.isValid()) {
|
||||
if (wip->hud_tracking_snd.isValid())
|
||||
{
|
||||
Missile_track_loop = snd_play_looping( gamesnd_get_game_sound(wip->hud_tracking_snd), 0.0f , -1, -1);
|
||||
@@ -863,9 +863,9 @@ void hud_calculate_lock_position(float frametime)
|
||||
|
||||
} else {
|
||||
|
||||
if ( Missile_track_loop > -1 ) {
|
||||
if (Missile_track_loop.isValid()) {
|
||||
snd_stop(Missile_track_loop);
|
||||
Missile_track_loop = -1;
|
||||
Missile_track_loop = sound_handle::invalid();
|
||||
}
|
||||
|
||||
Player_ai->current_target_is_locked = 0;
|
||||
@@ -977,9 +977,9 @@ void hud_calculate_lock_start_pos()
|
||||
// hud_stop_looped_locking_sounds() will terminate any hud related looping sounds that are playing
|
||||
void hud_stop_looped_locking_sounds()
|
||||
{
|
||||
if ( Missile_track_loop > -1 ) {
|
||||
if (Missile_track_loop.isValid()) {
|
||||
snd_stop(Missile_track_loop);
|
||||
Missile_track_loop = -1;
|
||||
Missile_track_loop = sound_handle::invalid();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -558,7 +558,7 @@ void HUD_ship_sent_printf(int sh, const char *format, ...)
|
||||
tmp[sizeof(tmp)-1] = '\0';
|
||||
size_t len;
|
||||
|
||||
snprintf(tmp, sizeof(tmp)-1, NOX("%s: "), Ships[sh].ship_name);
|
||||
snprintf(tmp, sizeof(tmp)-1, NOX("%s: "), Ships[sh].get_display_string());
|
||||
len = strlen(tmp);
|
||||
|
||||
va_start(args, format);
|
||||
|
||||
@@ -30,6 +30,7 @@ void hud_observer_init(ship *shipp, ai_info *aip)
|
||||
// (we used to do a memcpy here, but that doesn't work any longer, so let's just assign the values we need)
|
||||
Hud_obs_ship.clear();
|
||||
strcpy_s(Hud_obs_ship.ship_name, shipp->ship_name);
|
||||
Hud_obs_ship.display_name = shipp->display_name;
|
||||
Hud_obs_ship.team = shipp->team;
|
||||
Hud_obs_ship.ai_index = shipp->ai_index;
|
||||
Hud_obs_ship.flags = shipp->flags;
|
||||
|
||||
@@ -404,7 +404,7 @@ int hud_squadmsg_count_ships(int add_to_menu)
|
||||
if (add_to_menu)
|
||||
{
|
||||
Assert ( Num_menu_items < MAX_MENU_ITEMS );
|
||||
strcpy_s( MsgItems[Num_menu_items].text, shipp->ship_name );
|
||||
strcpy_s( MsgItems[Num_menu_items].text, shipp->get_display_string() );
|
||||
end_string_at_first_hash_symbol(MsgItems[Num_menu_items].text); // truncate the name if it has a # in it
|
||||
MsgItems[Num_menu_items].instance = SHIP_INDEX(shipp);
|
||||
MsgItems[Num_menu_items].active = 1;
|
||||
|
||||
+48
-34
@@ -37,6 +37,7 @@
|
||||
#include "network/multi.h"
|
||||
#include "network/multiutil.h"
|
||||
#include "object/object.h"
|
||||
#include "libs/renderdoc/renderdoc.h"
|
||||
#include "parse/parselo.h"
|
||||
#include "playerman/player.h"
|
||||
#include "render/3dinternal.h"
|
||||
@@ -437,7 +438,7 @@ weapon_flash Weapon_flash_info;
|
||||
// Data used for the proximity warning
|
||||
typedef struct homing_beep_info
|
||||
{
|
||||
int snd_handle; // sound handle for last played beep
|
||||
sound_handle snd_handle; // sound handle for last played beep
|
||||
fix last_time_played; // time beep was last played
|
||||
int min_cycle_time; // time (in ms) for fastest cycling of the sound
|
||||
int max_cycle_time; // time (in ms) for slowest cycling of the sound
|
||||
@@ -446,7 +447,7 @@ typedef struct homing_beep_info
|
||||
float precalced_interp; // a precalculated value used in a linear interpretation
|
||||
} homing_beep_info;
|
||||
|
||||
homing_beep_info Homing_beep = { -1, 0, 150, 1000, 30.0f, 1500.0f, 1.729412f };
|
||||
homing_beep_info Homing_beep = {sound_handle::invalid(), 0, 150, 1000, 30.0f, 1500.0f, 1.729412f};
|
||||
|
||||
// Set at the start of a mission, used to decide how to draw the separation for the warning missile indicators
|
||||
float Min_warning_missile_dist;
|
||||
@@ -1009,7 +1010,7 @@ void hud_weapons_init()
|
||||
// init data used to play the homing "proximity warning" sound
|
||||
void hud_init_homing_beep()
|
||||
{
|
||||
Homing_beep.snd_handle = -1;
|
||||
Homing_beep.snd_handle = sound_handle::invalid();
|
||||
Homing_beep.last_time_played = 0;
|
||||
Homing_beep.precalced_interp = (Homing_beep.max_cycle_dist-Homing_beep.min_cycle_dist) / (Homing_beep.max_cycle_time - Homing_beep.min_cycle_time );
|
||||
}
|
||||
@@ -5292,16 +5293,18 @@ void hud_stuff_ship_name(char *ship_name_text, ship *shipp)
|
||||
if ( ((Iff_info[shipp->team].flags & IFFF_WING_NAME_HIDDEN) && (shipp->wingnum != -1)) || (shipp->flags[Ship::Ship_Flags::Hide_ship_name]) ) {
|
||||
*ship_name_text = 0;
|
||||
} else {
|
||||
strcpy(ship_name_text, shipp->ship_name);
|
||||
strcpy(ship_name_text, shipp->get_display_string());
|
||||
|
||||
// handle hash symbol
|
||||
end_string_at_first_hash_symbol(ship_name_text);
|
||||
|
||||
// handle translation
|
||||
if (Lcl_gr) {
|
||||
lcl_translate_targetbox_name_gr(ship_name_text);
|
||||
} else if (Lcl_pl) {
|
||||
lcl_translate_targetbox_name_pl(ship_name_text);
|
||||
if (!Disable_built_in_translations) {
|
||||
// handle translation
|
||||
if (Lcl_gr) {
|
||||
lcl_translate_targetbox_name_gr(ship_name_text);
|
||||
} else if (Lcl_pl) {
|
||||
lcl_translate_targetbox_name_pl(ship_name_text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5333,11 +5336,13 @@ void hud_stuff_ship_callsign(char *ship_callsign_text, ship *shipp)
|
||||
// handle hash symbol
|
||||
end_string_at_first_hash_symbol(ship_callsign_text);
|
||||
|
||||
// handle translation
|
||||
if (Lcl_gr) {
|
||||
lcl_translate_targetbox_name_gr(ship_callsign_text);
|
||||
} else if (Lcl_pl) {
|
||||
lcl_translate_targetbox_name_pl(ship_callsign_text);
|
||||
if (!Disable_built_in_translations) {
|
||||
// handle translation
|
||||
if (Lcl_gr) {
|
||||
lcl_translate_targetbox_name_gr(ship_callsign_text);
|
||||
} else if (Lcl_pl) {
|
||||
lcl_translate_targetbox_name_pl(ship_callsign_text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5362,11 +5367,13 @@ void hud_stuff_ship_class(char *ship_class_text, ship *shipp)
|
||||
// handle hash symbol
|
||||
end_string_at_first_hash_symbol(ship_class_text);
|
||||
|
||||
// handle translation
|
||||
if (Lcl_gr) {
|
||||
lcl_translate_targetbox_name_gr(ship_class_text);
|
||||
} else if (Lcl_pl) {
|
||||
lcl_translate_targetbox_name_pl(ship_class_text);
|
||||
if (!Disable_built_in_translations) {
|
||||
// handle translation
|
||||
if (Lcl_gr) {
|
||||
lcl_translate_targetbox_name_gr(ship_class_text);
|
||||
} else if (Lcl_pl) {
|
||||
lcl_translate_targetbox_name_pl(ship_class_text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5592,7 +5599,7 @@ void HudGaugeWeaponEnergy::render(float /*frametime*/)
|
||||
setGaugeColor(HUD_C_BRIGHT);
|
||||
|
||||
//Draw name
|
||||
renderString(currentx, currenty, "Energy");
|
||||
renderString(currentx, currenty, XSTR("Energy", 1616));
|
||||
currenty += line_height;
|
||||
|
||||
//Draw background
|
||||
@@ -5626,10 +5633,11 @@ void HudGaugeWeaponEnergy::render(float /*frametime*/)
|
||||
setGaugeColor(HUD_C_NORMAL);
|
||||
}
|
||||
if(gr_screen.max_w_unscaled == 640) {
|
||||
strcpy_s(shortened_name, Weapon_info[Player_ship->weapons.primary_bank_weapons[x]].get_display_string());
|
||||
font::force_fit_string(shortened_name, NAME_LENGTH, 55);
|
||||
renderString(currentx, currenty, shortened_name);
|
||||
} else {
|
||||
renderString(currentx, currenty, Weapon_info[Player_ship->weapons.primary_bank_weapons[x]].name);
|
||||
renderString(currentx, currenty, Weapon_info[Player_ship->weapons.primary_bank_weapons[x]].get_display_string());
|
||||
}
|
||||
|
||||
//Next 'line'
|
||||
@@ -5747,7 +5755,7 @@ void HudGaugeWeaponEnergy::render(float /*frametime*/)
|
||||
// show all primary banks
|
||||
for ( i = 0; i < Player_ship->weapons.num_primary_banks; i++ ) {
|
||||
wip = &Weapon_info[sw->primary_bank_weapons[i]];
|
||||
strcpy_s(buf, (wip->alt_name[0]) ? wip->alt_name : wip->name);
|
||||
strcpy_s(buf, wip->get_display_string());
|
||||
|
||||
if ( Armed_alignment ) {
|
||||
gr_get_string_size(&w, &h, buf);
|
||||
@@ -5761,7 +5769,7 @@ void HudGaugeWeaponEnergy::render(float /*frametime*/)
|
||||
// just show the current armed bank
|
||||
i = Player_ship->weapons.current_primary_bank;
|
||||
wip = &Weapon_info[sw->primary_bank_weapons[i]];
|
||||
strcpy_s(buf, (wip->alt_name[0]) ? wip->alt_name : wip->name);
|
||||
strcpy_s(buf, wip->get_display_string());
|
||||
|
||||
if ( Armed_alignment ) {
|
||||
gr_get_string_size(&w, &h, buf);
|
||||
@@ -6051,8 +6059,8 @@ void HudGaugeWeapons::render(float /*frametime*/)
|
||||
renderBitmap(primary_last[ballistic_hud_index].first_frame, position[0] + frame_offset_x[ballistic_hud_index], y);
|
||||
}
|
||||
|
||||
strcpy_s(name, (Weapon_info[sw->primary_bank_weapons[i]].alt_name[0]) ? Weapon_info[sw->primary_bank_weapons[i]].alt_name : Weapon_info[sw->primary_bank_weapons[i]].name);
|
||||
if (Lcl_gr) {
|
||||
strcpy_s(name, Weapon_info[sw->primary_bank_weapons[i]].get_display_string());
|
||||
if (Lcl_gr && !Disable_built_in_translations) {
|
||||
lcl_translate_wep_name_gr(name);
|
||||
}
|
||||
|
||||
@@ -6119,11 +6127,16 @@ void HudGaugeWeapons::render(float /*frametime*/)
|
||||
|
||||
maybeFlashWeapon(np+i);
|
||||
|
||||
// HACK - make Cluster Bomb fit on the HUD.
|
||||
if(!stricmp(wip->name,"cluster bomb")){
|
||||
strcpy_s(weapon_name, NOX("Cluster"));
|
||||
if (wip->has_alternate_name()) {
|
||||
// Do not apply the cluster bomb hack if we have an alternate name to make translating that name possible
|
||||
strcpy_s(weapon_name, wip->get_display_string());
|
||||
} else {
|
||||
strcpy_s(weapon_name, (wip->alt_name[0]) ? wip->alt_name : wip->name);
|
||||
// HACK - make Cluster Bomb fit on the HUD.
|
||||
if(!stricmp(wip->name,"cluster bomb")){
|
||||
strcpy_s(weapon_name, NOX("Cluster"));
|
||||
} else {
|
||||
strcpy_s(weapon_name, wip->get_display_string());
|
||||
}
|
||||
}
|
||||
|
||||
// get rid of #
|
||||
@@ -6684,7 +6697,7 @@ void HudGaugeWarheadCount::render(float /*frametime*/)
|
||||
}
|
||||
|
||||
char weapon_name[NAME_LENGTH + 10];
|
||||
strcpy_s(weapon_name, (wip->alt_name[0]) ? wip->alt_name : wip->name);
|
||||
strcpy_s(weapon_name, wip->get_display_string());
|
||||
end_string_at_first_hash_symbol(weapon_name);
|
||||
|
||||
setGaugeColor();
|
||||
@@ -6921,9 +6934,9 @@ void HudGaugePrimaryWeapons::render(float /*frametime*/)
|
||||
|
||||
renderBitmap(_background_entry.first_frame, position[0], position[1] + bg_y_offset);
|
||||
|
||||
strcpy_s(name, (Weapon_info[sw->primary_bank_weapons[i]].alt_name[0]) ? Weapon_info[sw->primary_bank_weapons[i]].alt_name : Weapon_info[sw->primary_bank_weapons[i]].name);
|
||||
strcpy_s(name, Weapon_info[sw->primary_bank_weapons[i]].get_display_string());
|
||||
|
||||
if (Lcl_gr) {
|
||||
if (Lcl_gr && !Disable_built_in_translations) {
|
||||
lcl_translate_wep_name_gr(name);
|
||||
}
|
||||
|
||||
@@ -7040,7 +7053,7 @@ void HudGaugeSecondaryWeapons::render(float /*frametime*/)
|
||||
|
||||
maybeFlashWeapon(num_primaries+i);
|
||||
|
||||
strcpy_s(weapon_name, (wip->alt_name[0]) ? wip->alt_name : wip->name);
|
||||
strcpy_s(weapon_name, wip->get_display_string());
|
||||
end_string_at_first_hash_symbol(weapon_name);
|
||||
|
||||
if ( sw->current_secondary_bank == i ) {
|
||||
@@ -7182,7 +7195,8 @@ void HudGaugeHardpoints::render(float /*frametime*/)
|
||||
|
||||
render_info.set_color(gauge_color);
|
||||
render_info.set_flags(MR_NO_LIGHTING | MR_AUTOCENTER | MR_NO_FOGGING | MR_NO_TEXTURING | MR_NO_ZBUFFER | MR_NO_CULL | MR_STENCIL_READ);
|
||||
render_info.set_normal_extrude_width(_line_width * 0.01f);
|
||||
// Factor was chosen pretty arbitrarily to make outline feature work with existing data
|
||||
render_info.set_outline_thickness(15.f * _line_width);
|
||||
|
||||
model_render_immediate(
|
||||
&render_info,
|
||||
|
||||
+23
-17
@@ -55,7 +55,7 @@ object *Enemy_attacker = NULL;
|
||||
|
||||
static int Target_static_next;
|
||||
static int Target_static_playing;
|
||||
int Target_static_looping;
|
||||
sound_handle Target_static_looping = sound_handle::invalid();
|
||||
|
||||
int Target_display_cargo;
|
||||
char Cargo_string[256] = "";
|
||||
@@ -1008,7 +1008,7 @@ void HudGaugeTargetBox::renderTargetWeapon(object *target_objp)
|
||||
setGaugeColor();
|
||||
|
||||
// print out the weapon class name
|
||||
sprintf( outstr,"%s", target_wip->name );
|
||||
sprintf( outstr,"%s", target_wip->get_display_string() );
|
||||
gr_get_string_size(&w,&h,outstr);
|
||||
|
||||
// drop name past the # sign
|
||||
@@ -1034,7 +1034,7 @@ void HudGaugeTargetBox::renderTargetWeapon(object *target_objp)
|
||||
dist = vm_vec_dist(&target_objp->pos, &wp->homing_pos);
|
||||
|
||||
if ( speed > 0 ) {
|
||||
sprintf(outstr, NOX("impact: %.1f sec"), dist/speed);
|
||||
sprintf(outstr, XSTR("impact: %.1f sec", 1596), dist/speed);
|
||||
} else {
|
||||
strcpy_s(outstr, XSTR( "unknown", 349));
|
||||
}
|
||||
@@ -1405,7 +1405,7 @@ void HudGaugeExtraTargetData::pageIn()
|
||||
*/
|
||||
void HudGaugeExtraTargetData::render(float /*frametime*/)
|
||||
{
|
||||
char outstr[256], tmpbuf[256];
|
||||
char tmpbuf[256];
|
||||
int has_orders = 0;
|
||||
int not_training;
|
||||
int extra_data_shown=0;
|
||||
@@ -1440,17 +1440,22 @@ void HudGaugeExtraTargetData::render(float /*frametime*/)
|
||||
!(Iff_info[target_shipp->team].flags & IFFF_ORDERS_HIDDEN)))
|
||||
&& Ship_info[target_shipp->ship_info_index].is_flyable()) {
|
||||
extra_data_shown = 1;
|
||||
if (ship_return_orders(outstr, target_shipp)) {
|
||||
auto orders = ship_return_orders(target_shipp);
|
||||
if (!orders.empty()) {
|
||||
char outstr[256];
|
||||
strcpy_s(outstr, orders.c_str());
|
||||
font::force_fit_string(outstr, 255, order_max_w);
|
||||
orders = outstr;
|
||||
has_orders = 1;
|
||||
} else {
|
||||
strcpy_s(outstr, XSTR("no orders", 337));
|
||||
orders = XSTR("no orders", 337);
|
||||
}
|
||||
|
||||
renderString(position[0] + order_offsets[0], position[1] + order_offsets[1], EG_TBOX_EXTRA1, outstr);
|
||||
renderString(position[0] + order_offsets[0], position[1] + order_offsets[1], EG_TBOX_EXTRA1, orders.c_str());
|
||||
}
|
||||
|
||||
if ( has_orders ) {
|
||||
char outstr[256];
|
||||
strcpy_s(outstr, XSTR( "time to: ", 338));
|
||||
if ( ship_return_time_to_goal(tmpbuf, target_shipp) ) {
|
||||
strcat_s(outstr, tmpbuf);
|
||||
@@ -1471,10 +1476,11 @@ void HudGaugeExtraTargetData::render(float /*frametime*/)
|
||||
// count the objects directly docked to me
|
||||
int dock_count = dock_count_direct_docked_objects(target_objp);
|
||||
|
||||
char outstr[256];
|
||||
// docked to only one object
|
||||
if (dock_count == 1)
|
||||
{
|
||||
sprintf(outstr, XSTR("Docked: %s", 339), Ships[dock_get_first_docked_object(target_objp)->instance].ship_name);
|
||||
sprintf(outstr, XSTR("Docked: %s", 339), Ships[dock_get_first_docked_object(target_objp)->instance].get_display_string());
|
||||
end_string_at_first_hash_symbol(outstr);
|
||||
}
|
||||
// docked to multiple objects
|
||||
@@ -2040,10 +2046,10 @@ void HudGaugeTargetBox::showTargetData(float /*frametime*/)
|
||||
float dot, dist;
|
||||
vec3d v2t;
|
||||
|
||||
if (aip->target_objnum == Player_obj-Objects)
|
||||
if (aip->target_objnum == OBJ_INDEX(Player_obj))
|
||||
strcpy_s(target_str, "Player!");
|
||||
else
|
||||
sprintf(target_str, "%s", Ships[Objects[aip->target_objnum].instance].ship_name);
|
||||
sprintf(target_str, "%s", Ships[Objects[aip->target_objnum].instance].get_display_string());
|
||||
|
||||
gr_printf_no_resize(sx, sy, "Targ: %s", target_str);
|
||||
sy += dy;
|
||||
@@ -2091,14 +2097,14 @@ void HudGaugeTargetBox::showTargetData(float /*frametime*/)
|
||||
eshipp = &Ships[Enemy_attacker->instance];
|
||||
eaip = &Ai_info[eshipp->ai_index];
|
||||
|
||||
if (eaip->target_objnum == Player_obj-Objects) {
|
||||
if (eaip->target_objnum == OBJ_INDEX(Player_obj)) {
|
||||
found = 1;
|
||||
dist = vm_vec_dist_quick(&Enemy_attacker->pos, &Player_obj->pos);
|
||||
vm_vec_normalized_dir(&v2t,&Objects[eaip->target_objnum].pos, &Enemy_attacker->pos);
|
||||
|
||||
dot = vm_vec_dot(&v2t, &Enemy_attacker->orient.vec.fvec);
|
||||
|
||||
gr_printf_no_resize(sx, sy, "#%i: %s", OBJ_INDEX(Enemy_attacker), Ships[Enemy_attacker->instance].ship_name);
|
||||
gr_printf_no_resize(sx, sy, "#%i: %s", OBJ_INDEX(Enemy_attacker), Ships[Enemy_attacker->instance].get_display_string());
|
||||
sy += dy;
|
||||
gr_printf_no_resize(sx, sy, "Targ dist: %5.1f", dist);
|
||||
sy += dy;
|
||||
@@ -2158,7 +2164,7 @@ void HudGaugeTargetBox::showTargetData(float /*frametime*/)
|
||||
gr_printf_no_resize(sx,sy,"%s", outstr);
|
||||
sy += dy;
|
||||
for ( i = 0; i < swp->num_primary_banks; i++ ) {
|
||||
sprintf(outstr,"%d. %s", i+1, Weapon_info[swp->primary_bank_weapons[i]].name);
|
||||
sprintf(outstr,"%d. %s", i+1, Weapon_info[swp->primary_bank_weapons[i]].get_display_string());
|
||||
gr_printf_no_resize(sx,sy,"%s", outstr);
|
||||
sy += dy;
|
||||
}
|
||||
@@ -2168,7 +2174,7 @@ void HudGaugeTargetBox::showTargetData(float /*frametime*/)
|
||||
gr_printf_no_resize(sx,sy,"%s", outstr);
|
||||
sy += dy;
|
||||
for ( i = 0; i < swp->num_secondary_banks; i++ ) {
|
||||
sprintf(outstr,"%d. %s", i+1, Weapon_info[swp->secondary_bank_weapons[i]].name);
|
||||
sprintf(outstr,"%d. %s", i+1, Weapon_info[swp->secondary_bank_weapons[i]].get_display_string());
|
||||
gr_printf_no_resize(sx,sy,"%s", outstr);
|
||||
sy += dy;
|
||||
}
|
||||
@@ -2222,13 +2228,13 @@ void hud_update_target_static()
|
||||
}
|
||||
|
||||
if ( Target_static_playing ) {
|
||||
if ( Target_static_looping == -1 ) {
|
||||
if (!Target_static_looping.isValid()) {
|
||||
Target_static_looping = snd_play_looping(gamesnd_get_game_sound(GameSounds::STATIC));
|
||||
}
|
||||
} else {
|
||||
if ( Target_static_looping != -1 ) {
|
||||
if (Target_static_looping.isValid()) {
|
||||
snd_stop(Target_static_looping);
|
||||
Target_static_looping = -1;
|
||||
Target_static_looping = sound_handle::invalid();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ class object;
|
||||
#define TBOX_FLASH_STATUS 3
|
||||
#define TBOX_FLASH_SUBSYS 4
|
||||
|
||||
extern int Target_static_looping;
|
||||
extern sound_handle Target_static_looping;
|
||||
extern int Target_display_cargo;
|
||||
extern char Cargo_string[256];
|
||||
|
||||
|
||||
+12
-15
@@ -140,7 +140,7 @@ size_t factor_table::getNext(size_t n, size_t current)
|
||||
}
|
||||
}
|
||||
|
||||
Assertion(false, "For some reason, factor_table::getNext() was unable to locate the current factor. This should never happen; get a coder!\n");
|
||||
UNREACHABLE("For some reason, factor_table::getNext() was unable to locate the current factor. This should never happen; get a coder!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -211,7 +211,6 @@ static struct Cheat cheatsTable[] = {
|
||||
|
||||
int Tool_enabled = 0;
|
||||
bool Perspective_locked=false;
|
||||
bool quit_mission_popup_shown = false;
|
||||
|
||||
extern int AI_watch_object;
|
||||
extern int Countermeasures_enabled;
|
||||
@@ -897,7 +896,7 @@ void process_debug_keys(int k)
|
||||
object *objp = &Objects[Player_ai->target_objnum];
|
||||
|
||||
objp->flags.toggle(Object::Object_Flags::Invulnerable);
|
||||
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Player's target [%s] is %s", 13), Ships[objp->instance].ship_name, objp->flags[Object::Object_Flags::Invulnerable] ? XSTR( "now INVULNERABLE!", 11) : XSTR( "no longer invulnerable...", 12));
|
||||
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Player's target [%s] is %s", 13), Ships[objp->instance].get_display_string(), objp->flags[Object::Object_Flags::Invulnerable] ? XSTR( "now INVULNERABLE!", 11) : XSTR( "no longer invulnerable...", 12));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -977,7 +976,7 @@ void process_debug_keys(int k)
|
||||
int *weap = &shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank];
|
||||
*weap = get_next_weapon_looped(*weap, WP_MISSILE);
|
||||
|
||||
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary Weapon forced to %s", 18), Weapon_info[*weap].name);
|
||||
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary Weapon forced to %s", 18), Weapon_info[*weap].get_display_string());
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -990,7 +989,7 @@ void process_debug_keys(int k)
|
||||
int *weap = &shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank];
|
||||
*weap = get_prev_weapon_looped(*weap, WP_MISSILE);
|
||||
|
||||
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary Weapon forced to %s", 18), Weapon_info[*weap].name);
|
||||
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary Weapon forced to %s", 18), Weapon_info[*weap].get_display_string());
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1019,7 +1018,7 @@ void process_debug_keys(int k)
|
||||
int *weap = &shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank];
|
||||
*weap = get_next_weapon_looped(*weap, WP_LASER);
|
||||
|
||||
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Primary Weapon forced to %s", 19), Weapon_info[*weap].name);
|
||||
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Primary Weapon forced to %s", 19), Weapon_info[*weap].get_display_string());
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1031,7 +1030,7 @@ void process_debug_keys(int k)
|
||||
int *weap = &shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank];
|
||||
*weap = get_prev_weapon_looped(*weap, WP_LASER);
|
||||
|
||||
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Primary Weapon forced to %s", 19), Weapon_info[*weap].name);
|
||||
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Primary Weapon forced to %s", 19), Weapon_info[*weap].get_display_string());
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1067,12 +1066,12 @@ void process_debug_keys(int k)
|
||||
|
||||
if (is_support_allowed(obj_to_rearm))
|
||||
{
|
||||
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR("Issuing rearm request for %s", -1), Ships[obj_to_rearm->instance].ship_name);
|
||||
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR("Issuing rearm request for %s", 1610), Ships[obj_to_rearm->instance].get_display_string());
|
||||
ai_issue_rearm_request(obj_to_rearm);
|
||||
}
|
||||
else
|
||||
{
|
||||
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR("Cannot issue rearm request for %s", -1), Ships[obj_to_rearm->instance].ship_name);
|
||||
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR("Cannot issue rearm request for %s", 1611), Ships[obj_to_rearm->instance].get_display_string());
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1326,7 +1325,7 @@ void ppsk_hotkeys(int k)
|
||||
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "No target to add/remove from set %d.", 26), hotkey_set+1);
|
||||
else {
|
||||
hud_target_hotkey_add_remove( hotkey_set, &Objects[Player_ai->target_objnum], HOTKEY_USER_ADDED);
|
||||
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "%s added to set %d. (F%d)", 27), Ships[Objects[Player_ai->target_objnum].instance].ship_name, hotkey_set, 4+hotkey_set+1);
|
||||
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "%s added to set %d. (F%d)", 27), Ships[Objects[Player_ai->target_objnum].instance].get_display_string(), hotkey_set, 4+hotkey_set+1);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1442,8 +1441,6 @@ void game_do_end_mission_popup()
|
||||
game_stop_looped_sounds();
|
||||
snd_stop_all();
|
||||
|
||||
quit_mission_popup_shown = true;
|
||||
|
||||
pf_flags = PF_BODY_BIG | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON;
|
||||
choice = popup(pf_flags, 3, POPUP_NO, XSTR( "&Yes, Quit", 28), XSTR( "Yes, &Restart", 29), XSTR( "Do you really want to end the mission?", 30));
|
||||
|
||||
@@ -1459,7 +1456,6 @@ void game_do_end_mission_popup()
|
||||
default:
|
||||
break; // do nothing
|
||||
}
|
||||
quit_mission_popup_shown = false;
|
||||
|
||||
game_start_time();
|
||||
game_flush();
|
||||
@@ -1573,6 +1569,7 @@ void game_process_cheats(int k)
|
||||
|
||||
ship *shipp = &Ships[Objects[objnum].instance];
|
||||
shipp->ship_name[0] = '\0';
|
||||
shipp->display_name.clear();
|
||||
shipp->orders_accepted = (1<<NUM_COMM_ORDER_ITEMS)-1;
|
||||
|
||||
// Goober5000 - stolen from support ship creation
|
||||
@@ -2427,10 +2424,10 @@ int button_function(int n)
|
||||
HUD_printf("%s", XSTR("Engine failure. Cannot engage subspace drive.", 40));
|
||||
} else if (!ship_navigation_ok_to_warp(Player_ship)) {
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
HUD_printf("%s", XSTR("Navigation failure. Cannot engage subspace drive.", 1596));
|
||||
HUD_printf("%s", XSTR("Navigation failure. Cannot engage subspace drive.", 1572));
|
||||
} else if ( (Player_obj != NULL) && object_get_gliding(Player_obj)) {
|
||||
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
|
||||
HUD_printf("%s", XSTR("Cannot engage subspace drive while gliding.", 1597));
|
||||
HUD_printf("%s", XSTR("Cannot engage subspace drive while gliding.", 1573));
|
||||
} else {
|
||||
gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_START );
|
||||
}
|
||||
|
||||
@@ -23,8 +23,6 @@ extern bool Perspective_locked;
|
||||
|
||||
extern int Ignored_keys[];
|
||||
|
||||
extern bool quit_mission_popup_shown;
|
||||
|
||||
typedef struct button_info
|
||||
{
|
||||
int status[NUM_BUTTON_FIELDS];
|
||||
|
||||
+30
-11
@@ -920,7 +920,7 @@ void labviewer_update_variables_window()
|
||||
Assert(Lab_selected_index < Num_weapon_types);
|
||||
weapon_info *wip = &Weapon_info[Lab_selected_index];
|
||||
|
||||
VAR_SET_VALUE(wip->name);
|
||||
VAR_SET_VALUE(wip->get_display_string());
|
||||
VAR_SET_VALUE_SAVE(wip->subtype, Num_weapon_subtypes - 1);
|
||||
|
||||
VAR_SET_VALUE_SAVE(wip->mass, 0);
|
||||
@@ -1257,7 +1257,7 @@ void labviewer_update_desc_window()
|
||||
}
|
||||
}
|
||||
else if (Lab_mode == LAB_MODE_WEAPON) {
|
||||
Lab_description_window->SetCaption(Weapon_info[Lab_selected_index].name);
|
||||
Lab_description_window->SetCaption(Weapon_info[Lab_selected_index].get_display_string());
|
||||
|
||||
if (Weapon_info[Lab_selected_index].tech_desc != NULL) {
|
||||
Lab_description_text->SetText(Weapon_info[Lab_selected_index].tech_desc);
|
||||
@@ -1543,7 +1543,7 @@ void labviewer_make_weap_window(Button* /*caller*/)
|
||||
stip = type_nodes[Weapon_info[i].subtype];
|
||||
}
|
||||
|
||||
cmp->AddItem(stip, Weapon_info[i].name, i, false, labviewer_change_weapon);
|
||||
cmp->AddItem(stip, Weapon_info[i].get_display_string(), i, false, labviewer_change_weapon);
|
||||
|
||||
//if (Weapon_info[i].tech_model[0] != '\0') {
|
||||
// cmp->AddItem(cwip, "Tech Model", 0, false, labviewer_show_tech_model);
|
||||
@@ -1599,7 +1599,7 @@ char envmap_name[MAX_FILENAME_LEN];
|
||||
|
||||
const char* mission_ext_list[] = { ".fs2" };
|
||||
|
||||
SCP_string get_directory_or_vp(char* path)
|
||||
SCP_string get_directory_or_vp(const char* path)
|
||||
{
|
||||
SCP_string result(path);
|
||||
|
||||
@@ -1806,6 +1806,7 @@ void labviewer_change_background_actual()
|
||||
else {
|
||||
// (DahBlount) - This spot should be used to disable rendering features that only apply to missions.
|
||||
Motion_debris_override = true;
|
||||
Num_stars = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1832,14 +1833,15 @@ void labviewer_make_background_window(Button* /*caller*/)
|
||||
cf_get_file_list(missions, CF_TYPE_MISSIONS, NOX("*.fs2"));
|
||||
|
||||
SCP_map<SCP_string, SCP_vector<SCP_string>> directories;
|
||||
char fullpath[MAX_PATH_LEN];
|
||||
|
||||
for (const auto& filename : missions)
|
||||
{
|
||||
cf_find_file_location((filename + ".fs2").c_str(), CF_TYPE_MISSIONS, sizeof(fullpath) - 1, fullpath, NULL, NULL);
|
||||
auto location = get_directory_or_vp(fullpath);
|
||||
for (const auto& filename : missions) {
|
||||
auto res = cf_find_file_location((filename + ".fs2").c_str(), CF_TYPE_MISSIONS);
|
||||
|
||||
directories[location].push_back(filename);
|
||||
if (res.found) {
|
||||
auto location = get_directory_or_vp(res.full_name.c_str());
|
||||
|
||||
directories[location].push_back(filename);
|
||||
}
|
||||
}
|
||||
|
||||
Num_mission_directories = directories.size();
|
||||
@@ -1924,6 +1926,10 @@ void lab_init()
|
||||
Lab_viewer_flags |= LAB_FLAG_NO_ROTATION;
|
||||
Lab_viewer_flags |= LAB_FLAG_INITIAL_ROTATION;
|
||||
|
||||
obj_init();
|
||||
|
||||
//Reset the background
|
||||
labviewer_change_background_actual();
|
||||
|
||||
flagset<Object::Object_Flags> obs_flags;
|
||||
auto obj_index = obj_create(OBJ_OBSERVER, -1, 0, &vmd_identity_matrix, &vmd_zero_vector, 0, obs_flags);
|
||||
@@ -1941,6 +1947,19 @@ void lab_init()
|
||||
|
||||
if (The_mission.ai_profile == nullptr)
|
||||
The_mission.ai_profile = &Ai_profiles[Default_ai_profile];
|
||||
|
||||
lab_cam_distance = 100.0f;
|
||||
lab_cam_phi = 1.24f;
|
||||
lab_cam_theta = 2.25f;
|
||||
|
||||
Lab_selected_index = -1;
|
||||
Lab_last_selected_ship = -1;
|
||||
Lab_selected_object = -1;
|
||||
Lab_last_selected_weapon = -1;
|
||||
Lab_model_num = -1;
|
||||
|
||||
Lab_selected_mission = "None";
|
||||
Lab_skybox_orientation = vmd_identity_matrix;
|
||||
}
|
||||
|
||||
#include "controlconfig/controlsconfig.h"
|
||||
@@ -2174,5 +2193,5 @@ void lab_close()
|
||||
|
||||
cam_delete(Lab_cam);
|
||||
|
||||
Missiontime = Lab_Save_Missiontime;
|
||||
obj_init();
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
#include "discord.h"
|
||||
#include "freespace.h"
|
||||
#include "events/events.h"
|
||||
#include "gamesequence/gamesequence.h"
|
||||
#include "io/timer.h"
|
||||
#include "mission/missioncampaign.h"
|
||||
#include "mission/missionparse.h"
|
||||
#include "parse/parselo.h"
|
||||
#include "playerman/player.h"
|
||||
|
||||
#include "discord_rpc.h"
|
||||
|
||||
namespace {
|
||||
struct PresenceInfo {
|
||||
SCP_string state;
|
||||
int64_t timestamp;
|
||||
};
|
||||
|
||||
bool initialized = false;
|
||||
bool discord_ready = false;
|
||||
int next_mission_update = -1;
|
||||
|
||||
bool in_mission = false;
|
||||
|
||||
PresenceInfo current_info;
|
||||
|
||||
const char* APPLICATION_ID = "465270111440470016";
|
||||
|
||||
SCP_unordered_map<SCP_string, SCP_string> campaign_name_cache;
|
||||
|
||||
SCP_string get_campaign_name(const char* filename)
|
||||
{
|
||||
SCP_string name = filename;
|
||||
|
||||
auto iter = campaign_name_cache.find(name);
|
||||
if (iter != campaign_name_cache.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
auto campaign_name = mission_campaign_get_name(filename);
|
||||
campaign_name_cache[name] = campaign_name;
|
||||
|
||||
return campaign_name;
|
||||
}
|
||||
|
||||
SCP_string get_current_campaign_name()
|
||||
{
|
||||
if (Game_mode & GM_CAMPAIGN_MODE) {
|
||||
return Campaign.name;
|
||||
} else if (Player != nullptr) {
|
||||
return get_campaign_name(Player->current_campaign);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
SCP_string get_details()
|
||||
{
|
||||
SCP_string res;
|
||||
|
||||
auto has_campaign = Player != nullptr && strlen(Player->current_campaign) > 0;
|
||||
if (in_mission && !(Game_mode & GM_CAMPAIGN_MODE)) {
|
||||
// This is a standalone mission so we don't actually have a campaign
|
||||
has_campaign = false;
|
||||
}
|
||||
|
||||
if (has_campaign && in_mission) {
|
||||
sprintf(res, "%s: %s", get_current_campaign_name().c_str(), The_mission.name);
|
||||
} else if (has_campaign) {
|
||||
sprintf(res, "Campaign %s", get_current_campaign_name().c_str());
|
||||
} else if (in_mission) {
|
||||
res = The_mission.name;
|
||||
} else {
|
||||
res = "In game";
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void update_presence() {
|
||||
auto details = get_details();
|
||||
|
||||
DiscordRichPresence presence;
|
||||
memset(&presence, 0, sizeof(presence));
|
||||
presence.details = details.c_str();
|
||||
presence.state = current_info.state.c_str();
|
||||
presence.startTimestamp = current_info.timestamp;
|
||||
|
||||
Discord_UpdatePresence(&presence);
|
||||
}
|
||||
|
||||
void set_presence(const SCP_string& state, int64_t timestamp = 0) {
|
||||
if (current_info.state == state && current_info.timestamp == timestamp) {
|
||||
// No changes
|
||||
return;
|
||||
}
|
||||
|
||||
current_info.state = state;
|
||||
current_info.timestamp = timestamp;
|
||||
|
||||
if (discord_ready) {
|
||||
update_presence();
|
||||
}
|
||||
}
|
||||
|
||||
void set_game_play_presence()
|
||||
{
|
||||
SCP_string state;
|
||||
|
||||
sprintf(state, "In mission (%d %s)", Player->stats.m_kill_count_ok,
|
||||
Player->stats.m_kill_count_ok == 1 ? "kill" : "kills");
|
||||
|
||||
set_presence(state, (int64_t)time(nullptr) - f2i(Missiontime));
|
||||
|
||||
// Update this every 20 seconds since Discord already has a 15 second rate-limit
|
||||
// This will update the "elapsed" time even if time compression is active but the clock will jump forward
|
||||
next_mission_update = timestamp(20000);
|
||||
}
|
||||
|
||||
void update_discord()
|
||||
{
|
||||
if (!initialized)
|
||||
return;
|
||||
|
||||
Discord_RunCallbacks();
|
||||
|
||||
if (gameseq_get_state() == GS_STATE_GAME_PLAY && timestamp_elapsed(next_mission_update)) {
|
||||
set_game_play_presence();
|
||||
}
|
||||
}
|
||||
void shutdown_discord()
|
||||
{
|
||||
if (!initialized)
|
||||
return;
|
||||
|
||||
Discord_Shutdown();
|
||||
initialized = false;
|
||||
discord_ready = false;
|
||||
}
|
||||
|
||||
void handleEnterState(int old_state, int new_state)
|
||||
{
|
||||
if (old_state == new_state) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (new_state == GS_STATE_GAME_PLAY) {
|
||||
// Update immediately if we enter the game play state again
|
||||
set_game_play_presence();
|
||||
return;
|
||||
}
|
||||
|
||||
if (gameseq_get_state_idx(GS_STATE_GAME_PLAY) >= 0) {
|
||||
// Special case for when we come out of game play
|
||||
switch (new_state) {
|
||||
case GS_STATE_OPTIONS_MENU:
|
||||
case GS_STATE_HOTKEY_SCREEN:
|
||||
case GS_STATE_GAMEPLAY_HELP:
|
||||
case GS_STATE_MISSION_LOG_SCROLLBACK:
|
||||
set_presence("In game menu");
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (new_state) {
|
||||
case GS_STATE_MAIN_MENU:
|
||||
set_presence("In Mainhall");
|
||||
break;
|
||||
case GS_STATE_BRIEFING:
|
||||
set_presence("In mission briefing");
|
||||
break;
|
||||
case GS_STATE_CMD_BRIEF:
|
||||
set_presence("In command briefing");
|
||||
break;
|
||||
case GS_EVENT_DEBRIEF:
|
||||
set_presence("In debriefing");
|
||||
break;
|
||||
case GS_STATE_GAME_PAUSED:
|
||||
set_presence("Paused");
|
||||
break;
|
||||
case GS_STATE_RED_ALERT:
|
||||
set_presence("Red alert briefing");
|
||||
break;
|
||||
case GS_STATE_INITIAL_PLAYER_SELECT:
|
||||
set_presence("Selecting player");
|
||||
break;
|
||||
case GS_STATE_FICTION_VIEWER:
|
||||
set_presence("In fiction viewer");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void handleLeaveState(int old_state, int /*new_state*/)
|
||||
{
|
||||
if (old_state == GS_STATE_GAME_PAUSED) {
|
||||
// Reset the game play state immediately
|
||||
set_game_play_presence();
|
||||
}
|
||||
|
||||
if (old_state == GS_STATE_GAME_PLAY) {
|
||||
in_mission = false;
|
||||
next_mission_update = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void handleMissionLoad(const char* /*filename*/)
|
||||
{
|
||||
set_presence("Loading mission");
|
||||
in_mission = true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace libs {
|
||||
namespace discord {
|
||||
|
||||
void init()
|
||||
{
|
||||
Assertion(!initialized, "Discord integration can only be initialized once!");
|
||||
|
||||
DiscordEventHandlers handlers;
|
||||
memset(&handlers, 0, sizeof(handlers));
|
||||
handlers.ready = [](const DiscordUser* connectedUser) {
|
||||
mprintf(("Discord: connected to user %s#%s - %s\n", connectedUser->username, connectedUser->discriminator,
|
||||
connectedUser->userId));
|
||||
discord_ready = true;
|
||||
update_presence();
|
||||
};
|
||||
handlers.errored = [](int errcode, const char* message) {
|
||||
mprintf(("Discord: error (%d: %s)\n", errcode, message));
|
||||
discord_ready = false;
|
||||
};
|
||||
handlers.disconnected = [](int errcode, const char* message) {
|
||||
mprintf(("Discord: disconnected (%d: %s)\n", errcode, message));
|
||||
discord_ready = false;
|
||||
};
|
||||
|
||||
Discord_Initialize(APPLICATION_ID, &handlers, 0, nullptr);
|
||||
|
||||
events::EngineUpdate.add(update_discord);
|
||||
events::EngineShutdown.add(shutdown_discord);
|
||||
events::GameEnterState.add(handleEnterState);
|
||||
events::GameLeaveState.add(handleLeaveState);
|
||||
events::GameMissionLoad.add(handleMissionLoad);
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
} // namespace discord
|
||||
} // namespace libs
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
namespace libs {
|
||||
namespace discord {
|
||||
|
||||
void init();
|
||||
}
|
||||
} // namespace libs
|
||||
@@ -55,7 +55,10 @@ void initialize() {
|
||||
return;
|
||||
}
|
||||
|
||||
// This is deprecated since 58.9.100 and not needed anymore
|
||||
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100)
|
||||
av_register_all();
|
||||
#endif
|
||||
|
||||
check_version("libavcodec", avcodec_version(), LIBAVCODEC_VERSION_INT);
|
||||
check_version("libavformat", avformat_version(), LIBAVFORMAT_VERSION_INT);
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
|
||||
#include "renderdoc.h"
|
||||
#include "renderdoc_app.h"
|
||||
|
||||
#include "globalincs/pstypes.h"
|
||||
|
||||
#ifdef SCP_UNIX
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
bool api_loaded = false;
|
||||
RENDERDOC_API_1_1_1* api = nullptr;
|
||||
|
||||
pRENDERDOC_GetAPI load_getAPI() {
|
||||
#ifdef SCP_UNIX
|
||||
auto handle = dlopen("librenderdoc.so", RTLD_NOLOAD);
|
||||
auto symbol = dlsym(handle, "RENDERDOC_GetAPI");
|
||||
|
||||
if (handle != nullptr) {
|
||||
dlclose(handle);
|
||||
}
|
||||
|
||||
return (pRENDERDOC_GetAPI)symbol;
|
||||
#else
|
||||
// Renderdoc API loading is not implemented for this platform yet!
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace renderdoc {
|
||||
|
||||
bool loadApi() {
|
||||
if (api_loaded) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto getAPI = load_getAPI();
|
||||
|
||||
if (getAPI == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto res = getAPI(eRENDERDOC_API_Version_1_1_1, reinterpret_cast<void**>(&api));
|
||||
|
||||
if (res != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
api_loaded = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void triggerCapture() {
|
||||
if (!api_loaded) {
|
||||
// Do nothing if API is not available
|
||||
return;
|
||||
}
|
||||
|
||||
api->TriggerCapture();
|
||||
}
|
||||
void startCapture() {
|
||||
if (api_loaded) {
|
||||
api->StartFrameCapture(nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
bool isCapturing() {
|
||||
if (api_loaded) {
|
||||
return api->IsFrameCapturing() == 1;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
void endCapture() {
|
||||
if (api_loaded) {
|
||||
api->EndFrameCapture(nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
namespace renderdoc {
|
||||
|
||||
bool loadApi();
|
||||
|
||||
void triggerCapture();
|
||||
|
||||
void startCapture();
|
||||
|
||||
bool isCapturing();
|
||||
|
||||
void endCapture();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,617 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015-2017 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Documentation for the API is available at https://renderdoc.org/docs/in_application_api.html
|
||||
//
|
||||
|
||||
#if !defined(RENDERDOC_NO_STDINT)
|
||||
#include <cstdint>
|
||||
#endif
|
||||
|
||||
#if defined(WIN32)
|
||||
#define RENDERDOC_CC __cdecl
|
||||
#elif defined(__linux__)
|
||||
#define RENDERDOC_CC
|
||||
#elif defined(__APPLE__)
|
||||
#define RENDERDOC_CC
|
||||
#else
|
||||
#error "Unknown platform"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constants not used directly in below API
|
||||
|
||||
// This is a GUID/magic value used for when applications pass a path where shader debug
|
||||
// information can be found to match up with a stripped shader.
|
||||
// the define can be used like so: const GUID RENDERDOC_ShaderDebugMagicValue =
|
||||
// RENDERDOC_ShaderDebugMagicValue_value
|
||||
#define RENDERDOC_ShaderDebugMagicValue_struct \
|
||||
{ \
|
||||
0xeab25520, 0x6670, 0x4865, 0x84, 0x29, 0x6c, 0x8, 0x51, 0x54, 0x00, 0xff \
|
||||
}
|
||||
|
||||
// as an alternative when you want a byte array (assuming x86 endianness):
|
||||
#define RENDERDOC_ShaderDebugMagicValue_bytearray \
|
||||
{ \
|
||||
0x20, 0x55, 0xb2, 0xea, 0x70, 0x66, 0x65, 0x48, 0x84, 0x29, 0x6c, 0x8, 0x51, 0x54, 0x00, 0xff \
|
||||
}
|
||||
|
||||
// truncated version when only a uint64_t is available (e.g. Vulkan tags):
|
||||
#define RENDERDOC_ShaderDebugMagicValue_truncated 0x48656670eab25520ULL
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RenderDoc capture options
|
||||
//
|
||||
|
||||
typedef enum {
|
||||
// Allow the application to enable vsync
|
||||
//
|
||||
// Default - enabled
|
||||
//
|
||||
// 1 - The application can enable or disable vsync at will
|
||||
// 0 - vsync is force disabled
|
||||
eRENDERDOC_Option_AllowVSync = 0,
|
||||
|
||||
// Allow the application to enable fullscreen
|
||||
//
|
||||
// Default - enabled
|
||||
//
|
||||
// 1 - The application can enable or disable fullscreen at will
|
||||
// 0 - fullscreen is force disabled
|
||||
eRENDERDOC_Option_AllowFullscreen = 1,
|
||||
|
||||
// Record API debugging events and messages
|
||||
//
|
||||
// Default - disabled
|
||||
//
|
||||
// 1 - Enable built-in API debugging features and records the results into
|
||||
// the capture logfile, which is matched up with events on replay
|
||||
// 0 - no API debugging is forcibly enabled
|
||||
eRENDERDOC_Option_APIValidation = 2,
|
||||
eRENDERDOC_Option_DebugDeviceMode = 2, // deprecated name of this enum
|
||||
|
||||
// Capture CPU callstacks for API events
|
||||
//
|
||||
// Default - disabled
|
||||
//
|
||||
// 1 - Enables capturing of callstacks
|
||||
// 0 - no callstacks are captured
|
||||
eRENDERDOC_Option_CaptureCallstacks = 3,
|
||||
|
||||
// When capturing CPU callstacks, only capture them from drawcalls.
|
||||
// This option does nothing without the above option being enabled
|
||||
//
|
||||
// Default - disabled
|
||||
//
|
||||
// 1 - Only captures callstacks for drawcall type API events.
|
||||
// Ignored if CaptureCallstacks is disabled
|
||||
// 0 - Callstacks, if enabled, are captured for every event.
|
||||
eRENDERDOC_Option_CaptureCallstacksOnlyDraws = 4,
|
||||
|
||||
// Specify a delay in seconds to wait for a debugger to attach, after
|
||||
// creating or injecting into a process, before continuing to allow it to run.
|
||||
//
|
||||
// 0 indicates no delay, and the process will run immediately after injection
|
||||
//
|
||||
// Default - 0 seconds
|
||||
//
|
||||
eRENDERDOC_Option_DelayForDebugger = 5,
|
||||
|
||||
// Verify any writes to mapped buffers, by checking the memory after the
|
||||
// bounds of the returned pointer to detect any modification.
|
||||
//
|
||||
// Default - disabled
|
||||
//
|
||||
// 1 - Verify any writes to mapped buffers
|
||||
// 0 - No verification is performed, and overwriting bounds may cause
|
||||
// crashes or corruption in RenderDoc
|
||||
eRENDERDOC_Option_VerifyMapWrites = 6,
|
||||
|
||||
// Hooks any system API calls that create child processes, and injects
|
||||
// RenderDoc into them recursively with the same options.
|
||||
//
|
||||
// Default - disabled
|
||||
//
|
||||
// 1 - Hooks into spawned child processes
|
||||
// 0 - Child processes are not hooked by RenderDoc
|
||||
eRENDERDOC_Option_HookIntoChildren = 7,
|
||||
|
||||
// By default RenderDoc only includes resources in the final logfile necessary
|
||||
// for that frame, this allows you to override that behaviour.
|
||||
//
|
||||
// Default - disabled
|
||||
//
|
||||
// 1 - all live resources at the time of capture are included in the log
|
||||
// and available for inspection
|
||||
// 0 - only the resources referenced by the captured frame are included
|
||||
eRENDERDOC_Option_RefAllResources = 8,
|
||||
|
||||
// By default RenderDoc skips saving initial states for resources where the
|
||||
// previous contents don't appear to be used, assuming that writes before
|
||||
// reads indicate previous contents aren't used.
|
||||
//
|
||||
// Default - disabled
|
||||
//
|
||||
// 1 - initial contents at the start of each captured frame are saved, even if
|
||||
// they are later overwritten or cleared before being used.
|
||||
// 0 - unless a read is detected, initial contents will not be saved and will
|
||||
// appear as black or empty data.
|
||||
eRENDERDOC_Option_SaveAllInitials = 9,
|
||||
|
||||
// In APIs that allow for the recording of command lists to be replayed later,
|
||||
// RenderDoc may choose to not capture command lists before a frame capture is
|
||||
// triggered, to reduce overheads. This means any command lists recorded once
|
||||
// and replayed many times will not be available and may cause a failure to
|
||||
// capture.
|
||||
//
|
||||
// Note this is only true for APIs where multithreading is difficult or
|
||||
// discouraged. Newer APIs like Vulkan and D3D12 will ignore this option
|
||||
// and always capture all command lists since the API is heavily oriented
|
||||
// around it and the overheads have been reduced by API design.
|
||||
//
|
||||
// 1 - All command lists are captured from the start of the application
|
||||
// 0 - Command lists are only captured if their recording begins during
|
||||
// the period when a frame capture is in progress.
|
||||
eRENDERDOC_Option_CaptureAllCmdLists = 10,
|
||||
|
||||
// Mute API debugging output when the API validation mode option is enabled
|
||||
//
|
||||
// Default - enabled
|
||||
//
|
||||
// 1 - Mute any API debug messages from being displayed or passed through
|
||||
// 0 - API debugging is displayed as normal
|
||||
eRENDERDOC_Option_DebugOutputMute = 11,
|
||||
|
||||
} RENDERDOC_CaptureOption;
|
||||
|
||||
// Sets an option that controls how RenderDoc behaves on capture.
|
||||
//
|
||||
// Returns 1 if the option and value are valid
|
||||
// Returns 0 if either is invalid and the option is unchanged
|
||||
typedef int(RENDERDOC_CC *pRENDERDOC_SetCaptureOptionU32)(RENDERDOC_CaptureOption opt, uint32_t val);
|
||||
typedef int(RENDERDOC_CC *pRENDERDOC_SetCaptureOptionF32)(RENDERDOC_CaptureOption opt, float val);
|
||||
|
||||
// Gets the current value of an option as a uint32_t
|
||||
//
|
||||
// If the option is invalid, 0xffffffff is returned
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_GetCaptureOptionU32)(RENDERDOC_CaptureOption opt);
|
||||
|
||||
// Gets the current value of an option as a float
|
||||
//
|
||||
// If the option is invalid, -FLT_MAX is returned
|
||||
typedef float(RENDERDOC_CC *pRENDERDOC_GetCaptureOptionF32)(RENDERDOC_CaptureOption opt);
|
||||
|
||||
typedef enum {
|
||||
// '0' - '9' matches ASCII values
|
||||
eRENDERDOC_Key_0 = 0x30,
|
||||
eRENDERDOC_Key_1 = 0x31,
|
||||
eRENDERDOC_Key_2 = 0x32,
|
||||
eRENDERDOC_Key_3 = 0x33,
|
||||
eRENDERDOC_Key_4 = 0x34,
|
||||
eRENDERDOC_Key_5 = 0x35,
|
||||
eRENDERDOC_Key_6 = 0x36,
|
||||
eRENDERDOC_Key_7 = 0x37,
|
||||
eRENDERDOC_Key_8 = 0x38,
|
||||
eRENDERDOC_Key_9 = 0x39,
|
||||
|
||||
// 'A' - 'Z' matches ASCII values
|
||||
eRENDERDOC_Key_A = 0x41,
|
||||
eRENDERDOC_Key_B = 0x42,
|
||||
eRENDERDOC_Key_C = 0x43,
|
||||
eRENDERDOC_Key_D = 0x44,
|
||||
eRENDERDOC_Key_E = 0x45,
|
||||
eRENDERDOC_Key_F = 0x46,
|
||||
eRENDERDOC_Key_G = 0x47,
|
||||
eRENDERDOC_Key_H = 0x48,
|
||||
eRENDERDOC_Key_I = 0x49,
|
||||
eRENDERDOC_Key_J = 0x4A,
|
||||
eRENDERDOC_Key_K = 0x4B,
|
||||
eRENDERDOC_Key_L = 0x4C,
|
||||
eRENDERDOC_Key_M = 0x4D,
|
||||
eRENDERDOC_Key_N = 0x4E,
|
||||
eRENDERDOC_Key_O = 0x4F,
|
||||
eRENDERDOC_Key_P = 0x50,
|
||||
eRENDERDOC_Key_Q = 0x51,
|
||||
eRENDERDOC_Key_R = 0x52,
|
||||
eRENDERDOC_Key_S = 0x53,
|
||||
eRENDERDOC_Key_T = 0x54,
|
||||
eRENDERDOC_Key_U = 0x55,
|
||||
eRENDERDOC_Key_V = 0x56,
|
||||
eRENDERDOC_Key_W = 0x57,
|
||||
eRENDERDOC_Key_X = 0x58,
|
||||
eRENDERDOC_Key_Y = 0x59,
|
||||
eRENDERDOC_Key_Z = 0x5A,
|
||||
|
||||
// leave the rest of the ASCII range free
|
||||
// in case we want to use it later
|
||||
eRENDERDOC_Key_NonPrintable = 0x100,
|
||||
|
||||
eRENDERDOC_Key_Divide,
|
||||
eRENDERDOC_Key_Multiply,
|
||||
eRENDERDOC_Key_Subtract,
|
||||
eRENDERDOC_Key_Plus,
|
||||
|
||||
eRENDERDOC_Key_F1,
|
||||
eRENDERDOC_Key_F2,
|
||||
eRENDERDOC_Key_F3,
|
||||
eRENDERDOC_Key_F4,
|
||||
eRENDERDOC_Key_F5,
|
||||
eRENDERDOC_Key_F6,
|
||||
eRENDERDOC_Key_F7,
|
||||
eRENDERDOC_Key_F8,
|
||||
eRENDERDOC_Key_F9,
|
||||
eRENDERDOC_Key_F10,
|
||||
eRENDERDOC_Key_F11,
|
||||
eRENDERDOC_Key_F12,
|
||||
|
||||
eRENDERDOC_Key_Home,
|
||||
eRENDERDOC_Key_End,
|
||||
eRENDERDOC_Key_Insert,
|
||||
eRENDERDOC_Key_Delete,
|
||||
eRENDERDOC_Key_PageUp,
|
||||
eRENDERDOC_Key_PageDn,
|
||||
|
||||
eRENDERDOC_Key_Backspace,
|
||||
eRENDERDOC_Key_Tab,
|
||||
eRENDERDOC_Key_PrtScrn,
|
||||
eRENDERDOC_Key_Pause,
|
||||
|
||||
eRENDERDOC_Key_Max,
|
||||
} RENDERDOC_InputButton;
|
||||
|
||||
// Sets which key or keys can be used to toggle focus between multiple windows
|
||||
//
|
||||
// If keys is NULL or num is 0, toggle keys will be disabled
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_SetFocusToggleKeys)(RENDERDOC_InputButton *keys, int num);
|
||||
|
||||
// Sets which key or keys can be used to capture the next frame
|
||||
//
|
||||
// If keys is NULL or num is 0, captures keys will be disabled
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_SetCaptureKeys)(RENDERDOC_InputButton *keys, int num);
|
||||
|
||||
typedef enum {
|
||||
// This single bit controls whether the overlay is enabled or disabled globally
|
||||
eRENDERDOC_Overlay_Enabled = 0x1,
|
||||
|
||||
// Show the average framerate over several seconds as well as min/max
|
||||
eRENDERDOC_Overlay_FrameRate = 0x2,
|
||||
|
||||
// Show the current frame number
|
||||
eRENDERDOC_Overlay_FrameNumber = 0x4,
|
||||
|
||||
// Show a list of recent captures, and how many captures have been made
|
||||
eRENDERDOC_Overlay_CaptureList = 0x8,
|
||||
|
||||
// Default values for the overlay mask
|
||||
eRENDERDOC_Overlay_Default = (eRENDERDOC_Overlay_Enabled | eRENDERDOC_Overlay_FrameRate |
|
||||
eRENDERDOC_Overlay_FrameNumber | eRENDERDOC_Overlay_CaptureList),
|
||||
|
||||
// Enable all bits
|
||||
eRENDERDOC_Overlay_All = ~0U,
|
||||
|
||||
// Disable all bits
|
||||
eRENDERDOC_Overlay_None = 0,
|
||||
} RENDERDOC_OverlayBits;
|
||||
|
||||
// returns the overlay bits that have been set
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_GetOverlayBits)();
|
||||
// sets the overlay bits with an and & or mask
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_MaskOverlayBits)(uint32_t And, uint32_t Or);
|
||||
|
||||
// this function will attempt to shut down RenderDoc.
|
||||
//
|
||||
// Note: that this will only work correctly if done immediately after
|
||||
// the dll is loaded, before any API work happens. RenderDoc will remove its
|
||||
// injected hooks and shut down. Behaviour is undefined if this is called
|
||||
// after any API functions have been called.
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_Shutdown)();
|
||||
|
||||
// This function will unload RenderDoc's crash handler.
|
||||
//
|
||||
// If you use your own crash handler and don't want RenderDoc's handler to
|
||||
// intercede, you can call this function to unload it and any unhandled
|
||||
// exceptions will pass to the next handler.
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_UnloadCrashHandler)();
|
||||
|
||||
// Sets the logfile path template
|
||||
//
|
||||
// logfile is a UTF-8 string that gives a template for how captures will be named
|
||||
// and where they will be saved.
|
||||
//
|
||||
// Any extension is stripped off the path, and captures are saved in the directory
|
||||
// specified, and named with the filename and the frame number appended. If the
|
||||
// directory does not exist it will be created, including any parent directories.
|
||||
//
|
||||
// If pathtemplate is NULL, the template will remain unchanged
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// SetLogFilePathTemplate("my_captures/example");
|
||||
//
|
||||
// Capture #1 -> my_captures/example_frame123.rdc
|
||||
// Capture #2 -> my_captures/example_frame456.rdc
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_SetLogFilePathTemplate)(const char *pathtemplate);
|
||||
|
||||
// returns the current logfile template, see SetLogFileTemplate above, as a UTF-8 string
|
||||
typedef const char *(RENDERDOC_CC *pRENDERDOC_GetLogFilePathTemplate)();
|
||||
|
||||
// returns the number of captures that have been made
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_GetNumCaptures)();
|
||||
|
||||
// This function returns the details of a capture, by index. New captures are added
|
||||
// to the end of the list.
|
||||
//
|
||||
// logfile will be filled with the absolute path to the capture file, as a UTF-8 string
|
||||
// pathlength will be written with the length in bytes of the logfile string
|
||||
// timestamp will be written with the time of the capture, in seconds since the Unix epoch
|
||||
//
|
||||
// Any of the parameters can be NULL and they'll be skipped.
|
||||
//
|
||||
// The function will return 1 if the capture index is valid, or 0 if the index is invalid
|
||||
// If the index is invalid, the values will be unchanged
|
||||
//
|
||||
// Note: when captures are deleted in the UI they will remain in this list, so the
|
||||
// logfile path may not exist anymore.
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_GetCapture)(uint32_t idx, char *logfile,
|
||||
uint32_t *pathlength, uint64_t *timestamp);
|
||||
|
||||
// returns 1 if the RenderDoc UI is connected to this application, 0 otherwise
|
||||
// This was renamed to IsTargetControlConnected in API 1.1.1, the old typedef is kept here for
|
||||
// backwards compatibility with old code, it is castable either way since it's ABI compatible
|
||||
// as the same function pointer type.
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_IsRemoteAccessConnected)();
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_IsTargetControlConnected)();
|
||||
|
||||
// This function will launch the Replay UI associated with the RenderDoc library injected
|
||||
// into the running application.
|
||||
//
|
||||
// if connectTargetControl is 1, the Replay UI will be launched with a command line parameter
|
||||
// to connect to this application
|
||||
// cmdline is the rest of the command line, as a UTF-8 string. E.g. a captures to open
|
||||
// if cmdline is NULL, the command line will be empty.
|
||||
//
|
||||
// returns the PID of the replay UI if successful, 0 if not successful.
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_LaunchReplayUI)(uint32_t connectTargetControl,
|
||||
const char *cmdline);
|
||||
|
||||
// RenderDoc can return a higher version than requested if it's backwards compatible,
|
||||
// this function returns the actual version returned. If a parameter is NULL, it will be
|
||||
// ignored and the others will be filled out.
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_GetAPIVersion)(int *major, int *minor, int *patch);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Capturing functions
|
||||
//
|
||||
|
||||
// A device pointer is a pointer to the API's root handle.
|
||||
//
|
||||
// This would be an ID3D11Device, HGLRC/GLXContext, ID3D12Device, etc
|
||||
typedef void *RENDERDOC_DevicePointer;
|
||||
|
||||
// A window handle is the OS's native window handle
|
||||
//
|
||||
// This would be an HWND, GLXDrawable, etc
|
||||
typedef void *RENDERDOC_WindowHandle;
|
||||
|
||||
// This sets the RenderDoc in-app overlay in the API/window pair as 'active' and it will
|
||||
// respond to keypresses. Neither parameter can be NULL
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_SetActiveWindow)(RENDERDOC_DevicePointer device,
|
||||
RENDERDOC_WindowHandle wndHandle);
|
||||
|
||||
// capture the next frame on whichever window and API is currently considered active
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_TriggerCapture)();
|
||||
|
||||
// capture the next N frames on whichever window and API is currently considered active
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_TriggerMultiFrameCapture)(uint32_t numFrames);
|
||||
|
||||
// When choosing either a device pointer or a window handle to capture, you can pass NULL.
|
||||
// Passing NULL specifies a 'wildcard' match against anything. This allows you to specify
|
||||
// any API rendering to a specific window, or a specific API instance rendering to any window,
|
||||
// or in the simplest case of one window and one API, you can just pass NULL for both.
|
||||
//
|
||||
// In either case, if there are two or more possible matching (device,window) pairs it
|
||||
// is undefined which one will be captured.
|
||||
//
|
||||
// Note: for headless rendering you can pass NULL for the window handle and either specify
|
||||
// a device pointer or leave it NULL as above.
|
||||
|
||||
// Immediately starts capturing API calls on the specified device pointer and window handle.
|
||||
//
|
||||
// If there is no matching thing to capture (e.g. no supported API has been initialised),
|
||||
// this will do nothing.
|
||||
//
|
||||
// The results are undefined (including crashes) if two captures are started overlapping,
|
||||
// even on separate devices and/oror windows.
|
||||
typedef void(RENDERDOC_CC *pRENDERDOC_StartFrameCapture)(RENDERDOC_DevicePointer device,
|
||||
RENDERDOC_WindowHandle wndHandle);
|
||||
|
||||
// Returns whether or not a frame capture is currently ongoing anywhere.
|
||||
//
|
||||
// This will return 1 if a capture is ongoing, and 0 if there is no capture running
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_IsFrameCapturing)();
|
||||
|
||||
// Ends capturing immediately.
|
||||
//
|
||||
// This will return 1 if the capture succeeded, and 0 if there was an error capturing.
|
||||
typedef uint32_t(RENDERDOC_CC *pRENDERDOC_EndFrameCapture)(RENDERDOC_DevicePointer device,
|
||||
RENDERDOC_WindowHandle wndHandle);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RenderDoc API versions
|
||||
//
|
||||
|
||||
// RenderDoc uses semantic versioning (http://semver.org/).
|
||||
//
|
||||
// MAJOR version is incremented when incompatible API changes happen.
|
||||
// MINOR version is incremented when functionality is added in a backwards-compatible manner.
|
||||
// PATCH version is incremented when backwards-compatible bug fixes happen.
|
||||
//
|
||||
// Note that this means the API returned can be higher than the one you might have requested.
|
||||
// e.g. if you are running against a newer RenderDoc that supports 1.0.1, it will be returned
|
||||
// instead of 1.0.0. You can check this with the GetAPIVersion entry point
|
||||
typedef enum {
|
||||
eRENDERDOC_API_Version_1_0_0 = 10000, // RENDERDOC_API_1_0_0 = 1 00 00
|
||||
eRENDERDOC_API_Version_1_0_1 = 10001, // RENDERDOC_API_1_0_1 = 1 00 01
|
||||
eRENDERDOC_API_Version_1_0_2 = 10002, // RENDERDOC_API_1_0_2 = 1 00 02
|
||||
eRENDERDOC_API_Version_1_1_0 = 10100, // RENDERDOC_API_1_1_0 = 1 01 00
|
||||
eRENDERDOC_API_Version_1_1_1 = 10101, // RENDERDOC_API_1_1_1 = 1 01 01
|
||||
} RENDERDOC_Version;
|
||||
|
||||
// API version changelog:
|
||||
//
|
||||
// 1.0.0 - initial release
|
||||
// 1.0.1 - Bugfix: IsFrameCapturing() was returning false for captures that were triggered
|
||||
// by keypress or TriggerCapture, instead of Start/EndFrameCapture.
|
||||
// 1.0.2 - Refactor: Renamed eRENDERDOC_Option_DebugDeviceMode to eRENDERDOC_Option_APIValidation
|
||||
// 1.1.0 - Add feature: TriggerMultiFrameCapture(). Backwards compatible with 1.0.x since the new
|
||||
// function pointer is added to the end of the struct, the original layout is identical
|
||||
// 1.1.1 - Refactor: Renamed remote access to target control (to better disambiguate from remote
|
||||
// replay/remote server concept in replay UI)
|
||||
|
||||
// eRENDERDOC_API_Version_1_1_0
|
||||
typedef struct
|
||||
{
|
||||
pRENDERDOC_GetAPIVersion GetAPIVersion;
|
||||
|
||||
pRENDERDOC_SetCaptureOptionU32 SetCaptureOptionU32;
|
||||
pRENDERDOC_SetCaptureOptionF32 SetCaptureOptionF32;
|
||||
|
||||
pRENDERDOC_GetCaptureOptionU32 GetCaptureOptionU32;
|
||||
pRENDERDOC_GetCaptureOptionF32 GetCaptureOptionF32;
|
||||
|
||||
pRENDERDOC_SetFocusToggleKeys SetFocusToggleKeys;
|
||||
pRENDERDOC_SetCaptureKeys SetCaptureKeys;
|
||||
|
||||
pRENDERDOC_GetOverlayBits GetOverlayBits;
|
||||
pRENDERDOC_MaskOverlayBits MaskOverlayBits;
|
||||
|
||||
pRENDERDOC_Shutdown Shutdown;
|
||||
pRENDERDOC_UnloadCrashHandler UnloadCrashHandler;
|
||||
|
||||
pRENDERDOC_SetLogFilePathTemplate SetLogFilePathTemplate;
|
||||
pRENDERDOC_GetLogFilePathTemplate GetLogFilePathTemplate;
|
||||
|
||||
pRENDERDOC_GetNumCaptures GetNumCaptures;
|
||||
pRENDERDOC_GetCapture GetCapture;
|
||||
|
||||
pRENDERDOC_TriggerCapture TriggerCapture;
|
||||
|
||||
pRENDERDOC_IsRemoteAccessConnected IsRemoteAccessConnected;
|
||||
pRENDERDOC_LaunchReplayUI LaunchReplayUI;
|
||||
|
||||
pRENDERDOC_SetActiveWindow SetActiveWindow;
|
||||
|
||||
pRENDERDOC_StartFrameCapture StartFrameCapture;
|
||||
pRENDERDOC_IsFrameCapturing IsFrameCapturing;
|
||||
pRENDERDOC_EndFrameCapture EndFrameCapture;
|
||||
|
||||
pRENDERDOC_TriggerMultiFrameCapture TriggerMultiFrameCapture;
|
||||
} RENDERDOC_API_1_1_0;
|
||||
|
||||
typedef RENDERDOC_API_1_1_0 RENDERDOC_API_1_0_0;
|
||||
typedef RENDERDOC_API_1_1_0 RENDERDOC_API_1_0_1;
|
||||
typedef RENDERDOC_API_1_1_0 RENDERDOC_API_1_0_2;
|
||||
|
||||
// although this structure is identical to RENDERDOC_API_1_1_0, the member
|
||||
// IsRemoteAccessConnected was renamed to IsTargetControlConnected. So that
|
||||
// old code can still compile with a new header, we must declare a new struct
|
||||
// type. It can be casted back and forth though, so we will still return a
|
||||
// pointer to this type for all previous API versions - the above struct is
|
||||
// purely legacy for compilation compatibility
|
||||
|
||||
// eRENDERDOC_API_Version_1_1_1
|
||||
typedef struct
|
||||
{
|
||||
pRENDERDOC_GetAPIVersion GetAPIVersion;
|
||||
|
||||
pRENDERDOC_SetCaptureOptionU32 SetCaptureOptionU32;
|
||||
pRENDERDOC_SetCaptureOptionF32 SetCaptureOptionF32;
|
||||
|
||||
pRENDERDOC_GetCaptureOptionU32 GetCaptureOptionU32;
|
||||
pRENDERDOC_GetCaptureOptionF32 GetCaptureOptionF32;
|
||||
|
||||
pRENDERDOC_SetFocusToggleKeys SetFocusToggleKeys;
|
||||
pRENDERDOC_SetCaptureKeys SetCaptureKeys;
|
||||
|
||||
pRENDERDOC_GetOverlayBits GetOverlayBits;
|
||||
pRENDERDOC_MaskOverlayBits MaskOverlayBits;
|
||||
|
||||
pRENDERDOC_Shutdown Shutdown;
|
||||
pRENDERDOC_UnloadCrashHandler UnloadCrashHandler;
|
||||
|
||||
pRENDERDOC_SetLogFilePathTemplate SetLogFilePathTemplate;
|
||||
pRENDERDOC_GetLogFilePathTemplate GetLogFilePathTemplate;
|
||||
|
||||
pRENDERDOC_GetNumCaptures GetNumCaptures;
|
||||
pRENDERDOC_GetCapture GetCapture;
|
||||
|
||||
pRENDERDOC_TriggerCapture TriggerCapture;
|
||||
|
||||
pRENDERDOC_IsTargetControlConnected IsTargetControlConnected;
|
||||
pRENDERDOC_LaunchReplayUI LaunchReplayUI;
|
||||
|
||||
pRENDERDOC_SetActiveWindow SetActiveWindow;
|
||||
|
||||
pRENDERDOC_StartFrameCapture StartFrameCapture;
|
||||
pRENDERDOC_IsFrameCapturing IsFrameCapturing;
|
||||
pRENDERDOC_EndFrameCapture EndFrameCapture;
|
||||
|
||||
pRENDERDOC_TriggerMultiFrameCapture TriggerMultiFrameCapture;
|
||||
} RENDERDOC_API_1_1_1;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RenderDoc API entry point
|
||||
//
|
||||
// This entry point can be obtained via GetProcAddress/dlsym if RenderDoc is available.
|
||||
//
|
||||
// The name is the same as the typedef - "RENDERDOC_GetAPI"
|
||||
//
|
||||
// This function is not thread safe, and should not be called on multiple threads at once.
|
||||
// Ideally, call this once as early as possible in your application's startup, before doing
|
||||
// any API work, since some configuration functionality etc has to be done also before
|
||||
// initialising any APIs.
|
||||
//
|
||||
// Parameters:
|
||||
// version is a single value from the RENDERDOC_Version above.
|
||||
//
|
||||
// outAPIPointers will be filled out with a pointer to the corresponding struct of function
|
||||
// pointers.
|
||||
//
|
||||
// Returns:
|
||||
// 1 - if the outAPIPointers has been filled with a pointer to the API struct requested
|
||||
// 0 - if the requested version is not supported or the arguments are invalid.
|
||||
//
|
||||
typedef int(RENDERDOC_CC *pRENDERDOC_GetAPI)(RENDERDOC_Version version, void **outAPIPointers);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
@@ -278,7 +278,6 @@ void parse_stringstbl_common(const char *filename, const bool external)
|
||||
if (external) {
|
||||
ignore_white_space();
|
||||
get_string(buf, sizeof(buf));
|
||||
drop_trailing_white_space(buf);
|
||||
} else {
|
||||
stuff_string(buf, F_RAW, sizeof(buf));
|
||||
}
|
||||
|
||||
+972
-953
File diff suppressed because it is too large.
Load diff
+1
-1
@@ -445,7 +445,7 @@ void vm_vec_random_in_circle(vec3d *out, const vec3d *in, const matrix *orient,
|
||||
|
||||
// given a start vector, an orientation, and a radius, give a point in a spherical volume
|
||||
// if on_edge is 1, the point is on the very edge of the sphere
|
||||
void vm_vec_random_in_sphere(vec3d *out, const vec3d *in, const matrix *orient, float radius, int on_edge);
|
||||
void vm_vec_random_in_sphere(vec3d *out, const vec3d *in, float radius, int on_edge);
|
||||
|
||||
// find the nearest point on the line to p. if dist is non-NULL, it is filled in
|
||||
// returns 0 if the point is inside the line segment, -1 if "before" the line segment and 1 ir "after" the line segment
|
||||
|
||||
@@ -433,7 +433,7 @@ void barracks_init_stats(scoring_struct *stats)
|
||||
Num_stat_lines++;
|
||||
|
||||
Assert(Num_stat_lines < Max_stat_lines);
|
||||
STRCPY1(Stat_labels[Num_stat_lines], "Current Score:");
|
||||
strcpy_s(Stat_labels[Num_stat_lines], XSTR( "Current Score:", 1583));
|
||||
sprintf(Stats[Num_stat_lines], "%d", stats->score);
|
||||
Num_stat_lines++;
|
||||
|
||||
@@ -952,7 +952,9 @@ void barracks_init_player_stuff(int mode)
|
||||
Num_pilots = 0;
|
||||
Get_file_list_filter = barracks_pilot_filter;
|
||||
|
||||
Num_pilots = cf_get_file_list_preallocated(MAX_PILOTS, Pilots_arr, Pilots, CF_TYPE_PLAYERS, NOX("*.plr"), CF_SORT_TIME);
|
||||
Num_pilots =
|
||||
cf_get_file_list_preallocated(MAX_PILOTS, Pilots_arr, Pilots, CF_TYPE_PLAYERS, NOX("*.plr"), CF_SORT_TIME,
|
||||
nullptr, CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
|
||||
|
||||
int ranks[MAX_PILOTS];
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ int Main_hall_next_intercom_sound = 0;
|
||||
int Main_hall_next_intercom_sound_stamp = -1;
|
||||
|
||||
// handle to any playing instance of a random intercom sound
|
||||
int Main_hall_intercom_sound_handle = -1;
|
||||
sound_handle Main_hall_intercom_sound_handle = sound_handle::invalid();
|
||||
|
||||
// handle any details related to random intercom sounds
|
||||
void main_hall_handle_random_intercom_sounds();
|
||||
@@ -225,10 +225,10 @@ void main_hall_mouse_grab_region(int region);
|
||||
#define ALLENDER_REGION 4
|
||||
|
||||
// handles to the sound instances of the doors opening/closing
|
||||
SCP_vector<int> Main_hall_door_sound_handles;
|
||||
SCP_vector<sound_handle> Main_hall_door_sound_handles;
|
||||
|
||||
// sound handle for looping ambient sound
|
||||
int Main_hall_ambient_loop = -1;
|
||||
sound_handle Main_hall_ambient_loop = sound_handle::invalid();
|
||||
|
||||
// cull any door sounds that have finished playing
|
||||
void main_hall_cull_door_sounds();
|
||||
@@ -592,7 +592,7 @@ void main_hall_init(const SCP_string &main_hall_name)
|
||||
// initialize door sound handles
|
||||
Main_hall_door_sound_handles.clear();
|
||||
for (idx = 0; idx < Main_hall->num_door_animations; idx++) {
|
||||
Main_hall_door_sound_handles.push_back(-1);
|
||||
Main_hall_door_sound_handles.push_back(sound_handle::invalid());
|
||||
}
|
||||
|
||||
// skip the first frame
|
||||
@@ -607,7 +607,7 @@ void main_hall_init(const SCP_string &main_hall_name)
|
||||
// initialize the random intercom sound stuff
|
||||
Main_hall_next_intercom_sound = 0;
|
||||
Main_hall_next_intercom_sound_stamp = -1;
|
||||
Main_hall_intercom_sound_handle = -1;
|
||||
Main_hall_intercom_sound_handle = sound_handle::invalid();
|
||||
|
||||
// set the placement of the mouse cursor (start at the ready room)
|
||||
Main_hall_mouse_region = -1;
|
||||
@@ -1061,9 +1061,9 @@ void main_hall_close()
|
||||
|
||||
// stop any playing door sounds
|
||||
for (idx = 0; idx < Main_hall->num_door_animations-2; idx++) {
|
||||
if ( (Main_hall_door_sound_handles.at(idx) != -1) && snd_is_playing(Main_hall_door_sound_handles.at(idx)) ) {
|
||||
if ((Main_hall_door_sound_handles.at(idx).isValid()) && snd_is_playing(Main_hall_door_sound_handles.at(idx))) {
|
||||
snd_stop(Main_hall_door_sound_handles.at(idx));
|
||||
Main_hall_door_sound_handles.at(idx) = -1;
|
||||
Main_hall_door_sound_handles.at(idx) = sound_handle::invalid();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1382,7 +1382,7 @@ void main_hall_mouse_release_region(int region)
|
||||
// check for door sounds, ignoring the OPTIONS_REGION (which isn't a door)
|
||||
if (Main_hall_door_anim.at(region).num_frames > 0) {
|
||||
// don't stop the toaster oven or microwave regions from playing all the way through
|
||||
if (Main_hall_door_sound_handles.at(region) != -1) {
|
||||
if (Main_hall_door_sound_handles.at(region).isValid()) {
|
||||
snd_stop(Main_hall_door_sound_handles.at(region));
|
||||
}
|
||||
|
||||
@@ -1425,7 +1425,7 @@ void main_hall_mouse_grab_region(int region)
|
||||
|
||||
// check for opening/starting sounds
|
||||
// kill the currently playing sounds if necessary
|
||||
if (Main_hall_door_sound_handles.at(region) != -1) {
|
||||
if (Main_hall_door_sound_handles.at(region).isValid()) {
|
||||
snd_stop(Main_hall_door_sound_handles.at(region));
|
||||
}
|
||||
|
||||
@@ -1508,8 +1508,8 @@ void main_hall_cull_door_sounds()
|
||||
// basically just set the handle of any finished sound to be -1, so that we know its free any where else in the code we may need it
|
||||
Assert(Main_hall_door_sound_handles.size() < INT_MAX);
|
||||
for (idx = 0; idx < (int)Main_hall_door_sound_handles.size(); idx++) {
|
||||
if ( (Main_hall_door_sound_handles.at(idx) != -1) && !snd_is_playing(Main_hall_door_sound_handles.at(idx)) ) {
|
||||
Main_hall_door_sound_handles.at(idx) = -1;
|
||||
if ((Main_hall_door_sound_handles.at(idx).isValid()) && !snd_is_playing(Main_hall_door_sound_handles.at(idx))) {
|
||||
Main_hall_door_sound_handles.at(idx) = sound_handle::invalid();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1526,14 +1526,14 @@ void main_hall_handle_random_intercom_sounds()
|
||||
}
|
||||
|
||||
// if we have no timestamp for the next random sound, then set on
|
||||
if ( (Main_hall_next_intercom_sound_stamp == -1) && (Main_hall_intercom_sound_handle == -1) ) {
|
||||
if ((Main_hall_next_intercom_sound_stamp == -1) && (!Main_hall_intercom_sound_handle.isValid())) {
|
||||
Main_hall_next_intercom_sound_stamp = timestamp((int)((rand() * RAND_MAX_1f) *
|
||||
(float)(Main_hall->intercom_delay.at(Main_hall_next_intercom_sound).at(1)
|
||||
- Main_hall->intercom_delay.at(Main_hall_next_intercom_sound).at(0))) );
|
||||
}
|
||||
|
||||
// if the there is no sound playing
|
||||
if (Main_hall_intercom_sound_handle == -1) {
|
||||
if (!Main_hall_intercom_sound_handle.isValid()) {
|
||||
if (Main_hall_paused) {
|
||||
return;
|
||||
}
|
||||
@@ -1571,7 +1571,7 @@ void main_hall_handle_random_intercom_sounds()
|
||||
- Main_hall->intercom_delay.at(Main_hall_next_intercom_sound).at(0))) );
|
||||
|
||||
// release the sound handle
|
||||
Main_hall_intercom_sound_handle = -1;
|
||||
Main_hall_intercom_sound_handle = sound_handle::invalid();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1624,7 +1624,7 @@ void main_hall_start_ambient()
|
||||
return;
|
||||
}
|
||||
|
||||
if (Main_hall_ambient_loop == -1) {
|
||||
if (!Main_hall_ambient_loop.isValid()) {
|
||||
play_ambient_loop = 1;
|
||||
} else {
|
||||
if (!snd_is_playing(Main_hall_ambient_loop)) {
|
||||
@@ -1642,9 +1642,9 @@ void main_hall_start_ambient()
|
||||
*/
|
||||
void main_hall_stop_ambient()
|
||||
{
|
||||
if (Main_hall_ambient_loop != -1) {
|
||||
if (Main_hall_ambient_loop.isValid()) {
|
||||
snd_stop(Main_hall_ambient_loop);
|
||||
Main_hall_ambient_loop = -1;
|
||||
Main_hall_ambient_loop = sound_handle::invalid();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1655,7 +1655,7 @@ void main_hall_stop_ambient()
|
||||
*/
|
||||
void main_hall_reset_ambient_vol()
|
||||
{
|
||||
if (Main_hall_ambient_loop >= 0) {
|
||||
if (Main_hall_ambient_loop.isValid()) {
|
||||
snd_set_volume(Main_hall_ambient_loop, gamesnd_get_interface_sound(InterfaceSounds::MAIN_HALL_AMBIENT)->volume_range.next());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,7 +242,7 @@ static int Sound_volume_int;
|
||||
static int Music_volume_int;
|
||||
static int Voice_volume_int;
|
||||
|
||||
static int Voice_vol_handle = -1;
|
||||
static sound_handle Voice_vol_handle = sound_handle::invalid();
|
||||
int Options_notify_stamp = -1;
|
||||
char Options_notify_string[200];
|
||||
|
||||
@@ -465,16 +465,14 @@ UI_XSTR Options_text[GR_NUM_RESOLUTIONS][OPTIONS_NUM_TEXT] = {
|
||||
|
||||
void options_play_voice_clip()
|
||||
{
|
||||
int snd_id;
|
||||
|
||||
if ( snd_is_playing(Voice_vol_handle) ) {
|
||||
snd_stop(Voice_vol_handle);
|
||||
Voice_vol_handle=-1;
|
||||
Voice_vol_handle = sound_handle::invalid();
|
||||
}
|
||||
auto gs = gamesnd_get_interface_sound(InterfaceSounds::VOICE_SLIDER_CLIP);
|
||||
auto entry = gamesnd_choose_entry(gs);
|
||||
|
||||
snd_id = snd_load(entry, gs->flags, 0);
|
||||
auto snd_id = snd_load(entry, gs->flags, 0);
|
||||
|
||||
Voice_vol_handle = snd_play_raw( snd_id, 0.0f, 1.0f, SND_PRIORITY_SINGLE_INSTANCE );
|
||||
}
|
||||
@@ -1047,9 +1045,9 @@ void options_menu_close()
|
||||
}
|
||||
}
|
||||
|
||||
if ( Voice_vol_handle >= 0 ) {
|
||||
if (Voice_vol_handle.isValid()) {
|
||||
snd_stop(Voice_vol_handle);
|
||||
Voice_vol_handle = -1;
|
||||
Voice_vol_handle = sound_handle::invalid();
|
||||
}
|
||||
|
||||
options_multi_close();
|
||||
|
||||
@@ -506,7 +506,7 @@ int Om_vox_voice_buffer_size = -1;
|
||||
unsigned char Om_vox_comp_buffer[OM_VOX_COMP_SIZE];
|
||||
int Om_vox_voice_comp_size = -1;
|
||||
|
||||
int Om_vox_playback_handle;
|
||||
sound_handle Om_vox_playback_handle;
|
||||
|
||||
// status of any test voice recording
|
||||
#define OM_VOX_TEST_NONE -1
|
||||
@@ -1710,7 +1710,7 @@ void options_multi_disable_vox_controls()
|
||||
// unset the sound buffer size so we don't display any waveforms
|
||||
Om_vox_voice_buffer_size = -1;
|
||||
Om_vox_voice_comp_size = -1;
|
||||
Om_vox_playback_handle = -1;
|
||||
Om_vox_playback_handle = sound_handle::invalid();
|
||||
Om_vox_test_status = OM_VOX_TEST_NONE;
|
||||
|
||||
// disable the player list select button
|
||||
@@ -1739,7 +1739,7 @@ void options_multi_enable_vox_controls()
|
||||
// unset the sound buffer size so we don't display any waveforms
|
||||
Om_vox_voice_buffer_size = -1;
|
||||
Om_vox_voice_comp_size = -1;
|
||||
Om_vox_playback_handle = -1;
|
||||
Om_vox_playback_handle = sound_handle::invalid();
|
||||
Om_vox_test_status = OM_VOX_TEST_NONE;
|
||||
|
||||
// select the first player on the list
|
||||
@@ -1851,12 +1851,12 @@ void options_multi_vox_do()
|
||||
|
||||
case OM_VOX_TEST_PLAYBACK:
|
||||
// if we were playing a sound back, but now the sound is done
|
||||
if ( (Om_vox_playback_handle != -1) && !ds_is_channel_playing(ds_get_channel(Om_vox_playback_handle)) ) {
|
||||
if ((Om_vox_playback_handle.isValid()) && !ds_is_channel_playing(ds_get_channel(Om_vox_playback_handle))) {
|
||||
// flush all playing sounds safely
|
||||
rtvoice_stop_playback_all();
|
||||
|
||||
// null the sound handle
|
||||
Om_vox_playback_handle = -1;
|
||||
Om_vox_playback_handle = sound_handle::invalid();
|
||||
|
||||
// set this so we know not to display any more waveforms
|
||||
Om_vox_voice_buffer_size = -1;
|
||||
|
||||
Loaded 100 of 339 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user