forked from 0ad/0ad
# improvements to app_hooks
thesis pointed out more dependencies that had to be stomped on. 0ad-specific apphooks are now in pyrogenesis. added function AH_IS_DEFINED (useful for ogl_tex, which now has its own default version of a hook) This was SVN commit r4765.
This commit is contained in:
parent
f5bcb031ff
commit
38755cc589
@ -23,14 +23,7 @@
|
||||
#include "precompiled.h"
|
||||
#include "app_hooks.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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 <in_filename> from char to wchar_t and
|
||||
// append to <out> 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)
|
||||
|
@ -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__
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 <in_filename> from char to wchar_t and
|
||||
// append to <out> 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;
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user