diff --git a/source/lib/app_hooks.cpp b/source/lib/app_hooks.cpp index a9b7d8e4c3..34f102ed5e 100644 --- a/source/lib/app_hooks.cpp +++ b/source/lib/app_hooks.cpp @@ -23,14 +23,7 @@ #include "precompiled.h" #include "app_hooks.h" -#include -#include - #include "lib/path_util.h" -#include "lib/sysdep/gfx.h" -#include "lib/res/graphics/ogl_tex.h" -#include "lib/res/file/file.h" -#include "lib/res/file/vfs.h" //----------------------------------------------------------------------------- @@ -39,14 +32,6 @@ static void def_override_gl_upload_caps() { - if(gfx_card[0] == '\0') - debug_warn("gfx_detect must be called before ogl_tex_upload"); - - if(!strcmp(gfx_card, "S3 SuperSavage/IXC 1014")) - { - if(strstr(gfx_drv_ver, "ssicdnt.dll (2.60.115)")) - ogl_tex_override(OGL_TEX_S3TC, OGL_TEX_DISABLE); - } } @@ -54,56 +39,16 @@ static const char* def_get_log_dir() { static char N_log_dir[PATH_MAX]; ONCE(\ - char N_exe_name[PATH_MAX];\ - (void)sys_get_executable_name(N_exe_name, ARRAY_SIZE(N_exe_name));\ + (void)sys_get_executable_name(N_log_dir, ARRAY_SIZE(N_log_dir));\ /* strip app name (we only want its path) */\ - path_strip_fn(N_exe_name);\ - (void)path_append(N_log_dir, N_exe_name, "../logs/"); + path_strip_fn(N_log_dir);\ ); return N_log_dir; } -// convert contents of file from char to wchar_t and -// append to file. -static void cat_atow(FILE* out, const char* in_filename) +static void def_bundle_logs(FILE* UNUSED(f)) { - FILE* in = fopen(in_filename, "rb"); - if(!in) - { - fwprintf(out, L"(unavailable)"); - return; - } - - const size_t buf_size = 1024; - char buf[buf_size+1]; // include space for trailing '\0' - - while(!feof(in)) - { - size_t bytes_read = fread(buf, 1, buf_size, in); - if(!bytes_read) - break; - buf[bytes_read] = 0; // 0-terminate - fwprintf(out, L"%hs", buf); - } - - fclose(in); -} - -static void def_bundle_logs(FILE* f) -{ - // for user convenience, bundle all logs into this file: - char N_path[PATH_MAX]; - - fwprintf(f, L"System info:\n\n"); - (void)file_make_full_native_path("../logs/system_info.txt", N_path); - cat_atow(f, N_path); - fwprintf(f, L"\n\n====================================\n\n"); - - fwprintf(f, L"Main log:\n\n"); - (void)file_make_full_native_path("../logs/mainlog.html", N_path); - cat_atow(f, N_path); - fwprintf(f, L"\n\n====================================\n\n"); } @@ -137,8 +82,8 @@ static ErrorReaction def_display_error(const wchar_t* UNUSED(text), uint UNUSED( // may be changed via app_hooks_update. // // rationale: we don't ever need to switch "hook sets", so one global struct -// is fine. by always having one defined, we also avoid having to check -// if anything was registered yet. +// is fine. by always having one defined, we also avoid the trampolines +// having to check whether their function pointer is valid. static AppHooks ah = { def_override_gl_upload_caps, @@ -150,6 +95,11 @@ static AppHooks ah = def_display_error }; +// separate copy of ah; used to determine if a particular hook has been +// redefined. the additional storage needed is negligible and this is +// easier than comparing each value against its corresponding def_ value. +static AppHooks default_ah = ah; + // register the specified hook function pointers. any of them that // are non-zero override the previous function pointer value // (these default to the stub hooks which are functional but basic). @@ -167,6 +117,16 @@ void app_hooks_update(AppHooks* new_ah) OVERRIDE_IF_NONZERO(display_error) } +bool app_hook_was_redefined(size_t offset_in_struct) +{ + const u8* ah_bytes = (const u8*)&ah; + const u8* default_ah_bytes = (const u8*)&default_ah; + typedef void(*FP)(); // a bit safer than comparing void* pointers + if(*(FP)(ah_bytes+offset_in_struct) != *(FP)(default_ah_bytes+offset_in_struct)) + return true; + return false; +} + //----------------------------------------------------------------------------- // trampoline implementations @@ -175,7 +135,8 @@ void app_hooks_update(AppHooks* new_ah) void ah_override_gl_upload_caps(void) { - ah.override_gl_upload_caps(); + if(ah.override_gl_upload_caps) + ah.override_gl_upload_caps(); } const char* ah_get_log_dir(void) diff --git a/source/lib/app_hooks.h b/source/lib/app_hooks.h index ee5176d374..e00704d8fb 100644 --- a/source/lib/app_hooks.h +++ b/source/lib/app_hooks.h @@ -193,4 +193,14 @@ struct AppHooks **/ extern void app_hooks_update(AppHooks* ah); +/** + * was the app hook changed via app_hooks_update from its default value? + * + * @param offset_in_struct byte offset within AppHooks (determined via + * offsetof) of the app hook function pointer. + **/ +extern bool app_hook_was_redefined(size_t offset_in_struct); +// name is identifier of the function pointer within AppHooks to test. +#define AH_IS_DEFINED(name) app_hook_was_redefined(offsetof(AppHooks, name)) + #endif // #ifndef APP_HOOKS_H__ diff --git a/source/lib/res/graphics/ogl_tex.cpp b/source/lib/res/graphics/ogl_tex.cpp index 3698a1c7ca..5969da2f96 100644 --- a/source/lib/res/graphics/ogl_tex.cpp +++ b/source/lib/res/graphics/ogl_tex.cpp @@ -650,6 +650,10 @@ void ogl_tex_override(OglTexOverrides what, OglTexAllow allow) // called once from the first ogl_tex_upload. static void detect_gl_upload_caps() { + // make sure us and the app hook have graphics card info available + if(gfx_card[0] == '\0') + debug_warn("gfx_detect must be called before ogl_tex_upload"); + // detect features, but only change the variables if they were at // "undecided" (if overrides were set before this, they must remain). if(have_auto_mipmap_gen == -1) @@ -663,7 +667,23 @@ static void detect_gl_upload_caps() have_s3tc = oglHaveExtensions(0, "GL_ARB_texture_compression", "GL_EXT_texture_compression_s3tc", 0) == 0; } - ah_override_gl_upload_caps(); + // allow app hook to make ogl_tex_override calls + if(AH_IS_DEFINED(override_gl_upload_caps)) + { + ah_override_gl_upload_caps(); + } + // no app hook defined - have our own crack at blacklisting some hardware. + else + { + // rationale: janwas's laptop's S3 card blows up if S3TC is used + // (oh, the irony). it'd be annoying to have to share this between all + // projects, hence this default implementation here. + if(!strcmp(gfx_card, "S3 SuperSavage/IXC 1014")) + { + if(strstr(gfx_drv_ver, "ssicdnt.dll (2.60.115)")) + ogl_tex_override(OGL_TEX_S3TC, OGL_TEX_DISABLE); + } + } // warn if more-or-less essential features are missing if(!have_s3tc) diff --git a/source/lib/sysdep/win/wposix/waio.cpp b/source/lib/sysdep/win/wposix/waio.cpp index ff7d8cd248..9ba5a9bfc6 100644 --- a/source/lib/sysdep/win/wposix/waio.cpp +++ b/source/lib/sysdep/win/wposix/waio.cpp @@ -141,16 +141,15 @@ static void aio_h_cleanup() lock(); for(int i = 0; i < aio_hs_size; i++) + { if(aio_hs[i] != INVALID_HANDLE_VALUE) { - if(!CloseHandle(aio_hs[i])) - debug_warn("CloseHandle failed"); + WARN_IF_FALSE(CloseHandle(aio_hs[i])); aio_hs[i] = INVALID_HANDLE_VALUE; } + } - free(aio_hs); - aio_hs = 0; - + SAFE_FREE(aio_hs); aio_hs_size = 0; unlock(); @@ -170,16 +169,9 @@ static bool is_valid_file_handle(const HANDLE h) // used by aio_close. static bool aio_h_is_set(const int fd) { - bool is_set = false; - lock(); - - if(0 <= fd && fd < aio_hs_size) - if(aio_hs[fd] != INVALID_HANDLE_VALUE) - is_set = true; - + bool is_set = (0 <= fd && fd < aio_hs_size && aio_hs[fd] != INVALID_HANDLE_VALUE); unlock(); - return is_set; } diff --git a/source/ps/GameSetup/GameSetup.cpp b/source/ps/GameSetup/GameSetup.cpp index 16b0af09b3..4355516719 100644 --- a/source/ps/GameSetup/GameSetup.cpp +++ b/source/ps/GameSetup/GameSetup.cpp @@ -923,6 +923,8 @@ void Init(const CmdLineArgs& args, uint flags) AppHooks hooks = {0}; hooks.translate = psTranslate; hooks.translate_free = psTranslateFree; + hooks.bundle_logs = psBundleLogs; + hooks.get_log_dir = psGetLogDir; app_hooks_update(&hooks); // Set up the console early, so that debugging diff --git a/source/ps/Pyrogenesis.cpp b/source/ps/Pyrogenesis.cpp index 24f706d1ca..251dfc4904 100644 --- a/source/ps/Pyrogenesis.cpp +++ b/source/ps/Pyrogenesis.cpp @@ -3,6 +3,9 @@ #include "Pyrogenesis.h" #include "ps/i18n.h" +#include "lib/path_util.h" +#include "lib/res/file/file.h" + DEFINE_ERROR(PS_OK, "OK"); DEFINE_ERROR(PS_FAIL, "Fail"); @@ -38,3 +41,60 @@ void psTranslateFree(const wchar_t* text) if(text != translate_no_mem) free((void*)text); } + + +// convert contents of file from char to wchar_t and +// append to file. +static void cat_atow(FILE* out, const char* in_filename) +{ + FILE* in = fopen(in_filename, "rb"); + if(!in) + { + fwprintf(out, L"(unavailable)"); + return; + } + + const size_t buf_size = 1024; + char buf[buf_size+1]; // include space for trailing '\0' + + while(!feof(in)) + { + size_t bytes_read = fread(buf, 1, buf_size, in); + if(!bytes_read) + break; + buf[bytes_read] = 0; // 0-terminate + fwprintf(out, L"%hs", buf); + } + + fclose(in); +} + +void psBundleLogs(FILE* f) +{ + // for user convenience, bundle all logs into this file: + char N_path[PATH_MAX]; + + fwprintf(f, L"System info:\n\n"); + (void)file_make_full_native_path("../logs/system_info.txt", N_path); + cat_atow(f, N_path); + fwprintf(f, L"\n\n====================================\n\n"); + + fwprintf(f, L"Main log:\n\n"); + (void)file_make_full_native_path("../logs/mainlog.html", N_path); + cat_atow(f, N_path); + fwprintf(f, L"\n\n====================================\n\n"); +} + + +const char* psGetLogDir() +{ + static char N_log_dir[PATH_MAX]; + ONCE(\ + char N_exe_name[PATH_MAX];\ + (void)sys_get_executable_name(N_exe_name, ARRAY_SIZE(N_exe_name));\ + /* strip app name (we only want its path) */\ + path_strip_fn(N_exe_name);\ + (void)path_append(N_log_dir, N_exe_name, "../logs/"); + ); + return N_log_dir; +} diff --git a/source/ps/Pyrogenesis.h b/source/ps/Pyrogenesis.h index 875b3c9170..f64cd9aeab 100644 --- a/source/ps/Pyrogenesis.h +++ b/source/ps/Pyrogenesis.h @@ -26,5 +26,7 @@ DECLARE_ERROR(PS_FAIL); // overrides ah_translate. registered in GameSetup.cpp extern const wchar_t* psTranslate(const wchar_t* text); extern void psTranslateFree(const wchar_t* text); +extern void psBundleLogs(FILE* f); +extern const char* psGetLogDir(); #endif