Compare commits

..
Author SHA1 Message Date
MageKing17 322a152476 Timer cleanup/improved wraparound handling.
Changes timestamp code to hopefully remove any oddities involving timestamps in close proximity to ticker rollover. However, more involved computation probably means performance will be impacted.
2019-01-22 20:29:37 -08:00
168 changed files with 3988 additions and 6532 deletions

No files matched your search

-182
View File
@@ -1,182 +0,0 @@
version: 2
references:
container_config: &container_config
docker:
- image: "debian:stretch"
working_directory: /root/build
restore_repo: &restore_repo
restore_cache:
keys:
- source-repo-{{ .Branch }}-{{ .Revision }}
- source-repo-{{ .Branch }}
- source-repo
cmake_configure: &cmake_configure
run:
name: Creating Build Files
command: |
mkdir build
cd build
CXXFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
CFLAGS="-m64 -mtune=generic -mfpmath=sse -msse -msse2 -pipe -Wno-unknown-pragmas"
if [[ "$CC" =~ ^clang.*$ ]]; then
CXXFLAGS="$CXXFLAGS -stdlib=libc++"
fi
eval $CC --version
export CXXFLAGS
export CFLAGS
CMAKE="cmake -G Ninja -DFSO_FATAL_WARNINGS=ON $CMAKE_OPTIONS"
eval $CMAKE -DCMAKE_BUILD_TYPE=$CONFIGURATION -DFSO_BUILD_TESTS=ON -DFSO_BUILD_INCLUDED_LIBS=ON ..
compile: &compile
run:
name: Compiling Source code
command: |
cd build
ninja -k 20 all
run_tests: &run_tests
run:
name: Run unit tests
command: |
./build/bin/unittests --gtest_shuffle
compile_steps: &compile_steps
steps:
- *restore_repo
- *cmake_configure
- *compile
- *run_tests
jobs:
checkout_code:
<<: *container_config
steps:
- run:
name: Installing Git
command: 'apt-get update && apt-get -yq install git'
- *restore_repo
- checkout
- run:
name: Updating submodules
command: 'git submodule update --init --recursive'
- save_cache:
key: source-repo-{{ .Branch }}-{{ .Revision }}
paths:
- .
build_gcc_lowest_debug:
docker:
- image: asarium/fso_compile:gcc-lowest
working_directory: /root/build
environment:
CC: gcc
CXX: g++
CONFIGURATION: Debug
<<: *compile_steps
build_gcc_lowest_release:
docker:
- image: asarium/fso_compile:gcc-lowest
working_directory: /root/build
environment:
CC: gcc
CXX: g++
CONFIGURATION: Release
<<: *compile_steps
build_gcc_latest_debug:
docker:
- image: asarium/fso_compile:gcc-latest
working_directory: /root/build
environment:
CC: gcc
CXX: g++
CONFIGURATION: Debug
<<: *compile_steps
build_gcc_latest_release:
docker:
- image: asarium/fso_compile:gcc-latest
working_directory: /root/build
environment:
CC: gcc
CXX: g++
CONFIGURATION: Release
<<: *compile_steps
build_clang_latest_debug:
docker:
- image: asarium/fso_compile:clang-latest
working_directory: /root/build
environment:
CC: clang-8
CXX: clang++-8
CONFIGURATION: Debug
<<: *compile_steps
build_clang_latest_release:
docker:
- image: asarium/fso_compile:clang-latest
working_directory: /root/build
environment:
CC: clang-8
CXX: clang++-8
CONFIGURATION: Release
<<: *compile_steps
build_clang_lowest_debug:
docker:
- image: asarium/fso_compile:clang-lowest
working_directory: /root/build
environment:
CC: clang
CXX: clang++
CONFIGURATION: Debug
<<: *compile_steps
build_clang_lowest_release:
docker:
- image: asarium/fso_compile:clang-lowest
working_directory: /root/build
environment:
CC: clang
CXX: clang++
CONFIGURATION: Release
<<: *compile_steps
workflows:
version: 2
build_test:
jobs:
- checkout_code
- build_gcc_lowest_debug:
requires:
- checkout_code
- build_gcc_lowest_release:
requires:
- checkout_code
- build_gcc_latest_debug:
requires:
- checkout_code
- build_gcc_latest_release:
requires:
- checkout_code
- build_clang_latest_debug:
requires:
- checkout_code
- build_clang_latest_release:
requires:
- checkout_code
- build_clang_lowest_debug:
requires:
- checkout_code
- build_clang_lowest_release:
requires:
- checkout_code
-1
View File
@@ -5,7 +5,6 @@ cache:
directories:
- $HOME/cmake-3.8
- $HOME/.ccache
- $HOME/curl_cache
addons:
apt:
packages: &global_deps
+18 -53
View File
@@ -10,62 +10,27 @@ if [[ ! "$(curl -V)" == *"sftp"* ]]; then
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
if [ -f ~/curl_cache/curl*.deb ]; then
cd ~/curl_cache
sudo dpkg -i libcurl3*.deb
sudo dpkg -i curl*.deb
else
# Since the Travis CI people are not capable of enabling SSH/SCP support for their libcurl we need to build that manually...
# These commands are based on the tutorial from here: http://zeroset.mnim.org/2013/03/14/sftp-support-for-curl-in-ubuntu-12-10-quantal-quetzal-and-later/
mkdir /tmp/curl
cd /tmp/curl
sudo apt-get update
sudo apt-get install build-essential debhelper libssh2-1-dev libgnutls-dev libidn11-dev libkrb5-dev libldap2-dev libnss3-dev librtmp-dev libtool openssh-server quilt
apt-get source curl
sudo apt-get build-dep curl
# Since the Travis CI people are not capable of enabling SSH/SCP support for their libcurl we need to build that manually...
# These commands are based on the tutorial from here: http://zeroset.mnim.org/2013/03/14/sftp-support-for-curl-in-ubuntu-12-10-quantal-quetzal-and-later/
mkdir /tmp/curl
cd /tmp/curl
sudo apt-get update
sudo apt-get install build-essential debhelper libssh2-1-dev libgnutls-dev libidn11-dev libkrb5-dev libldap2-dev libnss3-dev librtmp-dev libtool openssh-server quilt
apt-get source curl
sudo apt-get build-dep curl
cd curl-*
export DEB_BUILD_OPTIONS="nocheck"
sudo dpkg-buildpackage -uc -us -j"$(grep -c ^processor /proc/cpuinfo)"
cd curl-*
export DEB_BUILD_OPTIONS="nocheck"
sudo dpkg-buildpackage -uc -us -j"$(grep -c ^processor /proc/cpuinfo)"
cd ..
dpkg -l | grep curl
ls -al
if [ ! -d ~/curl_cache ]; then
mkdir ~/curl_cache
fi
cp libcurl3*.deb curl*.deb ~/curl_cache
sudo dpkg -i libcurl3*.deb
sudo dpkg -i curl*.deb
fi
cd ..
dpkg -l | grep curl
ls -al
sudo dpkg -i libcurl3*.deb
sudo dpkg -i curl*.deb
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
brew install libssh2
if [ -d ~/curl_cache/curl ]; then
cd ~/curl_cache/curl
sudo make install
else
mkdir /tmp/curl
cd /tmp/curl
curl -LO "https://curl.haxx.se/download/curl-7.64.0.tar.bz2"
tar -xjf curl-7.64.0.tar.bz2
cd curl-7.64.0
./configure --disable-debug --disable-dependency-tracking --disable-silent-rules --with-libssh2 --with-darwinssl --without-ca-bundle --without-ca-path
make -j"$(sysctl hw.logicalcpu | cut -d " " -f 2)"
if [ ! -d ~/curl_cache ]; then
mkdir ~/curl_cache
fi
cp -a . ~/curl_cache/curl
sudo make install
fi
export PATH=/usr/local/bin:$PATH
brew install curl --with-libssh2
export PATH="/usr/local/opt/curl/bin:$PATH"
fi
# After
+2 -17
View File
@@ -58,8 +58,6 @@
#include "physics/physics.h"
#include "playerman/player.h"
#include "render/3d.h"
#include "scripting/api/objs/wing.h"
#include "scripting/scripting.h"
#include "ship/afterburner.h"
#include "ship/awacs.h"
#include "ship/ship.h"
@@ -1347,7 +1345,6 @@ void ai_object_init(object * obj, int ai_index)
aip->wing = -1; // Member of what wing? -1 means none.
aip->ai_class = Ship_info[Ships[obj->instance].ship_info_index].ai_class;
aip->behavior = AIM_NONE;
aip->mode = aip->behavior;
}
/**
@@ -4589,11 +4586,6 @@ void ai_waypoints()
ai_mission_wing_goal_complete( Ships[Pl_objp->instance].wingnum, &(aip->goals[aip->active_goal]) );
mission_log_add_entry( LOG_WAYPOINTS_DONE, Wings[Ships[Pl_objp->instance].wingnum].name, aip->wp_list->get_name(), -1 );
}
// adds scripting hook for 'On Waypoints Done' --wookieejedi
Script_system.SetHookObject("Ship", &Objects[Ships[Pl_objp->instance].objnum]);
Script_system.SetHookVar("Wing", 'o', scripting::api::l_Wing.Set(Ships[Pl_objp->instance].wingnum));
Script_system.RunCondition(CHA_ONWAYPOINTSDONE);
Script_system.RemHookVars(2, "Ship", "Wing");
}
}
}
@@ -5354,7 +5346,7 @@ int ai_select_primary_weapon(object *objp, object *other_objp, Weapon::Info_Flag
if (Weapon_info[swp->primary_bank_weapons[i]].wi_flags[Weapon::Info_Flags::Capital_plus])
{
swp->current_primary_bank = i;
nprintf(("AI", "%i: Ship %s selecting weapon %s (capital+) vs target %s\n", Framecount, Ships[objp->instance].ship_name, Weapon_info[swp->primary_bank_weapons[i]].name, Ships[other_objp->instance].ship_name));
nprintf(("AI", "%i: Ship %s selecting weapon %s\n", Framecount, Ships[objp->instance].ship_name, Weapon_info[swp->primary_bank_weapons[i]].name));
return i;
}
}
@@ -5392,7 +5384,6 @@ int ai_select_primary_weapon(object *objp, object *other_objp, Weapon::Info_Flag
i_hullfactor_prev_bank = 0; // Just switch to the first one
}
swp->current_primary_bank = i_hullfactor_prev_bank; // Select the best weapon
nprintf(("AI", "%i: Ship %s selecting weapon %s (no shields) vs target %s\n", Framecount, Ships[objp->instance].ship_name, Weapon_info[swp->primary_bank_weapons[i_hullfactor_prev_bank]].name, (other_objp->type == OBJ_SHIP ? Ships[other_objp->instance].ship_name : "non-ship") ));
return i_hullfactor_prev_bank; // Return
}
@@ -5407,7 +5398,6 @@ int ai_select_primary_weapon(object *objp, object *other_objp, Weapon::Info_Flag
if ((Weapon_info[swp->primary_bank_weapons[bank_index]].wi_flags[Weapon::Info_Flags::Pierce_shields]) && !(Weapon_info[swp->primary_bank_weapons[bank_index]].wi_flags[Weapon::Info_Flags::Capital_plus]))
{
nprintf(("AI", "%i: Ship %s selecting weapon %s (>10%% shields)\n", Framecount, Ships[objp->instance].ship_name, Weapon_info[swp->primary_bank_weapons[bank_index]].name));
return swp->current_primary_bank;
}
}
@@ -5422,7 +5412,6 @@ int ai_select_primary_weapon(object *objp, object *other_objp, Weapon::Info_Flag
if ((Weapon_info[weapon_info_index].wi_flags[Weapon::Info_Flags::Pierce_shields]) && !(Weapon_info[swp->primary_bank_weapons[i]].wi_flags[Weapon::Info_Flags::Capital_plus]))
{
swp->current_primary_bank = i;
nprintf(("AI", "%i: Ship %s selecting weapon %s (>10%% shields)\n", Framecount, Ships[objp->instance].ship_name, Weapon_info[swp->primary_bank_weapons[i]].name));
return i;
}
}
@@ -5457,7 +5446,6 @@ int ai_select_primary_weapon(object *objp, object *other_objp, Weapon::Info_Flag
i_hullfactor_prev_bank = 0; // Just switch to the first one
}
swp->current_primary_bank = i_hullfactor_prev_bank; // Select the best weapon
nprintf(("AI", "%i: Ship %s selecting weapon %s (<50%% shields)\n", Framecount, Ships[objp->instance].ship_name, Weapon_info[swp->primary_bank_weapons[i_hullfactor_prev_bank]].name));
return i_hullfactor_prev_bank; // Return
}
else
@@ -5487,7 +5475,6 @@ int ai_select_primary_weapon(object *objp, object *other_objp, Weapon::Info_Flag
i_hullfactor_prev_bank = 0; // Just switch to the first one
}
swp->current_primary_bank = i_hullfactor_prev_bank; // Select the best weapon
nprintf(("AI", "%i: Ship %s selecting weapon %s (>50%% shields)\n", Framecount, Ships[objp->instance].ship_name, Weapon_info[swp->primary_bank_weapons[i_hullfactor_prev_bank]].name));
return i_hullfactor_prev_bank; // Return
}
}
@@ -5515,9 +5502,7 @@ void set_primary_weapon_linkage(object *objp)
// If trying to destroy a big ship (i.e., not disable/disarm), always unleash all weapons
if ( Ship_info[Ships[Objects[aip->target_objnum].instance].ship_info_index].is_big_ship() ) {
if ( aip->targeted_subsys == NULL ) {
if (!sip->flags[Ship::Info_Flags::No_primary_linking] ) {
shipp->flags.set(Ship::Ship_Flags::Primary_linked);
}
shipp->flags.set(Ship::Ship_Flags::Primary_linked);
shipp->flags.set(Ship::Ship_Flags::Secondary_dual_fire);
return;
}
-6
View File
@@ -733,12 +733,6 @@ void ai_add_goal_sub_scripting(int type, int mode, int submode, int priority, ch
aigp->target_signature = Objects[Weapons[submode].objnum].signature;
}
if ( mode == AI_GOAL_WAYPOINTS_ONCE || mode == AI_GOAL_WAYPOINTS ) {
// should be the same as setting via sexp, see ai_add_goal_sub_sexp
// set to null so the AI code can setup the new waypoint list, see ai_mission_goal_achievable
aigp->wp_list = nullptr;
}
if ( target_name != NULL )
aigp->target_name = ai_get_goal_target_name( target_name, &aigp->target_name_index );
else
+2
View File
@@ -1143,6 +1143,8 @@ int asteroid_check_collision(object *pasteroid, object *other_obj, vec3d *hitpos
// SET PHYSICS PARAMETERS
// already have (hitpos - heavy) and light_cm_pos
// get heavy cm pos - already have light_cm_pos
asteroid_hit_info->heavy_collision_cm_pos = zero;
// get r_heavy and r_light
asteroid_hit_info->r_heavy = asteroid_hit_info->hit_pos;
+1 -19
View File
@@ -7,10 +7,9 @@
#include "math/vecmat.h"
#include "mod_table/mod_table.h"
#include "model/model.h" //polymodel, model_get
#include "options/Option.h"
#include "parse/parselo.h"
#include "playerman/player.h" //player_get_padlock_orient
#include "ship/ship.h" //compute_slew_matrix
#include "ship/ship.h" //compute_slew_matrix
//*************************IMPORTANT GLOBALS*************************
float VIEWER_ZOOM_DEFAULT = 0.75f; // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
@@ -25,23 +24,6 @@ SCP_vector<camera*> Cameras;
camid Current_camera;
camid Main_camera;
static SCP_string fov_display(float val)
{
auto degrees = fl_degrees(val);
SCP_string out;
sprintf(out, u8"%.1f\u00B0", degrees);
return out;
}
auto FovOption = options::OptionBuilder<float>("Graphics.FOV", "Field Of View", "The vertical field of view.")
.category("Graphics")
.range(0.436332f, 1.5708f)
.bind_to(&VIEWER_ZOOM_DEFAULT)
.display(fov_display)
.default_val(0.75f)
.level(options::ExpertLevel::Advanced)
.importance(60)
.finish();
//*************************CLASS: camera*************************
//This is where the camera class beings! :D
camera::camera(const char *in_name, int in_signature)
+263 -116
View File
@@ -38,6 +38,9 @@
#include <limits>
char Cfile_root_dir[CFILE_ROOT_DIRECTORY_LEN] = "";
char Cfile_user_dir[CFILE_ROOT_DIRECTORY_LEN] = "";
// During cfile_init, verify that Pathtypes[n].index == n for each item
// Each path must have a valid parent that can be tracable all the way back to the root
// so that we can create directories when we need to.
@@ -98,7 +101,10 @@ static int Cfile_stack_pos = 0;
static char Cfile_stack[CFILE_STACK_MAX][CFILE_ROOT_DIRECTORY_LEN];
std::array<CFILE, MAX_CFILE_BLOCKS> Cfile_block_list;
Cfile_block Cfile_block_list[MAX_CFILE_BLOCKS];
static CFILE Cfile_list[MAX_CFILE_BLOCKS];
static const char *Cfile_cdrom_dir = NULL;
//
// Function prototypes for internally-called functions
@@ -142,15 +148,47 @@ void cfile_close()
#define MIN_NUM_PATH_COMPONENTS 3 /* Drive + directory + file */
#endif
/**
* @brief Determine if the given path is in the root directory
*
* @param exe_path Path to executable
*
* @return true if root directory, false if not
*/
static bool cfile_in_root_dir(const char *exe_path)
{
int new_token;
int token_count = 0;
const char *p = exe_path;
Assert(exe_path != NULL);
do {
new_token = 0;
while (*p == DIR_SEPARATOR_CHAR) {
p++;
}
while ((*p != '\0') && (*p != DIR_SEPARATOR_CHAR)) {
new_token = 1;
p++;
}
token_count += new_token;
} while (*p != '\0');
return (token_count < MIN_NUM_PATH_COMPONENTS);
}
/**
* @brief Initialize the cfile system. Called once at application start.
*
* @param exe_dir Path to a file (not a directory)
* @param cdrom_dir Path to a CD drive mount point (may be NULL)
*
* @return 0 On success
* @return 1 On error
*/
int cfile_init(const SCP_vector<cfile::ModRoot>& modRoots)
int cfile_init(const char *exe_dir, const char *cdrom_dir)
{
// initialize encryption
encrypt_init();
@@ -159,16 +197,47 @@ int cfile_init(const SCP_vector<cfile::ModRoot>& modRoots)
return 0;
}
char buf[CFILE_ROOT_DIRECTORY_LEN];
strncpy(buf, exe_dir, CFILE_ROOT_DIRECTORY_LEN - 1);
buf[CFILE_ROOT_DIRECTORY_LEN - 1] = '\0';
size_t i = strlen(buf);
// are we in a root directory?
if(cfile_in_root_dir(buf)){
os::dialogs::Message(os::dialogs::MESSAGEBOX_ERROR, "FreeSpace2/Fred2 cannot be run from a drive root directory!");
return 1;
}
// This needs to be set here because cf_build_secondary_filelist assumes it to be true
cfile_inited = 1;
/*
* Determine the executable's directory. Note that DIR_SEPARATOR_CHAR
* is guaranteed to be found in the string else cfile_in_root_dir()
* would have failed.
*/
// Initialize the block list with proper data
Cfile_block_list.fill({});
char *p;
p = strrchr(buf, DIR_SEPARATOR_CHAR);
*p = '\0';
cfile_chdir(buf);
// set root directory
strcpy_s(Cfile_root_dir, buf);
strcpy_s(Cfile_user_dir, os_get_config_path().c_str());
for (i = 0; i < MAX_CFILE_BLOCKS; i++) {
Cfile_block_list[i].type = CFILE_BLOCK_UNUSED;
}
// 32 bit CRC table init
cf_chksum_long_init();
cf_build_secondary_filelist(modRoots);
Cfile_cdrom_dir = cdrom_dir;
cf_build_secondary_filelist(Cfile_cdrom_dir);
return 0;
}
@@ -796,14 +865,14 @@ CFILE *ctmpfile()
static int cfget_cfile_block()
{
int i;
CFILE* cfile;
Cfile_block *cb;
for ( i = 0; i < MAX_CFILE_BLOCKS; i++ ) {
cfile = &Cfile_block_list[i];
if (cfile->type == CFILE_BLOCK_UNUSED) {
cfile->data = nullptr;
cfile->fp = nullptr;
cfile->type = CFILE_BLOCK_USED;
cb = &Cfile_block_list[i];
if ( cb->type == CFILE_BLOCK_UNUSED ) {
cb->data = NULL;
cb->fp = NULL;
cb->type = CFILE_BLOCK_USED;
return i;
}
}
@@ -831,36 +900,39 @@ int cfclose( CFILE * cfile )
int result;
Assert(cfile != NULL);
Cfile_block *cb;
Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
cb = &Cfile_block_list[cfile->id];
result = 0;
if ( cfile->data && cfile->mem_mapped ) {
if ( cb->data && cb->mem_mapped ) {
// close memory mapped file
#if defined _WIN32
result = UnmapViewOfFile((void*)cfile->data);
result = UnmapViewOfFile((void*)cb->data);
Assert(result);
result = CloseHandle(cfile->hInFile);
result = CloseHandle(cb->hInFile);
Assert(result); // Ensure file handle is closed properly
result = CloseHandle(cfile->hMapFile);
result = CloseHandle(cb->hMapFile);
Assert(result); // Ensure file handle is closed properly
result = 0;
#elif defined SCP_UNIX
// FIXME: result is wrong after munmap() but it is successful
//result = munmap(cfile->data, cfile->data_length);
//result = munmap(cb->data, cb->data_length);
//Assert(result);
// This const_cast is safe since the pointer returned by mmap was also non-const
munmap(const_cast<void*>(cfile->data), cfile->data_length);
if ( cfile->fp != nullptr)
result = fclose(cfile->fp);
munmap(const_cast<void*>(cb->data), cb->data_length);
if ( cb->fp != NULL)
result = fclose(cb->fp);
#endif
} else if ( cfile->fp != nullptr ) {
Assert(cfile->fp != nullptr);
result = fclose(cfile->fp);
} else if ( cb->fp != NULL ) {
Assert(cb->fp != NULL);
result = fclose(cb->fp);
} else {
// VP do nothing
}
cfile->type = CFILE_BLOCK_UNUSED;
cb->type = CFILE_BLOCK_UNUSED;
return result;
}
@@ -870,8 +942,13 @@ int cf_is_valid(CFILE *cfile)
if(cfile == NULL)
return 0;
//Does it have a valid ID?
if(cfile->id < 0 || cfile->id >= MAX_CFILE_BLOCKS)
return 0;
//Is it used?
if (cfile->type != CFILE_BLOCK_USED && (cfile->fp != nullptr || cfile->data != nullptr))
Cfile_block *cb = &Cfile_block_list[cfile->id];
if(cb->type != CFILE_BLOCK_USED && (cb->fp != NULL || cb->data != NULL))
return 0;
//It's good, as near as we can tell.
@@ -896,15 +973,20 @@ static CFILE *cf_open_fill_cfblock(const char* source, int line, FILE *fp, int t
fclose(fp);
return NULL;
} else {
CFILE *cfp = &Cfile_block_list[cfile_block_index];
cfp->data = nullptr;
cfp->mem_mapped = false;
cfp->fp = fp;
cfp->dir_type = type;
cfp->max_read_len = 0;
CFILE *cfp;
Cfile_block *cfbp;
cfbp = &Cfile_block_list[cfile_block_index];
cfp = &Cfile_list[cfile_block_index];
cfp->id = cfile_block_index;
cfp->version = 0;
cfbp->data = NULL;
cfbp->mem_mapped = false;
cfbp->fp = fp;
cfbp->dir_type = type;
cfbp->max_read_len = 0;
cfp->source_file = source;
cfp->line_num = line;
cfbp->source_file = source;
cfbp->line_num = line;
int pos = ftell(fp);
if(pos == -1L)
@@ -932,16 +1014,21 @@ static CFILE *cf_open_packed_cfblock(const char* source, int line, FILE *fp, int
fclose(fp);
return NULL;
} else {
CFILE *cfp = &Cfile_block_list[cfile_block_index];
CFILE *cfp;
Cfile_block *cfbp;
cfbp = &Cfile_block_list[cfile_block_index];
cfp = &Cfile_list[cfile_block_index];
cfp->id = cfile_block_index;
cfp->version = 0;
cfbp->data = NULL;
cfbp->fp = fp;
cfbp->mem_mapped = false;
cfbp->dir_type = type;
cfbp->max_read_len = 0;
cfp->data = nullptr;
cfp->fp = fp;
cfp->mem_mapped = false;
cfp->dir_type = type;
cfp->max_read_len = 0;
cfp->source_file = source;
cfp->line_num = line;
cfbp->source_file = source;
cfbp->line_num = line;
cf_init_lowlevel_read_code(cfp,offset, size, 0 );
@@ -973,39 +1060,44 @@ static CFILE *cf_open_mapped_fill_cfblock(const char* source, int line, FILE *fp
return NULL;
}
else {
CFILE *cfp = &Cfile_block_list[cfile_block_index];
CFILE *cfp;
Cfile_block *cfbp;
cfbp = &Cfile_block_list[cfile_block_index];
cfp->max_read_len = 0;
cfp->fp = nullptr;
cfp->mem_mapped = true;
cfp = &Cfile_list[cfile_block_index];
cfp->id = cfile_block_index;
cfp->version = 0;
cfbp->max_read_len = 0;
cfbp->fp = NULL;
cfbp->mem_mapped = true;
#if defined _WIN32
cfp->hInFile = hFile;
cfbp->hInFile = hFile;
#endif
cfp->dir_type = type;
cfbp->dir_type = type;
cfp->source_file = source;
cfp->line_num = line;
cfbp->source_file = source;
cfbp->line_num = line;
cf_init_lowlevel_read_code(cfp, 0, 0, 0 );
#if defined _WIN32
cfp->hMapFile = CreateFileMapping(cfp->hInFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (cfp->hMapFile == NULL) {
cfbp->hMapFile = CreateFileMapping(cfbp->hInFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (cfbp->hMapFile == NULL) {
nprintf(("Error", "Could not create file-mapping object.\n"));
return NULL;
}
cfp->data = (ubyte*)MapViewOfFile(cfp->hMapFile, FILE_MAP_READ, 0, 0, 0);
Assert( cfp->data != NULL );
cfbp->data = (ubyte*)MapViewOfFile(cfbp->hMapFile, FILE_MAP_READ, 0, 0, 0);
Assert( cfbp->data != NULL );
#elif defined SCP_UNIX
cfp->fp = fp;
cfp->data_length = filelength(fileno(fp));
cfp->data = mmap(nullptr, // start
cfp->data_length, // length
PROT_READ, // prot
MAP_SHARED, // flags
fileno(fp), // fd
0); // offset
Assert(cfp->data != nullptr);
cfbp->fp = fp;
cfbp->data_length = filelength( fileno(fp) );
cfbp->data = mmap(NULL, // start
cfbp->data_length, // length
PROT_READ, // prot
MAP_SHARED, // flags
fileno(fp), // fd
0); // offset
Assert( cfbp->data != NULL );
#endif
return cfp;
@@ -1021,18 +1113,23 @@ static CFILE *cf_open_memory_fill_cfblock(const char* source, int line, const vo
return NULL;
}
else {
CFILE *cfp = &Cfile_block_list[cfile_block_index];
CFILE *cfp;
Cfile_block *cfbp;
cfbp = &Cfile_block_list[cfile_block_index];
cfp->max_read_len = 0;
cfp->fp = nullptr;
cfp->mem_mapped = false;
cfp->dir_type = dir_type;
cfp = &Cfile_list[cfile_block_index];
cfp->id = cfile_block_index;
cfp->version = 0;
cfbp->max_read_len = 0;
cfbp->fp = NULL;
cfbp->mem_mapped = false;
cfbp->dir_type = dir_type;
cfp->source_file = source;
cfp->line_num = line;
cfbp->source_file = source;
cfbp->line_num = line;
cf_init_lowlevel_read_code(cfp, 0, size, 0 );
cfp->data = data;
cfbp->data = data;
return cfp;
}
@@ -1040,7 +1137,7 @@ static CFILE *cf_open_memory_fill_cfblock(const char* source, int line, const vo
int cf_get_dir_type(CFILE *cfile)
{
return cfile->dir_type;
return Cfile_block_list[cfile->id].dir_type;
}
// cf_returndata() returns the data pointer for a memory-mapped file that is associated
@@ -1051,8 +1148,11 @@ int cf_get_dir_type(CFILE *cfile)
const void *cf_returndata(CFILE *cfile)
{
Assert(cfile != NULL);
Assert(cfile->data != nullptr);
return cfile->data;
Cfile_block *cb;
Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
cb = &Cfile_block_list[cfile->id];
Assert(cb->data != NULL);
return cb->data;
}
// cutoff point where cfread() will throw an error when it hits this limit
@@ -1060,21 +1160,27 @@ const void *cf_returndata(CFILE *cfile)
void cf_set_max_read_len( CFILE * cfile, size_t len )
{
Assert( cfile != NULL );
Assert( (cfile->id >= 0) && (cfile->id < MAX_CFILE_BLOCKS) );
Cfile_block *cb = &Cfile_block_list[cfile->id];
if (len) {
cfile->max_read_len = cfile->raw_position + len;
cb->max_read_len = cb->raw_position + len;
} else {
cfile->max_read_len = 0;
cb->max_read_len = 0;
}
}
// routines to read basic data types from CFILE's. Put here to
// simplify mac/pc reading from cfiles.
float cfread_float(CFILE* file, float deflt)
float cfread_float(CFILE *file, int ver, float deflt)
{
float f;
if (file->version < ver)
return deflt;
if (cfread( &f, sizeof(f), 1, file) != 1)
return deflt;
@@ -1082,10 +1188,13 @@ float cfread_float(CFILE* file, float deflt)
return f;
}
int cfread_int(CFILE* file, int deflt)
int cfread_int(CFILE *file, int ver, int deflt)
{
int i;
if (file->version < ver)
return deflt;
if (cfread( &i, sizeof(i), 1, file) != 1)
return deflt;
@@ -1093,10 +1202,13 @@ int cfread_int(CFILE* file, int deflt)
return i;
}
uint cfread_uint(CFILE* file, uint deflt)
uint cfread_uint(CFILE *file, int ver, uint deflt)
{
uint i;
if (file->version < ver)
return deflt;
if (cfread( &i, sizeof(i), 1, file) != 1)
return deflt;
@@ -1104,10 +1216,13 @@ uint cfread_uint(CFILE* file, uint deflt)
return i;
}
short cfread_short(CFILE* file, short deflt)
short cfread_short(CFILE *file, int ver, short deflt)
{
short s;
if (file->version < ver)
return deflt;
if (cfread( &s, sizeof(s), 1, file) != 1)
return deflt;
@@ -1115,10 +1230,13 @@ short cfread_short(CFILE* file, short deflt)
return s;
}
ushort cfread_ushort(CFILE* file, ushort deflt)
ushort cfread_ushort(CFILE *file, int ver, ushort deflt)
{
ushort s;
if (file->version < ver)
return deflt;
if (cfread( &s, sizeof(s), 1, file) != 1)
return deflt;
@@ -1126,26 +1244,42 @@ ushort cfread_ushort(CFILE* file, ushort deflt)
return s;
}
ubyte cfread_ubyte(CFILE* file, ubyte deflt)
ubyte cfread_ubyte(CFILE *file, int ver, ubyte deflt)
{
ubyte b;
if (file->version < ver)
return deflt;
if (cfread( &b, sizeof(b), 1, file) != 1)
return deflt;
return b;
}
void cfread_vector(vec3d* vec, CFILE* file, vec3d* deflt) {
vec->xyz.x = cfread_float(file, deflt ? deflt->xyz.x : 0.0f);
vec->xyz.y = cfread_float(file, deflt ? deflt->xyz.y : 0.0f);
vec->xyz.z = cfread_float(file, deflt ? deflt->xyz.z : 0.0f);
void cfread_vector(vec3d *vec, CFILE *file, int ver, vec3d *deflt)
{
if (file->version < ver) {
if (deflt)
*vec = *deflt;
else
vec->xyz.x = vec->xyz.y = vec->xyz.z = 0.0f;
return;
}
vec->xyz.x = cfread_float(file, ver, deflt ? deflt->xyz.x : 0.0f);
vec->xyz.y = cfread_float(file, ver, deflt ? deflt->xyz.y : 0.0f);
vec->xyz.z = cfread_float(file, ver, deflt ? deflt->xyz.z : 0.0f);
}
char cfread_char(CFILE* file, char deflt)
char cfread_char(CFILE *file, int ver, char deflt)
{
char b;
if (file->version < ver)
return deflt;
if (cfread( &b, sizeof(b), 1, file) != 1)
return deflt;
@@ -1258,18 +1392,22 @@ int cfwrite_string_len(const char *buf, CFILE *file)
}
// Get the filelength
int cfilelength(CFILE* cfile) {
int cfilelength( CFILE * cfile )
{
Assert(cfile != NULL);
Cfile_block *cb;
Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
cb = &Cfile_block_list[cfile->id];
// TODO: return length of memory mapped file
Assert(!cfile->mem_mapped);
// cfile->size gets set at cfopen
Assert( !cb->mem_mapped );
// cb->size gets set at cfopen
// The rest of the code still uses ints, do an overflow check to detect cases where this fails
Assertion(cfile->size <= static_cast<size_t>(std::numeric_limits<int>::max()),
"Integer overflow in cfilelength! A file is too large (but I don't know which...).");
return (int) cfile->size;
Assertion(cb->size <= static_cast<size_t>(std::numeric_limits<int>::max()),
"Integer overflow in cfilelength! A file is too large (but I don't know which...).");
return (int) cb->size;
}
// cfwrite() writes to the file
@@ -1285,13 +1423,15 @@ int cfwrite(const void *buf, int elsize, int nelem, CFILE *cfile)
if(buf == NULL || elsize == 0 || nelem == 0)
return 0;
if(cfile->lib_offset != 0)
Cfile_block *cb = &Cfile_block_list[cfile->id];
if(cb->lib_offset != 0)
{
Error(LOCATION, "Attempt to write to a VP file (unsupported)");
return 0;
}
if(cfile->data != nullptr)
if(cb->data != NULL)
{
Warning(LOCATION, "Writing is not supported for mem-mapped files");
return EOF;
@@ -1300,16 +1440,16 @@ int cfwrite(const void *buf, int elsize, int nelem, CFILE *cfile)
size_t bytes_written = 0;
size_t size = elsize * nelem;
bytes_written = fwrite(buf, 1, size, cfile->fp);
bytes_written = fwrite(buf, 1, size, cb->fp);
//WMC - update filesize and position
if (bytes_written > 0) {
cfile->size += bytes_written;
cfile->raw_position += bytes_written;
cb->size += bytes_written;
cb->raw_position += bytes_written;
}
#if defined(CHECK_SIZE) && !defined(NDEBUG)
Assert( cfile->size == filelength(fileno(cfile->fp)) );
Assert( cb->size == filelength(fileno(cb->fp)) );
#endif
return (int)(bytes_written / elsize);
@@ -1326,32 +1466,34 @@ int cfputc(int c, CFILE *cfile)
if(!cf_is_valid(cfile))
return EOF;
if(cfile->lib_offset != 0)
Cfile_block *cb = &Cfile_block_list[cfile->id];
if(cb->lib_offset != 0)
{
Error(LOCATION, "Attempt to write character to a VP file (unsupported)");
return EOF;
}
if(cfile->data != nullptr)
if(cb->data != NULL)
{
Warning(LOCATION, "Writing is not supported for mem-mapped files");
return EOF;
}
// writing not supported for memory-mapped files
Assert( !cfile->data );
Assert( !cb->data );
int result = fputc(c, cfile->fp);
int result = fputc(c, cb->fp);
//WMC - update filesize and position
if(result != EOF)
{
cfile->size += 1;
cfile->raw_position += 1;
cb->size += 1;
cb->raw_position += 1;
}
#if defined(CHECK_SIZE) && !defined(NDEBUG)
Assert( cfile->size == filelength(fileno(cfile->fp)) );
Assert( cb->size == filelength(fileno(cb->fp)) );
#endif
return result;
@@ -1370,29 +1512,31 @@ int cfputs(const char *str, CFILE *cfile)
if(str == NULL)
return EOF;
if(cfile->lib_offset != 0)
Cfile_block *cb = &Cfile_block_list[cfile->id];
if(cb->lib_offset != 0)
{
Error(LOCATION, "Attempt to write character to a VP file (unsupported)");
return EOF;
}
if(cfile->data != nullptr)
if(cb->data != NULL)
{
Warning(LOCATION, "Writing is not supported for mem-mapped files");
return EOF;
}
int result = fputs(str, cfile->fp);
int result = fputs(str, cb->fp);
//WMC - update filesize and position
if(result != EOF)
{
cfile->size += strlen(str);
cfile->raw_position += strlen(str);
cb->size += strlen(str);
cb->raw_position += strlen(str);
}
#if defined(CHECK_SIZE) && !defined(NDEBUG)
Assert( cfile->size == filelength(fileno(cfile->fp)) );
Assert( cb->size == filelength(fileno(cb->fp)) );
#endif
return result;
@@ -1754,16 +1898,19 @@ int cf_chksum_long(CFILE *file, uint *chksum, int max_size)
int cflush(CFILE *cfile)
{
Assert(cfile != NULL);
Cfile_block *cb;
Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
cb = &Cfile_block_list[cfile->id];
// not supported for memory mapped files
Assert( !cfile->data );
Assert( !cb->data );
Assert(cfile->fp != nullptr);
Assert(cb->fp != NULL);
int result = fflush(cfile->fp);
int result = fflush(cb->fp);
//WMC - update filesize
cfile->size = filelength(fileno(cfile->fp));
cb->size = filelength(fileno(cb->fp));
return result;
}
+16 -39
View File
@@ -13,11 +13,10 @@
#define __CFILE_H__
#include <ctime>
#include "globalincs/pstypes.h"
#include <ctime>
#include <stdexcept>
#include <memory>
#define CF_EOF (-1)
@@ -26,8 +25,10 @@
#define CF_SEEK_CUR (1)
#define CF_SEEK_END (2)
// Opaque file handle
struct CFILE;
typedef struct CFILE {
int id; // Index into cfile.cpp specific structure
int version; // version of this file
} CFILE;
// extra info that can be returned when getting a file listing
typedef struct {
@@ -165,22 +166,11 @@ extern const char *Get_file_list_child;
// cfile directory. valid after cfile_init() returns successfully
#define CFILE_ROOT_DIRECTORY_LEN 256
namespace cfile {
enum class ModRootType { Unknown, Folder, Package };
enum class LocationType { Unknown, SecondaryMod, PrimaryMod, GameRoot };
struct ModRoot {
ModRootType type = ModRootType::Unknown;
SCP_string path;
LocationType location_type = LocationType::Unknown;
bool user_location = false;
};
} // namespace cfile
extern char Cfile_root_dir[CFILE_ROOT_DIRECTORY_LEN];
extern char Cfile_user_dir[CFILE_ROOT_DIRECTORY_LEN];
//================= LOW-LEVEL FUNCTIONS ==================
int cfile_init(const SCP_vector<cfile::ModRoot>& modRoots);
int cfile_init(const char *exe_dir, const char *cdrom_dir=NULL);
void cfile_close();
// add an extension to a filename if it doesn't already have it
@@ -313,14 +303,14 @@ int cfile_flush_dir(int type);
// These are all high level, built up from
// cfread.
char *cfgets(char *buf, size_t n, CFILE *fp);
char cfread_char(CFILE* file, char deflt = 0);
ubyte cfread_ubyte(CFILE* file, ubyte deflt = 0);
short cfread_short(CFILE* file, short deflt = 0);
ushort cfread_ushort(CFILE* file, ushort deflt = 0);
int cfread_int(CFILE* file, int deflt = 0);
uint cfread_uint(CFILE* file, uint deflt = 0);
float cfread_float(CFILE* file, float deflt = 0.0f);
void cfread_vector(vec3d* vec, CFILE* file, vec3d* deflt = nullptr);
char cfread_char(CFILE *file, int ver = 0, char deflt = 0);
ubyte cfread_ubyte(CFILE *file, int ver = 0, ubyte deflt = 0);
short cfread_short(CFILE *file, int ver = 0, short deflt = 0);
ushort cfread_ushort(CFILE *file, int ver = 0, ushort deflt = 0);
int cfread_int(CFILE *file, int ver = 0, int deflt = 0);
uint cfread_uint(CFILE *file, int ver = 0, uint deflt = 0);
float cfread_float(CFILE *file, int ver = 0, float deflt = 0.0f);
void cfread_vector(vec3d *vec, CFILE *file, int ver = 0, vec3d *deflt = NULL);
// Reads variable length, null-termined string. Will only read up
// to n characters.
@@ -472,17 +462,4 @@ namespace cfile
}
// This allows to use std::unique_ptr with CFILE
namespace std {
template <>
struct default_delete<CFILE> {
void operator()(CFILE* ptr)
{
if (cf_is_valid(ptr)) {
cfclose(ptr);
}
}
};
} // namespace std
#endif /* __CFILE_H__ */
+74 -55
View File
@@ -36,20 +36,24 @@
void cf_init_lowlevel_read_code( CFILE * cfile, size_t lib_offset, size_t size, size_t pos )
{
Assert(cfile != nullptr);
Assert(cfile != NULL);
cfile->lib_offset = lib_offset;
cfile->raw_position = pos;
cfile->size = size;
Cfile_block *cb;
Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
cb = &Cfile_block_list[cfile->id];
if ( cfile->fp ) {
if ( cfile->lib_offset ) {
fseek( cfile->fp, (long)cfile->lib_offset, SEEK_SET );
cb->lib_offset = lib_offset;
cb->raw_position = pos;
cb->size = size;
if ( cb->fp ) {
if ( cb->lib_offset ) {
fseek( cb->fp, (long)cb->lib_offset, SEEK_SET );
}
#if defined(CHECK_POSITION) && !defined(NDEBUG)
auto raw_position = ftell(cfile->fp) - cfile->lib_offset;
Assert(raw_position == cfile->raw_position);
auto raw_position = ftell(cb->fp) - cb->lib_offset;
Assert(raw_position == cb->raw_position);
#endif
}
}
@@ -66,16 +70,20 @@ int cfeof(CFILE *cfile)
{
Assert(cfile != NULL);
Cfile_block *cb;
Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
cb = &Cfile_block_list[cfile->id];
int result = 0;
#if defined(CHECK_POSITION) && !defined(NDEBUG)
if (cfile->fp) {
auto raw_position = ftell(cfile->fp) - cfile->lib_offset;
Assert(raw_position == cfile->raw_position);
if (cb->fp) {
auto raw_position = ftell(cb->fp) - cb->lib_offset;
Assert(raw_position == cb->raw_position);
}
#endif
if (cfile->raw_position >= cfile->size ) {
if (cb->raw_position >= cb->size ) {
result = 1;
} else {
result = 0;
@@ -92,18 +100,21 @@ int cfeof(CFILE *cfile)
int cftell( CFILE * cfile )
{
Assert(cfile != NULL);
Cfile_block *cb;
Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
cb = &Cfile_block_list[cfile->id];
#if defined(CHECK_POSITION) && !defined(NDEBUG)
if (cfile->fp) {
auto raw_position = ftell(cfile->fp) - cfile->lib_offset;
Assert(raw_position == cfile->raw_position);
if (cb->fp) {
auto raw_position = ftell(cb->fp) - cb->lib_offset;
Assert(raw_position == cb->raw_position);
}
#endif
// The rest of the code still uses ints, do an overflow check to detect cases where this fails
Assertion(cfile->raw_position <= static_cast<size_t>(std::numeric_limits<int>::max()),
Assertion(cb->raw_position <= static_cast<size_t>(std::numeric_limits<int>::max()),
"Integer overflow in cftell, a file is probably too large (but I don't know which one).");
return (int) cfile->raw_position;
return (int) cb->raw_position;
}
@@ -116,23 +127,27 @@ int cfseek( CFILE *cfile, int offset, int where )
{
Assert(cfile != NULL);
Cfile_block *cb;
Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
cb = &Cfile_block_list[cfile->id];
// TODO: seek to offset in memory mapped file
Assert( !cfile->mem_mapped );
Assert( !cb->mem_mapped );
size_t goal_position;
switch( where ) {
case CF_SEEK_SET:
goal_position = offset+cfile->lib_offset;
goal_position = offset+cb->lib_offset;
break;
case CF_SEEK_CUR:
{
goal_position = cfile->raw_position+offset+cfile->lib_offset;
goal_position = cb->raw_position+offset+cb->lib_offset;
}
break;
case CF_SEEK_END:
goal_position = cfile->size+offset+cfile->lib_offset;
goal_position = cb->size+offset+cb->lib_offset;
break;
default:
Int3();
@@ -140,23 +155,23 @@ int cfseek( CFILE *cfile, int offset, int where )
}
// Make sure we don't seek beyond the end of the file
CAP(goal_position, cfile->lib_offset, cfile->lib_offset + cfile->size);
CAP(goal_position, cb->lib_offset, cb->lib_offset + cb->size);
int result = 0;
if (cfile->fp) {
if (cb->fp) {
// If we have a file pointer we can also seek in that file
result = fseek(cfile->fp, (long)goal_position, SEEK_SET );
Assertion(goal_position >= cfile->lib_offset, "Invalid offset values detected while seeking! Goal was " SIZE_T_ARG ", lib_offset is " SIZE_T_ARG ".", goal_position, cfile->lib_offset);
result = fseek(cb->fp, (long)goal_position, SEEK_SET );
Assertion(goal_position >= cb->lib_offset, "Invalid offset values detected while seeking! Goal was " SIZE_T_ARG ", lib_offset is " SIZE_T_ARG ".", goal_position, cb->lib_offset);
}
// If we only have a data pointer this will do all the work
cfile->raw_position = goal_position - cfile->lib_offset;
Assertion(cfile->raw_position <= cfile->size, "Invalid raw_position value detected!");
cb->raw_position = goal_position - cb->lib_offset;
Assertion(cb->raw_position <= cb->size, "Invalid raw_position value detected!");
#if defined(CHECK_POSITION) && !defined(NDEBUG)
if (cfile->fp) {
auto tmp_offset = ftell(cfile->fp) - cfile->lib_offset;
Assert(tmp_offset == cfile->raw_position);
if (cb->fp) {
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
Assert(tmp_offset == cb->raw_position);
}
#endif
@@ -179,17 +194,19 @@ int cfread(void *buf, int elsize, int nelem, CFILE *cfile)
if(buf == NULL || size <= 0)
return 0;
if ( (cfile->raw_position+size) > cfile->size ) {
Assertion(cfile->raw_position <= cfile->size, "Invalid raw_position value detected!");
size = cfile->size - cfile->raw_position;
Cfile_block *cb = &Cfile_block_list[cfile->id];
if ( (cb->raw_position+size) > cb->size ) {
Assertion(cb->raw_position <= cb->size, "Invalid raw_position value detected!");
size = cb->size - cb->raw_position;
if ( size < 1 ) {
return 0;
}
//mprintf(( "CFILE: EOF encountered in file\n" ));
}
if (cfile->max_read_len) {
if ( cfile->raw_position+size > cfile->max_read_len ) {
if (cb->max_read_len) {
if ( cb->raw_position+size > cb->max_read_len ) {
std::ostringstream s_buf;
s_buf << "Attempted to read " << size << "-byte(s) beyond length limit";
@@ -198,22 +215,22 @@ int cfread(void *buf, int elsize, int nelem, CFILE *cfile)
}
size_t bytes_read;
if (cfile->data != nullptr) {
if (cb->data != nullptr) {
// This is a file from memory
bytes_read = size;
memcpy(buf, reinterpret_cast<const char*>(cfile->data) + cfile->raw_position, size);
memcpy(buf, reinterpret_cast<const char*>(cb->data) + cb->raw_position, size);
} else {
bytes_read = fread( buf, 1, size, cfile->fp );
bytes_read = fread( buf, 1, size, cb->fp );
}
if ( bytes_read > 0 ) {
cfile->raw_position += bytes_read;
Assertion(cfile->raw_position <= cfile->size, "Invalid raw_position value detected!");
cb->raw_position += bytes_read;
Assertion(cb->raw_position <= cb->size, "Invalid raw_position value detected!");
}
#if defined(CHECK_POSITION) && !defined(NDEBUG)
if (cfile->fp) {
auto tmp_offset = ftell(cfile->fp) - cfile->lib_offset;
Assert(tmp_offset==cfile->raw_position);
if (cb->fp) {
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
Assert(tmp_offset==cb->raw_position);
}
#endif
@@ -229,8 +246,10 @@ int cfread_lua_number(double *buf, CFILE *cfile)
if(buf == NULL)
return 0;
Cfile_block *cb = &Cfile_block_list[cfile->id];
// cfread() not supported for memory-mapped files
if(cfile->data != nullptr)
if(cb->data != NULL)
{
Warning(LOCATION, "Writing is not supported for mem-mapped files");
return 0;
@@ -238,28 +257,28 @@ int cfread_lua_number(double *buf, CFILE *cfile)
size_t advance = 0;
int items_read;
if (cfile->fp) {
long orig_pos = ftell(cfile->fp);
items_read = fscanf(cfile->fp, LUA_NUMBER_SCAN, buf);
advance = (size_t) (ftell(cfile->fp)-orig_pos);
if (cb->fp) {
long orig_pos = ftell(cb->fp);
items_read = fscanf(cb->fp, LUA_NUMBER_SCAN, buf);
advance = (size_t) (ftell(cb->fp)-orig_pos);
} else {
int read;
// %n returns the number of bytes currently read so we append that to the scan format at the end so it will return
// how many bytes we have consumed
items_read = sscanf(reinterpret_cast<const char*>(cfile->data), LUA_NUMBER_SCAN "%n", buf, &read);
items_read = sscanf(reinterpret_cast<const char*>(cb->data), LUA_NUMBER_SCAN "%n", buf, &read);
if (items_read == 2) {
// We need to correct the items read counter since we read one additional item
items_read = 1;
}
advance = (size_t) read;
}
cfile->raw_position += advance;
Assertion(cfile->raw_position <= cfile->size, "Invalid raw_position value detected!");
cb->raw_position += advance;
Assertion(cb->raw_position <= cb->size, "Invalid raw_position value detected!");
#if defined(CHECK_POSITION) && !defined(NDEBUG)
if (cfile->fp) {
auto tmp_offset = ftell(cfile->fp) - cfile->lib_offset;
Assert(tmp_offset==cfile->raw_position);
if (cb->fp) {
auto tmp_offset = ftell(cb->fp) - cb->lib_offset;
Assert(tmp_offset==cb->raw_position);
}
#endif
+14 -14
View File
@@ -22,30 +22,30 @@
#define CFILE_BLOCK_UNUSED 0
#define CFILE_BLOCK_USED 1
struct CFILE {
int type = CFILE_BLOCK_UNUSED; // CFILE_BLOCK_UNUSED, CFILE_BLOCK_USED
int dir_type; // directory location
FILE* fp; // File pointer if opening an individual file
const void* data; // Pointer for memory-mapped file access. NULL if not mem-mapped.
bool mem_mapped; // Flag for memory mapped files (if data is not null and this is false it means that it's an embedded file)
typedef struct Cfile_block {
int type; // CFILE_BLOCK_UNUSED, CFILE_BLOCK_USED
int dir_type; // directory location
FILE *fp; // File pointer if opening an individual file
const void *data; // Pointer for memory-mapped file access. NULL if not mem-mapped.
bool mem_mapped; // Flag for memory mapped files (if data is not null and this is false it means that it's an embedded file)
#ifdef _WIN32
HANDLE hInFile; // Handle from CreateFile()
HANDLE hMapFile; // Handle from CreateFileMapping()
#else
size_t data_length; // length of data for mmap
size_t data_length; // length of data for mmap
#endif
size_t lib_offset;
size_t raw_position;
size_t size; // for packed files
size_t max_read_len; // max read offset, for special error handling
size_t lib_offset;
size_t raw_position;
size_t size; // for packed files
size_t max_read_len; // max read offset, for special error handling
const char* source_file;
int line_num;
};
} Cfile_block;
#define MAX_CFILE_BLOCKS 64
extern std::array<CFILE, MAX_CFILE_BLOCKS> Cfile_block_list;
extern Cfile_block Cfile_block_list[MAX_CFILE_BLOCKS];
// Called once to setup the low-level reading code.
void cf_init_lowlevel_read_code( CFILE * cfile, size_t lib_offset, size_t size, size_t pos );
-266
View File
@@ -1,266 +0,0 @@
#define _CFILE_INTERNAL
#include "cfilemod.h"
#include "cfile.h"
#include "cmdline/cmdline.h"
#include "osapi/osapi.h"
#include "cfilesystem.h"
#ifdef SCP_UNIX
#include <glob.h>
#include <sys/types.h>
#include <dirent.h>
#include <fnmatch.h>
#include <sys/stat.h>
#include <unistd.h>
#include <libgen.h>
#endif
namespace cfile {
namespace {
typedef struct cf_root_sort {
SCP_string path;
int cf_type;
} cf_root_sort;
// packfile sort function
bool cf_packfile_sort_func(const cf_root_sort& r1, const cf_root_sort& r2) {
// if the 2 directory types are the same, do a string compare
if (r1.cf_type == r2.cf_type) {
return (stricmp(r1.path.c_str(), r2.path.c_str()) < 0);
}
// otherwise return them in order of CF_TYPE_* precedence
return (r1.cf_type < r2.cf_type);
}
// Go through a root and look for pack files
void build_pack_list(SCP_vector<ModRoot>& mod_roots,
const SCP_string& search_path,
LocationType location_type,
bool user_location) {
char filespec[MAX_PATH_LEN];
// allocate a temporary array of temporary roots so we can easily sort them
SCP_vector<cf_root_sort> temp_roots_sort;
// now just setup all the root info
for (int i = CF_TYPE_ROOT; i < CF_MAX_PATH_TYPES; i++) {
strcpy_s(filespec, search_path.c_str());
if (strlen(Pathtypes[i].path)) {
strcat_s(filespec, Pathtypes[i].path);
if (filespec[strlen(filespec) - 1] != DIR_SEPARATOR_CHAR)
strcat_s(filespec, DIR_SEPARATOR_STR);
}
#if defined _WIN32
strcat_s( filespec, "*.vp" );
intptr_t find_handle;
_finddata_t find;
find_handle = _findfirst( filespec, &find );
if (find_handle != -1) {
do {
// add the new item
if (!(find.attrib & _A_SUBDIR)) {
// get a temp pointer
rptr_sort = &temp_roots_sort[root_index++];
// fill in all the proper info
strcpy_s(rptr_sort->path, root->path);
if(strlen(Pathtypes[i].path)) {
strcat_s(rptr_sort->path, Pathtypes[i].path );
strcat_s(rptr_sort->path, DIR_SEPARATOR_STR);
}
strcat_s(rptr_sort->path, find.name );
rptr_sort->roottype = CF_ROOTTYPE_PACK;
rptr_sort->cf_type = i;
}
} while (!_findnext(find_handle, &find));
_findclose( find_handle );
}
#elif defined SCP_UNIX
strcat_s(filespec, "*.[vV][pP]");
glob_t globinfo;
memset(&globinfo, 0, sizeof(globinfo));
int status = glob(filespec, 0, NULL, &globinfo);
if (status == 0) {
for (uint j = 0; j < globinfo.gl_pathc; j++) {
// Determine if this is a regular file
struct stat statbuf;
memset(&statbuf, 0, sizeof(statbuf));
stat(globinfo.gl_pathv[j], &statbuf);
if (S_ISREG(statbuf.st_mode)) {
cf_root_sort sort;
// fill in all the proper info
sort.path = globinfo.gl_pathv[j];
sort.cf_type = i;
temp_roots_sort.push_back(sort);
}
}
globfree(&globinfo);
}
#endif
}
// sort the roots
std::sort(temp_roots_sort.begin(), temp_roots_sort.end(), cf_packfile_sort_func);
// now insert them all into the real root list properly
for (const auto& pack_root : temp_roots_sort) {
ModRoot root;
root.type = ModRootType::Package;
root.path = pack_root.path;
root.user_location = user_location;
root.location_type = location_type;
mod_roots.push_back(root);
}
}
char normalize_directory_separator(char in) {
if (in == '/') {
return DIR_SEPARATOR_CHAR;
}
return in;
}
void
add_mod_roots(SCP_vector<ModRoot>& mod_roots, const char* mod_cmdline, const SCP_string& rootDirectory, bool user_location) {
if (mod_cmdline) {
bool primary = true;
for (const char* cur_pos = mod_cmdline; strlen(cur_pos) != 0; cur_pos += (strlen(cur_pos) + 1)) {
SCP_stringstream ss;
ss << rootDirectory;
if (rootDirectory.back() != DIR_SEPARATOR_CHAR) {
ss << DIR_SEPARATOR_CHAR;
}
ss << cur_pos << DIR_SEPARATOR_STR;
SCP_string rootPath = ss.str();
// normalize the path to the native path format
std::transform(rootPath.begin(), rootPath.end(), rootPath.begin(), normalize_directory_separator);
ModRoot root;
root.type = ModRootType::Folder;
root.path = rootPath;
root.user_location = user_location;
if (primary) {
root.location_type = LocationType::PrimaryMod;
} else {
root.location_type = LocationType::SecondaryMod;
}
mod_roots.push_back(root);
build_pack_list(mod_roots, rootPath, root.location_type, user_location);
primary = false;
}
}
}
}
SCP_vector<ModRoot> getModRootsFromModCmdline(const SCP_string& content_root, const char* mod_cmdline) {
SCP_vector<ModRoot> mod_roots;
if (os_is_legacy_mode()) {
// =========================================================================
#ifdef WIN32
// Nothing to do here, Windows uses the current directory as the base
#else
add_mod_roots(mod_roots, mod_cmdline, os_get_legacy_user_dir(), true);
ModRoot root;
root.type = ModRootType::Folder;
root.path = os_get_legacy_user_dir();
root.user_location = true;
root.location_type = LocationType::GameRoot;
// do we already have a slash? as in the case of a root directory install
if (root.path.back() != DIR_SEPARATOR_CHAR) {
root.path += DIR_SEPARATOR_STR; // put trailing backslash on for easier path construction
}
mod_roots.push_back(root);
// Next, check any VP files under the current directory.
build_pack_list(mod_roots, root.path, root.location_type, root.user_location);
#endif
// =========================================================================
} else if (!Cmdline_portable_mode) {
// =========================================================================
// now look for mods under the users HOME directory to use before system ones
add_mod_roots(mod_roots, mod_cmdline, os_get_config_path(), true);
// =========================================================================
// =========================================================================
// set users HOME directory as default for loading and saving files
ModRoot root;
root.type = ModRootType::Folder;
root.path = os_get_config_path();
root.user_location = true;
root.location_type = LocationType::GameRoot;
// do we already have a slash? as in the case of a root directory install
if (root.path.back() != DIR_SEPARATOR_CHAR) {
root.path += DIR_SEPARATOR_STR; // put trailing backslash on for easier path construction
}
mod_roots.push_back(root);
// Next, check any VP files under the current directory.
build_pack_list(mod_roots, root.path, root.location_type, root.user_location);
// =========================================================================
}
add_mod_roots(mod_roots, mod_cmdline, content_root, false);
ModRoot root;
root.type = ModRootType::Folder;
root.path = content_root;
root.user_location = false;
root.location_type = LocationType::GameRoot;
// do we already have a slash? as in the case of a root directory install
if (root.path.back() != DIR_SEPARATOR_CHAR) {
root.path += DIR_SEPARATOR_STR; // put trailing backslash on for easier path construction
}
mod_roots.push_back(root);
//======================================================
// Next, check any VP files under the current directory.
build_pack_list(mod_roots, root.path, root.location_type, root.user_location);
return mod_roots;
}
}
-10
View File
@@ -1,10 +0,0 @@
#pragma once
#include "globalincs/pstypes.h"
#include "cfile/cfile.h"
namespace cfile {
SCP_vector<ModRoot> getModRootsFromModCmdline(const SCP_string& content_root, const char* mod_cmdline);
}
+360 -94
View File
@@ -160,113 +160,379 @@ cf_root *cf_create_root()
return &Root_blocks[block]->roots[offset];
}
static bool has_mod_location(const SCP_vector<cfile::ModRoot>& modRoots)
// return the # of packfiles which exist
int cf_get_packfile_count(cf_root *root)
{
for (const auto& root : modRoots)
SCP_string filespec;
int i;
int packfile_count;
// count up how many packfiles we're gonna have
packfile_count = 0;
for (i=CF_TYPE_ROOT; i<CF_MAX_PATH_TYPES; i++ )
{
if (root.location_type == cfile::LocationType::PrimaryMod)
filespec = root->path;
if(strlen(Pathtypes[i].path))
{
return true;
}
}
return false;
}
void cf_build_root_list(const SCP_vector<cfile::ModRoot>& modRoots)
{
Num_roots = 0;
Num_path_roots = 0;
auto has_mod = has_mod_location(modRoots);
mprintf(("CFile root configuration:\n"));
// Go through the roots specified and convert them to the internal data structure
for (const auto& root : modRoots)
{
if (root.path.size() >= CF_MAX_PATHNAME_LENGTH - 1)
{
Error(LOCATION, "Mod root path '%s' is longer than the maximum %d!", root.path.c_str(), CF_MAX_PATHNAME_LENGTH - 1);
return;
}
auto cfile_root = cf_create_root();
memset(cfile_root, 0, sizeof(*cfile_root));
strcpy_s(cfile_root->path, root.path.c_str());
if (root.user_location)
{
cfile_root->location_flags |= CF_LOCATION_ROOT_USER;
} else {
cfile_root->location_flags |= CF_LOCATION_ROOT_GAME;
}
if (root.location_type == cfile::LocationType::SecondaryMod)
{
cfile_root->location_flags |= CF_LOCATION_TYPE_SECONDARY_MODS;
} else if (root.location_type == cfile::LocationType::PrimaryMod)
{
cfile_root->location_flags |= CF_LOCATION_TYPE_PRIMARY_MOD;
} else if (root.location_type == cfile::LocationType::GameRoot)
{
cfile_root->location_flags |= CF_LOCATION_TYPE_ROOT;
if (!has_mod)
filespec += Pathtypes[ i ].path;
if ( filespec[ filespec.length( ) - 1 ] != DIR_SEPARATOR_CHAR )
{
// If we do not have a mod then game roots are also primary mods
cfile_root->location_flags |= CF_LOCATION_TYPE_PRIMARY_MOD;
}
} else {
UNREACHABLE("Unknown root location type!");
}
switch (root.type)
{
case cfile::ModRootType::Folder:
cfile_root->roottype = CF_ROOTTYPE_PATH;
break;
case cfile::ModRootType::Package:
cfile_root->roottype = CF_ROOTTYPE_PACK;
break;
default:
UNREACHABLE("Unknown root type!");
break;
}
if (root.type == cfile::ModRootType::Folder)
{
size_t path_len = strlen(cfile_root->path);
// do we already have a slash? as in the case of a root directory install
if ( (path_len < (CF_MAX_PATHNAME_LENGTH-1)) && (cfile_root->path[path_len-1] != DIR_SEPARATOR_CHAR) ) {
strcat_s(cfile_root->path, DIR_SEPARATOR_STR); // put trailing backslash on for easier path construction
filespec += DIR_SEPARATOR_STR;
}
}
#ifndef NDEBUG
switch (root.type)
{
case cfile::ModRootType::Folder:
mprintf((" Found root folder '%s'\n", root.path.c_str()));
break;
case cfile::ModRootType::Package: {
uint chksum = 0;
cf_chksum_pack(root.path.c_str(), &chksum);
mprintf((" Found root pack '%s' with a checksum of 0x%08x\n", root.path.c_str(), chksum));
break;
}
default:
UNREACHABLE("Unknown root type!");
break;
#if defined _WIN32
filespec += "*.vp";
intptr_t find_handle;
_finddata_t find;
find_handle = _findfirst( filespec.c_str( ), &find );
if (find_handle != -1) {
do {
if (!(find.attrib & _A_SUBDIR)) {
packfile_count++;
}
} while (!_findnext(find_handle, &find));
_findclose( find_handle );
}
#elif defined SCP_UNIX
filespec += "*.[vV][pP]";
glob_t globinfo;
memset(&globinfo, 0, sizeof(globinfo));
int status = glob(filespec.c_str( ), 0, NULL, &globinfo);
if (status == 0) {
for (unsigned int j = 0; j < globinfo.gl_pathc; j++) {
// Determine if this is a regular file
struct stat statbuf;
memset(&statbuf, 0, sizeof(statbuf));
stat(globinfo.gl_pathv[j], &statbuf);
if (S_ISREG(statbuf.st_mode)) {
packfile_count++;
}
}
globfree(&globinfo);
}
#endif
}
return packfile_count;
}
// packfile sort function
bool cf_packfile_sort_func(const cf_root_sort &r1, const cf_root_sort &r2)
{
// if the 2 directory types are the same, do a string compare
if (r1.cf_type == r2.cf_type) {
return (stricmp(r1.path, r2.path) < 0);
}
// otherwise return them in order of CF_TYPE_* precedence
return (r1.cf_type < r2.cf_type);
}
// Go through a root and look for pack files
void cf_build_pack_list( cf_root *root )
{
char filespec[MAX_PATH_LEN];
int i;
cf_root_sort *temp_roots_sort, *rptr_sort;
int temp_root_count, root_index;
// determine how many packfiles there are
temp_root_count = cf_get_packfile_count(root);
if (temp_root_count <= 0)
return;
// allocate a temporary array of temporary roots so we can easily sort them
temp_roots_sort = (cf_root_sort*)vm_malloc(sizeof(cf_root_sort) * temp_root_count);
if (temp_roots_sort == NULL) {
Int3();
return;
}
// now just setup all the root info
root_index = 0;
for (i = CF_TYPE_ROOT; i < CF_MAX_PATH_TYPES; i++) {
strcpy_s( filespec, root->path );
if ( strlen(Pathtypes[i].path) ) {
strcat_s( filespec, Pathtypes[i].path );
if ( filespec[strlen(filespec)-1] != DIR_SEPARATOR_CHAR )
strcat_s( filespec, DIR_SEPARATOR_STR );
}
#if defined _WIN32
strcat_s( filespec, "*.vp" );
intptr_t find_handle;
_finddata_t find;
find_handle = _findfirst( filespec, &find );
if (find_handle != -1) {
do {
// add the new item
if (!(find.attrib & _A_SUBDIR)) {
Assert(root_index < temp_root_count);
// get a temp pointer
rptr_sort = &temp_roots_sort[root_index++];
// fill in all the proper info
strcpy_s(rptr_sort->path, root->path);
if(strlen(Pathtypes[i].path)) {
strcat_s(rptr_sort->path, Pathtypes[i].path );
strcat_s(rptr_sort->path, DIR_SEPARATOR_STR);
}
strcat_s(rptr_sort->path, find.name );
rptr_sort->roottype = CF_ROOTTYPE_PACK;
rptr_sort->cf_type = i;
}
} while (!_findnext(find_handle, &find));
_findclose( find_handle );
}
#elif defined SCP_UNIX
strcat_s( filespec, "*.[vV][pP]" );
glob_t globinfo;
memset(&globinfo, 0, sizeof(globinfo));
int status = glob(filespec, 0, NULL, &globinfo);
if (status == 0) {
for (uint j = 0; j < globinfo.gl_pathc; j++) {
// Determine if this is a regular file
struct stat statbuf;
memset(&statbuf, 0, sizeof(statbuf));
stat(globinfo.gl_pathv[j], &statbuf);
if ( S_ISREG(statbuf.st_mode) ) {
Assert(root_index < temp_root_count);
// get a temp pointer
rptr_sort = &temp_roots_sort[root_index++];
// fill in all the proper info
strcpy_s(rptr_sort->path, globinfo.gl_pathv[j] );
rptr_sort->roottype = CF_ROOTTYPE_PACK;
rptr_sort->cf_type = i;
}
}
globfree(&globinfo);
}
#endif
}
// these should always be the same
Assert(root_index == temp_root_count);
// sort the roots
std::sort(temp_roots_sort, temp_roots_sort + temp_root_count, cf_packfile_sort_func);
// now insert them all into the real root list properly
for (i = 0; i < temp_root_count; i++) {
auto new_root = cf_create_root();
new_root->location_flags = root->location_flags;
strcpy_s( new_root->path, root->path );
#ifndef NDEBUG
uint chksum = 0;
cf_chksum_pack(temp_roots_sort[i].path, &chksum);
mprintf(("Found root pack '%s' with a checksum of 0x%08x\n", temp_roots_sort[i].path, chksum));
#endif
// mwa -- 4/2/98 put in the next 2 lines because the path name needs to be there
// to find the files.
strcpy_s(new_root->path, temp_roots_sort[i].path);
new_root->roottype = CF_ROOTTYPE_PACK;
}
// free up the temp list
vm_free(temp_roots_sort);
}
static char normalize_directory_separator(char in)
{
if (in == '/')
{
return DIR_SEPARATOR_CHAR;
}
return in;
}
static void cf_add_mod_roots(const char* rootDirectory, uint32_t basic_location)
{
if (Cmdline_mod)
{
bool primary = true;
for (const char* cur_pos=Cmdline_mod; strlen(cur_pos) != 0; cur_pos+= (strlen(cur_pos)+1))
{
SCP_stringstream ss;
ss << rootDirectory;
if (rootDirectory[strlen(rootDirectory) - 1] != DIR_SEPARATOR_CHAR)
{
ss << DIR_SEPARATOR_CHAR;
}
ss << cur_pos << DIR_SEPARATOR_STR;
SCP_string rootPath = ss.str();
if (rootPath.size() + 1 >= CF_MAX_PATHNAME_LENGTH) {
Error(LOCATION, "The length of mod directory path '%s' exceeds the maximum of %d!\n", rootPath.c_str(), CF_MAX_PATHNAME_LENGTH);
}
// normalize the path to the native path format
std::transform(rootPath.begin(), rootPath.end(), rootPath.begin(), normalize_directory_separator);
cf_root* root = cf_create_root();
strncpy(root->path, rootPath.c_str(), CF_MAX_PATHNAME_LENGTH-1);
if (primary) {
root->location_flags = basic_location | CF_LOCATION_TYPE_PRIMARY_MOD;
} else {
root->location_flags = basic_location | CF_LOCATION_TYPE_SECONDARY_MODS;
}
root->roottype = CF_ROOTTYPE_PATH;
cf_build_pack_list(root);
primary = false;
}
}
}
void cf_build_root_list(const char *cdrom_dir)
{
Num_roots = 0;
Num_path_roots = 0;
cf_root *root = nullptr;
if (os_is_legacy_mode())
{
// =========================================================================
#ifdef WIN32
// Nothing to do here, Windows uses the current directory as the base
#else
cf_add_mod_roots(os_get_legacy_user_dir(), CF_LOCATION_ROOT_USER);
root = cf_create_root();
strncpy(root->path, os_get_legacy_user_dir(), CF_MAX_PATHNAME_LENGTH - 1);
root->location_flags |= CF_LOCATION_ROOT_USER | CF_LOCATION_TYPE_ROOT;
if (Cmdline_mod == nullptr || strlen(Cmdline_mod) <= 0) {
// If there are no mods then the root is the primary mod
root->location_flags |= CF_LOCATION_TYPE_PRIMARY_MOD;
}
// do we already have a slash? as in the case of a root directory install
if ((strlen(root->path) < (CF_MAX_PATHNAME_LENGTH - 1)) && (root->path[strlen(root->path) - 1] != DIR_SEPARATOR_CHAR)) {
strcat_s(root->path, DIR_SEPARATOR_STR); // put trailing backslash on for easier path construction
}
root->roottype = CF_ROOTTYPE_PATH;
// Next, check any VP files under the current directory.
cf_build_pack_list(root);
#endif
// =========================================================================
}
else if (!Cmdline_portable_mode)
{
// =========================================================================
// now look for mods under the users HOME directory to use before system ones
cf_add_mod_roots(Cfile_user_dir, CF_LOCATION_ROOT_USER);
// =========================================================================
// =========================================================================
// set users HOME directory as default for loading and saving files
root = cf_create_root();
strcpy_s(root->path, Cfile_user_dir);
root->location_flags |= CF_LOCATION_ROOT_USER | CF_LOCATION_TYPE_ROOT;
if (Cmdline_mod == nullptr || strlen(Cmdline_mod) <= 0) {
// If there are no mods then the root is the primary mod
root->location_flags |= CF_LOCATION_TYPE_PRIMARY_MOD;
}
// do we already have a slash? as in the case of a root directory install
if ((strlen(root->path) < (CF_MAX_PATHNAME_LENGTH - 1)) && (root->path[strlen(root->path) - 1] != DIR_SEPARATOR_CHAR)) {
strcat_s(root->path, DIR_SEPARATOR_STR); // put trailing backslash on for easier path construction
}
root->roottype = CF_ROOTTYPE_PATH;
// Next, check any VP files under the current directory.
cf_build_pack_list(root);
// =========================================================================
}
char working_directory[CF_MAX_PATHNAME_LENGTH];
if ( !_getcwd(working_directory, CF_MAX_PATHNAME_LENGTH ) ) {
Error(LOCATION, "Can't get current working directory -- %d", errno );
}
cf_add_mod_roots(working_directory, CF_LOCATION_ROOT_GAME);
root = cf_create_root();
root->location_flags |= CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT;
if (Cmdline_mod == nullptr || strlen(Cmdline_mod) <= 0) {
// If there are no mods then the root is the primary mod
root->location_flags |= CF_LOCATION_TYPE_PRIMARY_MOD;
}
strcpy_s(root->path, working_directory);
size_t path_len = strlen(root->path);
// do we already have a slash? as in the case of a root directory install
if ( (path_len < (CF_MAX_PATHNAME_LENGTH-1)) && (root->path[path_len-1] != DIR_SEPARATOR_CHAR) ) {
strcat_s(root->path, DIR_SEPARATOR_STR); // put trailing backslash on for easier path construction
}
root->roottype = CF_ROOTTYPE_PATH;
//======================================================
// Next, check any VP files under the current directory.
cf_build_pack_list(root);
//======================================================
// Check the real CD if one...
if ( cdrom_dir && (strlen(cdrom_dir) < CF_MAX_PATHNAME_LENGTH) ) {
root = cf_create_root();
strcpy_s( root->path, cdrom_dir );
root->roottype = CF_ROOTTYPE_PATH;
//======================================================
// Next, check any VP files in the CD-ROM directory.
cf_build_pack_list(root);
}
// The final root is the in-memory root
auto root = cf_create_root();
root = cf_create_root();
root->location_flags = CF_LOCATION_ROOT_MEMORY | CF_LOCATION_TYPE_ROOT;
memset(root->path, 0, sizeof(root->path));
root->roottype = CF_ROOTTYPE_MEMORY;
}
// Given a lower case list of file extensions
@@ -657,7 +923,7 @@ void cf_build_file_list()
}
void cf_build_secondary_filelist(const SCP_vector<cfile::ModRoot>& modRoots)
void cf_build_secondary_filelist(const char *cdrom_dir)
{
int i;
@@ -678,7 +944,7 @@ void cf_build_secondary_filelist(const SCP_vector<cfile::ModRoot>& modRoots)
mprintf(( "Building file index...\n" ));
// build the list of searchable roots
cf_build_root_list(modRoots);
cf_build_root_list(cdrom_dir);
// build the list of files themselves
cf_build_file_list();
+1 -1
View File
@@ -15,7 +15,7 @@
#include "cfile/cfile.h"
// Builds a list of all the files
void cf_build_secondary_filelist(const SCP_vector<cfile::ModRoot>& modRoots);
void cf_build_secondary_filelist( const char *cdrom_path );
void cf_free_secondary_filelist();
// Internal stuff
+210 -394
View File
@@ -5,27 +5,27 @@
* or otherwise commercially exploit the source or things you created based on the
* source.
*
*/
*/
#include "cmdline/cmdline.h"
#include "camera/camera.h" //VIEWER_ZOOM_DEFAULT
#include "cfile/cfilesystem.h"
#include "fireball/fireballs.h"
#include "cmdline/cmdline.h"
#include "globalincs/linklist.h"
#include "globalincs/pstypes.h"
#include "globalincs/systemvars.h"
#include "globalincs/version.h"
#include "graphics/shadows.h"
#include "hud/hudconfig.h"
#include "io/joy.h"
#include "network/multi.h"
#include "options/OptionsManager.h"
#include "osapi/osapi.h"
#include "parse/sexp.h"
#include "scripting/scripting.h"
#include "sound/openal.h"
#include "parse/sexp.h"
#include "globalincs/version.h"
#include "globalincs/pstypes.h"
#include "osapi/osapi.h"
#include "cfile/cfilesystem.h"
#include "sound/speech.h"
#include "starfield/starfield.h"
#include "sound/openal.h"
#include "io/joy.h"
#ifdef _WIN32
#include <io.h>
@@ -34,9 +34,6 @@
#include <CoreFoundation/CoreFoundation.h>
#endif
#include "cfile/cfile.h"
#include "cfile/cfilemod.h"
#ifdef SCP_UNIX
#include "osapi/osapi.h"
#include <dirent.h>
@@ -74,36 +71,23 @@ enum class flag_output_type {
Json_V1,
};
enum class flag_input_type {
Flags,
Stdin_Json_V1,
};
// variables
class cmdline_parm {
public:
cmdline_parm *next = nullptr, *prev = nullptr;
const char* name; // name of parameter, must start with '-' char
const char* help; // help text for this parameter
const bool stacks; // whether this arg stacks with each use or is replaced by newest use (should only be used for
// strings!!)
SCP_string args; // string value for parameter arguments (empty if no arguments)
bool name_found; // true if parameter on command line, otherwise false
const int arg_type; // from enum cmdline_arg_type; used for help
cmdline_parm *next, *prev;
const char *name; // name of parameter, must start with '-' char
const char *help; // help text for this parameter
const bool stacks; // whether this arg stacks with each use or is replaced by newest use (should only be used for strings!!)
char *args; // string value for parameter arguments (NULL if no arguments)
int name_found; // true if parameter on command line, otherwise false
const int arg_type; // from enum cmdline_arg_type; used for help
cmdline_parm(const char* name, const char* help, const int arg_type, const bool stacks = false) noexcept;
~cmdline_parm() noexcept;
cmdline_parm(const cmdline_parm& other) = delete;
cmdline_parm& operator=(const cmdline_parm& other) = delete;
cmdline_parm(cmdline_parm&& other) = delete;
cmdline_parm& operator=(cmdline_parm&& other) = delete;
bool found();
cmdline_parm(const char *name, const char *help, const int arg_type, const bool stacks = false);
~cmdline_parm();
int found();
int get_int();
float get_float();
SCP_string str();
char *str();
bool check_if_args_is_valid();
bool has_param();
};
@@ -291,11 +275,11 @@ cmdline_parm mouse_coords("-coords", NULL, AT_NONE); // Cmdline_mouse_coords
cmdline_parm timeout("-timeout", "Multiplayer network timeout (secs)", AT_INT); // Cmdline_timeout
cmdline_parm bit32_arg("-32bit", "Deprecated", AT_NONE); // (only here for retail compatibility reasons, doesn't actually do anything)
SCP_string Cmdline_connect_addr;
SCP_string Cmdline_game_name;
SCP_string Cmdline_game_password;
SCP_string Cmdline_rank_above;
SCP_string Cmdline_rank_below;
char *Cmdline_connect_addr = NULL;
char *Cmdline_game_name = NULL;
char *Cmdline_game_password = NULL;
char *Cmdline_rank_above = NULL;
char *Cmdline_rank_below = NULL;
int Cmdline_cd_check = 1;
int Cmdline_client_dodamage = 0;
int Cmdline_closed_game = 0;
@@ -347,11 +331,13 @@ cmdline_parm no_deferred_lighting_arg("-no_deferred", NULL, AT_NONE); // Cmdline
cmdline_parm anisotropy_level_arg("-anisotropic_filter", NULL, AT_INT);
float Cmdline_clip_dist = Default_min_draw_distance;
float Cmdline_fov = 0.75f;
float Cmdline_ogl_spec = 80.0f;
int Cmdline_ambient_factor = 128;
int Cmdline_env = 1;
int Cmdline_mipmap = 0;
int Cmdline_glow = 1;
int Cmdline_nomotiondebris = 0;
int Cmdline_noscalevid = 0;
int Cmdline_spec = 1;
int Cmdline_no_emissive = 0;
@@ -359,8 +345,15 @@ int Cmdline_normal = 1;
int Cmdline_height = 1;
int Cmdline_enable_3d_shockwave = 0;
int Cmdline_softparticles = 0;
int Cmdline_postprocess = 0;
int Cmdline_bloom_intensity = 75;
bool Cmdline_fxaa = false;
int Cmdline_fxaa_preset = 6;
extern int Fxaa_preset_last_frame;
bool Cmdline_fb_explosions = 0;
bool Cmdline_fb_thrusters = false;
extern bool ls_force_off;
int Cmdline_shadow_quality = 0;
int Cmdline_no_deferred_lighting = 0;
int Cmdline_aniso_level = 0;
@@ -408,7 +401,7 @@ int Cmdline_no_enhanced_sound = 0;
// MOD related
cmdline_parm mod_arg("-mod", "List of folders to overwrite/add-to the default data", AT_STRING, true); // Cmdline_mod -- DTP modsupport
SCP_vector<cfile::ModRoot> Cmdline_mod; // DTP for mod argument
char *Cmdline_mod = NULL; //DTP for mod argument
// Multiplayer/Network related
cmdline_parm almission_arg("-almission", "Autoload multiplayer mission", AT_STRING); // Cmdline_almission -- DTP for autoload Multi mission
@@ -418,19 +411,15 @@ cmdline_parm missioncrcspew_arg("-missioncrcs", NULL, AT_STRING); // Cmdline_sp
cmdline_parm tablecrcspew_arg("-tablecrcs", NULL, AT_STRING); // Cmdline_spew_table_crcs
cmdline_parm objupd_arg("-cap_object_update", "Multiplayer object update cap (0-3)", AT_INT);
SCP_string Cmdline_almission; // DTP for autoload multi mission.
char *Cmdline_almission = NULL; //DTP for autoload multi mission.
int Cmdline_ingamejoin = 0;
int Cmdline_mpnoreturn = 0;
SCP_string Cmdline_spew_mission_crcs;
SCP_string Cmdline_spew_table_crcs;
char *Cmdline_spew_mission_crcs = NULL;
char *Cmdline_spew_table_crcs = NULL;
int Cmdline_objupd = 3; // client object updates on LAN by default
// Launcher related options
cmdline_parm portable_mode("-portable_mode", NULL, AT_NONE);
cmdline_parm
stdin_flags("-stdin_flags",
"Tells FSO to read flags from stdin. Parameter is format if data supplied. Possible values: json_v1",
AT_STRING);
bool Cmdline_portable_mode = false;
@@ -462,7 +451,7 @@ int Cmdline_no_pbo = 0;
int Cmdline_ati_color_swap = 0;
int Cmdline_no_3d_sound = 0;
int Cmdline_drawelements = 0;
SCP_string Cmdline_keyboard_layout;
char* Cmdline_keyboard_layout = NULL;
bool Cmdline_gl_finish = false;
bool Cmdline_no_geo_sdr_effects = false;
bool Cmdline_set_cpu_affinity = false;
@@ -499,7 +488,8 @@ cmdline_parm show_video_info("-show_video_info", NULL, AT_NONE); //Cmdline_show_
cmdline_parm frame_profile_arg("-profile_frame_time", NULL, AT_NONE); //Cmdline_frame_profile
cmdline_parm debug_window_arg("-debug_window", NULL, AT_NONE); // Cmdline_debug_window
SCP_string Cmdline_start_mission;
char *Cmdline_start_mission = NULL;
int Cmdline_dis_collisions = 0;
int Cmdline_dis_weapons = 0;
bool Cmdline_output_sexp_info = false;
@@ -514,8 +504,8 @@ int Cmdline_show_stats = 0;
int Cmdline_save_render_targets = 0;
int Cmdline_window = 0;
int Cmdline_fullscreen_window = 0;
SCP_string Cmdline_res;
SCP_string Cmdline_center_res;
char *Cmdline_res = 0;
char *Cmdline_center_res = 0;
int Cmdline_verify_vps = 0;
int Cmdline_reparse_mainhall = 0;
bool Cmdline_profile_write_file = false;
@@ -566,8 +556,8 @@ void cmdline_debug_print_cmdline()
for (parmp = GET_FIRST(&Parm_list); parmp !=END_OF_LIST(&Parm_list); parmp = GET_NEXT(parmp) ) {
if ( parmp->name_found ) {
if (!parmp->args.empty()) {
mprintf(("\n %s %s", parmp->name, parmp->args.c_str()));
if ( parmp->args != NULL ) {
mprintf(("\n %s %s", parmp->name, parmp->args));
} else {
mprintf(("\n %s", parmp->name));
}
@@ -673,13 +663,14 @@ char *drop_extra_chars(char *str)
return str;
}
/*
* @brief Processes one argument for the given parameter
*
* @param param The parameter to check
* @param argc The argument count
* @param argv The argument values
* @param index The current index
* @param argc The argument values
* @param argc The current index
* @return @c true when an extra parameter was found, @c false otherwise
*/
bool parm_stuff_args(cmdline_parm *parm, int argc, char *argv[], int index)
@@ -696,17 +687,47 @@ bool parm_stuff_args(cmdline_parm *parm, int argc, char *argv[], int index)
}
else
{
if (parm->stacks) {
if (!parm->args.empty())
{
// Avoid adding the , at the start
parm->args += ",";
char* saved_args = NULL;
if (parm->args != NULL) {
if (parm->stacks) {
saved_args = parm->args;
}
parm->args += argv[index + 1];
else {
delete[] parm->args;
}
parm->args = NULL;
}
size_t argsize = strlen(argv[index + 1]);
size_t buffersize = argsize;
if (saved_args != NULL)
{
// Add one for the , separating args
buffersize += strlen(saved_args) + 1;
}
buffersize += 1; // Null-terminator
parm->args = new char[buffersize];
memset(parm->args, 0, buffersize);
if (saved_args != NULL)
{
// saved args go first, then new arg
strcpy_s(parm->args, buffersize, saved_args);
// add a separator too, so that we can tell the args apart
strcat_s(parm->args, buffersize, ",");
// now the new arg
strcat_s(parm->args, buffersize, argv[index + 1]);
delete[] saved_args;
}
else
{
parm->args = argv[index + 1];
strcpy_s(parm->args, buffersize, argv[index + 1]);
}
return true;
@@ -738,7 +759,7 @@ void os_parse_parms(int argc, char *argv[])
for (parmp = GET_FIRST(&Parm_list); parmp != END_OF_LIST(&Parm_list); parmp = GET_NEXT(parmp)) {
if (!stricmp(parmp->name, argv[i]))
{
parmp->name_found = true;
parmp->name_found = 1;
if (parm_stuff_args(parmp, argc, argv, i))
{
i++;
@@ -919,8 +940,11 @@ bool has_cmdline_only_flag(int argc, char *argv[])
static void reset_cmdline_parms()
{
for (cmdline_parm *parmp = GET_FIRST(&Parm_list); parmp != END_OF_LIST(&Parm_list); parmp = GET_NEXT(parmp)) {
parmp->args.clear();
parmp->name_found = false;
if (parmp->args != NULL) {
delete[] parmp->args;
parmp->args = NULL;
}
parmp->name_found = 0;
}
}
@@ -1016,14 +1040,11 @@ void os_init_cmdline(int argc, char *argv[])
* @param arg_type_ parameters arguement type (if any)
* @param stacks_ can the parameter be stacked
*/
cmdline_parm::cmdline_parm(const char* name_, const char* help_, const int arg_type_, const bool stacks_) noexcept
: name(name_), help(help_), stacks(stacks_), arg_type(arg_type_)
cmdline_parm::cmdline_parm(const char *name_, const char *help_, const int arg_type_, const bool stacks_):
name(name_), help(help_), stacks(stacks_), arg_type(arg_type_)
{
if (stacks) {
Assertion(arg_type == AT_STRING, "Only string arguments can stack!");
}
name_found = false;
args = NULL;
name_found = 0;
if (Parm_list_inited == 0) {
Assertion(&Parm_list == this, "Coding error! 1st initialised cmdline_parm must be static Parm_list\n");
@@ -1042,12 +1063,20 @@ cmdline_parm::cmdline_parm(const char* name_, const char* help_, const int arg_t
// destructor - frees any allocated memory
cmdline_parm::~cmdline_parm() noexcept = default;
cmdline_parm::~cmdline_parm()
{
#ifndef FRED
if (args) {
delete [] args;
args = NULL;
}
#endif
}
// checks if the objects args variable is valid
// returns true if it is, shows an error box and returns false if not valid.
bool cmdline_parm::check_if_args_is_valid() {
if (args.empty()) {
if ( args == NULL ) {
Error(__FILE__, __LINE__,
"Command line flag passed that requires an argument, but the argument is missing!\r\n"
"The flag is '%s', make sure that you have an argument that follows it.\r\n"
@@ -1061,7 +1090,10 @@ bool cmdline_parm::check_if_args_is_valid() {
// returns - true if the parameter exists on the command line, otherwise false
bool cmdline_parm::found() { return name_found; }
int cmdline_parm::found()
{
return name_found;
}
// returns - the interger representation for the parameter argument
int cmdline_parm::get_int()
@@ -1069,12 +1101,22 @@ int cmdline_parm::get_int()
Assertion(arg_type == AT_INT, "Coding error! Cmdline arg (%s) called cmdline_parm::get_int() with invalid arg_type (%s)", name, cmdline_arg_types[arg_type]);
check_if_args_is_valid();
try {
return std::stoi(args);
} catch (const std::exception& e) {
Warning(LOCATION, "Failed to convert '%s' to a float for parameter '%s'!", args.c_str(), name);
return 0;
size_t offset = 0;
if (stacks) {
// first off, DON'T STACK NON-STRINGS!!
Int3();
// secondly, we still need to get it right for the user's sake...
char *moron = strstr(args, ",");
if ( moron && ((strlen(moron) + 1) < strlen(args)) ) {
// we get the last arg, since it's the newest one
offset = strlen(args) - strlen(moron) + 1;
}
}
return atoi(args+offset);
}
@@ -1084,24 +1126,36 @@ float cmdline_parm::get_float()
Assertion(arg_type == AT_FLOAT, "Coding error! Cmdline arg (%s) called cmdline_parm::get_float() with invalid arg_type (%s)", name, cmdline_arg_types[arg_type]);
check_if_args_is_valid();
try {
return std::stof(args);
} catch (const std::exception& e) {
Warning(LOCATION, "Failed to convert '%s' to a float for parameter '%s'!", args.c_str(), name);
return 0.0f;
size_t offset = 0;
if (stacks) {
// first off, DON'T STACK NON-STRINGS!!
Int3();
// secondly, we still need to get it right for the user's sake
char *moron = strstr(args, ",");
if ( moron && ((strlen(moron) + 1) < strlen(args)) ) {
// we get the last arg, since it's the newest one
offset = strlen(args) - strlen(moron) + 1;
}
}
return (float)atof(args+offset);
}
// returns - the string value for the parameter argument
SCP_string cmdline_parm::str()
char *cmdline_parm::str()
{
Assertion(arg_type == AT_STRING, "Coding error! Cmdline arg (%s) called cmdline_parm::str() with invalid arg_type (%s)", name, cmdline_arg_types[arg_type]);
check_if_args_is_valid();
return args;
}
bool cmdline_parm::has_param() { return !args.empty(); }
bool cmdline_parm::has_param() {
return args != nullptr;
}
#ifdef SCP_UNIX
// Return a vector with all filesystem names of "parent/dir" relative to parent.
@@ -1162,31 +1216,39 @@ static SCP_vector<SCP_string> unix_get_dir_names(const SCP_string& parent, const
}
// For case sensitive filesystems (e.g. Linux/BSD) perform case-insensitive dir matches.
static SCP_string handle_unix_modlist(const SCP_string& modlist)
static void handle_unix_modlist(char **modlist, size_t *len)
{
// search filesystem for given paths
SCP_vector<SCP_string> mod_paths;
SCP_stringstream iss(modlist);
SCP_string cur_mod;
while (std::getline(iss, cur_mod, ',')) {
for (char *cur_mod = strtok(*modlist, ","); cur_mod != NULL; cur_mod = strtok(NULL, ","))
{
SCP_vector<SCP_string> this_mod_paths = unix_get_dir_names(".", cur_mod);
// Ignore non-existing mods for unit tests
if (!running_unittests && this_mod_paths.empty()) {
ReleaseWarning(LOCATION, "Can't find mod '%s'. Ignoring.", cur_mod.c_str());
ReleaseWarning(LOCATION, "Can't find mod '%s'. Ignoring.", cur_mod);
}
mod_paths.insert(mod_paths.end(), this_mod_paths.begin(), this_mod_paths.end());
}
// create new string to replace modlist
SCP_string new_modlist;
for (const auto& path : mod_paths) {
new_modlist += path;
new_modlist += ","; // replace later with NUL
// create new char[] to replace modlist
size_t total_len = 0;
SCP_vector<SCP_string>::iterator ii, end = mod_paths.end();
for (ii = mod_paths.begin(); ii != end; ++ii) {
total_len += ii->length() + 1;
}
char *new_modlist = new char[total_len + 1];
memset(new_modlist, 0, total_len + 1);
end = mod_paths.end();
for (ii = mod_paths.begin(); ii != end; ++ii) {
strcat_s(new_modlist, total_len + 1, ii->c_str());
strcat_s(new_modlist, total_len + 1, ","); // replace later with NUL
}
// make the rest of the modlist manipulation unaware that anything happened here
return new_modlist;
delete [] *modlist;
*modlist = new_modlist;
*len = total_len;
}
#endif /* SCP_UNIX */
@@ -1244,7 +1306,6 @@ static json_t* json_get_v1() {
json_array_append_new(caps_array, json_string("No D3D"));
json_array_append_new(caps_array, json_string("New Sound"));
json_array_append_new(caps_array, json_string("SDL"));
json_array_append_new(caps_array, json_string("Stdin Flags: Json V1"));
json_object_set_new(root, "caps", caps_array);
}
@@ -1435,218 +1496,16 @@ static void write_flags() {
case flag_output_type::Binary:
write_flags_file();
break;
case flag_output_type::Json_V1: {
case flag_output_type::Json_V1:
json_t* root = json_get_v1();
json_dumpf(root, stdout, JSON_INDENT(4));
json_decref(root);
break;
}
}
}
static bool validate_version(json_t* rootEl)
{
const auto version_el = json_object_get(rootEl, "version");
if (version_el == nullptr) {
printf("Version element is missing!\n");
return false;
}
if (!json_is_number(version_el)) {
printf("Version value is not a number!\n");
return false;
}
if (json_integer_value(version_el) != 1) {
printf("Version value %" JSON_INTEGER_FORMAT " is not supported!\n", json_integer_value(version_el));
return false;
}
return true;
}
static cfile::ModRootType mapModRootType(const char* rootStr) {
if (!stricmp(rootStr, "folder")) {
return cfile::ModRootType::Folder;
} else if (!stricmp(rootStr, "package")) {
return cfile::ModRootType::Package;
} else {
return cfile::ModRootType::Unknown;
}
}
static cfile::LocationType mapLocationType(const char* rootStr) {
if (!stricmp(rootStr, "game_root")) {
return cfile::LocationType::GameRoot;
} else if (!stricmp(rootStr, "primary_mod")) {
return cfile::LocationType::PrimaryMod;
} else if (!stricmp(rootStr, "secondary_mod")) {
return cfile::LocationType::SecondaryMod;
} else {
return cfile::LocationType::Unknown;
}
}
static void stuff_mod_option(cmdline_parm* param, json_t* el)
{
if (!json_is_array(el))
{
printf("Value for option %s must be an array!", param->name);
return;
}
SCP_vector<cfile::ModRoot> roots;
size_t i;
json_t* modObj;
json_array_foreach(el, i, modObj)
{
const auto typeEl = json_object_get(modObj, "type");
const auto pathEl = json_object_get(modObj, "path");
const auto locationEl = json_object_get(modObj, "location_type");
if (typeEl == nullptr || pathEl == nullptr || locationEl == nullptr)
{
printf("A required mod root element is missing: Type %p, Path %p, Location %p", typeEl, pathEl, locationEl);
continue;
}
if (!json_is_string(typeEl) || !json_is_string(pathEl) || !json_is_string(locationEl))
{
printf("An element had a wrong type: Type %d, Path %d, Location %d", json_typeof(typeEl), json_typeof(pathEl), json_typeof(locationEl));
continue;
}
const auto userEl = json_object_get(modObj, "user");
if (userEl != nullptr && !json_is_boolean(userEl))
{
printf("User element type is not a boolean!");
continue;
}
cfile::ModRoot root;
root.type = mapModRootType(json_string_value(typeEl));
root.path = json_string_value(pathEl);
root.location_type = mapLocationType(json_string_value(locationEl));
root.user_location = userEl == nullptr ? false : json_boolean_value(userEl);
roots.push_back(root);
}
Cmdline_mod = roots;
}
static void stuff_json_option(cmdline_parm* param, json_t* el)
{
if (param == &mod_arg)
{
// The -mod parameter is handled specially since it is not a simple string
stuff_mod_option(param, el);
return;
}
switch (param->arg_type) {
case AT_NONE:
if (!json_is_boolean(el)) {
printf("Value for option %s must be a boolean!", param->name);
return;
}
param->name_found = json_is_true(el);
break;
case AT_INT:
if (!json_is_number(el)) {
printf("Value for option %s must be a number!", param->name);
return;
}
param->name_found = true;
param->args = std::to_string(json_integer_value(el));
break;
case AT_FLOAT:
if (!json_is_number(el)) {
printf("Value for option %s must be a number!", param->name);
return;
}
param->name_found = true;
param->args = std::to_string(json_real_value(el));
break;
case AT_STRING:
if (!json_is_string(el)) {
printf("Value for option %s must be a string!", param->name);
return;
}
param->name_found = true;
param->args.assign(json_string_value(el), json_string_length(el));
break;
default:
UNREACHABLE("Unknown arg type %d.", param->arg_type);
return;
}
}
static bool parse_json_flags(json_t* rootEl)
{
if (!json_is_object(rootEl)) {
printf("Root element must be an object!\n");
return false;
}
if (!validate_version(rootEl)) {
return false;
}
const auto flagsEl = json_object_get(rootEl, "flags");
if (flagsEl == nullptr) {
printf("Flags element is missing!\n");
return false;
}
if (!json_is_object(flagsEl)) {
printf("Flags element is not an object!\n");
return false;
}
const char* flagName;
json_t* flagValue;
json_object_foreach(flagsEl, flagName, flagValue)
{
for (auto parmp = GET_FIRST(&Parm_list); parmp != END_OF_LIST(&Parm_list); parmp = GET_NEXT(parmp)) {
if (!stricmp(parmp->name, flagName)) {
stuff_json_option(parmp, flagValue);
}
}
}
return true;
}
static bool SetCmdlineParams(flag_input_type inputType);
static bool SetCmdlineParamsFromStdin(const SCP_string& format)
{
if (format != "json_v1") {
// Invalid format!
printf("INPUT TYPE '%s' IS NOT SUPPORTED!\n", format.c_str());
return false;
}
json_error_t error;
json_t* flagsEl = json_loadf(stdin, JSON_DISABLE_EOF_CHECK, &error);
if (flagsEl == nullptr) {
printf("Failed to parse JSON: %s(%d:%d): %s\n", error.source, error.line, error.column, error.text);
return false;
}
if (!parse_json_flags(flagsEl)) {
return false;
}
return SetCmdlineParams(flag_input_type::Stdin_Json_V1);
}
static bool SetCmdlineParams(flag_input_type inputType)
bool SetCmdlineParams()
// Sets externed variables used for communication cmdline information
{
//getcwd(FreeSpace_Directory, 256); // set the directory to our fs2 root
@@ -1658,10 +1517,6 @@ static bool SetCmdlineParams(flag_input_type inputType)
return false;
}
if (inputType == flag_input_type::Flags && stdin_flags.found()) {
return SetCmdlineParamsFromStdin(stdin_flags.str());
}
if (no_fpscap.found())
{
Cmdline_NoFPSCap = 1;
@@ -1693,8 +1548,8 @@ static bool SetCmdlineParams(flag_input_type inputType)
Cmdline_spew_mission_crcs = missioncrcspew_arg.str();
// strip off blank space at end if it's there
if (Cmdline_spew_mission_crcs.back() == ' ') {
Cmdline_spew_mission_crcs.resize(Cmdline_spew_mission_crcs.size() - 1);
if ( Cmdline_spew_mission_crcs[strlen(Cmdline_spew_mission_crcs)-1] == ' ' ) {
Cmdline_spew_mission_crcs[strlen(Cmdline_spew_mission_crcs)-1] = '\0';
}
}
@@ -1702,8 +1557,8 @@ static bool SetCmdlineParams(flag_input_type inputType)
Cmdline_spew_table_crcs = tablecrcspew_arg.str();
// strip off blank space at end if it's there
if (Cmdline_spew_table_crcs.back() == ' ') {
Cmdline_spew_table_crcs.resize(Cmdline_spew_table_crcs.size() - 1);
if ( Cmdline_spew_table_crcs[strlen(Cmdline_spew_table_crcs)-1] == ' ' ) {
Cmdline_spew_table_crcs[strlen(Cmdline_spew_table_crcs)-1] = '\0';
}
}
@@ -1769,8 +1624,8 @@ static bool SetCmdlineParams(flag_input_type inputType)
Cmdline_game_name = gamename_arg.str();
// be sure that this string fits in our limits
if (Cmdline_game_name.size() > MAX_GAMENAME_LEN - 1) {
Cmdline_game_name.resize(MAX_GAMENAME_LEN - 1);
if ( strlen(Cmdline_game_name) > MAX_GAMENAME_LEN ) {
Cmdline_game_name[MAX_GAMENAME_LEN-1] = '\0';
}
}
@@ -1779,8 +1634,8 @@ static bool SetCmdlineParams(flag_input_type inputType)
Cmdline_game_password = gamepassword_arg.str();
// be sure that this string fits in our limits
if (Cmdline_game_password.size() > MAX_GAMENAME_LEN - 1) {
Cmdline_game_password.resize(MAX_GAMENAME_LEN - 1);
if ( strlen(Cmdline_game_name) > MAX_PASSWD_LEN ) {
Cmdline_game_name[MAX_PASSWD_LEN-1] = '\0';
}
}
@@ -1830,33 +1685,18 @@ static bool SetCmdlineParams(flag_input_type inputType)
}
// d3d windowed
if(window_arg.found()) {
// We need to set both values since we don't know if we are going to use the new config system
options::OptionsManager::instance()->setOverride("Graphics.WindowMode", "0");
if(window_arg.found()){
Cmdline_window = 1;
}
if ( fullscreen_window_arg.found( ) )
{
options::OptionsManager::instance()->setOverride("Graphics.WindowMode", "1");
Cmdline_fullscreen_window = 1;
Cmdline_window = 0; /* Make sure no-one sets both */
}
if(res_arg.found()){
Cmdline_res = res_arg.str();
int width = 0;
int height = 0;
if (sscanf(Cmdline_res.c_str(), "%dx%d", &width, &height) == 2) {
SCP_string override;
sprintf(override, R"({"width":%d,"height":%d})", width, height);
options::OptionsManager::instance()->setOverride("Graphics.Resolution", override);
} else {
mprintf(("Failed to parse -res parameter \"%s\". Must be in format \"<width>x<height>\".",
Cmdline_res.c_str()));
}
}
if(center_res_arg.found()){
Cmdline_center_res = center_res_arg.str();
@@ -1888,32 +1728,35 @@ static bool SetCmdlineParams(flag_input_type inputType)
Cmdline_noparseerrors = 1;
}
// Legacy mod handling is handled here
if (inputType == flag_input_type::Flags && mod_arg.found()) {
auto modCmdline = mod_arg.str();
if(mod_arg.found() ) {
Cmdline_mod = mod_arg.str();
// strip off blank space it it's there
if (modCmdline.back() == ' ') {
modCmdline.resize(modCmdline.size() - 1);
if ( Cmdline_mod[strlen(Cmdline_mod)-1] == ' ' ) {
Cmdline_mod[strlen(Cmdline_mod)-1] = '\0';
}
// Ok - mod stacking support
size_t len = strlen(Cmdline_mod);
char *modlist = new char[len+2];
memset( modlist, 0, len + 2 );
strcpy_s(modlist, len+2, Cmdline_mod);
#ifdef SCP_UNIX
// handle case-insensitive searching
modCmdline = handle_unix_modlist(modCmdline);
handle_unix_modlist(&modlist, &len);
#endif
// null terminate each individual
for (auto& ch : modCmdline)
for (size_t i = 0; i < len; i++)
{
if (ch == ',')
ch = '\0';
if (modlist[i] == ',')
modlist[i] = '\0';
}
char whee[MAX_PATH_LEN];
memset(whee, 0, sizeof(whee));
_getcwd(whee, MAX_PATH_LEN-1);
Cmdline_mod = cfile::getModRootsFromModCmdline(whee, modCmdline.c_str());
//copy over - we don't have to delete[] Cmdline_mod because it's a pointer to an automatic global char*
Cmdline_mod = modlist;
}
@@ -1933,7 +1776,7 @@ static bool SetCmdlineParams(flag_input_type inputType)
}
if ( nomotiondebris_arg.found() ) {
Motion_debris_enabled = false;
Cmdline_nomotiondebris = 1;
}
if( mipmap_arg.found() ) {
@@ -1945,11 +1788,11 @@ static bool SetCmdlineParams(flag_input_type inputType)
}
if ( fov_arg.found() ) {
auto val = fov_arg.get_float();
if (val > 0.1) {
VIEWER_ZOOM_DEFAULT = val;
Cmdline_fov = fov_arg.get_float();
if (Cmdline_fov > 0.1) {
VIEWER_ZOOM_DEFAULT = Cmdline_fov;
} else {
VIEWER_ZOOM_DEFAULT = 0.75f;
VIEWER_ZOOM_DEFAULT = Cmdline_fov = 0.75f;
}
}
@@ -1963,7 +1806,7 @@ static bool SetCmdlineParams(flag_input_type inputType)
}
if ( use_3dwarp.found() ) {
Fireball_use_3d_warp = true;
Cmdline_3dwarp = 1;
}
if ( use_warp_flash.found() ) {
@@ -2006,7 +1849,7 @@ static bool SetCmdlineParams(flag_input_type inputType)
if(no_vsync_arg.found() )
{
Gr_enable_vsync = false;
Cmdline_no_vsync = 1;
}
if ( normal_arg.found() ) {
@@ -2018,20 +1861,13 @@ static bool SetCmdlineParams(flag_input_type inputType)
}
if (fxaa_arg.found() ) {
Gr_aa_mode = AntiAliasMode::FXAA_Medium;
Cmdline_fxaa = true;
if (fxaa_preset_arg.found()) {
auto val = fxaa_preset_arg.get_int();
if (val > 6) {
Gr_aa_mode = AntiAliasMode::FXAA_High;
} else if (val > 3) {
Gr_aa_mode = AntiAliasMode::FXAA_Medium;
} else {
Gr_aa_mode = AntiAliasMode::FXAA_Low;
}
Cmdline_fxaa_preset = fxaa_preset_arg.get_int();
}
Gr_aa_mode_last_frame = Gr_aa_mode;
Fxaa_preset_last_frame = Cmdline_fxaa_preset;
}
if ( glow_arg.found() )
@@ -2168,17 +2004,17 @@ static bool SetCmdlineParams(flag_input_type inputType)
if ( fb_explosions_arg.found() )
{
Gr_framebuffer_effects.set(FramebufferEffects::Shockwaves, true);
Cmdline_fb_explosions = 1;
}
if (fb_thrusters_arg.found())
{
Gr_framebuffer_effects.set(FramebufferEffects::Thrusters, true);
Cmdline_fb_thrusters = true;
}
if ( postprocess_arg.found() )
{
Gr_post_processing_enabled = true;
Cmdline_postprocess = 1;
}
if ( bloom_intensity_arg.found() )
@@ -2198,32 +2034,12 @@ static bool SetCmdlineParams(flag_input_type inputType)
if( enable_shadows_arg.found() )
{
Shadow_quality = ShadowQuality::Medium;
Cmdline_shadow_quality = 2;
}
if( shadow_quality_arg.found() )
{
switch (shadow_quality_arg.get_int()) {
case 0:
Shadow_quality = ShadowQuality::Disabled;
break;
case 1:
Shadow_quality = ShadowQuality::Low;
break;
case 2:
Shadow_quality = ShadowQuality::Medium;
break;
case 3:
Shadow_quality = ShadowQuality::High;
break;
case 4:
Shadow_quality = ShadowQuality::Ultra;
break;
default:
mprintf(("Invalid shadow quality %d. Disabling shadows...\n", shadow_quality_arg.get_int()));
Shadow_quality = ShadowQuality::Disabled;
break;
}
Cmdline_shadow_quality = shadow_quality_arg.get_int();
}
if( no_deferred_lighting_arg.found() )
@@ -2337,7 +2153,7 @@ int parse_cmdline(int argc, char *argv[])
// --------------- Kazan -------------
// If you're looking for the list of if (someparam.found()) { cmdline_someparam = something; } look above at this function
// I did this because of fred2_parse_cmdline()
return SetCmdlineParams(flag_input_type::Flags);
return SetCmdlineParams();
}
const char * get_param_desc(const char *flag_name)
+21 -18
View File
@@ -12,7 +12,6 @@
#ifndef FS_CMDLINE_HEADER_FILE
#define FS_CMDLINE_HEADER_FILE
#include "globalincs/pstypes.h"
int parse_cmdline(int argc, char *argv[]);
@@ -25,11 +24,11 @@ int parse_cmdline(int argc, char *argv[]);
// RETAIL OPTIONS ----------------------------------------------
extern SCP_string Cmdline_connect_addr;
extern SCP_string Cmdline_game_name;
extern SCP_string Cmdline_game_password;
extern SCP_string Cmdline_rank_above;
extern SCP_string Cmdline_rank_below;
extern char *Cmdline_connect_addr;
extern char *Cmdline_game_name;
extern char *Cmdline_game_password;
extern char *Cmdline_rank_above;
extern char *Cmdline_rank_below;
extern int Cmdline_cd_check;
extern int Cmdline_client_dodamage;
extern int Cmdline_closed_game;
@@ -47,8 +46,8 @@ extern int Cmdline_timeout;
extern int Cmdline_use_last_pilot;
extern int Cmdline_window;
extern int Cmdline_fullscreen_window;
extern SCP_string Cmdline_res;
extern SCP_string Cmdline_center_res;
extern char *Cmdline_res;
extern char *Cmdline_center_res;
// FSO OPTIONS -------------------------------------------------
@@ -56,6 +55,7 @@ extern SCP_string Cmdline_center_res;
// Graphics related
extern double specular_exponent_value;
extern float Cmdline_clip_dist;
extern float Cmdline_fov;
extern float Cmdline_ogl_spec;
extern float static_light_factor;
extern float static_point_factor;
@@ -63,13 +63,20 @@ extern float static_tube_factor;
extern int Cmdline_ambient_factor;
extern int Cmdline_env;
extern int Cmdline_glow;
extern int Cmdline_nomotiondebris;
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_postprocess;
extern int Cmdline_bloom_intensity;
extern bool Cmdline_fxaa;
extern int Cmdline_fxaa_preset;
extern bool Cmdline_fb_explosions;
extern bool Cmdline_fb_thrusters;
extern int Cmdline_shadow_quality;
extern int Cmdline_no_deferred_lighting;
extern int Cmdline_no_emissive;
extern int Cmdline_aniso_level;
@@ -97,18 +104,14 @@ extern int Cmdline_stretch_menu;
extern int Cmdline_voice_recognition;
extern int Cmdline_no_enhanced_sound;
namespace cfile {
struct ModRoot;
} // namespace cfile
// MOD related
extern SCP_vector<cfile::ModRoot> Cmdline_mod; // DTP for mod support
extern char *Cmdline_mod; // DTP for mod support
// Multiplayer/Network related
extern SCP_string Cmdline_almission; // DTP for autoload mission (for multi only)
extern char *Cmdline_almission; // DTP for autoload mission (for multi only)
extern int Cmdline_ingamejoin;
extern int Cmdline_mpnoreturn;
extern SCP_string Cmdline_spew_mission_crcs;
extern SCP_string Cmdline_spew_table_crcs;
extern char *Cmdline_spew_mission_crcs;
extern char *Cmdline_spew_table_crcs;
extern int Cmdline_objupd;
// Launcher related options
@@ -124,7 +127,7 @@ extern int Cmdline_mipmap;
extern int Cmdline_ati_color_swap;
extern int Cmdline_no_3d_sound;
extern int Cmdline_drawelements;
extern SCP_string Cmdline_keyboard_layout;
extern char* Cmdline_keyboard_layout;
extern bool Cmdline_gl_finish;
extern bool Cmdline_no_geo_sdr_effects;
extern bool Cmdline_set_cpu_affinity;
@@ -135,7 +138,7 @@ extern bool Cmdline_alternate_registry_path;
#endif
// Developer/Testing related
extern SCP_string Cmdline_start_mission;
extern char *Cmdline_start_mission;
extern int Cmdline_dis_collisions;
extern int Cmdline_dis_weapons;
extern bool Cmdline_output_sexp_info;
-48
View File
@@ -1,48 +0,0 @@
{
"version": 1,
"flags": {
"-bool_option": false,
"-number_option": 5.8,
"-string_option": "asdf",
"-mod": [
{
"type": "folder",
"path": "/home/fso/mediavps",
"user": true,
"location_type": "primary_mod"
},
{
"type": "folder",
"path": "/home/fso",
"user": true,
"location_type": "game_root"
},
{
"type": "folder",
"path": "/path/to/fso/mediavps",
"user": false,
"location_type": "primary_mod"
},
{
"type": "package",
"path": "/path/to/fso/mediavps/MVPS-Z.vp",
"location_type": "primary_mod"
},
{
"type": "package",
"path": "/path/to/fso/mediavps/MVPS-X.vp",
"location_type": "primary_mod"
},
{
"type": "folder",
"path": "/path/to/fso",
"location_type": "game_root"
},
{
"type": "package",
"path": "/path/to/fso/retail.vp",
"location_type": "game_root"
}
]
}
}
+1 -3
View File
@@ -504,9 +504,7 @@ char *translate_key(char *key)
// both key and joystick button are mapped to this control
if ((key_code >= 0 ) && (joy_code >= 0) ) {
strcpy_s(text, key_text);
strcat_s(text, " ");
strcat_s(text, XSTR("or", 1638));
strcat_s(text, " ");
strcat_s(text, " or ");
strcat_s(text, joy_text);
}
// if we only have one
+8
View File
@@ -21,7 +21,15 @@ typedef struct cutscene_info
bool viewable;
} cutscene_info;
#if SCP_COMPILER_IS_GNU
#pragma GCC diagnostic push
// This suppresses a GCC bug where it thinks that the Cutscenes from the enum class below shadows a global variable
#pragma GCC diagnostic ignored "-Wshadow"
#endif
extern SCP_vector<cutscene_info> Cutscenes;
#if SCP_COMPILER_IS_GNU
#pragma GCC diagnostic pop
#endif
// initializa table data
void cutscene_init();
+2
View File
@@ -974,6 +974,8 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
// SET PHYSICS PARAMETERS
// already have (hitpos - heavy) and light_cm_pos
// get heavy cm pos - already have light_cm_pos
debris_hit_info->heavy_collision_cm_pos = zero;
// get r_heavy and r_light
debris_hit_info->r_heavy = debris_hit_info->hit_pos;
+6 -14
View File
@@ -1,21 +1,22 @@
/*
* Copyright (C) Volition, Inc. 1999. All rights reserved.
*
* All source code herein is the property of Volition, Inc. You may not sell
* or otherwise commercially exploit the source or things you created based on the
* All source code herein is the property of Volition, Inc. You may not sell
* or otherwise commercially exploit the source or things you created based on the
* source.
*
*/
*/
#include "fireball/fireballs.h"
#include "asteroid/asteroid.h"
#include "cmdline/cmdline.h"
#include "fireball/fireballs.h"
#include "gamesnd/gamesnd.h"
#include "graphics/tmapper.h"
#include "localization/localize.h"
#include "model/model.h"
#include "object/object.h"
#include "options/Option.h"
#include "parse/parselo.h"
#include "render/3d.h"
#include "render/batching.h"
@@ -45,15 +46,6 @@ int Num_fireball_types = 0;
bool fireballs_inited = false;
bool fireballs_parsed = false;
bool Fireball_use_3d_warp = false;
static auto WarpOption = options::OptionBuilder<bool>("Graphics.3dWarp", "3D Warp", "Use a 3D model for warp effects")
.category("Graphics")
.default_val(true)
.level(options::ExpertLevel::Advanced)
.bind_to(&Fireball_use_3d_warp)
.importance(65)
.finish();
/**
* Play warp in sound for warp effect
*/
-2
View File
@@ -137,6 +137,4 @@ float fireball_wormhole_intensity( fireball *fb );
// Goober5000
extern int Knossos_warp_ani_used;
extern bool Fireball_use_3d_warp;
#endif /* _FIREBALLS_H */
+2 -2
View File
@@ -100,7 +100,7 @@ void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, ve
}
}
if ( (warp_model_id >= 0) && (warp_3d || Fireball_use_3d_warp) ) {
if ( (warp_model_id >= 0) && (warp_3d || Cmdline_3dwarp) ) {
model_render_params render_info;
float scale = radius / 25.0f;
@@ -137,7 +137,7 @@ void warpin_queue_render(model_draw_list *scene, object *obj, matrix *orient, ve
vm_vec_scale_add2( &vecs[3], &orient->vec.rvec, -radius );
vm_vec_scale_add2( &vecs[3], &orient->vec.fvec, Grid_depth );
// vm_vec_scale_add( &vecs[4], center, &orient->vec.fvec, -Grid_depth );
// vm_vec_scale_add( &vecs[4], ¢er, &orient->vec.fvec, -Grid_depth );
vecs[4] = center;
verts[0].texture_position.u = 0.01f;
+2 -2
View File
@@ -1678,7 +1678,7 @@ void fs2netd_spew_table_checksums(const char *outfile)
char description[512] = { 0 };
char filename[65] = { 0 };
size_t offset = 0;
const char *p = nullptr;
char *p = NULL;
if ( Table_valid_status.empty() ) {
return;
@@ -1693,7 +1693,7 @@ void fs2netd_spew_table_checksums(const char *outfile)
return;
}
p = Cmdline_spew_table_crcs.c_str();
p = Cmdline_spew_table_crcs;
while (*p && (offset < sizeof(description))) {
if (*p == '"' && offset < sizeof(description)-1) {
+1 -1
View File
@@ -246,7 +246,7 @@ enum class GameSounds {
/**
* Interface sounds
*/
enum class InterfaceSounds {
enum InterfaceSounds {
IFACE_MOUSE_CLICK =0, //!< mouse click
ICON_PICKUP =1, //!< pick up a ship icon (Empty in Retail)
ICON_DROP_ON_WING =2, //!< drop a ship icon on a wing slot
-9
View File
@@ -125,17 +125,8 @@ class flagset {
void from_u64(std::uint64_t num) { values = (unsigned long) num; }
std::uint64_t to_u64() const { return (std::uint64_t) values.to_ulong(); }
size_t hash() const { return std::hash<std::bitset<SIZE>>()(values); }
};
namespace std {
template <typename T, size_t N>
struct hash<::flagset<T, N>> {
size_t operator()(const ::flagset<T, N>& val) { return val.hash(); }
};
} // namespace std
#define FLAG_LIST(Type) enum class Type : size_t
template<typename TEnum, size_t SIZE>
+7 -41
View File
@@ -3,15 +3,15 @@
/* SCP_vm_allocator - maintained by portej05 (i.e. please don't patch this one yourself!) */
#include <deque>
#include <vector>
#include <list>
#include <map>
#include <queue>
#include <sstream>
#include <string>
#include <type_traits>
#include <sstream>
#include <queue>
#include <deque>
#include <unordered_map>
#include <vector>
#include <sstream>
template< typename T >
using SCP_vector = std::vector< T, std::allocator< T > >;
@@ -35,41 +35,7 @@ using SCP_queue = std::queue< T, std::deque< T, std::allocator< T > > >;
template< typename T >
using SCP_deque = std::deque< T, std::allocator< T > >;
#if __cplusplus < 201402L
template <class T, bool>
struct enum_hasher_util {
inline size_t operator()(const T& elem) { return std::hash<T>()(elem); }
};
template <class T>
struct enum_hasher_util<T, true> {
inline size_t operator()(const T& elem)
{
typedef typename std::underlying_type<T>::type enumType;
return std::hash<enumType>()(static_cast<enumType>(elem));
}
};
/**
* @brief An enum class compatible hashing class
*
* This is the same as std::hash except that is can handle enum classes properly using their underlying type. This is
* only required for C++ < 14 since after that the standard mandates that enum classes should be hashable.
*
* @tparam T The type that should be hashed
*/
template <class T>
struct SCP_hash {
inline size_t operator()(const T& elem) const { return enum_hasher_util<T, std::is_enum<T>::value>()(elem); }
};
#else
// No need for the special hash class so just use the standard hash
template <typename T>
using SCP_hash = std::hash<T>;
#endif
template <typename Key, typename T, typename Hash = SCP_hash<Key>, typename KeyEqual = std::equal_to<Key>>
using SCP_unordered_map = std::unordered_map<Key, T, Hash, KeyEqual, std::allocator<std::pair<const Key, T>>>;
template< typename Key, typename T, typename Hash = std::hash<Key>, typename KeyEqual = std::equal_to<Key> >
using SCP_unordered_map = std::unordered_map< Key, T, Hash, KeyEqual, std::allocator< std::pair<const Key, T> > >;
#endif // _VMALLOCATOR_H_INCLUDED_
+50 -293
View File
@@ -36,8 +36,6 @@
#include "graphics/util/UniformBufferManager.h"
#include "io/keycontrol.h" // m!m
#include "io/timer.h"
#include "libs/jansson.h"
#include "options/Option.h"
#include "osapi/osapi.h"
#include "parse/parselo.h"
#include "popup/popup.h"
@@ -105,239 +103,6 @@ float Gr_save_menu_zoomed_offset_X = 0.0f, Gr_save_menu_zoomed_offset_Y = 0.0f;
bool Save_custom_screen_size;
static int videodisplay_deserializer(const json_t* value)
{
int id;
json_error_t err;
if (json_unpack_ex((json_t*)value, &err, 0, "i", &id) != 0) {
throw json_exception(err);
}
return id;
}
static json_t* videodisplay_serializer(int value) { return json_pack("i", value); }
static SCP_vector<int> videodisplay_enumerator()
{
SCP_vector<int> vals;
for (int i = 0; i < SDL_GetNumVideoDisplays(); ++i) {
vals.push_back(i);
}
return vals;
}
static SCP_string videodisplay_display(int id)
{
SCP_string out;
sprintf(out, "(%d) %s", id + 1, SDL_GetDisplayName(id));
return out;
}
static bool videodisplay_change(int display, bool initial)
{
if (initial) {
return false;
}
auto window = os::getSDLMainWindow();
if (window == nullptr) {
return false;
}
SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED_DISPLAY(display), SDL_WINDOWPOS_CENTERED_DISPLAY(display));
return true;
}
static auto VideoDisplayOption =
options::OptionBuilder<int>("Graphics.Display", "Primary display", "The display used for rendering.")
.category("Graphics")
.level(options::ExpertLevel::Beginner)
.deserializer(videodisplay_deserializer)
.serializer(videodisplay_serializer)
.enumerator(videodisplay_enumerator)
.display(videodisplay_display)
.default_val(0)
.change_listener(videodisplay_change)
.importance(99)
.finish();
struct ResolutionInfo {
uint32_t width = 0;
uint32_t height = 0;
ResolutionInfo(uint32_t _width, uint32_t _height) : width(_width), height(_height) {}
ResolutionInfo() = default;
friend bool operator==(const ResolutionInfo& lhs, const ResolutionInfo& rhs)
{
return lhs.width == rhs.width && lhs.height == rhs.height;
}
friend bool operator!=(const ResolutionInfo& lhs, const ResolutionInfo& rhs) { return !(rhs == lhs); }
};
static ResolutionInfo resolution_deserializer(const json_t* el)
{
int width;
int height;
json_error_t err;
if (json_unpack_ex((json_t*)el, &err, 0, "{s:i, s:i}", "width", &width, "height", &height) != 0) {
throw json_exception(err);
}
return {(uint32_t)width, (uint32_t)height};
}
static json_t* resolution_serializer(const ResolutionInfo& value)
{
return json_pack("{s:i, s:i}", "width", value.width, "height", value.height);
}
static SCP_vector<ResolutionInfo> resolution_enumerator()
{
SCP_vector<ResolutionInfo> out;
auto display = VideoDisplayOption->getValue();
for (auto i = 0; i < SDL_GetNumDisplayModes(display); ++i) {
SDL_DisplayMode mode;
if (SDL_GetDisplayMode(display, i, &mode) != 0) {
continue;
}
auto res = ResolutionInfo(mode.w, mode.h);
if (std::find(out.begin(), out.end(), res) == out.end()) {
out.push_back(res);
}
}
return out;
}
static SCP_string resolution_display(const ResolutionInfo& info)
{
SCP_string str;
sprintf(str, "%dx%d", info.width, info.height);
return str;
}
static ResolutionInfo resolution_default()
{
SDL_DisplayMode mode;
if (SDL_GetDesktopDisplayMode(VideoDisplayOption->getValue(), &mode) != 0) {
return {};
}
return ResolutionInfo(mode.w, mode.h);
}
static bool resolution_change(const ResolutionInfo& /*info*/, bool initial)
{
if (initial) {
return false;
}
return false;
// The following code should change the size of the window properly but FSO currently can't handle that
/*
auto window = os::getSDLMainWindow();
if (window == nullptr) {
return;
}
auto display = VideoDisplayOption->getValue();
if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) {
SDL_DisplayMode target;
target.w = info.width;
target.h = info.height;
target.format = 0; // don't care
target.refresh_rate = 0; // don't care
target.driverdata = 0; // initialize to 0
SDL_DisplayMode closest;
if (SDL_GetClosestDisplayMode(display, &target, &closest) == nullptr) {
return;
}
SDL_SetWindowDisplayMode(window, &closest);
} else {
SDL_SetWindowSize(window, info.width, info.height);
// Recenter the window
SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED_DISPLAY(display), SDL_WINDOWPOS_CENTERED_DISPLAY(display));
}
*/
}
static auto ResolutionOption =
options::OptionBuilder<ResolutionInfo>("Graphics.Resolution", "Resolution", "The rendering resolution.")
.category("Graphics")
.level(options::ExpertLevel::Beginner)
.deserializer(resolution_deserializer)
.serializer(resolution_serializer)
.enumerator(resolution_enumerator)
.display(resolution_display)
.default_func(resolution_default)
.change_listener(resolution_change)
.importance(100)
.finish();
bool Gr_enable_soft_particles = false;
static auto SoftParticlesOption = options::OptionBuilder<bool>("Graphics.SoftParticles", "Soft Particles",
"Enable or disable soft particle rendering.")
.category("Graphics")
.level(options::ExpertLevel::Advanced)
.default_val(true)
.bind_to_once(&Gr_enable_soft_particles)
.importance(68)
.finish();
flagset<FramebufferEffects> Gr_framebuffer_effects;
static auto FramebufferEffectsOption =
options::OptionBuilder<flagset<FramebufferEffects>>(
"Graphics.FramebufferEffects", "Framebuffer effects",
"Controls which framebuffer effects will be applied to the scene.")
.category("Graphics")
.level(options::ExpertLevel::Advanced)
.values({{{}, "None"},
{{FramebufferEffects::Shockwaves}, "Shockwaves"},
{{FramebufferEffects::Thrusters}, "Thrusters"},
{{FramebufferEffects::Shockwaves, FramebufferEffects::Thrusters}, "All"}})
.default_val({FramebufferEffects::Shockwaves, FramebufferEffects::Thrusters})
.bind_to_once(&Gr_framebuffer_effects)
.importance(77)
.finish();
AntiAliasMode Gr_aa_mode = AntiAliasMode::None;
AntiAliasMode Gr_aa_mode_last_frame = AntiAliasMode::None;
static auto AAOption = options::OptionBuilder<AntiAliasMode>("Graphics.AAMode", "Anti Aliasing",
"Controls the anti aliasing mode of the engine.")
.category("Graphics")
.level(options::ExpertLevel::Advanced)
.values({{AntiAliasMode::None, "None"},
{AntiAliasMode::FXAA_Low, "FXAA Low"},
{AntiAliasMode::FXAA_Medium, "FXAA Medium"},
{AntiAliasMode::FXAA_High, "FXAA High"}})
.default_val(AntiAliasMode::None)
.bind_to(&Gr_aa_mode)
.importance(79)
.finish();
bool gr_is_fxaa_mode(AntiAliasMode mode)
{
return mode == AntiAliasMode::FXAA_Low || mode == AntiAliasMode::FXAA_Medium || mode == AntiAliasMode::FXAA_High;
}
bool Gr_post_processing_enabled = false;
static auto PostProcessOption =
options::OptionBuilder<bool>("Graphis.PostProcessing", "Post processing",
"Controls whether post processing is enabled in the engine")
.category("Graphics")
.level(options::ExpertLevel::Advanced)
.default_val(false)
.bind_to_once(&Gr_post_processing_enabled)
.importance(69)
.finish();
bool Gr_enable_vsync = true;
static auto VSyncOption = options::OptionBuilder<bool>("Graphis.VSync", "Vertical Sync",
"Controls how the engine does vertical synchronization")
.category("Graphics")
.level(options::ExpertLevel::Advanced)
.default_val(true)
.bind_to_once(&Gr_enable_vsync)
.importance(70)
.finish();
// Forward definitions
static void uniform_buffer_managers_init();
static void uniform_buffer_managers_deinit();
@@ -1188,83 +953,75 @@ bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode,
}
}
if (Using_in_game_options) {
auto res = ResolutionOption->getValue();
width = res.width;
height = res.height;
} else {
// We cannot continue without this, quit, but try to help the user out first
ptr = os_config_read_string(nullptr, NOX("VideocardFs2open"), nullptr);
// We cannot continue without this, quit, but try to help the user out first
ptr = os_config_read_string(NULL, NOX("VideocardFs2open"), NULL);
// if we don't have a config string then construct one, using OpenGL 1024x768 32-bit as the default
if (ptr == nullptr) {
// If we don't have a display mode, use SDL to get default settings
// We need to initialize SDL to do this
// if we don't have a config string then construct one, using OpenGL 1024x768 32-bit as the default
if (ptr == NULL) {
// If we don't have a display mode, use SDL to get default settings
// We need to initialize SDL to do this
if (SDL_InitSubSystem(SDL_INIT_VIDEO) == 0)
if (SDL_InitSubSystem(SDL_INIT_VIDEO) == 0)
{
int display = static_cast<int>(os_config_read_uint("Video", "Display", 0));
SDL_DisplayMode displayMode;
if (SDL_GetDesktopDisplayMode(display, &displayMode) == 0)
{
auto display = static_cast<int>(os_config_read_uint("Video", "Display", 0));
SDL_DisplayMode displayMode;
if (SDL_GetDesktopDisplayMode(display, &displayMode) == 0)
{
width = displayMode.w;
height = displayMode.h;
int sdlBits = SDL_BITSPERPIXEL(displayMode.format);
width = displayMode.w;
height = displayMode.h;
int sdlBits = SDL_BITSPERPIXEL(displayMode.format);
if (SDL_ISPIXELFORMAT_ALPHA(displayMode.format))
if (SDL_ISPIXELFORMAT_ALPHA(displayMode.format))
{
depth = sdlBits;
}
else
{
// Fix a few values
if (sdlBits == 24)
{
depth = sdlBits;
depth = 32;
}
else if (sdlBits == 15)
{
depth = 16;
}
else
{
// Fix a few values
if (sdlBits == 24)
{
depth = 32;
}
else if (sdlBits == 15)
{
depth = 16;
}
else
{
depth = sdlBits;
}
depth = sdlBits;
}
SCP_string videomode;
sprintf(videomode, "OGL -(%dx%d)x%d bit", width, height, depth);
os_config_write_string(nullptr, NOX("VideocardFs2open"), videomode.c_str());
}
}
} else {
Assert(ptr != nullptr);
// NOTE: The "ptr+5" is to skip over the initial "????-" in the video string.
// If the format of that string changes you'll have to change this too!!!
if (sscanf(ptr + 5, "(%dx%d)x%d ", &width, &height, &depth) != 3) {
Error(LOCATION, "Can't understand 'VideocardFs2open' config entry!");
SCP_string videomode;
sprintf(videomode, "OGL -(%dx%d)x%d bit", width, height, depth);
os_config_write_string(NULL, NOX("VideocardFs2open"), videomode.c_str());
}
}
} else {
Assert(ptr != NULL);
if (!Cmdline_res.empty()) {
int tmp_width = 0;
int tmp_height = 0;
if ( sscanf(Cmdline_res.c_str(), "%dx%d", &tmp_width, &tmp_height) == 2 ) {
width = tmp_width;
height = tmp_height;
}
// NOTE: The "ptr+5" is to skip over the initial "????-" in the video string.
// If the format of that string changes you'll have to change this too!!!
if (sscanf(ptr + 5, "(%dx%d)x%d ", &width, &height, &depth) != 3) {
Error(LOCATION, "Can't understand 'VideocardFs2open' config entry!");
}
Gr_enable_soft_particles = Cmdline_softparticles != 0;
}
if (!Cmdline_center_res.empty()) {
if (Cmdline_res != NULL) {
int tmp_width = 0;
int tmp_height = 0;
if ( sscanf(Cmdline_res, "%dx%d", &tmp_width, &tmp_height) == 2 ) {
width = tmp_width;
height = tmp_height;
}
}
if (Cmdline_center_res != NULL) {
int tmp_center_width = 0;
int tmp_center_height = 0;
if ( (sscanf(Cmdline_center_res.c_str(), "%dx%d", &tmp_center_width, &tmp_center_height) == 2) && (tmp_center_width > 0) && (tmp_center_height > 0) ) {
if ( (sscanf(Cmdline_center_res, "%dx%d", &tmp_center_width, &tmp_center_height) == 2) && (tmp_center_width > 0) && (tmp_center_height > 0) ) {
center_aspect_ratio = (float)tmp_center_width / (float)tmp_center_height;
}
}
+4 -25
View File
@@ -12,15 +12,15 @@
#ifndef _GRAPHICS_H
#define _GRAPHICS_H
#include "graphics/grinternal.h"
#include "osapi/osapi.h"
#include "bmpman/bmpman.h"
#include "cfile/cfile.h"
#include "globalincs/flagset.h"
#include "globalincs/pstypes.h"
#include "graphics/grinternal.h"
#include "graphics/tmapper.h"
#include "io/cursor.h"
#include "cfile/cfile.h"
#include "math/vecmat.h"
#include "osapi/osapi.h"
#include "io/cursor.h"
// Forward definition
namespace graphics {
@@ -40,26 +40,6 @@ extern int Gr_inited;
extern int gr_zbuffering, gr_zbuffering_mode;
extern int gr_global_zbuffering;
extern bool Gr_enable_soft_particles;
FLAG_LIST(FramebufferEffects){Thrusters = 0, Shockwaves, NUM_VALUES};
extern flagset<FramebufferEffects> Gr_framebuffer_effects;
enum class AntiAliasMode {
None,
FXAA_Low,
FXAA_Medium,
FXAA_High
};
extern AntiAliasMode Gr_aa_mode;
extern AntiAliasMode Gr_aa_mode_last_frame;
bool gr_is_fxaa_mode(AntiAliasMode mode);
extern bool Gr_post_processing_enabled;
extern bool Gr_enable_vsync;
class material;
class model_material;
class particle_material;
@@ -314,7 +294,6 @@ typedef enum gr_capability {
enum class gr_property {
UNIFORM_BUFFER_OFFSET_ALIGNMENT,
UNIFORM_BUFFER_MAX_SIZE,
MAX_ANISOTROPY
};
// stencil buffering stuff
+69 -67
View File
@@ -667,7 +667,7 @@ float batch_add_laser(int texture, vec3d *p0, float width1, vec3d *p1, float wid
batch_item *item = NULL;
SCP_map<int, batch_item>::iterator it = geometry_map.find(texture);
if (it != geometry_map.end()) {
if ( !geometry_map.empty() && it != geometry_map.end() ) {
item = &it->second;
} else {
item = &geometry_map[texture];
@@ -690,12 +690,12 @@ int batch_add_bitmap(int texture, int tmap_flags, vertex *pnt, int orient, float
return 1;
}
if ( tmap_flags & TMAP_FLAG_SOFT_QUAD && !Gr_enable_soft_particles ) {
if ( tmap_flags & TMAP_FLAG_SOFT_QUAD && !Cmdline_softparticles ) {
// don't render this as a soft particle if we don't support soft particles
tmap_flags &= ~(TMAP_FLAG_SOFT_QUAD);
}
if ( Gr_enable_soft_particles && !Cmdline_no_geo_sdr_effects && (tmap_flags & TMAP_FLAG_VERTEX_GEN) ) {
if ( Cmdline_softparticles && !Cmdline_no_geo_sdr_effects && (tmap_flags & TMAP_FLAG_VERTEX_GEN) ) {
geometry_batch_add_bitmap(texture, tmap_flags, pnt, orient, rad, alpha, depth);
return 0;
} else if ( tmap_flags & TMAP_FLAG_VERTEX_GEN ) {
@@ -706,7 +706,7 @@ int batch_add_bitmap(int texture, int tmap_flags, vertex *pnt, int orient, float
SCP_map<int, batch_item>::iterator it = geometry_map.find(texture);
if (it != geometry_map.end()) {
if ( !geometry_map.empty() && it != geometry_map.end() ) {
item = &it->second;
} else {
item = &geometry_map[texture];
@@ -735,7 +735,7 @@ int geometry_batch_add_bitmap(int texture, int tmap_flags, vertex *pnt, int orie
g_sdr_batch_item *item = NULL;
SCP_map<int, g_sdr_batch_item>::iterator it = geometry_shader_map.find(texture);
if (it != geometry_shader_map.end()) {
if ( !geometry_shader_map.empty() && it != geometry_shader_map.end() ) {
item = &it->second;
} else {
item = &geometry_shader_map[texture];
@@ -759,7 +759,7 @@ int batch_add_bitmap_rotated(int texture, int tmap_flags, vertex *pnt, float ang
return 1;
}
if ( tmap_flags & TMAP_FLAG_SOFT_QUAD && !Gr_enable_soft_particles ) {
if ( tmap_flags & TMAP_FLAG_SOFT_QUAD && !Cmdline_softparticles ) {
// don't render this as a soft particle if we don't support soft particles
tmap_flags &= ~(TMAP_FLAG_SOFT_QUAD);
}
@@ -768,7 +768,7 @@ int batch_add_bitmap_rotated(int texture, int tmap_flags, vertex *pnt, float ang
SCP_map<int, batch_item>::iterator it = geometry_map.find(texture);
if (it != geometry_map.end()) {
if ( !geometry_map.empty() && it != geometry_map.end() ) {
item = &it->second;
} else {
item = &geometry_map[texture];
@@ -798,7 +798,7 @@ int batch_add_tri(int texture, int tmap_flags, vertex *verts, float alpha)
SCP_map<int, batch_item>::iterator it = geometry_map.find(texture);
if (it != geometry_map.end()) {
if ( !geometry_map.empty() && it != geometry_map.end() ) {
item = &it->second;
} else {
item = &geometry_map[texture];
@@ -828,7 +828,7 @@ int batch_add_quad(int texture, int tmap_flags, vertex *verts, float alpha)
SCP_map<int, batch_item>::iterator it = geometry_map.find(texture);
if (it != geometry_map.end()) {
if ( !geometry_map.empty() && it != geometry_map.end() ) {
item = &it->second;
} else {
item = &geometry_map[texture];
@@ -908,7 +908,7 @@ int batch_add_polygon(int texture, int tmap_flags, vec3d *pos, matrix *orient, f
SCP_map<int, batch_item>::iterator it = geometry_map.find(texture);
if (it != geometry_map.end()) {
if ( !geometry_map.empty() && it != geometry_map.end() ) {
item = &it->second;
} else {
item = &geometry_map[texture];
@@ -938,7 +938,7 @@ int batch_add_beam(int texture, int tmap_flags, vec3d *start, vec3d *end, float
SCP_map<int, batch_item>::iterator it = geometry_map.find(texture);
if (it != geometry_map.end()) {
if ( !geometry_map.empty() && it != geometry_map.end() ) {
item = &it->second;
} else {
item = &geometry_map[texture];
@@ -959,102 +959,102 @@ int batch_add_beam(int texture, int tmap_flags, vec3d *start, vec3d *end, float
void batch_render_lasers(int buffer_handle)
{
for (auto &bi : geometry_map) {
for (SCP_map<int, batch_item>::iterator bi = geometry_map.begin(); bi != geometry_map.end(); ++bi) {
if ( !bi.second.laser )
if ( !bi->second.laser )
continue;
if ( !bi.second.batch.need_to_render() )
if ( !bi->second.batch.need_to_render() )
continue;
Assert( bi.second.texture >= 0 );
gr_set_bitmap(bi.second.texture, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 0.99999f);
Assert( bi->second.texture >= 0 );
gr_set_bitmap(bi->second.texture, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 0.99999f);
if ( buffer_handle >= 0 ) {
bi.second.batch.render_buffer(buffer_handle, TMAP_FLAG_TEXTURED | TMAP_FLAG_XPARENT | TMAP_HTL_3D_UNLIT | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_FLAG_CORRECT | TMAP_FLAG_EMISSIVE);
bi->second.batch.render_buffer(buffer_handle, TMAP_FLAG_TEXTURED | TMAP_FLAG_XPARENT | TMAP_HTL_3D_UNLIT | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_FLAG_CORRECT | TMAP_FLAG_EMISSIVE);
} else {
bi.second.batch.render(TMAP_FLAG_TEXTURED | TMAP_FLAG_XPARENT | TMAP_HTL_3D_UNLIT | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_FLAG_CORRECT | TMAP_FLAG_EMISSIVE);
bi->second.batch.render(TMAP_FLAG_TEXTURED | TMAP_FLAG_XPARENT | TMAP_HTL_3D_UNLIT | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_FLAG_CORRECT | TMAP_FLAG_EMISSIVE);
}
}
}
void batch_load_buffer_lasers(effect_vertex* buffer, int *n_verts)
{
for (auto &bi : geometry_map) {
for (SCP_map<int, batch_item>::iterator bi = geometry_map.begin(); bi != geometry_map.end(); ++bi) {
if ( !bi.second.laser )
if ( !bi->second.laser )
continue;
if ( !bi.second.batch.need_to_render() )
if ( !bi->second.batch.need_to_render() )
continue;
Assert( bi.second.texture >= 0 );
bi.second.batch.load_buffer(buffer, n_verts);
Assert( bi->second.texture >= 0 );
bi->second.batch.load_buffer(buffer, n_verts);
}
}
void batch_render_geometry_map_bitmaps(int buffer_handle)
{
for (auto &bi : geometry_map) {
for (SCP_map<int, batch_item>::iterator bi = geometry_map.begin(); bi != geometry_map.end(); ++bi) {
if ( bi.second.laser )
if ( bi->second.laser )
continue;
if ( !bi.second.batch.need_to_render() )
if ( !bi->second.batch.need_to_render() )
continue;
Assert( bi.second.texture >= 0 );
gr_set_bitmap(bi.second.texture, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, bi.second.alpha);
Assert( bi->second.texture >= 0 );
gr_set_bitmap(bi->second.texture, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, bi->second.alpha);
if ( buffer_handle >= 0 ) {
bi.second.batch.render_buffer(buffer_handle, bi.second.tmap_flags);
bi->second.batch.render_buffer(buffer_handle, bi->second.tmap_flags);
} else {
bi.second.batch.render( bi.second.tmap_flags);
bi->second.batch.render( bi->second.tmap_flags);
}
}
}
void batch_render_geometry_shader_map_bitmaps(int buffer_handle)
{
for (auto &bi : geometry_shader_map) {
for (SCP_map<int, g_sdr_batch_item>::iterator bi = geometry_shader_map.begin(); bi != geometry_shader_map.end(); ++bi) {
if ( bi.second.laser )
if ( bi->second.laser )
continue;
if ( !bi.second.batch.need_to_render() )
if ( !bi->second.batch.need_to_render() )
continue;
Assert( bi.second.texture >= 0 );
gr_set_bitmap(bi.second.texture, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, bi.second.alpha);
bi.second.batch.render_buffer(buffer_handle, bi.second.tmap_flags);
Assert( bi->second.texture >= 0 );
gr_set_bitmap(bi->second.texture, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, bi->second.alpha);
bi->second.batch.render_buffer(buffer_handle, bi->second.tmap_flags);
}
}
void batch_load_buffer_geometry_map_bitmaps(effect_vertex* buffer, int *n_verts)
{
for (auto &bi : geometry_map) {
for (SCP_map<int, batch_item>::iterator bi = geometry_map.begin(); bi != geometry_map.end(); ++bi) {
if ( bi.second.laser )
if ( bi->second.laser )
continue;
if ( !bi.second.batch.need_to_render() )
if ( !bi->second.batch.need_to_render() )
continue;
Assert( bi.second.texture >= 0 );
bi.second.batch.load_buffer(buffer, n_verts);
Assert( bi->second.texture >= 0 );
bi->second.batch.load_buffer(buffer, n_verts);
}
}
void batch_load_buffer_geometry_shader_map_bitmaps(particle_pnt* buffer, size_t *n_verts)
{
for (auto &bi : geometry_shader_map) {
for (SCP_map<int, g_sdr_batch_item>::iterator bi = geometry_shader_map.begin(); bi != geometry_shader_map.end(); ++bi) {
if ( bi.second.laser )
if ( bi->second.laser )
continue;
if ( !bi.second.batch.need_to_render() )
if ( !bi->second.batch.need_to_render() )
continue;
Assert( bi.second.texture >= 0 );
bi.second.batch.load_buffer(buffer, n_verts);
Assert( bi->second.texture >= 0 );
bi->second.batch.load_buffer(buffer, n_verts);
}
}
@@ -1145,7 +1145,7 @@ int distortion_add_bitmap_rotated(int texture, int tmap_flags, vertex *pnt, floa
SCP_map<int, batch_item>::iterator it = distortion_map.find(texture);
if (it != distortion_map.end()) {
if ( !distortion_map.empty() && it != distortion_map.end() ) {
item = &it->second;
} else {
item = &distortion_map[texture];
@@ -1175,7 +1175,7 @@ int distortion_add_beam(int texture, int tmap_flags, vec3d *start, vec3d *end, f
SCP_map<int, batch_item>::iterator it = distortion_map.find(texture);
if (it != distortion_map.end()) {
if ( !distortion_map.empty() && it != distortion_map.end() ) {
item = &it->second;
} else {
item = &distortion_map[texture];
@@ -1196,53 +1196,54 @@ int distortion_add_beam(int texture, int tmap_flags, vec3d *start, vec3d *end, f
void batch_render_distortion_map_bitmaps(int buffer_handle)
{
for (auto &bi : distortion_map) {
for (SCP_map<int,batch_item>::iterator bi = distortion_map.begin(); bi != distortion_map.end(); ++bi) {
if ( bi.second.laser )
if ( bi->second.laser )
continue;
if ( !bi.second.batch.need_to_render() )
if ( !bi->second.batch.need_to_render() )
continue;
Assert( bi.second.texture >= 0 );
gr_set_bitmap(bi.second.texture, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, bi.second.alpha);
Assert( bi->second.texture >= 0 );
gr_set_bitmap(bi->second.texture, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, bi->second.alpha);
if ( buffer_handle >= 0 ) {
bi.second.batch.render_buffer(buffer_handle, bi.second.tmap_flags);
bi->second.batch.render_buffer(buffer_handle, bi->second.tmap_flags);
} else {
bi.second.batch.render( bi.second.tmap_flags);
bi->second.batch.render( bi->second.tmap_flags);
}
}
}
void batch_load_buffer_distortion_map_bitmaps(effect_vertex* buffer, int *n_verts)
{
for (auto &bi : distortion_map) {
for (SCP_map<int, batch_item>::iterator bi = distortion_map.begin(); bi != distortion_map.end(); ++bi) {
if ( bi.second.laser )
if ( bi->second.laser )
continue;
if ( !bi.second.batch.need_to_render() )
if ( !bi->second.batch.need_to_render() )
continue;
Assert( bi.second.texture >= 0 );
bi.second.batch.load_buffer(buffer, n_verts);
Assert( bi->second.texture >= 0 );
bi->second.batch.load_buffer(buffer, n_verts);
}
}
int batch_get_size()
{
int n_to_render = 0;
SCP_map<int, batch_item>::iterator bi;
for (auto &bi : geometry_map) {
n_to_render += bi.second.batch.need_to_render();
for (bi = geometry_map.begin(); bi != geometry_map.end(); ++bi) {
n_to_render += bi->second.batch.need_to_render();
}
for (auto &bi : distortion_map) {
if ( bi.second.laser )
for (bi = distortion_map.begin(); bi != distortion_map.end(); ++bi) {
if ( bi->second.laser )
continue;
n_to_render += bi.second.batch.need_to_render();
n_to_render += bi->second.batch.need_to_render();
}
return n_to_render * 3;
@@ -1251,9 +1252,10 @@ int batch_get_size()
size_t geometry_batch_get_size()
{
size_t n_to_render = 0;
SCP_map<int, g_sdr_batch_item>::iterator bi;
for (auto &bi : geometry_shader_map) {
n_to_render += bi.second.batch.need_to_render();
for (bi = geometry_shader_map.begin(); bi != geometry_shader_map.end(); ++bi) {
n_to_render += bi->second.batch.need_to_render();
}
return n_to_render;
+45 -89
View File
@@ -1,16 +1,8 @@
#include "gropengl.h"
#include "gropenglbmpman.h"
#include "gropengldeferred.h"
#include "gropengldraw.h"
#include "gropenglpostprocessing.h"
#include "gropenglquery.h"
#include "gropenglshader.h"
#include "gropenglstate.h"
#include "gropenglsync.h"
#include "gropengltexture.h"
#include "gropengltnl.h"
#include "bmpman/bmpman.h"
#include "cfile/cfile.h"
#include "cmdline/cmdline.h"
@@ -18,22 +10,32 @@
#include "debugconsole/console.h"
#include "globalincs/systemvars.h"
#include "graphics/2d.h"
#include "graphics/line.h"
#include "graphics/matrix.h"
#include "graphics/paths/PathRenderer.h"
#include "gropengl.h"
#include "gropenglbmpman.h"
#include "gropengldraw.h"
#include "gropenglpostprocessing.h"
#include "gropenglquery.h"
#include "gropenglsync.h"
#include "gropenglshader.h"
#include "gropenglstate.h"
#include "gropengltexture.h"
#include "gropengltnl.h"
#include "gropengldeferred.h"
#include "graphics/line.h"
#include "io/mouse.h"
#include "io/timer.h"
#include "libs/renderdoc/renderdoc.h"
#include "math/floating.h"
#include "model/model.h"
#include "nebula/neb.h"
#include "options/Option.h"
#include "libs/renderdoc/renderdoc.h"
#include "osapi/osapi.h"
#include "osapi/osregistry.h"
#include "pngutils/pngutils.h"
#include "popup/popup.h"
#include "render/3d.h"
#include "popup/popup.h"
#include "tracing/tracing.h"
#include "pngutils/pngutils.h"
#if defined(_WIN32)
#include <windows.h>
@@ -97,33 +99,6 @@ static std::unique_ptr<os::OpenGLContext> GL_context = nullptr;
static std::unique_ptr<os::GraphicsOperations> graphic_operations = nullptr;
static os::Viewport* current_viewport = nullptr;
static bool mode_change_func(os::ViewportState state, bool initial)
{
if (initial) {
return false;
}
auto window = os::getMainViewport();
if (window == nullptr) {
return false;
}
window->setState(state);
return true;
}
static auto WindowModeOption = options::OptionBuilder<os::ViewportState>("Graphics.WindowMode", "Window Mode",
"Controls how the game window is created.")
.category("Graphics")
.level(options::ExpertLevel::Beginner)
.values({{os::ViewportState::Fullscreen, "Fullscreen"},
{os::ViewportState::Borderless, "Borderless"},
{os::ViewportState::Windowed, "Windowed"}})
.importance(98)
.default_val(os::ViewportState::Fullscreen)
.change_listener(mode_change_func)
.finish();
void opengl_go_fullscreen()
{
if (Cmdline_fullscreen_window || Cmdline_window || GL_fullscreen || Fred_running)
@@ -879,16 +854,16 @@ int opengl_check_for_errors(const char *err_at)
return num_errors;
}
void opengl_set_vsync(bool enable)
void opengl_set_vsync(int status)
{
if (enable) {
// Try to use adaptive vsync when supported
if (!GL_context->setSwapInterval(-1)) {
GL_context->setSwapInterval(1);
}
} else {
GL_context->setSwapInterval(0);
if ( (status < 0) || (status > 1) ) {
Int3();
return;
}
GL_context->setSwapInterval(status);
GL_CHECK_FOR_ERRORS("end of set_vsync()");
}
std::unique_ptr<os::Viewport> gr_opengl_create_viewport(const os::ViewPortProperties& props) {
@@ -1046,24 +1021,10 @@ int opengl_init_display_device()
attrs.title = Window_title;
}
if (Using_in_game_options) {
switch (WindowModeOption->getValue()) {
case os::ViewportState::Windowed:
// That's the default
break;
case os::ViewportState::Borderless:
attrs.flags.set(os::ViewPortFlags::Borderless);
break;
case os::ViewportState::Fullscreen:
attrs.flags.set(os::ViewPortFlags::Fullscreen);
break;
}
} else {
if (!Cmdline_window && !Cmdline_fullscreen_window) {
attrs.flags.set(os::ViewPortFlags::Fullscreen);
} else if (Cmdline_fullscreen_window) {
attrs.flags.set(os::ViewPortFlags::Borderless);
}
if (!Cmdline_window && ! Cmdline_fullscreen_window) {
attrs.flags.set(os::ViewPortFlags::Fullscreen);
} else if (Cmdline_fullscreen_window) {
attrs.flags.set(os::ViewPortFlags::Borderless);
}
auto viewport = gr_opengl_create_viewport(attrs);
@@ -1536,7 +1497,7 @@ bool gr_opengl_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps)
opengl_post_process_init();
// must be called after extensions are setup
opengl_set_vsync(Gr_enable_vsync);
opengl_set_vsync( !Cmdline_no_vsync );
gr_reset_matrices();
gr_setup_viewport();
@@ -1580,7 +1541,7 @@ bool gr_opengl_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps)
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(( " Post-processing enabled: %s\n", (Cmdline_postprocess) ? "YES" : "NO"));
mprintf(( " Using %s texture filter.\n", (GL_mipmap_filter) ? NOX("trilinear") : NOX("bilinear") ));
mprintf(( " OpenGL Shader Version: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION) ));
@@ -1611,9 +1572,9 @@ bool gr_opengl_is_capable(gr_capability capability)
return Cmdline_height ? true : false;
case CAPABILITY_SOFT_PARTICLES:
case CAPABILITY_DISTORTION:
return Gr_enable_soft_particles && !Cmdline_no_fbo;
return Cmdline_softparticles && !Cmdline_no_fbo;
case CAPABILITY_POST_PROCESSING:
return Gr_post_processing_enabled && !Cmdline_no_fbo;
return Cmdline_postprocess && !Cmdline_no_fbo;
case CAPABILITY_DEFERRED_LIGHTING:
return !Cmdline_no_fbo && !Cmdline_no_deferred_lighting;
case CAPABILITY_SHADOWS:
@@ -1631,20 +1592,16 @@ bool gr_opengl_is_capable(gr_capability capability)
return false;
}
bool gr_opengl_get_property(gr_property prop, void* dest)
{
switch (prop) {
case gr_property::UNIFORM_BUFFER_OFFSET_ALIGNMENT:
*((int*)dest) = GL_state.Constants.GetUniformBufferOffsetAlignment();
return true;
case gr_property::UNIFORM_BUFFER_MAX_SIZE:
*((int*)dest) = GL_state.Constants.GetMaxUniformBlockSize();
return true;
case gr_property::MAX_ANISOTROPY:
*((float*)dest) = GL_state.Constants.GetMaxAnisotropy();
return true;
default:
return false;
bool gr_opengl_get_property(gr_property prop, void* dest) {
switch(prop) {
case gr_property::UNIFORM_BUFFER_OFFSET_ALIGNMENT:
*((int*)dest) = GL_state.Constants.GetUniformBufferOffsetAlignment();
return true;
case gr_property::UNIFORM_BUFFER_MAX_SIZE:
*((int*)dest) = GL_state.Constants.GetMaxUniformBlockSize();
return true;
default:
return false;
}
}
@@ -1722,8 +1679,7 @@ DCF(ogl_anisotropy, "toggles anisotropic filtering")
if (dc_optional_string_either("help", "--help")) {
dc_printf("Sets OpenGL anisotropic filtering level.\n");
dc_printf("GL_anisotropy [int] Valid values are 0 to %i. 0 turns off anisotropic filtering.\n",
(int)GL_state.Constants.GetMaxAnisotropy());
dc_printf("GL_anisotropy [int] Valid values are 0 to %i. 0 turns off anisotropic filtering.\n", (int)opengl_get_max_anisotropy());
process = false;
}
+3 -3
View File
@@ -115,7 +115,7 @@ void gr_opengl_deferred_lighting_finish()
GL_state.Texture.Enable(1, GL_TEXTURE_2D, Scene_normal_texture);
GL_state.Texture.Enable(2, GL_TEXTURE_2D, Scene_position_texture);
GL_state.Texture.Enable(3, GL_TEXTURE_2D, Scene_specular_texture);
if (Shadow_quality != ShadowQuality::Disabled) {
if (Cmdline_shadow_quality) {
GL_state.Texture.Enable(4, GL_TEXTURE_2D_ARRAY, Shadow_map_texture);
}
@@ -133,7 +133,7 @@ void gr_opengl_deferred_lighting_finish()
GR_DEBUG_SCOPE("Build buffer data");
auto header = uniformAligner.getHeader<deferred_global_data>();
if (Shadow_quality != ShadowQuality::Disabled) {
if (Cmdline_shadow_quality) {
// Avoid this overhead when we are not going to use these values
header->shadow_mv_matrix = Shadow_view_matrix;
for (size_t i = 0; i < MAX_SHADOW_CASCADES; ++i) {
@@ -173,7 +173,7 @@ void gr_opengl_deferred_lighting_finish()
switch (l.type) {
case Light_Type::Directional:
if (Shadow_quality != ShadowQuality::Disabled) {
if (Cmdline_shadow_quality) {
light_data->enable_shadows = first_directional ? 1 : 0;
}
vec4 light_dir;
+10 -10
View File
@@ -88,9 +88,9 @@ void opengl_setup_scene_textures()
Scene_texture_initialized = 0;
if ( Cmdline_no_fbo ) {
Gr_post_processing_enabled = false;
Gr_enable_soft_particles = false;
Gr_framebuffer_effects = {};
Cmdline_postprocess = 0;
Cmdline_softparticles = 0;
Cmdline_fb_explosions = 0;
Scene_ldr_texture = 0;
Scene_color_texture = 0;
@@ -338,13 +338,13 @@ void opengl_setup_scene_textures()
//glDeleteTextures(1, &Scene_fxaa_output_texture);
//Scene_fxaa_output_texture = 0;
Gr_post_processing_enabled = false;
Gr_enable_soft_particles = false;
Cmdline_postprocess = 0;
Cmdline_softparticles = 0;
return;
}
//Setup thruster distortion framebuffer
if (Gr_framebuffer_effects.any_set())
if (Cmdline_fb_thrusters || Cmdline_fb_explosions)
{
glGenFramebuffers(1, &Distortion_framebuffer);
GL_state.BindFrameBuffer(Distortion_framebuffer);
@@ -392,8 +392,8 @@ void opengl_setup_scene_textures()
Scene_color_texture = 0;
Scene_depth_texture = 0;
Gr_post_processing_enabled = false;
Gr_enable_soft_particles = false;
Cmdline_postprocess = 0;
Cmdline_softparticles = 0;
return;
}
@@ -510,7 +510,7 @@ void gr_opengl_scene_texture_begin()
Scene_framebuffer_in_frame = true;
if ( Gr_post_processing_enabled && !PostProcessing_override ) {
if ( Cmdline_postprocess && !PostProcessing_override ) {
High_dynamic_range = true;
}
}
@@ -533,7 +533,7 @@ void gr_opengl_scene_texture_end()
time_buffer = 0.0f;
}
if ( Gr_post_processing_enabled && !PostProcessing_override ) {
if ( Cmdline_postprocess && !PostProcessing_override ) {
gr_post_process_end();
} else {
GR_DEBUG_SCOPE("Draw scene texture");
+54 -18
View File
@@ -21,8 +21,10 @@ extern bool PostProcessing_override;
extern int opengl_check_framebuffer();
//Needed to track where the FXAA shaders are
size_t fxaa_shader_id;
//In case we don't find the shaders at all, this override is needed
bool fxaa_unavailable = false;
int Fxaa_preset_last_frame;
bool zbuffer_saved = false;
// lightshaft parameters
@@ -225,11 +227,8 @@ void gr_opengl_post_process_begin()
}
void recompile_fxaa_shader() {
if (!gr_is_fxaa_mode(Gr_aa_mode)) {
return;
}
mprintf(("Recompiling FXAA shader...\n"));
mprintf(("Recompiling FXAA shader with preset %d\n", Cmdline_fxaa_preset));
// start recompile by grabbing deleting the current shader we have, assuming it's already created
opengl_delete_shader( gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_FXAA, 0) );
@@ -237,7 +236,7 @@ void recompile_fxaa_shader() {
// then recreate it again. shader loading code will be updated with the new FXAA presets
gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_FXAA, 0);
Gr_aa_mode_last_frame = Gr_aa_mode;
Fxaa_preset_last_frame = Cmdline_fxaa_preset;
}
void opengl_post_pass_fxaa() {
@@ -245,7 +244,7 @@ void opengl_post_pass_fxaa() {
TRACE_SCOPE(tracing::FXAA);
//If the preset changed, recompile the shader
if (Gr_aa_mode_last_frame != Gr_aa_mode) {
if (Fxaa_preset_last_frame != Cmdline_fxaa_preset) {
recompile_fxaa_shader();
}
@@ -363,7 +362,7 @@ void gr_opengl_post_process_end()
opengl_post_pass_tonemap();
// Do FXAA
if (gr_is_fxaa_mode(Gr_aa_mode) && !fxaa_unavailable && !GL_rendering_to_texture) {
if (Cmdline_fxaa && !fxaa_unavailable && !GL_rendering_to_texture) {
opengl_post_pass_fxaa();
}
@@ -729,26 +728,63 @@ void opengl_post_shader_header(SCP_stringstream &sflags, shader_type shader_t, i
sflags << "#define FXAA_GATHER4_ALPHA 1\n";
}
switch (Gr_aa_mode) {
case AntiAliasMode::None:
switch (Cmdline_fxaa_preset) {
case 0:
sflags << "#define FXAA_QUALITY_PRESET 10\n";
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/6.0)\n";
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/12.0)\n";
sflags << "#define FXAA_QUALITY_SUBPIX 0.33\n";
break;
case AntiAliasMode::FXAA_Low:
case 1:
sflags << "#define FXAA_QUALITY_PRESET 11\n";
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/7.0)\n";
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/14.0)\n";
sflags << "#define FXAA_QUALITY_SUBPIX 0.33\n";
break;
case 2:
sflags << "#define FXAA_QUALITY_PRESET 12\n";
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/8.0)\n";
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/16.0)\n";
sflags << "#define FXAA_QUALITY_SUBPIX 0.33\n";
break;
case AntiAliasMode::FXAA_Medium:
case 3:
sflags << "#define FXAA_QUALITY_PRESET 13\n";
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/9.0)\n";
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/18.0)\n";
sflags << "#define FXAA_QUALITY_SUBPIX 0.33\n";
break;
case 4:
sflags << "#define FXAA_QUALITY_PRESET 14\n";
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/10.0)\n";
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/20.0)\n";
sflags << "#define FXAA_QUALITY_SUBPIX 0.33\n";
break;
case 5:
sflags << "#define FXAA_QUALITY_PRESET 25\n";
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/11.0)\n";
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/22.0)\n";
sflags << "#define FXAA_QUALITY_SUBPIX 0.33\n";
break;
case 6:
sflags << "#define FXAA_QUALITY_PRESET 26\n";
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/12.0)\n";
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/24.0)\n";
sflags << "#define FXAA_QUALITY_SUBPIX 0.33\n";
break;
case AntiAliasMode::FXAA_High:
case 7:
sflags << "#define FXAA_PC 1\n";
sflags << "#define FXAA_QUALITY_PRESET 27\n";
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/13.0)\n";
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/26.0)\n";
sflags << "#define FXAA_QUALITY_SUBPIX 0.33\n";
break;
case 8:
sflags << "#define FXAA_QUALITY_PRESET 28\n";
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/14.0)\n";
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/28.0)\n";
sflags << "#define FXAA_QUALITY_SUBPIX 0.33\n";
break;
case 9:
sflags << "#define FXAA_QUALITY_PRESET 39\n";
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/15.0)\n";
sflags << "#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/32.0)\n";
@@ -785,7 +821,7 @@ bool opengl_post_init_shaders()
if ( gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_FXAA, 0) < 0 ||
gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_FXAA_PREPASS, 0) < 0 ) {
Gr_aa_mode = AntiAliasMode::None;
Cmdline_fxaa = false;
fxaa_unavailable = true;
mprintf(("Error while compiling FXAA shaders. FXAA will be unavailable.\n"));
}
@@ -882,11 +918,11 @@ void opengl_post_process_init()
//We need to read the tbl first. This is mostly for FRED's benefit, as otherwise the list of post effects for the sexp doesn't get updated.
if ( !opengl_post_init_table() ) {
mprintf((" Unable to read post-processing table! Disabling post-processing...\n\n"));
Gr_post_processing_enabled = false;
Cmdline_postprocess = 0;
return;
}
if ( !Gr_post_processing_enabled ) {
if ( !Cmdline_postprocess ) {
return;
}
@@ -895,19 +931,19 @@ void opengl_post_process_init()
}
if ( Cmdline_no_fbo ) {
Gr_post_processing_enabled = false;
Cmdline_postprocess = 0;
return;
}
if ( !opengl_post_init_shaders() ) {
mprintf((" Unable to initialize post-processing shaders! Disabling post-processing...\n\n"));
Gr_post_processing_enabled = false;
Cmdline_postprocess = 0;
return;
}
if ( !opengl_post_init_framebuffer() ) {
mprintf((" Unable to initialize post-processing framebuffer! Disabling post-processing...\n\n"));
Gr_post_processing_enabled = false;
Cmdline_postprocess = 0;
return;
}
+14
View File
@@ -883,6 +883,20 @@ static void opengl_purge_shader_cache_type(const char* ext) {
SCP_string filter("*.");
filter += ext;
// Previously the cache files were stored in the mod directory. Since we have a better system now, those files
// should be cleaned out. This is only needed if we have a mod directory since otherwise we would delete the actual
// cache files
if (Cmdline_mod != nullptr && strlen(Cmdline_mod) > 0) {
SCP_vector<SCP_string> cache_files;
cf_get_file_list(cache_files, CF_TYPE_CACHE, filter.c_str(), CF_SORT_NONE, nullptr,
CF_LOCATION_TYPE_PRIMARY_MOD | CF_LOCATION_TYPE_SECONDARY_MODS);
for (auto& file : cache_files) {
cf_delete((file + "." + ext).c_str(), CF_TYPE_CACHE,
CF_LOCATION_TYPE_PRIMARY_MOD | CF_LOCATION_TYPE_SECONDARY_MODS);
}
}
SCP_vector<SCP_string> cache_files;
SCP_vector<file_list_info> file_info;
cf_get_file_list(cache_files, CF_TYPE_CACHE, filter.c_str(), CF_SORT_NONE, &file_info,
+16 -19
View File
@@ -718,8 +718,10 @@ void opengl_array_state::VertexAttribPointer(GLuint index, GLint size, GLenum ty
void opengl_array_state::ResetVertexAttribs()
{
for (auto &it : vertex_attrib_units) {
DisableVertexAttrib(it.first);
SCP_map<GLuint, opengl_vertex_attrib_unit>::iterator it;
for ( it = vertex_attrib_units.begin(); it != vertex_attrib_units.end(); ++it ) {
DisableVertexAttrib(it->first);
}
vertex_attrib_units.clear();
@@ -731,17 +733,19 @@ void opengl_array_state::BindPointersBegin()
client_texture_units[i].used_for_draw = false;
}
for (auto &it : vertex_attrib_units) {
it.second.used_for_draw = false;
SCP_map<GLuint, opengl_vertex_attrib_unit>::iterator it;
for (it = vertex_attrib_units.begin(); it != vertex_attrib_units.end(); ++it) {
it->second.used_for_draw = false;
}
}
void opengl_array_state::BindPointersEnd()
{
for (auto &it : vertex_attrib_units) {
if (!it.second.used_for_draw) {
DisableVertexAttrib(it.first);
}
SCP_map<GLuint, opengl_vertex_attrib_unit>::iterator it;
for (it = vertex_attrib_units.begin(); it != vertex_attrib_units.end(); ++it) {
if ( !it->second.used_for_draw ) DisableVertexAttrib(it->first);
}
}
@@ -760,8 +764,10 @@ void opengl_array_state::BindArrayBuffer(GLuint id)
client_texture_units[i].reset_ptr = true;
}
for (auto &it : vertex_attrib_units) {
it.second.reset_ptr = true;
SCP_map<GLuint,opengl_vertex_attrib_unit>::iterator it;
for ( it = vertex_attrib_units.begin(); it != vertex_attrib_units.end(); ++it ) {
it->second.reset_ptr = true;
}
}
@@ -843,12 +849,6 @@ void opengl_constant_state::init() {
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &_uniform_buffer_offset_alignment);
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &_max_uniform_block_size);
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &_max_uniform_block_bindings);
if (GLAD_GL_EXT_texture_filter_anisotropic) {
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &_max_anisotropy);
} else {
_max_anisotropy = -1.0f;
}
}
GLint opengl_constant_state::GetUniformBufferOffsetAlignment() {
return _uniform_buffer_offset_alignment;
@@ -859,9 +859,6 @@ GLint opengl_constant_state::GetMaxUniformBlockSize() {
GLint opengl_constant_state::GetMaxUniformBlockBindings() {
return _max_uniform_block_bindings;
}
GLfloat opengl_constant_state::GetMaxAnisotropy() {
return _max_anisotropy;
}
void gr_opengl_clear_states()
{
-3
View File
@@ -178,7 +178,6 @@ class opengl_constant_state {
GLint _uniform_buffer_offset_alignment;
GLint _max_uniform_block_size;
GLint _max_uniform_block_bindings;
GLfloat _max_anisotropy;
public:
opengl_constant_state();
@@ -190,8 +189,6 @@ class opengl_constant_state {
GLint GetMaxUniformBlockSize();
GLint GetMaxUniformBlockBindings();
GLfloat GetMaxAnisotropy();
};
class opengl_state
+24 -63
View File
@@ -12,16 +12,15 @@
#endif
#define BMPMAN_INTERNAL
#include "gropenglstate.h"
#include "gropengltexture.h"
#include "bmpman/bm_internal.h"
#include "bmpman/bmpman.h"
#include "cmdline/cmdline.h"
#include "ddsutils/ddsutils.h"
#include "globalincs/systemvars.h"
#include "graphics/grinternal.h"
#include "gropenglstate.h"
#include "gropengltexture.h"
#include "math/vecmat.h"
#include "options/Option.h"
#include "osapi/osregistry.h"
matrix4 GL_texture_matrix;
@@ -36,6 +35,7 @@ int GL_last_detail = -1;
GLint GL_supported_texture_units = 2;
int GL_should_preload = 0;
GLfloat GL_anisotropy = 1.0f;
GLfloat GL_max_anisotropy = -1.0f;
int GL_mipmap_filter = 0;
GLenum GL_texture_target = GL_TEXTURE_2D;
GLenum GL_texture_face = GL_TEXTURE_2D;
@@ -49,57 +49,6 @@ extern int CLOAKMAP;
extern int ENVMAP;
extern int Interp_multitex_cloakmap;
static SCP_vector<float> anisotropic_value_enumerator()
{
float max;
if (!gr_get_property(gr_property::MAX_ANISOTROPY, &max)) {
return SCP_vector<float>();
}
if (max <= 2.0f) {
return SCP_vector<float>();
}
SCP_vector<float> out;
// We assume here that the anisotropy levels are powers of two...
float current = 1.0f;
while (current <= max) {
out.push_back(current);
current *= 2.0f;
}
return out;
}
static SCP_string anisotropic_display(float val)
{
if (val < 2.0f) {
return "None";
}
SCP_string out;
sprintf(out, "%.0fx", val);
return out;
}
static float anisotropic_default()
{
float max;
if (!gr_get_property(gr_property::MAX_ANISOTROPY, &max)) {
return 1.0f;
}
return max;
}
static auto AnisotropyOption =
options::OptionBuilder<float>("Graphics.Anisotropy", "Anisotropic filtering",
"Controls the amount of anisotropic filtering of the textures.")
.enumerator(anisotropic_value_enumerator)
.category("Graphics")
.display(anisotropic_display)
.default_func(anisotropic_default)
.level(options::ExpertLevel::Advanced)
.importance(78)
.finish();
// forward declarations
int opengl_free_texture(tcache_slot_opengl *t);
@@ -123,6 +72,22 @@ void opengl_set_modulate_tex_env()
GL_CHECK_FOR_ERRORS("end of set_modulate_tex_env()");
}
GLfloat opengl_get_max_anisotropy()
{
if ( !GLAD_GL_EXT_texture_filter_anisotropic ) {
return 0.0f;
}
if ( GL_max_anisotropy < 0.0f ) {
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &GL_max_anisotropy);
}
// the spec says that it should be a minimum of 2.0
Assert( GL_max_anisotropy >= 2.0f );
return GL_max_anisotropy;
}
void opengl_set_texture_target( GLenum target )
{
GL_texture_target = target;
@@ -166,17 +131,13 @@ void opengl_tcache_init()
// anisotropy
if ( GLAD_GL_EXT_texture_filter_anisotropic ) {
// set max value first thing
GL_anisotropy = GL_state.Constants.GetMaxAnisotropy();
GL_anisotropy = opengl_get_max_anisotropy();
if (Using_in_game_options) {
GL_anisotropy = AnisotropyOption->getValue();
} else {
// now for the user setting
if (Cmdline_aniso_level != 0)
GL_anisotropy = (GLfloat)Cmdline_aniso_level;
}
// now for the user setting
if (Cmdline_aniso_level != 0)
GL_anisotropy = (GLfloat) Cmdline_aniso_level;
CLAMP(GL_anisotropy, 1.0f, GL_state.Constants.GetMaxAnisotropy());
CLAMP(GL_anisotropy, 1.0f, GL_max_anisotropy);
}
Assert( GL_supported_texture_units >= 2 );
+1
View File
@@ -80,6 +80,7 @@ void opengl_tcache_frame();
void opengl_set_additive_tex_env();
void opengl_set_modulate_tex_env();
void opengl_preload_init();
GLfloat opengl_get_max_anisotropy();
void opengl_kill_render_target(bitmap_slot* slot);
int opengl_make_render_target(int handle, int *w, int *h, int *bpp, int *mm_lvl, int flags);
int opengl_set_render_target(int slot, int face = -1, int is_static = 0);
+18 -37
View File
@@ -12,29 +12,28 @@
#include <windows.h>
#endif
#include "ShaderProgram.h"
#include "gropengldeferred.h"
#include "gropengldraw.h"
#include "gropenglshader.h"
#include "gropenglstate.h"
#include "gropengltexture.h"
#include "gropengltnl.h"
#include "cmdline/cmdline.h"
#include "def_files/def_files.h"
#include "globalincs/alphacolors.h"
#include "globalincs/systemvars.h"
#include "graphics/2d.h"
#include "graphics/grinternal.h"
#include "graphics/light.h"
#include "graphics/material.h"
#include "graphics/matrix.h"
#include "graphics/shadows.h"
#include "graphics/grinternal.h"
#include "gropengldraw.h"
#include "gropenglshader.h"
#include "gropenglstate.h"
#include "gropengltexture.h"
#include "gropengldeferred.h"
#include "gropengltnl.h"
#include "lighting/lighting.h"
#include "math/vecmat.h"
#include "options/Option.h"
#include "particle/particle.h"
#include "render/3d.h"
#include "weapon/trails.h"
#include "particle/particle.h"
#include "graphics/shadows.h"
#include "graphics/material.h"
#include "graphics/light.h"
#include "ShaderProgram.h"
extern int GLOWMAP;
extern int CLOAKMAP;
@@ -62,7 +61,6 @@ GLint GL_max_elements_indices = 4096;
GLuint Shadow_map_texture = 0;
GLuint Shadow_map_depth_texture = 0;
GLuint shadow_fbo = 0;
int Shadow_texture_size = 0;
bool Rendering_to_shadow_map = false;
int Transform_buffer_handle = -1;
@@ -457,7 +455,6 @@ static bool opengl_init_shadow_framebuffer(int size, GLenum color_format)
if (status == GL_FRAMEBUFFER_COMPLETE) {
// Everything is fine
mprintf(("Shadow framebuffer created successfully.\n"));
Shadow_texture_size = size;
return true;
}
@@ -494,30 +491,13 @@ void opengl_tnl_init()
{
Transform_buffer_handle = opengl_create_texture_buffer_object();
if (Shadow_quality != ShadowQuality::Disabled) {
int size;
switch (Shadow_quality) {
case ShadowQuality::Low:
size = 512;
break;
case ShadowQuality::Medium:
size = 1024;
break;
case ShadowQuality::High:
size = 2048;
break;
case ShadowQuality::Ultra:
size = 4096;
break;
default:
size = 256;
break;
}
if (Cmdline_shadow_quality) {
int size = (Cmdline_shadow_quality == 2 ? 1024 : 512);
if (!opengl_init_shadow_framebuffer(size, GL_RGBA32F)) {
if (!opengl_init_shadow_framebuffer(size, GL_RGBA16F)) {
mprintf(("Failed to create either 32 or 16-bit color shadow framebuffer. Disabling shadow support.\n"));
Shadow_quality = ShadowQuality::Disabled;
Cmdline_shadow_quality = 0;
}
}
}
@@ -648,7 +628,7 @@ extern bool gr_htl_projection_matrix_set;
void gr_opengl_shadow_map_start(matrix4 *shadow_view_matrix, const matrix *light_orient)
{
if (Shadow_quality == ShadowQuality::Disabled)
if ( !Cmdline_shadow_quality )
return;
GL_state.PushFramebufferState();
@@ -672,7 +652,8 @@ void gr_opengl_shadow_map_start(matrix4 *shadow_view_matrix, const matrix *light
*shadow_view_matrix = gr_view_matrix;
glViewport(0, 0, Shadow_texture_size, Shadow_texture_size);
int size = (Cmdline_shadow_quality == 2 ? 1024 : 512);
glViewport(0, 0, size, size);
}
void gr_opengl_shadow_map_end()
+5 -27
View File
@@ -1,22 +1,21 @@
/*
* Copyright (C) Freespace Open 2013. All rights reserved.
*
* All source code herein is the property of Freespace Open. You may not sell
* or otherwise commercially exploit the source or things you created based on the
* All source code herein is the property of Freespace Open. You may not sell
* or otherwise commercially exploit the source or things you created based on the
* source.
*
*/
*/
#include "graphics/shadows.h"
#include "asteroid/asteroid.h"
#include "cmdline/cmdline.h"
#include "debris/debris.h"
#include "graphics/shadows.h"
#include "graphics/matrix.h"
#include "lighting/lighting.h"
#include "math/vecmat.h"
#include "model/model.h"
#include "model/modelrender.h"
#include "options/Option.h"
#include "render/3d.h"
#include "tracing/tracing.h"
@@ -28,27 +27,6 @@ float Shadow_cascade_distances[MAX_SHADOW_CASCADES];
light_frustum_info Shadow_frustums[MAX_SHADOW_CASCADES];
ShadowQuality Shadow_quality;
auto ShadowQualityOption =
options::OptionBuilder<ShadowQuality>("Graphics.Shadows", "Shadow Quality", "The quality of the shadows")
.values({{ShadowQuality::Disabled, "Disabled"},
{ShadowQuality::Low, "Low"},
{ShadowQuality::Medium, "Medium"},
{ShadowQuality::High, "High"},
{ShadowQuality::Ultra, "Ultra"}})
.change_listener([](ShadowQuality val, bool initial) {
if (initial) {
Shadow_quality = val;
}
return initial; // No dynamic changes implemented
})
.level(options::ExpertLevel::Advanced)
.category("Graphics")
.default_val(ShadowQuality::Disabled)
.importance(80)
.finish();
bool shadows_obj_in_frustum(object *objp, matrix *light_orient, vec3d *min, vec3d *max)
{
vec3d pos, pos_rot;
@@ -424,7 +402,7 @@ void shadows_render_all(float fov, matrix *eye_orient, vec3d *eye_pos)
return;
}
if (Shadow_quality == ShadowQuality::Disabled) {
if (!Cmdline_shadow_quality) {
return;
}
+1 -5
View File
@@ -25,10 +25,6 @@ struct light_frustum_info
float start_dist;
};
enum class ShadowQuality { Disabled = 0, Low = 1, Medium = 2, High = 3, Ultra = 4 };
extern ShadowQuality Shadow_quality;
extern matrix4 Shadow_view_matrix;
extern matrix4 Shadow_proj_matrix[MAX_SHADOW_CASCADES];
extern float Shadow_cascade_distances[MAX_SHADOW_CASCADES];
@@ -40,4 +36,4 @@ void shadows_render_all(float fov, matrix *eye_orient, vec3d *eye_pos);
matrix shadows_start_render(matrix *eye_orient, vec3d *eye_pos, float fov, float aspect, float veryneardist, float neardist, float middist, float fardist);
void shadows_end_render();
#endif
#endif
+9 -43
View File
@@ -5,7 +5,7 @@
* or otherwise commercially exploit the source or things you created based on the
* source.
*
*/
*/
#include "ai/aigoals.h"
@@ -23,10 +23,9 @@
#include "hud/hudets.h"
#include "hud/hudlock.h"
#include "hud/hudmessage.h"
#include "hud/hudnavigation.h" //kazan
#include "hud/hudnavigation.h" //kazan
#include "hud/hudobserver.h"
#include "hud/hudreticle.h"
#include "hud/hudscripting.h"
#include "hud/hudshield.h"
#include "hud/hudsquadmsg.h"
#include "hud/hudtarget.h"
@@ -51,7 +50,6 @@
#include "radar/radar.h"
#include "radar/radarsetup.h"
#include "render/3d.h"
#include "scripting/scripting.h"
#include "ship/ship.h"
#include "starfield/supernova.h"
#include "weapon/emp.h"
@@ -248,7 +246,7 @@ static int Damage_flash_timer;
HudGauge::HudGauge():
base_w(0), base_h(0), gauge_config(-1), font_num(font::FONT1), lock_color(false), sexp_lock_color(false), reticle_follow(false),
active(false), off_by_default(false), sexp_override(false), pop_up(false), disabled_views(0), only_render_in_chase_view(false), custom_gauge(false),
active(false), off_by_default(false), sexp_override(false), pop_up(false), disabled_views(0), custom_gauge(false),
texture_target(-1), canvas_w(-1), canvas_h(-1), target_w(-1), target_h(-1)
{
position[0] = 0;
@@ -273,7 +271,7 @@ texture_target(-1), canvas_w(-1), canvas_h(-1), target_w(-1), target_h(-1)
HudGauge::HudGauge(int _gauge_object, int _gauge_config, bool _slew, bool _message, int _disabled_views, int r, int g, int b):
base_w(0), base_h(0), gauge_config(_gauge_config), gauge_object(_gauge_object), font_num(font::FONT1), lock_color(false), sexp_lock_color(false),
reticle_follow(_slew), active(false), off_by_default(false), sexp_override(false), pop_up(false), message_gauge(_message),
disabled_views(_disabled_views), only_render_in_chase_view(false), custom_gauge(false), textoffset_x(0), textoffset_y(0), texture_target(-1),
disabled_views(_disabled_views), custom_gauge(false), textoffset_x(0), textoffset_y(0), texture_target(-1),
canvas_w(-1), canvas_h(-1), target_w(-1), target_h(-1)
{
Assert(gauge_config <= NUM_HUD_GAUGES && gauge_config >= 0);
@@ -309,8 +307,8 @@ canvas_w(-1), canvas_h(-1), target_w(-1), target_h(-1)
HudGauge::HudGauge(int _gauge_config, bool _slew, int r, int g, int b, char* _custom_name, char* _custom_text, char* frame_fname, int txtoffset_x, int txtoffset_y):
base_w(0), base_h(0), gauge_config(_gauge_config), gauge_object(HUD_OBJECT_CUSTOM), font_num(font::FONT1), lock_color(false), sexp_lock_color(false),
reticle_follow(_slew), active(false), off_by_default(false), sexp_override(false), pop_up(false), message_gauge(false),
disabled_views(VM_EXTERNAL | VM_DEAD_VIEW | VM_WARP_CHASE | VM_PADLOCK_ANY), only_render_in_chase_view(false), custom_gauge(true), textoffset_x(txtoffset_x),
textoffset_y(txtoffset_y), texture_target(-1), canvas_w(-1), canvas_h(-1), target_w(-1), target_h(-1)
disabled_views(VM_EXTERNAL | VM_DEAD_VIEW | VM_WARP_CHASE | VM_PADLOCK_ANY), custom_gauge(true), textoffset_x(txtoffset_x),
textoffset_y(txtoffset_y), texture_target(-1), canvas_w(-1), canvas_h(-1), target_w(-1), target_h(-1)
{
position[0] = 0;
position[1] = 0;
@@ -548,11 +546,6 @@ void HudGauge::initRenderStatus(bool do_render)
off_by_default = !do_render;
}
void HudGauge::initChase_view_only(bool chase_view_only)
{
only_render_in_chase_view = chase_view_only;
}
bool HudGauge::isOffbyDefault()
{
return off_by_default;
@@ -924,7 +917,7 @@ void HudGauge::renderRect(int x, int y, int w, int h)
gr_reset_screen_scale();
}
void HudGauge::renderCircle(int x, int y, int diameter, bool filled)
void HudGauge::renderCircle(int x, int y, int diameter)
{
int nx = 0, ny = 0;
@@ -942,12 +935,8 @@ void HudGauge::renderCircle(int x, int y, int diameter, bool filled)
gr_set_screen_scale(base_w, base_h);
}
}
if (filled) {
gr_circle(x + nx, y + ny, diameter);
} else {
gr_unfilled_circle(x + nx, y + ny, diameter);
}
gr_circle(x+nx, y+ny, diameter);
gr_reset_screen_scale();
}
@@ -1093,10 +1082,6 @@ bool HudGauge::canRender()
return false;
}
if ((Viewer_mode & (VM_CHASE)) == 0 && only_render_in_chase_view) {
return false;
}
if(pop_up) {
if(!popUpActive()) {
return false;
@@ -1237,25 +1222,6 @@ void HUD_init()
default_hud_gauges[j]->resetTimers();
default_hud_gauges[j]->updateSexpOverride(false);
}
Script_system.OnStateDestroy.add(hud_scripting_close);
}
void hud_scripting_close(lua_State*) {
// Clean up Lua references so that we don't have dangling references on to the lua state in the HUD gauges
for (auto it = Ship_info.begin(); it != Ship_info.end(); ++it) {
for (const auto& gauge : it->hud_gauges) {
if (gauge->getObjectType() == HUD_OBJECT_SCRIPTING) {
static_cast<HudGaugeScripting*>(gauge.get())->setRenderFunction(luacpp::LuaFunction());
}
}
}
for (const auto& gauge : default_hud_gauges) {
if (gauge->getObjectType() == HUD_OBJECT_SCRIPTING) {
static_cast<HudGaugeScripting*>(gauge.get())->setRenderFunction(luacpp::LuaFunction());
}
}
}
/**
@@ -3945,7 +3911,7 @@ void HudGaugeSupernova::render(float /*frametime*/)
if (Lcl_pl) {
renderPrintf(position[0], position[1], "Wybuch supernowej: %.2f s", time_left);
} else {
renderPrintf(position[0], position[1], XSTR( "Supernova Warning: %.2f s", 1639), time_left);
renderPrintf(position[0], position[1], "Supernova Warning: %.2f s", time_left);
}
}
+2 -4
View File
@@ -110,7 +110,6 @@ extern int Hud_max_targeting_range;
void HUD_init_colors();
void HUD_init();
void hud_scripting_close(lua_State*);
void hud_close();
void hud_level_close();
void hud_update_frame(float frametime); // updates hud systems not dependant on rendering
@@ -224,7 +223,6 @@ protected:
int flash_duration;
int flash_next;
bool flash_status;
bool only_render_in_chase_view;
// custom gauge specific stuff
bool custom_gauge;
@@ -270,7 +268,7 @@ public:
void updateActive(bool show);
void updatePopUp(bool pop_up_flag);
void updateSexpOverride(bool sexp);
void initChase_view_only(bool chase_view_only);
// SEXP interfacing functions
// For flashing gauges in training missions
@@ -318,7 +316,7 @@ public:
void renderLine(int x1, int y1, int x2, int y2);
void renderGradientLine(int x1, int y1, int x2, int y2);
void renderRect(int x, int y, int w, int h);
void renderCircle(int x, int y, int diameter, bool filled = true);
void renderCircle(int x, int y, int diameter);
void unsize(int *x, int *y);
void unsize(float *x, float *y);
+1 -27
View File
@@ -95,32 +95,6 @@ void parse_ssm(const char *filename)
s.max_count = -1;
}
if (optional_string("+WarpEffect:")) {
int temp;
if (stuff_int_optional(&temp) != 2) {
// We have a string to parse instead.
char unique_id[NAME_LENGTH];
memset(unique_id, 0, NAME_LENGTH);
stuff_string(unique_id, F_NAME, NAME_LENGTH);
int fireball_type = fireball_info_lookup(unique_id);
if (fireball_type < 0) {
error_display(1, "Unknown fireball [%s] to use as warp effect for SSM strike [%s]", unique_id, s.name);
s.fireball_idx = FIREBALL_WARP;
} else {
s.fireball_idx = fireball_type;
}
} else {
if ((temp < 0) || (temp >= Num_fireball_types)) {
error_display(1, "Fireball index [%d] out of range (should be 0-%d) for SSM strike [%s]", temp, Num_fireball_types - 1, s.name);
s.fireball_idx = FIREBALL_WARP;
} else {
s.fireball_idx = temp;
}
}
} else {
s.fireball_idx = FIREBALL_WARP;
}
required_string("+WarpRadius:");
stuff_float(&s.warp_radius);
@@ -448,7 +422,7 @@ void ssm_process()
vm_vec_sub(&temp, &moveup->sinfo.target->pos, &moveup->sinfo.start_pos[idx]);
vm_vec_normalize(&temp);
vm_vector_2_matrix(&orient, &temp, NULL, NULL);
moveup->fireballs[idx] = fireball_create(&moveup->sinfo.start_pos[idx], si->fireball_idx, FIREBALL_WARP_EFFECT, -1, si->warp_radius, false, &vmd_zero_vector, si->warp_time, 0, &orient);
moveup->fireballs[idx] = fireball_create(&moveup->sinfo.start_pos[idx], FIREBALL_WARP, FIREBALL_WARP_EFFECT, -1, si->warp_radius, false, &vmd_zero_vector, si->warp_time, 0, &orient);
}
}
}
+1 -2
View File
@@ -30,7 +30,6 @@ typedef struct ssm_info {
int count; // # of missiles in this type of strike
int max_count; // Maximum # of missiles in this type of strike (-1 for no variance)
int weapon_info_index; // missile type
int fireball_idx; // Type of fireball to use for warp effect (defaults to FIREBALL_WARP)
float warp_radius; // radius of associated warp effect
float warp_time; // how long the warp effect lasts
float radius; // radius around the target ship
@@ -50,7 +49,7 @@ typedef struct ssm_firing_info {
SCP_vector<vec3d> start_pos; // start positions
int count; // The ssm_info count may be variable; this stores the actual number of projectiles for this strike.
size_t ssm_index; // index into ssm_info array
size_t ssm_index; // index info ssm_info array
class object* target; // target for the strike
int ssm_team; // team that fired the ssm.
float duration; // how far into the warp effect to fire
-46
View File
@@ -19,7 +19,6 @@
#include "hud/hudmessage.h"
#include "hud/hudparse.h" //Duh.
#include "hud/hudreticle.h"
#include "hud/hudscripting.h"
#include "hud/hudshield.h"
#include "hud/hudsquadmsg.h"
#include "hud/hudtarget.h"
@@ -50,8 +49,6 @@ int Force_scaling_above_res_global[2] = {-1, -1};
int Hud_font = -1;
bool Chase_view_only_ex = false;
//WARNING: If you add gauges to this array, make sure to bump num_default_gauges!
int num_default_gauges = 42;
static int retail_gauges[] = {
@@ -176,7 +173,6 @@ void parse_hud_gauges_tbl(const char *filename)
color *hud_clr_p = NULL;
color *ship_clr_p = NULL;
bool scale_gauge = true;
bool chase_view_only = false;
try
{
@@ -199,11 +195,6 @@ void parse_hud_gauges_tbl(const char *filename)
Hud_font = font::parse_font();
}
if (optional_string("$Chase View Only:")) {
stuff_boolean(&chase_view_only);
Chase_view_only_ex = chase_view_only;
}
if(optional_string("$Max Directives:")) {
stuff_int(&Max_directives);
}
@@ -318,10 +309,6 @@ void parse_hud_gauges_tbl(const char *filename)
if (optional_string("$Font:")) {
ship_font = font::parse_font();
}
if (optional_string("$Chase View Only:")) {
stuff_boolean(&chase_view_only);
}
}
else {
// can't find ship class. move on.
@@ -357,9 +344,6 @@ void parse_hud_gauges_tbl(const char *filename)
if (optional_string("$Font:")) {
ship_font = font::parse_font();
}
if (optional_string("$Chase View Only:")) {
stuff_boolean(&chase_view_only);
}
break;
default:
// No particular ship. -1 for default HUD configuration.
@@ -465,7 +449,6 @@ void parse_hud_gauges_tbl(const char *filename)
memcpy(settings.force_scaling_above_res, force_scaling_above_res, sizeof(settings.force_scaling_above_res));
settings.ship_idx = &ship_classes;
settings.use_clr = use_clr_p;
settings.chase_view_only = chase_view_only;
// if "default" is specified, then the base resolution is {-1, -1},
// indicating GR_640 or GR_1024 to the handlers. otherwise, change it
@@ -915,9 +898,6 @@ int parse_gauge_type()
if ( optional_string("+Secondary Weapons:") )
return HUD_OBJECT_SECONDARY_WEAPONS;
if ( optional_string("+Scripted Gauge:") )
return HUD_OBJECT_SCRIPTING;
return -1;
}
@@ -1098,9 +1078,6 @@ void load_gauge(int gauge, gauge_settings* settings)
case HUD_OBJECT_SECONDARY_WEAPONS:
load_gauge_secondary_weapons(settings);
break;
case HUD_OBJECT_SCRIPTING:
load_gauge_scripting(settings);
break;
default:
// It's either -1, indicating we're ignoring a parse error, or it's a coding error.
Assertion(gauge == -1, "Invalid value '%d' passed to load_gauge(); get a coder!\n", gauge);
@@ -1285,10 +1262,6 @@ std::unique_ptr<T> gauge_load_common(gauge_settings* settings, T* preAllocated =
}
}
if (optional_string("Chase View Only:")) {
stuff_boolean(&settings->chase_view_only);
}
if (settings->set_position) {
if(optional_string("Slew:")) {
stuff_boolean(&settings->slew);
@@ -1304,7 +1277,6 @@ std::unique_ptr<T> gauge_load_common(gauge_settings* settings, T* preAllocated =
instance->initBaseResolution(settings->base_res[0], settings->base_res[1]);
instance->initFont(settings->font_num);
instance->initChase_view_only(settings->chase_view_only);
if (settings->set_position) {
instance->initPosition(settings->coords[0], settings->coords[1]);
instance->initSlew(settings->slew);
@@ -1429,10 +1401,6 @@ void load_gauge_custom(gauge_settings* settings)
}
}
if (optional_string("Chase View Only:")) {
stuff_boolean(&settings->chase_view_only);
}
required_string("Name:");
stuff_string(name, F_NAME, MAX_FILENAME_LEN);
@@ -1484,7 +1452,6 @@ void load_gauge_custom(gauge_settings* settings)
hud_gauge->updateColor(colors[0], colors[1], colors[2]);
hud_gauge->lockConfigColor(lock_color);
hud_gauge->initCockpitTarget(display_name, display_offset[0], display_offset[1], display_size[0], display_size[1], canvas_size[0], canvas_size[1]);
hud_gauge->initChase_view_only(settings->chase_view_only);
gauge_assign_common(settings, std::move(hud_gauge));
}
@@ -2997,7 +2964,6 @@ void load_gauge_radar_dradis(gauge_settings* settings)
hud_gauge->initCockpitTarget(display_name, display_offset[0], display_offset[1], display_size[0], display_size[1], canvas_size[0], canvas_size[1]);
hud_gauge->initFont(settings->font_num);
hud_gauge->initSound(loop_snd, loop_snd_volume, arrival_beep_snd, departure_beep_snd, stealth_arrival_snd, stealth_departure_snd, arrival_beep_delay, departure_beep_delay);
hud_gauge->initChase_view_only(settings->chase_view_only);
gauge_assign_common(settings, std::move(hud_gauge));
}
@@ -5226,15 +5192,3 @@ void load_gauge_secondary_weapons(gauge_settings* settings)
gauge_assign_common(settings, std::move(hud_gauge));
}
void load_gauge_scripting(gauge_settings* settings) {
auto hud_gauge = gauge_load_common<HudGaugeScripting>(settings);
required_string("Name:");
SCP_string name;
stuff_string(name, F_NAME);
hud_gauge->initName(name);
gauge_assign_common(settings, std::move(hud_gauge));
}
+1 -6
View File
@@ -23,7 +23,6 @@ extern int Hud_reticle_style;
extern bool Scale_retail_gauges;
extern int Force_scaling_above_res_global[2];
extern int Hud_font;
extern bool Chase_view_only_ex;
typedef struct gauge_settings {
int base_res[2];
@@ -39,9 +38,8 @@ typedef struct gauge_settings {
bool set_position;
bool set_colour;
bool slew;
bool chase_view_only;
gauge_settings() : font_num(Hud_font), scale_gauge(Scale_retail_gauges), ship_idx(nullptr), use_clr(nullptr), use_coords(false), set_position(true), set_colour(true), slew(false), chase_view_only(Chase_view_only_ex) {
gauge_settings() : font_num(Hud_font), scale_gauge(Scale_retail_gauges), ship_idx(nullptr), use_clr(nullptr), use_coords(false), set_position(true), set_colour(true), slew(false) {
base_res[0] = -1;
base_res[1] = -1;
memcpy(force_scaling_above_res, Force_scaling_above_res_global, sizeof(force_scaling_above_res));
@@ -232,7 +230,4 @@ void load_gauge_primary_weapons(gauge_settings* settings);
#define HUD_OBJECT_SECONDARY_WEAPONS 55
void load_gauge_secondary_weapons(gauge_settings* settings);
#define HUD_OBJECT_SCRIPTING 56
void load_gauge_scripting(gauge_settings* settings);
#endif // _HUDPARSE_H
-47
View File
@@ -1,47 +0,0 @@
//
//
#include "hud/hudscripting.h"
#include "parse/parselo.h"
#include "scripting/api/objs/hudgauge.h"
HudGaugeScripting::HudGaugeScripting() :
HudGauge(HUD_OBJECT_SCRIPTING,
HUD_CENTER_RETICLE,
true,
false,
(VM_EXTERNAL | VM_DEAD_VIEW | VM_WARP_CHASE | VM_PADLOCK_ANY | VM_TOPDOWN | VM_OTHER_SHIP),
255,
255,
255) {
}
void HudGaugeScripting::render(float /*frametime*/) {
using namespace scripting::api;
if (!_renderFunction.isValid()) {
return;
}
_renderFunction.call({ luacpp::LuaValue::createValue(_renderFunction.getLuaState(),
l_HudGaugeDrawFuncs.Set(this)) });
}
void HudGaugeScripting::initName(SCP_string name) {
if (name.size() > NAME_LENGTH - 1) {
error_display(0,
"Name \"%s\" is too long. May not be longer than %d! Name will be truncated",
name.c_str(),
NAME_LENGTH - 1);
name.resize(NAME_LENGTH - 1);
}
strcpy(custom_name, name.c_str());
}
const luacpp::LuaFunction& HudGaugeScripting::getRenderFunction() const {
return _renderFunction;
}
void HudGaugeScripting::setRenderFunction(const luacpp::LuaFunction& renderFunction) {
_renderFunction = renderFunction;
}
-18
View File
@@ -1,18 +0,0 @@
#pragma once
#include "globalincs/pstypes.h"
#include "hud/hud.h"
#include "scripting/lua/LuaFunction.h"
class HudGaugeScripting: public HudGauge {
luacpp::LuaFunction _renderFunction;
public:
HudGaugeScripting();
void render(float frametime) override;
void initName(SCP_string name);
const luacpp::LuaFunction& getRenderFunction() const;
void setRenderFunction(const luacpp::LuaFunction& renderFunction);
};
-4
View File
@@ -6338,8 +6338,6 @@ void HudGaugeOffscreen::calculatePosition(vertex* target_point, vec3d *tpos, vec
if (eye_vertex->flags&PF_OVERFLOW) {
Int3(); // This is unlikely to happen, but can if a clip goes through the player's eye.
Player_ai->target_objnum = -1;
if (!in_frame)
g3_end_frame();
return;
}
@@ -6400,8 +6398,6 @@ void HudGaugeOffscreen::calculatePosition(vertex* target_point, vec3d *tpos, vec
} else {
Int3();
if (!in_frame)
g3_end_frame();
return;
}
+4 -3
View File
@@ -1435,9 +1435,10 @@ void HudGaugeExtraTargetData::render(float /*frametime*/)
// Print out current orders if the targeted ship is friendly
// AL 12-26-97: only show orders and time to target for friendly ships
// Backslash: actually let's consult the IFF table. Maybe we want to show orders for certain teams, or hide orders for friendlies
if ( ((Player_ship->team == target_shipp->team) ||
((Iff_info[target_shipp->team].flags & IFFF_ORDERS_SHOWN) && !(Iff_info[target_shipp->team].flags & IFFF_ORDERS_HIDDEN)))
&& Ship_info[target_shipp->ship_info_index].is_flyable() ) {
if (((Player_ship->team == target_shipp->team) ||
((Iff_info[target_shipp->team].flags & IFFF_ORDERS_SHOWN) &&
!(Iff_info[target_shipp->team].flags & IFFF_ORDERS_HIDDEN)))
&& Ship_info[target_shipp->ship_info_index].is_flyable()) {
extra_data_shown = 1;
auto orders = ship_return_orders(target_shipp);
if (!orders.empty()) {
+34 -114
View File
@@ -1,8 +1,6 @@
#include "io/joy.h"
#include "io/joy_ff.h"
#include "io/timer.h"
#include "mod_table/mod_table.h"
#include "options/Option.h"
#include "osapi/osapi.h"
#include <algorithm>
@@ -10,13 +8,10 @@
#include <memory>
#include <utility>
#include "libs/jansson.h"
using namespace io::joystick;
using namespace os::events;
namespace {
typedef std::unique_ptr<Joystick> JoystickPtr;
SCP_vector<JoystickPtr> joysticks;
@@ -64,7 +59,7 @@ HatPosition hatBtnToEnum(int in) {
}
};
SCP_string getJoystickGUID(SDL_Joystick* stick)
SCP_string getJoystickGUID(SDL_Joystick *stick)
{
auto guid = SDL_JoystickGetGUID(stick);
@@ -84,14 +79,16 @@ SCP_string getJoystickGUID(SDL_Joystick* stick)
return joystickGUID;
}
bool joystickMatchesGuid(Joystick* testStick, const SCP_string& guid, int id)
{
if (guid.empty()) {
bool isCurrentJoystick(Joystick* testStick) {
auto currentGUID = os_config_read_string(nullptr, "CurrentJoystickGUID", nullptr);
auto currentId = (int)os_config_read_uint(nullptr, "CurrentJoystick", 0);
if ((currentGUID == nullptr) || !strcmp(currentGUID, "")) {
// Only use the id
return id == testStick->getDeviceId();
return currentId == testStick->getDeviceId();
}
SCP_string guidStr(guid);
SCP_string guidStr(currentGUID);
std::transform(begin(guidStr), end(guidStr), begin(guidStr), [](char c) { return (char)::toupper(c); });
if (testStick->getGUID() != guidStr) {
@@ -116,73 +113,26 @@ bool joystickMatchesGuid(Joystick* testStick, const SCP_string& guid, int id)
}
// Multiple sticks -> check if the device id is the same
return testStick->getDeviceId() == id;
return testStick->getDeviceId() == currentId;
}
bool isCurrentJoystick(Joystick* testStick)
void enumerateJoysticks(SCP_vector<JoystickPtr>& outVec)
{
auto currentGUID = os_config_read_string(nullptr, "CurrentJoystickGUID", nullptr);
auto currentId = (int)os_config_read_uint(nullptr, "CurrentJoystick", 0);
auto num = SDL_NumJoysticks();
outVec.clear();
outVec.reserve(static_cast<size_t>(num));
return joystickMatchesGuid(testStick, currentGUID, currentId);
}
mprintf(("Printing joystick info:\n"));
Joystick* joystick_deserialize(const json_t* value)
{
const char* guid;
int id;
for (auto i = 0; i < num; ++i)
{
auto ptr = JoystickPtr(new Joystick(i));
ptr->printInfo();
json_error_t err;
if (json_unpack_ex((json_t*)value, &err, 0, "{s:s, s:i}", "guid", &guid, "id", &id) != 0) {
throw json_exception(err);
outVec.push_back(std::move(ptr));
}
for (auto& test_stick : joysticks) {
if (joystickMatchesGuid(test_stick.get(), guid, id)) {
return test_stick.get();
}
}
return nullptr;
}
json_t* joystick_serializer(Joystick* joystick)
{
if (joystick == nullptr) {
return json_null();
}
return json_pack("{sssi}", "guid", joystick->getGUID().c_str(), "id", joystick->getID());
}
SCP_string joystick_display(Joystick* stick)
{
if (stick == nullptr) {
return "None";
}
return stick->getName();
}
SCP_vector<Joystick*> joystick_enumerator()
{
SCP_vector<Joystick*> out;
out.push_back(nullptr);
for (auto& stick : joysticks) {
out.push_back(stick.get());
}
return out;
}
auto JoystickOption = options::OptionBuilder<Joystick*>("Input.Joystick", "Joystick", "The current joystick.")
.category("Input")
.deserializer(joystick_deserialize)
.serializer(joystick_serializer)
.display(joystick_display)
.enumerator(joystick_enumerator)
.level(options::ExpertLevel::Beginner)
.default_val(nullptr)
.finish();
HatPosition convertSDLHat(int val)
{
switch (val)
@@ -210,22 +160,6 @@ HatPosition convertSDLHat(int val)
}
}
void enumerateJoysticks(SCP_vector<JoystickPtr>& outVec)
{
auto num = SDL_NumJoysticks();
outVec.clear();
outVec.reserve(static_cast<size_t>(num));
mprintf(("Printing joystick info:\n"));
for (auto i = 0; i < num; ++i) {
auto ptr = JoystickPtr(new Joystick(i));
ptr->printInfo();
outVec.push_back(std::move(ptr));
}
}
void setCurrentJoystick(Joystick *stick)
{
currentJoystick = stick;
@@ -352,18 +286,10 @@ bool device_event_handler(const SDL_Event &evt)
return true;
}
if (Using_in_game_options) {
auto value = JoystickOption->getValue();
// Since the new stick has been added to the joystick list, the option will return the same pointer here
if (value == addedStick) {
setCurrentJoystick(addedStick);
}
} else {
if (isCurrentJoystick(addedStick)) {
// found our wanted stick!
setCurrentJoystick(addedStick);
}
if (isCurrentJoystick(addedStick))
{
// found our wanted stick!
setCurrentJoystick(addedStick);
}
}
else if (evtType == SDL_JOYDEVICEREMOVED)
@@ -820,25 +746,19 @@ namespace joystick
addEventListener(SDL_JOYDEVICEREMOVED, DEFAULT_LISTENER_WEIGHT, device_event_handler);
// Search for the correct stick
if (Using_in_game_options) {
// The new options system is in use
setCurrentJoystick(JoystickOption->getValue());
} else {
// Fall back to the legacy config values
for (auto& stick : joysticks) {
if (isCurrentJoystick(stick.get())) {
// Joystick found
setCurrentJoystick(stick.get());
break;
}
}
for (auto& stick : joysticks) {
if (isCurrentJoystick(stick.get())) {
// Joystick found
setCurrentJoystick(stick.get());
break;
}
}
if (currentJoystick == nullptr) {
mprintf((" No joystick is being used.\n"));
}
}
if (currentJoystick == nullptr) {
mprintf((" No joystick is being used.\n"));
}
initialized = true;
initialized = true;
joy_ff_init();
+14 -49
View File
@@ -1,20 +1,21 @@
/*
* Copyright (C) Volition, Inc. 1999. All rights reserved.
*
* All source code herein is the property of Volition, Inc. You may not sell
* or otherwise commercially exploit the source or things you created based on the
* All source code herein is the property of Volition, Inc. You may not sell
* or otherwise commercially exploit the source or things you created based on the
* source.
*
*/
*/
#include "globalincs/pstypes.h"
#include "io/joy.h"
#include "io/joy_ff.h"
#include "math/vecmat.h"
#include "mod_table/mod_table.h"
#include "options/Option.h"
#include "osapi/osapi.h"
#include "osapi/osregistry.h"
#include "io/joy_ff.h"
#include "io/joy.h"
#include "osapi/osapi.h"
#include "SDL_haptic.h"
@@ -26,7 +27,7 @@
static int Joy_ff_enabled = 0;
static SDL_Haptic *haptic = NULL;
static int joy_ff_handling_scaler = 0;
static bool Joy_ff_directional_hit_effect_enabled = true;
static int Joy_ff_directional_hit_effect_enabled = 1;
typedef struct {
SDL_HapticEffect eff;
@@ -46,28 +47,6 @@ static haptic_effect_t pDeathroll1;
static haptic_effect_t pDeathroll2;
static haptic_effect_t pExplode;
static auto ForceFeedbackOption =
options::OptionBuilder<bool>("Input.ForceFeedback", "Force Feedback", "Enable or disable force feedback.")
.category("Input")
.level(options::ExpertLevel::Beginner)
.default_val(false)
.finish();
static auto HitEffectOption =
options::OptionBuilder<bool>("Input.HitEffect", "Directional Hit", "Enable or disable the directional hit effect.")
.category("Input")
.level(options::ExpertLevel::Beginner)
.default_val(false)
.finish();
static auto ForceFeedbackStrength = options::OptionBuilder<float>("Input.FFStrength", "Force Feedback Strength",
"The relative strength of Force Feedback effects.")
.category("Input")
.level(options::ExpertLevel::Beginner)
.range(0, 100)
.default_val(100)
.finish();
static int joy_ff_create_effects();
static int joy_ff_has_valid_effects();
static int joy_ff_effect_playing(haptic_effect_t *eff);
@@ -103,13 +82,9 @@ static void print_haptic_support() {
int joy_ff_init()
{
bool ff_enabled;
int ff_enabled = 0;
if (Using_in_game_options) {
ff_enabled = ForceFeedbackOption->getValue();
} else {
ff_enabled = os_config_read_uint(nullptr, "EnableJoystickFF", 1) != 0;
}
ff_enabled = os_config_read_uint(NULL, "EnableJoystickFF", 1);
if ( !ff_enabled || io::joystick::getCurrentJoystick() == nullptr) {
return 0;
@@ -162,20 +137,10 @@ int joy_ff_init()
return -1;
}
if (Using_in_game_options) {
Joy_ff_directional_hit_effect_enabled = HitEffectOption->getValue();
} else {
Joy_ff_directional_hit_effect_enabled = os_config_read_uint(nullptr, "EnableHitEffect", 1) != 0;
}
Joy_ff_directional_hit_effect_enabled = os_config_read_uint(NULL, "EnableHitEffect", 1);
// ForceFeedback.Strength lets the user specify how strong the effects should be. This uses SDL_HapticSetGain which
// needs to be supported by the haptic device
int ff_strength;
if (Using_in_game_options) {
ff_strength = (int)ForceFeedbackStrength->getValue();
} else {
ff_strength = os_config_read_uint("ForceFeedback", "Strength", 100);
}
int ff_strength = os_config_read_uint("ForceFeedback", "Strength", 100);
CLAMP(ff_strength, 0, 100);
if (SDL_HapticQuery(haptic) & SDL_HAPTIC_GAIN) {
SDL_HapticSetGain(haptic, ff_strength);
+20 -22
View File
@@ -127,13 +127,14 @@ void timestamp_reset()
// For debugging & testing, you could set this to
// something like 1 minute (6000).
const std::uint32_t MAX_TIME = INT_MAX / 2;
const std::uint64_t MAX_TICKER = (MAX_TIME - 2) * 1000; // subtract 2 because timestamp_ms() adds 2, and we want MAX_TICKER to correspond to MAX_TIME
static int timestamp_ms() {
if (timestamp_ticker <= 2) {
// These are special values, don't adjust them
return (int)timestamp_ticker;
}
return (int)(timestamp_ticker / 1000);
return (int)(timestamp_ticker / 1000) + 2; // avoid values below 2
}
void timestamp_inc(fix frametime)
@@ -144,8 +145,8 @@ void timestamp_inc(fix frametime)
timestamp_ticker += delta;
if ( timestamp_ms() > (int)MAX_TIME ) {
timestamp_ticker = 2; // Roll!
if ( timestamp_ticker > MAX_TICKER ) {
timestamp_ticker -= MAX_TICKER - 2; // Roll!
}
if (timestamp_ticker < 2 ) {
@@ -161,8 +162,9 @@ int timestamp(int delta_ms ) {
t2 = timestamp_ms() + delta_ms;
if ( t2 > (int)MAX_TIME ) {
// wrap!!!
t2 = delta_ms - (MAX_TIME-timestamp_ms());
t2 -= MAX_TIME - 2;
}
Assertion(t2 >= 2, "Math no longer makes sense; t2 is %d", t2);
if (t2 < 2 ) t2 = 2; // hack??
return t2;
}
@@ -170,25 +172,16 @@ int timestamp(int delta_ms ) {
// Returns milliseconds until timestamp will elapse.
// Negative value gives milliseconds ago that timestamp elapsed.
int timestamp_until(int stamp) {
// JAS: FIX
// HACK!! This doesn't handle rollover!
// (Will it ever happen?)
int delta;
return stamp - timestamp_ms();
delta = stamp - timestamp_ms();
/*
uint delta;
delta = stamp - timestamp_ticker;
if (delta > UINT_MAX/2)
delta = UINT_MAX - delta + 1;
else if (delta < - ( (int) (UINT_MAX/2)))
delta = UINT_MAX + delta + 1;
if (delta > (int)MAX_TIME/2)
delta = delta - MAX_TIME + 1;
else if (delta < -(int)MAX_TIME/2)
delta = delta + MAX_TIME - 1;
return delta;
*/
}
// alternate timestamp functions. The way these work is you call xtimestamp() to get the
@@ -204,17 +197,22 @@ int timestamp_has_time_elapsed(int stamp, int time) {
return 1;
t = stamp + time;
if (t <= timestamp_ms())
return 1; // if we are unlucky enough to have it wrap on us, this will assume time has elapsed.
if (t > (int)MAX_TIME) {
t -= MAX_TIME - 2;
}
if (timestamp_until(t) <= 0)
return 1;
return 0;
}
bool timestamp_elapsed(int stamp) {
if (stamp == 0) {
return false;
} else if (stamp == 1) {
return true;
}
return timestamp_ms() >= stamp;
return timestamp_until(stamp) <= 0;
}
bool timestamp_elapsed_safe(int a, int b) {
if (a == 0) {
+37 -26
View File
@@ -405,13 +405,13 @@ void labviewer_render_model(float frametime)
if (Lab_selected_object != -1) {
auto lab_render_light_save = Lab_render_without_light;
auto lab_debris_override_save = Motion_debris_enabled;
auto lab_debris_override_save = Cmdline_nomotiondebris;
auto lab_envmap_override_save = Envmap_override;
auto lab_emissive_light_save = Cmdline_no_emissive;
if (Lab_selected_mission == "None") {
Lab_render_without_light = true;
Motion_debris_enabled = true;
Cmdline_nomotiondebris = 1;
}
Cmdline_no_emissive = !Lab_emissive_light_override;
@@ -464,7 +464,7 @@ void labviewer_render_model(float frametime)
Trail_render_override = false;
Lab_render_without_light = lab_render_light_save;
Motion_debris_enabled = lab_debris_override_save;
Cmdline_nomotiondebris = lab_debris_override_save;
Envmap_override = lab_envmap_override_save;
Cmdline_no_emissive = lab_emissive_light_save;
@@ -548,27 +548,10 @@ void labviewer_do_render(float frametime)
}
// Print FXAA preset
if (gr_is_fxaa_mode(Gr_aa_mode) && !PostProcessing_override) {
const char* fxaa_mode;
switch (Gr_aa_mode) {
case AntiAliasMode::FXAA_Low:
fxaa_mode = "Low";
break;
case AntiAliasMode::FXAA_Medium:
fxaa_mode = "Medium";
break;
case AntiAliasMode::FXAA_High:
fxaa_mode = "High";
break;
default:
fxaa_mode = "None";
break;
}
if (Cmdline_fxaa && !PostProcessing_override)
gr_printf_no_resize(gr_screen.center_offset_x + 2,
gr_screen.center_offset_y + gr_screen.center_h - (gr_get_font_height() * 2) - 3,
"FXAA Preset: %s", fxaa_mode);
}
"FXAA Preset: %i", Cmdline_fxaa_preset);
// Print current Team Color setting, if any
if (Lab_team_color != "<none>")
@@ -1157,7 +1140,7 @@ void labviewer_make_render_options_window(Button* /*caller*/)
ADD_RENDER_FLAG("Show Damage Lightning", Lab_viewer_flags, LAB_FLAG_LIGHTNING_ARCS);
ADD_RENDER_BOOL("Rotate Subsystems", Lab_rotate_subobjects);
if (Gr_post_processing_enabled) {
if (Cmdline_postprocess) {
ADD_RENDER_BOOL("Hide Post Processing", PostProcessing_override);
}
@@ -2287,15 +2270,43 @@ void lab_do_frame(float frametime)
// Adjust FXAA presets
case KEY_0:
if (!PostProcessing_override)
Gr_aa_mode = AntiAliasMode::FXAA_Low;
Cmdline_fxaa_preset = 0;
break;
case KEY_1:
if (!PostProcessing_override)
Gr_aa_mode = AntiAliasMode::FXAA_Medium;
Cmdline_fxaa_preset = 1;
break;
case KEY_2:
if (!PostProcessing_override)
Gr_aa_mode = AntiAliasMode::FXAA_High;
Cmdline_fxaa_preset = 2;
break;
case KEY_3:
if (!PostProcessing_override)
Cmdline_fxaa_preset = 3;
break;
case KEY_4:
if (!PostProcessing_override)
Cmdline_fxaa_preset = 4;
break;
case KEY_5:
if (!PostProcessing_override)
Cmdline_fxaa_preset = 5;
break;
case KEY_6:
if (!PostProcessing_override)
Cmdline_fxaa_preset = 6;
break;
case KEY_7:
if (!PostProcessing_override)
Cmdline_fxaa_preset = 7;
break;
case KEY_8:
if (!PostProcessing_override)
Cmdline_fxaa_preset = 8;
break;
case KEY_9:
if (!PostProcessing_override)
Cmdline_fxaa_preset = 9;
break;
case KEY_T:
-28
View File
@@ -1,7 +1,5 @@
#include "libs/jansson.h"
#include "jansson.h"
#include "parse/parselo.h"
namespace {
int json_write_callback(const char *buffer, size_t size, void *data) {
@@ -19,12 +17,6 @@ size_t json_read_callback(void *buffer, size_t buflen, void *data) {
return (size_t)cfread(buffer, 1, (int)buflen, fp);
}
SCP_string format_error(const json_error_t& err)
{
SCP_string out;
sprintf(out, "%s(%d:%d): %s", err.source, err.line, err.column, err.text);
return out;
}
}
int json_dump_cfile(const json_t* json, CFILE* file, size_t flags) {
@@ -33,23 +25,3 @@ int json_dump_cfile(const json_t* json, CFILE* file, size_t flags) {
json_t* json_load_cfile(CFILE* cfile, size_t flags, json_error_t* error) {
return json_load_callback(json_read_callback, cfile, flags, error);
}
SCP_string json_dump_string(const json_t* json, size_t flags)
{
auto buf = json_dumps(json, flags);
if (buf == nullptr) {
return SCP_string();
}
SCP_string out(buf);
free(buf);
return out;
}
SCP_string json_dump_string_new(json_t* json, size_t flags) {
auto str = json_dump_string(json, flags);
json_decref(json);
return str;
}
json_exception::json_exception(const json_error_t& error) : std::runtime_error(format_error(error)) {}
+1 -24
View File
@@ -1,32 +1,9 @@
#pragma once
#include "cfile/cfile.h"
#include <jansson.h>
#include <stdexcept>
int json_dump_cfile(const json_t *json, CFILE* file, size_t flags);
json_t *json_load_cfile(CFILE* cfile, size_t flags, json_error_t *error);
SCP_string json_dump_string(const json_t* json, size_t flags);
SCP_string json_dump_string_new(json_t* json, size_t flagse);
// This allows using std::unique_ptr with json_t values
namespace std {
template <>
class default_delete<json_t> {
public:
void operator()(json_t* ptr) const
{
if (ptr) {
json_decref(ptr);
}
}
};
}; // namespace std
class json_exception : public std::runtime_error {
public:
explicit json_exception(const json_error_t& error);
};
+1 -1
View File
@@ -56,7 +56,7 @@ int Lcl_english = 1;
// the english version (in the code) to a foreign version (in the table). Thus, if you
// add a new string to the code, you must assign it a new index. Use the number below for
// that index and increase the number below by one.
#define XSTR_SIZE 1641
#define XSTR_SIZE 1638
// struct to allow for strings.tbl-determined x offset
+1 -1
View File
@@ -352,7 +352,7 @@ void player_select_do()
// Goober5000 - display a popup warning about problems in the mod
if ((Global_warning_count > 10 || Global_error_count > 0) && !Startup_warning_dialog_displayed) {
char text[512];
sprintf(text, XSTR ("Warning!\n\nThe currently active mod has generated %d warnings and/or errors during program startup. These could have been caused by anything from incorrectly formated table files to corrupt models.\n\nWhile FreeSpace Open will attempt to compensate for these issues, it cannot guarantee a trouble-free gameplay experience.\n\nPlease contact the authors of the mod for assistance.", 1640), Global_warning_count + Global_error_count);
sprintf(text, "Warning!\n\nThe currently active mod has generated %d warnings and/or errors during program startup. These could have been caused by anything from incorrectly formated table files to corrupt models.\n\nWhile FreeSpace Open will attempt to compensate for these issues, it cannot guarantee a trouble-free gameplay experience.\n\nPlease contact the authors of the mod for assistance.", Global_warning_count + Global_error_count);
popup(PF_TITLE_BIG | PF_TITLE_RED | PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, text);
Startup_warning_dialog_displayed = true;
}
+1 -1
View File
@@ -569,7 +569,7 @@ void techroom_ships_render(float frametime)
render_info.set_replacement_textures(Techroom_ship_modelnum, sip->replacement_textures);
}
if(Shadow_quality != ShadowQuality::Disabled)
if(Cmdline_shadow_quality)
{
gr_reset_clip();
+7 -7
View File
@@ -97,8 +97,9 @@ bool mission_is_ignored(const char *filename)
// Mission_load takes no parameters.
// It sets the following global variables
// Game_current_mission_filename
// returns true successful, false if failed
bool mission_load(const char* filename_ext)
// returns -1 if failed, 0 if successful
int mission_load(const char* filename_ext)
{
TRACE_SCOPE(tracing::LoadMissionLoad);
@@ -119,7 +120,7 @@ bool mission_load(const char* filename_ext)
if (mission_is_ignored(filename)) {
mprintf(("MISSION LOAD: Tried to load an ignored mission! Aborting..."));
return false;
return -1;
}
strcat_s(filename, FS_MISSION_FILE_EXT);
@@ -130,8 +131,8 @@ bool mission_load(const char* filename_ext)
// to choose the type of ship that he is to fly
// return value of 0 indicates success, other is failure.
if ( !parse_main(filename) )
return false;
if ( parse_main(filename) )
return -1;
if (Select_default_ship) {
int ret;
@@ -142,8 +143,7 @@ bool mission_load(const char* filename_ext)
ml_update_recent_missions(filename_ext); // update recently played missions list (save the csg later)
init_hud();
return true;
return 0;
}
//====================================
+1 -1
View File
@@ -27,7 +27,7 @@ extern SCP_vector<SCP_string> Ignored_missions;
// It sets the following global variables:
// Game_current_mission_filename
bool mission_load(const char* filename_ext);
int mission_load(const char* filename_ext);
bool mission_is_ignored(const char *filename);
+3 -3
View File
@@ -1500,8 +1500,8 @@ void message_queue_process()
return;
// Goober5000 - argh, don't conflate special sources with ships!
// NOTA BENE: don't check for != HUD_SOURCE_TERRAN_CMD, because with the new command persona code, Command could be a ship
if ( q->source != HUD_SOURCE_IMPORTANT ) {
// NOTA BENE: don't check for != MESSAGE_SOURCE_COMMAND, because with the new command persona code, Command could be a ship
if ( q->source != MESSAGE_SOURCE_SPECIAL ) {
Message_shipnum = ship_name_lookup( q->who_from );
// see if we need to check if sending ship is alive
@@ -1859,7 +1859,7 @@ void message_send_unique_to_player( char *id, void *data, int m_source, int prio
source = HUD_SOURCE_TERRAN_CMD;
} else if ( m_source == MESSAGE_SOURCE_SPECIAL ) {
who_from = (char *)data;
source = HUD_SOURCE_IMPORTANT;
source = HUD_SOURCE_TERRAN_CMD;
} else if ( m_source == MESSAGE_SOURCE_WINGMAN ) {
int m_persona, ship_index;
+128 -126
View File
@@ -374,7 +374,7 @@ extern fix game_get_overall_frametime(); // for texture animation
// local prototypes
void parse_player_info2(mission *pm);
bool post_process_mission();
void post_process_mission();
int allocate_subsys_status();
void parse_common_object_data(p_object *objp);
void parse_asteroid_fields(mission *pm);
@@ -1859,6 +1859,7 @@ int parse_create_object(p_object *pobjp)
}
void parse_bring_in_docked_wing(p_object *p_objp, int wingnum, int shipnum);
void ship_set_warp_effects(object *objp);
/**
* Given a stuffed p_object struct, create an object and fill in the necessary fields.
@@ -1905,6 +1906,7 @@ int parse_create_object_sub(p_object *p_objp)
shipp->group = p_objp->group;
shipp->team = p_objp->team;
strcpy_s(shipp->ship_name, p_objp->name);
shipp->display_name = p_objp->display_name;
shipp->escort_priority = p_objp->escort_priority;
shipp->use_special_explosion = p_objp->use_special_explosion;
@@ -1966,25 +1968,37 @@ int parse_create_object_sub(p_object *p_objp)
}
}
if (!Fred_running)
{
ship_assign_sound(&Ships[shipnum]);
}
aip = &(Ai_info[shipp->ai_index]);
aip->behavior = p_objp->behavior;
aip->mode = aip->behavior;
// make sure aim_safety has its submode defined
if (aip->mode == AIM_SAFETY) {
aip->submode = AISS_1;
}
// alternate stuff
shipp->alt_type_index = p_objp->alt_type_index;
shipp->callsign_index = p_objp->callsign_index;
// AI stuff. Note a lot of the AI was already initialized in ship_create.
aip = &(Ai_info[shipp->ai_index]);
aip->ai_class = p_objp->ai_class;
shipp->weapons.ai_class = p_objp->ai_class; // Fred uses this instead of above.
//Fixes a bug where the AI class attributes were not copied if the AI class was set in the mission.
if (The_mission.ai_profile->flags[AI::Profile_Flags::Fix_ai_class_bug])
ship_set_new_ai_class(shipnum, p_objp->ai_class);
aip->behavior = p_objp->behavior;
aip->mode = aip->behavior;
// make sure aim_safety has its submode defined
if (aip->mode == AIM_SAFETY) {
aip->submode = AISS_1;
// must reset the number of ai goals when the object is created
for (i = 0; i < MAX_AI_GOALS; i++)
{
aip->goals[i].ai_mode = AI_GOAL_NONE;
aip->goals[i].signature = -1;
aip->goals[i].priority = -1;
aip->goals[i].flags.reset();
}
shipp->cargo1 = p_objp->cargo1;
@@ -2245,13 +2259,11 @@ int parse_create_object_sub(p_object *p_objp)
}
}
// skip the rest because the Pilot subsystem is special
continue;
}
// find the subsystem in the ship list that corresponds to the parsed subsystem
ptr = ship_get_subsys(shipp, sssp->name);
if (ptr != nullptr)
ptr = GET_FIRST(&shipp->subsys_list);
while (ptr != END_OF_LIST(&shipp->subsys_list))
{
// check the mission flag to possibly free all beam weapons - Goober5000, taken from SEXP.CPP
if (The_mission.flags[Mission::Mission_Flags::Beam_free_all_by_default])
@@ -2273,80 +2285,81 @@ int parse_create_object_sub(p_object *p_objp)
}
}
if (Fred_running)
if (!subsystem_stricmp(ptr->system_info->subobj_name, sssp->name))
{
ptr->current_hits = sssp->percent;
ptr->max_hits = 100.0f;
}
else
{
ptr->max_hits = ptr->system_info->max_subsys_strength * (shipp->ship_max_hull_strength / sip->max_hull_strength);
float new_hits = ptr->max_hits * (100.0f - sssp->percent) / 100.f;
if (!(ptr->flags[Ship::Subsystem_Flags::No_aggregate])) {
shipp->subsys_info[ptr->system_info->type].aggregate_current_hits -= (ptr->max_hits - new_hits);
}
if ((100.0f - sssp->percent) < 0.5)
if (Fred_running)
{
ptr->current_hits = 0.0f;
ptr->submodel_info_1.blown_off = 1;
ptr->current_hits = sssp->percent;
ptr->max_hits = 100.0f;
}
else
{
ptr->current_hits = new_hits;
ptr->max_hits = ptr->system_info->max_subsys_strength * (shipp->ship_max_hull_strength / sip->max_hull_strength);
float new_hits = ptr->max_hits * (100.0f - sssp->percent) / 100.f;
if (!(ptr->flags[Ship::Subsystem_Flags::No_aggregate])) {
shipp->subsys_info[ptr->system_info->type].aggregate_current_hits -= (ptr->max_hits - new_hits);
}
if ((100.0f - sssp->percent) < 0.5)
{
ptr->current_hits = 0.0f;
ptr->submodel_info_1.blown_off = 1;
}
else
{
ptr->current_hits = new_hits;
}
}
if (sssp->primary_banks[0] != SUBSYS_STATUS_NO_CHANGE)
for (j=0; j<MAX_SHIP_PRIMARY_BANKS; j++)
ptr->weapons.primary_bank_weapons[j] = sssp->primary_banks[j];
if (sssp->secondary_banks[0] != SUBSYS_STATUS_NO_CHANGE)
for (j=0; j<MAX_SHIP_SECONDARY_BANKS; j++)
ptr->weapons.secondary_bank_weapons[j] = sssp->secondary_banks[j];
// Goober5000
for (j = 0; j < ptr->weapons.num_primary_banks; j++)
{
if (Fred_running) {
ptr->weapons.primary_bank_ammo[j] = sssp->primary_ammo[j];
} else if (ptr->weapons.primary_bank_weapons[j] >= 0 && Weapon_info[ptr->weapons.primary_bank_weapons[j]].wi_flags[Weapon::Info_Flags::Ballistic]) {
Assertion(Weapon_info[ptr->weapons.primary_bank_weapons[j]].cargo_size > 0.0f,
"Primary weapon cargo size <= 0. Ship (%s) Subsystem (%s) Bank (%i) Weapon (%s)",
shipp->ship_name, sssp->name, j, Weapon_info[ptr->weapons.primary_bank_weapons[j]].name);
int capacity = (int)std::lround(sssp->primary_ammo[j]/100.0f * ptr->weapons.primary_bank_capacity[j]);
ptr->weapons.primary_bank_ammo[j] = (int)std::lround(capacity / Weapon_info[ptr->weapons.primary_bank_weapons[j]].cargo_size);
}
}
for (j = 0; j < ptr->weapons.num_secondary_banks; j++)
{
if (Fred_running) {
ptr->weapons.secondary_bank_ammo[j] = sssp->secondary_ammo[j];
} else if (ptr->weapons.secondary_bank_weapons[j] >= 0) {
Assertion(Weapon_info[ptr->weapons.secondary_bank_weapons[j]].cargo_size > 0.0f,
"Secondary weapon cargo size <= 0. Ship (%s) Subsystem (%s) Bank (%i) Weapon (%s)",
shipp->ship_name, sssp->name, j, Weapon_info[ptr->weapons.secondary_bank_weapons[j]].name);
int capacity = (int)std::lround(sssp->secondary_ammo[j]/100.0f * ptr->weapons.secondary_bank_capacity[j]);
ptr->weapons.secondary_bank_ammo[j] = (int)std::lround(capacity / Weapon_info[ptr->weapons.secondary_bank_weapons[j]].cargo_size);
}
}
ptr->subsys_cargo_name = sssp->subsys_cargo_name;
if (sssp->ai_class != SUBSYS_STATUS_NO_CHANGE)
ptr->weapons.ai_class = sssp->ai_class;
ptr->turret_best_weapon = -1;
ptr->turret_animation_position = MA_POS_NOT_SET; // model animation position is not set
ptr->turret_animation_done_time = 0;
}
if (sssp->primary_banks[0] != SUBSYS_STATUS_NO_CHANGE)
for (j=0; j<MAX_SHIP_PRIMARY_BANKS; j++)
ptr->weapons.primary_bank_weapons[j] = sssp->primary_banks[j];
if (sssp->secondary_banks[0] != SUBSYS_STATUS_NO_CHANGE)
for (j=0; j<MAX_SHIP_SECONDARY_BANKS; j++)
ptr->weapons.secondary_bank_weapons[j] = sssp->secondary_banks[j];
// Goober5000
for (j = 0; j < ptr->weapons.num_primary_banks; j++)
{
if (Fred_running) {
ptr->weapons.primary_bank_ammo[j] = sssp->primary_ammo[j];
} else if (ptr->weapons.primary_bank_weapons[j] >= 0 && Weapon_info[ptr->weapons.primary_bank_weapons[j]].wi_flags[Weapon::Info_Flags::Ballistic]) {
Assertion(Weapon_info[ptr->weapons.primary_bank_weapons[j]].cargo_size > 0.0f,
"Primary weapon cargo size <= 0. Ship (%s) Subsystem (%s) Bank (%i) Weapon (%s)",
shipp->ship_name, sssp->name, j, Weapon_info[ptr->weapons.primary_bank_weapons[j]].name);
int capacity = (int)std::lround(sssp->primary_ammo[j]/100.0f * ptr->weapons.primary_bank_capacity[j]);
ptr->weapons.primary_bank_ammo[j] = (int)std::lround(capacity / Weapon_info[ptr->weapons.primary_bank_weapons[j]].cargo_size);
}
}
for (j = 0; j < ptr->weapons.num_secondary_banks; j++)
{
if (Fred_running) {
ptr->weapons.secondary_bank_ammo[j] = sssp->secondary_ammo[j];
} else if (ptr->weapons.secondary_bank_weapons[j] >= 0) {
Assertion(Weapon_info[ptr->weapons.secondary_bank_weapons[j]].cargo_size > 0.0f,
"Secondary weapon cargo size <= 0. Ship (%s) Subsystem (%s) Bank (%i) Weapon (%s)",
shipp->ship_name, sssp->name, j, Weapon_info[ptr->weapons.secondary_bank_weapons[j]].name);
int capacity = (int)std::lround(sssp->secondary_ammo[j]/100.0f * ptr->weapons.secondary_bank_capacity[j]);
ptr->weapons.secondary_bank_ammo[j] = (int)std::lround(capacity / Weapon_info[ptr->weapons.secondary_bank_weapons[j]].cargo_size);
}
}
ptr->subsys_cargo_name = sssp->subsys_cargo_name;
if (sssp->ai_class != SUBSYS_STATUS_NO_CHANGE)
ptr->weapons.ai_class = sssp->ai_class;
ptr->turret_best_weapon = -1;
ptr->turret_animation_position = MA_POS_NOT_SET; // model animation position is not set
ptr->turret_animation_done_time = 0;
}
else
{
Warning(LOCATION, "Unable to find '%s' in ship subsys_list!", sssp->name);
ptr = GET_NEXT(ptr);
}
}
@@ -2462,9 +2475,11 @@ int parse_create_object_sub(p_object *p_objp)
// If the ship is in a wing, this will be done in mission_set_wing_arrival_location() instead
// If the ship is in a wing, but the wing is docked then addition of bool brought_in_docked_wing accounts for that status --wookieejedi
if (Game_mode & GM_IN_MISSION && ((shipp->wingnum == -1) || (brought_in_docked_wing))) {
object *anchor_objp = (anchor_objnum >= 0) ? &Objects[anchor_objnum] : nullptr;
if (anchor_objnum >= 0)
Script_system.SetHookObjects(2, "Ship", &Objects[objnum], "Parent", &Objects[anchor_objnum]);
else
Script_system.SetHookObjects(2, "Ship", &Objects[objnum], "Parent", NULL);
Script_system.SetHookObjects(2, "Ship", &Objects[objnum], "Parent", anchor_objp);
Script_system.RunCondition(CHA_ONSHIPARRIVE, &Objects[objnum]);
Script_system.RemHookVars(2, "Ship", "Parent");
}
@@ -5598,7 +5613,7 @@ void parse_variables()
}
}
bool parse_mission(mission *pm, int flags)
int parse_mission(mission *pm, int flags)
{
int saved_warning_count = Global_warning_count;
int saved_error_count = Global_error_count;
@@ -5639,7 +5654,7 @@ bool parse_mission(mission *pm, int flags)
Current_file_checksum = netmisc_calc_checksum(pm,MISSION_CHECKSUM_SIZE);
if (flags & MPF_ONLY_MISSION_INFO)
return true;
return 0;
parse_plot_info(pm);
parse_variables();
@@ -5666,7 +5681,7 @@ bool parse_mission(mission *pm, int flags)
// if running on standalone server, just print to the log
if (Game_mode & GM_STANDALONE_SERVER) {
mprintf(("Warning! Could not load %d ship classes!", Num_unknown_ship_classes));
return false;
return -2;
}
// don't do this in FRED; we will display a separate popup
else if (!Fred_running) {
@@ -5688,29 +5703,16 @@ bool parse_mission(mission *pm, int flags)
strcat_s(text, pm->name);
}
strcat_s(text, "\", and the current mod root is \"");
strcat_s(text, "\", and the current mod is \"");
// Try to find the first non-user, folder root and display that. Not ideal but better than nothing I guess...
// We go through all the specified mod roots and find the first non-user folder. If that does not exist then
// user folders will be considered next. If that also fails, a default value is used.
SCP_string modRoot = "<Unknown>";
for (const auto& consider_user : {false, true})
{
for (const auto& root : Cmdline_mod)
{
if (root.type != cfile::ModRootType::Folder)
{
continue;
}
if (root.user_location && !consider_user) {
continue;
}
modRoot = root.path;
if (Cmdline_mod == NULL || *Cmdline_mod == 0) {
strcat_s(text, "<retail default> ");
} else {
for (char *mod_token = Cmdline_mod; *mod_token != '\0'; mod_token += strlen(mod_token) + 1) {
strcat_s(text, mod_token);
strcat_s(text, " ");
}
}
strcat_s(text, modRoot.c_str());
strcpy(text + strlen(text) - 1, "\".)\n\n You can continue to load the mission, but it is quite likely that you will encounter a large number of mysterious errors. It is recommended that you either select a ");
strcat(text, (Game_mode & GM_CAMPAIGN_MODE) ? "campaign" : "mission");
@@ -5721,14 +5723,12 @@ bool parse_mission(mission *pm, int flags)
// now display the popup
int popup_rval = popup(PF_TITLE_BIG | PF_TITLE_RED, 2, POPUP_NO, POPUP_YES, text);
if (popup_rval == 0) {
return false;
return -2;
}
}
}
if (!post_process_mission()) {
return false;
}
post_process_mission();
if ((saved_warning_count - Global_warning_count) > 10 || (saved_error_count - Global_error_count) > 0) {
char text[512];
@@ -5739,10 +5739,10 @@ bool parse_mission(mission *pm, int flags)
log_printf(LOGFILE_EVENT_LOG, "Mission %s loaded.\n", pm->name);
// success
return true;
return 0;
}
bool post_process_mission()
void post_process_mission()
{
int i;
int indices[MAX_SHIPS], objnum;
@@ -5855,7 +5855,6 @@ bool post_process_mission()
// entering this if statement will result in program termination!!!!!
// print out an error based on the return value from check_sexp_syntax()
// G5K: now entering this statement simply aborts the mission load
if ( result ) {
SCP_string sexp_str;
SCP_string error_msg;
@@ -5863,10 +5862,14 @@ bool post_process_mission()
convert_sexp_to_string(sexp_str, i, SEXP_ERROR_CHECK_MODE);
truncate_message_lines(sexp_str, 30);
sprintf(error_msg, "%s.\n\nIn sexpression: %s\n(Error appears to be: %s)", sexp_error_message(result), sexp_str.c_str(), Sexp_nodes[bad_node].text);
Warning(LOCATION, "%s", error_msg.c_str());
// syntax errors are unrecoverable, so abort
return false;
if (!Fred_running) {
nprintf(("Error", "%s", error_msg.c_str()));
Error(LOCATION, "%s", error_msg.c_str());
} else {
nprintf(("Warning", "%s", error_msg.c_str()));
Warning(LOCATION, "%s", error_msg.c_str());
}
}
}
}
@@ -5970,9 +5973,6 @@ bool post_process_mission()
mission_hotkey_reset_saved();
}
Last_file_checksum = Current_file_checksum;
// success
return true;
}
int get_mission_info(const char *filename, mission *mission_p, bool basic)
@@ -6038,13 +6038,12 @@ void parse_init(bool basic)
init_sexp();
}
// main parse routine for parsing a mission. The default parameter flags tells us which information
// mai parse routine for parsing a mission. The default parameter flags tells us which information
// to get when parsing the mission. 0 means get everything (default). Other flags just gets us basic
// info such as game type, number of players etc.
bool parse_main(const char *mission_name, int flags)
int parse_main(const char *mission_name, int flags)
{
int i;
bool rval;
int rval, i;
// reset parse error stuff
Num_unknown_ship_classes = 0;
@@ -6073,7 +6072,7 @@ bool parse_main(const char *mission_name, int flags)
Current_file_length = -1;
Current_file_checksum = 0;
rval = false;
rval = -1;
break;
}
@@ -6099,7 +6098,7 @@ bool parse_main(const char *mission_name, int flags)
catch (const parse::ParseException& e)
{
mprintf(("MISSIONS: Unable to parse '%s'! Error message = %s.\n", mission_name, e.what()));
rval = false;
rval = 1;
break;
}
} while (0);
@@ -6180,9 +6179,12 @@ void mission_set_wing_arrival_location( wing *wingp, int num_to_set )
if (Game_mode & GM_IN_MISSION) {
for ( index = wingp->current_count - num_to_set; index < wingp->current_count; index ++ ) {
object *objp = &Objects[Ships[wingp->ship_index[index]].objnum];
object *anchor_objp = (anchor_objnum >= 0) ? &Objects[anchor_objnum] : nullptr;
Script_system.SetHookObjects(2, "Ship", objp, "Parent", anchor_objp);
if (anchor_objnum >= 0)
Script_system.SetHookObjects(2, "Ship", objp, "Parent", &Objects[anchor_objnum]);
else
Script_system.SetHookObjects(2, "Ship", objp, "Parent", NULL);
Script_system.RunCondition(CHA_ONSHIPARRIVE, objp);
Script_system.RemHookVars(2, "Ship", "Parent");
+1 -1
View File
@@ -479,7 +479,7 @@ extern p_object *Arriving_support_ship;
extern char Neb2_texture_name[MAX_FILENAME_LEN];
bool parse_main(const char *mission_name, int flags = 0);
int parse_main(const char *mission_name, int flags = 0);
p_object *mission_parse_get_arrival_ship(ushort net_signature);
p_object *mission_parse_get_arrival_ship(const char *name);
p_object *mission_parse_get_parse_object(ushort net_signature);
+2 -2
View File
@@ -1780,7 +1780,7 @@ void draw_model_rotating(model_render_params *render_info, int model_id, int x1,
render_info->set_detail_level_lock(0);
gr_zbuffer_set(true);
if(Shadow_quality != ShadowQuality::Disabled)
if(Cmdline_shadow_quality)
{
gr_end_view_matrix();
gr_end_proj_matrix();
@@ -1894,7 +1894,7 @@ void draw_model_rotating(model_render_params *render_info, int model_id, int x1,
render_info->set_detail_level_lock(0);
if(Shadow_quality != ShadowQuality::Disabled)
if(Cmdline_shadow_quality)
{
if ( flags & MR_IS_MISSILE ) {
shadows_start_render(&Eye_matrix, &Eye_position, Proj_fov, gr_screen.clip_aspect, -closeup_pos->xyz.z + pm->rad, -closeup_pos->xyz.z + pm->rad + 20.0f, -closeup_pos->xyz.z + pm->rad + 200.0f, -closeup_pos->xyz.z + pm->rad + 1000.0f);
+1 -1
View File
@@ -909,7 +909,7 @@ void wl_render_overhead_view(float frametime)
render_info.set_replacement_textures(wl_ship->model_num, sip->replacement_textures);
}
if(Shadow_quality != ShadowQuality::Disabled)
if(Cmdline_shadow_quality)
{
gr_reset_clip();
shadows_start_render(&Eye_matrix, &Eye_position, Proj_fov, gr_screen.clip_aspect, -sip->closeup_pos.xyz.z + pm->rad,
-12
View File
@@ -47,7 +47,6 @@ bool Enable_scripts_in_fred; // By default FRED does not initialize the scriptin
SCP_string Window_icon_path;
bool Disable_built_in_translations;
bool Weapon_shockwaves_respect_huge;
bool Using_in_game_options;
void parse_mod_table(const char *filename)
{
@@ -415,16 +414,6 @@ void parse_mod_table(const char *filename)
stuff_float(&Minimum_player_warpout_time);
}
if (optional_string("$Enable in-game options:")) {
stuff_boolean(&Using_in_game_options);
if (Using_in_game_options) {
mprintf(("Game Settings Table: Using in-game options system.\n"));
} else {
mprintf(("Game Settings Table: Not using in-game options system.\n"));
}
}
required_string("#END");
}
catch (const parse::ParseException& e)
@@ -484,5 +473,4 @@ void mod_table_reset() {
Window_icon_path = "app_icon_sse";
Disable_built_in_translations = false;
Weapon_shockwaves_respect_huge = false;
Using_in_game_options = false;
}
-1
View File
@@ -38,7 +38,6 @@ extern bool Enable_scripts_in_fred;
extern SCP_string Window_icon_path;
extern bool Disable_built_in_translations;
extern bool Weapon_shockwaves_respect_huge;
extern bool Using_in_game_options;
void mod_table_init();
-1
View File
@@ -346,7 +346,6 @@ public:
bool use_render_box_offset; // whether an offset has been defined; needed because one can't tell just by looking at render_box_offset
int use_render_sphere; // 0==do nothing, 1==only render this object if you are inside the sphere, -1==only if you're outside
bool use_render_sphere_offset;// whether an offset has been defined; needed because one can't tell just by looking at render_sphere_offset
bool do_not_scale_detail_distances{false}; // if set should not scale boxes or spheres based on 'model detail' settings
bool gun_rotation; // for animated weapon models
bool no_collisions; // for $no_collisions property - kazan
bool nocollide_this_only; //SUSHI: Like no_collisions, but not recursive. For the "replacement" collision model scheme.
-10
View File
@@ -1513,11 +1513,6 @@ int read_model_file(polymodel * pm, const char *filename, int n_subsystems, mode
} else {
pm->submodel[n].render_box_max = pm->submodel[n].max;
}
if ( (p = strstr(props, "$do_not_scale_distances")) != nullptr ) {
p += 23;
pm->submodel[n].do_not_scale_detail_distances = true;
}
}
if ( (p = strstr(props, "$detail_sphere:")) != NULL ) {
@@ -1546,11 +1541,6 @@ int read_model_file(polymodel * pm, const char *filename, int n_subsystems, mode
} else {
pm->submodel[n].render_sphere_offset = vmd_zero_vector;
}
if ( (p = strstr(props, "$do_not_scale_distances")) != nullptr ) {
p += 23;
pm->submodel[n].do_not_scale_detail_distances = true;
}
}
// Added for new handling of turret orientation - KeldorKatarn
+2 -6
View File
@@ -502,7 +502,7 @@ void model_draw_list::add_buffer_draw(model_material *render_material, indexed_v
draw_data.render_material.set_deferred_lighting(possibly_deferred ? Deferred_lighting : false);
draw_data.render_material.set_high_dynamic_range(High_dynamic_range);
draw_data.render_material.set_shadow_receiving(Shadow_quality != ShadowQuality::Disabled);
draw_data.render_material.set_shadow_receiving(Cmdline_shadow_quality != 0);
}
if (tmap_flags & TMAP_FLAG_BATCH_TRANSFORMS && buffer->flags & VB_FLAG_MODEL_ID) {
@@ -1461,9 +1461,6 @@ bool model_render_check_detail_box(vec3d *view_pos, polymodel *pm, int submodel_
bsp_info *model = &pm->submodel[submodel_num];
float box_scale = model_render_determine_box_scale();
if (model->do_not_scale_detail_distances) {
box_scale = 1.0f;
}
if ( !( flags & MR_FULL_DETAIL ) && model->use_render_box ) {
vec3d box_min, box_max, offset;
@@ -2257,8 +2254,7 @@ void model_queue_render_thrusters(model_render_params *interp, polymodel *pm, in
batching_add_beam(thruster_info.secondary_glow_bitmap, &pnt, &norm2, wVal*thruster_info.secondary_glow_rad_factor*0.5f, d);
if (Scene_framebuffer_in_frame && thruster_info.draw_distortion &&
Gr_framebuffer_effects[FramebufferEffects::Thrusters]) {
if (Scene_framebuffer_in_frame && thruster_info.draw_distortion && Cmdline_fb_thrusters) {
vm_vec_scale_add(&norm2, &pnt, &fvec, wVal * 2 * thruster_info.distortion_length_factor);
int dist_bitmap;
if (thruster_info.distortion_bitmap > 0) {
+2 -2
View File
@@ -1370,8 +1370,8 @@ void process_accept_player_data( ubyte *data, header *hinfo )
if ( stop == APD_END_DATA ) {
// if joining a game automatically, set the connect address to NULl so we don't try and
// do this next time we enter a game
if (!Cmdline_connect_addr.empty()) {
Cmdline_connect_addr.clear();
if (Cmdline_connect_addr != NULL) {
Cmdline_connect_addr = NULL;
}
// send my stats to the server if I'm not in observer mode
+26 -23
View File
@@ -945,7 +945,8 @@ void multi_join_game_init()
// if starting a network game, then go to the create game screen
if ( Cmdline_start_netgame ) {
multi_join_create_game();
} else if ( !Cmdline_connect_addr.empty() ) {
} else if ( Cmdline_connect_addr != NULL ) {
char *p;
short port_num;
int ip_addr;
@@ -955,11 +956,13 @@ void multi_join_game_init()
// create the address, looking out for port number at the end
port_num = DEFAULT_GAME_PORT;
const auto number_end = Cmdline_connect_addr.find(':');
if ( number_end != SCP_string::npos ) {
port_num = (short)atoi(Cmdline_connect_addr.substr(0, number_end).c_str());
p = strrchr(Cmdline_connect_addr, ':');
if ( p ) {
*p = '\0';
p++;
port_num = (short)atoi(p);
}
ip_addr = inet_addr(Cmdline_connect_addr.c_str());
ip_addr = inet_addr(Cmdline_connect_addr);
memcpy(Multi_autojoin_addr.addr, &ip_addr, 4);
Multi_autojoin_addr.port = port_num;
@@ -1003,7 +1006,7 @@ void multi_join_game_do_frame()
}
// when joining a network game, wait for the server query to come back, and then join the game
if ( !Cmdline_connect_addr.empty() ) {
if ( Cmdline_connect_addr != NULL ) {
int rval;
if ( !Multi_did_autojoin ) {
@@ -1011,7 +1014,7 @@ void multi_join_game_do_frame()
if ( rval == 0 ) {
// cancel was hit. Send the user back to the main hall
gameseq_post_event(GS_EVENT_MAIN_MENU);
Cmdline_connect_addr.clear(); // reset this value.
Cmdline_connect_addr = NULL; // reset this value.
}
// when we get here, we have the data -- join the game.
@@ -2267,7 +2270,7 @@ void multi_sg_select_rank_default();
// function which takes a rank name and returns the index. Useful for commandline options
// for above and below rank. We return the index of the rank in the Ranks[] array. If
// the rank isn't found, we return -1
int multi_start_game_rank_from_name( const char *rank ) {
int multi_start_game_rank_from_name( char *rank ) {
int i;
for ( i = 0; i <= MAX_FREESPACE2_RANK; i++ ) {
@@ -2352,8 +2355,8 @@ void multi_start_game_init()
// if starting a netgame, set the name of the game and any other options that are appropriate
if ( Cmdline_start_netgame ) {
if ( !Cmdline_game_name.empty() ) {
strcpy_s( Multi_sg_netgame->name, Cmdline_game_name.c_str() );
if ( Cmdline_game_name != NULL ) {
strcpy_s( Multi_sg_netgame->name, Cmdline_game_name );
Multi_sg_game_name.set_text(Multi_sg_netgame->name);
}
@@ -2363,21 +2366,21 @@ void multi_start_game_init()
Multi_sg_netgame->mode = NG_MODE_CLOSED;
} else if ( Cmdline_restricted_game ) {
Multi_sg_netgame->mode = NG_MODE_RESTRICTED;
} else if ( !Cmdline_game_password.empty() ) {
} else if ( Cmdline_game_password != NULL ) {
Multi_sg_netgame->mode = NG_MODE_PASSWORD;
strcpy_s(Multi_sg_netgame->passwd, Cmdline_game_password.c_str());
strcpy_s(Multi_sg_netgame->passwd, Cmdline_game_password);
Multi_sg_game_passwd.set_text(Multi_sg_netgame->passwd);
}
// deal with rank above and rank below
if ( (!Cmdline_rank_above.empty()) || (!Cmdline_rank_below.empty()) ) {
if ( (Cmdline_rank_above != NULL) || (Cmdline_rank_below != NULL) ) {
int rank;
const char *rank_str;
char *rank_str;
if ( !Cmdline_rank_above.empty() ) {
rank_str = Cmdline_rank_above.c_str();
if ( Cmdline_rank_above != NULL ) {
rank_str = Cmdline_rank_above;
} else {
rank_str = Cmdline_rank_below.c_str();
rank_str = Cmdline_rank_below;
}
// try and get the rank index from the name -- if found, then set the rank base
@@ -2388,7 +2391,7 @@ void multi_start_game_init()
Multi_sg_netgame->rank_base = Multi_sg_rank_select;
// now an arbitrary decision
if ( !Cmdline_rank_above.empty() ) {
if ( Cmdline_rank_above != NULL ) {
Multi_sg_netgame->mode = NG_MODE_RANK_ABOVE;
} else {
Multi_sg_netgame->mode = NG_MODE_RANK_BELOW;
@@ -3644,7 +3647,7 @@ void multi_create_game_do()
//DTP CHECK ALMISSION FLAG HERE AND SKIP THE BITMAP LOADING PROGRESS
//SINCE WE ALREADY HAVE A MISSION SELECTED IF THIS MISSION IS A VALID MULTIPLAYER MISSION
//IF NOT A VALID MULTIPLAYER MISSION CONTINUE LOADING, MAYBE CALL POPUP.
if ((!Cmdline_almission.empty()) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) { //
if ((Cmdline_almission) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) { //
multi_create_list_do(); //uhm here because off, hehe, my mind is failing right now
// DTP Var section for the is mission multi player Check.
@@ -3652,7 +3655,7 @@ void multi_create_game_do()
char mission_name[NAME_LENGTH+1];
int flags;
char *filename;
filename = cf_add_ext( Cmdline_almission.c_str(), FS_MISSION_FILE_EXT ); //DTP ADD EXTENSION needed next line
filename = cf_add_ext( Cmdline_almission, FS_MISSION_FILE_EXT ); //DTP ADD EXTENSION needed next line
flags = mission_parse_is_multi(filename, mission_name); //DTP flags will set if mission is multi
if (flags) { //only continue if mission is multiplayer mission
@@ -3660,7 +3663,7 @@ void multi_create_game_do()
ng = &Netgame;
char almissionname[256]; // needed, for the strncpy below
strncpy(almissionname, Cmdline_almission.c_str(), MAX_FILENAME_LEN); //DTP; copying name from cmd_almission line
strncpy(almissionname, Cmdline_almission,MAX_FILENAME_LEN); //DTP; copying name from cmd_almission line
Netgame.options.respawn = 99; //override anything //for debugging, i often forget this.
ng->respawn = Netgame.options.respawn;
@@ -3673,13 +3676,13 @@ void multi_create_game_do()
Multi_sync_mode = MULTI_SYNC_PRE_BRIEFING; //DTP must be set before a call to gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC) is done as it is below.
gameseq_post_event(GS_EVENT_MULTI_MISSION_SYNC);//DTP STart game
Cmdline_almission.clear(); // we don't want to autoload anymore do we, we will be able to quit. halleluja. Startgame has already been disabled, so no need to turn of "Cmdline_start_netgame"
Cmdline_almission = NULL; // we don't want to autoload anymore do we, we will be able to quit. halleluja. Startgame has already been disabled, so no need to turn of "Cmdline_start_netgame"
return; // we don't need to check or set regarding ships/weapons anything as we are already progressing into mission so return
}
else {
popup(PF_BODY_BIG | PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR(" Not a multi player-mission",9999)); //DTP startgame popup pilot error
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
Cmdline_almission.clear(); //DTP make sure this gets nullified.
Cmdline_almission = NULL; //DTP make sure this gets nullified.
}
}
+2 -2
View File
@@ -3263,7 +3263,7 @@ void multi_spew_pxo_checksums(int max_files, const char *outfile)
char filename[65] = { 0 };
char gametype[32] = { 0 };
size_t offset = 0;
const char *p = nullptr;
char *p = NULL;
// allocate filename space
file_names = (char**)vm_malloc(sizeof(char*) * max_files);
@@ -3285,7 +3285,7 @@ void multi_spew_pxo_checksums(int max_files, const char *outfile)
if (out == NULL)
goto Done;
p = Cmdline_spew_mission_crcs.c_str();
p = Cmdline_spew_mission_crcs;
while (*p && (offset < sizeof(description))) {
if (*p == '"') {
+13 -18
View File
@@ -66,14 +66,11 @@ int collide_debris_ship( obj_pair * pair )
hit = debris_check_collision(pdebris, pship, &hitpos, &debris_hit_info );
if ( hit )
{
Script_system.SetHookObjects(4, "Self", pship, "Object", pdebris, "Ship", pship, "Debris", pdebris);
Script_system.SetHookObjects(4, "Ship", pship, "Debris", pdebris, "Self", pship, "Object", pdebris);
bool ship_override = Script_system.IsConditionOverride(CHA_COLLIDEDEBRIS, pship);
Script_system.RemHookVars(4, "Self", "Object", "Ship", "Debris");
Script_system.SetHookObjects(4, "Self", pdebris, "Object", pship, "Ship", pship, "Debris", pdebris);
Script_system.SetHookObjects(2, "Self",pdebris, "Object", pship);
bool debris_override = Script_system.IsConditionOverride(CHA_COLLIDESHIP, pdebris);
Script_system.RemHookVars(4, "Self", "Object", "Ship", "Debris");
if(!ship_override && !debris_override)
{
float ship_damage;
@@ -111,7 +108,7 @@ int collide_debris_ship( obj_pair * pair )
int quadrant_num, apply_ship_damage;
// apply damage to ship unless 1) debris is from ship
apply_ship_damage = (pship->signature != pdebris->parent_sig);
apply_ship_damage = !(pship->signature == pdebris->parent_sig);
if ( debris_hit_info.heavy == pship ) {
quadrant_num = get_ship_quadrant_from_global(&hitpos, pship);
@@ -136,15 +133,15 @@ int collide_debris_ship( obj_pair * pair )
collide_ship_ship_do_sound(&hitpos, pship, pdebris, pship==Player_obj);
}
Script_system.SetHookObjects(4, "Self", pship, "Object", pdebris, "Ship", pship, "Debris", pdebris);
Script_system.SetHookObjects(2, "Self",pship, "Object", pdebris);
if(!(debris_override && !ship_override))
Script_system.RunCondition(CHA_COLLIDEDEBRIS, pship);
Script_system.RemHookVars(4, "Self", "Object", "Ship", "Debris");
Script_system.SetHookObjects(4, "Self", pdebris, "Object", pship, "Ship", pship, "Debris", pdebris);
Script_system.SetHookObjects(2, "Self",pdebris, "Object", pship);
if((debris_override && !ship_override) || (!debris_override && !ship_override))
Script_system.RunCondition(CHA_COLLIDESHIP, pdebris);
Script_system.RemHookVars(4, "Self", "Object", "Ship", "Debris");
Script_system.RemHookVars(4, "Ship", "Debris", "Self", "Object");
return 0;
}
@@ -224,13 +221,11 @@ int collide_asteroid_ship( obj_pair * pair )
if ( hit )
{
//Scripting support (WMC)
Script_system.SetHookObjects(4, "Self", pship, "Object", pasteroid, "Ship", pship, "Asteroid", pasteroid);
Script_system.SetHookObjects(4, "Ship", pship, "Asteroid", pasteroid, "Self",pship, "Object", pasteroid);
bool ship_override = Script_system.IsConditionOverride(CHA_COLLIDEASTEROID, pship);
Script_system.RemHookVars(4, "Self", "Object", "Ship", "Asteroid");
Script_system.SetHookObjects(4, "Self", pasteroid, "Object", pship, "Ship", pship, "Asteroid", pasteroid);
Script_system.SetHookObjects(2, "Self",pasteroid, "Object", pship);
bool asteroid_override = Script_system.IsConditionOverride(CHA_COLLIDESHIP, pasteroid);
Script_system.RemHookVars(4, "Self", "Object", "Ship", "Asteroid");
if(!ship_override && !asteroid_override)
{
@@ -299,15 +294,15 @@ int collide_asteroid_ship( obj_pair * pair )
collide_ship_ship_do_sound(&hitpos, pship, pasteroid, pship==Player_obj);
}
Script_system.SetHookObjects(4, "Self", pship, "Object", pasteroid, "Ship", pship, "Asteroid", pasteroid);
Script_system.SetHookObjects(2, "Self",pship, "Object", pasteroid);
if(!(asteroid_override && !ship_override))
Script_system.RunCondition(CHA_COLLIDEASTEROID, pship);
Script_system.RemHookVars(4, "Self", "Object", "Ship", "Asteroid");
Script_system.SetHookObjects(4, "Self", pasteroid, "Object", pship, "Ship", pship, "Asteroid", pasteroid);
Script_system.SetHookObjects(2, "Self",pasteroid, "Object", pship);
if((asteroid_override && !ship_override) || (!asteroid_override && !ship_override))
Script_system.RunCondition(CHA_COLLIDESHIP, pasteroid);
Script_system.RemHookVars(4, "Self", "Object", "Ship", "Asteroid");
Script_system.RemHookVars(4, "Ship", "Asteroid", "Self", "Object");
return 0;
}
+17 -21
View File
@@ -27,6 +27,7 @@
int collide_debris_weapon( obj_pair * pair )
{
vec3d hitpos, hitnormal;
int hit;
object *pdebris = pair->a;
object *weapon_obj = pair->b;
@@ -34,20 +35,18 @@ int collide_debris_weapon( obj_pair * pair )
Assert( weapon_obj->type == OBJ_WEAPON );
// first check the bounding spheres of the two objects.
int hit = fvi_segment_sphere(&hitpos, &weapon_obj->last_pos, &weapon_obj->pos, &pdebris->pos, pdebris->radius);
hit = fvi_segment_sphere(&hitpos, &weapon_obj->last_pos, &weapon_obj->pos, &pdebris->pos, pdebris->radius);
if (hit) {
hit = debris_check_collision(pdebris, weapon_obj, &hitpos, nullptr, &hitnormal );
hit = debris_check_collision(pdebris, weapon_obj, &hitpos, NULL, &hitnormal );
if ( !hit )
return 0;
Script_system.SetHookObjects(4, "Self", weapon_obj, "Object", pdebris, "Weapon", weapon_obj, "Debris", pdebris);
Script_system.SetHookObjects(4, "Weapon", weapon_obj, "Debris", pdebris, "Self", weapon_obj, "Object", pdebris);
bool weapon_override = Script_system.IsConditionOverride(CHA_COLLIDEDEBRIS, weapon_obj);
Script_system.RemHookVars(4, "Self", "Object", "Weapon", "Debris");
Script_system.SetHookObjects(4, "Self", pdebris, "Object", weapon_obj, "Weapon", weapon_obj, "Debris", pdebris);
Script_system.SetHookObjects(2, "Self", pdebris, "Object", weapon_obj);
bool debris_override = Script_system.IsConditionOverride(CHA_COLLIDEWEAPON, pdebris);
Script_system.RemHookVars(4, "Self", "Object", "Weapon", "Debris");
if(!weapon_override && !debris_override)
{
@@ -55,16 +54,15 @@ int collide_debris_weapon( obj_pair * pair )
debris_hit( pdebris, weapon_obj, &hitpos, Weapon_info[Weapons[weapon_obj->instance].weapon_info_index].damage );
}
Script_system.SetHookObjects(4, "Self", weapon_obj, "Object", pdebris, "Weapon", weapon_obj, "Debris", pdebris);
Script_system.SetHookObjects(2, "Self", weapon_obj, "Object", pdebris);
if(!(debris_override && !weapon_override))
Script_system.RunCondition(CHA_COLLIDEDEBRIS, weapon_obj);
Script_system.RemHookVars(4, "Self", "Object", "Weapon", "Debris");
Script_system.SetHookObjects(4, "Self", pdebris, "Object", weapon_obj, "Weapon", weapon_obj, "Debris", pdebris);
Script_system.SetHookObjects(2, "Self", pdebris, "Object", weapon_obj);
if((debris_override && !weapon_override) || (!debris_override && !weapon_override))
Script_system.RunCondition(CHA_COLLIDEWEAPON, pdebris, Weapons[weapon_obj->instance].weapon_info_index);
Script_system.RemHookVars(4, "Self", "Object", "Weapon", "Debris");
Script_system.RemHookVars(4, "Weapon", "Debris", "Self", "Object");
return 0;
} else {
@@ -85,6 +83,7 @@ int collide_asteroid_weapon( obj_pair * pair )
return 0;
vec3d hitpos, hitnormal;
int hit;
object *pasteroid = pair->a;
object *weapon_obj = pair->b;
@@ -92,19 +91,17 @@ int collide_asteroid_weapon( obj_pair * pair )
Assert( weapon_obj->type == OBJ_WEAPON );
// first check the bounding spheres of the two objects.
int hit = fvi_segment_sphere(&hitpos, &weapon_obj->last_pos, &weapon_obj->pos, &pasteroid->pos, pasteroid->radius);
hit = fvi_segment_sphere(&hitpos, &weapon_obj->last_pos, &weapon_obj->pos, &pasteroid->pos, pasteroid->radius);
if (hit) {
hit = asteroid_check_collision(pasteroid, weapon_obj, &hitpos, nullptr, &hitnormal);
hit = asteroid_check_collision(pasteroid, weapon_obj, &hitpos, NULL, &hitnormal);
if ( !hit )
return 0;
Script_system.SetHookObjects(4, "Self", weapon_obj, "Object", pasteroid, "Weapon", weapon_obj, "Asteroid", pasteroid);
bool weapon_override = Script_system.IsConditionOverride(CHA_COLLIDEASTEROID, weapon_obj);
Script_system.RemHookVars(4, "Self", "Object", "Weapon", "Asteroid");
Script_system.SetHookObjects(4, "Weapon", weapon_obj, "Asteroid", pasteroid, "Self", weapon_obj, "Object", pasteroid);
Script_system.SetHookObjects(4, "Self", pasteroid, "Object", weapon_obj, "Weapon", weapon_obj, "Asteroid", pasteroid);
bool weapon_override = Script_system.IsConditionOverride(CHA_COLLIDEASTEROID, weapon_obj);
Script_system.SetHookObjects(2, "Self",pasteroid, "Object", weapon_obj);
bool asteroid_override = Script_system.IsConditionOverride(CHA_COLLIDEWEAPON, pasteroid);
Script_system.RemHookVars(4, "Self", "Object", "Weapon", "Asteroid");
if(!weapon_override && !asteroid_override)
{
@@ -112,16 +109,15 @@ int collide_asteroid_weapon( obj_pair * pair )
asteroid_hit( pasteroid, weapon_obj, &hitpos, Weapon_info[Weapons[weapon_obj->instance].weapon_info_index].damage );
}
Script_system.SetHookObjects(4, "Self", weapon_obj, "Object", pasteroid, "Weapon", weapon_obj, "Asteroid", pasteroid);
Script_system.SetHookObjects(2, "Self", weapon_obj, "Object", pasteroid);
if(!(asteroid_override && !weapon_override))
Script_system.RunCondition(CHA_COLLIDEASTEROID, weapon_obj);
Script_system.RemHookVars(4, "Self", "Object", "Weapon", "Asteroid");
Script_system.SetHookObjects(4, "Self", pasteroid, "Object", weapon_obj, "Weapon", weapon_obj, "Asteroid", pasteroid);
Script_system.SetHookObjects(2, "Self", pasteroid, "Object", weapon_obj);
if((asteroid_override && !weapon_override) || (!asteroid_override && !weapon_override))
Script_system.RunCondition(CHA_COLLIDEWEAPON, pasteroid, Weapons[weapon_obj->instance].weapon_info_index);
Script_system.RemHookVars(4, "Self", "Object", "Weapon", "Asteroid");
Script_system.RemHookVars(4, "Weapon", "Asteroid", "Self", "Object");
return 0;
} else {
+13 -15
View File
@@ -129,7 +129,7 @@ int ship_ship_check_collision(collision_info_struct *ship_ship_hit_info, vec3d *
}
// Make ships that are warping in not get collision detection done
if ( heavy_shipp->is_arriving(ship::warpstage::STAGE1, false) ) {
if ( heavy_shipp->flags[Ship::Ship_Flags::Arriving_stage_1] ) {
return 0;
}
@@ -381,6 +381,8 @@ int ship_ship_check_collision(collision_info_struct *ship_ship_hit_info, vec3d *
// SET PHYSICS PARAMETERS
// already have (hitpos - heavy) and light_cm_pos
// get heavy cm pos - already have light_cm_pos
ship_ship_hit_info->heavy_collision_cm_pos = zero;
// get r_heavy and r_light
ship_ship_hit_info->r_heavy = ship_ship_hit_info->hit_pos;
@@ -1135,15 +1137,12 @@ int collide_ship_ship( obj_pair * pair )
if ( hit )
{
Script_system.SetHookObjects(4, "Self", A, "Object", B, "Ship", A, "ShipB", B);
Script_system.SetHookObjects(4, "Ship", A, "ShipB", B, "Self", A, "Object", B);
bool a_override = Script_system.IsConditionOverride(CHA_COLLIDESHIP, A);
Script_system.RemHookVars(4, "Self", "Object", "Ship", "ShipB");
// Yes, this should be reversed.
Script_system.SetHookObjects(4, "Self", B, "Object", A, "Ship", B, "ShipB", A);
//Yes this should be reversed.
Script_system.SetHookObjects(4, "Ship", B, "ShipB", A, "Self", B, "Object", A);
bool b_override = Script_system.IsConditionOverride(CHA_COLLIDESHIP, B);
Script_system.RemHookVars(4, "Self", "Object", "Ship", "ShipB");
if(!a_override && !b_override)
{
float damage;
@@ -1248,18 +1247,17 @@ int collide_ship_ship( obj_pair * pair )
if(!(b_override && !a_override))
{
Script_system.SetHookObjects(4, "Self", A, "Object", B, "Ship", A, "ShipB", B);
Script_system.SetHookObjects(4, "Ship", A, "ShipB", B, "Self", A, "Object", B);
Script_system.RunCondition(CHA_COLLIDESHIP, A);
Script_system.RemHookVars(4, "Self", "Object", "Ship", "ShipB");
}
if((b_override && !a_override) || (!b_override && !a_override))
{
// Yes, this should be reversed.
Script_system.SetHookObjects(4, "Self", B, "Object", A, "Ship", B, "ShipB", A);
//Yes this should be reversed.
Script_system.SetHookObjects(4, "Ship", B, "ShipB", A, "Self", B, "Object", A);
Script_system.RunCondition(CHA_COLLIDESHIP, B);
Script_system.RemHookVars(4, "Self", "Object", "Ship", "ShipB");
}
Script_system.RemHookVars(4, "Ship", "ShipB", "Self", "Object");
return 0;
}
}
@@ -1270,8 +1268,8 @@ int collide_ship_ship( obj_pair * pair )
// if ship is warping in, in stage 1, its velocity is 0, so make ship try to collide next frame
// if ship is huge and warping in or out
if (((Ships[A->instance].is_arriving(ship::warpstage::STAGE1, false)) && (Ship_info[Ships[A->instance].ship_info_index].is_huge_ship()))
|| ((Ships[B->instance].is_arriving(ship::warpstage::STAGE1, false)) && (Ship_info[Ships[B->instance].ship_info_index].is_huge_ship())) ) {
if (((Ships[A->instance].flags[Ship::Ship_Flags::Arriving_stage_1]) && (Ship_info[Ships[A->instance].ship_info_index].is_huge_ship()))
|| ((Ships[B->instance].flags[Ship::Ship_Flags::Arriving_stage_1]) && (Ship_info[Ships[B->instance].ship_info_index].is_huge_ship())) ) {
pair->next_check_time = timestamp(0); // check next time
return 0;
}
+9 -11
View File
@@ -129,7 +129,7 @@ static void ship_weapon_do_hit_stuff(object *pship_obj, object *weapon_obj, vec3
extern int Framecount;
static int ship_weapon_check_collision(object *ship_objp, object *weapon_objp, float time_limit = 0.0f, int *next_hit = nullptr)
static int ship_weapon_check_collision(object *ship_objp, object *weapon_objp, float time_limit = 0.0f, int *next_hit = NULL)
{
mc_info mc, mc_shield, mc_hull;
ship *shipp;
@@ -137,14 +137,14 @@ static int ship_weapon_check_collision(object *ship_objp, object *weapon_objp, f
weapon *wp;
weapon_info *wip;
Assert( ship_objp != nullptr );
Assert( ship_objp != NULL );
Assert( ship_objp->type == OBJ_SHIP );
Assert( ship_objp->instance >= 0 );
shipp = &Ships[ship_objp->instance];
sip = &Ship_info[shipp->ship_info_index];
Assert( weapon_objp != nullptr );
Assert( weapon_objp != NULL );
Assert( weapon_objp->type == OBJ_WEAPON );
Assert( weapon_objp->instance >= 0 );
@@ -422,13 +422,11 @@ static int ship_weapon_check_collision(object *ship_objp, object *weapon_objp, f
wp->collisionInfo = new mc_info; // The weapon will free this memory later
memcpy(wp->collisionInfo, &mc, sizeof(mc_info));
Script_system.SetHookObjects(4, "Self", ship_objp, "Object", weapon_objp, "Ship", ship_objp, "Weapon", weapon_objp);
Script_system.SetHookObjects(4, "Ship", ship_objp, "Weapon", weapon_objp, "Self",ship_objp, "Object", weapon_objp);
bool ship_override = Script_system.IsConditionOverride(CHA_COLLIDEWEAPON, ship_objp);
Script_system.RemHookVars(4, "Self", "Object", "Ship", "Weapon");
Script_system.SetHookObjects(4, "Self", weapon_objp, "Object", ship_objp, "Ship", ship_objp, "Weapon", weapon_objp);
Script_system.SetHookObjects(2, "Self",weapon_objp, "Object", ship_objp);
bool weapon_override = Script_system.IsConditionOverride(CHA_COLLIDESHIP, weapon_objp);
Script_system.RemHookVars(4, "Self", "Object", "Ship", "Weapon");
if(!ship_override && !weapon_override) {
if (shield_collision && quadrant_num >= 0) {
@@ -439,15 +437,15 @@ static int ship_weapon_check_collision(object *ship_objp, object *weapon_objp, f
ship_weapon_do_hit_stuff(ship_objp, weapon_objp, &mc.hit_point_world, &mc.hit_point, quadrant_num, mc.hit_submodel, mc.hit_normal);
}
Script_system.SetHookObjects(4, "Self", ship_objp, "Object", weapon_objp, "Ship", ship_objp, "Weapon", weapon_objp);
Script_system.SetHookObjects(2, "Self",ship_objp, "Object", weapon_objp);
if(!(weapon_override && !ship_override))
Script_system.RunCondition(CHA_COLLIDEWEAPON, ship_objp, wp->weapon_info_index);
Script_system.RemHookVars(4, "Self", "Object", "Ship", "Weapon");
Script_system.SetHookObjects(4, "Self", weapon_objp, "Object", ship_objp, "Ship", ship_objp, "Weapon", weapon_objp);
Script_system.SetHookObjects(2, "Self",weapon_objp, "Object", ship_objp);
if((weapon_override && !ship_override) || (!weapon_override && !ship_override))
Script_system.RunCondition(CHA_COLLIDESHIP, weapon_objp);
Script_system.RemHookVars(4, "Self", "Object", "Ship", "Weapon");
Script_system.RemHookVars(4, "Ship", "Weapon", "Self","Object");
}
else if ((Missiontime - wp->creation_time > F1_0/2) && (wip->is_homing()) && (wp->homing_object == ship_objp)) {
if (dist < wip->shockwave.inner_rad) {
+8 -11
View File
@@ -82,14 +82,12 @@ int collide_weapon_weapon( obj_pair * pair )
// Rats, do collision detection.
if (collide_subdivide(&A->last_pos, &A->pos, A_radius, &B->last_pos, &B->pos, B_radius))
{
Script_system.SetHookObjects(4, "Self", A, "Object", B, "Weapon", A, "WeaponB", B);
Script_system.SetHookObjects(4, "Weapon", A, "WeaponB", B, "Self",A, "Object", B);
bool a_override = Script_system.IsConditionOverride(CHA_COLLIDEWEAPON, A);
Script_system.RemHookVars(4, "Self", "Object", "Weapon", "WeaponB");
// Yes, this should be reversed.
Script_system.SetHookObjects(4, "Self", B, "Object", A, "Weapon", B, "WeaponB", A);
//Should be reversed
Script_system.SetHookObjects(4, "Weapon", B, "WeaponB", A, "Self",B, "Object", A);
bool b_override = Script_system.IsConditionOverride(CHA_COLLIDEWEAPON, B);
Script_system.RemHookVars(4, "Self", "Object", "Weapon", "WeaponB");
if(!a_override && !b_override)
{
@@ -172,18 +170,17 @@ int collide_weapon_weapon( obj_pair * pair )
if(!(b_override && !a_override))
{
Script_system.SetHookObjects(4, "Self", A, "Object", B, "Weapon", A, "WeaponB", B);
Script_system.SetHookObjects(4, "Weapon", A, "WeaponB", B, "Self",A, "Object", B);
Script_system.RunCondition(CHA_COLLIDEWEAPON, A, wpA->weapon_info_index);
Script_system.RemHookVars(4, "Self", "Object", "Weapon", "WeaponB");
}
else
{
// Yes, this should be reversed.
Script_system.SetHookObjects(4, "Self", B, "Object", A, "Weapon", B, "WeaponB", A);
//Should be reversed
Script_system.SetHookObjects(4, "Weapon", B, "WeaponB", A, "Self",B, "Object", A);
Script_system.RunCondition(CHA_COLLIDEWEAPON, B, wpB->weapon_info_index);
Script_system.RemHookVars(4, "Self", "Object", "Weapon", "WeaponB");
}
Script_system.RemHookVars(4, "Weapon", "WeaponB", "Self", "Object");
return 1;
}
+865 -433
View File
File diff suppressed because it is too large. Load diff
+14 -5
View File
@@ -19,9 +19,10 @@ struct CFILE;
struct mc_info;
// used for ship:ship and ship:debris
struct collision_info_struct {
typedef struct collision_info_struct {
object *heavy;
object *light;
vec3d heavy_collision_cm_pos; // should be zero
vec3d light_collision_cm_pos; // relative cm collision pos
vec3d r_heavy; // relative to A
vec3d r_light; // relative to B
@@ -35,7 +36,7 @@ struct collision_info_struct {
int edge_hit; // if edge is hit, need to change collision normal
int submodel_rot_hit; // if collision is against rotating submodel
bool is_landing; //SUSHI: Maybe treat current collision as a landing
};
} collision_info_struct;
//Collision physics constants
#define COLLISION_FRICTION_FACTOR 0.0f //Default value if not set in ships.tbl
@@ -50,12 +51,13 @@ struct collision_info_struct {
//===============================================================================
// Keeps track of pairs of objects for collision detection
struct obj_pair {
typedef struct obj_pair {
object *a;
object *b;
int (*check_collision)( obj_pair * pair );
int next_check_time; // a timestamp that when elapsed means to check for a collision
struct obj_pair *next;
};
} obj_pair;
#define COLLISION_OF(a,b) (((a)<<8)|(b))
@@ -64,10 +66,17 @@ struct obj_pair {
#define SUBMODEL_ROT_HIT 1
void set_hit_struct_info(collision_info_struct *hit, mc_info *mc, int submodel_rot_hit);
void obj_add_pair( object *A, object *B, int check_time = -1, int add_to_end = 0 );
void obj_add_collider(int obj_index);
void obj_remove_collider(int obj_index);
void obj_reset_colliders();
void obj_sort_and_collide();
void obj_quicksort_colliders(SCP_vector<int> *list, int left, int right, int axis);
void obj_find_overlap_colliders(SCP_vector<int> *overlap_list_out, SCP_vector<int> *list, int axis, bool collide);
float obj_get_collider_endpoint(int obj_num, int axis, bool min);
void obj_collide_pair(object *A, object *B);
// retimes all collision pairs to be checked (in 25ms by default)
void obj_collide_retime_cached_pairs(int checkdly=25);
@@ -125,7 +134,7 @@ int pp_collide(vec3d *curpos, vec3d *goalpos, object *goalobjp, float radius);
int collide_predict_large_ship(object *objp, float distance);
// function to remove old weapons when no more weapon slots available.
int collide_remove_weapons();
int collide_remove_weapons(void);
void collide_ship_ship_do_sound(vec3d *world_hit_pos, object *A, object *B, int player_involved);
void collide_ship_ship_sounds_init();
+82 -1
View File
@@ -1498,8 +1498,8 @@ void obj_move_all(float frametime)
Script_system.SetHookObjects(2, "User", objp, "Target", target);
Script_system.RunCondition(CHA_ONWPEQUIPPED, objp);
Script_system.RemHookVars(2, "User", "Target");
}
Script_system.RemHookVars(2, "User", "Target");
}
// Now that we've moved all the objects, move all the models that use intrinsic rotations. We do that here because we already handled the
@@ -1853,11 +1853,92 @@ int obj_team(object *objp)
return team;
}
/**
* Add an element to the CheckObjects[] array, and update the
* object pairs. This is called from obj_create(), and the restore
* save-game code.
*/
void obj_add_pairs(int objnum)
{
object *objp;
Assert(objnum != -1);
objp = &Objects[objnum];
// don't do anything if its already in the object pair list
if(!(objp->flags[Object::Object_Flags::Not_in_coll])){
return;
}
#ifdef OBJECT_CHECK
CheckObjects[objnum].type = objp->type;
CheckObjects[objnum].signature = objp->signature;
CheckObjects[objnum].flags = objp->flags;
CheckObjects[objnum].flags.remove(Object::Object_Flags::Not_in_coll);
CheckObjects[objnum].parent_sig = objp->parent_sig;
CheckObjects[objnum].parent_type = objp->parent_type;
#endif
// Find all the objects that can collide with this and add
// it to the collision pair list.
object * A;
for ( A = GET_FIRST(&obj_used_list); A !=END_OF_LIST(&obj_used_list); A = GET_NEXT(A) ) {
obj_add_pair( objp, A );
}
objp->flags.remove(Object::Object_Flags::Not_in_coll);
}
/**
* Removes any occurances of object 'a' from
* the pairs list.
*/
extern int Num_pairs;
extern obj_pair pair_used_list;
extern obj_pair pair_free_list;
void obj_remove_pairs( object * a )
{
obj_pair *parent, *tmp;
a->flags.set(Object::Object_Flags::Not_in_coll);
#ifdef OBJECT_CHECK
CheckObjects[OBJ_INDEX(a)].flags.set(Object::Object_Flags::Not_in_coll);
#endif
if ( a->num_pairs < 1 ) {
return;
}
Num_pairs-=a->num_pairs;
parent = &pair_used_list;
tmp = parent->next;
while( tmp != NULL ) {
if ( (tmp->a==a) || (tmp->b==a) ) {
// Hmmm... a potenial compiler optimization problem here... either tmp->a or tmp->b
// is equal to 'a' and we modify 'num_pairs' in one of these and then use the value
// stored in 'a' later one... will the optimizer find that? Hmmm...
tmp->a->num_pairs--;
Assert( tmp->a->num_pairs > -1 );
tmp->b->num_pairs--;
Assert( tmp->b->num_pairs > -1 );
parent->next = tmp->next;
tmp->a = tmp->b = NULL;
tmp->next = pair_free_list.next;
pair_free_list.next = tmp;
tmp = parent->next;
if ( a->num_pairs==0 ) {
break;
}
} else {
parent = tmp;
tmp = tmp->next;
}
}
}
/**
* Reset all collisions
+6
View File
@@ -254,6 +254,12 @@ void obj_merge_created_list(void);
// recalculate object pairs for an object
#define OBJ_RECALC_PAIRS(obj_to_reset) do { obj_set_flags(obj_to_reset, obj_to_reset->flags - Object::Object_Flags::Collides); obj_set_flags(obj_to_reset, obj_to_reset->flags + Object::Object_Flags::Collides); } while(0);
// Removes any occurances of object 'a' from the pairs list.
void obj_remove_pairs( object * a );
// add an object to the pairs list
void obj_add_pairs(int objnum);
// Returns true if objects A and B are expected to collide in next duration seconds.
// For purposes of this check, the first object moves from current location to predicted
// location. The second object is assumed to be where it will be at time duration, NOT
-25
View File
@@ -708,31 +708,6 @@ void dock_find_max_speed_helper(object *objp, dock_function_info *infop)
infop->maintained_variables.objp_value = objp;
}
}
void object_set_arriving_stage1_ndl_flag_helper(object *objp, dock_function_info * /*infop*/ )
{
if (! Ships[objp->instance].flags[Ship::Ship_Flags::Dock_leader])
Ships[objp->instance].flags.set(Ship::Ship_Flags::Arriving_stage_1_dock_follower);
}
void object_remove_arriving_stage1_ndl_flag_helper(object *objp, dock_function_info * /*infop*/ )
{
if (! Ships[objp->instance].flags[Ship::Ship_Flags::Dock_leader])
Ships[objp->instance].flags.remove(Ship::Ship_Flags::Arriving_stage_1_dock_follower);
}
void object_set_arriving_stage2_ndl_flag_helper(object *objp, dock_function_info * /*infop*/ )
{
if (! Ships[objp->instance].flags[Ship::Ship_Flags::Dock_leader])
Ships[objp->instance].flags.set(Ship::Ship_Flags::Arriving_stage_2_dock_follower);
}
void object_remove_arriving_stage2_ndl_flag_helper(object *objp, dock_function_info * /*infop*/ )
{
if (! Ships[objp->instance].flags[Ship::Ship_Flags::Dock_leader])
Ships[objp->instance].flags.remove(Ship::Ship_Flags::Arriving_stage_2_dock_follower);
}
// ---------------------------------------------------------------------------------------------------------------
// end of über code block ----------------------------------------------------------------------------------------
-6
View File
@@ -141,10 +141,4 @@ void dock_undock_all(object *objp);
// free the entire dock list without undocking anything; should only be used on object cleanup
void dock_free_dock_list(object *objp);
// flag set/remove helpers required in multiple places
void object_set_arriving_stage1_ndl_flag_helper(object *objp, dock_function_info * /*infop*/ );
void object_remove_arriving_stage1_ndl_flag_helper(object *objp, dock_function_info * /*infop*/ );
void object_set_arriving_stage2_ndl_flag_helper(object *objp, dock_function_info * /*infop*/ );
void object_remove_arriving_stage2_ndl_flag_helper(object *objp, dock_function_info * /*infop*/ );
#endif // _OBJECT_DOCK_H
+7 -12
View File
@@ -391,23 +391,18 @@ void maybe_play_flyby_snd(float closest_dist, object *closest_objp, object *list
return;
}
// check to see if a flyby sound is specified in ship class
// if not, then pick a random species-based sound
// pick a random species-based sound
ship_info* sip = &Ship_info[Ships[closest_objp->instance].ship_info_index];
ship_info *sip = &Ship_info[Ships[closest_objp->instance].ship_info_index];
game_snd *snd;
if (sip->flyby_snd.isValid()) {
snd = gamesnd_get_game_sound(sip->flyby_snd);
} else {
if (sip->flags[Ship::Info_Flags::Bomber])
snd = &Species_info[sip->species].snd_flyby_bomber;
else
snd = &Species_info[sip->species].snd_flyby_fighter;
}
if (sip->flags[Ship::Info_Flags::Bomber])
snd = &Species_info[sip->species].snd_flyby_bomber;
else
snd = &Species_info[sip->species].snd_flyby_fighter;
if (snd->sound_entries.empty())
return; // This class or species does not define any relevant flyby sounds
return; //This species does not define any relevant flyby sounds
// play da sound
snd_play_3d(snd, &closest_objp->pos, &View_position);
-138
View File
@@ -1,138 +0,0 @@
//
//
#include "Option.h"
#include "OptionsManager.h"
#include "parse/parselo.h"
#include <utility>
namespace {
} // namespace
namespace options {
namespace internal {
json_t* string_serializer(const SCP_string& value) { return json_pack("s", value.c_str()); }
SCP_string string_deserializer(const json_t* value) {
const char* s;
json_error_t err;
if (json_unpack_ex((json_t*)value, &err, 0, "s", &s) != 0) {
throw json_exception(err);
}
return SCP_string(s);
}
template<>
void set_defaults<SCP_string>(Option<SCP_string>& opt) {
opt.setDeserializer(string_deserializer);
opt.setSerializer(string_serializer);
}
float float_deserializer(const json_t* value)
{
double f;
json_error_t err;
if (json_unpack_ex((json_t*)value, &err, 0, "f", &f) != 0) {
throw json_exception(err);
}
return (float)f;
}
json_t* float_serializer(float value) { return json_pack("f", value); }
SCP_string float_display(float value)
{
SCP_string out;
sprintf(out, "%.1f", value);
return out;
}
template<>
void set_defaults<float>(Option<float>& opt) {
opt.setDeserializer(float_deserializer);
opt.setSerializer(float_serializer);
opt.setDisplayFunc(float_display);
opt.setType(OptionType::Range);
}
bool boolean_deserializer(const json_t* value)
{
int b;
json_error_t err;
if (json_unpack_ex((json_t*)value, &err, 0, "b", &b) != 0) {
throw json_exception(err);
}
return b != 0;
}
json_t* boolean_serializer(bool value) { return json_pack("b", value ? 1 : 0); }
SCP_string boolean_display(bool value) { return value ? "On" : "Off"; }
template<>
void set_defaults<bool>(Option<bool>& opt) {
opt.setDeserializer(boolean_deserializer);
opt.setSerializer(boolean_serializer);
opt.setDisplayFunc(boolean_display);
opt.setValueEnumerator(VectorEnumerator<bool>({false, true}));
}
} // namespace internal
ValueDescription::ValueDescription(SCP_string _display, SCP_string _serialized)
: display(std::move(_display)), serialized(std::move(_serialized))
{
}
OptionBase::~OptionBase() = default;
OptionBase::OptionBase(SCP_string config_key, SCP_string title, SCP_string description)
: _config_key(std::move(config_key)), _title(std::move(title)), _description(std::move(description))
{
_parent = OptionsManager::instance();
}
std::unique_ptr<json_t> OptionBase::getConfigValue() const { return _parent->getValueFromConfig(_config_key); }
ExpertLevel OptionBase::getExpertLevel() const { return _expert_level; }
void OptionBase::setExpertLevel(ExpertLevel expert_level) { _expert_level = expert_level; }
void OptionBase::setPreset(PresetKind preset, const SCP_string& value) { _preset_values.emplace(preset, value); }
const SCP_string& OptionBase::getCategory() const { return _category; }
void OptionBase::setCategory(const SCP_string& category) { _category = category; }
const SCP_string& OptionBase::getConfigKey() const {
return _config_key;
}
const SCP_string& OptionBase::getTitle() const {
return _title;
}
const SCP_string& OptionBase::getDescription() const {
return _description;
}
int OptionBase::getImportance() const {
return _importance;
}
void OptionBase::setImportance(int importance) {
_importance = importance;
}
bool operator<(const OptionBase& lhs, const OptionBase& rhs) {
if (lhs._category < rhs._category)
return true;
if (rhs._category < lhs._category)
return false;
return lhs._importance > rhs._importance; // Importance is sorted from highest to lowest
}
bool operator>(const OptionBase& lhs, const OptionBase& rhs) {
return rhs < lhs;
}
bool operator<=(const OptionBase& lhs, const OptionBase& rhs) {
return !(rhs < lhs);
}
bool operator>=(const OptionBase& lhs, const OptionBase& rhs) {
return !(lhs < rhs);
}
} // namespace options
-501
View File
@@ -1,501 +0,0 @@
#pragma once
#include "globalincs/flagset.h"
#include "globalincs/pstypes.h"
#include "libs/jansson.h"
#include "options/OptionsManager.h"
#include <functional>
#include <utility>
namespace options {
enum class OptionType { Range, Selection };
enum class ExpertLevel { Beginner, Advanced, Expert };
enum class PresetKind { Basic, Low, Medium, High, Ultra };
struct ValueDescription {
const SCP_string display;
const SCP_string serialized;
ValueDescription(SCP_string _display, SCP_string _serialized);
};
class OptionBase {
protected:
OptionsManager* _parent = nullptr;
ExpertLevel _expert_level = ExpertLevel::Expert;
SCP_string _config_key;
SCP_string _category = "Other";
SCP_string _title;
SCP_string _description;
int _importance = 0;
SCP_unordered_map<PresetKind, SCP_string> _preset_values;
std::unique_ptr<json_t> getConfigValue() const;
OptionBase(SCP_string config_key, SCP_string title, SCP_string description);
public:
virtual ~OptionBase() = 0;
ExpertLevel getExpertLevel() const;
void setExpertLevel(ExpertLevel expert_level);
const SCP_string& getCategory() const;
void setCategory(const SCP_string& category);
int getImportance() const;
void setImportance(int importance);
const SCP_string& getConfigKey() const;
const SCP_string& getTitle() const;
const SCP_string& getDescription() const;
void setPreset(PresetKind preset, const SCP_string& value);
virtual bool valueChanged(const json_t* val) const = 0;
virtual ValueDescription getCurrentValueDescription() const = 0;
virtual void setValueDescription(const ValueDescription& desc) const = 0;
virtual OptionType getType() const = 0;
virtual SCP_vector<ValueDescription> getValidValues() const = 0;
virtual ValueDescription getValueFromRange(float interpolant) const = 0;
virtual float getInterpolantFromValue(const ValueDescription& val) const = 0;
virtual void loadInitial() const = 0;
friend bool operator<(const OptionBase& lhs, const OptionBase& rhs);
friend bool operator>(const OptionBase& lhs, const OptionBase& rhs);
friend bool operator<=(const OptionBase& lhs, const OptionBase& rhs);
friend bool operator>=(const OptionBase& lhs, const OptionBase& rhs);
};
template <typename T>
using ValueEnumerator = std::function<SCP_vector<T>()>;
template <typename T>
using ValueDeserializer = std::function<T(const json_t*)>;
template <typename T>
using ValueSerializer = std::function<json_t*(const T&)>;
template <typename T>
using ValueDisplay = std::function<SCP_string(const T&)>;
template <typename T>
using DefaultValueFunctor = std::function<T()>;
template <typename T>
using ValueChangeListener = std::function<bool(const T&, bool initial)>;
template <typename T>
using ValueInterpolator = std::function<T(float)>;
template <typename T>
using ValueDeinterpolator = std::function<float(const T&)>;
template <typename T>
class ValueFunctor {
T _value;
public:
ValueFunctor() = default;
explicit ValueFunctor(T value) : _value(value) {}
T operator()() { return _value; }
};
template <typename T>
class Option : public OptionBase {
protected:
ValueEnumerator<T> _valueEnumerator;
ValueDeserializer<T> _deserializer;
ValueSerializer<T> _serializer;
ValueDisplay<T> _displayFunc;
DefaultValueFunctor<T> _defaultValueFunc = ValueFunctor<T>();
ValueChangeListener<T> _changeListener;
ValueInterpolator<T> _interpolator;
ValueDeinterpolator<T> _deinterpolator;
OptionType _type = OptionType::Selection; // By default the generic type is always a selection
ValueDescription toDescription(const T& val) const
{
auto json = _serializer(val);
auto json_str = json_dump_string_new(json, JSON_COMPACT | JSON_ENSURE_ASCII | JSON_ENCODE_ANY);
if (_displayFunc) {
return ValueDescription(_displayFunc(val), json_str);
} else {
return ValueDescription(json_str, json_str);
}
}
std::unique_ptr<json_t> fromDescription(const ValueDescription& desc) const
{
json_error_t err;
std::unique_ptr<json_t> el(json_loads(desc.serialized.c_str(), JSON_DECODE_ANY, &err));
if (el == nullptr) {
// Shouldn't really happen...
throw json_exception(err);
}
return el;
}
public:
Option(const SCP_string& config_key, const SCP_string& title, const SCP_string& description)
: OptionBase(config_key, title, description)
{
}
~Option() override = default;
OptionType getType() const override { return _type; }
void setType(OptionType type) { _type = type; }
SCP_vector<ValueDescription> getValidValues() const override
{
Assertion(_valueEnumerator, "Invalid value enumerator detected!");
Assertion(_type == OptionType::Selection, "getValidValues may only be called on selection option!");
auto values = _valueEnumerator();
SCP_vector<ValueDescription> descriptions;
descriptions.reserve(values.size());
for (const auto& val : values) {
descriptions.emplace_back(toDescription(val));
}
return descriptions;
}
ValueDescription getValueFromRange(float interpolant) const override
{
Assertion(_interpolator, "Need a valid interpolator!");
Assertion(_type == OptionType::Range, "getValidValues may only be called on range option!");
try {
return toDescription(_interpolator(interpolant));
} catch (const std::exception&) {
return toDescription(_defaultValueFunc());
}
}
float getInterpolantFromValue(const ValueDescription& val) const override
{
Assertion(_deinterpolator, "Need a valid deinterpolator!");
Assertion(_type == OptionType::Range, "getInterpolantFromValue may only be called on range option!");
try {
auto el = fromDescription(val);
return _deinterpolator(_deserializer(el.get()));
} catch (const std::exception&) {
return 0.0f;
}
}
T getValue() const
{
try {
return _deserializer(getConfigValue().get());
} catch (const std::exception&) {
// deserializers are allowed to throw on error
return _defaultValueFunc();
}
}
ValueDescription getCurrentValueDescription() const override
{
auto val = getValue();
return toDescription(val);
}
void setValueDescription(const ValueDescription& desc) const override
{
std::unique_ptr<json_t> el;
try {
el = fromDescription(desc);
} catch (const std::exception&) {
// Functions are allowed to throw
}
if (el) {
_parent->setConfigValue(_config_key, std::move(el));
}
}
bool valueChanged(const json_t* val) const override
{
try {
if (_changeListener) {
return _changeListener(_deserializer(val), false);
}
return false; // Value not changed, requires restart
} catch (const std::exception&) {
// Functions are allowed to throw
return false;
}
}
void loadInitial() const override
{
if (!_changeListener) {
// This requires a change listener
return;
}
try {
_changeListener(getValue(), true);
} catch (const std::exception&) {
}
}
const DefaultValueFunctor<T>& getDefaultValueFunc() const { return _defaultValueFunc; }
void setDefaultValueFunc(const DefaultValueFunctor<T>& defaultValueFunc) { _defaultValueFunc = defaultValueFunc; }
const ValueDeserializer<T>& getDeserializer() const { return _deserializer; }
void setDeserializer(const ValueDeserializer<T>& converter) { _deserializer = converter; }
const ValueSerializer<T>& getSerializer() const { return _serializer; }
void setSerializer(const ValueSerializer<T>& serializer) { _serializer = serializer; }
const ValueDisplay<T>& getDisplayFunc() const { return _displayFunc; }
void setDisplayFunc(const ValueDisplay<T>& displayFunc) { _displayFunc = displayFunc; }
const ValueEnumerator<T>& getValueEnumerator() const { return _valueEnumerator; }
void setValueEnumerator(const ValueEnumerator<T>& valueEnumerator)
{
_valueEnumerator = valueEnumerator;
_type = OptionType::Selection;
}
const ValueChangeListener<T>& getChangeListener() const { return _changeListener; }
void setChangeListener(const ValueChangeListener<T>& changeListener) { _changeListener = changeListener; }
const ValueInterpolator<T>& getInterpolator() const { return _interpolator; }
const ValueDeinterpolator<T>& getDeinterpolator() const { return _deinterpolator; }
void setInterpolator(const ValueInterpolator<T>& interpolator, const ValueDeinterpolator<T>& deinterpolator)
{
_interpolator = interpolator;
_deinterpolator = deinterpolator;
_type = OptionType::Range;
}
};
template <typename T>
class VectorEnumerator {
SCP_vector<T> _values;
public:
explicit VectorEnumerator(SCP_vector<T> values) : _values(std::move(values)) {}
SCP_vector<T> operator()() { return _values; }
};
template <typename T>
class MapValueDisplay {
SCP_unordered_map<T, SCP_string> _mapping;
public:
explicit MapValueDisplay(SCP_unordered_map<T, SCP_string> mapping)
: _mapping(std::move(mapping))
{
}
SCP_string operator()(const T& value) const
{
auto iter = _mapping.find(value);
if (iter == _mapping.end()) {
throw std::runtime_error("Display called with invalid value!");
}
return iter->second;
}
};
namespace internal {
// This would be so much easier with Concepts...
template <typename T>
typename std::enable_if<!std::is_enum<T>::value, void>::type set_defaults(Option<T>& /*opt*/)
{
// No defaults for the generic case since we don't know anything about this
}
template <>
void set_defaults<SCP_string>(Option<SCP_string>& opt);
template <>
void set_defaults<float>(Option<float>& opt);
template <>
void set_defaults<bool>(Option<bool>& opt);
template <typename T>
typename std::enable_if<std::is_enum<T>::value, void>::type set_defaults(Option<T>& opt)
{
opt.setSerializer([](T val) { return json_pack("I", static_cast<json_int_t>(val)); });
opt.setDeserializer([](const json_t* value) {
json_int_t i;
json_error_t err;
if (json_unpack_ex((json_t*)value, &err, 0, "I", &i) != 0) {
throw json_exception(err);
}
return static_cast<T>(i);
});
}
template <typename T, size_t N>
void set_defaults(Option<flagset<T, N>>& opt)
{
opt.setSerializer([](const flagset<T, N>& val) { return json_pack("I", static_cast<json_int_t>(val.to_u64())); });
opt.setDeserializer([](const json_t* value) {
json_int_t i;
json_error_t err;
if (json_unpack_ex((json_t*)value, &err, 0, "I", &i) != 0) {
throw json_exception(err);
}
flagset<T, N> out;
out.from_u64((std::uint64_t)i);
return out;
});
}
} // namespace internal
template <typename T>
class OptionBuilder {
Option<T> _instance;
SCP_unordered_map<PresetKind, T> _preset_values;
public:
OptionBuilder(const SCP_string& config_key, const SCP_string& title, const SCP_string& description)
: _instance(config_key, title, description)
{
internal::set_defaults(_instance);
}
OptionBuilder(const OptionBuilder&) = delete;
OptionBuilder& operator=(const OptionBuilder&) = delete;
OptionBuilder(OptionBuilder&&) noexcept = delete;
OptionBuilder& operator=(OptionBuilder&&) noexcept = delete;
OptionBuilder& category(const SCP_string& category)
{
_instance.setCategory(category);
return *this;
}
OptionBuilder& level(ExpertLevel level)
{
_instance.setExpertLevel(level);
return *this;
}
OptionBuilder& default_val(const T& val)
{
_instance.setDefaultValueFunc(ValueFunctor<T>(val));
return *this;
}
OptionBuilder& default_func(const DefaultValueFunctor<T>& func)
{
_instance.setDefaultValueFunc(func);
return *this;
}
OptionBuilder& deserializer(const ValueDeserializer<T>& converter)
{
_instance.setDeserializer(converter);
return *this;
}
OptionBuilder& serializer(const ValueSerializer<T>& serializer)
{
_instance.setSerializer(serializer);
return *this;
}
OptionBuilder& enumerator(const ValueEnumerator<T>& enumerator)
{
_instance.setValueEnumerator(enumerator);
return *this;
}
OptionBuilder& values(const SCP_vector<std::pair<T, SCP_string>>& value_display_pairs)
{
SCP_vector<T> values;
SCP_unordered_map<T, SCP_string> display_mapping;
for (auto& p : value_display_pairs) {
values.push_back(p.first);
display_mapping.emplace(p.first, p.second);
}
_instance.setValueEnumerator(VectorEnumerator<T>(values));
_instance.setDisplayFunc(MapValueDisplay<T>(display_mapping));
return *this;
}
OptionBuilder& display(const ValueDisplay<T>& display)
{
_instance.setDisplayFunc(display);
return *this;
}
OptionBuilder& change_listener(const ValueChangeListener<T>& listener)
{
_instance.setChangeListener(listener);
return *this;
}
OptionBuilder& bind_to(T* dest)
{
return change_listener([dest](const T& val, bool) {
*dest = val;
return true;
});
}
OptionBuilder& bind_to_once(T* dest)
{
return change_listener([dest](const T& val, bool initial) {
if (initial) {
*dest = val;
}
return initial;
});
}
OptionBuilder& range(T min, T max)
{
Assertion(min <= max, "Invalid number range!");
_instance.setInterpolator([min, max](T f) { return min + (max - min) * f; },
[min, max](T f) { return (f - min) / (max - min); });
return *this;
}
OptionBuilder& preset(PresetKind kind, const T& value)
{
_preset_values.emplace(kind, value);
return *this;
}
OptionBuilder& importance(int value)
{
_instance.setImportance(value);
return *this;
}
const Option<T>* finish()
{
for (auto& val : _preset_values) {
_instance.setPreset(val.first, json_dump_string_new(_instance.getSerializer()(val.second),
JSON_COMPACT | JSON_ENSURE_ASCII | JSON_ENCODE_ANY));
}
std::unique_ptr<Option<T>> opt_ptr(new Option<T>(_instance));
auto ptr = opt_ptr.get(); // We need to get the pointer now since we loose the type information otherwise
OptionsManager::instance()->addOption(std::unique_ptr<OptionBase>(opt_ptr.release()));
return ptr;
}
};
} // namespace options
-150
View File
@@ -1,150 +0,0 @@
//
//
#include "OptionsManager.h"
#include "Option.h"
#include "mod_table/mod_table.h"
#include "osapi/osregistry.h"
namespace {
std::pair<SCP_string, SCP_string> parse_key(const SCP_string& key)
{
auto point_pos = key.find('.');
if (point_pos == SCP_string::npos) {
// Invalid key
return std::pair<SCP_string, SCP_string>();
}
auto section = key.substr(0, point_pos);
auto section_key = key.substr(point_pos + 1);
return std::make_pair(section, section_key);
}
} // namespace
namespace options {
OptionsManager::OptionsManager() = default;
OptionsManager::~OptionsManager() = default;
OptionsManager* options::OptionsManager::instance()
{
static OptionsManager instance;
return &instance;
}
std::unique_ptr<json_t> OptionsManager::getValueFromConfig(const SCP_string& key) const
{
auto override_iter = _config_overrides.find(key);
if (override_iter != _config_overrides.end()) {
// We return a reference to an existing object so we need to increment the reference count
json_incref(override_iter->second.get());
return std::unique_ptr<json_t>(override_iter->second.get());
}
auto changed_iter = _changed_values.find(key);
if (changed_iter != _changed_values.end()) {
json_incref(changed_iter->second.get());
return std::unique_ptr<json_t>(changed_iter->second.get());
}
auto parts = parse_key(key);
if (parts.first.empty()) {
// Invalid key
throw std::runtime_error("Invalid key");
}
auto value = os_config_read_string(parts.first.c_str(), parts.second.c_str());
if (value == nullptr) {
// TODO: This is not really an error but I would like to avoid return nullptr here...
throw std::runtime_error("No value available");
}
json_error_t err;
auto el = json_loads(value, JSON_DECODE_ANY, &err);
if (el == nullptr) {
throw json_exception(err);
}
return std::unique_ptr<json_t>(el);
}
void OptionsManager::setConfigValue(const SCP_string& key,std::unique_ptr<json_t>&& value)
{
_changed_values[key] = std::move(value);
}
void OptionsManager::setOverride(const SCP_string& key, const SCP_string& json)
{
json_error_t err;
auto el = json_loads(json.c_str(), JSON_DECODE_ANY, &err);
if (el == nullptr) {
return;
}
_config_overrides.emplace(key, std::unique_ptr<json_t>(el));
}
const OptionBase* OptionsManager::addOption(std::unique_ptr<const OptionBase>&& option)
{
_options.emplace_back(std::move(option));
_optionsSorted = false; // Order got invalidated by adding a new option
auto ptr = _options.back().get();
_optionsMapping.emplace(ptr->getConfigKey(), ptr);
return ptr;
}
void OptionsManager::removeOption(const OptionBase* option)
{
_optionsMapping.erase(option->getConfigKey());
_options.erase(
std::remove_if(_options.begin(), _options.end(),
[option](const std::unique_ptr<const OptionBase>& ptr) { return ptr.get() == option; }));
}
const SCP_vector<std::unique_ptr<const options::OptionBase>>& OptionsManager::getOptions()
{
if (!_optionsSorted) {
// Keep options sorted by only sorting them when necessary
std::sort(_options.begin(), _options.end(),
[](const std::unique_ptr<const OptionBase>& left, const std::unique_ptr<const OptionBase>& right) {
return *left < *right;
});
_optionsSorted = true;
}
return _options;
}
SCP_vector<const options::OptionBase*> OptionsManager::persistChanges()
{
for (auto& entry : _changed_values) {
auto parts = parse_key(entry.first);
if (parts.first.empty()) {
// Invalid key
continue;
}
auto val = json_dump_string(entry.second.get(), JSON_COMPACT | JSON_ENSURE_ASCII | JSON_ENCODE_ANY);
os_config_write_string(parts.first.c_str(), parts.second.c_str(), val.c_str());
}
SCP_vector<const options::OptionBase*> unchanged;
// Only notify options once all values have been written to config
for (auto& entry : _changed_values) {
auto iter = _optionsMapping.find(entry.first);
if (iter != _optionsMapping.end()) {
if (!iter->second->valueChanged(entry.second.get())) {
unchanged.push_back(iter->second);
}
}
}
_changed_values.clear();
return unchanged;
}
void OptionsManager::discardChanges() { _changed_values.clear(); }
void OptionsManager::loadInitialValues()
{
for (auto& opt : _options) {
opt->loadInitial();
}
}
} // namespace options
-57
View File
@@ -1,57 +0,0 @@
#pragma once
#include "globalincs/pstypes.h"
#include "libs/jansson.h"
#include <memory>
namespace options {
// Forward declaration
class OptionBase;
class OptionsManager {
OptionsManager();
SCP_unordered_map<SCP_string, std::unique_ptr<json_t>> _config_overrides;
SCP_unordered_map<SCP_string, std::unique_ptr<json_t>> _changed_values;
SCP_unordered_map<SCP_string, const OptionBase*> _optionsMapping;
SCP_vector<std::unique_ptr<const OptionBase>> _options;
bool _optionsSorted = false;
public:
static OptionsManager* instance();
~OptionsManager();
std::unique_ptr<json_t> getValueFromConfig(const SCP_string& key) const;
void setConfigValue(const SCP_string& key, std::unique_ptr<json_t>&& value);
void setOverride(const SCP_string& key, const SCP_string& json);
const OptionBase* addOption(std::unique_ptr<const OptionBase>&& option);
void removeOption(const OptionBase* option);
const SCP_vector<std::unique_ptr<const options::OptionBase>>& getOptions();
/**
* @brief Persists changes to the disk
*
* This writes all the outstanding changes to the config file and returns a vector of all the options that indicated
* that they could not change the value. If the return value is empty then all changes were applied but if it is not
* empty then a restart is required for all the options to take effect.
*
* @return A vector of options that did not support changing the value
*/
SCP_vector<const options::OptionBase*> persistChanges();
void discardChanges();
void loadInitialValues();
};
}
+2 -4
View File
@@ -9,9 +9,9 @@
#include <fcntl.h>
#include "freespace.h"
#include "gamesequence/gamesequence.h"
#include "globalincs/pstypes.h"
#include "gamesequence/gamesequence.h"
#include "freespace.h"
#include "parse/parselo.h"
#ifdef SCP_UNIX
@@ -300,8 +300,6 @@ void os_set_title( const char * title )
// call at program end
void os_cleanup()
{
os_deinit_registry_stuff();
#ifndef NDEBUG
outwnd_close();
#endif
+4 -4
View File
@@ -171,7 +171,7 @@ namespace os
/**
* @brief Sets the swap interval
*/
virtual bool setSwapInterval(int status) = 0;
virtual void setSwapInterval(int status) = 0;
};
/**
@@ -213,9 +213,9 @@ namespace os
* @ingroup os_graphics_api
*/
enum class ViewportState {
Windowed = 0,
Borderless = 1,
Fullscreen = 2
Windowed,
Borderless,
Fullscreen
};
/**
+25 -37
View File
@@ -11,8 +11,6 @@
#include "osapi/osregistry.h"
#include "osapi/osapi.h"
#include "cmdline/cmdline.h"
#include "osregistry.h"
#ifdef WIN32
#include <windows.h>
@@ -830,8 +828,6 @@ static void profile_save(Profile *profile, const char *file)
// os registry functions -------------------------------------------------------------
static Profile* Osreg_profile = nullptr;
// initialize the registry. setup default keys to use
void os_init_registry_stuff(const char *company, const char *app)
{
@@ -849,36 +845,15 @@ void os_init_registry_stuff(const char *company, const char *app)
strcpy_s(szAppName, Osreg_app_name);
}
Osreg_profile = profile_read(Osreg_config_file_name);
Os_reg_inited = 1;
}
void os_deinit_registry_stuff()
{
if (Osreg_profile != nullptr) {
profile_free(Osreg_profile);
Osreg_profile = nullptr;
}
}
bool os_config_has_value(const char* section, const char* name) {
#ifdef WIN32
if (Osreg_profile == nullptr) {
// No config file, fall back to registy
return registry_read_string(section, name, nullptr) != nullptr;
}
#endif
if (section == nullptr)
section = DEFAULT_SECTION;
char *ptr = profile_get_value(Osreg_profile, section, name);
return ptr != nullptr;
}
const char *os_config_read_string(const char *section, const char *name, const char *default_value)
{
Profile *p = profile_read(Osreg_config_file_name);
#ifdef WIN32
if (Osreg_profile == nullptr) {
if (p == nullptr) {
// No config file, fall back to registy
return registry_read_string(section, name, default_value);
}
@@ -889,20 +864,24 @@ const char *os_config_read_string(const char *section, const char *name, const c
if (section == NULL)
section = DEFAULT_SECTION;
char *ptr = profile_get_value(Osreg_profile, section, name);
char *ptr = profile_get_value(p, section, name);
if (ptr != NULL) {
strncpy(tmp_string_data, ptr, 1023);
default_value = tmp_string_data;
}
profile_free(p);
return default_value;
}
unsigned int os_config_read_uint(const char *section, const char *name, unsigned int default_value)
{
Profile *p = profile_read(Osreg_config_file_name);
#ifdef WIN32
if (Osreg_profile == nullptr) {
if (p == nullptr) {
// No config file, fall back to registy
return registry_read_uint(section, name, default_value);
}
@@ -911,21 +890,25 @@ unsigned int os_config_read_uint(const char *section, const char *name, unsigned
if (section == NULL)
section = DEFAULT_SECTION;
char *ptr = profile_get_value(Osreg_profile, section, name);
char *ptr = profile_get_value(p, section, name);
if (ptr != NULL) {
default_value = atoi(ptr);
}
profile_free(p);
return default_value;
}
void os_config_write_string(const char *section, const char *name, const char *value)
{
Profile *p = profile_read(Osreg_config_file_name);
#ifdef WIN32
// When there is no config file then it shouldn't be created because that would "hide" all previous settings
// Instead fall back to writing the settings to the config file
if (Osreg_profile == nullptr) {
if (p == nullptr) {
registry_write_string(section, name, value);
return;
}
@@ -934,16 +917,20 @@ void os_config_write_string(const char *section, const char *name, const char *v
if (section == NULL)
section = DEFAULT_SECTION;
Osreg_profile = profile_update(Osreg_profile, section, name, value);
profile_save(Osreg_profile, Osreg_config_file_name);
p = profile_update(p, section, name, value);
profile_save(p, Osreg_config_file_name);
profile_free(p);
}
void os_config_write_uint(const char *section, const char *name, unsigned int value)
{
Profile *p = profile_read(Osreg_config_file_name);
#ifdef WIN32
// When there is no config file then it shouldn't be created because that would "hide" all previous settings
// Instead fall back to writing the settings to the config file
if (Osreg_profile == nullptr) {
if (p == nullptr) {
registry_write_uint(section, name, value);
return;
}
@@ -956,7 +943,8 @@ void os_config_write_uint(const char *section, const char *name, unsigned int va
snprintf(buf, 20, "%u", value);
Osreg_profile = profile_update(Osreg_profile, section, name, buf);
profile_save(Osreg_profile, Osreg_config_file_name);
p = profile_update(p, section, name, buf);
profile_save(p, Osreg_config_file_name);
profile_free(p);
}
-4
View File
@@ -36,16 +36,12 @@ time_t os_registry_get_last_modification_time();
// initialize the registry. setup default keys to use
void os_init_registry_stuff( const char *company, const char *app);
void os_deinit_registry_stuff();
// Writes a string to the registry
void os_config_write_string( const char *section, const char *name, const char *value );
// Writes an unsigned int to the INI file.
void os_config_write_uint( const char *section, const char *name, unsigned int value );
bool os_config_has_value(const char *section, const char *name);
// Reads a string from the INI file. If default is passed,
// and the string isn't found, returns ptr to default otherwise
// returns NULL; Copy the return value somewhere before
+809 -810
View File
File diff suppressed because it is too large. Load diff
+7 -16
View File
@@ -235,8 +235,6 @@ class waypoint_list;
#define OP_UNSET_BIT (0x0011 | OP_CATEGORY_ARITHMETIC) // Goober5000
#define OP_IS_BIT_SET (0x0012 | OP_CATEGORY_ARITHMETIC) // Goober5000
#define OP_SIGNUM (0x0013 | OP_CATEGORY_ARITHMETIC) // Goober5000
#define OP_IS_NAN (0x0014 | OP_CATEGORY_ARITHMETIC) // Goober5000
#define OP_NAN_TO_NUMBER (0x0015 | OP_CATEGORY_ARITHMETIC) // Goober5000
#define OP_TRUE (0x0000 | OP_CATEGORY_LOGICAL)
@@ -392,7 +390,6 @@ class waypoint_list;
#define OP_TURRET_GET_SECONDARY_AMMO (0x0050 | OP_CATEGORY_STATUS | OP_NONCAMPAIGN_FLAG) // DahBlount, part of the turret ammo code
#define OP_IS_DOCKED (0x0051 | OP_CATEGORY_STATUS | OP_NONCAMPAIGN_FLAG) // Goober5000
#define OP_IS_IN_TURRET_FOV (0x0052 | OP_CATEGORY_STATUS | OP_NONCAMPAIGN_FLAG) // Goober5000
#define OP_GET_HOTKEY (0x0053 | OP_CATEGORY_STATUS | OP_NONCAMPAIGN_FLAG) // wookieejedi
// conditional sexpressions
#define OP_WHEN (0x0000 | OP_CATEGORY_CONDITIONAL)
@@ -411,10 +408,8 @@ class waypoint_list;
#define OP_INVALIDATE_ALL_ARGUMENTS (0x000d | OP_CATEGORY_CONDITIONAL) // Karajorma
#define OP_VALIDATE_ALL_ARGUMENTS (0x000e | OP_CATEGORY_CONDITIONAL) // Karajorma
#define OP_FOR_COUNTER (0x000f | OP_CATEGORY_CONDITIONAL) // Goober5000
#define OP_IF_THEN_ELSE (0x0010 | OP_CATEGORY_CONDITIONAL) // Goober5000
#define OP_NUM_VALID_ARGUMENTS (0x0011 | OP_CATEGORY_CONDITIONAL) // Karajorma
#define OP_FUNCTIONAL_IF_THEN_ELSE (0x0012 | OP_CATEGORY_CONDITIONAL) // Goober5000
// sexpressions with side-effects
@@ -745,7 +740,6 @@ class waypoint_list;
#define OP_MODIFY_VARIABLE_XSTR (0X0030 | OP_CATEGORY_CHANGE2 | OP_NONCAMPAIGN_FLAG) // m!m
#define OP_RESET_POST_EFFECTS (0x0031 | OP_CATEGORY_CHANGE2 | OP_NONCAMPAIGN_FLAG) // Goober5000
#define OP_ADD_REMOVE_HOTKEY (0x0032 | OP_CATEGORY_CHANGE2 | OP_NONCAMPAIGN_FLAG) // wookieejedi
// defined for AI goals
#define OP_AI_CHASE (0x0000 | OP_CATEGORY_AI | OP_NONCAMPAIGN_FLAG)
@@ -951,17 +945,14 @@ char *CTEXT(int n);
#define SEXP_TRUE 1
#define SEXP_FALSE 0
// Goober5000: changed these to unlikely values, because now we have sexps using negative numbers
#define SEXP_KNOWN_FALSE (INT_MIN+10)
#define SEXP_KNOWN_TRUE (INT_MIN+11)
#define SEXP_UNKNOWN (INT_MIN+12)
#define SEXP_NAN (INT_MIN+13) // not a number -- used when ships/wing part of boolean and haven't arrived yet
#define SEXP_NAN_FOREVER (INT_MIN+14) // not a number and will never change -- used to falsify boolean sexpressions
#define SEXP_CANT_EVAL (INT_MIN+15) // can't evaluate yet for whatever reason (acts like false)
#define SEXP_NUM_EVAL (INT_MIN+16) // already completed an arithmetic operation and result is stored
// in case we want to test for any of the above
#define SEXP_UNLIKELY_RETURN_VALUE_BOUND (INT_MIN+17)
#define SEXP_KNOWN_FALSE -32767 //-1
#define SEXP_KNOWN_TRUE -32766 //-2
#define SEXP_UNKNOWN -32765 //-3
#define SEXP_NAN -32764 //-4 // not a number -- used when ships/wing part of boolean and haven't arrived yet
#define SEXP_NAN_FOREVER -32763 //-5 // not a number and will never change -- used to falsify boolean sexpressions
#define SEXP_CANT_EVAL -32762 //-6 // can't evaluate yet for whatever reason (acts like false)
#define SEXP_NUM_EVAL -32761 //-7 // already completed an arithmetic operation and result is stored
// defines for check_sexp_syntax
#define SEXP_CHECK_NONOP_ARGS -1 // non-operator has arguments
+1 -1
View File
@@ -7,9 +7,9 @@
*/
#include "cfile/cfilesystem.h"
#include "pilotfile/pilotfile_convert.h"
#include "cutscene/cutscenes.h"
#include "menuui/techmenu.h"
#include "pilotfile/pilotfile_convert.h"
#include "ship/ship.h"
#include "stats/medals.h"
#include "weapon/weapon.h"
Loaded 100 of 168 files, more files were not shown because too many files have changed in this diff. Show more