mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 22:56:30 -10:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db5a90c955 | ||
|
|
95f26ef625 | ||
|
|
bc7654392a | ||
|
|
760b035a3a | ||
|
|
ce2fd88c24 | ||
|
|
3d6c02ffe2 | ||
|
|
2aae150981 |
No files matched your search
+1
-11
@@ -4,27 +4,20 @@ modernize-*,\
|
||||
-modernize-avoid-c-arrays,\
|
||||
-modernize-make-unique,\
|
||||
-modernize-raw-string-literal,\
|
||||
-modernize-use-default-member-init,\
|
||||
-modernize-use-trailing-return-type,\
|
||||
-modernize-use-using,\
|
||||
performance-*,\
|
||||
-performance-no-int-to-ptr,\
|
||||
-performance-type-promotion-in-math-fn,\
|
||||
misc-*,\
|
||||
-misc-include-cleaner,\
|
||||
-misc-macro-parentheses,\
|
||||
-misc-misplaced-widening-cast,\
|
||||
-misc-no-recursion,\
|
||||
-misc-non-private-member-variables-in-classes,\
|
||||
-misc-static-assert,\
|
||||
-misc-unused-parameters,\
|
||||
-misc-use-anonymous-namespace,\
|
||||
readability-*,\
|
||||
-readability-avoid-const-params-in-decls,\
|
||||
-readability-else-after-return,\
|
||||
-readability-function-cognitive-complexity,\
|
||||
-readability-function-size,\
|
||||
-readability-identifier-length,\
|
||||
-readability-identifier-naming,\
|
||||
-readability-implicit-bool-conversion,\
|
||||
-readability-inconsistent-declaration-parameter-name,\
|
||||
@@ -36,13 +29,10 @@ readability-*,\
|
||||
"
|
||||
WarningsAsErrors: ''
|
||||
HeaderFilterRegex: 'code/.*$|freespace2/.*$|qtfred/.*$|test/src/.*$|build/.*$'
|
||||
AnalyzeTemporaryDtors: false
|
||||
CheckOptions:
|
||||
- key: 'misc-assert-side-effect.AssertMacros'
|
||||
value: 'assert,Assert,Assertion'
|
||||
- key: 'misc-const-correctness.AnalyzeValues'
|
||||
value: 'false'
|
||||
- key: 'misc-const-correctness.TransformValues'
|
||||
value: 'false'
|
||||
- key: 'modernize-use-emplace.ContainersWithPushBack'
|
||||
value: 'std::vector;std::deque;std::list;SCP_vector;SCP_deque;SCP_list'
|
||||
- key: 'readability-braces-around-statements.ShortStatementLines'
|
||||
|
||||
@@ -2,14 +2,17 @@ name: Weekly Coverity Scan for Freespace Open
|
||||
# adapted from code by "albert-github" on the doxygen repository
|
||||
# many thanks for figuring this out first so it could be less painful for us!
|
||||
|
||||
# keep this from running on everyone's fork
|
||||
# if: github.ref == 'refs/heads/master'
|
||||
|
||||
#This mode is for testing
|
||||
#on: [push, pull_request]
|
||||
|
||||
# In production, push on a specific schedule
|
||||
on:
|
||||
schedule:
|
||||
- cron: "5 0 * * 5" # Run once per a week on Friday morning (midnight UTC, 4 AM EST), to avoid Coverity's submission limits
|
||||
|
||||
- cron: "57 18 * * *" # Run once per a week on Friday morning (4 AM EST), to avoid Coverity's submission limits
|
||||
|
||||
env:
|
||||
QT_VERSION: 5.12.12
|
||||
coverity_email: [email protected]
|
||||
@@ -18,20 +21,17 @@ env:
|
||||
jobs:
|
||||
build:
|
||||
name: Build FSO With Coverity Wrapper
|
||||
if: github.repository == 'scp-fs2open/fs2open.github.com'
|
||||
runs-on: ${{ matrix.config.os }}
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/scp-fs2open/linux_build:sha-1ff82e8
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
config:
|
||||
- { name: "GCC on ubuntu", os: ubuntu-latest, build_type: "Release" }
|
||||
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
with:
|
||||
submodules: recursive # `true` to checkout submodules, `recursive` to recursively checkout submodules
|
||||
submodules: true # `true` to checkout submodules, `recursive` to recursively checkout submodules
|
||||
|
||||
# pipe results of wget to a log file because it's very verbose and rarely fails
|
||||
- name: Install Coverity
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
|
||||
- name: Configure CMake for FSO
|
||||
env:
|
||||
CONFIGURATION: Release
|
||||
CONFIGURATION: FastDebug
|
||||
COMPILER: gcc-9
|
||||
ENABLE_QTFRED: OFF
|
||||
run: $GITHUB_WORKSPACE/ci/linux/configure_cmake.sh
|
||||
|
||||
@@ -5,8 +5,6 @@ set -e
|
||||
SCRIPT=$(readlink -f "$0")
|
||||
HERE=$(dirname "$SCRIPT")
|
||||
|
||||
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
|
||||
COMMIT_RANGE=$1..$2
|
||||
|
||||
if ! git rev-list $COMMIT_RANGE 2>&1 >/dev/null; then
|
||||
@@ -22,4 +20,4 @@ echo "Running clang-tidy on changed files"
|
||||
git diff -U0 --no-color "$BASE_COMMIT..$2" | \
|
||||
$HERE/clang-tidy-diff.py -path "$(pwd)/build" -p1 \
|
||||
-regex '(code(?!((\/graphics\/shaders\/compiled)|(\/globalincs\/windebug)))|freespace2|qtfred|test|build|tools)\/.*\.(cpp|h)' \
|
||||
-clang-tidy-binary /usr/bin/clang-tidy-16 -j$(nproc) -export-fixes "$(pwd)/clang-fixes.yaml"
|
||||
-clang-tidy-binary /usr/bin/clang-tidy-9 -j$(nproc) -export-fixes "$(pwd)/clang-fixes.yaml"
|
||||
@@ -1,3 +1,3 @@
|
||||
Mako==1.2.2
|
||||
requests==2.32.0
|
||||
requests==2.31.0
|
||||
semantic-version==2.8.5
|
||||
+4
-10
@@ -8,14 +8,8 @@ else()
|
||||
set(IS_64BIT FALSE)
|
||||
endif()
|
||||
|
||||
set(IS_ARM64 FALSE)
|
||||
|
||||
if (NOT "${CMAKE_GENERATOR_PLATFORM}" STREQUAL "") # needed to cover Visual Studio generator
|
||||
if(CMAKE_GENERATOR_PLATFORM MATCHES "^(aarch64|arm64|ARM64)")
|
||||
set(IS_ARM64 TRUE)
|
||||
endif()
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|ARM64)")
|
||||
set(IS_ARM64 TRUE)
|
||||
else()
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|ARM64)")
|
||||
set(IS_ARM64 TRUE)
|
||||
endif()
|
||||
endif()
|
||||
set(IS_ARM64 FALSE)
|
||||
endif()
|
||||
@@ -46,13 +46,9 @@ target_compile_options(compiler INTERFACE ${WARNING_FLAGS})
|
||||
set(CMAKE_C_FLAGS "/MP /GS- /analyze- /Zc:wchar_t /errorReport:prompt /Zc:forScope /Gd /EHsc /nologo /Zm200")
|
||||
set(CMAKE_CXX_FLAGS "/MP /GS- /analyze- /Zc:wchar_t /errorReport:prompt /Zc:forScope /Gd /EHsc /nologo /Zm200")
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "/MANIFEST /SAFESEH:NO /ERRORREPORT:PROMPT /NOLOGO")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "/MANIFEST /DYNAMICBASE:NO /SAFESEH:NO /ERRORREPORT:PROMPT /NOLOGO")
|
||||
set(CMAKE_STATIC_LINKER_FLAGS "")
|
||||
|
||||
if(NOT IS_ARM64)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DYNAMICBASE:NO")
|
||||
endif()
|
||||
|
||||
# Release
|
||||
set(CMAKE_C_FLAGS_RELEASE "/GL /Gy- /Ox /Ot /Ob2 /fp:precise /GF /Oy /Oi /Zi /W3")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "/GL /Gy- /Ox /Ot /Ob2 /fp:precise /GF /Oy /Oi /Zi /W3")
|
||||
|
||||
@@ -26,7 +26,7 @@ ActionResult MoveToSubmodel::execute(ProgramLocals& locals) const
|
||||
// The calling code should ensure that this never happens
|
||||
Assertion(locals.hostSubobject >= 0, "Did not have a valid host subobject.");
|
||||
|
||||
auto instance = object_get_model_instance(locals.host.objp());
|
||||
auto instance = object_get_model_instance(locals.host.objp);
|
||||
Assertion(instance != -1, "Model instances are required if a host subobject is specified.");
|
||||
|
||||
auto pmi = model_get_instance(instance);
|
||||
|
||||
@@ -37,7 +37,7 @@ ActionResult ParticleEffectAction::execute(ProgramLocals& locals) const
|
||||
vec3d local_pos;
|
||||
matrix local_orient;
|
||||
if (locals.hostSubobject != -1) {
|
||||
auto instance = object_get_model_instance(locals.host.objp());
|
||||
auto instance = object_get_model_instance(locals.host.objp);
|
||||
Assertion(instance != -1, "Model instances are required if a host subobject is specified.");
|
||||
|
||||
auto pmi = model_get_instance(instance);
|
||||
@@ -59,7 +59,7 @@ ActionResult ParticleEffectAction::execute(ProgramLocals& locals) const
|
||||
|
||||
auto direction = locals.variables.getValue({"locals", "direction"}).getVector();
|
||||
|
||||
source.moveToObject(locals.host.objp(), &local_pos);
|
||||
source.moveToObject(locals.host.objp, &local_pos);
|
||||
source.setOrientationFromNormalizedVec(&direction, true);
|
||||
|
||||
source.finish();
|
||||
|
||||
@@ -26,7 +26,7 @@ ActionResult PlaySoundAction::execute(ProgramLocals& locals) const
|
||||
vec3d local_pos;
|
||||
matrix local_orient;
|
||||
if (locals.hostSubobject != -1) {
|
||||
auto instance = object_get_model_instance(locals.host.objp());
|
||||
auto instance = object_get_model_instance(locals.host.objp);
|
||||
Assertion(instance != -1, "Model instances are required if a host subobject is specified.");
|
||||
|
||||
auto pmi = model_get_instance(instance);
|
||||
@@ -47,8 +47,8 @@ ActionResult PlaySoundAction::execute(ProgramLocals& locals) const
|
||||
local_pos += locals.variables.getValue({"locals", "position"}).getVector();
|
||||
|
||||
vec3d global_pos;
|
||||
vm_vec_unrotate(&global_pos, &local_pos, &locals.host.objp()->orient);
|
||||
global_pos += locals.host.objp()->pos;
|
||||
vm_vec_unrotate(&global_pos, &local_pos, &locals.host.objp->orient);
|
||||
global_pos += locals.host.objp->pos;
|
||||
|
||||
const auto soundId = gamesnd_get_by_name(m_soundIdExpression.execute(locals.variables).c_str());
|
||||
|
||||
|
||||
+2
-3
@@ -601,8 +601,7 @@ float ai_get_weapon_speed(const ship_weapon *swp);
|
||||
void set_predicted_enemy_pos_turret(vec3d *predicted_enemy_pos, const vec3d *gun_pos, const object *pobjp, const vec3d *enemy_pos, const vec3d *enemy_vel, float weapon_speed, float time_enemy_in_range);
|
||||
|
||||
// function to change rearm status for ai ships (called from sexpression code)
|
||||
extern void ai_set_good_rearm_time( int team, int time );
|
||||
extern void ai_set_bad_rearm_time(int team, int time);
|
||||
extern void ai_set_rearm_status( int team, int new_status );
|
||||
extern void ai_good_secondary_time( int team, int weapon_index, int num_weapons, const char *shipname );
|
||||
|
||||
extern void ai_do_objects_docked_stuff(object *docker, int docker_point, object *dockee, int dockee_point, bool update_clients = true);
|
||||
@@ -635,6 +634,6 @@ void do_random_sidethrust(ai_info *aip, ship_info *sip);
|
||||
void ai_formation_object_recalculate_slotnums(int form_objnum, int exiting_objnum = -1);
|
||||
|
||||
|
||||
bool test_line_of_sight(vec3d* from, vec3d* to, std::unordered_set<int>&& excluded_object_ids = {}, float threshold = 10.0f, bool test_for_shields = false, bool test_for_hull = true, float* first_intersect_dist = nullptr, object** first_intersect_obj = nullptr);
|
||||
bool test_line_of_sight(vec3d* from, vec3d* to, std::unordered_set<const object*>&& excluded_objects = {}, float threshold = 10.0f, bool test_for_shields = false, bool test_for_hull = true, float* first_intersect_dist = nullptr, object** first_intersect_obj = nullptr);
|
||||
|
||||
#endif
|
||||
@@ -32,8 +32,6 @@ namespace AI {
|
||||
Unload_primaries, // Fire primaries as fast as possible!
|
||||
Trying_unsuccessfully_to_warp, // Trying to warp, but can't warp at the moment
|
||||
Free_afterburner_use, // Use afterburners while following waypoints or flying towards objects
|
||||
Waypoints_no_formation, // wont get into formation when running waypoints as part of a wing
|
||||
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
@@ -162,9 +160,6 @@ namespace AI {
|
||||
Player_orders_afterburn_hard,
|
||||
Hudsquadmsg_tactical_disarm_disable,
|
||||
Align_to_target_when_guarding_still,
|
||||
Debris_respects_big_damage,
|
||||
Dont_limit_change_in_speed_due_to_physics_whack,
|
||||
Guards_ignore_protected_attackers,
|
||||
|
||||
NUM_VALUES
|
||||
};
|
||||
|
||||
+3
-36
@@ -184,14 +184,6 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
if (optional_string("$Max Beam Friendly Fire Damage:"))
|
||||
parse_float_list(profile->beam_friendly_damage_cap, NUM_SKILL_LEVELS);
|
||||
|
||||
if (optional_string("$Max Weapon Friendly Fire Damage:")) {
|
||||
parse_float_list(profile->weapon_friendly_damage_cap, NUM_SKILL_LEVELS);
|
||||
}
|
||||
|
||||
if (optional_string("$Max Weapon Self Damage:")) {
|
||||
parse_float_list(profile->weapon_self_damage_cap, NUM_SKILL_LEVELS);
|
||||
}
|
||||
|
||||
if (optional_string("$Player Countermeasure Life Scale:"))
|
||||
parse_float_list(profile->cmeasure_life_scale, NUM_SKILL_LEVELS);
|
||||
|
||||
@@ -479,20 +471,10 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
set_flag(profile, "$firing requires exact los:", AI::Profile_Flags::Require_exact_los);
|
||||
|
||||
if (optional_string("$exact los minimum detection radius:")) {
|
||||
stuff_float(&profile->los_min_detection_radius);
|
||||
}
|
||||
|
||||
set_flag(profile, "$fighterbay arrivals use carrier orientation:", AI::Profile_Flags::Fighterbay_arrivals_use_carrier_orient);
|
||||
|
||||
set_flag(profile, "$fighterbay departures use carrier orientation:", AI::Profile_Flags::Fighterbay_departures_use_carrier_orient);
|
||||
|
||||
set_flag(profile, "$debris damage respects 'big damage' flag:", AI::Profile_Flags::Debris_respects_big_damage);
|
||||
|
||||
set_flag(profile, "$don't limit change in speed due to physics whack:", AI::Profile_Flags::Dont_limit_change_in_speed_due_to_physics_whack);
|
||||
|
||||
set_flag(profile, "$guards ignore protected attackers:", AI::Profile_Flags::Guards_ignore_protected_attackers);
|
||||
|
||||
if (optional_string("$ai path mode:"))
|
||||
{
|
||||
stuff_string(buf, F_NAME, NAME_LENGTH);
|
||||
@@ -649,19 +631,13 @@ void parse_ai_profiles_tbl(const char *filename)
|
||||
|
||||
set_flag(profile, "$align to target when guarding stationary ship:", AI::Profile_Flags::Align_to_target_when_guarding_still);
|
||||
|
||||
if (optional_string("$rotation factor multiplier for player collisions:")) {
|
||||
stuff_float(&profile->rot_fac_multiplier_ply_collisions);
|
||||
}
|
||||
|
||||
// end of options ----------------------------------------
|
||||
|
||||
// if we've been through once already and are at the same place, force a move
|
||||
if (saved_Mp && (saved_Mp == Mp))
|
||||
{
|
||||
char tmp[60];
|
||||
memset(tmp, 0, 60);
|
||||
strncpy(tmp, Mp, 59);
|
||||
mprintf(("WARNING: Unrecognized parameter in %s: %s\n", filename, tmp));
|
||||
mprintf(("WARNING: Unrecognized parameter in ai_profiles: %s\n", tmp));
|
||||
|
||||
Mp++;
|
||||
}
|
||||
@@ -735,7 +711,6 @@ void ai_profile_t::reset()
|
||||
|
||||
flags.reset();
|
||||
|
||||
los_min_detection_radius = 10.0f;
|
||||
ai_path_mode = AI_PATH_MODE_NORMAL;
|
||||
subsystem_path_radii = 0;
|
||||
bay_arrive_speed_mult = 1.0f;
|
||||
@@ -743,7 +718,6 @@ void ai_profile_t::reset()
|
||||
second_order_lead_predict_factor = 0;
|
||||
ai_range_aware_secondary_select_mode = AI_RANGE_AWARE_SEC_SEL_MODE_RETAIL;
|
||||
turret_target_recheck_time = 2000.0f;
|
||||
rot_fac_multiplier_ply_collisions = 0.0f;
|
||||
|
||||
for (int i = 0; i < NUM_SKILL_LEVELS; ++i) {
|
||||
max_incoming_asteroids[i] = 0;
|
||||
@@ -766,12 +740,10 @@ void ai_profile_t::reset()
|
||||
shield_energy_scale[i] = 0;
|
||||
afterburner_recharge_scale[i] = 0;
|
||||
player_damage_scale[i] = 0;
|
||||
player_damage_inflicted_scale[i] = 0;
|
||||
player_damage_inflicted_scale[i] = 0;
|
||||
|
||||
subsys_damage_scale[i] = 0;
|
||||
beam_friendly_damage_cap[i] = -1.f;
|
||||
weapon_friendly_damage_cap[i] = -1.f;
|
||||
weapon_self_damage_cap[i] = -1.f;
|
||||
beam_friendly_damage_cap[i] = 0;
|
||||
turn_time_scale[i] = 0;
|
||||
glide_attack_percent[i] = 0;
|
||||
circle_strafe_percent[i] = 0;
|
||||
@@ -851,9 +823,4 @@ void ai_profile_t::reset()
|
||||
if (mod_supports_version(23, 4, 0)) {
|
||||
flags.set(AI::Profile_Flags::Hudsquadmsg_tactical_disarm_disable);
|
||||
}
|
||||
if (mod_supports_version(24, 2, 0)) {
|
||||
flags.set(AI::Profile_Flags::Debris_respects_big_damage);
|
||||
flags.set(AI::Profile_Flags::Force_beam_turret_fov);
|
||||
flags.set(AI::Profile_Flags::Guards_ignore_protected_attackers);
|
||||
}
|
||||
}
|
||||
@@ -57,8 +57,6 @@ public:
|
||||
|
||||
float subsys_damage_scale[NUM_SKILL_LEVELS]; // damage applied to a player subsystem
|
||||
float beam_friendly_damage_cap[NUM_SKILL_LEVELS]; // damage cap values for friendly beam fire
|
||||
float weapon_friendly_damage_cap[NUM_SKILL_LEVELS];
|
||||
float weapon_self_damage_cap[NUM_SKILL_LEVELS];
|
||||
float turn_time_scale[NUM_SKILL_LEVELS]; // speed at which enemy ships turn
|
||||
float glide_attack_percent[NUM_SKILL_LEVELS]; // SUSHI: The likelihood (0.0-1.0) of the AI to use the "glide attack" move
|
||||
float circle_strafe_percent[NUM_SKILL_LEVELS]; // SUSHI: The likelihood (0.0-1.0) of the AI to use the "circle strafe" move
|
||||
@@ -101,9 +99,6 @@ public:
|
||||
|
||||
float detail_distance_mult[MAX_DETAIL_LEVEL + 1]; //MAX_DETAIL_LEVEL really needs to be 4
|
||||
|
||||
// minimum radius for the line-of-sight (los) detection --wookieejedi
|
||||
float los_min_detection_radius;
|
||||
|
||||
int ai_path_mode;
|
||||
|
||||
// radii to use for the radius for subsystem path points and default value --wookieejedi
|
||||
@@ -123,9 +118,6 @@ public:
|
||||
// how often turrets shoulds check for new targets, milliseconds
|
||||
float turret_target_recheck_time;
|
||||
|
||||
// Multiplier value so the player can also experience rotational effects from collisions --wookieejedi
|
||||
float rot_fac_multiplier_ply_collisions;
|
||||
|
||||
void reset();
|
||||
};
|
||||
|
||||
|
||||
+1
-4
@@ -1933,10 +1933,7 @@ int ai_big_maybe_enter_strafe_mode(const object *pl_objp, int weapon_objnum)
|
||||
weapon_objp = &Objects[weapon_objnum];
|
||||
Assert(weapon_objp->type == OBJ_WEAPON);
|
||||
|
||||
if (weapon_objp->parent < 0) {
|
||||
return 0;
|
||||
}
|
||||
Assert(weapon_objp->parent < MAX_OBJECTS);
|
||||
Assert(weapon_objp->parent >= 0 && weapon_objp->parent < MAX_OBJECTS);
|
||||
parent_objp = &Objects[weapon_objp->parent];
|
||||
if ( (parent_objp->signature != weapon_objp->parent_sig) || (parent_objp->type != OBJ_SHIP) ) {
|
||||
return 0;
|
||||
|
||||
+20
-70
@@ -216,13 +216,11 @@ int Mission_all_attack = 0; // !0 means all teams attack all teams.
|
||||
ai_flag_name Ai_flag_names[] = {
|
||||
{AI::AI_Flags::No_dynamic, "no-dynamic", },
|
||||
{AI::AI_Flags::Free_afterburner_use, "free-afterburner-use", },
|
||||
{AI::AI_Flags::Waypoints_no_formation, "waypoints-no-formation" },
|
||||
};
|
||||
|
||||
ai_flag_description Ai_flag_descriptions[] = {
|
||||
{AI::AI_Flags::No_dynamic, "Will stop allowing the AI to pursue dynamic goals (eg: chasing ships it was not ordered to)."},
|
||||
{AI::AI_Flags::Free_afterburner_use, "Will allow AI to use afterburners when attacking a big ship, flying to a target position, guarding a ship, and flying in formation."},
|
||||
{AI::AI_Flags::Waypoints_no_formation, "Ship will not form up with its wingmates while running waypoints with them." },
|
||||
};
|
||||
|
||||
extern const int Num_ai_flag_names = sizeof(Ai_flag_names) / sizeof(ai_flag_name);
|
||||
@@ -323,34 +321,16 @@ object *Autopilot_flight_leader = NULL;
|
||||
|
||||
/**
|
||||
* Sets the timestamp used to tell is it is a good time for this team to rearm.
|
||||
* Ends a 'bad rearm time'
|
||||
* Once the timestamp is no longer valid, then rearming is not a "good time" (may or may not rearm)
|
||||
* Once the timestamp is no longer valid, then rearming is not a "good time"
|
||||
*
|
||||
* @param team Team (friendly, hostile, neutral)
|
||||
* @param time Time to rearm
|
||||
*/
|
||||
void ai_set_good_rearm_time(int team, int time)
|
||||
void ai_set_rearm_status(int team, int time)
|
||||
{
|
||||
Assert( time >= 0 );
|
||||
|
||||
Iff_info[team].ai_good_rearm_timestamp = _timestamp(time * MILLISECONDS_PER_SECOND);
|
||||
Iff_info[team].ai_bad_rearm_timestamp = TIMESTAMP::invalid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the timestamp used to tell is it is a bad time for this team to rearm.
|
||||
* Ends a 'good rearm time'
|
||||
* Once the timestamp is no longer valid, then rearming is not a "bad time" (may or may not rearm)
|
||||
*
|
||||
* @param team Team (friendly, hostile, neutral)
|
||||
* @param time Time to rearm
|
||||
*/
|
||||
void ai_set_bad_rearm_time(int team, int time)
|
||||
{
|
||||
Assert(time >= 0);
|
||||
|
||||
Iff_info[team].ai_bad_rearm_timestamp = _timestamp(time * MILLISECONDS_PER_SECOND);
|
||||
Iff_info[team].ai_good_rearm_timestamp = TIMESTAMP::invalid();
|
||||
Iff_info[team].ai_rearm_timestamp = _timestamp(time * MILLISECONDS_PER_SECOND);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -359,7 +339,7 @@ void ai_set_bad_rearm_time(int team, int time)
|
||||
* @return true(1) or false(0) if it is "safe" for the given object to rearm.
|
||||
* @todo This function could be easily expended to further the definition of "safe"
|
||||
*/
|
||||
bool ai_good_time_to_rearm(object *objp)
|
||||
int ai_good_time_to_rearm(object *objp)
|
||||
{
|
||||
int team;
|
||||
|
||||
@@ -367,24 +347,9 @@ bool ai_good_time_to_rearm(object *objp)
|
||||
team = Ships[objp->instance].team;
|
||||
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Fix_good_rearm_time_bug])
|
||||
return Iff_info[team].ai_good_rearm_timestamp.isValid() && !timestamp_elapsed(Iff_info[team].ai_good_rearm_timestamp);
|
||||
return Iff_info[team].ai_rearm_timestamp.isValid() && !timestamp_elapsed(Iff_info[team].ai_rearm_timestamp);
|
||||
else
|
||||
return Iff_info[team].ai_good_rearm_timestamp.isValid();
|
||||
}
|
||||
|
||||
/**
|
||||
* "unsafe" is currently defined by the mission designer using the good/bad time to rearm sexpressions. This status is currently team based.
|
||||
*
|
||||
* @return true(1) or false(0) if it is "unsafe" for the given object to rearm.
|
||||
*/
|
||||
bool ai_bad_time_to_rearm(object* objp)
|
||||
{
|
||||
int team;
|
||||
|
||||
Assert(objp->type == OBJ_SHIP);
|
||||
team = Ships[objp->instance].team;
|
||||
|
||||
return Iff_info[team].ai_bad_rearm_timestamp.isValid() && !timestamp_elapsed(Iff_info[team].ai_bad_rearm_timestamp);
|
||||
return Iff_info[team].ai_rearm_timestamp.isValid();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1038,10 +1003,8 @@ void ai_level_init()
|
||||
|
||||
Ai_goal_signature = 0;
|
||||
|
||||
for (i = 0; i < (int)Iff_info.size(); i++) {
|
||||
Iff_info[i].ai_good_rearm_timestamp = TIMESTAMP::invalid();
|
||||
Iff_info[i].ai_bad_rearm_timestamp = TIMESTAMP::invalid();
|
||||
}
|
||||
for (i = 0; i < (int) Iff_info.size(); i++)
|
||||
Iff_info[i].ai_rearm_timestamp = TIMESTAMP::invalid();
|
||||
|
||||
// clear out the stuff needed for AI firing powerful secondary weapons
|
||||
ai_init_secondary_info();
|
||||
@@ -1369,8 +1332,8 @@ void ai_turn_towards_vector(const vec3d* dest, object* objp, const vec3d* slide_
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't allow a ship to turn if it's prevented from turning.
|
||||
if ( objp->flags[Object::Object_Flags::Dont_change_orientation, Object::Object_Flags::Immobile] ) {
|
||||
// Don't allow a ship to turn if it's immobile.
|
||||
if ( objp->flags[Object::Object_Flags::Immobile] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -6235,7 +6198,7 @@ int ai_fire_primary_weapon(object *objp)
|
||||
weapon_info* wip = &Weapon_info[swp->primary_bank_weapons[swp->current_primary_bank]];
|
||||
if (aip->target_objnum != -1 && (The_mission.ai_profile->flags[AI::Profile_Flags::Require_exact_los] || wip->wi_flags[Weapon::Info_Flags::Require_exact_los])) {
|
||||
//Check if th AI has Line of Sight and is allowed to fire
|
||||
if (!check_los(OBJ_INDEX(objp), aip->target_objnum, The_mission.ai_profile->los_min_detection_radius, swp->current_primary_bank, -1, nullptr)) {
|
||||
if (!check_los(OBJ_INDEX(objp), aip->target_objnum, 10.0f, swp->current_primary_bank, -1, nullptr)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -6612,7 +6575,7 @@ bool check_ok_to_fire(int objnum, int target_objnum, const weapon_info *wip, int
|
||||
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Require_exact_los] || wip->wi_flags[Weapon::Info_Flags::Require_exact_los]) {
|
||||
//Check if th AI has Line of Sight and is allowed to fire
|
||||
if (!check_los(objnum, target_objnum, The_mission.ai_profile->los_min_detection_radius, -1, secondary_bank, firing_pos_global)) {
|
||||
if (!check_los(objnum, target_objnum, 10.0f, -1, secondary_bank, firing_pos_global)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -6703,7 +6666,7 @@ bool check_los(int objnum, int target_objnum, float threshold, int primary_bank,
|
||||
vec3d end = Objects[target_objnum].pos;
|
||||
|
||||
//Don't collision check against ourselves or our target
|
||||
return test_line_of_sight(&start, &end, {objnum, target_objnum}, threshold);
|
||||
return test_line_of_sight(&start, &end, {&Objects[objnum], &Objects[target_objnum]}, threshold);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
@@ -10269,11 +10232,6 @@ void guard_object_was_hit(object *guard_objp, object *hitter_objp)
|
||||
if (is_ignore_object(aip, OBJ_INDEX(hitter_objp)))
|
||||
return;
|
||||
|
||||
// If the hitter is protected, ignore it
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Guards_ignore_protected_attackers] &&
|
||||
hitter_objp->flags[Object::Object_Flags::Protected])
|
||||
return;
|
||||
|
||||
// If hitter is on same team as me, don't attack him.
|
||||
if (Ships[guard_objp->instance].team == Ships[hitter_objp->instance].team)
|
||||
return;
|
||||
@@ -10283,9 +10241,9 @@ void guard_object_was_hit(object *guard_objp, object *hitter_objp)
|
||||
return;
|
||||
}
|
||||
|
||||
// don't attack if you can't see it
|
||||
// don't attack if you can't see him
|
||||
if ( awacs_get_level(hitter_objp, &Ships[aip->shipnum], true) < 1.0f ) {
|
||||
// if it's stealthed and visible, but not targetable, ok to attack.
|
||||
// if he's a stealth and visible, but not targetable, ok to attack.
|
||||
if ( is_object_stealth_ship(hitter_objp) ) {
|
||||
if ( ai_is_stealth_visible(guard_objp, hitter_objp) != STEALTH_IN_FRUSTUM ) {
|
||||
return;
|
||||
@@ -10954,8 +10912,7 @@ void ai_guard()
|
||||
set_accel_for_target_speed(Pl_objp, (dist_to_goal_point-10.0f)/2.0f);
|
||||
} else if (Pl_objp->phys_info.speed < 1.0f) {
|
||||
if (aip->ai_profile_flags[AI::Profile_Flags::Align_to_target_when_guarding_still]) {
|
||||
vec3d goal_vec = guard_objp->orient.vec.fvec + Pl_objp->pos;
|
||||
turn_towards_point(Pl_objp, &goal_vec, nullptr, 0.0f, &guard_objp->orient);
|
||||
turn_towards_point(Pl_objp, &guard_objp->pos, nullptr, 0.0f, &guard_objp->orient);
|
||||
} else {
|
||||
turn_away_from_point(Pl_objp, &guard_objp->pos, 0.0f);
|
||||
}
|
||||
@@ -12656,11 +12613,6 @@ int ai_formation()
|
||||
}
|
||||
|
||||
if (aip->mode == AIM_WAYPOINTS) {
|
||||
// skip if they have the flag
|
||||
if (aip->ai_flags[AI::AI_Flags::Waypoints_no_formation] ||
|
||||
(shipp->wingnum >= 0 && Wings[shipp->wingnum].flags[Ship::Wing_Flags::Waypoints_no_formation]))
|
||||
return 1;
|
||||
|
||||
if (The_mission.ai_profile->flags[AI::Profile_Flags::Fix_ai_path_order_bug]){
|
||||
// skip if wing leader has no waypoint order or a different waypoint list
|
||||
// ...or if it's a different start index or direction
|
||||
@@ -14275,10 +14227,8 @@ int maybe_request_support(object *objp)
|
||||
|
||||
// Compute danger threshold.
|
||||
// Balance this with desire and maybe request support.
|
||||
if (ai_good_time_to_rearm(objp)) {
|
||||
if (ai_good_time_to_rearm( objp )) {
|
||||
try_to_rearm = true;
|
||||
} else if (ai_bad_time_to_rearm(objp)) {
|
||||
try_to_rearm = false;
|
||||
} else if (num_allies_rearming(objp) < 2) {
|
||||
if (desire >= 8) { // guarantees disabled will cause repair request
|
||||
try_to_rearm = true;
|
||||
@@ -16703,7 +16653,7 @@ void maybe_cheat_fire_synaptic(object *objp)
|
||||
}
|
||||
}
|
||||
|
||||
bool test_line_of_sight(vec3d* from, vec3d* to, std::unordered_set<int>&& excluded_object_ids, float threshold, bool test_for_shields, bool test_for_hull, float* first_intersect_dist, object** first_intersect_obj) {
|
||||
bool test_line_of_sight(vec3d* from, vec3d* to, std::unordered_set<const object*>&& excluded_objects, float threshold, bool test_for_shields, bool test_for_hull, float* first_intersect_dist, object** first_intersect_obj) {
|
||||
bool collides = false;
|
||||
|
||||
for (object* objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp)) {
|
||||
@@ -16711,7 +16661,7 @@ bool test_line_of_sight(vec3d* from, vec3d* to, std::unordered_set<int>&& exclud
|
||||
continue;
|
||||
|
||||
//Don't collision check against excluded objects
|
||||
if (excluded_object_ids.count(OBJ_INDEX(objp)) > 0)
|
||||
if (excluded_objects.count(objp) > 0)
|
||||
continue;
|
||||
|
||||
int model_num = 0;
|
||||
@@ -16724,7 +16674,7 @@ bool test_line_of_sight(vec3d* from, vec3d* to, std::unordered_set<int>&& exclud
|
||||
model_instance_num = -1;
|
||||
}
|
||||
else if (type == OBJ_ASTEROID) {
|
||||
model_num = Asteroid_info[Asteroids[objp->instance].asteroid_type].subtypes[Asteroids[objp->instance].asteroid_subtype].model_number;
|
||||
model_num = Asteroid_info[Asteroids[objp->instance].asteroid_type].model_num[Asteroids[objp->instance].asteroid_subtype];
|
||||
model_instance_num = Asteroids[objp->instance].model_instance_num;
|
||||
}
|
||||
else if (type == OBJ_SHIP) {
|
||||
|
||||
+35
-52
@@ -133,7 +133,7 @@ bool object_in_turret_fov(const object *objp, const ship_subsys *ss, const vec3d
|
||||
model_num = Ship_info[Ships[objp->instance].ship_info_index].model_num;
|
||||
break;
|
||||
case OBJ_ASTEROID:
|
||||
model_num = Asteroid_info[Asteroids[objp->instance].asteroid_type].subtypes[Asteroids[objp->instance].asteroid_subtype].model_number;
|
||||
model_num = Asteroid_info[Asteroids[objp->instance].asteroid_type].model_num[Asteroids[objp->instance].asteroid_subtype];
|
||||
break;
|
||||
default:
|
||||
vm_vec_normalized_dir(&v2e, &objp->pos, tpos);
|
||||
@@ -1215,7 +1215,6 @@ void ship_get_global_turret_gun_info(const object *objp, const ship_subsys *ssp,
|
||||
}
|
||||
|
||||
model_instance_local_to_global_point(gpos, gun_pos, pm, pmi, tp->turret_gun_sobj, &objp->orient, &objp->pos);
|
||||
|
||||
|
||||
// we might not need to calculate this
|
||||
if (!gvec)
|
||||
@@ -1782,47 +1781,45 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
if (!(turret->weapons.flags[Ship::Weapon_Flags::Beam_Free])) {
|
||||
return false;
|
||||
}
|
||||
beam_fire_info fire_info;
|
||||
|
||||
for (int i = 0; i < wip->shots; i++) {
|
||||
beam_fire_info fire_info;
|
||||
// stuff beam firing info
|
||||
memset(&fire_info, 0, sizeof(beam_fire_info));
|
||||
fire_info.accuracy = 1.0f;
|
||||
fire_info.beam_info_index = turret_weapon_class;
|
||||
fire_info.beam_info_override = nullptr;
|
||||
fire_info.shooter = &Objects[parent_objnum];
|
||||
fire_info.target = turret_enemy_objp;
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Antisubsysbeam])
|
||||
fire_info.target_subsys = turret->targeted_subsys;
|
||||
else
|
||||
fire_info.target_subsys = nullptr;
|
||||
fire_info.turret = turret;
|
||||
fire_info.burst_seed = old_burst_seed;
|
||||
fire_info.fire_method = BFM_TURRET_FIRED;
|
||||
fire_info.per_burst_rotation = swp->per_burst_rot;
|
||||
fire_info.burst_index = old_burst_counter;
|
||||
|
||||
// stuff beam firing info
|
||||
memset(&fire_info, 0, sizeof(beam_fire_info));
|
||||
fire_info.accuracy = 1.0f;
|
||||
fire_info.beam_info_index = turret_weapon_class;
|
||||
fire_info.beam_info_override = nullptr;
|
||||
fire_info.shooter = &Objects[parent_objnum];
|
||||
fire_info.target = turret_enemy_objp;
|
||||
if (wip->wi_flags[Weapon::Info_Flags::Antisubsysbeam])
|
||||
fire_info.target_subsys = turret->targeted_subsys;
|
||||
else
|
||||
fire_info.target_subsys = nullptr;
|
||||
fire_info.turret = turret;
|
||||
fire_info.burst_seed = old_burst_seed;
|
||||
fire_info.fire_method = BFM_TURRET_FIRED;
|
||||
fire_info.per_burst_rotation = swp->per_burst_rot;
|
||||
fire_info.burst_index = (old_burst_counter * wip->shots) + i;
|
||||
// fire a beam weapon
|
||||
weapon_objnum = beam_fire(&fire_info);
|
||||
|
||||
// fire a beam weapon
|
||||
weapon_objnum = beam_fire(&fire_info);
|
||||
if (weapon_objnum != -1) {
|
||||
objp = &Objects[weapon_objnum];
|
||||
|
||||
if (weapon_objnum != -1) {
|
||||
objp = &Objects[weapon_objnum];
|
||||
parent_ship->last_fired_turret = turret;
|
||||
turret->last_fired_weapon_info_index = turret_weapon_class;
|
||||
turret->turret_last_fired = _timestamp();
|
||||
|
||||
parent_ship->last_fired_turret = turret;
|
||||
turret->last_fired_weapon_info_index = turret_weapon_class;
|
||||
turret->turret_last_fired = _timestamp();
|
||||
|
||||
if (scripting::hooks::OnTurretFired->isActive()) {
|
||||
scripting::hooks::OnTurretFired->run(scripting::hooks::WeaponUsedConditions{ parent_ship , turret_enemy_objp, SCP_vector<int>{ turret_weapon_class }, true },
|
||||
scripting::hook_param_list(
|
||||
scripting::hook_param("Ship", 'o', &Objects[parent_objnum]),
|
||||
scripting::hook_param("Beam", 'o', objp),
|
||||
scripting::hook_param("Target", 'o', turret_enemy_objp)
|
||||
));
|
||||
}
|
||||
if (scripting::hooks::OnTurretFired->isActive()) {
|
||||
scripting::hooks::OnTurretFired->run(scripting::hooks::WeaponUsedConditions{ parent_ship , turret_enemy_objp, SCP_vector<int>{ turret_weapon_class }, true },
|
||||
scripting::hook_param_list(
|
||||
scripting::hook_param("Ship", 'o', &Objects[parent_objnum]),
|
||||
scripting::hook_param("Beam", 'o', objp),
|
||||
scripting::hook_param("Target", 'o', turret_enemy_objp)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
turret->flags.set(Ship::Subsystem_Flags::Has_fired); //set fired flag for scripting -nike
|
||||
return true;
|
||||
}
|
||||
@@ -1991,14 +1988,7 @@ bool turret_fire_weapon(int weapon_num, ship_subsys *turret, int parent_objnum,
|
||||
}
|
||||
|
||||
// do mflash if the weapon has it
|
||||
if (wip->muzzle_effect.isValid()) {
|
||||
//spawn particle effect
|
||||
auto particleSource = particle::ParticleManager::get()->createSource(wip->muzzle_effect);
|
||||
particleSource.moveToTurret(&Objects[parent_ship->objnum], turret->system_info->turret_gun_sobj, turret->turret_next_fire_pos);
|
||||
particleSource.setVelocity(&Objects[parent_ship->objnum].phys_info.vel);
|
||||
particleSource.finish();
|
||||
}
|
||||
else if (wip->muzzle_flash >= 0) {
|
||||
if (wip->muzzle_flash >= 0) {
|
||||
mflash_create(firing_pos, firing_vec, &Objects[parent_ship->objnum].phys_info, wip->muzzle_flash);
|
||||
}
|
||||
|
||||
@@ -2108,14 +2098,7 @@ void turret_swarm_fire_from_turret(turret_swarm_info *tsi)
|
||||
}
|
||||
|
||||
// muzzle flash?
|
||||
if (Weapon_info[tsi->weapon_class].muzzle_effect.isValid()) {
|
||||
//spawn particle effect
|
||||
auto particleSource = particle::ParticleManager::get()->createSource(Weapon_info[tsi->weapon_class].muzzle_effect);
|
||||
particleSource.moveToTurret(&Objects[tsi->parent_objnum], tsi->turret->system_info->turret_gun_sobj, tsi->turret->turret_next_fire_pos - 1);
|
||||
particleSource.setVelocity(&Objects[tsi->parent_objnum].phys_info.vel);
|
||||
particleSource.finish();
|
||||
}
|
||||
else if (Weapon_info[tsi->weapon_class].muzzle_flash >= 0) {
|
||||
if (Weapon_info[tsi->weapon_class].muzzle_flash >= 0) {
|
||||
mflash_create(&turret_pos, &turret_fvec, &Objects[tsi->parent_objnum].phys_info, Weapon_info[tsi->weapon_class].muzzle_flash);
|
||||
}
|
||||
|
||||
|
||||
+174
-222
@@ -262,25 +262,6 @@ static void inner_bound_pos_fixup(asteroid_field *asfieldp, vec3d *pos)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Randomly select an asteroid subtype
|
||||
*/
|
||||
const SCP_string& pick_random_asteroid_type()
|
||||
{
|
||||
return Asteroid_field.field_asteroid_type[Random::next(static_cast<int>(Asteroid_field.field_asteroid_type.size()))];
|
||||
}
|
||||
|
||||
int get_asteroid_subtype_index_by_name(const SCP_string &name, int asteroid_idx) {
|
||||
asteroid_info* this_asteroid = &Asteroid_info[asteroid_idx];
|
||||
for (int i = 0; i < static_cast<int>(this_asteroid->subtypes.size()); i++) {
|
||||
if (this_asteroid->subtypes[i].type_name == name) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a single asteroid
|
||||
*/
|
||||
@@ -298,8 +279,8 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
|
||||
int rand_base;
|
||||
|
||||
// bogus
|
||||
if(asfieldp == nullptr) {
|
||||
return nullptr;
|
||||
if(asfieldp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (n=0; n<MAX_ASTEROIDS; n++) {
|
||||
@@ -310,11 +291,15 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
|
||||
|
||||
if (n >= MAX_ASTEROIDS) {
|
||||
nprintf(("Warning","Could not create asteroid, no more slots left\n"));
|
||||
return nullptr;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!SCP_vector_inbounds(Asteroid_info, asteroid_type)) {
|
||||
return nullptr;
|
||||
if((asteroid_type < 0) || (asteroid_type >= (int)Asteroid_info.size())) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if((asteroid_subtype < 0) || (asteroid_subtype >= NUM_ASTEROID_POFS)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// HACK: multiplayer asteroid subtype always 0 to keep subtype in sync
|
||||
@@ -324,13 +309,9 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
|
||||
|
||||
asip = &Asteroid_info[asteroid_type];
|
||||
|
||||
if (!SCP_vector_inbounds(asip->subtypes, asteroid_subtype)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// if the model is not loaded then abort
|
||||
if(asip->subtypes[asteroid_subtype].model_pointer == nullptr) {
|
||||
return nullptr;
|
||||
// bogus
|
||||
if(asip->modelp[asteroid_subtype] == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
asp = &Asteroids[n];
|
||||
@@ -345,7 +326,7 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
|
||||
asp->collide_objsig = -1;
|
||||
asp->target_objnum = -1;
|
||||
|
||||
radius = model_get_radius(asip->subtypes[asteroid_subtype].model_number);
|
||||
radius = model_get_radius(asip->model_num[asteroid_subtype]);
|
||||
|
||||
vm_vec_sub(&delta_bound, &asfieldp->max_bound, &asfieldp->min_bound);
|
||||
|
||||
@@ -398,8 +379,8 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
|
||||
asp->objnum = objnum;
|
||||
asp->model_instance_num = -1;
|
||||
|
||||
if (model_get(asip->subtypes[asteroid_subtype].model_number)->flags & PM_FLAG_HAS_INTRINSIC_MOTION) {
|
||||
asp->model_instance_num = model_create_instance(objnum, asip->subtypes[asteroid_subtype].model_number);
|
||||
if (model_get(asip->model_num[asteroid_subtype])->flags & PM_FLAG_HAS_INTRINSIC_MOTION) {
|
||||
asp->model_instance_num = model_create_instance(objnum, asip->model_num[asteroid_subtype]);
|
||||
}
|
||||
|
||||
// Add to Asteroid_used_list
|
||||
@@ -454,8 +435,8 @@ object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroi
|
||||
objp->phys_info.max_vel.xyz.y = 0.0f;
|
||||
objp->phys_info.max_vel.xyz.z = vm_vec_mag(&objp->phys_info.desired_vel);
|
||||
|
||||
objp->phys_info.mass = asip->subtypes[asteroid_subtype].model_pointer->rad * 700.0f;
|
||||
objp->phys_info.I_body_inv.vec.rvec.xyz.x = 1.0f / (objp->phys_info.mass*asip->subtypes[asteroid_subtype].model_pointer->rad);
|
||||
objp->phys_info.mass = asip->modelp[asteroid_subtype]->rad * 700.0f;
|
||||
objp->phys_info.I_body_inv.vec.rvec.xyz.x = 1.0f / (objp->phys_info.mass*asip->modelp[asteroid_subtype]->rad);
|
||||
objp->phys_info.I_body_inv.vec.uvec.xyz.y = objp->phys_info.I_body_inv.vec.rvec.xyz.x;
|
||||
objp->phys_info.I_body_inv.vec.fvec.xyz.z = objp->phys_info.I_body_inv.vec.rvec.xyz.x;
|
||||
objp->hull_strength = asip->initial_asteroid_strength * (0.8f + (float)Game_skill_level/NUM_SKILL_LEVELS)/2.0f;
|
||||
@@ -484,8 +465,7 @@ void asteroid_sub_create(object *parent_objp, int asteroid_type, vec3d *relvec)
|
||||
int subtype = Asteroids[parent_objp->instance].asteroid_subtype;
|
||||
new_objp = asteroid_create(&Asteroid_field, asteroid_type, subtype);
|
||||
|
||||
// New asteroid size doesn't have this subtype, so abort
|
||||
if (new_objp == nullptr)
|
||||
if (new_objp == NULL)
|
||||
return;
|
||||
|
||||
if ( MULTIPLAYER_MASTER ){
|
||||
@@ -522,35 +502,27 @@ static void asteroid_load(int asteroid_info_index, int asteroid_subtype)
|
||||
int i;
|
||||
asteroid_info *asip;
|
||||
|
||||
Assertion(asteroid_info_index < static_cast<int>(Asteroid_info.size()),
|
||||
"Command to load asteroid at index %i, but only %i asteroids exist",
|
||||
asteroid_info_index,
|
||||
static_cast<int>(Asteroid_info.size()));
|
||||
Assertion(asteroid_info_index < (int)Asteroid_info.size(), "Command to load asteroid at index %i, but only %i asteroids exist", asteroid_info_index, (int)Asteroid_info.size());
|
||||
Assertion(asteroid_subtype < NUM_ASTEROID_POFS, "Command to load asteroid pof %i, but only %i pofs are allowed", asteroid_subtype, NUM_ASTEROID_POFS);
|
||||
|
||||
// invalid asteroid index
|
||||
if (!SCP_vector_inbounds(Asteroid_info, asteroid_info_index)) {
|
||||
if ( (asteroid_info_index >= (int)Asteroid_info.size()) || (asteroid_subtype >= NUM_ASTEROID_POFS) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
asip = &Asteroid_info[asteroid_info_index];
|
||||
|
||||
// This asteroid does not have this subtype so just return
|
||||
if (!SCP_vector_inbounds(asip->subtypes, asteroid_subtype)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !VALID_FNAME(asip->subtypes[asteroid_subtype].pof_filename) )
|
||||
if ( !VALID_FNAME(asip->pof_files[asteroid_subtype]) )
|
||||
return;
|
||||
|
||||
//Check if the model is already loaded
|
||||
if (asip->subtypes[asteroid_subtype].model_number >= 0)
|
||||
if (asip->model_num[asteroid_subtype] >= 0)
|
||||
return;
|
||||
|
||||
asip->subtypes[asteroid_subtype].model_number = model_load( asip->subtypes[asteroid_subtype].pof_filename, 0, nullptr );
|
||||
asip->model_num[asteroid_subtype] = model_load( asip->pof_files[asteroid_subtype], 0, NULL );
|
||||
|
||||
if (asip->subtypes[asteroid_subtype].model_number >= 0)
|
||||
if (asip->model_num[asteroid_subtype] >= 0)
|
||||
{
|
||||
polymodel *pm = asip->subtypes[asteroid_subtype].model_pointer = model_get(asip->subtypes[asteroid_subtype].model_number);
|
||||
polymodel *pm = asip->modelp[asteroid_subtype] = model_get(asip->model_num[asteroid_subtype]);
|
||||
|
||||
if ( asip->num_detail_levels != pm->n_detail_levels )
|
||||
{
|
||||
@@ -581,11 +553,10 @@ void asteroid_create_all()
|
||||
// each different type (size) of debris piece has a diffenent weight, smaller weighted more heavily than larger.
|
||||
// choose next type from table ship_debris_odds_table by Random::next()%max_weighted_range,
|
||||
// the threshold *below* which the debris type is selected.
|
||||
struct ShipDebrisOdds {
|
||||
struct {
|
||||
float random_threshold;
|
||||
int debris_type;
|
||||
};
|
||||
std::vector<ShipDebrisOdds> shipDebrisOddsTable(Asteroid_field.field_debris_type.size());
|
||||
} ship_debris_odds_table[MAX_ACTIVE_DEBRIS_TYPES];
|
||||
|
||||
float max_weighted_range = 0.0f;
|
||||
|
||||
@@ -596,8 +567,7 @@ void asteroid_create_all()
|
||||
return;
|
||||
}
|
||||
|
||||
if ((Asteroid_field.debris_genre == DG_DEBRIS && Asteroid_field.field_debris_type.empty()) ||
|
||||
(Asteroid_field.debris_genre == DG_ASTEROID && Asteroid_field.field_asteroid_type.empty())) {
|
||||
if (Asteroid_field.num_used_field_debris_types <= 0) {
|
||||
Warning(LOCATION, "An asteroid field is enabled, but no asteroid types were enabled.");
|
||||
return;
|
||||
}
|
||||
@@ -632,29 +602,45 @@ void asteroid_create_all()
|
||||
|
||||
int num_debris_types = 0;
|
||||
|
||||
// get number of debris types
|
||||
// get number of ship debris types
|
||||
if (Asteroid_field.debris_genre == DG_DEBRIS) {
|
||||
num_debris_types = static_cast<int>(Asteroid_field.field_debris_type.size());
|
||||
for (idx=0; idx<MAX_ACTIVE_DEBRIS_TYPES; idx++) {
|
||||
if (Asteroid_field.field_debris_type[idx] != -1) {
|
||||
num_debris_types++;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the odds table
|
||||
for (idx=0; idx<num_debris_types; idx++) {
|
||||
float debris_weight = Asteroid_info[Asteroid_field.field_debris_type[idx]].spawn_weight;
|
||||
shipDebrisOddsTable[idx].random_threshold = max_weighted_range + debris_weight;
|
||||
shipDebrisOddsTable[idx].debris_type = Asteroid_field.field_debris_type[idx];
|
||||
ship_debris_odds_table[idx].random_threshold = max_weighted_range + debris_weight;
|
||||
ship_debris_odds_table[idx].debris_type = Asteroid_field.field_debris_type[idx];
|
||||
max_weighted_range += debris_weight;
|
||||
}
|
||||
}
|
||||
|
||||
// Load Asteroid/debris models
|
||||
// Load Asteroid/ship models
|
||||
if (Asteroid_field.debris_genre == DG_DEBRIS) {
|
||||
for (idx=0; idx<num_debris_types; idx++) {
|
||||
asteroid_load(Asteroid_field.field_debris_type[idx], 0);
|
||||
}
|
||||
} else {
|
||||
for (const auto& subtype : Asteroid_field.field_asteroid_type) {
|
||||
asteroid_load(ASTEROID_TYPE_SMALL, get_asteroid_subtype_index_by_name(subtype, ASTEROID_TYPE_SMALL));
|
||||
asteroid_load(ASTEROID_TYPE_MEDIUM, get_asteroid_subtype_index_by_name(subtype, ASTEROID_TYPE_MEDIUM));
|
||||
asteroid_load(ASTEROID_TYPE_LARGE, get_asteroid_subtype_index_by_name(subtype, ASTEROID_TYPE_LARGE));
|
||||
if (Asteroid_field.field_debris_type[0] != -1) {
|
||||
asteroid_load(ASTEROID_TYPE_SMALL, 0);
|
||||
asteroid_load(ASTEROID_TYPE_MEDIUM, 0);
|
||||
asteroid_load(ASTEROID_TYPE_LARGE, 0);
|
||||
}
|
||||
|
||||
if (Asteroid_field.field_debris_type[1] != -1) {
|
||||
asteroid_load(ASTEROID_TYPE_SMALL, 1);
|
||||
asteroid_load(ASTEROID_TYPE_MEDIUM, 1);
|
||||
asteroid_load(ASTEROID_TYPE_LARGE, 1);
|
||||
}
|
||||
|
||||
if (Asteroid_field.field_debris_type[2] != -1) {
|
||||
asteroid_load(ASTEROID_TYPE_SMALL, 2);
|
||||
asteroid_load(ASTEROID_TYPE_MEDIUM, 2);
|
||||
asteroid_load(ASTEROID_TYPE_LARGE, 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -664,7 +650,17 @@ void asteroid_create_all()
|
||||
// For asteroid, load only large asteroids
|
||||
|
||||
// get a valid subtype
|
||||
int subtype = get_asteroid_subtype_index_by_name(pick_random_asteroid_type(), ASTEROID_TYPE_LARGE);
|
||||
int counter = Random::next(Asteroid_field.num_used_field_debris_types);
|
||||
int subtype = -1;
|
||||
for (int j = 0; j < NUM_ASTEROID_POFS; j++) {
|
||||
if (Asteroid_field.field_debris_type[j] >= 0) {
|
||||
if (counter == 0) {
|
||||
subtype = j;
|
||||
break;
|
||||
} else
|
||||
counter--;
|
||||
}
|
||||
}
|
||||
|
||||
if (subtype >= 0)
|
||||
asteroid_create(&Asteroid_field, ASTEROID_TYPE_LARGE, subtype);
|
||||
@@ -673,10 +669,10 @@ void asteroid_create_all()
|
||||
|
||||
float rand_choice = frand() * max_weighted_range;
|
||||
|
||||
for (idx = 0; idx < static_cast<int>(Asteroid_field.field_debris_type.size()); idx++) {
|
||||
for (idx=0; idx<MAX_ACTIVE_DEBRIS_TYPES; idx++) {
|
||||
// for ship debris, choose type according to odds table
|
||||
if (rand_choice < shipDebrisOddsTable[idx].random_threshold) {
|
||||
asteroid_create(&Asteroid_field, shipDebrisOddsTable[idx].debris_type, 0);
|
||||
if (rand_choice < ship_debris_odds_table[idx].random_threshold) {
|
||||
asteroid_create(&Asteroid_field, ship_debris_odds_table[idx].debris_type, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -702,7 +698,7 @@ void remove_all_asteroids()
|
||||
}
|
||||
|
||||
// will replace any existing asteroid or debris field with an asteroid field
|
||||
void asteroid_create_asteroid_field(int num_asteroids, int field_type, int asteroid_speed, vec3d o_min, vec3d o_max, bool inner_box, vec3d i_min, vec3d i_max, SCP_vector<SCP_string> asteroid_types)
|
||||
void asteroid_create_asteroid_field(int num_asteroids, int field_type, int asteroid_speed, bool brown, bool blue, bool orange, vec3d o_min, vec3d o_max, bool inner_box, vec3d i_min, vec3d i_max, SCP_vector<SCP_string> targets)
|
||||
{
|
||||
remove_all_asteroids();
|
||||
|
||||
@@ -736,11 +732,25 @@ void asteroid_create_asteroid_field(int num_asteroids, int field_type, int aster
|
||||
Asteroid_field.speed = (float)asteroid_speed;
|
||||
Asteroid_field.debris_genre = DG_ASTEROID;
|
||||
|
||||
Asteroid_field.field_debris_type.clear();
|
||||
Asteroid_field.field_debris_type[0] = -1;
|
||||
Asteroid_field.field_debris_type[1] = -1;
|
||||
Asteroid_field.field_debris_type[2] = -1;
|
||||
|
||||
Asteroid_field.field_asteroid_type.clear();
|
||||
int count = 0;
|
||||
if (brown) {
|
||||
Asteroid_field.field_debris_type[0] = 1;
|
||||
count++;
|
||||
}
|
||||
if (blue) {
|
||||
Asteroid_field.field_debris_type[1] = 1;
|
||||
count++;
|
||||
}
|
||||
if (orange) {
|
||||
Asteroid_field.field_debris_type[2] = 1;
|
||||
count++;
|
||||
}
|
||||
|
||||
Asteroid_field.field_asteroid_type = std::move(asteroid_types);
|
||||
Asteroid_field.num_used_field_debris_types = count;
|
||||
|
||||
Asteroid_field.min_bound = o_min;
|
||||
Asteroid_field.max_bound = o_max;
|
||||
@@ -758,14 +768,16 @@ void asteroid_create_asteroid_field(int num_asteroids, int field_type, int aster
|
||||
Asteroid_field.inner_max_bound = i_max;
|
||||
}
|
||||
|
||||
Asteroid_field.target_names = targets;
|
||||
|
||||
// Only create asteroids if we have some to create
|
||||
if ((!Asteroid_field.field_asteroid_type.empty()) && (num_asteroids > 0)) {
|
||||
if ((count > 0) && (num_asteroids > 0)) {
|
||||
asteroid_create_all();
|
||||
}
|
||||
}
|
||||
|
||||
// will replace any existing asteroid or debris field with a debris field
|
||||
void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, SCP_vector<int> debris_types, vec3d o_min, vec3d o_max, bool enhanced)
|
||||
void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, int debris1, int debris2, int debris3, vec3d o_min, vec3d o_max, bool enhanced)
|
||||
{
|
||||
remove_all_asteroids();
|
||||
|
||||
@@ -780,11 +792,33 @@ void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, SCP_vec
|
||||
Asteroid_field.speed = (float)asteroid_speed;
|
||||
Asteroid_field.debris_genre = DG_DEBRIS;
|
||||
|
||||
Asteroid_field.field_debris_type.clear();
|
||||
Asteroid_field.field_debris_type[0] = -1;
|
||||
Asteroid_field.field_debris_type[1] = -1;
|
||||
Asteroid_field.field_debris_type[2] = -1;
|
||||
|
||||
Asteroid_field.field_asteroid_type.clear();
|
||||
int count = 0;
|
||||
for (int i = 0; i < MAX_ACTIVE_DEBRIS_TYPES; i++) {
|
||||
if (debris1 >= 0) {
|
||||
Asteroid_field.field_debris_type[i] = debris1;
|
||||
debris1 = -1;
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
if (debris2 >= 0) {
|
||||
Asteroid_field.field_debris_type[i] = debris2;
|
||||
debris2 = -1;
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
if (debris3 >= 0) {
|
||||
Asteroid_field.field_debris_type[i] = debris3;
|
||||
debris3 = -1;
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Asteroid_field.field_debris_type = std::move(debris_types);
|
||||
Asteroid_field.num_used_field_debris_types = count;
|
||||
|
||||
Asteroid_field.min_bound = o_min;
|
||||
Asteroid_field.max_bound = o_max;
|
||||
@@ -797,7 +831,7 @@ void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, SCP_vec
|
||||
Asteroid_field.bound_rad = MAX(3000.0f, b_rad);
|
||||
|
||||
// Only create debris if we have some to create
|
||||
if ((!Asteroid_field.field_debris_type.empty()) && (num_asteroids > 0)) {
|
||||
if ((count > 0) && (num_asteroids > 0)) {
|
||||
asteroid_create_all();
|
||||
}
|
||||
}
|
||||
@@ -816,8 +850,10 @@ void asteroid_level_init()
|
||||
Asteroid_field.has_inner_bound = false;
|
||||
Asteroid_field.field_type = FT_ACTIVE;
|
||||
Asteroid_field.debris_genre = DG_ASTEROID;
|
||||
Asteroid_field.field_debris_type.clear();
|
||||
Asteroid_field.field_asteroid_type.clear();
|
||||
Asteroid_field.field_debris_type[0] = -1;
|
||||
Asteroid_field.field_debris_type[1] = -1;
|
||||
Asteroid_field.field_debris_type[2] = -1;
|
||||
Asteroid_field.num_used_field_debris_types = 0;
|
||||
Asteroid_field.target_names.clear();
|
||||
|
||||
if (!Fred_running)
|
||||
@@ -1013,7 +1049,7 @@ bool asteroid_is_within_view(vec3d *pos, float range, bool range_override)
|
||||
*/
|
||||
static void maybe_throw_asteroid()
|
||||
{
|
||||
Assertion(!Asteroid_field.field_asteroid_type.empty(), "maybe_throw_asteroid() called while field_asteroid_type.size was 0; this should never happen, get a coder!");
|
||||
Assertion(Asteroid_field.num_used_field_debris_types > 0, "maybe_throw_asteroid() called while num_used_field_debris_types was 0; this should never happen, get a coder!");
|
||||
|
||||
for (asteroid_target& target : Asteroid_targets) {
|
||||
if (!timestamp_elapsed(target.throw_stamp))
|
||||
@@ -1031,8 +1067,18 @@ static void maybe_throw_asteroid()
|
||||
|
||||
target.throw_stamp = _timestamp(1000 + 1200 * target.incoming_asteroids / (Game_skill_level+1));
|
||||
|
||||
// get a valid subtype
|
||||
int subtype = get_asteroid_subtype_index_by_name(pick_random_asteroid_type(), ASTEROID_TYPE_LARGE);
|
||||
int counter = Random::next(Asteroid_field.num_used_field_debris_types);
|
||||
int subtype = -1;
|
||||
for (int i = 0; i < NUM_ASTEROID_POFS; i++) {
|
||||
if (Asteroid_field.field_debris_type[i] >= 0) {
|
||||
if (counter == 0) {
|
||||
subtype = i;
|
||||
break;
|
||||
}
|
||||
else
|
||||
counter--;
|
||||
}
|
||||
}
|
||||
|
||||
// this really shouldn't happen but just in case...
|
||||
if (subtype < 0)
|
||||
@@ -1209,7 +1255,7 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
|
||||
// asteroid weapon collision
|
||||
Assert( other_obj->type == OBJ_WEAPON );
|
||||
mc.model_instance_num = Asteroids[num].model_instance_num;
|
||||
mc.model_num = Asteroid_info[Asteroids[num].asteroid_type].subtypes[asteroid_subtype].model_number; // Fill in the model to check
|
||||
mc.model_num = Asteroid_info[Asteroids[num].asteroid_type].model_num[asteroid_subtype]; // Fill in the model to check
|
||||
mc.orient = &pasteroid->orient; // The object's orient
|
||||
mc.pos = &pasteroid->pos; // The object's position
|
||||
mc.p0 = &other_obj->last_pos; // Point 1 of ray to check
|
||||
@@ -1390,7 +1436,7 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
|
||||
} else {
|
||||
// Asteroid is heavier obj
|
||||
mc.model_instance_num = Asteroids[num].model_instance_num;
|
||||
mc.model_num = Asteroid_info[Asteroids[num].asteroid_type].subtypes[asteroid_subtype].model_number; // Fill in the model to check
|
||||
mc.model_num = Asteroid_info[Asteroids[num].asteroid_type].model_num[asteroid_subtype]; // Fill in the model to check
|
||||
mc.orient = &pasteroid->orient; // The object's orient
|
||||
mc.radius = model_get_core_radius(Ship_info[Ships[pship_obj->instance].ship_info_index].model_num);
|
||||
|
||||
@@ -1471,16 +1517,14 @@ void asteroid_render(object * obj, model_draw_list *scene)
|
||||
|
||||
Assert( asp->flags & AF_USED );
|
||||
|
||||
model_clear_instance( Asteroid_info[asp->asteroid_type].subtypes[asp->asteroid_subtype].model_number);
|
||||
model_clear_instance( Asteroid_info[asp->asteroid_type].model_num[asp->asteroid_subtype]);
|
||||
|
||||
model_render_params render_info;
|
||||
|
||||
render_info.set_object_number( OBJ_INDEX(obj) );
|
||||
render_info.set_flags(MR_IS_ASTEROID);
|
||||
if (asp->model_instance_num >= 0)
|
||||
render_info.set_replacement_textures(model_get_instance(asp->model_instance_num)->texture_replace);
|
||||
|
||||
model_render_queue(&render_info, scene, Asteroid_info[asp->asteroid_type].subtypes[asp->asteroid_subtype].model_number, &obj->orient, &obj->pos); // Replace MR_NORMAL with 0x07 for big yellow blobs
|
||||
model_render_queue(&render_info, scene, Asteroid_info[asp->asteroid_type].model_num[asp->asteroid_subtype], &obj->orient, &obj->pos); // Replace MR_NORMAL with 0x07 for big yellow blobs
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1549,8 +1593,9 @@ static float asteroid_create_explosion(object *objp)
|
||||
fireball_type = FIREBALL_ASTEROID;
|
||||
}
|
||||
|
||||
if (fireball_type >= static_cast<int>(Fireball_info.size())) {
|
||||
Warning(LOCATION, "Invalid fireball type %i specified for an asteroid; only " SIZE_T_ARG " fireball types are defined.", fireball_type, Fireball_info.size());
|
||||
if (fireball_type >= Num_fireball_types) {
|
||||
Warning(LOCATION, "Invalid fireball type %i specified for an asteroid, only %i fireball types are defined.", fireball_type, Num_fireball_types);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1714,10 +1759,9 @@ void asteroid_level_close()
|
||||
|
||||
//when a level is closed, all models are cleared, so let's make sure that
|
||||
//is tracked for asteroids as well -Mjn
|
||||
for (size_t i = 0; i < Asteroid_info.size(); i++) {
|
||||
for (size_t j = 0; j < Asteroid_info[i].subtypes.size(); j++) {
|
||||
Asteroid_info[i].subtypes[j].model_number = -1;
|
||||
Asteroid_info[i].subtypes[j].model_pointer = nullptr;
|
||||
for (int i = 0; i < (int)Asteroid_info.size(); i++) {
|
||||
for (int j = 0; j < NUM_ASTEROID_POFS; j++) {
|
||||
Asteroid_info[i].model_num[j] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2176,71 +2220,15 @@ static void asteroid_parse_section()
|
||||
}
|
||||
|
||||
if (optional_string("$POF file1:")) {
|
||||
asteroid_subtype_info thisType;
|
||||
|
||||
thisType.type_name = "Brown";
|
||||
|
||||
stuff_string(thisType.pof_filename, F_NAME, MAX_FILENAME_LEN);
|
||||
|
||||
thisType.model_number = -1;
|
||||
thisType.model_pointer = nullptr;
|
||||
|
||||
asteroid_p->subtypes.push_back(thisType);
|
||||
stuff_string(asteroid_p->pof_files[0], F_NAME, MAX_FILENAME_LEN);
|
||||
}
|
||||
|
||||
if (optional_string("$POF file2:")) {
|
||||
asteroid_subtype_info thisType;
|
||||
|
||||
thisType.type_name = "Blue";
|
||||
stuff_string(thisType.pof_filename, F_NAME, MAX_FILENAME_LEN);
|
||||
|
||||
thisType.model_number = -1;
|
||||
thisType.model_pointer = nullptr;
|
||||
|
||||
asteroid_p->subtypes.push_back(thisType);
|
||||
stuff_string(asteroid_p->pof_files[1], F_NAME, MAX_FILENAME_LEN);
|
||||
}
|
||||
|
||||
if (optional_string("$POF file3:")) {
|
||||
asteroid_subtype_info thisType;
|
||||
|
||||
thisType.type_name = "Orange";
|
||||
stuff_string(thisType.pof_filename, F_NAME, MAX_FILENAME_LEN);
|
||||
|
||||
thisType.model_number = -1;
|
||||
thisType.model_pointer = nullptr;
|
||||
|
||||
asteroid_p->subtypes.push_back(thisType);
|
||||
}
|
||||
|
||||
// For asteroid types we can have unlimited subtypes
|
||||
if (asteroid_p->type != ASTEROID_TYPE_DEBRIS) {
|
||||
while (optional_string("$Subtype:")) {
|
||||
asteroid_subtype_info thisType;
|
||||
|
||||
stuff_string(thisType.type_name, F_NAME);
|
||||
|
||||
required_string("+POF file:");
|
||||
stuff_string(thisType.pof_filename, F_NAME, MAX_FILENAME_LEN);
|
||||
|
||||
thisType.model_number = -1;
|
||||
thisType.model_pointer = nullptr;
|
||||
|
||||
bool exists = false;
|
||||
for (const auto& type : asteroid_p->subtypes) {
|
||||
if (type.type_name == thisType.type_name) {
|
||||
exists = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (exists) {
|
||||
error_display(0,
|
||||
"Asteroid subtype %s already exists for asteroid %s",
|
||||
thisType.type_name.c_str(),
|
||||
asteroid_p->name);
|
||||
} else {
|
||||
asteroid_p->subtypes.push_back(thisType);
|
||||
}
|
||||
}
|
||||
stuff_string(asteroid_p->pof_files[2], F_NAME, MAX_FILENAME_LEN);
|
||||
}
|
||||
|
||||
if (optional_string("$Detail distance:")) {
|
||||
@@ -2263,7 +2251,10 @@ static void asteroid_parse_section()
|
||||
}
|
||||
|
||||
if(optional_string("$Explosion Animations:")){
|
||||
stuff_fireball_index_list(asteroid_p->explosion_bitmap_anims, asteroid_p->name);
|
||||
int temp[MAX_FIREBALL_TYPES];
|
||||
auto parsed_ints = stuff_int_list(temp, MAX_FIREBALL_TYPES, RAW_INTEGER_TYPE);
|
||||
asteroid_p->explosion_bitmap_anims.clear();
|
||||
asteroid_p->explosion_bitmap_anims.insert(asteroid_p->explosion_bitmap_anims.begin(), temp, temp + parsed_ints);
|
||||
}
|
||||
|
||||
if (optional_string("$Explosion Radius Mult:")) {
|
||||
@@ -2429,7 +2420,7 @@ static void asteroid_parse_tbl(const char* filename)
|
||||
// Gets the index of an asteroid by name from Asteroid_info
|
||||
int get_asteroid_index(const char* asteroid_name)
|
||||
{
|
||||
for (int i = 0; i < static_cast<int>(Asteroid_info.size()); i++) {
|
||||
for (int i = 0; i < (int)Asteroid_info.size(); i++) {
|
||||
if (!stricmp(asteroid_name, Asteroid_info[i].name)) {
|
||||
return i;
|
||||
}
|
||||
@@ -2438,31 +2429,6 @@ int get_asteroid_index(const char* asteroid_name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// For FRED. Gets a list of unique asteroid subtype names
|
||||
SCP_vector<SCP_string> get_list_valid_asteroid_subtypes()
|
||||
{
|
||||
SCP_vector<SCP_string> list;
|
||||
|
||||
for (const auto& this_asteroid : Asteroid_info) {
|
||||
if (this_asteroid.type != ASTEROID_TYPE_DEBRIS) {
|
||||
for (const auto& subtype : this_asteroid.subtypes) {
|
||||
bool exists = false;
|
||||
for (const auto& entry : list) {
|
||||
if (subtype.type_name == entry) {
|
||||
exists = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!exists) {
|
||||
list.push_back(subtype.type_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static void verify_asteroid_splits()
|
||||
{
|
||||
|
||||
@@ -2521,14 +2487,7 @@ static void verify_asteroid_list()
|
||||
|
||||
}
|
||||
|
||||
// Rest should be debris type
|
||||
for (int i = 0; i < (int)asteroid_list.size(); i++) {
|
||||
|
||||
// Remove all subtypes except the first one
|
||||
asteroid_list[i].subtypes.resize(1);
|
||||
// Make sure the first subtype is set as debris
|
||||
asteroid_list[i].subtypes[0].type_name = "Debris";
|
||||
|
||||
if (asteroid_list[i].type < 0) {
|
||||
Asteroid_info.push_back(asteroid_list[i]);
|
||||
} else {
|
||||
@@ -2542,8 +2501,14 @@ static void verify_asteroid_list()
|
||||
|
||||
//Check that we have the appropriate POF files-Mjn
|
||||
for (int i = 0; i < (int)Asteroid_info.size(); i++) {
|
||||
if (Asteroid_info[i].subtypes.size() == 0) {
|
||||
Error(LOCATION, "Asteroid %s needs at least one subtype!", Asteroid_info[i].name);
|
||||
if (Asteroid_info[i].pof_files[0][0] == '\0')
|
||||
Error(LOCATION, "Missing [POF File 1] for %s", Asteroid_info[i].name);
|
||||
|
||||
if (Asteroid_info[i].type != ASTEROID_TYPE_DEBRIS) {
|
||||
if (Asteroid_info[i].pof_files[1][0] == '\0')
|
||||
Error(LOCATION, "Missing [POF File 2] for %s", Asteroid_info[i].name);
|
||||
if (Asteroid_info[i].pof_files[2][0] == '\0')
|
||||
Error(LOCATION, "Missing [POF File 3] for %s", Asteroid_info[i].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2580,7 +2545,7 @@ void asteroid_init()
|
||||
}
|
||||
|
||||
if (Asteroid_icon_closeup_model[0] == '\0')
|
||||
strcpy_s(Asteroid_icon_closeup_model, Asteroid_info[ASTEROID_TYPE_LARGE].subtypes[0].pof_filename); // magic file from retail
|
||||
strcpy_s(Asteroid_icon_closeup_model, Asteroid_info[ASTEROID_TYPE_LARGE].pof_files[0]); // magic file from retail
|
||||
|
||||
}
|
||||
|
||||
@@ -2621,7 +2586,7 @@ void asteroid_frame()
|
||||
}
|
||||
|
||||
// If no asteroid types are defined for the field, abort.
|
||||
if (Asteroid_field.field_asteroid_type.empty()) {
|
||||
if (Asteroid_field.num_used_field_debris_types <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2733,26 +2698,21 @@ void asteroid_page_in()
|
||||
return;
|
||||
|
||||
if (Asteroid_field.num_initial_asteroids > 0 ) {
|
||||
int i, j, k;
|
||||
|
||||
nprintf(( "Paging", "Paging in asteroids\n" ));
|
||||
|
||||
size_t num_debris_types = NUM_ASTEROID_SIZES;
|
||||
if (Asteroid_field.debris_genre == DG_DEBRIS) {
|
||||
num_debris_types = Asteroid_field.field_debris_type.size();
|
||||
}
|
||||
|
||||
|
||||
// for asteroids this will loop over all three possible sizes
|
||||
// for debris this will loop over all selected types
|
||||
for (size_t i = 0; i < num_debris_types; i++) {
|
||||
// max of MAX_ACTIVE_DEBRIS_TYPES possible debris field models
|
||||
for (i=0; i<MAX_ACTIVE_DEBRIS_TYPES; i++) {
|
||||
asteroid_info *asip;
|
||||
|
||||
if (Asteroid_field.debris_genre == DG_ASTEROID) {
|
||||
// asteroid
|
||||
Assertion(i < NUM_ASTEROID_SIZES, "Got invalid call to load non-existent asteroid size!");
|
||||
Assertion(i < NUM_ASTEROID_SIZES, "Got invalid call to load a debris type instead of asteroid type!");
|
||||
asip = &Asteroid_info[i];
|
||||
} else {
|
||||
// debris - always full until empty
|
||||
// ship debris - always full until empty
|
||||
if (Asteroid_field.field_debris_type[i] != -1) {
|
||||
asip = &Asteroid_info[Asteroid_field.field_debris_type[i]];
|
||||
} else {
|
||||
@@ -2761,36 +2721,28 @@ void asteroid_page_in()
|
||||
}
|
||||
|
||||
|
||||
for (size_t k = 0; k < asip->subtypes.size(); k++) {
|
||||
for (k=0; k<NUM_ASTEROID_POFS; k++) {
|
||||
|
||||
// DEBRIS FIELDS - always use subtype 0
|
||||
// SHIP DEBRIS - use subtype 0
|
||||
if (Asteroid_field.debris_genre == DG_DEBRIS) {
|
||||
if (k > 0) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// ASTEROID FIELDS - use subtype k, if active
|
||||
bool active = false;
|
||||
for (const auto& active_type : Asteroid_field.field_asteroid_type) {
|
||||
if (active_type == asip->subtypes[k].type_name) {
|
||||
active = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!active) {
|
||||
// ASTEROID DEBRIS - use subtype (Asteroid_field.field_debris_type[] != -1)
|
||||
if (Asteroid_field.field_debris_type[k] == -1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// model is already paged in
|
||||
if (asip->subtypes[k].model_number < 0)
|
||||
if (asip->model_num[k] < 0)
|
||||
continue;
|
||||
|
||||
asip->subtypes[k].model_pointer = model_get(asip->subtypes[k].model_number);
|
||||
asip->modelp[k] = model_get(asip->model_num[k]);
|
||||
|
||||
// Page in textures
|
||||
for (int j = 0; j < asip->subtypes[k].model_pointer->n_textures; j++ ) {
|
||||
asip->subtypes[k].model_pointer->maps[j].PageIn();
|
||||
for (j=0; j<asip->modelp[k]->n_textures; j++ ) {
|
||||
asip->modelp[k]->maps[j].PageIn();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+20
-19
@@ -24,14 +24,15 @@ class model_draw_list;
|
||||
#define MAX_ASTEROIDS 2000 //Increased from 512 to 2000 in 2022
|
||||
|
||||
#define NUM_ASTEROID_SIZES 3
|
||||
#define NUM_ASTEROID_POFS 3 // Number of POFs per debris size
|
||||
|
||||
#define ASTEROID_TYPE_DEBRIS -1
|
||||
#define ASTEROID_TYPE_SMALL 0
|
||||
#define ASTEROID_TYPE_MEDIUM 1
|
||||
#define ASTEROID_TYPE_LARGE 2
|
||||
|
||||
// Only used for parsing & saving retail compatible mission files
|
||||
#define MAX_RETAIL_DEBRIS_TYPES 3
|
||||
// these should always be equal for the benefit of generic asteroids (c.f. asteroid_page_in)
|
||||
#define MAX_ACTIVE_DEBRIS_TYPES NUM_ASTEROID_SIZES
|
||||
|
||||
// Goober5000 - currently same as MAX_SHIP_DETAIL_LEVELS (put here to avoid an #include)
|
||||
#define MAX_ASTEROID_DETAIL_LEVELS 5
|
||||
@@ -53,20 +54,13 @@ typedef struct asteroid_split_info {
|
||||
int max; //maximum asteroids to spawn
|
||||
} asteroid_split_info;
|
||||
|
||||
// Data structure for storing asteroid subtype info. POFs, model pointer, model num, etc.
|
||||
typedef struct asteroid_subtype_info {
|
||||
char pof_filename[MAX_FILENAME_LEN];
|
||||
polymodel* model_pointer;
|
||||
int model_number;
|
||||
SCP_string type_name;
|
||||
} asteroid_subtype_info;
|
||||
|
||||
class asteroid_info
|
||||
{
|
||||
public:
|
||||
char name[NAME_LENGTH]; // name for the asteroid
|
||||
int type; // type of asteroid, 0 = small, 1 = medium, 2 = large, -1 = debris
|
||||
int num_detail_levels; // number of detail levels for this asteroid
|
||||
char pof_files[NUM_ASTEROID_POFS][MAX_FILENAME_LEN]; // POF files to load/associate with ship
|
||||
int num_detail_levels; // number of detail levels for this ship
|
||||
int detail_distance[MAX_ASTEROID_DETAIL_LEVELS]; // distance to change detail levels at
|
||||
float max_speed; // cap on speed for asteroid
|
||||
float rotational_vel_multiplier; // rotational velocity multiplier for asteroid --wookieejedi
|
||||
@@ -78,12 +72,13 @@ public:
|
||||
float blast; // maximum blast impulse from area effect explosion
|
||||
float initial_asteroid_strength; // starting strength of asteroid
|
||||
SCP_vector< asteroid_split_info > split_info;
|
||||
polymodel *modelp[NUM_ASTEROID_POFS];
|
||||
int model_num[NUM_ASTEROID_POFS];
|
||||
SCP_vector<int> explosion_bitmap_anims;
|
||||
float fireball_radius_multiplier; // the model radius is multiplied by this to determine the fireball size
|
||||
SCP_string display_name; // only used for hud targeting display and for debris
|
||||
float spawn_weight; // debris only, relative proportion to spawn compared to other types in its asteroid field
|
||||
SCP_string display_name; // only used for hud targeting display and for 'ship' asteroids
|
||||
float spawn_weight; // ship asteroids only, relative proportion to spawn compared to other types in its asteroid field
|
||||
float gravity_const; // multiplier for mission gravity
|
||||
SCP_vector<asteroid_subtype_info> subtypes;
|
||||
|
||||
asteroid_info( )
|
||||
: type(ASTEROID_TYPE_DEBRIS), num_detail_levels(0), max_speed(0),
|
||||
@@ -95,6 +90,13 @@ public:
|
||||
name[ 0 ] = 0;
|
||||
display_name = "";
|
||||
memset( detail_distance, 0, sizeof( detail_distance ) );
|
||||
|
||||
for (int i = 0; i < NUM_ASTEROID_POFS; i++)
|
||||
{
|
||||
modelp[i] = NULL;
|
||||
model_num[i] = -1;
|
||||
pof_files[i][0] = '\0';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -141,8 +143,8 @@ typedef struct asteroid_field {
|
||||
int num_initial_asteroids; // Number of asteroids at creation.
|
||||
field_type_t field_type; // active throws and wraps, passive does not
|
||||
debris_genre_t debris_genre; // type of debris (ship or asteroid) [generic type]
|
||||
SCP_vector<int> field_debris_type; // one of the debris type defines above
|
||||
SCP_vector<SCP_string> field_asteroid_type; // one of the asteroid subtypes
|
||||
int field_debris_type[MAX_ACTIVE_DEBRIS_TYPES]; // one of the debris type defines above
|
||||
int num_used_field_debris_types; // how many of the above are used
|
||||
bool enhanced_visibility_checks; // if true then range checks are overridden for spawning and wrapping asteroids in the field
|
||||
|
||||
SCP_vector<SCP_string> target_names; // default retail behavior is to just throw at the first big ship in the field
|
||||
@@ -163,8 +165,8 @@ bool asteroid_is_within_view(vec3d *pos, float range, bool range_override = f
|
||||
void asteroid_level_init();
|
||||
void asteroid_level_close();
|
||||
void asteroid_create_all();
|
||||
void asteroid_create_asteroid_field(int num_asteroids, int field_type, int asteroid_speed, vec3d o_min, vec3d o_max, bool inner_box, vec3d i_min, vec3d i_max, SCP_vector<SCP_string> asteroid_types);
|
||||
void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, SCP_vector<int> debris_types, vec3d o_min, vec3d o_max, bool enhanced);
|
||||
void asteroid_create_asteroid_field(int num_asteroids, int field_type, int asteroid_speed, bool brown, bool blue, bool orange, vec3d o_min, vec3d o_max, bool inner_box, vec3d i_min, vec3d i_max, SCP_vector<SCP_string> targets);
|
||||
void asteroid_create_debris_field(int num_asteroids, int asteroid_speed, int debris1, int debris2, int debris3, vec3d o_min, vec3d o_max, bool enhanced);
|
||||
void asteroid_render(object* obj, model_draw_list* scene);
|
||||
void asteroid_delete( object *asteroid_objp );
|
||||
void asteroid_process_pre( object *asteroid_objp );
|
||||
@@ -178,7 +180,6 @@ void asteroid_show_brackets();
|
||||
void asteroid_target_closest_danger();
|
||||
void asteroid_add_target(object* objp);
|
||||
int get_asteroid_index(const char* asteroid_name);
|
||||
SCP_vector<SCP_string> get_list_valid_asteroid_subtypes();
|
||||
|
||||
// need to extern for keycontrol debug commands
|
||||
object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int asteroid_subtype, bool check_visibility = false);
|
||||
|
||||
@@ -1027,6 +1027,10 @@ int bm_is_compressed(int num) {
|
||||
auto entry = bm_get_entry(num);
|
||||
BM_TYPE type = BM_TYPE_NONE;
|
||||
|
||||
//duh
|
||||
if (!Use_compressed_textures)
|
||||
return 0;
|
||||
|
||||
type = entry->comp_type;
|
||||
|
||||
switch (type) {
|
||||
|
||||
+14
-8
@@ -364,7 +364,10 @@ void camera::do_frame(float /*in_frametime*/)
|
||||
|
||||
object *camera::get_object_host()
|
||||
{
|
||||
return object_host.objp_or_null();
|
||||
if(object_host.isValid())
|
||||
return object_host.objp;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int camera::get_object_host_submodel()
|
||||
@@ -374,7 +377,10 @@ int camera::get_object_host_submodel()
|
||||
|
||||
object *camera::get_object_target()
|
||||
{
|
||||
return object_target.objp_or_null();
|
||||
if(object_target.isValid())
|
||||
return object_target.objp;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int camera::get_object_target_submodel()
|
||||
@@ -418,7 +424,7 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
|
||||
|
||||
if(object_host.isValid())
|
||||
{
|
||||
object *objp = object_host.objp();
|
||||
object *objp = object_host.objp;
|
||||
int model_num = object_get_model(objp);
|
||||
polymodel *pm = nullptr;
|
||||
polymodel_instance *pmi = nullptr;
|
||||
@@ -432,8 +438,8 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
|
||||
|
||||
if(object_host_submodel < 0 || pm == NULL)
|
||||
{
|
||||
vm_vec_unrotate(&c_pos, &pt, &object_host.objp()->orient);
|
||||
vm_vec_add2(&c_pos, &object_host.objp()->pos);
|
||||
vm_vec_unrotate(&c_pos, &pt, &object_host.objp->orient);
|
||||
vm_vec_add2(&c_pos, &object_host.objp->pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -482,7 +488,7 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
|
||||
{
|
||||
if(object_target.isValid())
|
||||
{
|
||||
object *target_objp = object_target.objp();
|
||||
object *target_objp = object_target.objp;
|
||||
int model_num = object_get_model(target_objp);
|
||||
polymodel *target_pm = nullptr;
|
||||
polymodel_instance *target_pmi = nullptr;
|
||||
@@ -519,7 +525,7 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
|
||||
{
|
||||
if(eyep)
|
||||
{
|
||||
vm_vector_2_matrix(&c_ori, &host_normal, vm_vec_same(&host_normal, &object_host.objp()->orient.vec.uvec)?NULL:&object_host.objp()->orient.vec.uvec, NULL);
|
||||
vm_vector_2_matrix(&c_ori, &host_normal, vm_vec_same(&host_normal, &object_host.objp->orient.vec.uvec)?NULL:&object_host.objp->orient.vec.uvec, NULL);
|
||||
target_set = true;
|
||||
}
|
||||
else if (use_host_orient)
|
||||
@@ -528,7 +534,7 @@ void camera::get_info(vec3d *position, matrix *orientation, bool apply_camera_or
|
||||
}
|
||||
else
|
||||
{
|
||||
c_ori = object_host.objp()->orient;
|
||||
c_ori = object_host.objp->orient;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -377,7 +377,6 @@ struct CFileLocation {
|
||||
SCP_string full_name;
|
||||
size_t size = 0;
|
||||
size_t offset = 0;
|
||||
time_t m_time = 0;
|
||||
const void* data_ptr = nullptr;
|
||||
|
||||
explicit CFileLocation(bool found_in = false) : found(found_in) {}
|
||||
|
||||
@@ -595,7 +595,7 @@ static void cf_add_mod_roots(const char* rootDirectory, uint32_t basic_location)
|
||||
|
||||
cf_root* root = cf_create_root();
|
||||
|
||||
root->path = std::move(rootPath);
|
||||
root->path = rootPath;
|
||||
if (primary) {
|
||||
root->location_flags = basic_location | CF_LOCATION_TYPE_PRIMARY_MOD;
|
||||
} else {
|
||||
@@ -826,8 +826,7 @@ static void check_file_shadows(const int root_index __UNUSED, const int pathtype
|
||||
}
|
||||
|
||||
// this log message occurs in the middle of an existing line, hence the extra new lines
|
||||
// critical files and files in same root are always logged, files in different root are behind a filter
|
||||
nprintf(((critical || !root->path.compare(r->path)) ? "General" : "CFileSystem", "\nWARNING! A %sfile being indexed may be shadowed by an existing file!\n New:\n %s\n Existing:\n %s\n",
|
||||
mprintf(("\nWARNING! A %sfile being indexed may be shadowed by an existing file!\n New:\n %s\n Existing:\n %s\n",
|
||||
critical ? "critical " : "",
|
||||
newfile.c_str(), curfile.c_str()));
|
||||
|
||||
@@ -1237,22 +1236,6 @@ static bool sub_path_match(const SCP_string &search, const SCP_string &index)
|
||||
return !stricmp(search.c_str(), index.c_str());
|
||||
}
|
||||
|
||||
static time_t get_mtime(int fd)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
struct _stat buf;
|
||||
#define fstat _fstat
|
||||
#else
|
||||
struct stat buf;
|
||||
#endif
|
||||
|
||||
if (fstat(fd, &buf) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return buf.st_mtime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a file.
|
||||
*
|
||||
@@ -1287,7 +1270,6 @@ CFileLocation cf_find_file_location(const char* filespec, int pathtype, uint32_t
|
||||
if (fp) {
|
||||
CFileLocation res(true);
|
||||
res.size = static_cast<size_t>(filelength(fileno(fp)));
|
||||
res.m_time = get_mtime(fileno(fp));
|
||||
|
||||
fclose(fp);
|
||||
|
||||
@@ -1350,7 +1332,6 @@ CFileLocation cf_find_file_location(const char* filespec, int pathtype, uint32_t
|
||||
if (fp) {
|
||||
CFileLocation res(true);
|
||||
res.size = static_cast<size_t>(filelength( fileno(fp) ));
|
||||
res.m_time = get_mtime(fileno(fp));
|
||||
|
||||
fclose(fp);
|
||||
|
||||
@@ -1407,7 +1388,6 @@ CFileLocation cf_find_file_location(const char* filespec, int pathtype, uint32_t
|
||||
res.offset = (size_t)f->pack_offset;
|
||||
res.data_ptr = f->data;
|
||||
res.name_ext = f->name_ext;
|
||||
res.m_time = f->write_time;
|
||||
|
||||
if (f->data != nullptr) {
|
||||
// This is an in-memory file so we just copy the pathtype name + file name
|
||||
@@ -1543,7 +1523,6 @@ CFileLocationExt cf_find_file_location_ext(const char *filename, const int ext_n
|
||||
CFileLocationExt res(cur_ext);
|
||||
res.found = true;
|
||||
res.size = static_cast<size_t>(filelength( fileno(fp) ));
|
||||
res.m_time = get_mtime(fileno(fp));
|
||||
|
||||
fclose(fp);
|
||||
|
||||
@@ -1632,7 +1611,6 @@ CFileLocationExt cf_find_file_location_ext(const char *filename, const int ext_n
|
||||
res.offset = (size_t)f->pack_offset;
|
||||
res.data_ptr = f->data;
|
||||
res.name_ext = f->name_ext;
|
||||
res.m_time = f->write_time;
|
||||
|
||||
if (f->data != nullptr) {
|
||||
// This is an in-memory file so we just copy the pathtype name + file name
|
||||
|
||||
+50
-23
@@ -165,9 +165,11 @@ Flag exe_params[] =
|
||||
{ "-nonormal", "Disable normal maps", true, EASY_DEFAULT | EASY_HI_MEM_OFF, EASY_ALL_ON | EASY_HI_MEM_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nonormal" },
|
||||
{ "-emissive_light", "Enable emissive light from ships", true, 0, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-emissive_light" },
|
||||
{ "-noheight", "Disable height/parallax maps", true, EASY_DEFAULT | EASY_HI_MEM_OFF, EASY_ALL_ON | EASY_HI_MEM_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noheight" },
|
||||
{ "-3dshockwave", "Enable 3D shockwaves", true, EASY_ALL_ON | EASY_HI_MEM_ON, EASY_DEFAULT | EASY_HI_MEM_OFF, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-3dshockwave" },
|
||||
{ "-no_post_process", "Disable post-processing", true, EASY_DEFAULT | EASY_HI_MEM_OFF, EASY_ALL_ON | EASY_HI_MEM_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_post_process" },
|
||||
{ "-soft_particles", "Enable soft particles", true, EASY_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-soft_particles" },
|
||||
{ "-aa", "Enable Post-process anti-aliasing", true, EASY_ALL_ON | EASY_HI_MEM_ON, EASY_DEFAULT | EASY_HI_MEM_OFF, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-aa" },
|
||||
{ "-nolightshafts", "Disable lightshafts", true, EASY_DEFAULT | EASY_HI_MEM_OFF, EASY_ALL_ON | EASY_HI_MEM_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nolightshafts"},
|
||||
{ "-fb_explosions", "Enable Framebuffer Shockwaves", true, EASY_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fb_explosions", },
|
||||
{ "-fb_thrusters", "Enable Framebuffer Thrusters", true, EASY_ALL_ON, EASY_DEFAULT, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fb_thrusters", },
|
||||
{ "-no_deferred", "Disable Deferred Lighting", true, EASY_DEFAULT | EASY_HI_MEM_OFF, EASY_ALL_ON | EASY_HI_MEM_ON, "Graphics", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_deferred"},
|
||||
@@ -191,10 +193,13 @@ Flag exe_params[] =
|
||||
{ "-capture_mouse", "Capture the mouse within the window", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-capture_mouse", },
|
||||
{ "-stretch_menu", "Stretch interface to fill screen", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-stretch_menu", },
|
||||
{ "-noscalevid", "Disable scale-to-window for movies", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-noscalevid", },
|
||||
{ "-nomotiondebris", "Disable motion debris", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nomotiondebris",},
|
||||
{ "-3dwarp", "Enable 3D warp", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-3dwarp", },
|
||||
{ "-warp_flash", "Enable flash upon warp", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-warp_flash", },
|
||||
{ "-no_ap_interrupt", "Disable interrupting autopilot", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_ap_interrupt", },
|
||||
{ "-no_screenshake", "Disable screen shaking", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_screenshake", },
|
||||
{ "-vr", "Enable Virtual Reality Mode", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-vr", },
|
||||
{ "-no_unfocused_pause","Don't pause if the window isn't focused", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_unfocused_pause", },
|
||||
{ "-orig_speedx_range", "Restrict speedup/slowdown (1x to 4x)", true, 0, EASY_DEFAULT, "Gameplay", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-orig_speedx_range", },
|
||||
|
||||
//flag launcher text FSO on_flags off_flags category reference URL
|
||||
{ "-nosound", "Disable all sound", false, 0, EASY_DEFAULT, "Audio", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-nosound", },
|
||||
@@ -237,8 +242,6 @@ Flag exe_params[] =
|
||||
{ "-prefer_ipv6", "Prefer IPv6 DNS lookups", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-prefer_ipv6", },
|
||||
{ "-log_multi_packet", "Log multi packet types ", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-log_multi_packet",},
|
||||
{ "-no_bsp_align", "Disable pof BSP data alignment", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_bsp_align", },
|
||||
{ "-no_large_shaders", "Split large shader into smaller shaders", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-no_large_shaders", },
|
||||
|
||||
#ifdef WIN32
|
||||
{ "-fix_registry", "Use a different registry path", true, 0, EASY_DEFAULT, "Troubleshoot", "http://www.hard-light.net/wiki/index.php/Command-Line_Reference#-fix_registry", },
|
||||
#endif
|
||||
@@ -339,12 +342,15 @@ cmdline_parm emissive_power_arg("-emissive", "Multiplies the brightness of all a
|
||||
cmdline_parm emissive_arg("-emissive_light", "Enable emissive light from ships", AT_NONE); // semi-deprecated but still functional
|
||||
cmdline_parm env("-noenv", NULL, AT_NONE); // Cmdline_env
|
||||
cmdline_parm glow_arg("-noglow", NULL, AT_NONE); // Cmdline_glow -- use Bobs glow code
|
||||
cmdline_parm nomotiondebris_arg("-nomotiondebris", NULL, AT_NONE); // Cmdline_nomotiondebris -- Removes those ugly floating rocks -C
|
||||
cmdline_parm noscalevid_arg("-noscalevid", NULL, AT_NONE); // Cmdline_noscalevid -- disable video scaling that fits to window
|
||||
cmdline_parm spec_arg("-nospec", NULL, AT_NONE); // Cmdline_spec --
|
||||
cmdline_parm normal_arg("-nonormal", NULL, AT_NONE); // Cmdline_normal -- disable normal mapping
|
||||
cmdline_parm height_arg("-noheight", NULL, AT_NONE); // Cmdline_height -- enable support for parallax mapping
|
||||
cmdline_parm enable_3d_shockwave_arg("-3dshockwave", NULL, AT_NONE);
|
||||
cmdline_parm softparticles_arg("-soft_particles", NULL, AT_NONE);
|
||||
cmdline_parm no_postprocess_arg("-no_post_process", "Disables post-processing", AT_NONE);
|
||||
cmdline_parm bloom_intensity_arg("-bloom_intensity", "Set bloom intensity, requires post-processing", AT_INT);
|
||||
cmdline_parm post_process_aa_arg("-aa", "Enables post-process antialiasing", AT_NONE);
|
||||
cmdline_parm post_process_aa_preset_arg("-aa_preset", "Sets the AA effect to use. See the wiki for details", AT_INT);
|
||||
cmdline_parm deprecated_fxaa_arg("-fxaa", nullptr, AT_NONE);
|
||||
@@ -354,6 +360,7 @@ cmdline_parm deprecated_smaa_preset_arg("-smaa_preset", "SMAA quality (0-3), req
|
||||
cmdline_parm msaa_enabled_arg("-msaa", nullptr, AT_INT);
|
||||
cmdline_parm fb_explosions_arg("-fb_explosions", NULL, AT_NONE);
|
||||
cmdline_parm fb_thrusters_arg("-fb_thrusters", NULL, AT_NONE);
|
||||
cmdline_parm flightshaftsoff_arg("-nolightshafts", NULL, AT_NONE);
|
||||
cmdline_parm shadow_quality_arg("-shadow_quality", NULL, AT_INT);
|
||||
cmdline_parm enable_shadows_arg("-enable_shadows", NULL, AT_NONE);
|
||||
cmdline_parm no_deferred_lighting_arg("-no_deferred", NULL, AT_NONE); // Cmdline_no_deferred
|
||||
@@ -371,7 +378,10 @@ int Cmdline_spec = 1;
|
||||
int Cmdline_emissive = 0;
|
||||
int Cmdline_normal = 1;
|
||||
int Cmdline_height = 1;
|
||||
int Cmdline_enable_3d_shockwave = 0;
|
||||
int Cmdline_softparticles = 0;
|
||||
int Cmdline_bloom_intensity = 25;
|
||||
bool Cmdline_force_lightshaft_off = false;
|
||||
int Cmdline_no_deferred_lighting = 0;
|
||||
bool Cmdline_deferred_lighting_cockpit = false;
|
||||
int Cmdline_aniso_level = 0;
|
||||
@@ -397,16 +407,22 @@ int Cmdline_orb_radar = 0;
|
||||
int Cmdline_rearm_timer = 0;
|
||||
|
||||
// Gameplay related
|
||||
cmdline_parm use_3dwarp("-3dwarp", nullptr, AT_NONE); // Is now Fireball_use_3d_warp
|
||||
cmdline_parm use_warp_flash("-warp_flash", nullptr, AT_NONE); // Cmdline_warp_flash
|
||||
cmdline_parm allow_autpilot_interrupt("-no_ap_interrupt", nullptr, AT_NONE);
|
||||
cmdline_parm stretch_menu("-stretch_menu", nullptr, AT_NONE); // Cmdline_stretch_menu
|
||||
cmdline_parm capture_mouse("-capture_mouse", nullptr, AT_NONE); // Cmdline_capture_mouse
|
||||
cmdline_parm no_screenshake("-no_screenshake", nullptr, AT_NONE); // Cmdline_no_screenshake
|
||||
cmdline_parm vr("-vr", nullptr, AT_NONE);
|
||||
cmdline_parm deadzone("-deadzone",
|
||||
"Sets the joystick deadzone. Integer value from 0 to 100 as a percentage of the joystick's range (100% would make the stick do nothing). Disables deadzone slider in the in-game Options menu.", AT_INT); //Cmdline_deadzone
|
||||
|
||||
int Cmdline_ship_choice_3d = 0;
|
||||
int Cmdline_weapon_choice_3d = 0;
|
||||
int Cmdline_autopilot_interruptable = 1;
|
||||
int Cmdline_stretch_menu = 0;
|
||||
bool Cmdline_capture_mouse = false;
|
||||
int Cmdline_no_screenshake = 0;
|
||||
int Cmdline_deadzone = -1;
|
||||
bool Cmdline_enable_vr = false;
|
||||
|
||||
@@ -463,7 +479,6 @@ cmdline_parm prefer_ipv4_arg("-prefer_ipv4", nullptr, AT_NONE);
|
||||
cmdline_parm prefer_ipv6_arg("-prefer_ipv6", nullptr, AT_NONE);
|
||||
cmdline_parm log_multi_packet_arg("-log_multi_packet", nullptr, AT_NONE);
|
||||
cmdline_parm no_bsp_align_arg("-no_bsp_align", nullptr, AT_NONE);
|
||||
cmdline_parm no_large_shaders("-no_large_shaders", NULL, AT_NONE);
|
||||
#ifdef WIN32
|
||||
cmdline_parm fix_registry("-fix_registry", NULL, AT_NONE);
|
||||
#endif
|
||||
@@ -487,7 +502,6 @@ bool Cmdline_prefer_ipv4 = false;
|
||||
bool Cmdline_prefer_ipv6 = false;
|
||||
bool Cmdline_dump_packet_type = false;
|
||||
bool Cmdline_no_bsp_align = false;
|
||||
bool Cmdline_no_large_shaders = false;
|
||||
#ifdef WIN32
|
||||
bool Cmdline_alternate_registry_path = false;
|
||||
#endif
|
||||
@@ -516,7 +530,6 @@ cmdline_parm parse_cmdline_only(PARSE_COMMAND_LINE_STRING, "Ignore any cmdline_f
|
||||
cmdline_parm reparse_mainhall_arg("-reparse_mainhall", NULL, AT_NONE); //Cmdline_reparse_mainhall
|
||||
cmdline_parm frame_profile_write_file("-profile_write_file", NULL, AT_NONE); // Cmdline_profile_write_file
|
||||
cmdline_parm no_unfocused_pause_arg("-no_unfocused_pause", NULL, AT_NONE); //Cmdline_no_unfocus_pause
|
||||
cmdline_parm retail_time_compression_range_arg("-orig_speedx_range", NULL, AT_NONE); //Cmdline_retail_time_compression_range
|
||||
cmdline_parm benchmark_mode_arg("-benchmark_mode", NULL, AT_NONE); //Cmdline_benchmark_mode
|
||||
cmdline_parm pilot_arg("-pilot", nullptr, AT_STRING); //Cmdline_pilot
|
||||
cmdline_parm noninteractive_arg("-noninteractive", NULL, AT_NONE); //Cmdline_noninteractive
|
||||
@@ -555,7 +568,6 @@ int Cmdline_verify_vps = 0;
|
||||
int Cmdline_reparse_mainhall = 0;
|
||||
bool Cmdline_profile_write_file = false;
|
||||
bool Cmdline_no_unfocus_pause = false;
|
||||
bool Cmdline_retail_time_compression_range = false;
|
||||
bool Cmdline_benchmark_mode = false;
|
||||
const char *Cmdline_pilot = nullptr;
|
||||
bool Cmdline_noninteractive = false;
|
||||
@@ -598,13 +610,6 @@ cmdline_parm deprecated_spec_tube_arg("-spec_tube", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_ambient_factor_arg("-ambient_factor", "Deprecated", AT_NONE); //
|
||||
cmdline_parm deprecated_ship_choice_3d_arg("-ship_choice_3d", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_weapon_choice_3d_arg("-weapon_choice_3d", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_no_screenshake("-no_screenshake", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_bloom_intensity_arg("-bloom_intensity", "Deprecated", AT_INT);
|
||||
cmdline_parm deprecated_nomotiondebris_arg("-nomotiondebris", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_flightshaftsoff_arg("-nolightshafts", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_use_warp_flash("-warp_flash", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_use_3dwarp("-3dwarp", "Deprecated", AT_NONE);
|
||||
cmdline_parm deprecated_enable_3d_shockwave_arg("-3dshockwave", "Deprecated", AT_NONE);
|
||||
|
||||
#ifndef NDEBUG
|
||||
// NOTE: this assumes that os_init() has already been called but isn't a fatal error if it hasn't
|
||||
@@ -1878,6 +1883,10 @@ bool SetCmdlineParams()
|
||||
Cmdline_show_pos = 1;
|
||||
}
|
||||
|
||||
if ( nomotiondebris_arg.found() ) {
|
||||
Motion_debris_enabled = false;
|
||||
}
|
||||
|
||||
if( mipmap_arg.found() ) {
|
||||
Cmdline_mipmap = 1;
|
||||
}
|
||||
@@ -1918,9 +1927,21 @@ bool SetCmdlineParams()
|
||||
Cmdline_orb_radar = 1;
|
||||
}
|
||||
|
||||
if ( use_3dwarp.found() ) {
|
||||
Fireball_use_3d_warp = true;
|
||||
}
|
||||
|
||||
if ( use_warp_flash.found() ) {
|
||||
Fireball_warp_flash = true;
|
||||
}
|
||||
|
||||
if ( allow_autpilot_interrupt.found() ) {
|
||||
Cmdline_autopilot_interruptable = 0;
|
||||
}
|
||||
|
||||
if ( no_screenshake.found() ) {
|
||||
Cmdline_no_screenshake = 1;
|
||||
}
|
||||
|
||||
if ( deadzone.found() ) {
|
||||
Cmdline_deadzone = deadzone.get_int();
|
||||
@@ -2094,10 +2115,6 @@ bool SetCmdlineParams()
|
||||
if (no_bsp_align_arg.found()) {
|
||||
Cmdline_no_bsp_align = true;
|
||||
}
|
||||
|
||||
if (no_large_shaders.found()) {
|
||||
Cmdline_no_large_shaders = true;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
if (fix_registry.found()) {
|
||||
@@ -2140,6 +2157,11 @@ bool SetCmdlineParams()
|
||||
Cmdline_ati_color_swap = 1;
|
||||
}
|
||||
|
||||
if ( enable_3d_shockwave_arg.found() )
|
||||
{
|
||||
Cmdline_enable_3d_shockwave = 1;
|
||||
}
|
||||
|
||||
if ( softparticles_arg.found() )
|
||||
{
|
||||
Cmdline_softparticles = 1;
|
||||
@@ -2160,6 +2182,16 @@ bool SetCmdlineParams()
|
||||
Gr_post_processing_enabled = false;
|
||||
}
|
||||
|
||||
if ( bloom_intensity_arg.found() )
|
||||
{
|
||||
Cmdline_bloom_intensity = bloom_intensity_arg.get_int();
|
||||
}
|
||||
|
||||
if ( flightshaftsoff_arg.found() )
|
||||
{
|
||||
Cmdline_force_lightshaft_off = true;
|
||||
}
|
||||
|
||||
if( reparse_mainhall_arg.found() )
|
||||
{
|
||||
Cmdline_reparse_mainhall = 1;
|
||||
@@ -2225,11 +2257,6 @@ bool SetCmdlineParams()
|
||||
{
|
||||
Cmdline_no_unfocus_pause = true;
|
||||
}
|
||||
|
||||
if (retail_time_compression_range_arg.found())
|
||||
{
|
||||
Cmdline_retail_time_compression_range = true;
|
||||
}
|
||||
|
||||
if (benchmark_mode_arg.found())
|
||||
{
|
||||
|
||||
@@ -63,7 +63,10 @@ extern int Cmdline_noscalevid; // disables fit-to-window for movies - taylor
|
||||
extern int Cmdline_spec;
|
||||
extern int Cmdline_normal;
|
||||
extern int Cmdline_height;
|
||||
extern int Cmdline_enable_3d_shockwave;
|
||||
extern int Cmdline_softparticles;
|
||||
extern int Cmdline_bloom_intensity;
|
||||
extern bool Cmdline_force_lightshaft_off;
|
||||
extern int Cmdline_no_deferred_lighting;
|
||||
extern bool Cmdline_deferred_lighting_cockpit;
|
||||
extern int Cmdline_emissive;
|
||||
@@ -81,9 +84,12 @@ extern int Cmdline_orb_radar;
|
||||
extern int Cmdline_rearm_timer;
|
||||
|
||||
// Gameplay related
|
||||
extern int Cmdline_ship_choice_3d;
|
||||
extern int Cmdline_weapon_choice_3d;
|
||||
extern int Cmdline_autopilot_interruptable;
|
||||
extern int Cmdline_stretch_menu;
|
||||
extern bool Cmdline_capture_mouse;
|
||||
extern int Cmdline_no_screenshake;
|
||||
extern int Cmdline_deadzone;
|
||||
extern bool Cmdline_enable_vr;
|
||||
|
||||
@@ -124,7 +130,6 @@ extern bool Cmdline_noshadercache;
|
||||
extern bool Cmdline_prefer_ipv4;
|
||||
extern bool Cmdline_prefer_ipv6;
|
||||
extern bool Cmdline_dump_packet_type;
|
||||
extern bool Cmdline_no_large_shaders;
|
||||
#ifdef WIN32
|
||||
extern bool Cmdline_alternate_registry_path;
|
||||
#endif
|
||||
@@ -144,7 +149,6 @@ extern int Cmdline_verify_vps;
|
||||
extern int Cmdline_reparse_mainhall;
|
||||
extern bool Cmdline_profile_write_file;
|
||||
extern bool Cmdline_no_unfocus_pause;
|
||||
extern bool Cmdline_retail_time_compression_range;
|
||||
extern bool Cmdline_benchmark_mode;
|
||||
extern const char *Cmdline_pilot;
|
||||
extern bool Cmdline_noninteractive;
|
||||
|
||||
@@ -141,9 +141,6 @@ SCP_vector<cc_line> Cc_lines;
|
||||
// Backups for use when user closes the config menu without saving
|
||||
SCP_vector<CCI> Control_config_backup;
|
||||
|
||||
// The current preset that the user is working on and will likely want to save to
|
||||
static SCP_string Current_preset_name;
|
||||
|
||||
// Undo system
|
||||
Undo_system Undo_controls;
|
||||
|
||||
@@ -1294,12 +1291,11 @@ bool control_config_accept(bool API_Access)
|
||||
char* cstr; // Must be a char *, because popup_input may return nullptr and std::string don't like it
|
||||
|
||||
retry:;
|
||||
SCP_string default_string = (Current_preset_name.empty()) ? Player->callsign : Current_preset_name;
|
||||
cstr = popup_input(flags,
|
||||
"Confirm new custom preset name.\n\nThe name must not be empty.\n\n Press [Enter] to accept, [Esc] to "
|
||||
"abort to config menu.",
|
||||
32 - 6,
|
||||
default_string.c_str());
|
||||
Player->callsign);
|
||||
if (cstr == nullptr) {
|
||||
// Abort
|
||||
gamesnd_play_iface(InterfaceSounds::USER_SELECT);
|
||||
@@ -1358,9 +1354,6 @@ bool control_config_accept(bool API_Access)
|
||||
// consistant ordering
|
||||
Control_config_presets.resize(1);
|
||||
load_preset_files();
|
||||
|
||||
// finally, save the new preset so that changes will get saved to this preset
|
||||
Current_preset_name = preset.name;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -1544,11 +1537,9 @@ void control_config_init(bool API_Access)
|
||||
// Init preset cycling system
|
||||
auto preset_it = control_config_get_current_preset();
|
||||
if (preset_it == Control_config_presets.end()) {
|
||||
Current_preset_name.clear();
|
||||
Defaults_cycle_pos = 0;
|
||||
|
||||
} else {
|
||||
Current_preset_name = preset_it->name;
|
||||
Defaults_cycle_pos = static_cast<unsigned int>(std::distance(Control_config_presets.begin(), preset_it));
|
||||
}
|
||||
|
||||
@@ -1660,9 +1651,6 @@ void control_config_close(bool API_Access)
|
||||
Cc_lines.clear();
|
||||
Conflicts.clear();
|
||||
Undo_controls.clear();
|
||||
|
||||
// Clear this, just to be tidy
|
||||
Current_preset_name.clear();
|
||||
}
|
||||
|
||||
SCP_vector<CC_preset>::iterator control_config_get_current_preset(bool invert_agnostic) {
|
||||
@@ -1908,7 +1896,7 @@ int control_config_draw_list(int select_tease_line) {
|
||||
char buf[256]; // c_str buffer
|
||||
int font_height = gr_get_font_height();
|
||||
|
||||
for (line = Scroll_offset; cc_line_query_visible(line) && (line - Scroll_offset < LIST_BUTTONS_MAX); ++line) {
|
||||
for (line = Scroll_offset; cc_line_query_visible(line); ++line) {
|
||||
z = Cc_lines[line].cc_index;
|
||||
|
||||
// screen coordinate y = list box origin y + (this item's relative y - topmost item's relative y)
|
||||
@@ -2103,7 +2091,7 @@ int control_config_bind_key_on_frame(int ctrl, selItem item, bool API_Access)
|
||||
}
|
||||
|
||||
if ((ctrl == BANK_WHEN_PRESSED || ctrl == GLIDE_WHEN_PRESSED) && (Last_key >= 0) && (k <= 0) &&
|
||||
!key_is_pressed(Last_key)) {
|
||||
!keyd_pressed[Last_key]) {
|
||||
// If the selected cc_item is BANK_WHEN_PRESSED or GLIDE_WHEN_PRESSED, and
|
||||
// If the polled key is a modifier, and
|
||||
// k was consumed, and
|
||||
@@ -2832,12 +2820,12 @@ int check_control_used(int id, int key)
|
||||
|
||||
// check what current modifiers are pressed
|
||||
mask = 0;
|
||||
if (key_is_pressed(KEY_LSHIFT, true) || key_is_pressed(KEY_RSHIFT, true)) {
|
||||
if (keyd_pressed[KEY_LSHIFT] || key_down_count(KEY_LSHIFT) || keyd_pressed[KEY_RSHIFT] || key_down_count(KEY_RSHIFT)) {
|
||||
// Any shift key is pressed, add KEY_SHIFTED mask
|
||||
mask |= KEY_SHIFTED;
|
||||
}
|
||||
|
||||
if (key_is_pressed(KEY_LALT, true) || key_is_pressed(KEY_RALT, true)) {
|
||||
if (keyd_pressed[KEY_LALT] || key_down_count(KEY_LALT) || keyd_pressed[KEY_RALT] || key_down_count(KEY_RALT)) {
|
||||
// Any alt key is pressed, add KEY_ALTED to the mask
|
||||
mask |= KEY_ALTED;
|
||||
}
|
||||
@@ -2853,7 +2841,7 @@ int check_control_used(int id, int key)
|
||||
|
||||
z &= KEY_MASK;
|
||||
|
||||
if (key_is_pressed(z, true)) {
|
||||
if (keyd_pressed[z] || key_down_count(z)) {
|
||||
// Key combo is pressed, control activated
|
||||
control_used(id);
|
||||
return 1;
|
||||
|
||||
@@ -2784,12 +2784,10 @@ bool CCB::operator!=(const CCB& A) const {
|
||||
}
|
||||
|
||||
bool CCB::has_first_conflict(const CCB& A) const {
|
||||
// coverity[copy_paste_error:FALSE]
|
||||
return !first.empty() && (first.conflicts_with(A.first) || first.conflicts_with(A.second));
|
||||
}
|
||||
|
||||
bool CCB::has_second_conflict(const CCB& A) const {
|
||||
// coverity[copy_paste_error:FALSE]
|
||||
return !second.empty() && (second.conflicts_with(A.first) || second.conflicts_with(A.second));
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace {
|
||||
const int OUT_CH_LAYOUT = AV_CH_LAYOUT_STEREO;
|
||||
const int OUT_SAMPLE_RATE = 48000;
|
||||
const AVSampleFormat OUT_SAMPLE_FORMAT = AV_SAMPLE_FMT_S16;
|
||||
const int OUT_NUM_CHANNELS = av_popcount64(OUT_CH_LAYOUT);
|
||||
const int OUT_NUM_CHANNELS = av_get_channel_layout_nb_channels(OUT_CH_LAYOUT);
|
||||
|
||||
const int DEFAULT_SRC_NUM_SAMPLES = 1024;
|
||||
|
||||
|
||||
@@ -69,11 +69,7 @@ CodecContextParameters getCodecParameters(AVStream* stream) {
|
||||
paras.height = stream->codecpar->height;
|
||||
paras.pixel_format = (AVPixelFormat)stream->codecpar->format;
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(59, 36, 255)
|
||||
paras.channel_layout = stream->codecpar->ch_layout.u.mask;
|
||||
#else
|
||||
paras.channel_layout = stream->codecpar->channel_layout;
|
||||
#endif
|
||||
paras.channel_layout = stream->codecpar->channel_layout;
|
||||
paras.sample_rate = stream->codecpar->sample_rate;
|
||||
paras.audio_format = (AVSampleFormat)stream->codecpar->format;
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ void SubtitleDecoder::pushSubtitleFrame(AVPacket* packet, AVSubtitle* subtitle)
|
||||
}
|
||||
|
||||
SubtitleFramePtr frame(new SubtitleFrame());
|
||||
frame->text = std::move(processed_text);
|
||||
frame->text = processed_text;
|
||||
|
||||
frame->displayStartTime = start_time;
|
||||
frame->displayEndTime = end_time;
|
||||
|
||||
+1
-15
@@ -45,7 +45,6 @@ struct PlaybackState {
|
||||
vec2d posBottomRight;
|
||||
|
||||
int subtitle_font = -1;
|
||||
color subtitle_color = Color_bright_white;
|
||||
};
|
||||
|
||||
void processEvents()
|
||||
@@ -103,7 +102,7 @@ void displayVideo(Player* player, PlaybackState* state) {
|
||||
|
||||
auto subtitle = player->getCurrentSubtitle();
|
||||
if (!subtitle.empty() && state->subtitle_font >= 0) {
|
||||
gr_set_color_fast(&state->subtitle_color);
|
||||
gr_set_color_fast(&Color_bright_white);
|
||||
font::set_font(state->subtitle_font);
|
||||
|
||||
int width;
|
||||
@@ -180,20 +179,7 @@ void initialize_player_state(Player* player, PlaybackState* state) {
|
||||
|
||||
if (state->subtitle_font < 0) {
|
||||
Warning(LOCATION, "Failed to load subtitle font '%s'! Subtitles will be disabled.", Movie_subtitle_font.c_str());
|
||||
}
|
||||
|
||||
if ((Movie_subtitle_rgba[0] >= 0 && Movie_subtitle_rgba[0] <= 255) &&
|
||||
(Movie_subtitle_rgba[1] >= 0 && Movie_subtitle_rgba[1] <= 255) &&
|
||||
(Movie_subtitle_rgba[2] >= 0 && Movie_subtitle_rgba[2] <= 255) &&
|
||||
(Movie_subtitle_rgba[3] >= 0 && Movie_subtitle_rgba[3] <= 255))
|
||||
{
|
||||
gr_init_alphacolor(&state->subtitle_color,
|
||||
Movie_subtitle_rgba[0],
|
||||
Movie_subtitle_rgba[1],
|
||||
Movie_subtitle_rgba[2],
|
||||
Movie_subtitle_rgba[3]);
|
||||
}
|
||||
|
||||
}
|
||||
else if (font::FontManager::numberOfFonts() > 0) {
|
||||
state->subtitle_font = 0; // if not explicitly specified, default to the first available font
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
+176
-331
@@ -3,17 +3,6 @@
|
||||
#include "cfile/cfile.h"
|
||||
#include "osapi/osregistry.h"
|
||||
|
||||
#ifdef WITH_OPENGL
|
||||
#include <glad/glad.h>
|
||||
#else
|
||||
static constexpr int GLAD_GL_EXT_texture_compression_s3tc = 0;
|
||||
static constexpr int GLAD_GL_ARB_texture_compression_bptc = 0;
|
||||
#endif
|
||||
|
||||
#define BCDEC_IMPLEMENTATION 1
|
||||
PUSH_SUPPRESS_WARNINGS
|
||||
#include "ddsutils/bcdec.h"
|
||||
POP_SUPPRESS_WARNINGS
|
||||
|
||||
/* Currently supported formats:
|
||||
* DXT1a (compressed)
|
||||
@@ -23,9 +12,12 @@ POP_SUPPRESS_WARNINGS
|
||||
* uncompressed 1555 (16-bit, 1-bit being alpha)
|
||||
* uncompressed 8888 (32-bit)
|
||||
* uncompressed 888 (24-bit, no alpha)
|
||||
* uncompressed R8 (8-bit, Red channel as luminance)
|
||||
* paletted 8-bit (256 colors)
|
||||
*/
|
||||
|
||||
|
||||
int Texture_compression_available = 0;
|
||||
int Use_compressed_textures = 0;
|
||||
|
||||
// power of two check, to verify that a given DDS will always be usable since
|
||||
// some may not be power-of-2
|
||||
@@ -34,219 +26,39 @@ static inline int is_power_of_two(int w, int h)
|
||||
return ( (w && !(w & (w-1))) && (h && !(h & (h-1))) );
|
||||
}
|
||||
|
||||
static bool valid_dx10_format(const DDS_HEADER_DXT10 &header)
|
||||
// This function is used to verify that the file format specified in the DX10 Header
|
||||
// is supported by the OpenGL extensions
|
||||
bool dds_read_dx10_header(CFILE* dds_file, DDS_HEADER_DXT10* header)
|
||||
{
|
||||
switch (header.dxgiFormat) {
|
||||
case DXGI_FORMAT::DXGI_FORMAT_BC7_TYPELESS:
|
||||
case DXGI_FORMAT::DXGI_FORMAT_BC7_UNORM:
|
||||
case DXGI_FORMAT::DXGI_FORMAT_BC7_UNORM_SRGB:
|
||||
return true;
|
||||
header->dxgiFormat = static_cast<DXGI_FORMAT>(cfread_uint(dds_file));
|
||||
header->resourceDimension = static_cast<D3D10_RESOURCE_DIMENSION>(cfread_uint(dds_file));
|
||||
header->miscFlag = cfread_uint(dds_file);
|
||||
header->arraySize = cfread_uint(dds_file);
|
||||
header->miscFlags2 = cfread_uint(dds_file);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool conversion_needed(const DDS_HEADER &dds_header)
|
||||
{
|
||||
if ((dds_header.ddspf.dwFlags & DDPF_FOURCC) != DDPF_FOURCC) {
|
||||
switch (header->dxgiFormat) {
|
||||
case DXGI_FORMAT::DXGI_FORMAT_BC7_TYPELESS:
|
||||
case DXGI_FORMAT::DXGI_FORMAT_BC7_UNORM:
|
||||
case DXGI_FORMAT::DXGI_FORMAT_BC7_UNORM_SRGB:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (dds_header.ddspf.dwFourCC) {
|
||||
case FOURCC_DXT1:
|
||||
case FOURCC_DXT3:
|
||||
case FOURCC_DXT5:
|
||||
return !GLAD_GL_EXT_texture_compression_s3tc;
|
||||
|
||||
case FOURCC_DX10:
|
||||
// anything other than BC7 will end up invalid
|
||||
return !GLAD_GL_ARB_texture_compression_bptc;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// anything not specifically listed should end up invalid
|
||||
return false;
|
||||
}
|
||||
|
||||
// Memory usage for uncompressed textures is quite high. Some MVP assets can
|
||||
// require well over a GB of VRAM for a single ship after conversion. To help
|
||||
// alleviate this we need to resize those textures where possible. At 1024x1024
|
||||
// the memory requirement is reduced to about 36 MB per ship with a full set
|
||||
// of textures.
|
||||
//
|
||||
// NOTE: modifies header!!
|
||||
//
|
||||
// returns: number of mipmap levels to skip
|
||||
static uint conversion_resize(DDS_HEADER &dds_header)
|
||||
{
|
||||
const size_t MAX_SIZE = 1024;
|
||||
uint width, height, depth, offset = 0;
|
||||
|
||||
if (dds_header.dwMipMapCount <= 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
width = dds_header.dwWidth;
|
||||
height = dds_header.dwHeight;
|
||||
depth = dds_header.dwDepth;
|
||||
|
||||
// drop levels until we get to an appropriate size, but make sure we have
|
||||
// at least 1 mipmap level remaining at the end (in case there's not a full chain)
|
||||
while (((width > MAX_SIZE) || (height > MAX_SIZE)) && (offset < dds_header.dwMipMapCount-1)) {
|
||||
width >>= 1;
|
||||
height >>= 1;
|
||||
depth >>= 1;
|
||||
|
||||
++offset;
|
||||
}
|
||||
|
||||
// no change needed
|
||||
if ( !offset ) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
// update header with new values
|
||||
dds_header.dwWidth = std::max(1U, width);
|
||||
dds_header.dwHeight = std::max(1U, height);
|
||||
dds_header.dwDepth = std::max(1U, depth);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int _dds_read_header(CFILE *ddsfile, DDS_HEADER &dds_header, DDS_HEADER_DXT10 *dds_header_dx10 = nullptr)
|
||||
{
|
||||
DDS_HEADER_DXT10 dx10_header;
|
||||
|
||||
// read the code
|
||||
int code = cfread_int(ddsfile);
|
||||
|
||||
// check it
|
||||
if (code != DDS_FILECODE) {
|
||||
return DDS_ERROR_BAD_HEADER;
|
||||
}
|
||||
|
||||
// read header variables
|
||||
dds_header.dwSize = cfread_uint(ddsfile);
|
||||
dds_header.dwFlags = cfread_uint(ddsfile);
|
||||
dds_header.dwHeight = cfread_uint(ddsfile);
|
||||
dds_header.dwWidth = cfread_uint(ddsfile);
|
||||
dds_header.dwPitchOrLinearSize = cfread_uint(ddsfile);
|
||||
dds_header.dwDepth = cfread_uint(ddsfile);
|
||||
dds_header.dwMipMapCount = cfread_uint(ddsfile);
|
||||
|
||||
// skip over the crap we don't care about
|
||||
cfseek(ddsfile, 11*4, CF_SEEK_CUR);
|
||||
|
||||
dds_header.ddspf.dwSize = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwFlags = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwFourCC = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwRGBBitCount = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwRBitMask = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwGBitMask = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwBBitMask = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwABitMask = cfread_uint(ddsfile);
|
||||
|
||||
dds_header.dwCaps = cfread_uint(ddsfile);
|
||||
dds_header.dwCaps2 = cfread_uint(ddsfile);
|
||||
|
||||
// Unused but need them checked for later
|
||||
dds_header.dwCaps3 = cfread_uint(ddsfile);
|
||||
dds_header.dwCaps4 = cfread_uint(ddsfile);
|
||||
dds_header.dwReserved2 = cfread_uint(ddsfile);
|
||||
|
||||
if (dds_header.ddspf.dwFourCC == FOURCC_DX10) {
|
||||
dx10_header.dxgiFormat = static_cast<DXGI_FORMAT>(cfread_uint(ddsfile));
|
||||
dx10_header.resourceDimension = static_cast<D3D10_RESOURCE_DIMENSION>(cfread_uint(ddsfile));
|
||||
dx10_header.miscFlag = cfread_uint(ddsfile);
|
||||
dx10_header.arraySize = cfread_uint(ddsfile);
|
||||
dx10_header.miscFlags2 = cfread_uint(ddsfile);
|
||||
|
||||
if (dds_header_dx10) {
|
||||
memcpy(dds_header_dx10, &dx10_header, sizeof(DDS_HEADER_DXT10));
|
||||
}
|
||||
}
|
||||
|
||||
// sanitize values
|
||||
dds_header.dwDepth = std::max(1U, dds_header.dwDepth);
|
||||
dds_header.dwMipMapCount = std::max(1U, dds_header.dwMipMapCount);
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (dds_header.dwDepth > 1) {
|
||||
Assertion(dds_header.dwFlags & DDSD_DEPTH, "ERROR: Volume texture missing proper flags!!");
|
||||
}
|
||||
#endif
|
||||
|
||||
// set pitch manually (per MS docs)
|
||||
dds_header.dwFlags &= ~DDSD_LINEARSIZE;
|
||||
dds_header.dwFlags |= DDSD_PITCH;
|
||||
|
||||
if (dds_header.ddspf.dwFlags & DDPF_FOURCC) {
|
||||
int block_size = (dds_header.ddspf.dwFourCC == FOURCC_DXT1) ? 8 : 16;
|
||||
dds_header.dwPitchOrLinearSize = std::max(1U, (dds_header.dwWidth+3)/4) * block_size;
|
||||
} else {
|
||||
// this isn't technically correct, but it's only wrong for formats we don't support
|
||||
dds_header.dwPitchOrLinearSize = (dds_header.dwWidth * dds_header.ddspf.dwRGBBitCount + 7) / 8;
|
||||
}
|
||||
|
||||
return DDS_ERROR_NONE;
|
||||
}
|
||||
|
||||
static size_t compute_dds_size(const DDS_HEADER &dds_header)
|
||||
{
|
||||
uint d_width, d_height, d_depth;
|
||||
size_t d_size = 0;
|
||||
|
||||
for (uint i = 0; i < dds_header.dwMipMapCount; i++) {
|
||||
d_width = std::max(1U, dds_header.dwWidth >> i);
|
||||
d_height = std::max(1U, dds_header.dwHeight >> i);
|
||||
d_depth = std::max(1U, dds_header.dwDepth >> i);
|
||||
|
||||
if (dds_header.ddspf.dwFlags & DDPF_FOURCC) {
|
||||
// size of data block (4x4)
|
||||
d_size += ((d_width + 3) / 4) * ((d_height + 3) / 4) * d_depth * ((dds_header.ddspf.dwFourCC == FOURCC_DXT1) ? 8 : 16);
|
||||
} else {
|
||||
d_size += d_width * d_height * d_depth * (dds_header.ddspf.dwRGBBitCount / 8);
|
||||
}
|
||||
}
|
||||
|
||||
// assumes valid cubemap (should be checked elsewhere)
|
||||
if (dds_header.dwCaps2 & DDSCAPS2_CUBEMAP) {
|
||||
// the previously computed size is just per face, mult by 6 for full size
|
||||
d_size *= 6;
|
||||
}
|
||||
|
||||
Assertion(d_size > 0, "ERROR: DDS size computed to 0!!");
|
||||
|
||||
return d_size;
|
||||
}
|
||||
|
||||
static int get_bit_count(const DDS_HEADER &dds_header)
|
||||
{
|
||||
if (dds_header.ddspf.dwFlags & DDPF_RGB) {
|
||||
return dds_header.ddspf.dwRGBBitCount;
|
||||
} else if (dds_header.ddspf.dwFlags & DDPF_FOURCC) {
|
||||
if (dds_header.ddspf.dwFourCC == FOURCC_DXT1) {
|
||||
return 24;
|
||||
} else {
|
||||
return 32;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *height, int *bpp, int *compression_type, int *levels, size_t *size)
|
||||
int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *height, int *bpp, int *compression_type, int *levels, size_t *size, ubyte *palette)
|
||||
{
|
||||
DDS_HEADER dds_header;
|
||||
DDS_HEADER_DXT10 dds_header_dx10;
|
||||
int code = 0;
|
||||
CFILE *ddsfile;
|
||||
char real_name[MAX_FILENAME_LEN];
|
||||
int retval = DDS_ERROR_NONE;
|
||||
int ct = DDS_UNCOMPRESSED;
|
||||
int is_cubemap = 0;
|
||||
int bits = 0;
|
||||
int i, is_cubemap = 0;
|
||||
uint32_t d_width = 0, d_height = 0, d_depth = 0;
|
||||
size_t d_size = 0;
|
||||
|
||||
|
||||
if (img_cfp == NULL) {
|
||||
@@ -269,36 +81,113 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
|
||||
ddsfile = img_cfp;
|
||||
}
|
||||
|
||||
retval = _dds_read_header(ddsfile, dds_header, &dds_header_dx10);
|
||||
// read the code
|
||||
code = cfread_int(ddsfile);
|
||||
|
||||
if (retval != DDS_ERROR_NONE) {
|
||||
// check it
|
||||
if (code != DDS_FILECODE) {
|
||||
retval = DDS_ERROR_BAD_HEADER;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
// check for valid cubemap (we require all 6 faces)
|
||||
if (dds_header.dwCaps2 & DDSCAPS2_CUBEMAP) {
|
||||
if ( !(dds_header.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES) ) {
|
||||
retval = DDS_ERROR_CUBEMAP_FACES;
|
||||
ct = DDS_DXT_INVALID;
|
||||
goto Done;
|
||||
// read header variables
|
||||
dds_header.dwSize = cfread_uint(ddsfile);
|
||||
dds_header.dwFlags = cfread_uint(ddsfile);
|
||||
dds_header.dwHeight = cfread_uint(ddsfile);
|
||||
dds_header.dwWidth = cfread_uint(ddsfile);
|
||||
dds_header.dwPitchOrLinearSize = cfread_uint(ddsfile);
|
||||
dds_header.dwDepth = cfread_uint(ddsfile);
|
||||
dds_header.dwMipMapCount = cfread_uint(ddsfile);
|
||||
|
||||
// skip over the crap we don't care about
|
||||
for (i = 0; i < 11; i++)
|
||||
cfread_uint(ddsfile);
|
||||
|
||||
dds_header.ddspf.dwSize = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwFlags = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwFourCC = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwRGBBitCount = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwRBitMask = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwGBitMask = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwBBitMask = cfread_uint(ddsfile);
|
||||
dds_header.ddspf.dwABitMask = cfread_uint(ddsfile);
|
||||
|
||||
dds_header.dwCaps = cfread_uint(ddsfile);
|
||||
dds_header.dwCaps2 = cfread_uint(ddsfile);
|
||||
|
||||
// Unused but need them checked for later
|
||||
dds_header.dwCaps3 = cfread_uint(ddsfile);
|
||||
dds_header.dwCaps4 = cfread_uint(ddsfile);
|
||||
dds_header.dwReserved2 = cfread_uint(ddsfile);
|
||||
|
||||
// sanity
|
||||
if (dds_header.dwDepth == 0)
|
||||
dds_header.dwDepth = 1;
|
||||
|
||||
if (dds_header.dwMipMapCount < 1)
|
||||
dds_header.dwMipMapCount = 1;
|
||||
|
||||
d_width = dds_header.dwWidth;
|
||||
d_height = dds_header.dwHeight;
|
||||
d_depth = dds_header.dwDepth;
|
||||
|
||||
// calculate the type and size of the data
|
||||
if (dds_header.ddspf.dwFlags & DDPF_FOURCC) {
|
||||
// did I mention lately that I hate Microsoft?
|
||||
// this is here to fix the situation where Microsoft doesn't follow their own docs
|
||||
if ( !(dds_header.dwFlags & (DDSD_LINEARSIZE | DDSD_PITCH) ) || dds_header.dwPitchOrLinearSize <= 0 ) {
|
||||
// calculate the block size, mult by 8 for DXT1, 16 for DXT3 & 5
|
||||
d_size = ((dds_header.dwWidth + 3)/4) * ((dds_header.dwHeight + 3)/4) * ((dds_header.dwDepth + 3)/4) * ((dds_header.ddspf.dwFourCC == FOURCC_DXT1) ? 8 : 16);
|
||||
} else {
|
||||
d_size = dds_header.dwPitchOrLinearSize;
|
||||
}
|
||||
|
||||
// it's a valid cubemap, probably
|
||||
is_cubemap = 1;
|
||||
}
|
||||
// if we have mipmaps then compute them into the final size too
|
||||
for (i = 1; i < (int)dds_header.dwMipMapCount; i++) {
|
||||
// reduce size by half for the next pass
|
||||
d_width /= 2;
|
||||
d_height /= 2;
|
||||
|
||||
if (d_width <= 0)
|
||||
d_width = 1;
|
||||
|
||||
if (d_height <= 0)
|
||||
d_height = 1;
|
||||
|
||||
// size of data block (4x4)
|
||||
d_size += ((d_width + 3) / 4) * ((d_height + 3) / 4) * ((dds_header.ddspf.dwFourCC == FOURCC_DXT1) ? 8 : 16);
|
||||
}
|
||||
|
||||
if ( dds_header.dwCaps2 & DDSCAPS2_CUBEMAP ) {
|
||||
if ( !(dds_header.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES) ) {
|
||||
retval = DDS_ERROR_CUBEMAP_FACES;
|
||||
ct = DDS_DXT_INVALID;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
// it's a valid cubemap, probably
|
||||
is_cubemap = 1;
|
||||
|
||||
// the previously computed size is just per face, mult by 6 for full size
|
||||
d_size *= 6;
|
||||
}
|
||||
|
||||
Assert( d_size > 0 );
|
||||
*size = d_size;
|
||||
|
||||
// determine and verify the type of data for internal use
|
||||
if (dds_header.ddspf.dwFlags & DDPF_FOURCC) {
|
||||
switch (dds_header.ddspf.dwFourCC) {
|
||||
case FOURCC_DXT1:
|
||||
bits = 24;
|
||||
ct = (is_cubemap) ? DDS_CUBEMAP_DXT1 : DDS_DXT1;
|
||||
break;
|
||||
|
||||
case FOURCC_DXT3:
|
||||
bits = 32;
|
||||
ct = (is_cubemap) ? DDS_CUBEMAP_DXT3 : DDS_DXT3;
|
||||
break;
|
||||
|
||||
case FOURCC_DXT5:
|
||||
bits = 32;
|
||||
ct = (is_cubemap) ? DDS_CUBEMAP_DXT5 : DDS_DXT5;
|
||||
break;
|
||||
|
||||
@@ -311,8 +200,9 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
|
||||
break;
|
||||
|
||||
case FOURCC_DX10:
|
||||
if (valid_dx10_format(dds_header_dx10)) {
|
||||
if (dds_read_dx10_header(ddsfile, &dds_header_dx10)) {
|
||||
// Currently only BC7 is supported
|
||||
bits = 32;
|
||||
ct = DDS_BC7;
|
||||
} else {
|
||||
retval = DDS_ERROR_UNSUPPORTED;
|
||||
@@ -328,7 +218,46 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
|
||||
goto Done;
|
||||
break;
|
||||
}
|
||||
} else if (dds_header.ddspf.dwFlags & DDPF_RGB) {
|
||||
} else if ( dds_header.ddspf.dwFlags & (DDPF_RGB | DDPF_PALETTEINDEXED8) ) {
|
||||
d_size += d_width * d_height * d_depth * (dds_header.ddspf.dwRGBBitCount / 8);
|
||||
|
||||
// calculate full data size for all mipmap levels
|
||||
for (i = 1; i < (int)dds_header.dwMipMapCount; i++) {
|
||||
d_width /= 2;
|
||||
d_height /= 2;
|
||||
d_depth /= 2;
|
||||
|
||||
if (d_width < 1)
|
||||
d_width = 1;
|
||||
|
||||
if (d_height < 1)
|
||||
d_height = 1;
|
||||
|
||||
if (d_depth < 1)
|
||||
d_depth = 1;
|
||||
|
||||
d_size += d_width * d_height * d_depth * (dds_header.ddspf.dwRGBBitCount / 8);
|
||||
}
|
||||
|
||||
Assert( d_size > 0 );
|
||||
|
||||
if ( dds_header.dwCaps2 & DDSCAPS2_CUBEMAP ) {
|
||||
if ( !(dds_header.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES) ) {
|
||||
retval = DDS_ERROR_CUBEMAP_FACES;
|
||||
ct = DDS_DXT_INVALID;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
// it's a valid cubemap, probably
|
||||
is_cubemap = 1;
|
||||
|
||||
// the previously computed size is just per face, mult by 6 for full size
|
||||
d_size *= 6;
|
||||
}
|
||||
|
||||
*size = d_size;
|
||||
|
||||
bits = dds_header.ddspf.dwRGBBitCount;
|
||||
ct = (is_cubemap) ? DDS_CUBEMAP_UNCOMPRESSED : DDS_UNCOMPRESSED;
|
||||
} else {
|
||||
// it's not a readable format
|
||||
@@ -336,33 +265,21 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
|
||||
goto Done;
|
||||
}
|
||||
|
||||
// maybe do conversion if format not supported
|
||||
if (conversion_needed(dds_header)) {
|
||||
// switch to uncompressed format and reset vars
|
||||
dds_header.ddspf.dwFlags &= ~DDPF_FOURCC;
|
||||
dds_header.ddspf.dwFlags |= DDPF_RGB;
|
||||
|
||||
dds_header.ddspf.dwRGBBitCount = 32;
|
||||
|
||||
// NOTE: modifies header and returns offset for mipmap count
|
||||
dds_header.dwMipMapCount -= conversion_resize(dds_header);
|
||||
dds_header.dwMipMapCount = std::max(1U, dds_header.dwMipMapCount);
|
||||
|
||||
ct = (is_cubemap) ? DDS_CUBEMAP_UNCOMPRESSED : DDS_UNCOMPRESSED;
|
||||
}
|
||||
|
||||
// we don't support compressed, non-power-of-2 images
|
||||
if ( (ct != DDS_UNCOMPRESSED) && (!is_power_of_two(dds_header.dwWidth, dds_header.dwHeight)) ) {
|
||||
retval = DDS_ERROR_NON_POWER_OF_2;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
// stuff important info
|
||||
if (size)
|
||||
*size = compute_dds_size(dds_header);
|
||||
// make sure that the video card can handle compressed textures before using them
|
||||
if ( !Use_compressed_textures && (ct != DDS_UNCOMPRESSED) && (ct != DDS_DXT_INVALID) ) {
|
||||
retval = DDS_ERROR_NO_COMPRESSION;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
// stuff important info
|
||||
if (bpp)
|
||||
*bpp = get_bit_count(dds_header);
|
||||
*bpp = bits;
|
||||
|
||||
if (compression_type)
|
||||
*compression_type = ct;
|
||||
@@ -376,6 +293,12 @@ int dds_read_header(const char *filename, CFILE *img_cfp, int *width, int *heigh
|
||||
if (levels)
|
||||
*levels = dds_header.dwMipMapCount;
|
||||
|
||||
if (palette && (bits == 8)) {
|
||||
cfseek(ddsfile, (ct == DDS_BC7) ? DX10_OFFSET : DDS_OFFSET, CF_SEEK_SET);
|
||||
cfread(palette, 1, 1024, ddsfile);
|
||||
}
|
||||
|
||||
|
||||
Done:
|
||||
if (img_cfp == NULL) {
|
||||
// close file and return
|
||||
@@ -390,10 +313,11 @@ Done:
|
||||
int dds_read_bitmap(const char *filename, ubyte *data, ubyte *bpp, int cf_type)
|
||||
{
|
||||
int retval;
|
||||
int w,h,ct,lvl;
|
||||
size_t size = 0;
|
||||
int bits = 0;
|
||||
CFILE *cfp;
|
||||
char real_name[MAX_FILENAME_LEN];
|
||||
DDS_HEADER dds_header;
|
||||
|
||||
// this better not happen.. ever
|
||||
Assert(filename != NULL);
|
||||
@@ -408,104 +332,25 @@ int dds_read_bitmap(const char *filename, ubyte *data, ubyte *bpp, int cf_type)
|
||||
cfp = cfopen(real_name, "rb", CFILE_NORMAL, cf_type);
|
||||
|
||||
// just in case
|
||||
if (cfp == nullptr)
|
||||
if (cfp == NULL)
|
||||
return DDS_ERROR_INVALID_FILENAME;
|
||||
|
||||
// read the header -- if its at this stage, it should be legal.
|
||||
retval = _dds_read_header(cfp, dds_header);
|
||||
retval = dds_read_header(real_name, cfp, &w, &h, &bits, &ct, &lvl, &size);
|
||||
Assert(retval == DDS_ERROR_NONE);
|
||||
|
||||
// this really shouldn't be needed but better safe than sorry
|
||||
if (retval != DDS_ERROR_NONE) {
|
||||
cfclose(cfp);
|
||||
return retval;
|
||||
}
|
||||
|
||||
cfseek(cfp, (dds_header.ddspf.dwFourCC == FOURCC_DX10) ? DX10_OFFSET : DDS_OFFSET, CF_SEEK_SET);
|
||||
|
||||
size = compute_dds_size(dds_header);
|
||||
cfseek(cfp, (ct == DDS_BC7) ? DX10_OFFSET : DDS_OFFSET, CF_SEEK_SET);
|
||||
|
||||
// read in the data
|
||||
if ( !conversion_needed(dds_header) ) {
|
||||
cfread(data, 1, (int)size, cfp);
|
||||
} else {
|
||||
// Compression format not supported, convert to BGRA
|
||||
ubyte *comp_data = (ubyte*)vm_malloc(size);
|
||||
|
||||
cfread(comp_data, 1, (int)size, cfp);
|
||||
|
||||
ubyte *src = comp_data;
|
||||
ubyte *dst = data;
|
||||
|
||||
uint d_width, d_height, d_depth;
|
||||
size_t data_offset = 0;
|
||||
|
||||
// NOTE: this alters the width, height, and depth values in the header,
|
||||
// so we have to jump through some hoops to get the proper values
|
||||
const uint mipmap_offset = conversion_resize(dds_header);
|
||||
|
||||
const int num_faces = (dds_header.dwCaps2 & DDSCAPS2_CUBEMAP) ? 6 : 1;
|
||||
const bool has_depth = (dds_header.dwFlags & DDSD_DEPTH) == DDSD_DEPTH;
|
||||
|
||||
for (int f = 0; f < num_faces; ++f) {
|
||||
// if we resized then skip over all of that data (altering values to match pre-resize)
|
||||
for (uint x = 0; x < mipmap_offset; ++x) {
|
||||
d_width = std::max(1U, dds_header.dwWidth << (mipmap_offset - x));
|
||||
d_height = std::max(1U, dds_header.dwHeight << (mipmap_offset - x));
|
||||
d_depth = has_depth ? std::max(1U, dds_header.dwDepth << (mipmap_offset - x)) : 1U;
|
||||
|
||||
src += (d_width * d_height * d_depth);
|
||||
}
|
||||
|
||||
for (uint m = mipmap_offset; m < dds_header.dwMipMapCount; ++m) {
|
||||
// width/height/depth at post-resize mipmap sizes, so compensate here
|
||||
d_width = std::max(1U, dds_header.dwWidth >> (m - mipmap_offset));
|
||||
d_height = std::max(1U, dds_header.dwHeight >> (m - mipmap_offset));
|
||||
d_depth = std::max(1U, dds_header.dwDepth >> (m - mipmap_offset));
|
||||
|
||||
for (uint d = 0; d < d_depth; ++d) {
|
||||
for (uint i = 0; i < d_height; i += 4) {
|
||||
for (uint j = 0; j < d_width; j += 4) {
|
||||
dst = data + data_offset + ((i * d_width + j) * 4);
|
||||
|
||||
if (dds_header.ddspf.dwFourCC == FOURCC_DX10) {
|
||||
bcdec_bc7(src, dst, d_width * 4);
|
||||
src += BCDEC_BC7_BLOCK_SIZE;
|
||||
} else if (dds_header.ddspf.dwFourCC == FOURCC_DXT5) {
|
||||
bcdec_bc3(src, dst, d_width * 4);
|
||||
src += BCDEC_BC3_BLOCK_SIZE;
|
||||
} else if (dds_header.ddspf.dwFourCC == FOURCC_DXT1) {
|
||||
bcdec_bc1(src, dst, d_width * 4);
|
||||
src += BCDEC_BC1_BLOCK_SIZE;
|
||||
} else if (dds_header.ddspf.dwFourCC == FOURCC_DXT3) {
|
||||
bcdec_bc2(src, dst, d_width * 4);
|
||||
src += BCDEC_BC2_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we need it in bgra, XOR to the rescue
|
||||
for (size_t x = data_offset; x < (data_offset + (d_width * d_height * d_depth * 4)); x += 4) {
|
||||
data[x] ^= data[x+2], data[x+2] ^= data[x], data[x] ^= data[x+2];
|
||||
}
|
||||
|
||||
// bump data offset to next layer
|
||||
data_offset += (d_width * d_height * d_depth * 4);
|
||||
}
|
||||
}
|
||||
|
||||
vm_free(comp_data);
|
||||
comp_data = nullptr;
|
||||
|
||||
// switch to uncompressed format and reset vars (needed below to get correct bit count)
|
||||
dds_header.ddspf.dwFlags &= ~DDPF_FOURCC;
|
||||
dds_header.ddspf.dwFlags |= DDPF_RGB;
|
||||
dds_header.ddspf.dwRGBBitCount = 32;
|
||||
}
|
||||
cfread(data, 1, (int)size, cfp);
|
||||
|
||||
if (bpp)
|
||||
*bpp = (ubyte)get_bit_count(dds_header);
|
||||
*bpp = (ubyte)bits;
|
||||
|
||||
// we look done here
|
||||
cfclose(cfp);
|
||||
|
||||
@@ -59,7 +59,6 @@
|
||||
#define DDSD_HEIGHT 0x00000002
|
||||
#define DDSD_CAPS 0x00000001
|
||||
#define DDSD_MIPMAPCOUNT 0x00020000
|
||||
#define DDSD_DEPTH 0x00800000
|
||||
|
||||
#define DDSCAPS_COMPLEX 0x00000008
|
||||
#define DDSCAPS_PRIMARYSURFACE 0x00000200
|
||||
@@ -279,7 +278,7 @@ typedef struct {
|
||||
//reads a dds header
|
||||
//returns one of the error values
|
||||
//'compression_type' comes back as one of the DDS_DXTC* defines
|
||||
int dds_read_header(const char *filename, CFILE *img_cfp = NULL, int *width = 0, int *height = 0, int *bpp = 0, int *compression_type = 0, int *levels = 0, size_t *size = 0);
|
||||
int dds_read_header(const char *filename, CFILE *img_cfp = NULL, int *width = 0, int *height = 0, int *bpp = 0, int *compression_type = 0, int *levels = 0, size_t *size = 0, ubyte *palette = NULL);
|
||||
|
||||
//reads bitmap
|
||||
//size of the data it stored in size
|
||||
@@ -291,4 +290,7 @@ void dds_save_image(int width, int height, int bpp, int num_mipmaps, ubyte *data
|
||||
//returns a string from a DDS error code
|
||||
const char *dds_error_string(int code);
|
||||
|
||||
extern int Texture_compression_available;
|
||||
extern int Use_compressed_textures;
|
||||
|
||||
#endif //__DDS_H
|
||||
@@ -1197,9 +1197,6 @@ void debris_render(object * obj, model_draw_list *scene)
|
||||
// render_info.set_flags(MR_NO_LIGHTING);
|
||||
}
|
||||
|
||||
if (db->model_instance_num >= 0)
|
||||
render_info.set_replacement_textures(model_get_instance(db->model_instance_num)->texture_replace);
|
||||
|
||||
submodel_render_queue( &render_info, scene, pm, pmi, db->submodel_num, &obj->orient, &obj->pos );
|
||||
|
||||
if (tbase != NULL && (swapped!=-1) && pm) {
|
||||
|
||||
+12
-12
@@ -174,7 +174,7 @@ void parse_decals_table(const char* filename) {
|
||||
SCP_string name;
|
||||
stuff_string(name, F_NAME);
|
||||
|
||||
DecalDefinition def(std::move(name));
|
||||
DecalDefinition def(name);
|
||||
def.parse();
|
||||
|
||||
DecalDefinitions.push_back(std::move(def));
|
||||
@@ -186,17 +186,17 @@ void parse_decals_table(const char* filename) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gr_is_capable(gr_capability::CAPABILITY_DEFERRED_LIGHTING)) {
|
||||
if (!gr_is_capable(CAPABILITY_DEFERRED_LIGHTING)) {
|
||||
// We need deferred lighting
|
||||
Decal_system_active = false;
|
||||
mprintf(("Note: Decal system has been disabled due to lack of deferred lighting.\n"));
|
||||
}
|
||||
if (!gr_is_capable(gr_capability::CAPABILITY_NORMAL_MAP)) {
|
||||
if (!gr_is_capable(CAPABILITY_NORMAL_MAP)) {
|
||||
// We need normal mapping for the full feature range
|
||||
Decal_system_active = false;
|
||||
mprintf(("Note: Decal system has been disabled due to lack of normal mapping.\n"));
|
||||
}
|
||||
if (!gr_is_capable(gr_capability::CAPABILITY_SEPARATE_BLEND_FUNCTIONS)) {
|
||||
if (!gr_is_capable(CAPABILITY_SEPARATE_BLEND_FUNCTIONS)) {
|
||||
// We need separate blending functions for different color buffers
|
||||
Decal_system_active = false;
|
||||
mprintf(("Note: Decal system has been disabled due to lack of separate color buffer blend functions.\n"));
|
||||
@@ -224,13 +224,13 @@ struct Decal {
|
||||
if (!object.isValid()) {
|
||||
return false;
|
||||
}
|
||||
if (object.objp()->flags[Object::Object_Flags::Should_be_dead]) {
|
||||
if (object.objp->flags[Object::Object_Flags::Should_be_dead]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (orig_obj_type != object.objp()->type) {
|
||||
if (orig_obj_type != object.objp->type) {
|
||||
mprintf(("Decal object type for object %d has changed from %s to %s. Please let m!m know about this\n",
|
||||
object.objnum, Object_type_names[orig_obj_type], Object_type_names[object.objp()->type]));
|
||||
OBJ_INDEX(object.objp), Object_type_names[orig_obj_type], Object_type_names[object.objp->type]));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -241,7 +241,7 @@ struct Decal {
|
||||
}
|
||||
}
|
||||
|
||||
auto objp = object.objp();
|
||||
auto objp = object.objp;
|
||||
if (objp->type == OBJ_SHIP) {
|
||||
auto shipp = &Ships[objp->instance];
|
||||
auto model_instance = model_get_instance(shipp->model_instance_num);
|
||||
@@ -339,7 +339,7 @@ void parseDecalReference(creation_info& dest_info, bool is_new_entry) {
|
||||
}
|
||||
|
||||
if (required_string_if_new("+Radius:", is_new_entry)) {
|
||||
dest_info.radius = util::ParsedRandomFloatRange::parseRandomRange(0.0001f);
|
||||
dest_info.radius = util::parseUniformRange(0.0001f);
|
||||
}
|
||||
|
||||
if (required_string_if_new("+Lifetime:", is_new_entry)) {
|
||||
@@ -347,7 +347,7 @@ void parseDecalReference(creation_info& dest_info, bool is_new_entry) {
|
||||
dest_info.lifetime = util::UniformFloatRange(-1.0f);
|
||||
} else {
|
||||
// Require at least a small lifetime so that the calculations don't have to deal with div-by-zero
|
||||
dest_info.lifetime = util::ParsedRandomFloatRange::parseRandomRange(0.0001f);
|
||||
dest_info.lifetime = util::parseUniformRange(0.0001f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,9 +393,9 @@ void initializeMission() {
|
||||
}
|
||||
|
||||
matrix4 getDecalTransform(Decal& decal) {
|
||||
Assertion(decal.object.objp()->type == OBJ_SHIP, "Only ships are currently supported for decals!");
|
||||
Assertion(decal.object.objp->type == OBJ_SHIP, "Only ships are currently supported for decals!");
|
||||
|
||||
auto objp = decal.object.objp();
|
||||
auto objp = decal.object.objp;
|
||||
auto ship = &Ships[objp->instance];
|
||||
auto pmi = model_get_instance(ship->model_instance_num);
|
||||
auto pm = model_get(pmi->model_num);
|
||||
|
||||
@@ -65,10 +65,10 @@ typedef int DecalReference;
|
||||
*/
|
||||
struct creation_info {
|
||||
DecalReference definition_handle = -1;
|
||||
util::ParsedRandomFloatRange radius = ::util::UniformFloatRange(-1.0f);
|
||||
util::UniformFloatRange radius = ::util::UniformFloatRange(-1.0f);
|
||||
float width = -1.0f;
|
||||
float height = -1.0f;
|
||||
util::ParsedRandomFloatRange lifetime = ::util::UniformFloatRange(-1.0f);
|
||||
util::UniformFloatRange lifetime = ::util::UniformFloatRange(-1.0f);
|
||||
bool random_rotation = false;
|
||||
};
|
||||
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
#include "shadows.sdr" //! #include "shadows.sdr"
|
||||
#include "lighting.sdr" //! #include "lighting.sdr"
|
||||
#include "gamma.sdr" //! #include "gamma.sdr"
|
||||
#include "model_shader_flags.h"
|
||||
|
||||
#conditional_include +"LARGE_SHADER" "main_large.sdr"
|
||||
#conditional_include -"LARGE_SHADER" "main_small.sdr"
|
||||
|
||||
#define MAX_LIGHTS 8
|
||||
#define LT_DIRECTIONAL 0
|
||||
@@ -97,56 +96,30 @@ layout (std140) uniform modelData {
|
||||
};
|
||||
|
||||
in VertexOutput {
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
|
||||
vec3 envReflect;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
|
||||
|
||||
mat3 tangentMatrix;
|
||||
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
|
||||
float fogDist;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
|
||||
|
||||
vec4 position;
|
||||
vec3 normal;
|
||||
vec4 texCoord;
|
||||
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
|
||||
vec4 shadowUV[4];
|
||||
vec4 shadowPos;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
|
||||
} vertIn;
|
||||
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_DIFFUSE
|
||||
uniform sampler2DArray sBasemap;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_DIFFUSE
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_GLOW
|
||||
uniform sampler2DArray sGlowmap;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_GLOW
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SPEC
|
||||
uniform sampler2DArray sSpecmap;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SPEC
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
|
||||
uniform samplerCube sEnvmap;
|
||||
uniform samplerCube sIrrmap;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_NORMAL
|
||||
uniform sampler2DArray sNormalmap;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_NORMAL
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_AMBIENT
|
||||
uniform sampler2DArray sAmbientmap;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_AMBIENT
|
||||
uniform sampler2D sFramebuffer;
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_MISC
|
||||
uniform sampler2DArray sMiscmap;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_MISC
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
|
||||
uniform sampler2DArray shadow_map;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
|
||||
|
||||
out vec4 fragOut0;
|
||||
|
||||
#ifndef MODEL_SDR_FLAG_SHADOW_MAP
|
||||
#ifndef FLAG_SHADOW_MAP
|
||||
out vec4 fragOut1;
|
||||
out vec4 fragOut2;
|
||||
out vec4 fragOut3;
|
||||
@@ -212,7 +185,7 @@ vec3 CalculateLighting(vec3 normal, vec3 diffuseMaterial, vec3 specularMaterial,
|
||||
|
||||
void main()
|
||||
{
|
||||
#ifdef MODEL_SDR_FLAG_SHADOW_MAP
|
||||
#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);
|
||||
|
||||
@@ -232,13 +205,13 @@ void main()
|
||||
vec3 unitNormal = normalize(vertIn.normal);
|
||||
vec3 normal = unitNormal;
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_AMBIENT
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_AMBIENT)) {
|
||||
// red channel is ambient occlusion factor which only affects ambient lighting.
|
||||
// green is cavity occlusion factor which only affects diffuse and specular lighting.
|
||||
aoFactors = texture(sAmbientmap, vec3(texCoord, float(sAmbientmapIndex))).xy;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_AMBIENT
|
||||
}
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_NORMAL
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_NORMAL)) {
|
||||
// Normal map - convert from DXT5nm
|
||||
vec2 normalSample;
|
||||
normal.rg = normalSample = (texture(sNormalmap, vec3(texCoord, float(sNormalmapIndex))).ag * 2.0) - 1.0;
|
||||
@@ -250,7 +223,7 @@ void main()
|
||||
normal /= norm;
|
||||
else
|
||||
normal = unitNormal;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_NORMAL
|
||||
}
|
||||
|
||||
vec2 distort = vec2(0.0, 0.0);
|
||||
|
||||
@@ -258,26 +231,26 @@ void main()
|
||||
distort = vec2(cos(vertIn.position.x*vertIn.position.w*0.005+anim_timer*20.0)*sin(vertIn.position.y*vertIn.position.w*0.005),sin(vertIn.position.x*vertIn.position.w*0.005+anim_timer*20.0)*cos(vertIn.position.y*vertIn.position.w*0.005))*0.03;
|
||||
}
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_DIFFUSE
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_DIFFUSE)) {
|
||||
vec2 diffuseTexCoord = texCoord;
|
||||
if (effect_num == 2) {
|
||||
diffuseTexCoord = texCoord + distort*(1.0-anim_timer);
|
||||
}
|
||||
baseColor = texture(sBasemap, vec3(diffuseTexCoord, float(sBasemapIndex)));
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_HDR
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
|
||||
baseColor.rgb = srgb_to_linear(baseColor.rgb);
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_HDR
|
||||
}
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_ALPHA_MULT
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ALPHA_MULT)) {
|
||||
baseColor.a *= alphaMult;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ALPHA_MULT
|
||||
}
|
||||
|
||||
if ( blend_alpha == 0 && baseColor.a < 0.95 ) discard; // if alpha blending is not on, discard transparent pixels
|
||||
// premultiply alpha if blend_alpha is 1. assume that our blend function is srcColor + (1-Alpha)*destColor.
|
||||
// if blend_alpha is 2, assume blend func is additive and don't modify color
|
||||
if(blend_alpha == 1) baseColor.rgb = baseColor.rgb * baseColor.a;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DIFFUSE
|
||||
}
|
||||
|
||||
// Anti-glint "trick" based on Valve's "Advanced VR Rendering" talk at GDC2015:
|
||||
// http://media.steampowered.com/apps/valve/2015/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf Page 43
|
||||
@@ -290,22 +263,21 @@ void main()
|
||||
// Now that we have a base color and min gloss value, compute the spec color
|
||||
vec4 specColor = vec4(baseColor.rgb * SPEC_FACTOR_NO_SPEC_MAP, glossData);
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_SPEC
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SPEC)) {
|
||||
specColor = texture(sSpecmap, vec3(texCoord, float(sSpecmapIndex)));
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_ALPHA_MULT
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ALPHA_MULT)) {
|
||||
specColor *= alphaMult;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ALPHA_MULT
|
||||
|
||||
}
|
||||
if(alphaGloss) glossData = specColor.a;
|
||||
if(gammaSpec) {
|
||||
specColor.rgb = max(specColor.rgb, vec3(0.03f)); // hardcoded minimum specular value. read John Hable's blog post titled 'Everything Is Shiny'.
|
||||
fresnelFactor = 1.0;
|
||||
}
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_HDR
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
|
||||
specColor.rgb = srgb_to_linear(specColor.rgb);
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_HDR
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SPEC
|
||||
}
|
||||
}
|
||||
|
||||
baseColor.rgb *= aoFactors.y;
|
||||
specColor.rgb *= aoFactors.y;
|
||||
@@ -313,8 +285,8 @@ void main()
|
||||
vec4 teamMask = vec4(0.0);
|
||||
vec3 team_color_glow = vec3(0.0);
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_MISC
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_TEAMCOLOR
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_MISC)) {
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_TEAMCOLOR)) {
|
||||
teamMask = texture(sMiscmap, vec3(texCoord, float(sMiscmapIndex)));
|
||||
|
||||
//For team colors applied to a diffuse or spec map, we assume that the base color of the diffuse
|
||||
@@ -324,52 +296,52 @@ void main()
|
||||
vec3 team_color = base_color * teamMask.x + stripe_color * teamMask.y + color_offset;
|
||||
team_color_glow = (base_color * teamMask.b) + (stripe_color * teamMask.a);
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_HDR
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
|
||||
baseColor.rgb = linear_to_srgb(baseColor.rgb);
|
||||
specColor.rgb = linear_to_srgb(specColor.rgb);
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_HDR
|
||||
}
|
||||
|
||||
baseColor.rgb += team_color;
|
||||
baseColor.rgb = max(baseColor.rgb, vec3(0.0)); // We need to make sure that nothing here ever goes negative
|
||||
specColor.rgb += team_color;
|
||||
specColor.rgb = max(specColor.rgb, vec3(0.03));
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_HDR
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
|
||||
baseColor.rgb = srgb_to_linear(baseColor.rgb);
|
||||
specColor.rgb = srgb_to_linear(specColor.rgb);
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_HDR
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_TEAMCOLOR
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_MISC
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Lights aren't applied when we are rendering to the G-buffers since that gets handled later
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_DEFERRED
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_LIGHT
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_DEFERRED)) {
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_LIGHT)) {
|
||||
// Ambient lighting still needs to be done since that counts as an "emissive" color
|
||||
vec3 lightAmbient = (emissionFactor + ambientFactor * ambientFactor) * aoFactors.x; // ambientFactor^2 due to legacy OpenGL compatibility behavior
|
||||
emissiveColor.rgb += baseColor.rgb * lightAmbient;
|
||||
#prereplace ELSE_FLAG //MODEL_SDR_FLAG_LIGHT
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_SPEC
|
||||
} else {
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SPEC)) {
|
||||
baseColor.rgb += pow(1.0 - clamp(dot(eyeDir, normal), 0.0, 1.0), 5.0 * clamp(glossData, 0.01, 1.0)) * specColor.rgb;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SPEC
|
||||
}
|
||||
// If there is no lighting then we copy the color data so far into the
|
||||
emissiveColor.rgb += baseColor.rgb;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT
|
||||
#prereplace ELSE_FLAG //MODEL_SDR_FLAG_DEFERRED
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_LIGHT
|
||||
}
|
||||
} else {
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_LIGHT)) {
|
||||
float shadow = 1.0;
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_SHADOWS
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SHADOWS)) {
|
||||
shadow = getShadowValue(shadow_map, -vertIn.position.z, vertIn.shadowPos.z, vertIn.shadowUV, fardist, middist, neardist, veryneardist);
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SHADOWS
|
||||
}
|
||||
baseColor.rgb = CalculateLighting(normal, baseColor.rgb, specColor.rgb, glossData, fresnelFactor, shadow, aoFactors.x);
|
||||
#prereplace ELSE_FLAG //MODEL_SDR_FLAG_LIGHT
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_SPEC
|
||||
} else {
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SPEC)) {
|
||||
baseColor.rgb += pow(1.0 - clamp(dot(eyeDir, normal), 0.0, 1.0), 5.0 * clamp(glossData, 0.01, 1.0)) * specColor.rgb;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SPEC
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DEFERRED
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_ENV
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_LIGHT
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ENV)) {
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_LIGHT)) {
|
||||
// Bit of a hack here, pretend we're doing blinn-phong shading and use a (modified version of) the derivation from
|
||||
// Plausible Blinn-Phong Reflection of Standard Cube MIP-Maps - McGuire et al.
|
||||
// to determine the mip bias.
|
||||
@@ -413,48 +385,48 @@ void main()
|
||||
vec3 diffEnvColor = srgb_to_linear(texture(sIrrmap, vec3(envMatrix * vec4(normal, 0.0))).rgb);
|
||||
vec3 diffEnvLighting = kD * baseColor.rgb * diffEnvColor * aoFactors.x;
|
||||
emissiveColor.rgb += (specEnvLighting + diffEnvLighting) * baseColor.a;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ENV
|
||||
}
|
||||
}
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_GLOW
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_GLOW)) {
|
||||
vec3 glowColor = texture(sGlowmap, vec3(texCoord, float(sGlowmapIndex))).rgb;
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_MISC
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_TEAMCOLOR
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_MISC)) {
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_TEAMCOLOR)) {
|
||||
float glowColorLuminance = dot(glowColor, vec3(0.299, 0.587, 0.114));
|
||||
glowColor = team_glow_enabled ? mix(max(team_color_glow, vec3(0.0)), glowColor, clamp(glowColorLuminance - teamMask.b - teamMask.a, 0.0, 1.0)) : glowColor;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_TEAMCOLOR
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_MISC
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_HDR
|
||||
}
|
||||
}
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
|
||||
glowColor = srgb_to_linear(glowColor) * GLOW_MAP_SRGB_MULTIPLIER;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_HDR
|
||||
}
|
||||
emissiveColor.rgb += glowColor * GLOW_MAP_INTENSITY;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_GLOW
|
||||
}
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_ALPHA_MULT
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ALPHA_MULT)) {
|
||||
//Since this is emissive, we need to premultiply it for intensity, and apply alpha to not replace existing emissive
|
||||
emissiveColor *= alphaMult;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ALPHA_MULT
|
||||
}
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_FOG
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_FOG)) {
|
||||
vec3 finalFogColor = fogColor.rgb;
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_HDR
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_HDR)) {
|
||||
finalFogColor = srgb_to_linear(finalFogColor);
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_HDR
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_DIFFUSE
|
||||
}
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_DIFFUSE)) {
|
||||
if(blend_alpha == 1) finalFogColor *= baseColor.a;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DIFFUSE
|
||||
}
|
||||
// This code will only be used by the forward renderer so we apply the fog effect to both the emissive and the base
|
||||
// color.
|
||||
baseColor.rgb = mix(emissiveColor.rgb + baseColor.rgb, finalFogColor, vertIn.fogDist);
|
||||
emissiveColor.rgb = vec3(0.0); // Zero the emissive color since it has already been added by the previous line
|
||||
specColor.rgb *= vertIn.fogDist;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_FOG
|
||||
}
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_DIFFUSE
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_DIFFUSE)) {
|
||||
if(desaturate == 1) {
|
||||
baseColor.rgb = color.rgb * dot(vec3(1.0), baseColor.rgb) * 0.3333333;
|
||||
}
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DIFFUSE
|
||||
}
|
||||
|
||||
if (effect_num == 0) {
|
||||
float shinefactor = 1.0/(1.0 + pow(abs((fract(abs(texCoord.x))-anim_timer) * 1000.0), 2.0)) * 1000.0;
|
||||
@@ -463,34 +435,33 @@ void main()
|
||||
} else if (effect_num == 1) {
|
||||
float shinefactor = 1.0/(1.0 + pow(abs(vertIn.position.y-anim_timer), 2.0));
|
||||
emissiveColor.rgb += vec3(shinefactor);
|
||||
#prereplace IF_NOT_FLAG MODEL_SDR_FLAG_LIGHT
|
||||
if (!(FLAG_ACTIVE(MODEL_SDR_FLAG_LIGHT))) {
|
||||
// ATI Wireframe fix *grumble*
|
||||
baseColor.a = clamp((vertIn.position.y-anim_timer) * 10000.0,0.0,1.0);
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT
|
||||
}
|
||||
} else if (effect_num == 2) {
|
||||
vec2 screenPos = gl_FragCoord.xy * vec2(vpwidth,vpheight);
|
||||
baseColor.a = baseColor.a;
|
||||
float cloak_interp = (sin(vertIn.position.x*vertIn.position.w*0.005+anim_timer*20.0)*sin(vertIn.position.y*vertIn.position.w*0.005)*0.5)-0.5;
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_LIGHT
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_LIGHT)) {
|
||||
baseColor.rgb = mix(texture(sFramebuffer, screenPos + distort*anim_timer + anim_timer*0.1*normal.xy).rgb,baseColor.rgb,clamp(cloak_interp+anim_timer*2.0,0.0,1.0));
|
||||
#prereplace ELSE_FLAG //MODEL_SDR_FLAG_LIGHT
|
||||
} else {
|
||||
baseColor.rgb = mix(texture(sFramebuffer, screenPos + distort*anim_timer + anim_timer*0.1*vertIn.normal.xy).rgb,baseColor.rgb,clamp(cloak_interp+anim_timer*2.0,0.0,1.0));
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_LIGHT
|
||||
}
|
||||
}
|
||||
|
||||
#prereplace IF_NOT_FLAG MODEL_SDR_FLAG_DEFERRED
|
||||
if (!(FLAG_ACTIVE(MODEL_SDR_FLAG_DEFERRED))) {
|
||||
// emissive colors won't be added later when we are using forward rendering so we need to do that here
|
||||
baseColor.rgb += emissiveColor.rgb;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DEFERRED
|
||||
}
|
||||
|
||||
fragOut0 = baseColor;
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_DEFERRED
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_DEFERRED)) {
|
||||
fragOut1 = vec4(vertIn.position.xyz, 1.0);
|
||||
fragOut2 = vec4(normal, glossData);
|
||||
fragOut3 = vec4(specColor.rgb, fresnelFactor);
|
||||
fragOut4 = emissiveColor;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_DEFERRED
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,18 +1,17 @@
|
||||
#extension GL_ARB_gpu_shader5: enable
|
||||
|
||||
#conditional_include +"LARGE_SHADER" "main_large.sdr"
|
||||
#conditional_include -"LARGE_SHADER" "main_small.sdr"
|
||||
#include "model_shader_flags.h"
|
||||
|
||||
#ifdef MODEL_SDR_FLAG_THICK_OUTLINES
|
||||
#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;
|
||||
#elif defined(MODEL_SDR_FLAG_SHADOW_MAP)
|
||||
#elif defined(FLAG_SHADOW_MAP)
|
||||
layout (triangles) in;
|
||||
layout (triangle_strip, max_vertices = 3) out;
|
||||
#endif
|
||||
|
||||
#ifdef MODEL_SDR_FLAG_SHADOW_MAP
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
#ifdef GL_ARB_gpu_shader5
|
||||
layout(invocations = 4) in;
|
||||
#endif
|
||||
@@ -103,17 +102,11 @@ layout (std140) uniform modelData {
|
||||
};
|
||||
|
||||
in VertexOutput {
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
|
||||
vec3 envReflect;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
|
||||
|
||||
mat3 tangentMatrix;
|
||||
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
|
||||
float fogDist;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
|
||||
|
||||
#ifdef MODEL_SDR_FLAG_SHADOW_MAP
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
#if !defined(GL_ARB_gpu_shader5)
|
||||
float instance;
|
||||
#endif
|
||||
@@ -123,35 +116,22 @@ in VertexOutput {
|
||||
#endif
|
||||
vec3 normal;
|
||||
vec4 texCoord;
|
||||
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
|
||||
vec4 shadowUV[4];
|
||||
vec4 shadowPos;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
|
||||
} vertIn[];
|
||||
|
||||
out VertexOutput {
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
|
||||
vec3 envReflect;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
|
||||
|
||||
mat3 tangentMatrix;
|
||||
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
|
||||
float fogDist;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
|
||||
|
||||
vec4 position;
|
||||
vec3 normal;
|
||||
vec4 texCoord;
|
||||
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
|
||||
vec4 shadowUV[4];
|
||||
vec4 shadowPos;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
|
||||
} vertOut;
|
||||
|
||||
#ifdef MODEL_SDR_FLAG_SHADOW_MAP
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
void main(void)
|
||||
{
|
||||
#ifdef GL_ARB_gpu_shader5
|
||||
@@ -161,17 +141,16 @@ out VertexOutput {
|
||||
#endif
|
||||
for(int vert = 0; vert < gl_in.length(); vert++)
|
||||
{
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_TRANSFORM
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_TRANSFORM)) {
|
||||
if (vertIn[vert].clipModel > 0.9) {
|
||||
// If the model was clipped in the vertex shader then we do not apply the shadow projection matrix here
|
||||
gl_Position = gl_in[vert].gl_Position;
|
||||
} else {
|
||||
gl_Position = shadow_proj_matrix[instanceID] * gl_in[vert].gl_Position;
|
||||
}
|
||||
#prereplace ELSE_FLAG //MODEL_SDR_FLAG_TRANSFORM
|
||||
} else {
|
||||
gl_Position = shadow_proj_matrix[instanceID] * gl_in[vert].gl_Position;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_TRANSFORM
|
||||
|
||||
}
|
||||
if(gl_Position.z < -1.0)
|
||||
gl_Position.z = -1.0;
|
||||
|
||||
@@ -181,26 +160,22 @@ out VertexOutput {
|
||||
|
||||
gl_Layer = instanceID;
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_ENV
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ENV)) {
|
||||
vertOut.envReflect = vertIn[vert].envReflect;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ENV
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_NORMAL
|
||||
}
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_NORMAL)) {
|
||||
vertOut.tangentMatrix = vertIn[vert].tangentMatrix;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_NORMAL
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_FOG
|
||||
}
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_FOG)) {
|
||||
vertOut.fogDist = vertIn[vert].fogDist;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_FOG
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_SHADOWS
|
||||
}
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SHADOWS)) {
|
||||
vertOut.shadowUV[0] = vertIn[vert].shadowUV[0];
|
||||
vertOut.shadowUV[1] = vertIn[vert].shadowUV[1];
|
||||
vertOut.shadowUV[2] = vertIn[vert].shadowUV[2];
|
||||
vertOut.shadowUV[3] = vertIn[vert].shadowUV[3];
|
||||
vertOut.shadowPos = vertIn[vert].shadowPos;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SHADOWS
|
||||
|
||||
}
|
||||
if (use_clip_plane) {
|
||||
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
|
||||
}
|
||||
@@ -208,7 +183,7 @@ out VertexOutput {
|
||||
}
|
||||
EndPrimitive();
|
||||
}
|
||||
#elif defined(MODEL_SDR_FLAG_THICK_OUTLINES)
|
||||
#elif defined(FLAG_THICK_OUTLINE)
|
||||
const vec2 pixelOffsetDir[4] = vec2[](
|
||||
vec2(0.0, 1.0),
|
||||
vec2(1.0, 1.0),
|
||||
@@ -239,26 +214,22 @@ out VertexOutput {
|
||||
vertOut.normal = vertIn[vert].normal;
|
||||
vertOut.texCoord = vertIn[vert].texCoord;
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_ENV
|
||||
vertOut.envReflect = vertIn[vert].envReflect;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ENV
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_NORMAL
|
||||
vertOut.tangentMatrix = vertIn[vert].tangentMatrix;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_NORMAL
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_FOG
|
||||
vertOut.fogDist = vertIn[vert].fogDist;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_FOG
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_SHADOWS
|
||||
vertOut.shadowUV[0] = vertIn[vert].shadowUV[0];
|
||||
vertOut.shadowUV[1] = vertIn[vert].shadowUV[1];
|
||||
vertOut.shadowUV[2] = vertIn[vert].shadowUV[2];
|
||||
vertOut.shadowUV[3] = vertIn[vert].shadowUV[3];
|
||||
vertOut.shadowPos = vertIn[vert].shadowPos;
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SHADOWS
|
||||
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ENV)) {
|
||||
vertOut.envReflect = vertIn[vert].envReflect;
|
||||
}
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_NORMAL)) {
|
||||
vertOut.tangentMatrix = vertIn[vert].tangentMatrix;
|
||||
}
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_FOG)) {
|
||||
vertOut.fogDist = vertIn[vert].fogDist;
|
||||
}
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SHADOWS)) {
|
||||
vertOut.shadowUV[0] = vertIn[vert].shadowUV[0];
|
||||
vertOut.shadowUV[1] = vertIn[vert].shadowUV[1];
|
||||
vertOut.shadowUV[2] = vertIn[vert].shadowUV[2];
|
||||
vertOut.shadowUV[3] = vertIn[vert].shadowUV[3];
|
||||
vertOut.shadowPos = vertIn[vert].shadowPos;
|
||||
}
|
||||
if (use_clip_plane) {
|
||||
gl_ClipDistance[0] = gl_in[vert].gl_ClipDistance[0];
|
||||
}
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
#extension GL_ARB_gpu_shader5: enable
|
||||
|
||||
#include "shadows.sdr"
|
||||
|
||||
#conditional_include +"LARGE_SHADER" "main_large.sdr"
|
||||
#conditional_include -"LARGE_SHADER" "main_small.sdr"
|
||||
#include "model_shader_flags.h"
|
||||
|
||||
in vec4 vertPosition;
|
||||
in vec4 vertTexCoord;
|
||||
@@ -97,22 +95,13 @@ layout (std140) uniform modelData {
|
||||
int flags;
|
||||
};
|
||||
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_TRANSFORM
|
||||
uniform samplerBuffer transform_tex;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_TRANSFORM
|
||||
|
||||
out VertexOutput {
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
|
||||
vec3 envReflect;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_ENV
|
||||
|
||||
mat3 tangentMatrix;
|
||||
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
|
||||
float fogDist;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
|
||||
|
||||
#ifdef MODEL_SDR_FLAG_SHADOW_MAP
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
#if !defined(GL_ARB_gpu_shader5)
|
||||
float instance;
|
||||
#endif
|
||||
@@ -124,15 +113,11 @@ out VertexOutput {
|
||||
#endif
|
||||
vec3 normal;
|
||||
vec4 texCoord;
|
||||
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
|
||||
vec4 shadowUV[4];
|
||||
vec4 shadowPos;
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
|
||||
} vertOut;
|
||||
|
||||
#define TEXELS_PER_MATRIX 4
|
||||
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_TRANSFORM
|
||||
void getModelTransform(inout mat4 transform, out bool invisible, int id, int matrix_offset)
|
||||
{
|
||||
transform[0] = texelFetch(transform_tex, (matrix_offset + id) * TEXELS_PER_MATRIX);
|
||||
@@ -142,7 +127,6 @@ void getModelTransform(inout mat4 transform, out bool invisible, int id, int mat
|
||||
invisible = transform[3].w >= 0.9;
|
||||
transform[3].w = 1.0;
|
||||
}
|
||||
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_TRANSFORM
|
||||
|
||||
void main()
|
||||
{
|
||||
@@ -153,21 +137,20 @@ void main()
|
||||
mat4 scale = mat4(1.0);
|
||||
bool clipModel = false;
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_TRANSFORM
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_TRANSFORM)) {
|
||||
getModelTransform(orient, clipModel, int(vertModelID), buffer_matrix_offset);
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_TRANSFORM
|
||||
|
||||
}
|
||||
texCoord = textureMatrix * vertTexCoord;
|
||||
vec4 vertex = vertPosition;
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_THRUSTER
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_THRUSTER)) {
|
||||
if(vertex.z < -1.5) {
|
||||
vertex.z *= thruster_scale;
|
||||
}
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_THRUSTER
|
||||
}
|
||||
// Transform the normal into eye space and normalize the result.
|
||||
normal = normalize(mat3(modelViewMatrix) * mat3(orient) * vertNormal);
|
||||
position = modelViewMatrix * orient * vertex;
|
||||
#ifdef MODEL_SDR_FLAG_SHADOW_MAP
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
gl_Position = position;
|
||||
#if !defined(GL_ARB_gpu_shader5)
|
||||
#ifdef APPLE
|
||||
@@ -179,39 +162,37 @@ void main()
|
||||
#else
|
||||
gl_Position = projMatrix * position;
|
||||
#endif
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_SHADOWS
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_SHADOWS)) {
|
||||
vec4 shadowPos = shadow_mv_matrix * modelMatrix * orient * vertPosition;
|
||||
vertOut.shadowPos = shadow_mv_matrix * modelMatrix * orient * vertPosition;
|
||||
vertOut.shadowUV[0] = transformToShadowMap(shadow_proj_matrix[0], 0, shadowPos);
|
||||
vertOut.shadowUV[1] = transformToShadowMap(shadow_proj_matrix[1], 1, shadowPos);
|
||||
vertOut.shadowUV[2] = transformToShadowMap(shadow_proj_matrix[2], 2, shadowPos);
|
||||
vertOut.shadowUV[3] = transformToShadowMap(shadow_proj_matrix[3], 3, shadowPos);
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SHADOWS
|
||||
}
|
||||
|
||||
// Setup stuff for normal maps and envmaps
|
||||
vec3 t = normalize(mat3(modelViewMatrix) * mat3(orient) * vertTangent.xyz);
|
||||
vec3 b = cross(normal, t) * vertTangent.w;
|
||||
vertOut.tangentMatrix = mat3(t, b, normal);
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_ENV
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_ENV)) {
|
||||
// Environment mapping reflection vector.
|
||||
vec3 envReflect = reflect(normalize(position.xyz), normal);
|
||||
vertOut.envReflect = vec3(envMatrix * vec4(envReflect, 0.0));
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_ENV
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_FOG
|
||||
}
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_FOG)) {
|
||||
vertOut.fogDist = clamp((gl_Position.z - fogStart) * 0.75 * fogScale, 0.0, 1.0);
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_FOG
|
||||
|
||||
#prereplace IF_FLAG MODEL_SDR_FLAG_TRANSFORM
|
||||
}
|
||||
if (FLAG_ACTIVE(MODEL_SDR_FLAG_TRANSFORM)) {
|
||||
if (clipModel) {
|
||||
// Clip this model by moving all vertices outside the clip volume
|
||||
gl_Position = vec4(vec3(-2.0), 1.0);
|
||||
}
|
||||
#ifdef MODEL_SDR_FLAG_SHADOW_MAP
|
||||
#ifdef FLAG_SHADOW_MAP
|
||||
vertOut.clipModel = clipModel ? 1.0 : 0.0;
|
||||
#endif
|
||||
#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_TRANSFORM
|
||||
}
|
||||
|
||||
if(use_clip_plane) {
|
||||
gl_ClipDistance[0] = dot(clip_equation, modelMatrix * orient * vertex);
|
||||
@@ -219,7 +200,7 @@ void main()
|
||||
gl_ClipDistance[0] = 1.0;
|
||||
}
|
||||
|
||||
#ifndef MODEL_SDR_FLAG_SHADOW_MAP
|
||||
#ifndef FLAG_SHADOW_MAP
|
||||
vertOut.position = position;
|
||||
vertOut.normal = normal;
|
||||
vertOut.texCoord = texCoord;
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
#predefine IF_FLAG if ((flags & %s) != 0) {
|
||||
#predefine IF_NOT_FLAG if ((flags & %s) == 0) {
|
||||
#predefine ELSE_FLAG } else { %s
|
||||
#predefine ENDIF_FLAG } %s
|
||||
#predefine IF_FLAG_COMPILED //if true %s
|
||||
#predefine ENDIF_FLAG_COMPILED //endif true %s
|
||||
|
||||
#define MODEL_SDR_FLAG_MODE_GLSL 1
|
||||
#include "model_shader_flags.h"
|
||||
@@ -1,6 +0,0 @@
|
||||
#predefine IF_FLAG #ifdef %s
|
||||
#predefine IF_NOT_FLAG #ifndef %s
|
||||
#predefine ELSE_FLAG #else //%s
|
||||
#predefine ENDIF_FLAG #endif //%s
|
||||
#predefine IF_FLAG_COMPILED #ifdef %s
|
||||
#predefine ENDIF_FLAG_COMPILED #endif //%s
|
||||
@@ -1,35 +1,19 @@
|
||||
#ifdef MODEL_SDR_FLAG_MODE_CPP
|
||||
#define SDR_FLAG(name, value, geoshader) constexpr int name = value;
|
||||
#elif defined MODEL_SDR_FLAG_MODE_CPP_ARRAY
|
||||
#define SDR_FLAG(name, value, geoshader) {SDR_TYPE_MODEL, geoshader, value, #name, {}, #name},
|
||||
#elif defined MODEL_SDR_FLAG_MODE_GLSL
|
||||
#define SDR_FLAG(name, value, geoshader) const int name = value;
|
||||
#else
|
||||
#error Make sure to properly define the usage mode for this file!
|
||||
#endif
|
||||
#define MODEL_SDR_FLAG_LIGHT (1 << 0)
|
||||
#define MODEL_SDR_FLAG_DEFERRED (1 << 1)
|
||||
#define MODEL_SDR_FLAG_HDR (1 << 2)
|
||||
#define MODEL_SDR_FLAG_DIFFUSE (1 << 3)
|
||||
#define MODEL_SDR_FLAG_GLOW (1 << 4)
|
||||
#define MODEL_SDR_FLAG_SPEC (1 << 5)
|
||||
#define MODEL_SDR_FLAG_ENV (1 << 6)
|
||||
#define MODEL_SDR_FLAG_NORMAL (1 << 7)
|
||||
#define MODEL_SDR_FLAG_AMBIENT (1 << 8)
|
||||
#define MODEL_SDR_FLAG_MISC (1 << 9)
|
||||
#define MODEL_SDR_FLAG_TEAMCOLOR (1 << 10)
|
||||
#define MODEL_SDR_FLAG_FOG (1 << 11)
|
||||
#define MODEL_SDR_FLAG_TRANSFORM (1 << 12)
|
||||
#define MODEL_SDR_FLAG_SHADOWS (1 << 13)
|
||||
#define MODEL_SDR_FLAG_THRUSTER (1 << 14)
|
||||
#define MODEL_SDR_FLAG_ALPHA_MULT (1 << 15)
|
||||
|
||||
SDR_FLAG(MODEL_SDR_FLAG_LIGHT , (1 << 0) , false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_DEFERRED , (1 << 1) , false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_HDR , (1 << 2) , false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_DIFFUSE , (1 << 3) , false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_GLOW , (1 << 4) , false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_SPEC , (1 << 5) , false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_ENV , (1 << 6) , false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_NORMAL , (1 << 7) , false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_AMBIENT , (1 << 8) , false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_MISC , (1 << 9) , false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_TEAMCOLOR , (1 << 10), false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_FOG , (1 << 11), false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_TRANSFORM , (1 << 12), false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_SHADOWS , (1 << 13), false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_THRUSTER , (1 << 14), false)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_ALPHA_MULT , (1 << 15), false)
|
||||
|
||||
#ifndef MODEL_SDR_FLAG_MODE_GLSL
|
||||
//The following ones are used ONLY as compile-time flags, but they still need to be defined here to ensure no conflict occurs
|
||||
//But since these are checked with ifdefs even for the large shader, they must never be available in GLSL mode
|
||||
|
||||
SDR_FLAG(MODEL_SDR_FLAG_SHADOW_MAP , (1 << 16), true)
|
||||
SDR_FLAG(MODEL_SDR_FLAG_THICK_OUTLINES, (1 << 17), true)
|
||||
|
||||
#endif
|
||||
#define FLAG_ACTIVE(flag) (flags & flag) != 0
|
||||
@@ -174,8 +174,7 @@ void main()
|
||||
for(int i = 0; i < samples; i++) {
|
||||
vec4 localPos = texelFetch(texPos, texel, i);
|
||||
//Calculate local weight from distance Voxel, but if the distance is 0 (i.e. no model at all), set weight to 1 to allow stuff like background emissive
|
||||
//However, if the median distance is 0, only deal with current texel if it's local distance is 0 as well
|
||||
float localWeight = max(step(-0.001, dist) * step(-0.001, localPos.z),
|
||||
float localWeight = max(step(-0.001, dist),
|
||||
smoothstep(dist + dist * texelWidthFactor * (voxelDepth + voxelDepthFalloff), dist + dist * texelWidthFactor * voxelDepth, localPos.z) *
|
||||
smoothstep(dist - dist * texelWidthFactor * voxelDepth, dist + dist * texelWidthFactor * (voxelDepth + voxelDepthFalloff), localPos.z)
|
||||
);
|
||||
@@ -191,7 +190,7 @@ void main()
|
||||
|
||||
fragOut0 = color / weight;
|
||||
fragOut1 = pos / weight;
|
||||
fragOut2 = vec4(normalize(normal.xyz), normal.a / weight);
|
||||
fragOut2 = normalize(normal);
|
||||
fragOut3 = specular / weight;
|
||||
fragOut4 = emissive / weight;
|
||||
gl_FragDepth = depth / weight;
|
||||
|
||||
@@ -21,11 +21,9 @@ layout (std140) uniform genericData {
|
||||
vec3 globalLightDiffuse;
|
||||
float stepsize;
|
||||
vec3 nebPos;
|
||||
float opacitydistance;
|
||||
float globalstepalpha;
|
||||
vec3 nebSize;
|
||||
float alphalim;
|
||||
vec3 nebulaColor;
|
||||
float udfScale;
|
||||
float emissiveSpreadFactor;
|
||||
float emissiveIntensity;
|
||||
float emissiveFalloff;
|
||||
@@ -94,14 +92,12 @@ void main()
|
||||
|
||||
vec3 sidestep = 1.0 / vec3(textureSize(volume_tex, 0));
|
||||
|
||||
for(float stept = maxtMin; stept < mintMax;) {
|
||||
for(float stept = maxtMin; stept < mintMax; stept += stepsize) {
|
||||
//Step setup
|
||||
vec3 position = camera + rayDirection * stept - nebPos;
|
||||
vec3 sampleposition = position / nebSize + 0.5;
|
||||
vec4 volume_sample = textureGrad(volume_tex, sampleposition, gradX, gradY);
|
||||
|
||||
float stepsize_current = min(max(stepsize, volume_sample.x * udfScale), mintMax - stept);
|
||||
|
||||
#ifdef DO_EDGE_SMOOTHING
|
||||
//Average 3D texel with texels on corner, in an attempt to reduce jagged edges.
|
||||
float stepcolor_alpha = volume_sample.a;
|
||||
@@ -121,7 +117,7 @@ void main()
|
||||
float stepcolor_alpha = volume_sample.a;
|
||||
#endif
|
||||
|
||||
float stepalpha = -(pow(alphalim, 1.0 / (opacitydistance / stepsize_current)) - 1.0f) * stepcolor_alpha;
|
||||
float stepalpha = globalstepalpha * stepcolor_alpha;
|
||||
//All the following computations are just required if we have a stepcoloralpha that is non-zero.
|
||||
if(stepcolor_alpha > 0.01)
|
||||
{
|
||||
@@ -131,10 +127,10 @@ void main()
|
||||
//Diffuse
|
||||
#ifdef NOISE
|
||||
//Mix the actual nebula color with the noise color depending on the product of the noise channels multiplied with intensity, smooth-clamped from 0 to 1
|
||||
vec3 stepcolor_neb = mix(nebulaColor, noiseColor,
|
||||
vec3 stepcolor_neb = mix(volume_sample.rgb, noiseColor,
|
||||
smoothstep(0, 1, (textureGrad(noise_volume_tex, position / noiseColorScale1, gradX, gradY).r + textureGrad(noise_volume_tex, position / noiseColorScale2, gradX, gradY).g) / 2.0 * noiseIntensity));
|
||||
#else
|
||||
vec3 stepcolor_neb = nebulaColor;
|
||||
vec3 stepcolor_neb = volume_sample.rgb;
|
||||
#endif
|
||||
vec3 stepcolor_diffuse = stepcolor_neb * henyey_greenstein(dot(rayDirection, globalLightDirection));
|
||||
float directionalLightStep = 4.0 / float(directionalLightSampleSteps);
|
||||
@@ -149,17 +145,17 @@ void main()
|
||||
stepcolor_diffuse *= beer_powder_norm * (1 - exp(-directionalLightDepth * 2.0)) * exp(-directionalLightDepth);
|
||||
|
||||
//Emissive
|
||||
cumnebdist += stepcolor_alpha * stepsize_current;
|
||||
cumnebdist += stepcolor_alpha * stepsize;
|
||||
vec3 emissive_lod = textureLod(emissive, fragTexCoord.xy, clamp(cumnebdist * emissiveSpreadFactor, 0, float(textureQueryLevels(emissive) - 1))).rgb;
|
||||
vec3 stepcolor_emissive = emissive_lod.rgb * pow(alphalim, 1.0 / (opacitydistance / ((depth - stept) * emissiveFalloff + 0.01))) * emissiveIntensity;
|
||||
vec3 stepcolor_emissive = emissive_lod.rgb * pow(1 - globalstepalpha, (depth - stept) * emissiveFalloff) * emissiveIntensity;
|
||||
|
||||
//Step finish
|
||||
vec3 stepcolor = clamp(stepcolor_diffuse + stepcolor_emissive, 0, 1);
|
||||
float stepalpha = globalstepalpha * stepcolor_alpha;
|
||||
cumcolor += stepalpha * cumOMAlpha * stepcolor;
|
||||
}
|
||||
|
||||
cumOMAlpha *= 1.0 - stepalpha;
|
||||
stept += stepsize_current;
|
||||
|
||||
if(cumOMAlpha < alphalim)
|
||||
break;
|
||||
|
||||
@@ -8,9 +8,9 @@ $Fog:
|
||||
+Start dist: 10.0
|
||||
+Compl dist: 500.0
|
||||
$AI:
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Turrets attack this: YES
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Sentry Gun
|
||||
@@ -28,10 +28,10 @@ $Fog:
|
||||
$AI:
|
||||
+Accept Player Orders: NO
|
||||
+Auto attacks: YES
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Guards attack this: YES
|
||||
+Turrets attack this: YES
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Escape Pod
|
||||
@@ -48,9 +48,9 @@ $Fog:
|
||||
+Compl dist: 600.0
|
||||
$AI:
|
||||
+Valid goals: ( "fly to ship" "attack ship" "attack wing" "dock" "waypoints" "waypoints once" "depart" "undock" "stay still" "play dead" "play dead (persistent)" "stay near ship" )
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Turrets attack this: YES
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Cargo
|
||||
@@ -87,11 +87,37 @@ $AI:
|
||||
+Accept Player Orders: YES
|
||||
+Player orders: ( "rearm me" "abort rearm" "depart" )
|
||||
+Auto attacks: YES
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Guards attack this: YES
|
||||
+Turrets attack this: YES
|
||||
+Active docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
;;WMC - Stealth ships always have another type, so this isn't used
|
||||
$Name: Stealth
|
||||
$Counts for Alone: YES
|
||||
$Praise Destruction: YES
|
||||
$On Hotkey List: YES
|
||||
$Target as Threat: YES
|
||||
$Show Attack Direction: YES
|
||||
$Max Debris Speed: 200
|
||||
$FF Multiplier: 1.0
|
||||
$EMP Multiplier: 4.0
|
||||
$Protected on cripple: YES
|
||||
$Fog:
|
||||
+Start dist: 10.0
|
||||
+Compl dist: 500.0
|
||||
$AI:
|
||||
+Valid goals: ( "fly to ship" "attack ship" "waypoints" "waypoints once" "depart" "attack subsys" "attack wing" "guard ship" "disable ship" "disarm ship" "attack any" "attack ship class" "ignore ship" "ignore ship (new)" "guard wing" "evade ship" "stay still" "play dead" "play dead (persistent)" "stay near ship" "keep safe dist" )
|
||||
+Accept Player Orders: YES
|
||||
+Player Orders: ( "attack ship" "disable ship" "disarm ship" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "depart" "disable subsys" )
|
||||
+Auto attacks: YES
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Guards attack this: YES
|
||||
+Turrets attack this: YES
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Fighter
|
||||
@@ -110,16 +136,16 @@ $Fog:
|
||||
+Start dist: 10.0
|
||||
+Compl dist: 500.0
|
||||
$AI:
|
||||
+Valid goals: ( "fly to ship" "attack ship" "waypoints" "waypoints once" "depart" "attack subsys" "attack wing" "guard ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "attack any" "attack ship class" "ignore ship" "ignore ship (new)" "guard wing" "evade ship" "stay still" "play dead" "play dead (persistent)" "stay near ship" "keep safe dist" "form on wing")
|
||||
+Valid goals: ( "fly to ship" "attack ship" "waypoints" "waypoints once" "depart" "attack subsys" "attack wing" "guard ship" "disable ship" "disarm ship" "attack any" "attack ship class" "ignore ship" "ignore ship (new)" "guard wing" "evade ship" "stay still" "play dead" "play dead (persistent)" "stay near ship" "keep safe dist" "form on wing")
|
||||
+Accept Player Orders: YES
|
||||
+Player Orders: ( "attack ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "attack ship class" "depart" "disable subsys" )
|
||||
+Player Orders: ( "attack ship" "disable ship" "disarm ship" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "depart" "disable subsys" )
|
||||
+Auto attacks: YES
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Guards attack this: YES
|
||||
+Turrets attack this: YES
|
||||
+Can Form Wing: YES
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Bomber
|
||||
@@ -138,16 +164,16 @@ $Fog:
|
||||
+Start dist: 10.0
|
||||
+Compl dist: 500.0
|
||||
$AI:
|
||||
+Valid goals: ( "fly to ship" "attack ship" "waypoints" "waypoints once" "depart" "attack subsys" "attack wing" "guard ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "attack any" "attack ship class" "ignore ship" "ignore ship (new)" "guard wing" "evade ship" "stay still" "play dead" "play dead (persistent)" "stay near ship" "keep safe dist" "form on wing" )
|
||||
+Valid goals: ( "fly to ship" "attack ship" "waypoints" "waypoints once" "depart" "attack subsys" "attack wing" "guard ship" "disable ship" "disarm ship" "attack any" "attack ship class" "ignore ship" "ignore ship (new)" "guard wing" "evade ship" "stay still" "play dead" "play dead (persistent)" "stay near ship" "keep safe dist" "form on wing" )
|
||||
+Accept Player Orders: YES
|
||||
+Player Orders: ( "attack ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "attack ship class" "depart" "disable subsys" )
|
||||
+Player Orders: ( "attack ship" "disable ship" "disarm ship" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "depart" "disable subsys" )
|
||||
+Auto attacks: YES
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Guards attack this: YES
|
||||
+Turrets attack this: YES
|
||||
+Can Form Wing: YES
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
;;WMC - This fighter/bomber type doesn't seem to be used anywhere, because no ship is set as both fighter and bomber
|
||||
@@ -166,16 +192,16 @@ $Fog:
|
||||
+Start dist: 10.0
|
||||
+Compl dist: 500.0
|
||||
$AI:
|
||||
+Valid goals: ( "fly to ship" "attack ship" "waypoints" "waypoints once" "depart" "attack subsys" "attack wing" "guard ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "attack any" "attack ship class" "ignore ship" "ignore ship (new)" "guard wing" "evade ship" "stay still" "play dead" "play dead (persistent)" "stay near ship" "keep safe dist" "form on wing" )
|
||||
+Valid goals: ( "fly to ship" "attack ship" "waypoints" "waypoints once" "depart" "attack subsys" "attack wing" "guard ship" "disable ship" "disarm ship" "attack any" "attack ship class" "ignore ship" "ignore ship (new)" "guard wing" "evade ship" "stay still" "play dead" "play dead (persistent)" "stay near ship" "keep safe dist" "form on wing" )
|
||||
+Accept Player Orders: YES
|
||||
+Player Orders: ( "attack ship" "disable ship" "disable ship (tactical)" "disarm ship" "disarm ship (tactical)" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "attack ship class" "depart" "disable subsys" )
|
||||
+Player Orders: ( "attack ship" "disable ship" "disarm ship" "guard ship" "ignore ship" "ignore ship (new)" "form on wing" "cover me" "attack any" "depart" "disable subsys" )
|
||||
+Auto attacks: YES
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Actively Pursues: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Guards attack this: YES
|
||||
+Turrets attack this: YES
|
||||
+Can Form Wing: YES
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
$Name: Transport
|
||||
@@ -204,7 +230,7 @@ $AI:
|
||||
+Turrets attack this: YES
|
||||
+Can Form Wing: YES
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
@@ -236,7 +262,7 @@ $AI:
|
||||
+Can Form Wing: YES
|
||||
+Active docks: ( "cargo" )
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
@@ -266,7 +292,7 @@ $AI:
|
||||
+Turrets attack this: YES
|
||||
+Can Form Wing: YES
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
@@ -296,7 +322,7 @@ $AI:
|
||||
+Turrets attack this: YES
|
||||
+Can Form Wing: YES
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
@@ -326,7 +352,7 @@ $AI:
|
||||
+Turrets attack this: YES
|
||||
+Can Form Wing: YES
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
@@ -356,7 +382,7 @@ $AI:
|
||||
+Turrets attack this: YES
|
||||
+Can Form Wing: YES
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
@@ -386,7 +412,7 @@ $AI:
|
||||
+Turrets attack this: YES
|
||||
+Can Form Wing: YES
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
@@ -414,7 +440,7 @@ $AI:
|
||||
+Turrets attack this: YES
|
||||
+Can Form Wing: YES
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
@@ -440,7 +466,7 @@ $AI:
|
||||
+Guards attack this: YES
|
||||
+Turrets attack this: YES
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
@@ -464,7 +490,7 @@ $AI:
|
||||
+Guards attack this: YES
|
||||
+Turrets attack this: YES
|
||||
+Passive docks: ( "support" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Ignored on cripple by: ( "navbuoy" "sentry gun" "escape pod" "cargo" "support" "stealth" "fighter" "bomber" "fighter/bomber" "transport" "freighter" "awacs" "gas miner" "cruiser" "corvette" "capital" "super cap" "drydock" "knossos device" )
|
||||
+Targeted by 'Huge' weapons and Ignored by 'small only' weapons: YES
|
||||
$Skip Death Roll Percent Chance: 0.0
|
||||
|
||||
|
||||
+34
-38
@@ -37,7 +37,11 @@ constexpr int INTITIAL_FIREBALL_CONTAINTER_SIZE = 256;
|
||||
SCP_vector<fireball> Fireballs;
|
||||
SCP_vector<int> Unused_fireball_indices;
|
||||
|
||||
SCP_vector<fireball_info> Fireball_info;
|
||||
fireball_info Fireball_info[MAX_FIREBALL_TYPES];
|
||||
|
||||
int fireball_used[MAX_FIREBALL_TYPES];
|
||||
|
||||
int Num_fireball_types = 0;
|
||||
|
||||
bool fireballs_inited = false;
|
||||
bool fireballs_parsed = false;
|
||||
@@ -116,7 +120,7 @@ void fireball_play_warphole_close_sound(fireball *fb)
|
||||
|
||||
static void fireball_generate_unique_id(char *unique_id, int buffer_len, int fireball_index)
|
||||
{
|
||||
Assertion(SCP_vector_inbounds(Fireball_info, fireball_index), "fireball_index is out of bounds!");
|
||||
Assert((fireball_index >= 0) && (fireball_index < MAX_FIREBALL_TYPES));
|
||||
|
||||
switch (fireball_index)
|
||||
{
|
||||
@@ -160,7 +164,7 @@ static void fireball_generate_unique_id(char *unique_id, int buffer_len, int fir
|
||||
*/
|
||||
static void fireball_set_default_color(int idx)
|
||||
{
|
||||
Assertion(SCP_vector_inbounds(Fireball_info, idx), "idx is out of bounds!");
|
||||
Assert((idx >= 0) && (idx < MAX_FIREBALL_TYPES));
|
||||
|
||||
switch (idx)
|
||||
{
|
||||
@@ -196,7 +200,7 @@ static void fireball_set_default_color(int idx)
|
||||
|
||||
static void fireball_set_default_warp_attributes(int idx)
|
||||
{
|
||||
Assertion(SCP_vector_inbounds(Fireball_info, idx), "idx is out of bounds!");
|
||||
Assert((idx >= 0) && (idx < MAX_FIREBALL_TYPES));
|
||||
|
||||
switch (idx)
|
||||
{
|
||||
@@ -228,9 +232,9 @@ void fireball_info_clear(fireball_info *fb)
|
||||
|
||||
int fireball_info_lookup(const char *unique_id)
|
||||
{
|
||||
for (size_t i = 0; i < Fireball_info.size(); ++i)
|
||||
for (int i = 0; i < Num_fireball_types; ++i)
|
||||
if (!stricmp(Fireball_info[i].unique_id, unique_id))
|
||||
return static_cast<int>(i);
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -304,19 +308,25 @@ static void parse_fireball_tbl(const char *table_filename)
|
||||
// we are creating a new entry, so set some defaults
|
||||
else
|
||||
{
|
||||
int new_fireball_index = static_cast<int>(Fireball_info.size());
|
||||
Fireball_info.emplace_back();
|
||||
fi = &Fireball_info.back();
|
||||
// make sure we don't exceed the max
|
||||
if (Num_fireball_types >= MAX_FIREBALL_TYPES)
|
||||
{
|
||||
error_display(0, "Too many fireball entries! Max is %d", MAX_FIREBALL_TYPES);
|
||||
return;
|
||||
}
|
||||
|
||||
fi = &Fireball_info[Num_fireball_types];
|
||||
fireball_info_clear(fi);
|
||||
|
||||
// If the table didn't specify a unique ID, generate one. This will be assigned a few lines later.
|
||||
if (strlen(unique_id) == 0)
|
||||
fireball_generate_unique_id(unique_id, NAME_LENGTH, new_fireball_index);
|
||||
fireball_generate_unique_id(unique_id, NAME_LENGTH, Num_fireball_types);
|
||||
|
||||
// Set remaining fireball defaults
|
||||
fireball_set_default_color(new_fireball_index);
|
||||
fireball_set_default_warp_attributes(new_fireball_index);
|
||||
fireball_set_default_color(Num_fireball_types);
|
||||
fireball_set_default_warp_attributes(Num_fireball_types);
|
||||
|
||||
Num_fireball_types++;
|
||||
first_time = true;
|
||||
}
|
||||
|
||||
@@ -389,9 +399,9 @@ void fireball_parse_tbl()
|
||||
if (fireballs_parsed)
|
||||
return;
|
||||
|
||||
// every newly parsed fireball_info will get cleared before being added;
|
||||
// must clear the vector outside of parse_fireball_tbl because it's called more than once
|
||||
Fireball_info.clear();
|
||||
// every newly parsed fireball_info will get cleared before being added
|
||||
// must do this outside of parse_fireball_tbl because it's called twice
|
||||
Num_fireball_types = 0;
|
||||
|
||||
parse_fireball_tbl("fireball.tbl");
|
||||
|
||||
@@ -426,11 +436,10 @@ void fireball_parse_tbl()
|
||||
|
||||
void fireball_load_data()
|
||||
{
|
||||
int i, n, idx;
|
||||
int i, idx;
|
||||
fireball_info *fd;
|
||||
|
||||
n = static_cast<int>(Fireball_info.size());
|
||||
for ( i = 0; i < n; i++ ) {
|
||||
for ( i = 0; i < Num_fireball_types; i++ ) {
|
||||
fd = &Fireball_info[i];
|
||||
|
||||
for(idx=0; idx<fd->lod_count; idx++){
|
||||
@@ -789,7 +798,8 @@ int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_o
|
||||
object *obj;
|
||||
fireball_info *fd;
|
||||
fireball_lod *fl;
|
||||
Assertion(SCP_vector_inbounds(Fireball_info, fireball_type), "fireball_type is out of bounds!");
|
||||
Assert( fireball_type > -1 );
|
||||
Assert( fireball_type < Num_fireball_types );
|
||||
|
||||
fd = &Fireball_info[fireball_type];
|
||||
|
||||
@@ -936,14 +946,13 @@ void fireball_close()
|
||||
|
||||
void fireballs_page_in()
|
||||
{
|
||||
int i, n, idx;
|
||||
int i, idx;
|
||||
fireball_info *fd;
|
||||
|
||||
n = static_cast<int>(Fireball_info.size());
|
||||
for ( i = 0; i < n; i++ ) {
|
||||
for ( i = 0; i < Num_fireball_types; i++ ) {
|
||||
fd = &Fireball_info[i];
|
||||
|
||||
if ((i < NUM_DEFAULT_FIREBALLS) || fd->fireball_used) {
|
||||
if((i < NUM_DEFAULT_FIREBALLS) || fireball_used[i]) {
|
||||
// if this is a Knossos ani, only load if Knossos_warp_ani_used is true
|
||||
if ( (i == FIREBALL_KNOSSOS) && !Knossos_warp_ani_used)
|
||||
continue;
|
||||
@@ -975,8 +984,8 @@ void fireball_get_color(int idx, float *red, float *green, float *blue)
|
||||
{
|
||||
Assert( red && blue && green );
|
||||
|
||||
if (!SCP_vector_inbounds(Fireball_info, idx)) {
|
||||
UNREACHABLE("idx is out of bounds!");
|
||||
if ( (idx < 0) || (idx >= Num_fireball_types) ) {
|
||||
Int3();
|
||||
|
||||
*red = 1.0f;
|
||||
*green = 1.0f;
|
||||
@@ -1111,16 +1120,3 @@ int fireball_get_count()
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void stuff_fireball_index_list(SCP_vector<int> &list, const char *name)
|
||||
{
|
||||
stuff_int_list(list, RAW_INTEGER_TYPE);
|
||||
|
||||
list.erase(std::remove_if(list.begin(), list.end(), [&](int index) {
|
||||
if (!SCP_vector_inbounds(Fireball_info, index)) {
|
||||
Warning(LOCATION, "Fireball index %d for %s was out of bounds. Removing this index.", index, name);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}), list.end());
|
||||
}
|
||||
@@ -33,12 +33,15 @@ class asteroid_info;
|
||||
#define FIREBALL_EXPLOSION_LARGE1 4 // Used for the big explosion when a ship breaks into pieces
|
||||
#define FIREBALL_EXPLOSION_LARGE2 5 // Used for the big explosion when a ship breaks into pieces
|
||||
|
||||
#define MAX_FIREBALL_TYPES 32 // The maximum number of fireballs that can be defined
|
||||
#define NUM_DEFAULT_FIREBALLS 6
|
||||
|
||||
#define MAX_FIREBALL_LOD 4
|
||||
|
||||
#define FIREBALL_NUM_LARGE_EXPLOSIONS 2
|
||||
|
||||
extern int fireball_used[MAX_FIREBALL_TYPES];
|
||||
|
||||
// all this moved here by Goober5000 because it makes more sense in the H file
|
||||
typedef struct fireball_lod {
|
||||
char filename[MAX_FILENAME_LEN];
|
||||
@@ -54,7 +57,6 @@ typedef struct fireball_info {
|
||||
float exp_color[3]; // red, green, blue
|
||||
|
||||
bool use_3d_warp;
|
||||
bool fireball_used;
|
||||
|
||||
char warp_glow[NAME_LENGTH];
|
||||
int warp_glow_bitmap;
|
||||
@@ -64,7 +66,8 @@ typedef struct fireball_info {
|
||||
int warp_model_id;
|
||||
} fireball_info;
|
||||
|
||||
extern SCP_vector<fireball_info> Fireball_info;
|
||||
extern fireball_info Fireball_info[MAX_FIREBALL_TYPES];
|
||||
extern int Num_fireball_types;
|
||||
|
||||
// flag values for fireball struct flags member
|
||||
#define FBF_WARP_CLOSE_SOUND_PLAYED (1<<0)
|
||||
@@ -150,7 +153,4 @@ extern bool Fireball_warp_flash;
|
||||
// Cyborg - get a count of how many valid fireballs are in the mission.
|
||||
int fireball_get_count();
|
||||
|
||||
// Goober5000 - stuffs fireballs and checks that indexes are in bounds
|
||||
void stuff_fireball_index_list(SCP_vector<int> &list, const char *name);
|
||||
|
||||
#endif /* _FIREBALLS_H */
|
||||
@@ -30,7 +30,7 @@ static auto WarpFlashOption __UNUSED = options::OptionBuilder<bool>("Graphics.Wa
|
||||
.category(std::make_pair("Graphics", 1825))
|
||||
.default_val(true)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.bind_to(&Fireball_warp_flash)
|
||||
.bind_to_once(&Fireball_warp_flash)
|
||||
.importance(65)
|
||||
.finish();
|
||||
|
||||
|
||||
+37
-231
@@ -222,7 +222,6 @@ static EnhancedSoundData Default_sound_priorities[NUM_RETAIL_GAMEPLAY_SOUNDS] =
|
||||
|
||||
static const EnhancedSoundData default_enhanced_sound_data(SND_ENHANCED_PRIORITY_MEDIUM_HIGH, 1);
|
||||
|
||||
int gamesnd_find_nonreserved_last_index(SCP_vector<game_snd>& lookupVector, bool (*is_reserved_index)(int));
|
||||
|
||||
/*
|
||||
* Update any uninitialized EnhancedSoundData in Snds
|
||||
@@ -546,7 +545,7 @@ void gamesnd_preload_common_sounds()
|
||||
|
||||
Assert( Snds.size() <= INT_MAX );
|
||||
for (auto& gs: Snds) {
|
||||
if ( gs.flags & GAME_SND_PRELOAD ) {
|
||||
if ( gs.preload ) {
|
||||
for (auto& entry : gs.sound_entries) {
|
||||
if ( entry.filename[0] != 0 && strnicmp(entry.filename, NOX("none.wav"), 4) != 0 ) {
|
||||
game_busy( NOX("** preloading common game sounds **") ); // Animate loading cursor... does nothing if loading screen not active.
|
||||
@@ -567,7 +566,7 @@ void gamesnd_load_gameplay_sounds()
|
||||
|
||||
Assert( Snds.size() <= INT_MAX );
|
||||
for (auto& gs: Snds) {
|
||||
if ( !(gs.flags & GAME_SND_PRELOAD) ) { // don't try to load anything that's already preloaded
|
||||
if ( !gs.preload ) { // don't try to load anything that's already preloaded
|
||||
for (auto& entry : gs.sound_entries) {
|
||||
if (entry.filename[0] != 0 && strnicmp(entry.filename, NOX("none.wav"), 4) != 0) {
|
||||
game_busy(NOX("** preloading gameplay sounds **")); // Animate loading cursor... does nothing if loading screen not active.
|
||||
@@ -634,10 +633,6 @@ void parse_gamesnd_old(game_snd* gs)
|
||||
int is_3d;
|
||||
int temp;
|
||||
|
||||
// retail-style sounds with numeric indexes, as seen in the original sounds.tbl format
|
||||
if (can_construe_as_integer(gs->name.c_str()))
|
||||
gs->flags |= GAME_SND_RETAIL_STYLE;
|
||||
|
||||
// An old sound is just a single entry sound set
|
||||
gs->sound_entries.resize(1);
|
||||
auto& entry = gs->sound_entries.back();
|
||||
@@ -654,7 +649,7 @@ void parse_gamesnd_old(game_snd* gs)
|
||||
{
|
||||
entry.filename[0] = 0;
|
||||
advance_to_eoln(nullptr);
|
||||
gs->flags |= (GAME_SND_NOT_VALID | GAME_SND_EXPLICITLY_EMPTY);
|
||||
gs->flags |= GAME_SND_NOT_VALID;
|
||||
return;
|
||||
}
|
||||
Mp++;
|
||||
@@ -663,7 +658,7 @@ void parse_gamesnd_old(game_snd* gs)
|
||||
|
||||
if (temp > 0)
|
||||
{
|
||||
gs->flags |= GAME_SND_PRELOAD;
|
||||
gs->preload = true;
|
||||
}
|
||||
|
||||
float default_volume;
|
||||
@@ -706,7 +701,7 @@ void parse_gamesnd_old(game_snd* gs)
|
||||
// check for extra values per Mantis #2408
|
||||
if (stuff_int_optional(&temp) == 2)
|
||||
{
|
||||
error_display(0, "Unexpected extra value %d found for sound '%s' (filename '%s')! Check the format of the sounds.tbl (or .tbm) entry.", temp, gs->name.c_str(), entry.filename);
|
||||
Warning(LOCATION, "Unexpected extra value %d found for sound '%s' (filename '%s')! Check the format of the sounds.tbl (or .tbm) entry.", temp, gs->name.c_str(), entry.filename);
|
||||
}
|
||||
|
||||
advance_to_eoln(NULL);
|
||||
@@ -775,8 +770,8 @@ void parse_gamesnd_soundset(game_snd* gs, bool no_create) {
|
||||
// If this gets called then we just saw "+Entry:" so we can begin processing the first entry immediately
|
||||
|
||||
do {
|
||||
// For now there is no way to change an existing entry so every +Entry statement creates a new sound entry
|
||||
gs->sound_entries.emplace_back();
|
||||
// For now there is no way to change an existing entry so ever +Entry statement creates a new sound entry
|
||||
gs->sound_entries.resize(gs->sound_entries.size() + 1);
|
||||
auto& entry = gs->sound_entries.back();
|
||||
|
||||
stuff_string(entry.filename, F_NAME, MAX_FILENAME_LEN);
|
||||
@@ -788,18 +783,12 @@ void parse_gamesnd_soundset(game_snd* gs, bool no_create) {
|
||||
|
||||
if (required_string_no_create("+Preload:", no_create))
|
||||
{
|
||||
bool temp;
|
||||
stuff_boolean(&temp);
|
||||
|
||||
if (temp)
|
||||
gs->flags |= GAME_SND_PRELOAD;
|
||||
else
|
||||
gs->flags &= ~GAME_SND_PRELOAD;
|
||||
stuff_boolean(&gs->preload);
|
||||
}
|
||||
|
||||
if (required_string_no_create("+Volume:", no_create))
|
||||
{
|
||||
gs->volume_range = util::ParsedRandomFloatRange::parseRandomRange(0.0f, 1.0f);
|
||||
gs->volume_range = util::parseUniformRange(0.0f, 1.0f);
|
||||
}
|
||||
|
||||
if (optional_string("+3D Sound:"))
|
||||
@@ -848,7 +837,7 @@ void parse_gamesnd_soundset(game_snd* gs, bool no_create) {
|
||||
}
|
||||
|
||||
if (optional_string("+Pitch:")) {
|
||||
gs->pitch_range = util::ParsedRandomFloatRange::parseRandomRange(0.0001f);
|
||||
gs->pitch_range = util::parseUniformRange(0.0001f);
|
||||
} else if (!no_create) {
|
||||
// Default pitch is 1.0
|
||||
gs->pitch_range = util::UniformFloatRange(1.0f);
|
||||
@@ -862,9 +851,7 @@ void parse_gamesnd_new(game_snd* gs, bool no_create)
|
||||
gs->sound_entries.resize(1);
|
||||
entry = &gs->sound_entries.back();
|
||||
} else {
|
||||
if (gs->sound_entries.empty()) {
|
||||
gs->sound_entries.resize(1);
|
||||
} else if (gs->sound_entries.size() > 1) {
|
||||
if (gs->sound_entries.size() != 1) {
|
||||
error_display(1, "The SCP syntax cannot be used to modify an existing sound that has more than one entry! Use the soundset syntax for adding new entries.");
|
||||
}
|
||||
entry = &gs->sound_entries.back();
|
||||
@@ -883,7 +870,7 @@ void parse_gamesnd_new(game_snd* gs, bool no_create)
|
||||
if (!stricmp(name, NOX("empty")) || !stricmp(name, NOX("none")))
|
||||
{
|
||||
entry->filename[0] = 0;
|
||||
gs->flags |= (GAME_SND_NOT_VALID | GAME_SND_EXPLICITLY_EMPTY);
|
||||
gs->flags |= GAME_SND_NOT_VALID;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -901,13 +888,7 @@ void parse_gamesnd_new(game_snd* gs, bool no_create)
|
||||
|
||||
if (required_string_no_create("+Preload:", no_create))
|
||||
{
|
||||
bool temp;
|
||||
stuff_boolean(&temp);
|
||||
|
||||
if (temp)
|
||||
gs->flags |= GAME_SND_PRELOAD;
|
||||
else
|
||||
gs->flags &= ~GAME_SND_PRELOAD;
|
||||
stuff_boolean(&gs->preload);
|
||||
}
|
||||
|
||||
if (required_string_no_create("+Volume:", no_create))
|
||||
@@ -963,107 +944,33 @@ void parse_gamesnd_new(game_snd* gs, bool no_create)
|
||||
}
|
||||
}
|
||||
|
||||
bool gamesnd_is_placeholder(const game_snd& gs)
|
||||
{
|
||||
return (gs.sound_entries.empty() || gs.sound_entries[0].filename[0] == '\0') && !(gs.flags & GAME_SND_EXPLICITLY_EMPTY);
|
||||
}
|
||||
|
||||
void gamesnd_parse_entry(game_snd *gs, bool &orig_no_create, SCP_vector<game_snd> *lookupVector, size_t lookupVectorMaxIndexableSize, bool (*is_reserved_index)(int))
|
||||
void gamesnd_parse_entry(game_snd *gs, bool no_create, SCP_vector<game_snd> *lookupVector)
|
||||
{
|
||||
SCP_string name;
|
||||
|
||||
stuff_string(name, F_NAME, "\t \n");
|
||||
|
||||
if (lookupVector && can_construe_as_integer(name.c_str()))
|
||||
{
|
||||
Assertion(is_reserved_index != nullptr, "If lookupVector is supplied, the is_reserved_index() function must also be supplied");
|
||||
|
||||
int candidate_index = atoi(name.c_str());
|
||||
|
||||
// if this is a number within the range of possible indexes
|
||||
if (candidate_index >= 0 && static_cast<size_t>(candidate_index) < lookupVectorMaxIndexableSize)
|
||||
{
|
||||
// make sure the vector contains an entry for that index
|
||||
while (lookupVector->size() <= static_cast<size_t>(candidate_index))
|
||||
{
|
||||
size_t back_index = lookupVector->size();
|
||||
lookupVector->emplace_back();
|
||||
sprintf(lookupVector->back().name, SIZE_T_ARG, back_index);
|
||||
}
|
||||
|
||||
// if there is a named sound already at that index, move it to the end of the vector
|
||||
// (because named sounds can go anywhere, while indexed sounds need to be at their indexes)
|
||||
auto candidate_gs = &lookupVector->at(candidate_index);
|
||||
if (!candidate_gs->name.empty() && !can_construe_as_integer(candidate_gs->name.c_str()))
|
||||
{
|
||||
// prevent new named sounds from colliding with reserved indexes
|
||||
int endIndex = gamesnd_find_nonreserved_last_index(*lookupVector, is_reserved_index);
|
||||
|
||||
// add a new sound at the end of the vector
|
||||
lookupVector->emplace_back();
|
||||
|
||||
// swap them
|
||||
std::swap(lookupVector->at(candidate_index), lookupVector->at(endIndex));
|
||||
sprintf(lookupVector->at(candidate_index).name, "%d", candidate_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int vectorIndex;
|
||||
if (lookupVector)
|
||||
vectorIndex = gamesnd_lookup_name(name.c_str(), *lookupVector);
|
||||
else
|
||||
vectorIndex = -1;
|
||||
|
||||
bool no_create = orig_no_create;
|
||||
|
||||
if (!no_create)
|
||||
{
|
||||
if (vectorIndex >= 0)
|
||||
if (lookupVector != NULL)
|
||||
{
|
||||
auto existing_gs = &lookupVector->at(vectorIndex);
|
||||
|
||||
// if the existing sound was an empty or placeholder sound, replace it, don't warn
|
||||
if (gamesnd_is_placeholder(*existing_gs))
|
||||
if (gamesnd_lookup_name(name.c_str(), *lookupVector) >= 0)
|
||||
{
|
||||
gs = existing_gs;
|
||||
orig_no_create = true; // prevent sound from being appended in parse_sound_table
|
||||
// (leave no_create as false because we are creating a new sound and we need all the fields to be filled out)
|
||||
}
|
||||
else
|
||||
{
|
||||
error_display(0, "Duplicate sound name \"%s\" found!", name.c_str());
|
||||
}
|
||||
}
|
||||
else if (lookupVector)
|
||||
{
|
||||
// see if there is an empty or placeholder sound that we can replace
|
||||
int i = 0;
|
||||
for (const auto& ii : *lookupVector)
|
||||
{
|
||||
if (gamesnd_is_placeholder(ii) && !is_reserved_index(i))
|
||||
{
|
||||
vectorIndex = i;
|
||||
gs = &lookupVector->at(vectorIndex);
|
||||
orig_no_create = true; // prevent sound from being appended in parse_sound_table
|
||||
// (leave no_create as false because we are creating a new sound and we need all the fields to be filled out)
|
||||
|
||||
// a placeholder can have a single entry with an empty filename, so remove that if it exists
|
||||
gs->sound_entries.clear();
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
Warning(LOCATION, "Duplicate sound name \"%s\" found!", name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
gs->name = std::move(name);
|
||||
gs->name = name;
|
||||
}
|
||||
else
|
||||
{
|
||||
int vectorIndex = gamesnd_lookup_name(name.c_str(), *lookupVector);
|
||||
|
||||
if (vectorIndex < 0)
|
||||
{
|
||||
error_display(0, "No existing sound entry with name \"%s\" found!", name.c_str());
|
||||
no_create = false; // this is a new sound, so we need all the fields to be filled out
|
||||
gs->name = std::move(name);
|
||||
Warning(LOCATION, "No existing sound entry with name \"%s\" found!", name.c_str());
|
||||
no_create = false;
|
||||
gs->name = name;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1074,9 +981,7 @@ void gamesnd_parse_entry(game_snd *gs, bool &orig_no_create, SCP_vector<game_snd
|
||||
if (optional_string("+Filename:"))
|
||||
{
|
||||
parse_gamesnd_new(gs, no_create);
|
||||
}
|
||||
else if (optional_string("+Entry:"))
|
||||
{
|
||||
} else if (optional_string("+Entry:")) {
|
||||
parse_gamesnd_soundset(gs, no_create);
|
||||
}
|
||||
else
|
||||
@@ -1091,16 +996,11 @@ void gamesnd_parse_entry(game_snd *gs, bool &orig_no_create, SCP_vector<game_snd
|
||||
* @param gs The game_snd instance to fill in
|
||||
* @param tag The tag that's required before an entry
|
||||
* @param lookupVector If non-NULL used to look up @c +nocreate entries
|
||||
* @param lookupVectorMaxIndexableSize Numbers less than this size will be treated as indexes;
|
||||
* numbers at or above this size will be treated as numeric IDs that aren't indexes.
|
||||
* Note that this distinct from the vector's current or default size.
|
||||
* @param is_reserved_index A function to indicate whether a particular index should not be used
|
||||
* by a named sound
|
||||
*
|
||||
* @return @c true when a new entry has been parsed and should be added to the list of known
|
||||
* entries. @c false otherwise, for example in case of @c +nocreate
|
||||
*/
|
||||
bool gamesnd_parse_line(game_snd *gs, const char *tag, SCP_vector<game_snd> *lookupVector = nullptr, size_t lookupVectorMaxIndexableSize = 0, bool (*is_reserved_index)(int) = nullptr)
|
||||
bool gamesnd_parse_line(game_snd *gs, const char *tag, SCP_vector<game_snd> *lookupVector = NULL)
|
||||
{
|
||||
Assertion(gs != NULL, "Invalid game_snd pointer passed to gamesnd_parse_line!");
|
||||
|
||||
@@ -1116,7 +1016,7 @@ bool gamesnd_parse_line(game_snd *gs, const char *tag, SCP_vector<game_snd> *loo
|
||||
}
|
||||
}
|
||||
|
||||
gamesnd_parse_entry(gs, no_create, lookupVector, lookupVectorMaxIndexableSize, is_reserved_index);
|
||||
gamesnd_parse_entry(gs, no_create, lookupVector);
|
||||
|
||||
return !no_create;
|
||||
}
|
||||
@@ -1289,47 +1189,6 @@ void parse_sound_environments()
|
||||
required_string("#Sound Environments End");
|
||||
}
|
||||
|
||||
// indicate whether an index into Game Sounds is reserved for a built-in sound
|
||||
bool gamesnd_is_reserved_game_index(int index)
|
||||
{
|
||||
if (index >= 0 && index <= 161)
|
||||
return true;
|
||||
if (index >= 173 && index <= 191)
|
||||
return true;
|
||||
if (index == 200 || index == 201)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// indicate whether an index into Interface Sounds is reserved for a built-in sound
|
||||
bool gamesnd_is_reserved_interface_index(int index)
|
||||
{
|
||||
if (index >= 0 && index <= 64)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Finds an index that
|
||||
// 1) is just after the last index in lookupVector (i.e. equal to the size);
|
||||
// 2) does not correspond to a reserved index, as determined by the function.
|
||||
// If needed, empty game_snds are emplaced onto the vector until these conditions are true.
|
||||
int gamesnd_find_nonreserved_last_index(SCP_vector<game_snd>& lookupVector, bool (*is_reserved_index)(int))
|
||||
{
|
||||
int candidate_last_index = static_cast<int>(lookupVector.size());
|
||||
|
||||
// prevent new named sounds from colliding with reserved indexes
|
||||
while (is_reserved_index(candidate_last_index))
|
||||
{
|
||||
lookupVector.emplace_back();
|
||||
sprintf(lookupVector.back().name, "%d", candidate_last_index);
|
||||
candidate_last_index = static_cast<int>(lookupVector.size());
|
||||
}
|
||||
|
||||
return candidate_last_index;
|
||||
}
|
||||
|
||||
// Due to the cyclic depdendency between sounds and species, the parsing is now broken up into two stages.
|
||||
// First, just the sounds are parsed; and second, just the flyby sounds are parsed (or assigned).
|
||||
static bool Sound_table_first_stage = false;
|
||||
@@ -1351,19 +1210,9 @@ void parse_sound_table(const char* filename)
|
||||
while (!check_for_string("#Game Sounds End"))
|
||||
{
|
||||
game_snd tempSound;
|
||||
if (gamesnd_parse_line(&tempSound, "$Name:", &Snds, static_cast<size_t>(GameSounds::MIN_GAME_SOUNDS) * 2, gamesnd_is_reserved_game_index))
|
||||
if (gamesnd_parse_line(&tempSound, "$Name:", &Snds))
|
||||
{
|
||||
// if we are in this block, this is a new named sound that will be appended
|
||||
int tempIndex = static_cast<int>(Snds.size());
|
||||
|
||||
// retail sounds with numeric names must match their indexes
|
||||
if ((tempSound.flags & GAME_SND_RETAIL_STYLE) && (atoi(tempSound.name.c_str()) != tempIndex) && !gamesnd_is_placeholder(tempSound))
|
||||
error_display(0, "Retail-style sound %s has a name that does not match its index %d!", tempSound.name.c_str(), tempIndex);
|
||||
|
||||
// prevent new named sounds from colliding with reserved indexes
|
||||
tempIndex = gamesnd_find_nonreserved_last_index(Snds, gamesnd_is_reserved_game_index);
|
||||
|
||||
Snds.emplace_back(std::move(tempSound));
|
||||
Snds.push_back(game_snd(tempSound));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1381,19 +1230,10 @@ void parse_sound_table(const char* filename)
|
||||
while (!check_for_string("#Interface Sounds End"))
|
||||
{
|
||||
game_snd tempSound;
|
||||
if (gamesnd_parse_line(&tempSound, "$Name:", &Snds_iface, static_cast<size_t>(InterfaceSounds::MIN_INTERFACE_SOUNDS) * 2, gamesnd_is_reserved_interface_index))
|
||||
if (gamesnd_parse_line(&tempSound, "$Name:", &Snds_iface))
|
||||
{
|
||||
// if we are in this block, this is a new named sound that will be appended
|
||||
int tempIndex = static_cast<int>(Snds_iface.size());
|
||||
|
||||
// retail sounds with numeric names must match their indexes
|
||||
if ((tempSound.flags & GAME_SND_RETAIL_STYLE) && (atoi(tempSound.name.c_str()) != tempIndex) && !gamesnd_is_placeholder(tempSound))
|
||||
error_display(0, "Retail-style sound %s has a name that does not match its index %d!", tempSound.name.c_str(), tempIndex);
|
||||
|
||||
// prevent new named sounds from colliding with reserved indexes
|
||||
tempIndex = gamesnd_find_nonreserved_last_index(Snds_iface, gamesnd_is_reserved_interface_index);
|
||||
|
||||
Snds_iface.emplace_back(std::move(tempSound));
|
||||
Snds_iface.push_back(game_snd(tempSound));
|
||||
Snds_iface_handle.push_back(sound_handle::invalid());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1474,30 +1314,10 @@ void gamesnd_parse_soundstbl(bool first_stage)
|
||||
|
||||
parse_modular_table("*-snd.tbm", parse_sound_table);
|
||||
|
||||
if (first_stage)
|
||||
{
|
||||
// these vectors should be the same size
|
||||
while (Snds_iface_handle.size() < Snds_iface.size())
|
||||
Snds_iface_handle.push_back(sound_handle::invalid());
|
||||
|
||||
// mark any placeholder sounds as invalid
|
||||
// (most places in the code already check for this, but it is possible for sexps and scripts to attempt to play an empty sound)
|
||||
for (auto& snd : Snds)
|
||||
if (gamesnd_is_placeholder(snd))
|
||||
snd.flags |= GAME_SND_NOT_VALID;
|
||||
|
||||
// ditto for interface sounds
|
||||
for (auto& snd : Snds_iface)
|
||||
if (gamesnd_is_placeholder(snd))
|
||||
snd.flags |= GAME_SND_NOT_VALID;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!first_stage) {
|
||||
//Set any flyby sounds for species that use the borrowed feature
|
||||
for (size_t i = 0; i < Species_info.size(); i++)
|
||||
{
|
||||
if (Species_info[i].borrows_flyby_sounds_species >= 0)
|
||||
{
|
||||
for (size_t i = 0; i < Species_info.size(); i++) {
|
||||
if (Species_info[i].borrows_flyby_sounds_species >= 0) {
|
||||
int idx = Species_info[i].borrows_flyby_sounds_species;
|
||||
Species_info[i].snd_flyby_fighter = Species_info[idx].snd_flyby_fighter;
|
||||
Species_info[i].snd_flyby_bomber = Species_info[idx].snd_flyby_bomber;
|
||||
@@ -1557,16 +1377,6 @@ bool gamesnd_game_sound_try_load(gamesnd_id sound)
|
||||
}
|
||||
auto gs = gamesnd_get_game_sound(sound);
|
||||
|
||||
// check flag the first time
|
||||
if (gs->flags & GAME_SND_NOT_VALID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (gs->sound_entries.empty()) {
|
||||
gs->flags |= GAME_SND_NOT_VALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto& entry : gs->sound_entries) {
|
||||
if (!entry.id.isValid()) {
|
||||
// Lazily load unloaded sound entries when required
|
||||
@@ -1574,7 +1384,7 @@ bool gamesnd_game_sound_try_load(gamesnd_id sound)
|
||||
}
|
||||
}
|
||||
|
||||
// check flag again
|
||||
// check flag
|
||||
return (gs->flags & GAME_SND_NOT_VALID) == 0;
|
||||
}
|
||||
|
||||
@@ -1593,11 +1403,7 @@ float gamesnd_get_max_duration(game_snd* gs) {
|
||||
return max_length / gs->pitch_range.max();
|
||||
}
|
||||
game_snd_entry* gamesnd_choose_entry(game_snd* gs) {
|
||||
if (gs->sound_entries.empty()) {
|
||||
// This entire game_snd should have been skipped due to having the GAME_SND_NOT_VALID flag before we get to this function
|
||||
UNREACHABLE("No sound entries found in game sound %s! This may not happen!", gs->name.c_str());
|
||||
gs->sound_entries.emplace_back(); // add an empty entry so that we can return something; it will be invalid and will not be played
|
||||
}
|
||||
Assertion(!gs->sound_entries.empty(), "No sound entries found in game sound! This may not happen!");
|
||||
|
||||
size_t index = 0;
|
||||
switch(gs->cycle_type) {
|
||||
|
||||
@@ -237,8 +237,6 @@ enum class GameSounds {
|
||||
BALLISTIC_START_LOAD = 200,//!< (SCP)
|
||||
BALLISTIC_LOAD = 201,//!< (SCP)
|
||||
|
||||
// NOTE: If any other indexes become reserved, be sure to update gamesnd_is_reserved_game_index()
|
||||
|
||||
/**
|
||||
* Keep this below all defined enum values
|
||||
*/
|
||||
@@ -312,10 +310,8 @@ enum class InterfaceSounds {
|
||||
INTERFACE_UNDEFINED_60 =60,//!< vasudan hall - vasudan pa 3
|
||||
VASUDAN_BUP =61,//!< bup bup bup-bup bup bup
|
||||
INTERFACE_UNDEFINED_62 =62,//!< thankyou
|
||||
INTERFACE_UNDEFINED_63 =63,//!< vasudan hall - exit open
|
||||
INTERFACE_UNDEFINED_64 =64,//!< vasudan hall - exit close
|
||||
|
||||
// NOTE: If any other indexes become reserved, be sure to update gamesnd_is_reserved_interface_index()
|
||||
INTERFACE_UNDEFINED_63 =62,//!< vasudan hall - exit open
|
||||
INTERFACE_UNDEFINED_64 =62,//!< vasudan hall - exit close
|
||||
|
||||
/**
|
||||
* Keep this below all defined enum values
|
||||
@@ -356,9 +352,6 @@ class interface_snd_id : public util::ID<interface_snd_tag, int, -1> {
|
||||
}
|
||||
};
|
||||
|
||||
bool gamesnd_is_reserved_game_index(int index);
|
||||
bool gamesnd_is_reserved_interface_index(int index);
|
||||
|
||||
void gamesnd_parse_soundstbl(bool first_stage); // Loads in general game sounds from sounds.tbl
|
||||
void gamesnd_close(); // close out gamesnd... only call from game_shutdown()!
|
||||
void gamesnd_load_gameplay_sounds();
|
||||
|
||||
@@ -216,11 +216,6 @@ DWORD WINAPI SCP_mspdbcs_DumpStackThread( LPVOID pv )
|
||||
stackFrame.AddrPC.Offset = context.Rip;
|
||||
stackFrame.AddrStack.Offset = context.Rsp;
|
||||
stackFrame.AddrFrame.Offset = context.Rbp;
|
||||
#elif defined(_M_ARM64)
|
||||
dwMachType = IMAGE_FILE_MACHINE_ARM64;
|
||||
stackFrame.AddrPC.Offset = context.Pc;
|
||||
stackFrame.AddrStack.Offset = context.Sp;
|
||||
stackFrame.AddrFrame.Offset = context.Fp;
|
||||
#else
|
||||
# error UNKNOWN ARCHITECTURE
|
||||
#endif
|
||||
|
||||
@@ -99,14 +99,6 @@ struct ivec2 {
|
||||
int x, y;
|
||||
};
|
||||
|
||||
inline bool operator<(const ivec3& l, const ivec3& r){
|
||||
return l.x < r.x || (l.x == r.x && (l.y < r.y || (l.y == r.y && l.z < r.z)));
|
||||
}
|
||||
|
||||
inline bool operator<(const ivec2& l, const ivec2& r){
|
||||
return l.x < r.x || (l.x == r.x && l.y < r.y);
|
||||
}
|
||||
|
||||
namespace scripting {
|
||||
class ade_table_entry;
|
||||
}
|
||||
@@ -125,6 +117,9 @@ typedef struct vec3d {
|
||||
} xyz;
|
||||
float a1d[3];
|
||||
};
|
||||
|
||||
void serialize(lua_State* /*L*/, const scripting::ade_table_entry& /*tableEntry*/, const luacpp::LuaValue& value, ubyte* data, int& packet_size);
|
||||
void deserialize(lua_State* /*L*/, const scripting::ade_table_entry& /*tableEntry*/, char* data_ptr, ubyte* data, int& offset);
|
||||
} vec3d;
|
||||
|
||||
typedef struct vec2d {
|
||||
|
||||
@@ -239,9 +239,9 @@ detail_levels Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS] = {
|
||||
detail_levels Detail = Detail_defaults[NUM_DEFAULT_DETAIL_LEVELS - 1];
|
||||
|
||||
const SCP_vector<std::pair<int, std::pair<const char*, int>>> DetailLevelValues = {{ 0, {"Minimum", 1680}},
|
||||
{ 1, {"Low", 1160}},
|
||||
{ 2, {"Medium", 1161}},
|
||||
{ 3, {"High", 1162}},
|
||||
{ 1, {"Low", 1161}},
|
||||
{ 2, {"Medium", 1162}},
|
||||
{ 3, {"High", 1163}},
|
||||
{ 4, {"Ultra", 1721}}};
|
||||
|
||||
const auto ModelDetailOption __UNUSED = options::OptionBuilder<int>("Graphics.Detail",
|
||||
|
||||
@@ -27,7 +27,7 @@ void Undo_system::clamp_stacks() {
|
||||
// This while() shouldn't ever be triggered, but this is a safety to prevent any weird edge-cases.
|
||||
while (redo_stack.size() > max_undos) {
|
||||
delete redo_stack.front();
|
||||
redo_stack.pop_front();
|
||||
undo_stack.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -147,174 +147,4 @@ typename T::size_type stringcost(const T& op, const T& input, typename T::size_t
|
||||
return cost;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int count_items_with_name(const char* name, const T* item_array, int num_items)
|
||||
{
|
||||
if (!name || !item_array)
|
||||
return 0;
|
||||
|
||||
int count = 0;
|
||||
for (int i = 0; i < num_items; ++i)
|
||||
if (!stricmp(name, item_array[i].name))
|
||||
++count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int count_items_with_name(const char* name, const T& item_vector)
|
||||
{
|
||||
if (!name)
|
||||
return 0;
|
||||
|
||||
int count = 0;
|
||||
for (const auto& item : item_vector)
|
||||
if (!stricmp(name, item.name))
|
||||
++count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int count_items_with_scp_string_name(const char* name, const T& item_vector)
|
||||
{
|
||||
if (!name)
|
||||
return 0;
|
||||
|
||||
int count = 0;
|
||||
for (const auto& item : item_vector)
|
||||
if (!stricmp(name, item.name.c_str()))
|
||||
++count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
template <typename VECTOR_T, typename ITEM_T, typename FIELD_T>
|
||||
int find_item_with_field(const VECTOR_T& item_vector, FIELD_T ITEM_T::* field, const char* str)
|
||||
{
|
||||
if (!str)
|
||||
return -1;
|
||||
|
||||
int index = 0;
|
||||
for (const ITEM_T& item : item_vector)
|
||||
{
|
||||
if (!stricmp(item.*field, str))
|
||||
return index;
|
||||
else
|
||||
++index;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename VECTOR_T, typename ITEM_T, typename FIELD_T>
|
||||
int find_item_with_field(const VECTOR_T& item_vector, FIELD_T ITEM_T::* field, const SCP_string& str)
|
||||
{
|
||||
int index = 0;
|
||||
for (const ITEM_T& item : item_vector)
|
||||
{
|
||||
if (lcase_equal(item.*field, str))
|
||||
return index;
|
||||
else
|
||||
++index;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename VECTOR_T, typename ITEM_T, typename FIELD_T>
|
||||
int find_item_with_field(const VECTOR_T& item_vector, FIELD_T ITEM_T::* field, const FIELD_T& search)
|
||||
{
|
||||
int index = 0;
|
||||
for (const ITEM_T& item : item_vector)
|
||||
{
|
||||
if (item.*field == search)
|
||||
return index;
|
||||
else
|
||||
++index;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename ITEM_T, typename FIELD_T>
|
||||
int find_item_with_field(const ITEM_T* item_array, int num_items, FIELD_T ITEM_T::* field, const char* str)
|
||||
{
|
||||
if (!str)
|
||||
return -1;
|
||||
|
||||
for (int i = 0; i < num_items; ++i)
|
||||
if (!stricmp(item_array[i].*field, str))
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename ITEM_T, typename FIELD_T>
|
||||
int find_item_with_field(const ITEM_T* item_array, int num_items, FIELD_T ITEM_T::* field, const SCP_string& str)
|
||||
{
|
||||
for (int i = 0; i < num_items; ++i)
|
||||
if (lcase_equal(item_array[i].*field, str))
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename ITEM_T, typename FIELD_T>
|
||||
int find_item_with_field(const ITEM_T* item_array, int num_items, FIELD_T ITEM_T::* field, const FIELD_T& search)
|
||||
{
|
||||
for (int i = 0; i < num_items; ++i)
|
||||
if (item_array[i].*field == search)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename VECTOR_T>
|
||||
int find_item_with_name(const VECTOR_T& item_vector, const char* str)
|
||||
{
|
||||
if (!str)
|
||||
return -1;
|
||||
|
||||
int index = 0;
|
||||
for (const auto& item : item_vector)
|
||||
{
|
||||
if (!stricmp(item.name, str))
|
||||
return index;
|
||||
else
|
||||
++index;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename ITEM_T>
|
||||
int find_item_with_name(const ITEM_T* item_array, int num_items, const char* str)
|
||||
{
|
||||
return find_item_with_field(item_array, num_items, &ITEM_T::name, str);
|
||||
}
|
||||
|
||||
template <typename VECTOR_T>
|
||||
int find_item_with_name(const VECTOR_T& item_vector, const SCP_string& str)
|
||||
{
|
||||
int index = 0;
|
||||
for (const auto& item : item_vector)
|
||||
{
|
||||
if (lcase_equal(item.name, str))
|
||||
return index;
|
||||
else
|
||||
++index;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename NULLISH_T>
|
||||
NULLISH_T coalesce(NULLISH_T possibly_null, NULLISH_T value_if_null)
|
||||
{
|
||||
Assertion(value_if_null != nullptr, "value_if_null can never be null itself!");
|
||||
|
||||
return (possibly_null != nullptr) ? possibly_null : value_if_null;
|
||||
}
|
||||
|
||||
#endif
|
||||
+12
-49
@@ -61,30 +61,6 @@
|
||||
#include "SDL_cpuinfo.h"
|
||||
#endif
|
||||
|
||||
#define GR_CAPABILITY_ENTRY(capability) gr_capability_def{ gr_capability::CAPABILITY_##capability, #capability }
|
||||
|
||||
gr_capability_def gr_capabilities[] = {
|
||||
GR_CAPABILITY_ENTRY(ENVIRONMENT_MAP),
|
||||
GR_CAPABILITY_ENTRY(NORMAL_MAP),
|
||||
GR_CAPABILITY_ENTRY(HEIGHT_MAP),
|
||||
GR_CAPABILITY_ENTRY(SOFT_PARTICLES),
|
||||
GR_CAPABILITY_ENTRY(DISTORTION),
|
||||
GR_CAPABILITY_ENTRY(POST_PROCESSING),
|
||||
GR_CAPABILITY_ENTRY(DEFERRED_LIGHTING),
|
||||
GR_CAPABILITY_ENTRY(SHADOWS),
|
||||
GR_CAPABILITY_ENTRY(THICK_OUTLINE),
|
||||
GR_CAPABILITY_ENTRY(BATCHED_SUBMODELS),
|
||||
GR_CAPABILITY_ENTRY(TIMESTAMP_QUERY),
|
||||
GR_CAPABILITY_ENTRY(SEPARATE_BLEND_FUNCTIONS),
|
||||
GR_CAPABILITY_ENTRY(PERSISTENT_BUFFER_MAPPING),
|
||||
gr_capability_def {gr_capability::CAPABILITY_BPTC, "BPTC Texture Compression"}, //This one had a different parse string already!
|
||||
GR_CAPABILITY_ENTRY(LARGE_SHADER)
|
||||
};
|
||||
|
||||
const size_t gr_capabilities_num = sizeof(gr_capabilities) / sizeof(gr_capabilities[0]);
|
||||
|
||||
#undef GR_CAPABILITY_ENTRY
|
||||
|
||||
const char* Resolution_prefixes[GR_NUM_RESOLUTIONS] = {"", "2_"};
|
||||
|
||||
screen gr_screen;
|
||||
@@ -150,9 +126,9 @@ static auto GammaOption __UNUSED = options::OptionBuilder<float>("Graphics.Gamma
|
||||
|
||||
|
||||
const SCP_vector<std::pair<int, std::pair<const char*, int>>> DetailLevelValues = {{ 0, {"Minimum", 1680}},
|
||||
{ 1, {"Low", 1160}},
|
||||
{ 2, {"Medium", 1161}},
|
||||
{ 3, {"High", 1162}},
|
||||
{ 1, {"Low", 1161}},
|
||||
{ 2, {"Medium", 1162}},
|
||||
{ 3, {"High", 1163}},
|
||||
{ 4, {"Ultra", 1721}}};
|
||||
|
||||
const auto LightingOption __UNUSED = options::OptionBuilder<int>("Graphics.Lighting",
|
||||
@@ -1476,15 +1452,14 @@ static void init_window_icon() {
|
||||
bm_release(icon_handle);
|
||||
}
|
||||
|
||||
SCP_string gr_capability_to_human_readable_string(gr_capability capability)
|
||||
SCP_string gr_capability_to_string(gr_capability capability)
|
||||
{
|
||||
auto capability_it = std::find_if(&gr_capabilities[0], &gr_capabilities[gr_capabilities_num],
|
||||
[capability](const gr_capability_def &entry) { return entry.capability == capability; });
|
||||
|
||||
if (capability_it != &gr_capabilities[gr_capabilities_num])
|
||||
return capability_it->parse_name;
|
||||
else
|
||||
switch (capability) {
|
||||
case CAPABILITY_BPTC:
|
||||
return "BPTC Texture Compression";
|
||||
default:
|
||||
return "Invalid Capability";
|
||||
}
|
||||
}
|
||||
|
||||
bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode, int d_width, int d_height, int d_depth)
|
||||
@@ -1601,17 +1576,6 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
|
||||
}
|
||||
}
|
||||
|
||||
if (!gr_is_viewport_window() && !Cmdline_window_res.has_value()) {
|
||||
// For whatever reason, it seems that a combination of Win 11 and presumably NVidia GPU's causes weird artifacts.
|
||||
// These artifacts do not appear in windowed mode, or with an attached renderdoc / nvidia nsight.
|
||||
// Similarly using the -window_res command line parameter prevents this.
|
||||
// To the best of our knowledge, this is because all of the aforementioned methods route the rendering through another buffer
|
||||
// (be that a window, a render overlay from nsight, or an FSO-internal buffer) instead of directly rendering to the OS-provided direct screen backbuffer.
|
||||
// As the cost of -window_res is one single blit of a fullscreen buffer, it's probably an acceptable compromise to get rid of render artifacts.
|
||||
// As such, forcibly enable -window_res at the screen resolution here, if we're in fullscreen.
|
||||
Cmdline_window_res.emplace(static_cast<uint16_t>(width), static_cast<uint16_t>(height));
|
||||
}
|
||||
|
||||
if (d_mode == GR_DEFAULT) {
|
||||
// OpenGL should be default
|
||||
mode = GR_OPENGL;
|
||||
@@ -1728,13 +1692,12 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
|
||||
|
||||
mprintf(("Checking graphics capabilities:\n"));
|
||||
mprintf((" Persistent buffer mapping: %s\n",
|
||||
gr_is_capable(gr_capability::CAPABILITY_PERSISTENT_BUFFER_MAPPING) ? "Enabled" : "Disabled"));
|
||||
gr_is_capable(CAPABILITY_PERSISTENT_BUFFER_MAPPING) ? "Enabled" : "Disabled"));
|
||||
|
||||
mprintf(("Checking mod required rendering features...\n"));
|
||||
for (gr_capability ext : Required_render_ext) {
|
||||
if (!gr_is_capable(ext)) {
|
||||
Error(LOCATION, "Feature %s required by mod not supported by system.\n",
|
||||
gr_capability_to_human_readable_string(ext).c_str());
|
||||
Error(LOCATION, "Feature %s required by mod not supported by system.\n", gr_capability_to_string(ext).c_str());
|
||||
}
|
||||
}
|
||||
mprintf((" All required features are supported.\n"));
|
||||
@@ -1782,7 +1745,7 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
|
||||
|
||||
Gr_inited = 1;
|
||||
|
||||
if (!gr_is_capable(gr_capability::CAPABILITY_SHADOWS) && Shadow_quality != ShadowQuality::Disabled) {
|
||||
if (!gr_is_capable(CAPABILITY_SHADOWS) && Shadow_quality != ShadowQuality::Disabled) {
|
||||
Warning(LOCATION, "Shadows are enabled, but the system does not fulfill the requirements. Disabling shadows...");
|
||||
Shadow_quality = ShadowQuality::Disabled;
|
||||
}
|
||||
|
||||
+6
-12
@@ -219,6 +219,9 @@ enum shader_type {
|
||||
|
||||
|
||||
// Shader flags
|
||||
#define SDR_FLAG_MODEL_SHADOW_MAP (1<<13)
|
||||
#define SDR_FLAG_MODEL_THICK_OUTLINES (1<<21) // Renders the model geometry as an outline with configurable line width
|
||||
|
||||
#define SDR_FLAG_PARTICLE_POINT_GEN (1<<0)
|
||||
|
||||
#define SDR_FLAG_BLUR_HORIZONTAL (1<<0)
|
||||
@@ -318,7 +321,7 @@ template<> struct hash<vertex_layout> {
|
||||
};
|
||||
}
|
||||
|
||||
enum class gr_capability {
|
||||
typedef enum gr_capability {
|
||||
CAPABILITY_ENVIRONMENT_MAP,
|
||||
CAPABILITY_NORMAL_MAP,
|
||||
CAPABILITY_HEIGHT_MAP,
|
||||
@@ -332,17 +335,8 @@ enum class gr_capability {
|
||||
CAPABILITY_TIMESTAMP_QUERY,
|
||||
CAPABILITY_SEPARATE_BLEND_FUNCTIONS,
|
||||
CAPABILITY_PERSISTENT_BUFFER_MAPPING,
|
||||
CAPABILITY_BPTC,
|
||||
CAPABILITY_LARGE_SHADER
|
||||
};
|
||||
|
||||
struct gr_capability_def {
|
||||
gr_capability capability;
|
||||
const char* parse_name;
|
||||
};
|
||||
|
||||
extern gr_capability_def gr_capabilities[];
|
||||
extern const size_t gr_capabilities_num;
|
||||
CAPABILITY_BPTC
|
||||
} gr_capability;
|
||||
|
||||
enum class gr_property
|
||||
{
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
#include "globalincs/systemvars.h"
|
||||
#include "cmdline/cmdline.h"
|
||||
|
||||
#define MODEL_SDR_FLAG_MODE_CPP
|
||||
#include "def_files/data/effects/model_shader_flags.h"
|
||||
|
||||
gr_alpha_blend material_determine_blend_mode(int base_bitmap, bool blending)
|
||||
{
|
||||
if ( blending ) {
|
||||
@@ -731,71 +728,20 @@ uint model_material::get_shader_flags() const
|
||||
{
|
||||
uint Shader_flags = 0;
|
||||
|
||||
if (!gr_is_capable(gr_capability::CAPABILITY_LARGE_SHADER)) {
|
||||
Shader_flags |= get_shader_runtime_early_flags();
|
||||
}
|
||||
|
||||
if (Shadow_casting) {
|
||||
// if we're building the shadow map, we likely only need the flags here and above so bail
|
||||
Shader_flags |= MODEL_SDR_FLAG_SHADOW_MAP;
|
||||
Shader_flags |= SDR_FLAG_MODEL_SHADOW_MAP;
|
||||
|
||||
return Shader_flags;
|
||||
}
|
||||
|
||||
if (uses_thick_outlines() && gr_is_capable(gr_capability::CAPABILITY_THICK_OUTLINE)) {
|
||||
Shader_flags |= MODEL_SDR_FLAG_THICK_OUTLINES;
|
||||
if (uses_thick_outlines() && gr_is_capable(CAPABILITY_THICK_OUTLINE)) {
|
||||
Shader_flags |= SDR_FLAG_MODEL_THICK_OUTLINES;
|
||||
}
|
||||
|
||||
if (!gr_is_capable(gr_capability::CAPABILITY_LARGE_SHADER)) {
|
||||
Shader_flags |= get_shader_runtime_flags();
|
||||
}
|
||||
|
||||
return Shader_flags;
|
||||
}
|
||||
|
||||
int model_material::get_shader_runtime_early_flags() const {
|
||||
int flags = 0;
|
||||
if (is_batched())
|
||||
flags |= MODEL_SDR_FLAG_TRANSFORM;
|
||||
return flags;
|
||||
}
|
||||
|
||||
int model_material::get_shader_runtime_flags() const {
|
||||
int flags = 0;
|
||||
if (is_lit())
|
||||
flags |= MODEL_SDR_FLAG_LIGHT;
|
||||
if (is_deferred())
|
||||
flags |= MODEL_SDR_FLAG_DEFERRED;
|
||||
if (is_hdr())
|
||||
flags |= MODEL_SDR_FLAG_HDR;
|
||||
if (get_texture_map(TM_BASE_TYPE) > 0)
|
||||
flags |= MODEL_SDR_FLAG_DIFFUSE;
|
||||
if (get_texture_map(TM_GLOW_TYPE) > 0)
|
||||
flags |= MODEL_SDR_FLAG_GLOW;
|
||||
if (get_texture_map(TM_SPECULAR_TYPE) > 0 || get_texture_map(TM_SPEC_GLOSS_TYPE) > 0)
|
||||
flags |= MODEL_SDR_FLAG_SPEC;
|
||||
if (ENVMAP > 0)
|
||||
flags |= MODEL_SDR_FLAG_ENV;
|
||||
if (get_texture_map(TM_NORMAL_TYPE) > 0)
|
||||
flags |= MODEL_SDR_FLAG_NORMAL;
|
||||
if (get_texture_map(TM_AMBIENT_TYPE) > 0)
|
||||
flags |= MODEL_SDR_FLAG_AMBIENT;
|
||||
if (get_texture_map(TM_MISC_TYPE) > 0)
|
||||
flags |= MODEL_SDR_FLAG_MISC;
|
||||
if (get_texture_map(TM_MISC_TYPE) > 0 && is_team_color_set())
|
||||
flags |= MODEL_SDR_FLAG_TEAMCOLOR;
|
||||
if (is_fogged())
|
||||
flags |= MODEL_SDR_FLAG_FOG;
|
||||
if (is_shadow_receiving())
|
||||
flags |= MODEL_SDR_FLAG_SHADOWS;
|
||||
if (get_thrust_scale() > 0.0f)
|
||||
flags |= MODEL_SDR_FLAG_THRUSTER;
|
||||
if (is_alpha_mult_active())
|
||||
flags |= MODEL_SDR_FLAG_ALPHA_MULT;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
particle_material::particle_material():
|
||||
material()
|
||||
{
|
||||
|
||||
@@ -252,8 +252,6 @@ public:
|
||||
bool is_batched() const;
|
||||
|
||||
uint get_shader_flags() const override;
|
||||
int get_shader_runtime_early_flags() const;
|
||||
int get_shader_runtime_flags() const;
|
||||
|
||||
void set_fog(int r, int g, int b, float near, float far);
|
||||
void set_fog();
|
||||
|
||||
@@ -1202,6 +1202,9 @@ static bool printNextDebugMessage() {
|
||||
#endif
|
||||
|
||||
static void init_extensions() {
|
||||
// if S3TC compression is found, then "GL_ARB_texture_compression" must be an extension
|
||||
Use_compressed_textures = GLAD_GL_EXT_texture_compression_s3tc;
|
||||
Texture_compression_available = true;
|
||||
// Swifty put this in, but it's not doing anything. Once he uses it, he can uncomment it.
|
||||
//int use_base_vertex = Is_Extension_Enabled(OGL_ARB_DRAW_ELEMENTS_BASE_VERTEX);
|
||||
|
||||
@@ -1409,8 +1412,8 @@ bool gr_opengl_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps)
|
||||
GL_max_renderbuffer_size,
|
||||
GL_max_renderbuffer_size ));
|
||||
|
||||
mprintf(( " S3TC texture support: %s\n", GLAD_GL_EXT_texture_compression_s3tc ? NOX("YES") : NOX("NO") ));
|
||||
mprintf(( " BPTC texture support: %s\n", GLAD_GL_ARB_texture_compression_bptc ? NOX("YES") : NOX("NO") ));
|
||||
mprintf(( " Can use compressed textures: %s\n", Use_compressed_textures ? NOX("YES") : NOX("NO") ));
|
||||
mprintf(( " Texture compression available: %s\n", Texture_compression_available ? NOX("YES") : NOX("NO") ));
|
||||
mprintf(( " Post-processing enabled: %s\n", (Gr_post_processing_enabled) ? "YES" : "NO"));
|
||||
mprintf(( " Using %s texture filter.\n", (GL_mipmap_filter) ? NOX("trilinear") : NOX("bilinear") ));
|
||||
|
||||
@@ -1434,34 +1437,32 @@ bool gr_opengl_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps)
|
||||
bool gr_opengl_is_capable(gr_capability capability)
|
||||
{
|
||||
switch ( capability ) {
|
||||
case gr_capability::CAPABILITY_ENVIRONMENT_MAP:
|
||||
case CAPABILITY_ENVIRONMENT_MAP:
|
||||
return true;
|
||||
case gr_capability::CAPABILITY_NORMAL_MAP:
|
||||
case CAPABILITY_NORMAL_MAP:
|
||||
return Cmdline_normal ? true : false;
|
||||
case gr_capability::CAPABILITY_HEIGHT_MAP:
|
||||
case CAPABILITY_HEIGHT_MAP:
|
||||
return Cmdline_height ? true : false;
|
||||
case gr_capability::CAPABILITY_SOFT_PARTICLES:
|
||||
case gr_capability::CAPABILITY_DISTORTION:
|
||||
case CAPABILITY_SOFT_PARTICLES:
|
||||
case CAPABILITY_DISTORTION:
|
||||
return Gr_enable_soft_particles && !Cmdline_no_fbo && !Cmdline_no_geo_sdr_effects;
|
||||
case gr_capability::CAPABILITY_POST_PROCESSING:
|
||||
case CAPABILITY_POST_PROCESSING:
|
||||
return Gr_post_processing_enabled && !Cmdline_no_fbo;
|
||||
case gr_capability::CAPABILITY_DEFERRED_LIGHTING:
|
||||
case CAPABILITY_DEFERRED_LIGHTING:
|
||||
return !Cmdline_no_fbo && light_deferred_enabled();
|
||||
case gr_capability::CAPABILITY_SHADOWS:
|
||||
case gr_capability::CAPABILITY_THICK_OUTLINE:
|
||||
case CAPABILITY_SHADOWS:
|
||||
case CAPABILITY_THICK_OUTLINE:
|
||||
return !Cmdline_no_geo_sdr_effects;
|
||||
case gr_capability::CAPABILITY_BATCHED_SUBMODELS:
|
||||
case CAPABILITY_BATCHED_SUBMODELS:
|
||||
return true;
|
||||
case gr_capability::CAPABILITY_TIMESTAMP_QUERY:
|
||||
case CAPABILITY_TIMESTAMP_QUERY:
|
||||
return GLAD_GL_ARB_timer_query != 0; // Timestamp queries are available from 3.3 onwards
|
||||
case gr_capability::CAPABILITY_SEPARATE_BLEND_FUNCTIONS:
|
||||
case CAPABILITY_SEPARATE_BLEND_FUNCTIONS:
|
||||
return GLAD_GL_ARB_draw_buffers_blend != 0; // We need an OpenGL extension for this
|
||||
case gr_capability::CAPABILITY_PERSISTENT_BUFFER_MAPPING:
|
||||
case CAPABILITY_PERSISTENT_BUFFER_MAPPING:
|
||||
return GLAD_GL_ARB_buffer_storage != 0;
|
||||
case gr_capability::CAPABILITY_BPTC:
|
||||
case CAPABILITY_BPTC:
|
||||
return GLAD_GL_ARB_texture_compression_bptc != 0;
|
||||
case gr_capability::CAPABILITY_LARGE_SHADER:
|
||||
return !Cmdline_no_large_shaders;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -68,7 +68,7 @@ void gr_opengl_deferred_lighting_begin(bool clearNonColorBufs)
|
||||
Deferred_lighting = true;
|
||||
GL_state.ColorMask(true, true, true, true);
|
||||
|
||||
GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5 };
|
||||
GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT6 };
|
||||
|
||||
if (Cmdline_msaa_enabled > 0) {
|
||||
//Ensure MSAA Mode if necessary
|
||||
@@ -226,7 +226,7 @@ void gr_opengl_deferred_lighting_finish()
|
||||
opengl_shader_set_current(gr_opengl_maybe_create_shader(SDR_TYPE_DEFERRED_LIGHTING, 0));
|
||||
|
||||
// Render on top of the composite buffer texture
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT5);
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT6);
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT4);
|
||||
glBlitFramebuffer(0,
|
||||
0,
|
||||
@@ -523,10 +523,8 @@ void gr_opengl_deferred_lighting_finish()
|
||||
|
||||
opengl_draw_full_screen_textured(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
}
|
||||
else if (The_mission.volumetrics && The_mission.volumetrics->get_enabled() && !override_fog) {
|
||||
else if (The_mission.volumetrics && !override_fog) {
|
||||
GR_DEBUG_SCOPE("Volumetric Nebulae");
|
||||
TRACE_SCOPE(tracing::Volumetrics);
|
||||
|
||||
const volumetric_nebula& neb = *The_mission.volumetrics;
|
||||
|
||||
Assertion(neb.isVolumeBitmapValid(), "The volumetric nebula was not properly initialized!");
|
||||
@@ -552,11 +550,9 @@ void gr_opengl_deferred_lighting_finish()
|
||||
uint32_t array_index;
|
||||
gr_set_texture_addressing(TMAP_ADDRESS_CLAMP);
|
||||
gr_opengl_tcache_set(neb.getVolumeBitmapHandle(), TCACHE_TYPE_3DTEX, &u_scale, &v_scale, &array_index, 3);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
if (neb.getNoiseActive()) {
|
||||
gr_set_texture_addressing(TMAP_ADDRESS_WRAP);
|
||||
gr_opengl_tcache_set(neb.getNoiseVolumeBitmapHandle(), TCACHE_TYPE_3DTEX, &u_scale, &v_scale, &array_index, 4);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -571,12 +567,8 @@ void gr_opengl_deferred_lighting_finish()
|
||||
data->nebPos = neb.getPos();
|
||||
data->nebSize = neb.getSize();
|
||||
data->stepsize = neb.getStepsize();
|
||||
data->opacitydistance = neb.getOpacityDistance();
|
||||
data->globalstepalpha = neb.getStepalpha();
|
||||
data->alphalimit = neb.getAlphaLim();
|
||||
data->nebColor[0] = std::get<0>(neb.getNebulaColor());
|
||||
data->nebColor[1] = std::get<1>(neb.getNebulaColor());
|
||||
data->nebColor[2] = std::get<2>(neb.getNebulaColor());
|
||||
data->udfScale = neb.getUDFScale();
|
||||
data->emissiveSpreadFactor = neb.getEmissiveSpread();
|
||||
data->emissiveIntensity = neb.getEmissiveIntensity();
|
||||
data->emissiveFalloff = neb.getEmissiveFalloff();
|
||||
@@ -606,7 +598,7 @@ void gr_opengl_deferred_lighting_finish()
|
||||
else {
|
||||
// Transfer the resolved lighting back to the color texture
|
||||
// TODO: Maybe this could be improved so that it doesn't require the copy back operation?
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT5);
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT6);
|
||||
glBlitFramebuffer(0,
|
||||
0,
|
||||
gr_screen.max_w,
|
||||
|
||||
@@ -44,6 +44,7 @@ GLuint Scene_specular_texture_ms;
|
||||
GLuint Scene_emissive_texture_ms;
|
||||
GLuint Scene_composite_texture;
|
||||
GLuint Scene_luminance_texture;
|
||||
GLuint Scene_effect_texture;
|
||||
GLuint Scene_depth_texture;
|
||||
GLuint Scene_depth_texture_ms;
|
||||
GLuint Cockpit_depth_texture;
|
||||
@@ -104,6 +105,7 @@ void opengl_setup_scene_textures()
|
||||
|
||||
Scene_ldr_texture = 0;
|
||||
Scene_color_texture = 0;
|
||||
Scene_effect_texture = 0;
|
||||
Scene_depth_texture = 0;
|
||||
return;
|
||||
}
|
||||
@@ -250,7 +252,7 @@ void opengl_setup_scene_textures()
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, Scene_texture_width, Scene_texture_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
|
||||
opengl_set_object_label(GL_TEXTURE, Scene_composite_texture, "Scene Composite texture");
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT5, GL_TEXTURE_2D, Scene_composite_texture, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT6, GL_TEXTURE_2D, Scene_composite_texture, 0);
|
||||
|
||||
//Set up luminance texture (used as input for FXAA)
|
||||
// also used as a light accumulation buffer during the deferred pass
|
||||
@@ -269,6 +271,24 @@ void opengl_setup_scene_textures()
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, Scene_texture_width, Scene_texture_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
|
||||
opengl_set_object_label(GL_TEXTURE, Scene_luminance_texture, "Scene Luminance texture");
|
||||
|
||||
// setup effect texture
|
||||
glGenTextures(1, &Scene_effect_texture);
|
||||
|
||||
GL_state.Texture.SetActiveUnit(0);
|
||||
GL_state.Texture.SetTarget(GL_TEXTURE_2D);
|
||||
GL_state.Texture.Enable(Scene_effect_texture);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, Scene_texture_width, Scene_texture_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
|
||||
opengl_set_object_label(GL_TEXTURE, Scene_effect_texture, "Scene Effect texture");
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT5, GL_TEXTURE_2D, Scene_effect_texture, 0);
|
||||
|
||||
// setup cockpit depth texture
|
||||
glGenTextures(1, &Cockpit_depth_texture);
|
||||
|
||||
@@ -336,6 +356,9 @@ void opengl_setup_scene_textures()
|
||||
glDeleteTextures(1, &Scene_emissive_texture);
|
||||
Scene_emissive_texture = 0;
|
||||
|
||||
glDeleteTextures(1, &Scene_effect_texture);
|
||||
Scene_effect_texture = 0;
|
||||
|
||||
glDeleteTextures(1, &Scene_depth_texture);
|
||||
Scene_depth_texture = 0;
|
||||
|
||||
@@ -644,6 +667,11 @@ void opengl_scene_texture_shutdown()
|
||||
Scene_emissive_texture = 0;
|
||||
}
|
||||
|
||||
if ( Scene_effect_texture ) {
|
||||
glDeleteTextures(1, &Scene_effect_texture);
|
||||
Scene_effect_texture = 0;
|
||||
}
|
||||
|
||||
if ( Scene_depth_texture ) {
|
||||
glDeleteTextures(1, &Scene_depth_texture);
|
||||
Scene_depth_texture = 0;
|
||||
@@ -701,7 +729,7 @@ void gr_opengl_scene_texture_begin()
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
} else {
|
||||
GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5 };
|
||||
GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT6 };
|
||||
glDrawBuffers(6, buffers);
|
||||
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
@@ -804,8 +832,6 @@ void gr_opengl_copy_effect_texture()
|
||||
return;
|
||||
}
|
||||
|
||||
//Make sure we're reading from the up-to-date color texture
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT5);
|
||||
glBlitFramebuffer(0, 0, gr_screen.max_w, gr_screen.max_h, 0, 0, gr_screen.max_w, gr_screen.max_h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
||||
@@ -1173,7 +1199,7 @@ void gr_opengl_stop_decal_pass() {
|
||||
GL_COLOR_ATTACHMENT2,
|
||||
GL_COLOR_ATTACHMENT3,
|
||||
GL_COLOR_ATTACHMENT4,
|
||||
GL_COLOR_ATTACHMENT5,
|
||||
GL_COLOR_ATTACHMENT6,
|
||||
};
|
||||
glDrawBuffers(6, buffers2);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ extern GLuint Scene_normal_texture_ms;
|
||||
extern GLuint Scene_specular_texture_ms;
|
||||
extern GLuint Scene_emissive_texture_ms;
|
||||
extern GLuint Scene_luminance_texture;
|
||||
extern GLuint Scene_effect_texture;
|
||||
extern GLuint Scene_composite_texture;
|
||||
extern GLuint Scene_depth_texture;
|
||||
extern GLuint Scene_depth_texture_ms;
|
||||
@@ -155,6 +156,7 @@ extern int Scene_texture_initialized;
|
||||
extern GLuint Scene_color_texture;
|
||||
extern GLuint Scene_ldr_texture;
|
||||
extern GLuint Scene_luminance_texture;
|
||||
extern GLuint Scene_effect_texture;
|
||||
|
||||
extern int Scene_texture_width;
|
||||
extern int Scene_texture_height;
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
#include "gropenglopenxr.h"
|
||||
|
||||
// this block should go before the #includes otherwise MSVC will sometimes warn about APIENTRY redefinition
|
||||
// (glad.h checks for redefinition of the symbol, but minwindef.h does not)
|
||||
#ifdef WIN32
|
||||
|
||||
#define XR_USE_PLATFORM_WIN32
|
||||
#include <unknwn.h>
|
||||
|
||||
#endif
|
||||
// the other platforms do not go before the #includes because this will cause conflicts from symbols defined in XLib,
|
||||
// specifically None and Always; see https://stackoverflow.com/questions/22476110/c-compiling-error-including-x11-x-h-x11-xlib-h
|
||||
|
||||
#include "io/cursor.h"
|
||||
#include "io/mouse.h"
|
||||
#include "graphics/matrix.h"
|
||||
@@ -21,7 +10,13 @@
|
||||
#include "graphics/opengl/ShaderProgram.h"
|
||||
#include "osapi/osapi.h"
|
||||
|
||||
#if defined __APPLE_CC__
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
#define XR_USE_PLATFORM_WIN32
|
||||
#include <unknwn.h>
|
||||
|
||||
#elif defined __APPLE_CC__
|
||||
|
||||
//Not supported
|
||||
|
||||
|
||||
@@ -183,12 +183,16 @@ static opengl_shader_type_t GL_shader_types[] = {
|
||||
* When adding a new shader variant for a shader, list all associated uniforms and attributes here
|
||||
*/
|
||||
static opengl_shader_variant_t GL_shader_variants[] = {
|
||||
//Model shader flags, both those set always as a compile flag as well as those that are usually runtime checks, need to be defined in this file
|
||||
#define MODEL_SDR_FLAG_MODE_CPP_ARRAY
|
||||
#include "def_files/data/effects/model_shader_flags.h"
|
||||
#undef MODEL_SDR_FLAG_MODE_CPP_ARRAY
|
||||
{SDR_TYPE_MODEL, true, SDR_FLAG_MODEL_SHADOW_MAP, "FLAG_SHADOW_MAP", {}, "Shadow Mapping"},
|
||||
|
||||
{SDR_TYPE_EFFECT_PARTICLE, true, SDR_FLAG_PARTICLE_POINT_GEN, "FLAG_EFFECT_GEOMETRY", {opengl_vert_attrib::UVEC}, "Geometry shader point-based particles"},
|
||||
{SDR_TYPE_MODEL, true, SDR_FLAG_MODEL_THICK_OUTLINES, "FLAG_THICK_OUTLINE", {}, "Thick outlines"},
|
||||
|
||||
{SDR_TYPE_EFFECT_PARTICLE,
|
||||
true,
|
||||
SDR_FLAG_PARTICLE_POINT_GEN,
|
||||
"FLAG_EFFECT_GEOMETRY",
|
||||
{opengl_vert_attrib::UVEC},
|
||||
"Geometry shader point-based particles"},
|
||||
|
||||
{SDR_TYPE_POST_PROCESS_BLUR, false, SDR_FLAG_BLUR_HORIZONTAL, "PASS_0", {}, "Horizontal blur pass"},
|
||||
|
||||
@@ -390,68 +394,12 @@ static void handle_includes_impl(SCP_vector<SCP_string>& include_stack,
|
||||
auto current_source_number = include_counter + 1;
|
||||
|
||||
const char* INCLUDE_STRING = "#include";
|
||||
const char* CONDITIONAL_INCLUDE_STRING = "#conditional_include";
|
||||
SCP_stringstream input(original);
|
||||
|
||||
int line_num = 1;
|
||||
for (SCP_string line; std::getline(input, line);) {
|
||||
auto include_start = line.find(CONDITIONAL_INCLUDE_STRING);
|
||||
|
||||
auto include_start = line.find(INCLUDE_STRING);
|
||||
if (include_start != SCP_string::npos) {
|
||||
//This is a conditional include. Figure out whether to include, or whether not to.
|
||||
// Conditional include syntax: #conditional_include (+|-)"capability" "filename"
|
||||
// On +, include if capability is available, on -, include if not available
|
||||
include_start += strlen(CONDITIONAL_INCLUDE_STRING) + 1;
|
||||
bool require_capability = true;
|
||||
|
||||
switch(line.at(include_start)) {
|
||||
case '+':
|
||||
require_capability = true;
|
||||
break;
|
||||
case '-':
|
||||
require_capability = false;
|
||||
break;
|
||||
default:
|
||||
Error(LOCATION,
|
||||
"Shader %s:%d: Malformed conditional_include line. Expected + or -, got %c.",
|
||||
filename.c_str(),
|
||||
line_num,
|
||||
line.at(include_start));
|
||||
break;
|
||||
}
|
||||
|
||||
auto first_quote = line.find('"', include_start);
|
||||
auto second_quote = line.find('"', first_quote + 1);
|
||||
|
||||
if (first_quote == SCP_string::npos || second_quote == SCP_string::npos) {
|
||||
Error(LOCATION,
|
||||
"Shader %s:%d: Malformed conditional_include line. Could not find both quote characters for capability.",
|
||||
filename.c_str(),
|
||||
line_num);
|
||||
}
|
||||
auto condition = line.substr(first_quote + 1, second_quote - first_quote - 1);
|
||||
auto capability = std::find_if(&gr_capabilities[0], &gr_capabilities[gr_capabilities_num],
|
||||
[condition](const gr_capability_def &ext_pair) { return !stricmp(ext_pair.parse_name, condition.c_str()); });
|
||||
if (capability == &gr_capabilities[gr_capabilities_num]) {
|
||||
Error(LOCATION,
|
||||
"Shader %s:%d: Malformed conditional_include line. Capability %s does not exist.",
|
||||
filename.c_str(),
|
||||
line_num,
|
||||
condition.c_str());
|
||||
}
|
||||
|
||||
//Prepare for including if capability is correct, skip otherwise.
|
||||
if(gr_is_capable(capability->capability) == require_capability)
|
||||
include_start = second_quote + 1 - strlen(INCLUDE_STRING);
|
||||
else
|
||||
include_start = SCP_string::npos - 1;
|
||||
}
|
||||
else {
|
||||
//Only search for normal includes if it's not a conditional include.
|
||||
include_start = line.find(INCLUDE_STRING);
|
||||
}
|
||||
|
||||
if (include_start != SCP_string::npos && include_start != SCP_string::npos - 1) {
|
||||
auto first_quote = line.find('"', include_start + strlen(INCLUDE_STRING));
|
||||
auto second_quote = line.find('"', first_quote + 1);
|
||||
|
||||
@@ -492,7 +440,7 @@ static void handle_includes_impl(SCP_vector<SCP_string>& include_stack,
|
||||
|
||||
// We are done with the include file so now we can return to the original file
|
||||
output << "#line " << line_num + 1 << " " << current_source_number << "\n";
|
||||
} else if (include_start != SCP_string::npos - 1) {
|
||||
} else {
|
||||
output << line << "\n";
|
||||
}
|
||||
|
||||
@@ -512,89 +460,6 @@ static SCP_string handle_includes(const char* filename, const SCP_string& origin
|
||||
return output.str();
|
||||
}
|
||||
|
||||
static SCP_string handle_predefines(const char* filename, const SCP_string& original){
|
||||
SCP_stringstream output;
|
||||
SCP_unordered_map<SCP_string, SCP_string> defines;
|
||||
|
||||
const char* PREDEFINE_STRING = "#predefine";
|
||||
const char* PREREPLACE_STRING = "#prereplace";
|
||||
|
||||
SCP_stringstream input(original);
|
||||
for (SCP_string line; std::getline(input, line);) {
|
||||
auto predefine_start = line.find(PREDEFINE_STRING);
|
||||
auto prereplace_start = line.find(PREREPLACE_STRING);
|
||||
|
||||
if (predefine_start != SCP_string::npos){
|
||||
predefine_start += strlen(PREDEFINE_STRING);
|
||||
|
||||
auto token_start = line.find(' ', predefine_start);
|
||||
auto token_end = line.find(' ', token_start + 1);
|
||||
|
||||
if (token_start == SCP_string::npos || token_end == SCP_string::npos) {
|
||||
Error(LOCATION,
|
||||
"Shader %s: Malformed predefine line. Could not find define token.",
|
||||
filename);
|
||||
}
|
||||
|
||||
auto token = line.substr(token_start + 1, token_end - token_start - 1);
|
||||
auto replaceWith = line.substr(token_end + 1);
|
||||
|
||||
auto replaceStrToken = replaceWith.find("%s");
|
||||
if (replaceStrToken == SCP_string::npos || replaceWith.find("%s", replaceStrToken + 1) != SCP_string::npos){
|
||||
Error(LOCATION,
|
||||
"Shader %s: Malformed predefine line. Replacing string must have exactly one %%s.",
|
||||
filename);
|
||||
}
|
||||
if (defines.find(token) != defines.end()) {
|
||||
Error(LOCATION,
|
||||
"Shader %s: Malformed predefine line. Token %s is already defined.",
|
||||
filename,
|
||||
token.c_str());
|
||||
}
|
||||
|
||||
defines.emplace(std::move(token), std::move(replaceWith));
|
||||
|
||||
output << "\n"; //At this point, don't mess with the linecount
|
||||
}
|
||||
else if (prereplace_start != SCP_string::npos){
|
||||
prereplace_start += strlen(PREREPLACE_STRING);
|
||||
|
||||
auto token_start = line.find(' ', prereplace_start);
|
||||
auto token_end = line.find(' ', token_start + 1);
|
||||
|
||||
if (token_start == SCP_string::npos || token_end == SCP_string::npos) {
|
||||
Error(LOCATION,
|
||||
"Shader %s: Malformed prereplace line. Could not find define token.",
|
||||
filename);
|
||||
}
|
||||
|
||||
auto token = line.substr(token_start + 1, token_end - token_start - 1);
|
||||
auto replaceArg = line.substr(token_end + 1);
|
||||
|
||||
auto replaceWithIt = defines.find(token);
|
||||
if (replaceWithIt == defines.end()) {
|
||||
Error(LOCATION,
|
||||
"Shader %s: Malformed prereplace line. Could not find token %s.",
|
||||
filename,
|
||||
token.c_str());
|
||||
}
|
||||
|
||||
size_t size = replaceWithIt->second.length() - 1 + replaceArg.size();
|
||||
std::unique_ptr<char[]> buffer = make_unique<char[]>(size);
|
||||
|
||||
snprintf(buffer.get(), size, replaceWithIt->second.c_str(), replaceArg.c_str());
|
||||
buffer[size - 1] = '\0';
|
||||
|
||||
output << buffer.get() << "\n";
|
||||
}
|
||||
else {
|
||||
output << line << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return output.str();
|
||||
}
|
||||
|
||||
static SCP_vector<SCP_string>
|
||||
opengl_get_shader_content(shader_type type_id, const char* filename, int flags, bool has_geo_shader, bool spirv_shader)
|
||||
{
|
||||
@@ -605,7 +470,7 @@ opengl_get_shader_content(shader_type type_id, const char* filename, int flags,
|
||||
} else {
|
||||
parts.push_back(opengl_shader_get_header(type_id, flags, has_geo_shader));
|
||||
|
||||
parts.push_back(handle_predefines(filename, handle_includes(filename, opengl_load_shader(filename))));
|
||||
parts.push_back(handle_includes(filename, opengl_load_shader(filename)));
|
||||
}
|
||||
|
||||
return parts;
|
||||
@@ -1071,7 +936,7 @@ void opengl_shader_init()
|
||||
opengl_purge_old_shader_cache();
|
||||
|
||||
// compile effect shaders
|
||||
if (gr_opengl_is_capable(gr_capability::CAPABILITY_SOFT_PARTICLES)) {
|
||||
if (gr_opengl_is_capable(CAPABILITY_SOFT_PARTICLES)) {
|
||||
// only compile soft particle shaders if they are supported, as to avoid introducing geo shaders if they aren't needed
|
||||
gr_opengl_maybe_create_shader(SDR_TYPE_EFFECT_PARTICLE, 0);
|
||||
gr_opengl_maybe_create_shader(SDR_TYPE_EFFECT_PARTICLE, SDR_FLAG_PARTICLE_POINT_GEN);
|
||||
|
||||
@@ -1225,7 +1225,7 @@ int opengl_compress_image( ubyte **compressed_data, ubyte *in_data, int width, i
|
||||
{
|
||||
Assert( in_data != NULL );
|
||||
|
||||
if ( !GLAD_GL_EXT_texture_compression_s3tc ) {
|
||||
if ( !Texture_compression_available ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,9 +39,6 @@
|
||||
#include "render/3d.h"
|
||||
#include "weapon/trails.h"
|
||||
|
||||
#define MODEL_SDR_FLAG_MODE_CPP
|
||||
#include "def_files/data/effects/model_shader_flags.h"
|
||||
|
||||
extern int GLOWMAP;
|
||||
extern int SPECMAP;
|
||||
extern int SPECGLOSSMAP;
|
||||
@@ -846,33 +843,18 @@ void opengl_tnl_set_model_material(model_material *material_info)
|
||||
// it is uncritical at this time as texture reads are gated behind feature flags in the shader.
|
||||
// This will be fixed in future cleanups, where we plan to introduce engine-generated default textures to substitute
|
||||
// if the material doesn't provide anything.
|
||||
const bool setAllUniforms = gr_is_capable(gr_capability::CAPABILITY_LARGE_SHADER);
|
||||
const int flags = material_info->get_shader_runtime_early_flags() | material_info->get_shader_runtime_flags();
|
||||
|
||||
if (setAllUniforms || (flags & MODEL_SDR_FLAG_DIFFUSE))
|
||||
Current_shader->program->Uniforms.setTextureUniform("sBasemap", 0);
|
||||
if (setAllUniforms || (flags & MODEL_SDR_FLAG_GLOW))
|
||||
Current_shader->program->Uniforms.setTextureUniform("sGlowmap", 1);
|
||||
if (setAllUniforms || (flags & MODEL_SDR_FLAG_SPEC))
|
||||
Current_shader->program->Uniforms.setTextureUniform("sSpecmap", 2);
|
||||
if (setAllUniforms || (flags & MODEL_SDR_FLAG_ENV)) {
|
||||
Current_shader->program->Uniforms.setTextureUniform("sEnvmap", 3);
|
||||
Current_shader->program->Uniforms.setTextureUniform("sIrrmap", 11);
|
||||
}
|
||||
if (setAllUniforms || (flags & MODEL_SDR_FLAG_NORMAL))
|
||||
Current_shader->program->Uniforms.setTextureUniform("sNormalmap", 4);
|
||||
if (setAllUniforms || (flags & MODEL_SDR_FLAG_AMBIENT))
|
||||
Current_shader->program->Uniforms.setTextureUniform("sAmbientmap", 6);
|
||||
if (setAllUniforms || (flags & MODEL_SDR_FLAG_MISC))
|
||||
Current_shader->program->Uniforms.setTextureUniform("sMiscmap", 7);
|
||||
if (setAllUniforms || (flags & MODEL_SDR_FLAG_SHADOWS))
|
||||
Current_shader->program->Uniforms.setTextureUniform("shadow_map", 8);
|
||||
Current_shader->program->Uniforms.setTextureUniform("sBasemap", 0);
|
||||
Current_shader->program->Uniforms.setTextureUniform("sGlowmap", 1);
|
||||
Current_shader->program->Uniforms.setTextureUniform("sSpecmap", 2);
|
||||
Current_shader->program->Uniforms.setTextureUniform("sEnvmap", 3);
|
||||
Current_shader->program->Uniforms.setTextureUniform("sIrrmap", 11);
|
||||
Current_shader->program->Uniforms.setTextureUniform("sNormalmap", 4);
|
||||
Current_shader->program->Uniforms.setTextureUniform("sHeightmap", 5);
|
||||
Current_shader->program->Uniforms.setTextureUniform("sAmbientmap", 6);
|
||||
Current_shader->program->Uniforms.setTextureUniform("sMiscmap", 7);
|
||||
Current_shader->program->Uniforms.setTextureUniform("shadow_map", 8);
|
||||
Current_shader->program->Uniforms.setTextureUniform("sFramebuffer", 9);
|
||||
if (setAllUniforms || (flags & MODEL_SDR_FLAG_TRANSFORM))
|
||||
Current_shader->program->Uniforms.setTextureUniform("transform_tex", 10);
|
||||
|
||||
//No shader ever defines this, so don't push it.
|
||||
//Current_shader->program->Uniforms.setTextureUniform("sHeightmap", 5);
|
||||
Current_shader->program->Uniforms.setTextureUniform("transform_tex", 10);
|
||||
|
||||
if (material_info->get_texture_map(TM_BASE_TYPE) > 0) {
|
||||
gr_opengl_tcache_set(material_info->get_texture_map(TM_BASE_TYPE),
|
||||
@@ -959,7 +941,7 @@ void opengl_tnl_set_model_material(model_material *material_info)
|
||||
|
||||
if (material_info->get_animated_effect() > 0) {
|
||||
if (Scene_framebuffer_in_frame) {
|
||||
GL_state.Texture.Enable(9, GL_TEXTURE_2D, Scene_composite_texture);
|
||||
GL_state.Texture.Enable(9, GL_TEXTURE_2D, Scene_effect_texture);
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
||||
} else {
|
||||
GL_state.Texture.Enable(9, GL_TEXTURE_2D, Framebuffer_fallback_texture_id);
|
||||
@@ -1050,7 +1032,7 @@ void opengl_tnl_set_material_distortion(distortion_material* material_info)
|
||||
});
|
||||
|
||||
Current_shader->program->Uniforms.setTextureUniform("frameBuffer", 2);
|
||||
GL_state.Texture.Enable(2, GL_TEXTURE_2D, Scene_composite_texture);
|
||||
GL_state.Texture.Enable(2, GL_TEXTURE_2D, Scene_effect_texture);
|
||||
|
||||
Current_shader->program->Uniforms.setTextureUniform("distMap", 3);
|
||||
if (material_info->get_thruster_rendering()) {
|
||||
|
||||
@@ -224,7 +224,11 @@ bool gr_lightshafts_enabled()
|
||||
return false;
|
||||
}
|
||||
|
||||
return graphics::LightshaftsOption->getValue();
|
||||
if (Using_in_game_options) {
|
||||
return graphics::LightshaftsOption->getValue();
|
||||
} else {
|
||||
return !Cmdline_force_lightshaft_off;
|
||||
}
|
||||
}
|
||||
|
||||
int gr_bloom_intensity()
|
||||
@@ -237,7 +241,11 @@ int gr_bloom_intensity()
|
||||
return 0;
|
||||
}
|
||||
|
||||
return graphics::BloomIntensityOption->getValue();
|
||||
if (Using_in_game_options) {
|
||||
return graphics::BloomIntensityOption->getValue();
|
||||
} else {
|
||||
return Cmdline_bloom_intensity;
|
||||
}
|
||||
}
|
||||
|
||||
void gr_set_bloom_intensity(int intensity)
|
||||
@@ -246,6 +254,9 @@ void gr_set_bloom_intensity(int intensity)
|
||||
return;
|
||||
}
|
||||
|
||||
graphics::Post_processing_bloom_intensity = intensity;
|
||||
options::OptionsManager::instance()->set_ingame_range_option("Graphics.BloomIntensity", intensity);
|
||||
if (Using_in_game_options) {
|
||||
graphics::Post_processing_bloom_intensity = intensity;
|
||||
} else {
|
||||
Cmdline_bloom_intensity = intensity;
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ bool Shadow_quality_uses_mod_option = false;
|
||||
auto ShadowQualityOption = options::OptionBuilder<ShadowQuality>("Graphics.Shadows",
|
||||
std::pair<const char*, int>{"Shadow Quality", 1750},
|
||||
std::pair<const char*, int>{"The quality of the shadows", 1751})
|
||||
.values({{ShadowQuality::Disabled, {"Disabled", 413}},
|
||||
.values({{ShadowQuality::Disabled, {"Disabled", 1779}},
|
||||
{ShadowQuality::Low, {"Low", 1160}},
|
||||
{ShadowQuality::Medium, {"Medium", 1161}},
|
||||
{ShadowQuality::High, {"High", 1162}},
|
||||
@@ -494,8 +494,8 @@ void shadows_render_all(fov_t fov, matrix *eye_orient, vec3d *eye_pos)
|
||||
render_info.set_object_number(OBJ_INDEX(objp));
|
||||
render_info.set_flags(MR_IS_ASTEROID | MR_NO_TEXTURING | MR_NO_LIGHTING);
|
||||
|
||||
model_clear_instance( Asteroid_info[Asteroids[objp->instance].asteroid_type].subtypes[Asteroids[objp->instance].asteroid_subtype].model_number);
|
||||
model_render_queue(&render_info, &scene, Asteroid_info[Asteroids[objp->instance].asteroid_type].subtypes[Asteroids[objp->instance].asteroid_subtype].model_number, &objp->orient, &objp->pos);
|
||||
model_clear_instance( Asteroid_info[Asteroids[objp->instance].asteroid_type].model_num[Asteroids[objp->instance].asteroid_subtype]);
|
||||
model_render_queue(&render_info, &scene, Asteroid_info[Asteroids[objp->instance].asteroid_type].model_num[Asteroids[objp->instance].asteroid_subtype], &objp->orient, &objp->pos);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
#include "light.h"
|
||||
#include "globalincs/systemvars.h"
|
||||
#include "shadows.h"
|
||||
|
||||
#define MODEL_SDR_FLAG_MODE_CPP
|
||||
#include "def_files/data/effects/model_shader_flags.h"
|
||||
|
||||
namespace {
|
||||
@@ -57,7 +55,39 @@ void convert_model_material(model_uniform_data* data_out,
|
||||
data_out->anim_timer = 0;
|
||||
data_out->use_clip_plane = 0;
|
||||
|
||||
data_out->flags = material.get_shader_runtime_early_flags() | material.get_shader_runtime_flags();
|
||||
data_out->flags = 0;
|
||||
if (material.is_lit())
|
||||
data_out->flags |= MODEL_SDR_FLAG_LIGHT;
|
||||
if (material.is_deferred())
|
||||
data_out->flags |= MODEL_SDR_FLAG_DEFERRED;
|
||||
if (material.is_hdr())
|
||||
data_out->flags |= MODEL_SDR_FLAG_HDR;
|
||||
if (material.get_texture_map(TM_BASE_TYPE) > 0)
|
||||
data_out->flags |= MODEL_SDR_FLAG_DIFFUSE;
|
||||
if (material.get_texture_map(TM_GLOW_TYPE) > 0)
|
||||
data_out->flags |= MODEL_SDR_FLAG_GLOW;
|
||||
if (material.get_texture_map(TM_SPECULAR_TYPE) > 0 || material.get_texture_map(TM_SPEC_GLOSS_TYPE) > 0)
|
||||
data_out->flags |= MODEL_SDR_FLAG_SPEC;
|
||||
if (ENVMAP > 0)
|
||||
data_out->flags |= MODEL_SDR_FLAG_ENV;
|
||||
if (material.get_texture_map(TM_NORMAL_TYPE) > 0)
|
||||
data_out->flags |= MODEL_SDR_FLAG_NORMAL;
|
||||
if (material.get_texture_map(TM_AMBIENT_TYPE) > 0)
|
||||
data_out->flags |= MODEL_SDR_FLAG_AMBIENT;
|
||||
if (material.get_texture_map(TM_MISC_TYPE) > 0)
|
||||
data_out->flags |= MODEL_SDR_FLAG_MISC;
|
||||
if (material.get_texture_map(TM_MISC_TYPE) > 0 && material.is_team_color_set())
|
||||
data_out->flags |= MODEL_SDR_FLAG_TEAMCOLOR;
|
||||
if (material.is_fogged())
|
||||
data_out->flags |= MODEL_SDR_FLAG_FOG;
|
||||
if (material.is_batched())
|
||||
data_out->flags |= MODEL_SDR_FLAG_TRANSFORM;
|
||||
if (material.is_shadow_receiving())
|
||||
data_out->flags |= MODEL_SDR_FLAG_SHADOWS;
|
||||
if (material.get_thrust_scale() > 0.0f)
|
||||
data_out->flags |= MODEL_SDR_FLAG_THRUSTER;
|
||||
if (material.is_alpha_mult_active())
|
||||
data_out->flags |= MODEL_SDR_FLAG_ALPHA_MULT;
|
||||
|
||||
if (material.get_animated_effect() >= 0) {
|
||||
data_out->anim_timer = material.get_animated_effect_time();
|
||||
@@ -187,7 +217,7 @@ void convert_model_material(model_uniform_data* data_out,
|
||||
data_out->fardist = Shadow_cascade_distances[3];
|
||||
}
|
||||
|
||||
if (shader_flags & MODEL_SDR_FLAG_SHADOW_MAP) {
|
||||
if (shader_flags & SDR_FLAG_MODEL_SHADOW_MAP) {
|
||||
for (size_t i = 0; i < MAX_SHADOW_CASCADES; ++i) {
|
||||
data_out->shadow_proj_matrix[i] = Shadow_proj_matrix[i];
|
||||
}
|
||||
@@ -237,7 +267,7 @@ void convert_model_material(model_uniform_data* data_out,
|
||||
}
|
||||
}
|
||||
|
||||
if ( shader_flags & MODEL_SDR_FLAG_THICK_OUTLINES ) {
|
||||
if ( shader_flags & SDR_FLAG_MODEL_THICK_OUTLINES ) {
|
||||
data_out->outlineWidth = material.get_outline_thickness();
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ UniformBufferManager::UniformBufferManager()
|
||||
bool success = gr_get_property(gr_property::UNIFORM_BUFFER_OFFSET_ALIGNMENT, &_offset_alignment);
|
||||
Assertion(success, "Uniform buffer usage requires a backend which allows to query the offset alignment!");
|
||||
|
||||
_use_persistent_mapping = gr_is_capable(gr_capability::CAPABILITY_PERSISTENT_BUFFER_MAPPING);
|
||||
_use_persistent_mapping = gr_is_capable(CAPABILITY_PERSISTENT_BUFFER_MAPPING);
|
||||
|
||||
_segment_fences.fill(nullptr);
|
||||
changeSegmentSize(4096);
|
||||
|
||||
@@ -319,13 +319,10 @@ struct volumetric_fog_data {
|
||||
float stepsize;
|
||||
|
||||
vec3d nebPos;
|
||||
float opacitydistance;
|
||||
float globalstepalpha;
|
||||
|
||||
vec3d nebSize;
|
||||
float alphalimit;
|
||||
|
||||
float nebColor[3];
|
||||
float udfScale;
|
||||
|
||||
float emissiveSpreadFactor;
|
||||
float emissiveIntensity;
|
||||
|
||||
+28
-24
@@ -2844,39 +2844,43 @@ int hud_get_dock_time( object *docker_objp )
|
||||
/**
|
||||
* @brief Locate the closest support ship which is trying to dock with player
|
||||
*
|
||||
* @param objp Object of player
|
||||
* @param objnum Object number of player
|
||||
* @return Number of support ship, -1 if there is no support ship currently trying to dock
|
||||
*/
|
||||
int hud_support_find_closest( object *objp )
|
||||
int hud_support_find_closest( int objnum )
|
||||
{
|
||||
// invalid if player is dead or a ghost
|
||||
if (objp->flags[Object::Object_Flags::Should_be_dead] || objp->type != OBJ_SHIP)
|
||||
return -1;
|
||||
ai_info *aip;
|
||||
object *objp;
|
||||
int i;
|
||||
|
||||
objp = &Objects[objnum];
|
||||
|
||||
for (auto sop: list_range(&Ship_obj_list)) {
|
||||
if (Objects[sop->objnum].flags[Object::Object_Flags::Should_be_dead])
|
||||
continue;
|
||||
|
||||
auto shipp = &Ships[Objects[sop->objnum].instance];
|
||||
if ( Ship_info[shipp->ship_info_index].flags[Ship::Info_Flags::Support] ) {
|
||||
if ( Ship_info[Ships[Objects[sop->objnum].instance].ship_info_index].flags[Ship::Info_Flags::Support] ) {
|
||||
int pship_index, sindex;
|
||||
|
||||
// make sure support ship is not dying
|
||||
auto shipp = &Ships[Objects[sop->objnum].instance];
|
||||
|
||||
if ( !(shipp->flags[Ship::Ship_Flags::Dying] || shipp->flags[Ship::Ship_Flags::Exploded]) ) {
|
||||
auto aip = &Ai_info[shipp->ai_index];
|
||||
|
||||
Assert( objp->type == OBJ_SHIP );
|
||||
aip = &Ai_info[Ships[Objects[sop->objnum].instance].ai_index];
|
||||
pship_index = objp->instance;
|
||||
|
||||
// we must check all goals for this support ship -- not just the first one
|
||||
for ( int i = 0; i < MAX_AI_GOALS; i++ ) {
|
||||
for ( i = 0; i < MAX_AI_GOALS; i++ ) {
|
||||
|
||||
// we can use == in the next statement (and should) since a ship will only ever be
|
||||
// following one order at a time.
|
||||
if ( aip->goals[i].ai_mode == AI_GOAL_REARM_REPAIR ) {
|
||||
Assert( aip->goals[i].target_name );
|
||||
|
||||
auto entry = ship_registry_get( aip->goals[i].target_name );
|
||||
if (entry && entry->status == ShipStatus::PRESENT) {
|
||||
if ( entry->shipnum == objp->instance )
|
||||
return sop->objnum;
|
||||
}
|
||||
sindex = ship_name_lookup( aip->goals[i].target_name );
|
||||
if ( sindex == pship_index )
|
||||
return sop->objnum;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2898,7 +2902,7 @@ void hud_support_view_update()
|
||||
|
||||
// If we haven't determined yet who the rearm ship is, try to!
|
||||
if (Hud_support_objnum == -1) {
|
||||
Hud_support_objnum = hud_support_find_closest( Player_obj );
|
||||
Hud_support_objnum = hud_support_find_closest( OBJ_INDEX(Player_obj) );
|
||||
if ( Hud_support_objnum >= 0 ) {
|
||||
Hud_support_obj_sig = Objects[Hud_support_objnum].signature;
|
||||
Hud_support_target_sig = Player_obj->signature;
|
||||
@@ -3059,7 +3063,7 @@ void HudGaugeSupport::render(float /*frametime*/)
|
||||
renderStringAlignCenter(position[0], position[1] + text_val_offset_y, w, outstr);
|
||||
} else {
|
||||
if ( Hud_support_objnum == -1 ) {
|
||||
if (The_mission.support_ships.arrival_location == ArrivalLocation::FROM_DOCK_BAY)
|
||||
if (The_mission.support_ships.arrival_location == ARRIVE_FROM_DOCK_BAY)
|
||||
{
|
||||
strcpy_s(outstr, XSTR( "exiting hangar", 1622));
|
||||
}
|
||||
@@ -3750,6 +3754,10 @@ int hud_objective_notify_active()
|
||||
* @details Since the player's view vector may be different from the ship's forward vector,
|
||||
* we calculate the offset of those two in pixels and store the x and y offsets in
|
||||
* variables HUD_nose_x and HUD_nose_y (Swifty)
|
||||
*
|
||||
* @param viewer_obj Object, likely to be player
|
||||
* @param wiggedy_wack
|
||||
* @param eye_orient
|
||||
*/
|
||||
void HUD_set_offsets()
|
||||
{
|
||||
@@ -3759,8 +3767,6 @@ void HUD_set_offsets()
|
||||
} else {
|
||||
HUD_get_nose_coordinates(&HUD_nose_x, &HUD_nose_y);
|
||||
}
|
||||
|
||||
hud_reticle_set_flight_cursor_offset();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3908,9 +3914,7 @@ void hud_page_in()
|
||||
|
||||
HudGauge* hud_get_custom_gauge(const char* name, bool check_all_gauges)
|
||||
{
|
||||
ship_info *player_sip = nullptr;
|
||||
if (Player_ship && Player_ship->ship_info_index >= 0)
|
||||
player_sip = &Ship_info[Player_ship->ship_info_index];
|
||||
auto player_sip = Player_ship->ship_info_index < 0 ? nullptr : &Ship_info[Player_ship->ship_info_index];
|
||||
|
||||
// go through all gauges for all ships and defaults
|
||||
if (check_all_gauges) {
|
||||
@@ -3973,9 +3977,9 @@ int hud_get_default_gauge_index(const char *name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
HudGauge *hud_get_gauge(const char *name, bool check_all_custom_gauges)
|
||||
HudGauge *hud_get_gauge(const char *name)
|
||||
{
|
||||
auto gauge = hud_get_custom_gauge(name, check_all_custom_gauges);
|
||||
auto gauge = hud_get_custom_gauge(name);
|
||||
if (gauge == nullptr)
|
||||
{
|
||||
int idx = hud_get_default_gauge_index(name);
|
||||
|
||||
+2
-7
@@ -112,11 +112,6 @@ extern float Player_rearm_eta;
|
||||
|
||||
extern int Hud_max_targeting_range;
|
||||
|
||||
// maps of hud gauges configs to apply to ships as parsed in ships.tbl
|
||||
// this is cleared once parsing is completed
|
||||
// First string in the pair is the gauge name, second is the ship name
|
||||
extern SCP_vector<std::pair<SCP_string, SCP_string>> Hud_parsed_ships;
|
||||
|
||||
void HUD_init_colors();
|
||||
void HUD_init();
|
||||
void hud_scripting_close(lua_State*);
|
||||
@@ -199,7 +194,7 @@ void hud_maybe_render_multi_text();
|
||||
int hud_get_draw();
|
||||
void hud_toggle_draw();
|
||||
int hud_disabled();
|
||||
int hud_support_find_closest( object *objp );
|
||||
int hud_support_find_closest( int objnum );
|
||||
|
||||
// Goober5000
|
||||
void hud_set_draw(int draw);
|
||||
@@ -598,7 +593,7 @@ public:
|
||||
|
||||
HudGauge *hud_get_custom_gauge(const char *name, bool check_all_gauges = false);
|
||||
int hud_get_default_gauge_index(const char *name);
|
||||
HudGauge *hud_get_gauge(const char *name, bool check_all_custom_gauges = false);
|
||||
HudGauge *hud_get_gauge(const char *name);
|
||||
|
||||
extern SCP_vector<std::unique_ptr<HudGauge>> default_hud_gauges;
|
||||
|
||||
|
||||
@@ -132,8 +132,8 @@ void parse_ssm(const char *filename)
|
||||
{
|
||||
int temp = atoi(unique_id);
|
||||
|
||||
if (!SCP_vector_inbounds(Fireball_info, temp))
|
||||
error_display(0, "Fireball index [%d] out of range (should be 0-%d) for SSM strike [%s]", temp, static_cast<int>(Fireball_info.size()) - 1, s->name);
|
||||
if ((temp < 0) || (temp >= Num_fireball_types))
|
||||
error_display(0, "Fireball index [%d] out of range (should be 0-%d) for SSM strike [%s]", temp, Num_fireball_types - 1, s->name);
|
||||
else
|
||||
s->fireball_type = temp;
|
||||
}
|
||||
|
||||
@@ -438,7 +438,7 @@ void HudGaugeBrackets::renderObjectBrackets(object *targetp, color *clr, int w_c
|
||||
{
|
||||
int pof = 0;
|
||||
pof = Asteroids[targetp->instance].asteroid_subtype;
|
||||
modelnum = Asteroid_info[Asteroids[targetp->instance].asteroid_type].subtypes[pof].model_number;
|
||||
modelnum = Asteroid_info[Asteroids[targetp->instance].asteroid_type].model_num[pof];
|
||||
bound_rc = model_find_2d_bound_min( modelnum, &targetp->orient, &targetp->pos,&x1,&y1,&x2,&y2 );
|
||||
}
|
||||
break;
|
||||
|
||||
+11
-14
@@ -359,22 +359,19 @@ void HudGaugeEscort::renderIcon(int x, int y, int index)
|
||||
{
|
||||
hud_stuff_ship_name(buf, sp);
|
||||
|
||||
if (!Dont_show_callsigns_in_escort_list)
|
||||
// maybe concatenate the callsign
|
||||
if (*buf)
|
||||
{
|
||||
// maybe concatenate the callsign
|
||||
if (*buf)
|
||||
{
|
||||
char callsign[NAME_LENGTH];
|
||||
char callsign[NAME_LENGTH];
|
||||
|
||||
hud_stuff_ship_callsign(callsign, sp);
|
||||
if (*callsign)
|
||||
sprintf(&buf[strlen(buf)], " (%s)", callsign);
|
||||
}
|
||||
// maybe substitute the callsign
|
||||
else
|
||||
{
|
||||
hud_stuff_ship_callsign(buf, sp);
|
||||
}
|
||||
hud_stuff_ship_callsign(callsign, sp);
|
||||
if (*callsign)
|
||||
sprintf(&buf[strlen(buf)], " (%s)", callsign);
|
||||
}
|
||||
// maybe substitute the callsign
|
||||
else
|
||||
{
|
||||
hud_stuff_ship_callsign(buf, sp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -812,7 +812,7 @@ void hud_scrollback_button_pressed(int n)
|
||||
|
||||
case SHOW_EVENTS_BUTTON:
|
||||
Scrollback_mode = SCROLLBACK_MODE_EVENT_LOG;
|
||||
Scroll_max = mission_log_scrollback_num_lines() * gr_get_font_height();
|
||||
Scroll_max = Num_log_lines * gr_get_font_height();
|
||||
hud_scroll_reset();
|
||||
break;
|
||||
|
||||
@@ -913,9 +913,9 @@ void hud_scrollback_init()
|
||||
Background_bitmap = bm_load(Hud_mission_log_fname[gr_screen.res]);
|
||||
// Status_bitmap = bm_load(Hud_mission_log_status_fname[gr_screen.res]);
|
||||
|
||||
mission_log_init_scrollback(Hud_mission_log_list_coords[gr_screen.res][2]);
|
||||
message_log_init_scrollback(Hud_mission_log_list_coords[gr_screen.res][2]);
|
||||
if (Scrollback_mode == SCROLLBACK_MODE_EVENT_LOG)
|
||||
Scroll_max = mission_log_scrollback_num_lines() * gr_get_font_height();
|
||||
Scroll_max = Num_log_lines * gr_get_font_height();
|
||||
else if (Scrollback_mode == SCROLLBACK_MODE_OBJECTIVES)
|
||||
Scroll_max = Num_obj_lines * gr_get_font_height();
|
||||
else
|
||||
@@ -928,7 +928,7 @@ void hud_scrollback_init()
|
||||
void hud_scrollback_close()
|
||||
{
|
||||
ML_objectives_close();
|
||||
mission_log_shutdown_scrollback();
|
||||
message_log_shutdown_scrollback();
|
||||
if (Background_bitmap >= 0)
|
||||
bm_release(Background_bitmap);
|
||||
//if (Status_bitmap >= 0)
|
||||
@@ -960,7 +960,7 @@ void hud_scrollback_do_frame(float /*frametime*/)
|
||||
|
||||
} else if (Scrollback_mode == SCROLLBACK_MODE_MSGS_LOG) {
|
||||
Scrollback_mode = SCROLLBACK_MODE_EVENT_LOG;
|
||||
Scroll_max = mission_log_scrollback_num_lines() * gr_get_font_height();
|
||||
Scroll_max = Num_log_lines * gr_get_font_height();
|
||||
hud_scroll_reset();
|
||||
|
||||
} else {
|
||||
@@ -975,7 +975,7 @@ void hud_scrollback_do_frame(float /*frametime*/)
|
||||
case KEY_SHIFTED | KEY_TAB:
|
||||
if (Scrollback_mode == SCROLLBACK_MODE_OBJECTIVES) {
|
||||
Scrollback_mode = SCROLLBACK_MODE_EVENT_LOG;
|
||||
Scroll_max = mission_log_scrollback_num_lines() * gr_get_font_height();
|
||||
Scroll_max = Num_log_lines * gr_get_font_height();
|
||||
hud_scroll_reset();
|
||||
|
||||
} else if (Scrollback_mode == SCROLLBACK_MODE_MSGS_LOG) {
|
||||
|
||||
+3
-47
@@ -216,8 +216,6 @@ int parse_ship_start()
|
||||
return ship_index;
|
||||
}
|
||||
|
||||
SCP_vector<std::pair<SCP_string, SCP_string>> Hud_parsed_ships;
|
||||
|
||||
void parse_hud_gauges_tbl(const char *filename)
|
||||
{
|
||||
int i;
|
||||
@@ -343,11 +341,10 @@ void parse_hud_gauges_tbl(const char *filename)
|
||||
SCP_vector<int> ship_classes;
|
||||
bool retail_config = false;
|
||||
int n_ships = 0;
|
||||
SCP_string name;
|
||||
|
||||
while (optional_string("#Gauge Config")) {
|
||||
ship_classes.clear();
|
||||
switch (optional_string_one_of(3, "$Ship:", "$Ships:", "$Name:")) {
|
||||
switch (optional_string_either("$Ship:", "$Ships:")) {
|
||||
case 0:
|
||||
mprintf(("$Ship in hud_gauges.tbl and -hdg.tbms is deprecated. Use \"$Ships: (\"Some ship class\") instead.\n"));
|
||||
|
||||
@@ -394,8 +391,6 @@ void parse_hud_gauges_tbl(const char *filename)
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
mprintf(("$Ships in hud_gauges.tbl and -hdg.tbms can be replaced. Gauge Config Settings can now be defined per-ship in ships.tbl. \n"));
|
||||
|
||||
int shiparray[256];
|
||||
|
||||
n_ships = (int)stuff_int_list(shiparray, 256, SHIP_INFO_TYPE);
|
||||
@@ -418,38 +413,6 @@ void parse_hud_gauges_tbl(const char *filename)
|
||||
ship_clr_p = &ship_color;
|
||||
}
|
||||
|
||||
if (optional_string("$Font:")) {
|
||||
ship_font = font::parse_font();
|
||||
}
|
||||
if (optional_string("$Chase View Only:")) {
|
||||
stuff_boolean(&chase_view_only);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
stuff_string(name, F_NAME);
|
||||
|
||||
if (optional_string("$Load Retail Configuration:")) {
|
||||
stuff_boolean(&retail_config);
|
||||
}
|
||||
|
||||
// Here we add in any ships who set their HUD Config in ships.tbl
|
||||
for (const auto& pair : Hud_parsed_ships) {
|
||||
if (!stricmp(pair.first.c_str(), name.c_str())) {
|
||||
int idx = ship_info_lookup(pair.second.c_str());
|
||||
ship_classes.push_back(idx);
|
||||
Ship_info[idx].hud_enabled = true;
|
||||
Ship_info[idx].hud_retail = retail_config;
|
||||
}
|
||||
}
|
||||
|
||||
if (optional_string("$Color:")) {
|
||||
stuff_int_list(colors, 3);
|
||||
|
||||
check_color(colors);
|
||||
gr_init_alphacolor(&ship_color, colors[0], colors[1], colors[2], 255);
|
||||
ship_clr_p = &ship_color;
|
||||
}
|
||||
|
||||
if (optional_string("$Font:")) {
|
||||
ship_font = font::parse_font();
|
||||
}
|
||||
@@ -617,8 +580,6 @@ void hud_positions_init()
|
||||
|
||||
// load missing retail gauges for the default and ship-specific HUDs
|
||||
load_missing_retail_gauges();
|
||||
|
||||
Hud_parsed_ships.clear();
|
||||
}
|
||||
|
||||
void load_missing_retail_gauges()
|
||||
@@ -2171,7 +2132,6 @@ void load_gauge_center_reticle(gauge_settings* settings)
|
||||
int scaleY = 10;
|
||||
int size = 5;
|
||||
int autoaim_frame = -1;
|
||||
int flight_cursor_frame = -1;
|
||||
|
||||
settings->origin[0] = 0.5f;
|
||||
settings->origin[1] = 0.5f;
|
||||
@@ -2221,17 +2181,13 @@ void load_gauge_center_reticle(gauge_settings* settings)
|
||||
if (optional_string("Firepoint Y coordinate multiplier:"))
|
||||
stuff_int(&scaleY);
|
||||
|
||||
if (optional_string("Autoaim Frame:"))
|
||||
if(optional_string("Autoaim Frame:"))
|
||||
stuff_int(&autoaim_frame);
|
||||
|
||||
if (optional_string("Flight Cursor Frame:"))
|
||||
stuff_int(&flight_cursor_frame);
|
||||
|
||||
hud_gauge->initBitmaps(fname);
|
||||
hud_gauge->initHiRes(fname);
|
||||
hud_gauge->initFirepointDisplay(firepoints, scaleX, scaleY, size);
|
||||
hud_gauge->setAutoaimFrame(autoaim_frame);
|
||||
hud_gauge->setFlightCursorFrame(flight_cursor_frame);
|
||||
|
||||
gauge_assign_common(settings, std::move(hud_gauge));
|
||||
}
|
||||
@@ -5520,7 +5476,7 @@ void load_gauge_scripting(gauge_settings* settings) {
|
||||
SCP_string name;
|
||||
stuff_string(name, F_NAME);
|
||||
|
||||
hud_gauge->initName(std::move(name));
|
||||
hud_gauge->initName(name);
|
||||
|
||||
gauge_assign_common(settings, std::move(hud_gauge));
|
||||
}
|
||||
+21
-73
@@ -225,8 +225,6 @@ int Reticle_launch_coords[GR_NUM_RESOLUTIONS][2] = {
|
||||
static int Threat_lock_timer; // timestamp for when to show next flashing frame for lock threat
|
||||
static int Threat_lock_frame; // frame offset of current lock flashing warning
|
||||
|
||||
static vertex Player_flight_cursor_offset;
|
||||
|
||||
|
||||
HudGaugeReticle::HudGaugeReticle():
|
||||
HudGauge(HUD_OBJECT_CENTER_RETICLE, HUD_CENTER_RETICLE, true, false, (VM_EXTERNAL | VM_DEAD_VIEW | VM_WARP_CHASE | VM_PADLOCK_ANY | VM_TOPDOWN | VM_OTHER_SHIP), 255, 255, 255)
|
||||
@@ -256,8 +254,6 @@ void HudGaugeReticle::render(float /*frametime*/)
|
||||
}
|
||||
|
||||
ship_info *sip = &Ship_info[Player_ship->ship_info_index];
|
||||
int bitmap_size_x, bitmap_size_y;
|
||||
bm_get_info(crosshair.first_frame, &bitmap_size_x, &bitmap_size_y);
|
||||
|
||||
if (autoaim_frame_offset > 0 || sip->autoaim_lock_snd.isValid() || sip->autoaim_lost_snd.isValid()) {
|
||||
ship *shipp = &Ships[Objects[Player->objnum].instance];
|
||||
@@ -287,66 +283,38 @@ void HudGaugeReticle::render(float /*frametime*/)
|
||||
|
||||
setGaugeColor(HUD_C_BRIGHT);
|
||||
|
||||
// the typical reticle indicating the direction of shooting
|
||||
int shoot_reticle = 0;
|
||||
if (has_autoaim_lock)
|
||||
shoot_reticle = crosshair.first_frame + autoaim_frame_offset;
|
||||
else
|
||||
shoot_reticle = crosshair.first_frame;
|
||||
|
||||
// a secondary 'reticle' for distinguishing the flight cursor from the above
|
||||
int flight_reticle = flight_cursor_frame_offset >= 0 ? crosshair.first_frame + flight_cursor_frame_offset : -1;
|
||||
|
||||
int mobile_reticle = flight_reticle;
|
||||
int fixed_reticle = shoot_reticle;
|
||||
// depending on the parameters of the ship the 'mobile' reticle may be the one indicating the shoot direction
|
||||
if (sip->aims_at_flight_cursor) {
|
||||
mobile_reticle = shoot_reticle;
|
||||
fixed_reticle = flight_reticle;
|
||||
}
|
||||
|
||||
|
||||
if (fixed_reticle == shoot_reticle)
|
||||
setGaugeColor(HUD_C_BRIGHT);
|
||||
else
|
||||
setGaugeColor(HUD_C_NORMAL);
|
||||
|
||||
if (fixed_reticle >= 0) {
|
||||
if (HUD_shadows) {
|
||||
gr_set_color_fast(&Color_black);
|
||||
if (HUD_shadows){
|
||||
gr_set_color_fast(&Color_black);
|
||||
|
||||
if (has_autoaim_lock)
|
||||
{
|
||||
// Render the shadow twice to increase visibility
|
||||
renderBitmap(fixed_reticle, position[0] + 1, position[1] + 1);
|
||||
renderBitmap(fixed_reticle, position[0] + 1, position[1] + 1);
|
||||
gr_set_color_fast(&gauge_color);
|
||||
renderBitmap(crosshair.first_frame + autoaim_frame_offset, position[0] + 1, position[1] + 1);
|
||||
renderBitmap(crosshair.first_frame + autoaim_frame_offset, position[0] + 1, position[1] + 1);
|
||||
}
|
||||
|
||||
renderBitmap(fixed_reticle, position[0], position[1]);
|
||||
} else {
|
||||
renderCircle(fl2i(base_w * 0.5f), fl2i(base_h * 0.5f), fl2i(base_h * 0.03f), false);
|
||||
}
|
||||
|
||||
if (Player_flight_mode == FlightMode::FlightCursor || sip->aims_at_flight_cursor) {
|
||||
if (mobile_reticle == shoot_reticle)
|
||||
setGaugeColor(HUD_C_BRIGHT);
|
||||
else
|
||||
setGaugeColor(HUD_C_NORMAL);
|
||||
|
||||
int x = fl2i(Player_flight_cursor_offset.screen.xyw.x + 0.5f);
|
||||
int y = fl2i(Player_flight_cursor_offset.screen.xyw.y + 0.5f);
|
||||
unsize(&x, &y);
|
||||
if (mobile_reticle >= 0)
|
||||
renderBitmap(mobile_reticle, fl2i(x - base_w * 0.5f) + position[0], fl2i(y - base_h * 0.5f) + position[1]);
|
||||
else {
|
||||
renderCircle(x, y, fl2i(base_h * 0.03f), false);
|
||||
{
|
||||
// Render the shadow twice to increase visibility
|
||||
renderBitmap(crosshair.first_frame, position[0] + 1, position[1] + 1);
|
||||
renderBitmap(crosshair.first_frame, position[0] + 1, position[1] + 1);
|
||||
}
|
||||
gr_set_color_fast(&gauge_color);
|
||||
}
|
||||
|
||||
if (has_autoaim_lock)
|
||||
renderBitmap(crosshair.first_frame + autoaim_frame_offset, position[0], position[1]);
|
||||
else
|
||||
renderBitmap(crosshair.first_frame, position[0], position[1]);
|
||||
|
||||
if (firepoint_display) {
|
||||
fp.clear();
|
||||
getFirepointStatus();
|
||||
|
||||
if (!fp.empty()) {
|
||||
int ax, ay;
|
||||
bm_get_info(crosshair.first_frame, &ax, &ay);
|
||||
int centerX = position[0] + (ax / 2);
|
||||
int centerY = position[1] + (ay / 2);
|
||||
|
||||
for (SCP_vector<firepoint>::iterator fpi = fp.begin(); fpi != fp.end(); ++fpi) {
|
||||
if (fpi->active == 2)
|
||||
@@ -355,9 +323,7 @@ void HudGaugeReticle::render(float /*frametime*/)
|
||||
setGaugeColor(HUD_C_NORMAL);
|
||||
else
|
||||
setGaugeColor(HUD_C_DIM);
|
||||
|
||||
int centerX = position[0] + (bitmap_size_x / 2);
|
||||
int centerY = position[1] + (bitmap_size_y / 2);
|
||||
|
||||
renderCircle((int) (centerX + (fpi->xy.x * firepoint_scale_x)), (int) (centerY + (fpi->xy.y * firepoint_scale_y)), firepoint_size);
|
||||
}
|
||||
}
|
||||
@@ -449,13 +415,6 @@ void HudGaugeReticle::getFirepointStatus() {
|
||||
}
|
||||
}
|
||||
|
||||
void HudGaugeReticle::setFlightCursorFrame(int framenum) {
|
||||
if (framenum < 0 || framenum > crosshair.num_frames - 1)
|
||||
flight_cursor_frame_offset = -1;
|
||||
else
|
||||
flight_cursor_frame_offset = framenum;
|
||||
}
|
||||
|
||||
void HudGaugeReticle::setAutoaimFrame(int framenum) {
|
||||
if (framenum < 0 || framenum > crosshair.num_frames - 1)
|
||||
autoaim_frame_offset = 0;
|
||||
@@ -1181,14 +1140,3 @@ void hud_update_reticle( player *pp )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// calculates what the screen position of the flight cursor should be
|
||||
void hud_reticle_set_flight_cursor_offset() {
|
||||
matrix view_mat;
|
||||
vm_angles_2_matrix(&view_mat, &Player_flight_cursor);
|
||||
view_mat = view_mat * Eye_matrix;
|
||||
|
||||
vec3d view_pos = Eye_position + view_mat.vec.fvec * 10000.0f;
|
||||
g3_rotate_vertex(&Player_flight_cursor_offset, &view_pos);
|
||||
g3_project_vertex(&Player_flight_cursor_offset);
|
||||
}
|
||||
@@ -44,7 +44,6 @@ protected:
|
||||
int firepoint_scale_y;
|
||||
int autoaim_frame_offset;
|
||||
bool has_autoaim_lock;
|
||||
int flight_cursor_frame_offset;
|
||||
public:
|
||||
HudGaugeReticle();
|
||||
void render(float frametime) override;
|
||||
@@ -53,7 +52,6 @@ public:
|
||||
void initFirepointDisplay(bool firepoint, int scaleX, int scaleY, int size);
|
||||
void getFirepointStatus();
|
||||
void setAutoaimFrame(int framenum);
|
||||
void setFlightCursorFrame(int framenum);
|
||||
};
|
||||
|
||||
class HudGaugeThrottle: public HudGauge
|
||||
@@ -170,6 +168,5 @@ public:
|
||||
|
||||
void hud_init_reticle();
|
||||
void hud_update_reticle( player *pp );
|
||||
void hud_reticle_set_flight_cursor_offset();
|
||||
|
||||
#endif
|
||||
@@ -641,7 +641,7 @@ void HudGaugeShield::showShields(object *objp, int mode)
|
||||
model_render_params render_info;
|
||||
|
||||
render_info.set_flags(MR_NO_LIGHTING | MR_AUTOCENTER | MR_NO_FOGGING);
|
||||
render_info.set_replacement_textures(model_get_instance(sp->model_instance_num)->texture_replace);
|
||||
render_info.set_replacement_textures(sp->ship_replacement_textures);
|
||||
render_info.set_detail_level_lock(1);
|
||||
render_info.set_object_number(OBJ_INDEX(objp));
|
||||
|
||||
|
||||
@@ -508,7 +508,7 @@ int hud_squadmsg_read_key( int k )
|
||||
// after messaging is over. Return true for a while.
|
||||
if ( !timestamp_elapsed(Msg_eat_key_timestamp) ) {
|
||||
for (i = 0; i < num_keys_used; i++ ) {
|
||||
if ( key_is_pressed(keys_used[i]) )
|
||||
if ( keyd_pressed[keys_used[i]] )
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -524,7 +524,7 @@ int hud_squadmsg_read_key( int k )
|
||||
key_found = 1;
|
||||
}
|
||||
|
||||
if ( key_is_pressed(k) ) {
|
||||
if ( keyd_pressed[k] ) {
|
||||
key_found = 1;
|
||||
}
|
||||
|
||||
@@ -639,7 +639,7 @@ void hud_squadmsg_repair_rearm( int toggle_state, object *objp)
|
||||
if ( mission_is_repair_scheduled( tobj ) ) {
|
||||
message_send_builtin(MESSAGE_ALREADY_ON_WAY, nullptr, nullptr, multi_player_num, multi_player_team);
|
||||
} else {
|
||||
robjnum = hud_support_find_closest( tobj );
|
||||
robjnum = hud_support_find_closest(OBJ_INDEX(tobj));
|
||||
if ( robjnum != -1 ) {
|
||||
message_send_builtin(MESSAGE_ALREADY_ON_WAY, &Ships[Objects[robjnum].instance], nullptr, multi_player_num, multi_player_team);
|
||||
} else {
|
||||
|
||||
+15
-34
@@ -1587,14 +1587,13 @@ int hud_target_ship_can_be_scanned(ship *shipp)
|
||||
if (shipp->flags[Ship::Ship_Flags::Cargo_revealed])
|
||||
return 0;
|
||||
|
||||
// The old behavior treats some ship types as always scannable. The new behavior only checks the ship's Scannable flag.
|
||||
if (shipp->flags[Ship::Ship_Flags::Scannable]) {
|
||||
// allow ships with scannable flag set
|
||||
if (shipp->flags[Ship::Ship_Flags::Scannable])
|
||||
return 1;
|
||||
} else if (Use_new_scanning_behavior) {
|
||||
|
||||
// ignore ships that don't carry cargo
|
||||
if ((sip->class_type < 0) || !(Ship_types[sip->class_type].flags[Ship::Type_Info_Flags::Scannable]))
|
||||
return 0;
|
||||
} else if ((sip->class_type < 0) || !(Ship_types[sip->class_type].flags[Ship::Type_Info_Flags::Scannable])) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -2519,7 +2518,7 @@ void hud_target_in_reticle_new()
|
||||
{
|
||||
int pof = 0;
|
||||
pof = Asteroids[A->instance].asteroid_subtype;
|
||||
mc.model_num = Asteroid_info[Asteroids[A->instance].asteroid_type].subtypes[pof].model_number;
|
||||
mc.model_num = Asteroid_info[Asteroids[A->instance].asteroid_type].model_num[pof];
|
||||
}
|
||||
break;
|
||||
case OBJ_JUMP_NODE:
|
||||
@@ -3046,7 +3045,7 @@ void HudGaugeReticleTriangle::renderTriangle(vec3d *hostile_pos, int aspect_flag
|
||||
// even if the screen position overflowed, it will still be pointing in the correct direction
|
||||
unsize( &hostile_vertex.screen.xyw.x, &hostile_vertex.screen.xyw.y );
|
||||
|
||||
ang = atan2(-(hostile_vertex.screen.xyw.y - tablePosY), hostile_vertex.screen.xyw.x - tablePosX);
|
||||
ang = atan2_safe(-(hostile_vertex.screen.xyw.y - tablePosY), hostile_vertex.screen.xyw.x - tablePosX);
|
||||
sin_ang=sinf(ang);
|
||||
cos_ang=cosf(ang);
|
||||
|
||||
@@ -4039,7 +4038,6 @@ void HudGaugeLeadIndicator::renderLeadCurrentTarget()
|
||||
//overwritten if using non-default leadIndicatorBehaviors, this is desired.
|
||||
bank_to_fire = hud_get_best_primary_bank(&prange);
|
||||
wip = &Weapon_info[swp->primary_bank_weapons[bank_to_fire]];
|
||||
bool no_primary_indicator = false;
|
||||
|
||||
if (Lead_indicator_behavior != leadIndicatorBehavior::DEFAULT && Player_ship->flags[Ship::Ship_Flags::Primary_linked]) {
|
||||
vec3d averaged_lead_pos;
|
||||
@@ -4068,7 +4066,6 @@ void HudGaugeLeadIndicator::renderLeadCurrentTarget()
|
||||
continue;
|
||||
}
|
||||
|
||||
// Note! This is function call that actually determines if primary or secondary target gauges are going to be rendered.
|
||||
frame_offset = pickFrame(weapon_range, srange, dist_to_target);
|
||||
|
||||
if (frame_offset >= 0) {
|
||||
@@ -4084,10 +4081,6 @@ void HudGaugeLeadIndicator::renderLeadCurrentTarget()
|
||||
if (average_instances > 0 && Lead_indicator_behavior == leadIndicatorBehavior::AVERAGE) {
|
||||
averaged_lead_pos = averaged_lead_pos/i2fl(average_instances);
|
||||
renderIndicator(frame_offset, targetp, &averaged_lead_pos);
|
||||
|
||||
// This handles an edge case where secondary weapon indicators might not have been rendered, despite possibly being in range.
|
||||
} else if ( frame_offset == -1) {
|
||||
no_primary_indicator = true;
|
||||
}
|
||||
}
|
||||
else if (bank_to_fire >= 0) { //leadIndicatorBehavior::DEFAULT
|
||||
@@ -4095,11 +4088,7 @@ void HudGaugeLeadIndicator::renderLeadCurrentTarget()
|
||||
prange = 0.0f; // no ballistic trajectory, primary is 'always out of range'
|
||||
}
|
||||
|
||||
// Note! This is function call that actually determines if primary or secondary target gauges are going to be rendered.
|
||||
frame_offset = pickFrame(prange, srange, dist_to_target);
|
||||
|
||||
// note here, that srange being -1.0f is indicative of the Dont_merge_indicators flag being used above,
|
||||
// or the missile being a dumbfire.
|
||||
if ( frame_offset < 0 && srange != -1.0f ) {
|
||||
return;
|
||||
}
|
||||
@@ -4108,26 +4097,16 @@ void HudGaugeLeadIndicator::renderLeadCurrentTarget()
|
||||
renderIndicator(frame_offset, targetp, &lead_target_pos);
|
||||
}
|
||||
}
|
||||
//Cyborg - this `else return;` would force the secondary indicator off if no primaries are available.
|
||||
//Sure this is not a very common case, but we don't need the early return.
|
||||
//We are safe from any ill effects because we're not going to try to render any primary indicators
|
||||
//after this point anyway (the first argument for renderIndicator is forced to 0 below).
|
||||
//Anyone who rewrites this function to somehow re-evaluate primary indicators will have to revist this.
|
||||
//else return;
|
||||
|
||||
else return;
|
||||
|
||||
//do dumbfire lead indicator - color is orange (255,128,0) - bright, (192,96,0) - dim
|
||||
//phreak changed 9/01/02
|
||||
//Cyborg - This section mainly handles dumbfire indicators, unless Dont_merge_indicators is set, forcing a separate indicator
|
||||
//for homing weapons. OR if no_primary_indicator is true (no primary indicator was drawn when in multiple or average mode)
|
||||
//We are guaranteed (if the target is in the homing cone) to get here because in both of those situations srange is
|
||||
//forced to -1.0f, precluding the early returns.
|
||||
if((swp->current_secondary_bank>=0) && (swp->secondary_bank_weapons[swp->current_secondary_bank] >= 0)) {
|
||||
int bank=swp->current_secondary_bank;
|
||||
wip=&Weapon_info[swp->secondary_bank_weapons[bank]];
|
||||
|
||||
//get out of here if the secondary weapon is a homer and we don't have independent indicator behavior
|
||||
if ( wip->is_homing() && !wip->wi_flags[Weapon::Info_Flags::Dont_merge_indicators] && !no_primary_indicator )
|
||||
//get out of here if the secondary weapon is a homer or if its out of range
|
||||
if ( wip->is_homing() && !wip->wi_flags[Weapon::Info_Flags::Dont_merge_indicators] )
|
||||
return;
|
||||
|
||||
double max_dist = MIN((wip->lifetime * wip->max_speed), wip->weapon_range);
|
||||
@@ -4772,7 +4751,7 @@ int hud_communications_state(ship *sp, bool for_death_scream)
|
||||
}
|
||||
|
||||
// Goober5000 - check for scrambled communications
|
||||
if ((emp_active_local() && !sp->flags[Ship::Ship_Flags::EMP_doesnt_scramble_messages]) || sp->flags[Ship::Ship_Flags::Scramble_messages])
|
||||
if (emp_active_local() || sp->flags[Ship::Ship_Flags::Scramble_messages])
|
||||
return COMM_SCRAMBLED;
|
||||
|
||||
return COMM_OK;
|
||||
@@ -6561,7 +6540,8 @@ void HudGaugeOffscreen::calculatePosition(vertex* target_point, vec3d *tpos, vec
|
||||
g3_project_vertex(eye_vertex);
|
||||
|
||||
if (eye_vertex->flags&PF_OVERFLOW) {
|
||||
// This is unlikely to happen, but can if a clip goes through the player's eye.
|
||||
Int3(); // This is unlikely to happen, but can if a clip goes through the player's eye.
|
||||
Player_ai->target_objnum = -1;
|
||||
if (!in_frame)
|
||||
g3_end_frame();
|
||||
return;
|
||||
@@ -6623,6 +6603,7 @@ void HudGaugeOffscreen::calculatePosition(vertex* target_point, vec3d *tpos, vec
|
||||
xpos = gr_screen.clip_right_unscaled - half_gauge_length;
|
||||
|
||||
} else {
|
||||
Int3();
|
||||
if (!in_frame)
|
||||
g3_end_frame();
|
||||
return;
|
||||
@@ -7369,7 +7350,7 @@ void HudGaugeHardpoints::render(float /*frametime*/)
|
||||
vertex draw_point;
|
||||
vec3d subobj_pos;
|
||||
|
||||
uint64_t render_flags = MR_NO_LIGHTING | MR_AUTOCENTER | MR_NO_FOGGING | MR_NO_TEXTURING | MR_NO_ZBUFFER;
|
||||
int render_flags = MR_NO_LIGHTING | MR_AUTOCENTER | MR_NO_FOGGING | MR_NO_TEXTURING | MR_NO_ZBUFFER;
|
||||
|
||||
setGaugeColor();
|
||||
float alpha = gr_screen.current_color.alpha / 255.0f;
|
||||
|
||||
+11
-19
@@ -57,7 +57,7 @@ static int Target_static_next;
|
||||
static int Target_static_playing;
|
||||
sound_handle Target_static_looping = sound_handle::invalid();
|
||||
|
||||
bool Target_display_cargo;
|
||||
int Target_display_cargo;
|
||||
char Cargo_string[256] = "";
|
||||
|
||||
#ifndef NDEBUG
|
||||
@@ -570,7 +570,7 @@ void HudGaugeTargetBox::renderTargetShip(object *target_objp)
|
||||
target_shipp = &Ships[target_objp->instance];
|
||||
target_sip = &Ship_info[target_shipp->ship_info_index];
|
||||
|
||||
uint64_t flags = 0;
|
||||
int flags=0;
|
||||
if ( Detail.targetview_model ) {
|
||||
// take the forward orientation to be the vector from the player to the current target
|
||||
vm_vec_sub(&orient_vec, &target_objp->pos, &Player_obj->pos);
|
||||
@@ -677,7 +677,7 @@ void HudGaugeTargetBox::renderTargetShip(object *target_objp)
|
||||
if(target_sip->model_num_hud >= 0){
|
||||
model_render_immediate( &render_info, target_sip->model_num_hud, &target_objp->orient, &obj_pos);
|
||||
} else {
|
||||
render_info.set_replacement_textures(model_get_instance(target_shipp->model_instance_num)->texture_replace);
|
||||
render_info.set_replacement_textures(target_shipp->ship_replacement_textures);
|
||||
|
||||
model_render_immediate( &render_info, target_sip->model_num, &target_objp->orient, &obj_pos);
|
||||
}
|
||||
@@ -746,7 +746,7 @@ void HudGaugeTargetBox::renderTargetDebris(object *target_objp)
|
||||
debris *debrisp;
|
||||
vec3d orient_vec, up_vector;
|
||||
float factor;
|
||||
uint64_t flags = 0;
|
||||
int flags=0;
|
||||
|
||||
debrisp = &Debris[target_objp->instance];
|
||||
|
||||
@@ -777,9 +777,6 @@ void HudGaugeTargetBox::renderTargetDebris(object *target_objp)
|
||||
|
||||
model_render_params render_info;
|
||||
|
||||
if (debrisp->model_instance_num >= 0)
|
||||
render_info.set_replacement_textures(model_get_instance(debrisp->model_instance_num)->texture_replace);
|
||||
|
||||
color thisColor = GaugeWirecolor;
|
||||
bool thisOverride = GaugeWirecolorOverride;
|
||||
|
||||
@@ -866,9 +863,9 @@ void HudGaugeTargetBox::renderTargetWeapon(object *target_objp)
|
||||
weapon_info *target_wip = NULL;
|
||||
weapon *wp = NULL;
|
||||
object *viewer_obj, *viewed_obj;
|
||||
std::shared_ptr<model_texture_replace> replacement_textures = nullptr;
|
||||
int *replacement_textures = NULL;
|
||||
int target_team, is_homing, is_player_missile, missile_view, viewed_model_num, hud_target_lod, w, h;
|
||||
uint64_t flags = 0;
|
||||
int flags=0;
|
||||
|
||||
target_team = obj_team(target_objp);
|
||||
|
||||
@@ -905,13 +902,10 @@ void HudGaugeTargetBox::renderTargetWeapon(object *target_objp)
|
||||
viewed_obj = wp->homing_object;
|
||||
missile_view = TRUE;
|
||||
viewed_model_num = homing_sip->model_num;
|
||||
replacement_textures = homing_shipp->ship_replacement_textures;
|
||||
hud_target_lod = homing_sip->hud_target_lod;
|
||||
}
|
||||
|
||||
int pmi_id = object_get_model_instance(viewed_obj);
|
||||
if (pmi_id >= 0)
|
||||
replacement_textures = model_get_instance(pmi_id)->texture_replace;
|
||||
|
||||
// take the forward orientation to be the vector from the player to the current target
|
||||
vm_vec_sub(&orient_vec, &viewed_obj->pos, &viewer_obj->pos);
|
||||
vm_vec_normalize(&orient_vec);
|
||||
@@ -1074,6 +1068,7 @@ void HudGaugeTargetBox::renderTargetWeapon(object *target_objp)
|
||||
model_render_immediate( &render_info, homing_sip->model_num_hud, &viewed_obj->orient, &obj_pos);
|
||||
} else {
|
||||
render_info.set_flags(flags | MR_NO_FOGGING);
|
||||
render_info.set_replacement_textures(homing_shipp->ship_replacement_textures);
|
||||
|
||||
model_render_immediate( &render_info, homing_sip->model_num, &viewed_obj->orient, &obj_pos );
|
||||
}
|
||||
@@ -1141,7 +1136,7 @@ void HudGaugeTargetBox::renderTargetAsteroid(object *target_objp)
|
||||
float time_to_impact, factor;
|
||||
int pof;
|
||||
|
||||
uint64_t flags = 0; //draw flags for wireframe
|
||||
int flags=0; //draw flags for wireframe
|
||||
asteroidp = &Asteroids[target_objp->instance];
|
||||
|
||||
pof = asteroidp->asteroid_subtype;
|
||||
@@ -1171,13 +1166,10 @@ void HudGaugeTargetBox::renderTargetAsteroid(object *target_objp)
|
||||
vm_vec_copy_scale(&obj_pos,&orient_vec,factor);
|
||||
|
||||
renderTargetSetup(&camera_eye, &camera_orient, 0.5f);
|
||||
model_clear_instance(Asteroid_info[asteroidp->asteroid_type].subtypes[pof].model_number);
|
||||
model_clear_instance(Asteroid_info[asteroidp->asteroid_type].model_num[pof]);
|
||||
|
||||
model_render_params render_info;
|
||||
|
||||
if (asteroidp->model_instance_num >= 0)
|
||||
render_info.set_replacement_textures(model_get_instance(asteroidp->model_instance_num)->texture_replace);
|
||||
|
||||
color thisColor = GaugeWirecolor;
|
||||
bool thisOverride = GaugeWirecolorOverride;
|
||||
|
||||
@@ -1231,7 +1223,7 @@ void HudGaugeTargetBox::renderTargetAsteroid(object *target_objp)
|
||||
|
||||
render_info.set_flags(flags | MR_NO_FOGGING);
|
||||
|
||||
model_render_immediate( &render_info, Asteroid_info[asteroidp->asteroid_type].subtypes[pof].model_number, &target_objp->orient, &obj_pos );
|
||||
model_render_immediate( &render_info, Asteroid_info[asteroidp->asteroid_type].model_num[pof], &target_objp->orient, &obj_pos );
|
||||
|
||||
if ( Monitor_mask >= 0 ) {
|
||||
gr_stencil_set(GR_STENCIL_NONE);
|
||||
|
||||
@@ -30,7 +30,7 @@ class object;
|
||||
#define TBOX_FLASH_SUBSYS 4
|
||||
|
||||
extern sound_handle Target_static_looping;
|
||||
extern bool Target_display_cargo;
|
||||
extern int Target_display_cargo;
|
||||
extern char Cargo_string[256];
|
||||
|
||||
extern int Target_window_coords[GR_NUM_RESOLUTIONS][4];
|
||||
|
||||
+32
-133
@@ -13,7 +13,6 @@
|
||||
#include "mission/missionparse.h"
|
||||
#include "parse/parselo.h"
|
||||
#include "ship/ship.h"
|
||||
#include "options/Option.h"
|
||||
|
||||
extern int radar_target_id_flags;
|
||||
|
||||
@@ -41,21 +40,6 @@ flag_def_list rti_flags[] = {
|
||||
|
||||
int Num_rti_flags = sizeof(rti_flags)/sizeof(flag_def_list);
|
||||
|
||||
static bool AccessiblitySupported = false;
|
||||
|
||||
// used by In-Game Options menu
|
||||
static bool AccessibilityEnabled = false;
|
||||
|
||||
static auto AccessibilityOption = options::OptionBuilder<bool>("Game.IffAccessibility",
|
||||
std::pair<const char*, int>{"Accessibility IFF Colors", 1855},
|
||||
std::pair<const char*, int>{"Enables or disables IFF Accessibility color overrides", 1856})
|
||||
.category(std::make_pair("Game", 1824))
|
||||
.default_val(false)
|
||||
.level(options::ExpertLevel::Advanced)
|
||||
.bind_to_once(&AccessibilityEnabled)
|
||||
.importance(60)
|
||||
.finish();
|
||||
|
||||
/**
|
||||
* Borrowed from ship.cpp, ship_iff_init_colors
|
||||
*
|
||||
@@ -129,8 +113,6 @@ struct observed_color_t {
|
||||
|
||||
static SCP_vector<SCP_vector<observed_color_t>> observed_color_table;
|
||||
|
||||
static SCP_vector<SCP_vector<observed_color_t>> accessibility_observed_color_table;
|
||||
|
||||
void resolve_iff_data()
|
||||
{
|
||||
// first get the traitor
|
||||
@@ -175,30 +157,13 @@ void resolve_iff_data()
|
||||
int target_iff = iff_lookup(observed_color.iff_name);
|
||||
|
||||
// valid?
|
||||
if (target_iff >= 0) {
|
||||
if (target_iff >= 0)
|
||||
iff->observed_color_map[target_iff] = observed_color.color_index;
|
||||
} else{
|
||||
else
|
||||
Warning(LOCATION,
|
||||
"Observed color IFF %s not found for IFF %s in iff_defs.tbl!\n",
|
||||
observed_color.iff_name,
|
||||
iff->iff_name);
|
||||
}
|
||||
}
|
||||
|
||||
// resolve the accessibility observed color list names
|
||||
for (const auto& observed_color : accessibility_observed_color_table[cur_iff]) {
|
||||
// find out who
|
||||
int target_iff = iff_lookup(observed_color.iff_name);
|
||||
|
||||
// valid?
|
||||
if (target_iff >= 0) {
|
||||
iff->accessibility_observed_color_map[target_iff] = observed_color.color_index;
|
||||
} else {
|
||||
Warning(LOCATION,
|
||||
"Observed color IFF %s not found for IFF %s in iff_defs.tbl!\n",
|
||||
observed_color.iff_name,
|
||||
iff->iff_name);
|
||||
}
|
||||
}
|
||||
|
||||
// resolve the all teams at war relationships
|
||||
@@ -281,10 +246,6 @@ void parse_iff_table(const char* filename)
|
||||
stuff_string(traitor_name, F_NAME, NAME_LENGTH);
|
||||
}
|
||||
|
||||
if (optional_string("$Accessibility Supported:")) {
|
||||
stuff_boolean(&AccessiblitySupported);
|
||||
}
|
||||
|
||||
int rgb[3];
|
||||
|
||||
// check if alternate colours are wanted to be used for these
|
||||
@@ -474,12 +435,9 @@ void parse_iff_table(const char* filename)
|
||||
Iff_info.push_back(ifft);
|
||||
attack_names.emplace_back();
|
||||
observed_color_table.emplace_back();
|
||||
accessibility_observed_color_table.emplace_back();
|
||||
iffp = &Iff_info[Iff_info.size() - 1];
|
||||
//Initialize this to white for new IFFs
|
||||
iffp->color_index = iff_init_color(255, 255, 255);
|
||||
// Initialize this to white for new IFFs
|
||||
iffp->accessibility_color_index = iff_init_color(255, 255, 255);
|
||||
//Make sure flags are reset for new IFFs
|
||||
iffp->default_parse_flags.reset();
|
||||
}
|
||||
@@ -492,12 +450,6 @@ void parse_iff_table(const char* filename)
|
||||
iffp->color_index = iff_init_color(rgb[0], rgb[1], rgb[2]);
|
||||
}
|
||||
|
||||
// get the accessiblity iff color
|
||||
if (optional_string_either("$Accessibility Colour:", "$Accessibility Color:") != -1) {
|
||||
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
|
||||
iffp->accessibility_color_index = iff_init_color(rgb[0], rgb[1], rgb[2]);
|
||||
}
|
||||
|
||||
|
||||
// get relationships between IFFs -------------------------------------
|
||||
|
||||
@@ -518,18 +470,6 @@ void parse_iff_table(const char* filename)
|
||||
observed_color_table[cur_iff].back().color_index = iff_init_color(rgb[0], rgb[1], rgb[2]);
|
||||
}
|
||||
|
||||
// get the list of accessibility observed colors
|
||||
while (optional_string("+Accessibility Sees")) {
|
||||
accessibility_observed_color_table[cur_iff].emplace_back();
|
||||
// get iff observed
|
||||
stuff_string_until(accessibility_observed_color_table[cur_iff].back().iff_name, "As:", NAME_LENGTH);
|
||||
required_string("As:");
|
||||
|
||||
// get color observed
|
||||
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
|
||||
accessibility_observed_color_table[cur_iff].back().color_index = iff_init_color(rgb[0], rgb[1], rgb[2]);
|
||||
}
|
||||
|
||||
// get F3 override
|
||||
iffp->hotkey_team = IFF_hotkey_team::Default;
|
||||
if (optional_string("+Hotkey Team:"))
|
||||
@@ -589,8 +529,7 @@ void parse_iff_table(const char* filename)
|
||||
}
|
||||
|
||||
// this is cleared between each level but let's just set it here for thoroughness
|
||||
iffp->ai_good_rearm_timestamp = TIMESTAMP::invalid();
|
||||
iffp->ai_bad_rearm_timestamp = TIMESTAMP::invalid();
|
||||
iffp->ai_rearm_timestamp = TIMESTAMP::invalid();
|
||||
}
|
||||
|
||||
required_string("#End");
|
||||
@@ -611,11 +550,6 @@ void iff_init()
|
||||
// parse any modular tables
|
||||
parse_modular_table("*-iff.tbm", parse_iff_table);
|
||||
|
||||
if (!AccessiblitySupported) {
|
||||
options::OptionsManager::instance()->removeOption(AccessibilityOption);
|
||||
AccessibilityEnabled = false;
|
||||
}
|
||||
|
||||
// now resolve the relationships
|
||||
resolve_iff_data();
|
||||
}
|
||||
@@ -730,22 +664,14 @@ color *iff_get_color(int color_index, int is_bright)
|
||||
*/
|
||||
color *iff_get_color_by_team(int team, int seen_from_team, int is_bright)
|
||||
{
|
||||
Assertion(SCP_vector_inbounds(Iff_info, team), "Cannot get color by team because team is invalid. Get a coder!");
|
||||
Assertion((is_bright == 0 || is_bright == 1), "Error with brightness selection when getting color. Get a coder!");
|
||||
|
||||
int color_index;
|
||||
|
||||
if (AccessibilityEnabled) {
|
||||
color_index = Iff_info[team].accessibility_color_index;
|
||||
} else {
|
||||
color_index = Iff_info[team].color_index;
|
||||
}
|
||||
Assert(team >= 0 && team < (int)Iff_info.size());
|
||||
Assert(seen_from_team < (int)Iff_info.size());
|
||||
Assert(is_bright == 0 || is_bright == 1);
|
||||
|
||||
|
||||
// is this guy being seen by anyone?
|
||||
if (seen_from_team < 0) {
|
||||
return is_bright == 0 ? &Iff_colors[color_index].first : &Iff_colors[color_index].second;
|
||||
}
|
||||
if (seen_from_team < 0)
|
||||
return is_bright == 0 ? &Iff_colors[Iff_info[team].color_index].first : &Iff_colors[Iff_info[team].color_index].second;
|
||||
|
||||
// Goober5000 - base the following on "sees X as" from iff code
|
||||
// c.f. AL's comment:
|
||||
@@ -755,21 +681,13 @@ color *iff_get_color_by_team(int team, int seen_from_team, int is_bright)
|
||||
// drawn friendly. If the team is different than the player's, then draw the
|
||||
// appropriate IFF.
|
||||
|
||||
// This goes here because seen_from_team can validly be a negative number. In that case color_map is undefined
|
||||
// but that doesn't matter because we return in the statement above here. Below here, color_map needs to be defined
|
||||
// which will happen if seen_from_team is valid.
|
||||
Assertion(SCP_vector_inbounds(Iff_info, seen_from_team), "Cannot get color because seen_from_team is invalid. Get a coder!");
|
||||
|
||||
if (SCP_vector_inbounds(Iff_info, seen_from_team)) {
|
||||
const auto& color_map = AccessibilityEnabled ? Iff_info[seen_from_team].accessibility_observed_color_map : Iff_info[seen_from_team].observed_color_map;
|
||||
// assume an observed color is defined; if not, use normal color
|
||||
auto it = Iff_info[seen_from_team].observed_color_map.find(team);
|
||||
int color_index = Iff_info[team].color_index;
|
||||
|
||||
// assume an observed color is defined; if not, use normal color
|
||||
auto it = color_map.find(team);
|
||||
|
||||
if (it != color_map.end()) {
|
||||
color_index = it->second;
|
||||
}
|
||||
}
|
||||
if (it != Iff_info[seen_from_team].observed_color_map.end())
|
||||
color_index = it->second;
|
||||
|
||||
return is_bright == 0 ? &Iff_colors[color_index].first : &Iff_colors[color_index].second;
|
||||
}
|
||||
@@ -781,39 +699,23 @@ color *iff_get_color_by_team(int team, int seen_from_team, int is_bright)
|
||||
*/
|
||||
color *iff_get_color_by_team_and_object(int team, int seen_from_team, int is_bright, object *objp)
|
||||
{
|
||||
Assertion(SCP_vector_inbounds(Iff_info, team), "Cannot get color by team because team is invalid. Get a coder!");
|
||||
Assertion((is_bright == 0 || is_bright == 1), "Error with brightness selection when getting color. Get a coder!");
|
||||
|
||||
int color_index;
|
||||
|
||||
if (AccessibilityEnabled) {
|
||||
color_index = Iff_info[team].accessibility_color_index;
|
||||
} else {
|
||||
color_index = Iff_info[team].color_index;
|
||||
}
|
||||
|
||||
// is this guy being seen by anyone?
|
||||
if (seen_from_team < 0) {
|
||||
return is_bright == 0 ? &Iff_colors[color_index].first : &Iff_colors[color_index].second;
|
||||
}
|
||||
|
||||
// This goes here because seen_from_team can validly be a negative number. In that case color_map is undefined
|
||||
// but that doesn't matter because we return in the statement above here. Below here, color_map needs to be defined
|
||||
// which will happen if seen_from_team is valid.
|
||||
Assertion(SCP_vector_inbounds(Iff_info, seen_from_team), "Cannot get color because seen_from_team is invalid. Get a coder!");
|
||||
|
||||
if (SCP_vector_inbounds(Iff_info, seen_from_team)) {
|
||||
const auto& color_map = AccessibilityEnabled ? Iff_info[seen_from_team].accessibility_observed_color_map : Iff_info[seen_from_team].observed_color_map;
|
||||
|
||||
auto it = color_map.find(team);
|
||||
|
||||
if (it != color_map.end()) {
|
||||
color_index = it->second;
|
||||
}
|
||||
}
|
||||
Assert(team >= 0 && team < (int)Iff_info.size());
|
||||
Assert(seen_from_team < (int)Iff_info.size());
|
||||
Assert(is_bright == 0 || is_bright == 1);
|
||||
|
||||
int alt_color_index = -1;
|
||||
|
||||
// is this guy being seen by anyone?
|
||||
if (seen_from_team < 0)
|
||||
return is_bright == 0 ? &Iff_colors[Iff_info[team].color_index].first : &Iff_colors[Iff_info[team].color_index].second;
|
||||
|
||||
int color_index = -1;
|
||||
{
|
||||
auto it = Iff_info[seen_from_team].observed_color_map.find(team);
|
||||
if (it != Iff_info[seen_from_team].observed_color_map.end())
|
||||
color_index = it->second;
|
||||
}
|
||||
|
||||
// switch in case some sort of parent iff color inheritance for example for bombs is wanted...
|
||||
switch(objp->type)
|
||||
{
|
||||
@@ -836,15 +738,12 @@ color *iff_get_color_by_team_and_object(int team, int seen_from_team, int is_bri
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
int this_color_index = -1;
|
||||
// temporary solution....
|
||||
if (alt_color_index >= 0) {
|
||||
this_color_index = alt_color_index;
|
||||
} else {
|
||||
this_color_index = color_index;
|
||||
}
|
||||
if (alt_color_index >= 0)
|
||||
color_index = alt_color_index;
|
||||
if (color_index < 0)
|
||||
color_index = Iff_info[team].color_index;
|
||||
|
||||
|
||||
return is_bright == 0 ? &Iff_colors[this_color_index].first : &Iff_colors[this_color_index].second;
|
||||
return is_bright == 0 ? &Iff_colors[color_index].first : &Iff_colors[color_index].second;
|
||||
}
|
||||
@@ -38,13 +38,11 @@ typedef struct iff_info {
|
||||
// required stuff
|
||||
char iff_name[NAME_LENGTH];
|
||||
int color_index; // treat this as private and use iff_get_color or iff_get_color_by_team
|
||||
int accessibility_color_index;
|
||||
|
||||
// relationships
|
||||
int attackee_bitmask; // treat this as private and use iff_get_attackee_mask or iff_x_attacks_y
|
||||
int attackee_bitmask_all_teams_at_war; // treat this as private and use iff_get_attackee_mask or iff_x_attacks_y
|
||||
SCP_map<int, int> observed_color_map; // treat this as private and use iff_get_color or iff_get_color_by_team
|
||||
SCP_map<int, int> accessibility_observed_color_map;
|
||||
IFF_hotkey_team hotkey_team;
|
||||
|
||||
// flags
|
||||
@@ -52,8 +50,7 @@ typedef struct iff_info {
|
||||
flagset<Mission::Parse_Object_Flags> default_parse_flags;
|
||||
|
||||
// used internally, not parsed
|
||||
TIMESTAMP ai_good_rearm_timestamp;
|
||||
TIMESTAMP ai_bad_rearm_timestamp;
|
||||
TIMESTAMP ai_rearm_timestamp;
|
||||
|
||||
} iff_info;
|
||||
|
||||
|
||||
+115
-132
@@ -21,24 +21,27 @@
|
||||
#define THREADED // to use the proper set of macros
|
||||
#include "osapi/osapi.h"
|
||||
|
||||
|
||||
#define KEY_BUFFER_SIZE 16
|
||||
|
||||
//-------- Variable accessed by outside functions ---------
|
||||
bool key_allow_repeat;
|
||||
ubyte keyd_buffer_type; // 0=No buffer, 1=buffer ASCII, 2=buffer scans
|
||||
ubyte keyd_repeat;
|
||||
uint keyd_last_pressed;
|
||||
uint keyd_last_released;
|
||||
ubyte keyd_pressed[NUM_KEYS];
|
||||
int keyd_time_when_last_pressed;
|
||||
|
||||
typedef struct keyboard {
|
||||
enum class key_state : uint8_t { RELEASED, PRESSED, PRESSED_OVERRIDDEN };
|
||||
std::array<key_state, NUM_KEYS> state;
|
||||
SCP_queue<uint> key_queue;
|
||||
|
||||
//The time that the key was pressed. Tracks actual presses, even those overridden
|
||||
uint TimeKeyWentDown[NUM_KEYS];
|
||||
|
||||
//The cumulative time that the key has been held down.
|
||||
//This explicitly excludes any time the button has been down in the current press if the button is pressed.
|
||||
uint TimeKeyHeldDown[NUM_KEYS];
|
||||
uint TimeKeyDownChecked[NUM_KEYS];
|
||||
uint NumDowns[NUM_KEYS];
|
||||
uint NumUps[NUM_KEYS];
|
||||
int down_check[NUM_KEYS]; // nonzero if has been pressed yet this mission
|
||||
ushort keybuffer[KEY_BUFFER_SIZE];
|
||||
uint time_pressed[KEY_BUFFER_SIZE];
|
||||
uint TimeKeyWentDown[NUM_KEYS];
|
||||
uint TimeKeyHeldDown[NUM_KEYS];
|
||||
uint TimeKeyDownChecked[NUM_KEYS];
|
||||
uint NumDowns[NUM_KEYS];
|
||||
uint NumUps[NUM_KEYS];
|
||||
int down_check[NUM_KEYS]; // nonzero if has been pressed yet this mission
|
||||
uint keyhead, keytail;
|
||||
} keyboard;
|
||||
|
||||
keyboard key_data;
|
||||
@@ -296,15 +299,21 @@ void key_flush()
|
||||
|
||||
SDL_LockMutex( key_lock );
|
||||
|
||||
key_data.keyhead = key_data.keytail = 0;
|
||||
|
||||
//Clear the keyboard buffer
|
||||
key_data.key_queue = {};
|
||||
for (i=0; i<KEY_BUFFER_SIZE; i++ ) {
|
||||
key_data.keybuffer[i] = 0;
|
||||
key_data.time_pressed[i] = 0;
|
||||
}
|
||||
|
||||
//Clear the keyboard array
|
||||
|
||||
CurTime = timer_get_milliseconds();
|
||||
|
||||
|
||||
for (i=0; i<NUM_KEYS; i++ ) {
|
||||
key_data.state[i] = keyboard::key_state::RELEASED;
|
||||
keyd_pressed[i] = 0;
|
||||
key_data.TimeKeyDownChecked[i] = CurTime;
|
||||
key_data.TimeKeyWentDown[i] = CurTime;
|
||||
key_data.TimeKeyHeldDown[i] = 0;
|
||||
@@ -315,14 +324,28 @@ void key_flush()
|
||||
SDL_UnlockMutex( key_lock );
|
||||
}
|
||||
|
||||
// Returns 1 if character waiting... 0 otherwise
|
||||
bool key_checkch()
|
||||
// A nifty function which performs the function:
|
||||
// n = (n+1) % KEY_BUFFER_SIZE
|
||||
// (assuming positive values of n).
|
||||
int add_one( int n )
|
||||
{
|
||||
n++;
|
||||
if ( n >= KEY_BUFFER_SIZE ) n=0;
|
||||
return n;
|
||||
}
|
||||
|
||||
// Returns 1 if character waiting... 0 otherwise
|
||||
int key_checkch()
|
||||
{
|
||||
int is_one_waiting = 0;
|
||||
|
||||
if ( !key_inited ) return 0;
|
||||
|
||||
SDL_LockMutex( key_lock );
|
||||
SDL_LockMutex( key_lock );
|
||||
|
||||
bool is_one_waiting = !key_data.key_queue.empty();
|
||||
if (key_data.keytail != key_data.keyhead){
|
||||
is_one_waiting = 1;
|
||||
}
|
||||
|
||||
SDL_UnlockMutex( key_lock );
|
||||
|
||||
@@ -343,23 +366,18 @@ int key_inkey()
|
||||
|
||||
SDL_LockMutex( key_lock );
|
||||
|
||||
if (!key_data.key_queue.empty()) {
|
||||
key = key_data.key_queue.front();
|
||||
key_data.key_queue.pop();
|
||||
if (key_data.keytail!=key_data.keyhead) {
|
||||
key = key_data.keybuffer[key_data.keyhead];
|
||||
key_data.keyhead = add_one(key_data.keyhead);
|
||||
}
|
||||
|
||||
SDL_UnlockMutex( key_lock );
|
||||
SDL_UnlockMutex( key_lock );
|
||||
|
||||
Current_key_down = key;
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
bool key_is_pressed(int keycode, bool include_since_last_count) {
|
||||
Assertion(keycode >= 0 && keycode < NUM_KEYS, "Checked status for invalid keycode!");
|
||||
return key_data.state[keycode] == keyboard::key_state::PRESSED || (include_since_last_count && key_down_count(keycode) > 0);
|
||||
}
|
||||
|
||||
// If not installed, uses BIOS and returns getch();
|
||||
// Else returns pending key (or waits for one if none waiting).
|
||||
int key_getch()
|
||||
@@ -385,20 +403,20 @@ uint key_get_shift_status()
|
||||
|
||||
SDL_LockMutex( key_lock );
|
||||
|
||||
if ( key_is_pressed(KEY_LSHIFT) || key_is_pressed(KEY_RSHIFT) )
|
||||
if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] )
|
||||
shift_status |= KEY_SHIFTED;
|
||||
|
||||
if ( key_is_pressed(KEY_LALT) || key_is_pressed(KEY_RALT) )
|
||||
if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] )
|
||||
shift_status |= KEY_ALTED;
|
||||
|
||||
if ( key_is_pressed(KEY_LCTRL) || key_is_pressed(KEY_RCTRL) )
|
||||
if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] )
|
||||
shift_status |= KEY_CTRLED;
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (key_is_pressed(KEY_DEBUG_KEY))
|
||||
if (keyd_pressed[KEY_DEBUG_KEY])
|
||||
shift_status |= KEY_DEBUGGED;
|
||||
#else
|
||||
if (key_is_pressed(KEY_DEBUG_KEY)) {
|
||||
if (keyd_pressed[KEY_DEBUG_KEY]) {
|
||||
mprintf(("Cheats_enabled = %i, Key_normal_game = %i\n", Cheats_enabled, Key_normal_game));
|
||||
if ((Cheats_enabled) && Key_normal_game) {
|
||||
mprintf(("Debug key\n"));
|
||||
@@ -413,8 +431,11 @@ uint key_get_shift_status()
|
||||
|
||||
// Returns amount of time key (specified by "code") has been down since last call.
|
||||
// Returns float, unlike key_down_time() which returns a fix.
|
||||
float key_down_timef(uint scancode)
|
||||
float key_down_timef(uint scancode)
|
||||
{
|
||||
uint time_down, time;
|
||||
uint delta_time;
|
||||
|
||||
if ( !key_inited ) {
|
||||
return 0.0f;
|
||||
}
|
||||
@@ -425,14 +446,13 @@ float key_down_timef(uint scancode)
|
||||
|
||||
SDL_LockMutex( key_lock );
|
||||
|
||||
uint time = timer_get_milliseconds();
|
||||
uint last_check_time = key_data.TimeKeyDownChecked[scancode];
|
||||
uint delta_time = time - last_check_time;
|
||||
time = timer_get_milliseconds();
|
||||
delta_time = time - key_data.TimeKeyDownChecked[scancode];
|
||||
key_data.TimeKeyDownChecked[scancode] = time;
|
||||
|
||||
if ( delta_time <= 1 ) {
|
||||
key_data.TimeKeyHeldDown[scancode] = 0;
|
||||
if (key_is_pressed(scancode)) {
|
||||
key_data.TimeKeyWentDown[scancode] = time;
|
||||
if (keyd_pressed[scancode]) {
|
||||
SDL_UnlockMutex( key_lock );
|
||||
return 1.0f;
|
||||
} else {
|
||||
@@ -441,13 +461,13 @@ float key_down_timef(uint scancode)
|
||||
}
|
||||
}
|
||||
|
||||
uint time_down = key_data.TimeKeyHeldDown[scancode];
|
||||
if ( key_is_pressed(scancode) ) {
|
||||
//Since the stored time only updates on button release and reset on this check,
|
||||
//the time the button has been held down this time needs to be added
|
||||
time_down += time - MAX(key_data.TimeKeyWentDown[scancode], last_check_time);
|
||||
if ( !keyd_pressed[scancode] ) {
|
||||
time_down = key_data.TimeKeyHeldDown[scancode];
|
||||
key_data.TimeKeyHeldDown[scancode] = 0;
|
||||
} else {
|
||||
time_down = time - key_data.TimeKeyWentDown[scancode];
|
||||
key_data.TimeKeyWentDown[scancode] = time;
|
||||
}
|
||||
key_data.TimeKeyHeldDown[scancode] = 0;
|
||||
|
||||
SDL_UnlockMutex( key_lock );
|
||||
|
||||
@@ -477,7 +497,7 @@ int key_down_count(int scancode)
|
||||
//void key_mark( uint code, int state )
|
||||
void key_mark( uint code, int state, uint latency )
|
||||
{
|
||||
uint scancode, breakbit, event_time;
|
||||
uint scancode, breakbit, temp, event_time;
|
||||
ushort keycode;
|
||||
|
||||
if ( !key_inited ) return;
|
||||
@@ -500,116 +520,70 @@ void key_mark( uint code, int state, uint latency )
|
||||
|
||||
if (breakbit) {
|
||||
// Key going up
|
||||
keyd_last_released = scancode;
|
||||
keyd_pressed[scancode] = 0;
|
||||
key_data.NumUps[scancode]++;
|
||||
|
||||
int time_held = 0;
|
||||
if (event_time >= key_data.TimeKeyWentDown[scancode]) {
|
||||
//If the suspected key lift is "before" the key was pressed (i.e. fluctuating latency) we don't add any time to the pressed time since last poll
|
||||
time_held = event_time - key_data.TimeKeyWentDown[scancode];
|
||||
// What is the point of this code? "temp" is never used!
|
||||
temp = 0;
|
||||
temp |= keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT];
|
||||
temp |= keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT];
|
||||
temp |= keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL];
|
||||
temp |= keyd_pressed[KEY_DEBUG_KEY];
|
||||
|
||||
if (event_time < key_data.TimeKeyWentDown[scancode]) {
|
||||
key_data.TimeKeyHeldDown[scancode] = 0;
|
||||
} else {
|
||||
key_data.TimeKeyHeldDown[scancode] += event_time - key_data.TimeKeyWentDown[scancode];
|
||||
}
|
||||
|
||||
Current_key_down = scancode;
|
||||
if ( key_is_pressed(KEY_LSHIFT) || key_is_pressed(KEY_RSHIFT) ) {
|
||||
if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] ) {
|
||||
Current_key_down |= KEY_SHIFTED;
|
||||
}
|
||||
|
||||
if ( key_is_pressed(KEY_LALT) || key_is_pressed(KEY_RALT) ) {
|
||||
if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] ) {
|
||||
Current_key_down |= KEY_ALTED;
|
||||
}
|
||||
|
||||
if ( key_is_pressed(KEY_LCTRL) || key_is_pressed(KEY_RCTRL) ) {
|
||||
if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] ) {
|
||||
Current_key_down |= KEY_CTRLED;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
if ( key_is_pressed(KEY_DEBUG_KEY) ) {
|
||||
Current_key_down |= KEY_DEBUGGED;
|
||||
}
|
||||
#else
|
||||
if ( key_is_pressed(KEY_DEBUG_KEY) ) {
|
||||
mprintf(("Cheats_enabled = %i, Key_normal_game = %i\n", Cheats_enabled, Key_normal_game));
|
||||
if (Cheats_enabled && Key_normal_game) {
|
||||
Current_key_down |= KEY_DEBUGGED1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (scripting::hooks::OnKeyReleased->isActive()) {
|
||||
scripting::hooks::OnKeyReleased->run(scripting::hooks::KeyPressConditions{ static_cast<int>(scancode) },
|
||||
scripting::hook_param_list(
|
||||
scripting::hook_param("Key", 's', textify_scancode_universal(Current_key_down)),
|
||||
scripting::hook_param("RawKey", 's', textify_scancode_universal(scancode)),
|
||||
scripting::hook_param("TimeHeld", 'i', time_held),
|
||||
scripting::hook_param("WasOverridden", 'b', key_data.state[scancode] == keyboard::key_state::PRESSED_OVERRIDDEN)
|
||||
));
|
||||
scripting::hooks::OnKeyReleased->run(scripting::hook_param_list(
|
||||
scripting::hook_param("Key", 's', textify_scancode_universal(Current_key_down))));
|
||||
}
|
||||
|
||||
// Don't increment counters if was overridden
|
||||
if (key_data.state[scancode] == keyboard::key_state::PRESSED) {
|
||||
key_data.NumUps[scancode]++;
|
||||
key_data.TimeKeyHeldDown[scancode] += time_held;
|
||||
}
|
||||
|
||||
key_data.state[scancode] = keyboard::key_state::RELEASED;
|
||||
} else {
|
||||
// Key going down
|
||||
if (!key_is_pressed(scancode)) {
|
||||
keyd_last_pressed = scancode;
|
||||
keyd_time_when_last_pressed = event_time;
|
||||
if (!keyd_pressed[scancode]) {
|
||||
// First time down
|
||||
key_data.TimeKeyWentDown[scancode] = event_time;
|
||||
keyd_pressed[scancode] = 1;
|
||||
key_data.NumDowns[scancode]++;
|
||||
key_data.down_check[scancode]++;
|
||||
|
||||
//WMC - For scripting
|
||||
Current_key_down = scancode;
|
||||
if ( key_is_pressed(KEY_LSHIFT) || key_is_pressed(KEY_RSHIFT) ) {
|
||||
if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] ) {
|
||||
Current_key_down |= KEY_SHIFTED;
|
||||
}
|
||||
|
||||
if ( key_is_pressed(KEY_LALT) || key_is_pressed(KEY_RALT) ) {
|
||||
if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] ) {
|
||||
Current_key_down |= KEY_ALTED;
|
||||
}
|
||||
|
||||
if ( key_is_pressed(KEY_LCTRL) || key_is_pressed(KEY_RCTRL) ) {
|
||||
if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] ) {
|
||||
Current_key_down |= KEY_CTRLED;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
if ( key_is_pressed(KEY_DEBUG_KEY) ) {
|
||||
Current_key_down |= KEY_DEBUGGED;
|
||||
}
|
||||
#else
|
||||
if ( key_is_pressed(KEY_DEBUG_KEY) ) {
|
||||
mprintf(("Cheats_enabled = %i, Key_normal_game = %i\n", Cheats_enabled, Key_normal_game));
|
||||
if (Cheats_enabled && Key_normal_game) {
|
||||
Current_key_down |= KEY_DEBUGGED1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool overrideKey = false;
|
||||
if (scripting::hooks::OnKeyPressed->isActive()) {
|
||||
scripting::hooks::OnKeyPressed->run(scripting::hooks::KeyPressConditions{ static_cast<int>(scancode) },
|
||||
scripting::hook_param_list(
|
||||
scripting::hook_param("Key", 's', textify_scancode_universal(Current_key_down)),
|
||||
scripting::hook_param("RawKey", 's', textify_scancode_universal(scancode))
|
||||
));
|
||||
|
||||
overrideKey = scripting::hooks::OnKeyPressed->isOverride(scripting::hooks::KeyPressConditions{ static_cast<int>(scancode) },
|
||||
scripting::hook_param_list(
|
||||
scripting::hook_param("Key", 's', textify_scancode_universal(Current_key_down)),
|
||||
scripting::hook_param("RawKey", 's', textify_scancode_universal(scancode))
|
||||
));
|
||||
scripting::hooks::OnKeyPressed->run(scripting::hook_param_list(
|
||||
scripting::hook_param("Key", 's', textify_scancode_universal(Current_key_down))));
|
||||
}
|
||||
|
||||
if (overrideKey) {
|
||||
key_data.state[scancode] = keyboard::key_state::PRESSED_OVERRIDDEN;
|
||||
scancode = 0xAA; //Skip queueing this key
|
||||
}
|
||||
else {
|
||||
key_data.state[scancode] = keyboard::key_state::PRESSED;
|
||||
key_data.NumDowns[scancode]++;
|
||||
key_data.down_check[scancode]++;
|
||||
}
|
||||
} else if (!key_allow_repeat) {
|
||||
} else if (!keyd_repeat) {
|
||||
// Don't buffer repeating key if repeat mode is off
|
||||
scancode = 0xAA;
|
||||
}
|
||||
@@ -617,24 +591,24 @@ void key_mark( uint code, int state, uint latency )
|
||||
if ( scancode!=0xAA ) {
|
||||
keycode = (unsigned short)scancode;
|
||||
|
||||
if ( key_is_pressed(KEY_LSHIFT) || key_is_pressed(KEY_RSHIFT) ) {
|
||||
if ( keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT] ) {
|
||||
keycode |= KEY_SHIFTED;
|
||||
}
|
||||
|
||||
if ( key_is_pressed(KEY_LALT) || key_is_pressed(KEY_RALT) ) {
|
||||
if ( keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT] ) {
|
||||
keycode |= KEY_ALTED;
|
||||
}
|
||||
|
||||
if ( key_is_pressed(KEY_LCTRL) || key_is_pressed(KEY_RCTRL) ) {
|
||||
if ( keyd_pressed[KEY_LCTRL] || keyd_pressed[KEY_RCTRL] ) {
|
||||
keycode |= KEY_CTRLED;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
if ( key_is_pressed(KEY_DEBUG_KEY) ) {
|
||||
if ( keyd_pressed[KEY_DEBUG_KEY] ) {
|
||||
keycode |= KEY_DEBUGGED;
|
||||
}
|
||||
#else
|
||||
if ( key_is_pressed(KEY_DEBUG_KEY) ) {
|
||||
if ( keyd_pressed[KEY_DEBUG_KEY] ) {
|
||||
mprintf(("Cheats_enabled = %i, Key_normal_game = %i\n", Cheats_enabled, Key_normal_game));
|
||||
if (Cheats_enabled && Key_normal_game) {
|
||||
keycode |= KEY_DEBUGGED1;
|
||||
@@ -644,7 +618,14 @@ void key_mark( uint code, int state, uint latency )
|
||||
#endif
|
||||
|
||||
if ( keycode ) {
|
||||
key_data.key_queue.push(keycode);
|
||||
temp = key_data.keytail+1;
|
||||
if ( temp >= KEY_BUFFER_SIZE ) temp=0;
|
||||
|
||||
if (temp!=key_data.keyhead) {
|
||||
key_data.keybuffer[key_data.keytail] = keycode;
|
||||
key_data.time_pressed[key_data.keytail] = keyd_time_when_last_pressed;
|
||||
key_data.keytail = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -678,7 +659,9 @@ void key_init()
|
||||
|
||||
FillSDLArray();
|
||||
|
||||
key_allow_repeat = true;
|
||||
keyd_time_when_last_pressed = timer_get_milliseconds();
|
||||
keyd_buffer_type = 1;
|
||||
keyd_repeat = 1;
|
||||
|
||||
// Clear the keyboard array
|
||||
key_flush();
|
||||
|
||||
+4
-3
@@ -20,6 +20,9 @@ const size_t SIZE_OF_ASCII_TABLE = 128;
|
||||
extern int shifted_ascii_table[SIZE_OF_ASCII_TABLE];
|
||||
extern int ascii_table[SIZE_OF_ASCII_TABLE];
|
||||
|
||||
extern ubyte keyd_pressed[NUM_KEYS];
|
||||
|
||||
|
||||
// O/S level hooks...
|
||||
void key_init();
|
||||
void key_level_init();
|
||||
@@ -36,14 +39,12 @@ SDL_Scancode fs2_to_sdl( int scancode );
|
||||
int key_to_ascii(int keycode );
|
||||
int key_inkey();
|
||||
|
||||
bool key_is_pressed(int keycode, bool include_since_last_count = false);
|
||||
|
||||
// global flag that will enable/disable the backspace key from stopping execution
|
||||
//extern int Backspace_debug;
|
||||
|
||||
uint key_get_shift_status();
|
||||
int key_down_count(int scancode);
|
||||
bool key_checkch();
|
||||
int key_checkch();
|
||||
|
||||
extern SCP_string CheatUsed;
|
||||
extern int Cheats_enabled;
|
||||
|
||||
+45
-32
@@ -183,10 +183,8 @@ factor_table ftables;
|
||||
// time compression/dilation values - Goober5000
|
||||
// (Volition sez "can't compress below 0.25"... not sure if
|
||||
// this is arbitrary or dictated by code)
|
||||
constexpr int MAX_TIME_MULTIPLIER = 64;
|
||||
constexpr int MAX_TIME_DIVIDER = 4;
|
||||
constexpr int MAX_TIME_MULTIPLIER_RETAIL = 4;
|
||||
constexpr int MAX_TIME_DIVIDER_RETAIL = 1;
|
||||
#define MAX_TIME_MULTIPLIER 64
|
||||
#define MAX_TIME_DIVIDER 4
|
||||
|
||||
char CheatBuffer[CHEAT_BUFFER_LEN+1];
|
||||
|
||||
@@ -217,6 +215,7 @@ static struct Cheat cheatsTable[] = {
|
||||
|
||||
|
||||
int Tool_enabled = 0;
|
||||
bool Perspective_locked=false;
|
||||
|
||||
extern int AI_watch_object;
|
||||
extern int Countermeasures_enabled;
|
||||
@@ -750,24 +749,28 @@ void process_debug_keys(int k)
|
||||
case KEY_DEBUGGED + KEY_SHIFTED + KEY_COMMA:
|
||||
case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_COMMA:
|
||||
if ( Game_mode & GM_NORMAL ) {
|
||||
if (Game_time_compression > (F1_0 / (Cmdline_retail_time_compression_range ? MAX_TIME_DIVIDER_RETAIL : MAX_TIME_DIVIDER))) {
|
||||
change_time_compression(0.5f);
|
||||
break;
|
||||
if ( Game_time_compression > (F1_0/MAX_TIME_DIVIDER) ) {
|
||||
change_time_compression(0.5);
|
||||
} else {
|
||||
gamesnd_play_error_beep();
|
||||
}
|
||||
} else {
|
||||
gamesnd_play_error_beep();
|
||||
}
|
||||
gamesnd_play_error_beep();
|
||||
break;
|
||||
|
||||
// Goober5000: handle as normal here
|
||||
case KEY_DEBUGGED + KEY_SHIFTED + KEY_PERIOD:
|
||||
case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_PERIOD:
|
||||
if ( Game_mode & GM_NORMAL ) {
|
||||
if (Game_time_compression < (F1_0 * (Cmdline_retail_time_compression_range ? MAX_TIME_MULTIPLIER_RETAIL : MAX_TIME_MULTIPLIER))) {
|
||||
change_time_compression(2.0f);
|
||||
break;
|
||||
if ( Game_time_compression < (F1_0*MAX_TIME_MULTIPLIER) ) {
|
||||
change_time_compression(2);
|
||||
} else {
|
||||
gamesnd_play_error_beep();
|
||||
}
|
||||
} else {
|
||||
gamesnd_play_error_beep();
|
||||
}
|
||||
gamesnd_play_error_beep();
|
||||
break;
|
||||
|
||||
// Kill! the currently targeted ship.
|
||||
@@ -797,8 +800,11 @@ void process_debug_keys(int k)
|
||||
// play the next mission message
|
||||
case KEY_DEBUGGED + KEY_V:
|
||||
extern int Message_debug_index;
|
||||
extern int Num_messages_playing;
|
||||
// stop any other messages
|
||||
message_kill_all(true);
|
||||
if(Num_messages_playing){
|
||||
message_kill_all(1);
|
||||
}
|
||||
|
||||
// next message
|
||||
if(Message_debug_index >= Num_messages - 1){
|
||||
@@ -817,8 +823,11 @@ void process_debug_keys(int k)
|
||||
// play the previous mission message
|
||||
case KEY_DEBUGGED + KEY_SHIFTED + KEY_V:
|
||||
extern int Message_debug_index;
|
||||
extern int Num_messages_playing;
|
||||
// stop any other messages
|
||||
message_kill_all(true);
|
||||
if(Num_messages_playing){
|
||||
message_kill_all(1);
|
||||
}
|
||||
|
||||
// go maybe go down one
|
||||
if(Message_debug_index == Num_builtin_messages - 1){
|
||||
@@ -1258,17 +1267,17 @@ void process_debug_keys(int k)
|
||||
case KEY_PADMINUS: {
|
||||
int init_flag = 0;
|
||||
|
||||
if ( key_is_pressed(KEY_1) ) {
|
||||
if ( keyd_pressed[KEY_1] ) {
|
||||
init_flag = 1;
|
||||
HUD_color_red -= 4;
|
||||
}
|
||||
|
||||
if ( key_is_pressed(KEY_2) ) {
|
||||
if ( keyd_pressed[KEY_2] ) {
|
||||
init_flag = 1;
|
||||
HUD_color_green -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
if ( key_is_pressed(KEY_3) ) {
|
||||
if ( keyd_pressed[KEY_3] ) {
|
||||
init_flag = 1;
|
||||
HUD_color_blue -= 4;
|
||||
}
|
||||
@@ -1287,17 +1296,17 @@ void process_debug_keys(int k)
|
||||
case KEY_PADPLUS: {
|
||||
int init_flag = 0;
|
||||
|
||||
if ( key_is_pressed(KEY_1) ) {
|
||||
if ( keyd_pressed[KEY_1] ) {
|
||||
init_flag = 1;
|
||||
HUD_color_red += 4;
|
||||
}
|
||||
|
||||
if ( key_is_pressed(KEY_2) ) {
|
||||
if ( keyd_pressed[KEY_2] ) {
|
||||
init_flag = 1;
|
||||
HUD_color_green += 4;
|
||||
}
|
||||
|
||||
if ( key_is_pressed(KEY_3) ) {
|
||||
if ( keyd_pressed[KEY_3] ) {
|
||||
init_flag = 1;
|
||||
HUD_color_blue += 4;
|
||||
}
|
||||
@@ -1451,7 +1460,7 @@ void process_player_ship_keys(int k)
|
||||
// moved this line to beginning of function since hotkeys now encompass
|
||||
// F5 - F12. We can return after using F11 as a hotkey.
|
||||
ppsk_hotkeys(masked_k);
|
||||
if (key_is_pressed(KEY_DEBUG_KEY)){
|
||||
if (keyd_pressed[KEY_DEBUG_KEY]){
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2214,27 +2223,31 @@ int button_function_demo_valid(int n)
|
||||
break;
|
||||
|
||||
case TIME_SLOW_DOWN:
|
||||
ret = 1;
|
||||
if ( Game_mode & GM_NORMAL && !Time_compression_locked ) {
|
||||
if ( Game_mode & GM_NORMAL ) {
|
||||
// Goober5000 - time dilation only available in cheat mode (see above);
|
||||
// now you can do it with or without pressing the tilde, per Kazan's request
|
||||
if ((Game_time_compression > F1_0) || (Cheats_enabled && (Game_time_compression > (F1_0 / (Cmdline_retail_time_compression_range ? MAX_TIME_DIVIDER_RETAIL : MAX_TIME_DIVIDER))))) {
|
||||
if ( ((Game_time_compression > F1_0) || (Cheats_enabled && (Game_time_compression > (F1_0/MAX_TIME_DIVIDER)))) && !Time_compression_locked) {
|
||||
change_time_compression(0.5f);
|
||||
break;
|
||||
} else {
|
||||
gamesnd_play_error_beep();
|
||||
}
|
||||
} else {
|
||||
gamesnd_play_error_beep();
|
||||
}
|
||||
gamesnd_play_error_beep();
|
||||
ret = 1;
|
||||
break;
|
||||
|
||||
case TIME_SPEED_UP:
|
||||
ret = 1;
|
||||
if ( Game_mode & GM_NORMAL && !Time_compression_locked ) {
|
||||
if (Game_time_compression < (F1_0 * (Cmdline_retail_time_compression_range ? MAX_TIME_MULTIPLIER_RETAIL : MAX_TIME_MULTIPLIER))) {
|
||||
if ( Game_mode & GM_NORMAL ) {
|
||||
if ( (Game_time_compression < (F1_0*MAX_TIME_MULTIPLIER)) && !Time_compression_locked ) {
|
||||
change_time_compression(2.0f);
|
||||
break;
|
||||
} else {
|
||||
gamesnd_play_error_beep();
|
||||
}
|
||||
} else {
|
||||
gamesnd_play_error_beep();
|
||||
}
|
||||
gamesnd_play_error_beep();
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
extern int Dead_key_set[];
|
||||
extern int Dead_key_set_size;
|
||||
extern bool Perspective_locked;
|
||||
|
||||
extern int Ignored_keys[]; //!< Ignored_keys[CCFG_MAX]; Set by sexp. If >0; value is number of times the key will be temporarily. If <0, key is permamently ignored.
|
||||
|
||||
|
||||
+22
-40
@@ -180,23 +180,17 @@ UI_TIMESTAMP ui_timestamp() {
|
||||
|
||||
TIMESTAMP timestamp_delta(TIMESTAMP stamp, int delta_ms)
|
||||
{
|
||||
if (!stamp.isFinite())
|
||||
if (!stamp.isValid() || stamp.isImmediate() || stamp.isNever())
|
||||
return stamp;
|
||||
|
||||
if (stamp.isImmediate())
|
||||
return TIMESTAMP(timestamp_ms() + delta_ms);
|
||||
|
||||
return TIMESTAMP(stamp.value() + delta_ms);
|
||||
}
|
||||
|
||||
UI_TIMESTAMP ui_timestamp_delta(UI_TIMESTAMP stamp, int delta_ms)
|
||||
{
|
||||
if (!stamp.isFinite())
|
||||
if (!stamp.isValid() || stamp.isImmediate() || stamp.isNever())
|
||||
return stamp;
|
||||
|
||||
if (stamp.isImmediate())
|
||||
return UI_TIMESTAMP(timer_get_milliseconds() + delta_ms);
|
||||
|
||||
return UI_TIMESTAMP(stamp.value() + delta_ms);
|
||||
}
|
||||
|
||||
@@ -305,12 +299,6 @@ UI_TIMESTAMP ui_timestamp(int delta_ms) {
|
||||
// Negative value gives milliseconds ago that timestamp elapsed.
|
||||
int timestamp_until(int stamp)
|
||||
{
|
||||
// handle special values
|
||||
if (stamp <= 0)
|
||||
return INT_MAX;
|
||||
if (stamp == 1)
|
||||
return 0;
|
||||
|
||||
// JAS: FIX
|
||||
// HACK!! This doesn't handle rollover!
|
||||
// (Will it ever happen?)
|
||||
@@ -334,8 +322,8 @@ int timestamp_until(int stamp)
|
||||
|
||||
int timestamp_until(TIMESTAMP stamp)
|
||||
{
|
||||
Assertion(stamp.isFinite(), "timestamp_until was called with a%s timestamp!", !stamp.isValid() ? "n invalid" : " Never");
|
||||
if (!stamp.isFinite())
|
||||
Assertion(stamp.isValid() && !stamp.isNever(), "timestamp_until was called with a%s timestamp!", !stamp.isValid() ? "n invalid" : " Never");
|
||||
if (!stamp.isValid() || stamp.isNever())
|
||||
return INT_MAX;
|
||||
|
||||
if (stamp.isImmediate())
|
||||
@@ -346,8 +334,8 @@ int timestamp_until(TIMESTAMP stamp)
|
||||
|
||||
int ui_timestamp_until(UI_TIMESTAMP stamp)
|
||||
{
|
||||
Assertion(stamp.isFinite(), "timestamp_until was called with a%s timestamp!", !stamp.isValid() ? "n invalid" : " Never");
|
||||
if (!stamp.isFinite())
|
||||
Assertion(stamp.isValid() && !stamp.isNever(), "timestamp_until was called with a%s timestamp!", !stamp.isValid() ? "n invalid" : " Never");
|
||||
if (!stamp.isValid() || stamp.isNever())
|
||||
return INT_MAX;
|
||||
|
||||
if (stamp.isImmediate())
|
||||
@@ -358,19 +346,13 @@ int ui_timestamp_until(UI_TIMESTAMP stamp)
|
||||
|
||||
int timestamp_since(int stamp)
|
||||
{
|
||||
// handle special values
|
||||
if (stamp <= 0)
|
||||
return INT_MIN;
|
||||
if (stamp == 1)
|
||||
return 0;
|
||||
|
||||
return timestamp_ms() - stamp;
|
||||
}
|
||||
|
||||
int timestamp_since(TIMESTAMP stamp)
|
||||
{
|
||||
Assertion(stamp.isFinite(), "timestamp_since was called with a%s timestamp!", !stamp.isValid() ? "n invalid" : " Never");
|
||||
if (!stamp.isFinite())
|
||||
Assertion(stamp.isValid() && !stamp.isNever(), "timestamp_since was called with a%s timestamp!", !stamp.isValid() ? "n invalid" : " Never");
|
||||
if (!stamp.isValid() || stamp.isNever())
|
||||
return INT_MIN;
|
||||
|
||||
if (stamp.isImmediate())
|
||||
@@ -381,8 +363,8 @@ int timestamp_since(TIMESTAMP stamp)
|
||||
|
||||
int ui_timestamp_since(UI_TIMESTAMP stamp)
|
||||
{
|
||||
Assertion(stamp.isFinite(), "timestamp_since was called with a%s timestamp!", !stamp.isValid() ? "n invalid" : " Never");
|
||||
if (!stamp.isFinite())
|
||||
Assertion(stamp.isValid() && !stamp.isNever(), "timestamp_since was called with a%s timestamp!", !stamp.isValid() ? "n invalid" : " Never");
|
||||
if (!stamp.isValid() || stamp.isNever())
|
||||
return INT_MIN;
|
||||
|
||||
if (stamp.isImmediate())
|
||||
@@ -463,9 +445,9 @@ int ui_timestamp_compare(UI_TIMESTAMP t1, UI_TIMESTAMP t2)
|
||||
|
||||
bool timestamp_in_between(TIMESTAMP stamp, TIMESTAMP before, TIMESTAMP after)
|
||||
{
|
||||
Assertion(stamp.isFinite(), "timestamp_in_between was called with a%s 'stamp' timestamp!", !stamp.isValid() ? "n invalid" : " Never");
|
||||
Assertion(before.isFinite(), "timestamp_in_between was called with a%s 'before' timestamp!", !before.isValid() ? "n invalid" : " Never");
|
||||
Assertion(after.isFinite(), "timestamp_in_between was called with a%s 'after' timestamp!", !after.isValid() ? "n invalid" : " Never");
|
||||
Assertion(stamp.isValid() && !stamp.isNever(), "timestamp_in_between was called with a%s 'stamp' timestamp!", !stamp.isValid() ? "n invalid" : " Never");
|
||||
Assertion(before.isValid() && !before.isNever(), "timestamp_in_between was called with a%s 'before' timestamp!", !before.isValid() ? "n invalid" : " Never");
|
||||
Assertion(after.isValid() && !after.isNever(), "timestamp_in_between was called with a%s 'after' timestamp!", !after.isValid() ? "n invalid" : " Never");
|
||||
|
||||
if (!stamp.isValid() || !before.isValid() || !after.isValid())
|
||||
return false;
|
||||
@@ -475,9 +457,9 @@ bool timestamp_in_between(TIMESTAMP stamp, TIMESTAMP before, TIMESTAMP after)
|
||||
|
||||
bool ui_timestamp_in_between(UI_TIMESTAMP stamp, UI_TIMESTAMP before, UI_TIMESTAMP after)
|
||||
{
|
||||
Assertion(stamp.isFinite(), "ui_timestamp_in_between was called with a%s 'stamp' timestamp!", !stamp.isValid() ? "n invalid" : " Never");
|
||||
Assertion(before.isFinite(), "ui_timestamp_in_between was called with a%s 'before' timestamp!", !before.isValid() ? "n invalid" : " Never");
|
||||
Assertion(after.isFinite(), "ui_timestamp_in_between was called with a%s 'after' timestamp!", !after.isValid() ? "n invalid" : " Never");
|
||||
Assertion(stamp.isValid() && !stamp.isNever(), "ui_timestamp_in_between was called with a%s 'stamp' timestamp!", !stamp.isValid() ? "n invalid" : " Never");
|
||||
Assertion(before.isValid() && !before.isNever(), "ui_timestamp_in_between was called with a%s 'before' timestamp!", !before.isValid() ? "n invalid" : " Never");
|
||||
Assertion(after.isValid() && !after.isNever(), "ui_timestamp_in_between was called with a%s 'after' timestamp!", !after.isValid() ? "n invalid" : " Never");
|
||||
|
||||
if (!stamp.isValid() || !before.isValid() || !after.isValid())
|
||||
return false;
|
||||
@@ -494,7 +476,7 @@ bool timestamp_elapsed(int stamp) {
|
||||
}
|
||||
|
||||
bool timestamp_elapsed(TIMESTAMP stamp) {
|
||||
if (!stamp.isFinite()) {
|
||||
if (!stamp.isValid() || stamp.isNever()) {
|
||||
return false;
|
||||
}
|
||||
if (stamp.isImmediate()) {
|
||||
@@ -505,7 +487,7 @@ bool timestamp_elapsed(TIMESTAMP stamp) {
|
||||
}
|
||||
|
||||
bool ui_timestamp_elapsed(UI_TIMESTAMP ui_stamp) {
|
||||
if (!ui_stamp.isFinite()) {
|
||||
if (!ui_stamp.isValid() || ui_stamp.isNever()) {
|
||||
return false;
|
||||
}
|
||||
if (ui_stamp.isImmediate()) {
|
||||
@@ -516,7 +498,7 @@ bool ui_timestamp_elapsed(UI_TIMESTAMP ui_stamp) {
|
||||
}
|
||||
|
||||
bool timestamp_elapsed_last_frame(TIMESTAMP stamp) {
|
||||
if (!stamp.isFinite()) {
|
||||
if (!stamp.isValid() || stamp.isNever()) {
|
||||
return false;
|
||||
}
|
||||
if (stamp.isImmediate()) {
|
||||
@@ -527,7 +509,7 @@ bool timestamp_elapsed_last_frame(TIMESTAMP stamp) {
|
||||
}
|
||||
|
||||
bool ui_timestamp_elapsed_last_frame(UI_TIMESTAMP ui_stamp) {
|
||||
if (!ui_stamp.isFinite()) {
|
||||
if (!ui_stamp.isValid() || ui_stamp.isNever()) {
|
||||
return false;
|
||||
}
|
||||
if (ui_stamp.isImmediate()) {
|
||||
@@ -546,7 +528,7 @@ bool timestamp_elapsed_safe(int a, int b) {
|
||||
}
|
||||
|
||||
bool timestamp_elapsed_safe(TIMESTAMP a, int b) {
|
||||
if (!a.isFinite()) {
|
||||
if (!a.isValid() || a.isNever()) {
|
||||
return false;
|
||||
}
|
||||
if (a.isImmediate()) {
|
||||
@@ -557,7 +539,7 @@ bool timestamp_elapsed_safe(TIMESTAMP a, int b) {
|
||||
}
|
||||
|
||||
bool ui_timestamp_elapsed_safe(UI_TIMESTAMP a, int b) {
|
||||
if (!a.isFinite()) {
|
||||
if (!a.isValid() || a.isNever()) {
|
||||
return false;
|
||||
}
|
||||
if (a.isImmediate()) {
|
||||
|
||||
@@ -47,7 +47,6 @@ public:
|
||||
|
||||
inline bool isNever() const { return m_val == 0; }
|
||||
inline bool isImmediate() const { return m_val == 1; }
|
||||
inline bool isFinite() const { return isValid() && !isNever(); }
|
||||
};
|
||||
|
||||
// Timestamp measuring game time. Sensitive to time compression and pausing.
|
||||
@@ -64,7 +63,6 @@ public:
|
||||
|
||||
inline bool isNever() const { return m_val == 0; }
|
||||
inline bool isImmediate() const { return m_val == 1; }
|
||||
inline bool isFinite() const { return isValid() && !isNever(); }
|
||||
};
|
||||
|
||||
// For converting from old-style timestamps:
|
||||
|
||||
@@ -407,7 +407,7 @@ void CJumpNode::Render(model_draw_list *scene, const vec3d *pos, const vec3d *vi
|
||||
|
||||
matrix node_orient = IDENTITY_MATRIX;
|
||||
|
||||
uint64_t mr_flags = MR_NO_LIGHTING | MR_NO_BATCH;
|
||||
int mr_flags = MR_NO_LIGHTING | MR_NO_BATCH;
|
||||
if(!(m_flags & JN_SHOW_POLYS)) {
|
||||
mr_flags |= MR_NO_CULL | MR_NO_POLYS | MR_SHOW_OUTLINE | MR_SHOW_OUTLINE_HTL | MR_NO_TEXTURING;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ void LabUi::object_changed()
|
||||
trigger = false;
|
||||
}
|
||||
|
||||
void LabUi::build_species_entry(const species_info &species_def, int species_idx) const
|
||||
void LabUi::build_species_entry(species_info species_def, int species_idx) const
|
||||
{
|
||||
with_TreeNode(species_def.species_name)
|
||||
{
|
||||
|
||||
@@ -13,7 +13,7 @@ class LabUi {
|
||||
private:
|
||||
void build_options_menu();
|
||||
void build_ship_list() const;
|
||||
void build_species_entry(const species_info &species_def, int species_idx) const;
|
||||
void build_species_entry(species_info species_def, int species_idx) const;
|
||||
void build_weapon_list() const;
|
||||
void build_weapon_subtype_list() const;
|
||||
void build_background_list() const;
|
||||
|
||||
@@ -95,7 +95,6 @@ void LabRenderer::renderModel(float frametime) {
|
||||
Ships[obj->instance].flags.set(Ship::Ship_Flags::Render_without_miscmap, renderFlags[LabRenderFlag::NoMiscMap]);
|
||||
Ships[obj->instance].flags.set(Ship::Ship_Flags::Render_without_weapons, !renderFlags[LabRenderFlag::ShowWeapons]);
|
||||
Ships[obj->instance].flags.set(Ship::Ship_Flags::Render_without_ambientmap, renderFlags[LabRenderFlag::NoAOMap]);
|
||||
Ships[obj->instance].flags.set(Ship::Ship_Flags::No_insignias, !renderFlags[LabRenderFlag::ShowInsignia]);
|
||||
|
||||
Ships[obj->instance].team_name = currentTeamColor;
|
||||
|
||||
|
||||
@@ -118,13 +118,7 @@ static auto DeferredLightingOption = options::OptionBuilder<bool>("Graphics.Defe
|
||||
bool light_deferred_enabled()
|
||||
{
|
||||
if (Using_in_game_options) {
|
||||
static bool isToggledOn = DeferredLightingOption->getValue();
|
||||
// This used to be getting the value of the option object itself,
|
||||
// however that is not a free operation and changing it requires a restart anyway
|
||||
// if the restart requirement is lifted care should be taken to cache this value
|
||||
// and never look it up more than once a frame
|
||||
// otherwise the performance footprint is measurable enough to worry about.
|
||||
return isToggledOn;
|
||||
return DeferredLightingOption->getValue();
|
||||
} else {
|
||||
return !Cmdline_no_deferred_lighting;
|
||||
}
|
||||
@@ -320,7 +314,7 @@ void light_rotate_all()
|
||||
*/
|
||||
int light_get_global_count()
|
||||
{
|
||||
return static_cast<int>(Static_light.size());
|
||||
return (int)Static_light.size();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -64,7 +64,7 @@ bool *Lcl_unexpected_tstring_check = nullptr;
|
||||
// NOTE: with map storage of XSTR strings, the indexes no longer need to be contiguous,
|
||||
// but internal strings should still increment XSTR_SIZE to avoid collisions.
|
||||
// retail XSTR_SIZE = 1570
|
||||
// #define XSTR_SIZE 1857 // This is the next available ID
|
||||
// #define XSTR_SIZE 1842 // This is the next available ID
|
||||
|
||||
|
||||
// struct to allow for strings.tbl-determined x offset
|
||||
|
||||
Loaded 100 of 549 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user