mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 00:01:49 +02:00
1688 lines
35 KiB
C++
1688 lines
35 KiB
C++
// engine_stubs.cpp
|
|
//
|
|
|
|
#include "precompiled.h"
|
|
|
|
#include <windows.h>
|
|
#include <direct.h>
|
|
#include <io.h>
|
|
|
|
class idCommonStub : public idCommon {
|
|
public:
|
|
idCommonStub();
|
|
virtual ~idCommonStub();
|
|
|
|
virtual void Init(int argc, const char** argv, const char* cmdline);
|
|
virtual void Shutdown(void);
|
|
virtual void Quit(void);
|
|
virtual bool IsInitialized(void) const;
|
|
virtual void Frame(void);
|
|
virtual void GUIFrame(bool execCmd, bool network);
|
|
virtual void StartupVariable(const char* match, bool once);
|
|
|
|
#ifdef QUAKE4
|
|
virtual int GetUserCmdHz(void) const;
|
|
virtual int GetUserCmdMSec(void) const;
|
|
virtual int GetFrameTime(void) const;
|
|
virtual bool IsRenderableGameFrame(void) const;
|
|
virtual void SetRenderableGameFrame(bool in);
|
|
virtual const char* GetErrorMessage(void) const;
|
|
virtual bool IsToolActive(void) const;
|
|
|
|
#ifdef _RV_MEM_SYS_SUPPORT
|
|
virtual void InitHeaps(void);
|
|
virtual void ShutdownHeaps(void);
|
|
#endif
|
|
|
|
virtual void RunAlwaysThinkGUIs(int time);
|
|
virtual bool DoingDeclValidation(void);
|
|
virtual void SetCrashReportAutoSendString(const char* psString);
|
|
#endif
|
|
|
|
virtual void InitTool(const toolFlag_t tool, const idDict* dict);
|
|
virtual void ActivateTool(bool active);
|
|
|
|
virtual void WriteConfigToFile(const char* filename);
|
|
virtual void WriteFlaggedCVarsToFile(const char* filename, int flags, const char* setCmd);
|
|
|
|
#ifdef QUAKE4
|
|
virtual void BeginRedirect(char* buffer, int buffersize, void (*flush)(const char*), bool rcon = false);
|
|
#else
|
|
virtual void BeginRedirect(char* buffer, int buffersize, void (*flush)(const char*));
|
|
#endif
|
|
|
|
virtual void EndRedirect(void);
|
|
virtual void SetRefreshOnPrint(bool set);
|
|
|
|
virtual void Printf(const char* fmt, ...) id_attribute((format(printf, 2, 3)));
|
|
virtual void VPrintf(const char* fmt, va_list arg);
|
|
virtual void DPrintf(const char* fmt, ...) id_attribute((format(printf, 2, 3)));
|
|
virtual void Warning(const char* fmt, ...) id_attribute((format(printf, 2, 3)));
|
|
virtual void DWarning(const char* fmt, ...) id_attribute((format(printf, 2, 3)));
|
|
virtual void PrintWarnings(void);
|
|
virtual void ClearWarnings(const char* reason);
|
|
virtual void Error(const char* fmt, ...) id_attribute((format(printf, 2, 3)));
|
|
virtual void FatalError(const char* fmt, ...) id_attribute((format(printf, 2, 3)));
|
|
|
|
#ifdef QUAKE4
|
|
virtual void DumpWarnings(void);
|
|
#endif
|
|
|
|
virtual const idLangDict* GetLanguageDict(void);
|
|
|
|
#ifdef QUAKE4
|
|
virtual const char* GetLocalizedString(const char* token, int langIndex = -1);
|
|
virtual const idLangKeyValue* GetLocalizedString(int index, int langIndex = -1);
|
|
virtual int GetNumLanguages(void) const;
|
|
virtual int GetNumLocalizedStrings(void) const;
|
|
virtual const char* GetLanguage(int index) const;
|
|
virtual bool LanguageHasVO(int index) const;
|
|
#endif
|
|
|
|
virtual const char* KeysFromBinding(const char* bind);
|
|
virtual const char* BindingFromKey(const char* key);
|
|
virtual int ButtonState(int key);
|
|
virtual int KeyState(int key);
|
|
|
|
#ifdef QUAKE4
|
|
virtual int GetRModeForMachineSpec(int machineSpec) const;
|
|
virtual void SetDesiredMachineSpec(int machineSpec);
|
|
virtual bool IsRCon(void) const;
|
|
#endif
|
|
|
|
#ifdef PREY
|
|
virtual void MaterialKeyForBinding(const char* binding, char* materialName, char* keyText, bool* wideKey);
|
|
#endif
|
|
|
|
virtual float Get_com_engineHz_latched(void);
|
|
virtual int64_t Get_com_engineHz_numerator(void);
|
|
virtual int64_t Get_com_engineHz_denominator(void);
|
|
|
|
private:
|
|
void OutputString(const char* prefix, const char* text);
|
|
void VOutputf(const char* prefix, const char* fmt, va_list args);
|
|
|
|
private:
|
|
bool initialized;
|
|
bool quitRequested;
|
|
bool refreshOnPrint;
|
|
|
|
#ifdef QUAKE4
|
|
bool renderableGameFrame;
|
|
bool toolActive;
|
|
char errorMessage[4096];
|
|
#endif
|
|
|
|
char* redirectBuffer;
|
|
int redirectBufferSize;
|
|
int redirectBufferUsed;
|
|
void (*redirectFlush)(const char*);
|
|
};
|
|
|
|
idCommonStub commonLocal;
|
|
idCommon* common = &commonLocal;
|
|
|
|
idCommonStub::idCommonStub() {
|
|
initialized = false;
|
|
quitRequested = false;
|
|
refreshOnPrint = false;
|
|
|
|
#ifdef QUAKE4
|
|
renderableGameFrame = true;
|
|
toolActive = false;
|
|
errorMessage[0] = '\0';
|
|
#endif
|
|
|
|
redirectBuffer = NULL;
|
|
redirectBufferSize = 0;
|
|
redirectBufferUsed = 0;
|
|
redirectFlush = NULL;
|
|
}
|
|
|
|
idCommonStub::~idCommonStub() {
|
|
Shutdown();
|
|
}
|
|
|
|
void idCommonStub::OutputString(const char* prefix, const char* text) {
|
|
if (!text) {
|
|
text = "";
|
|
}
|
|
|
|
char finalBuffer[8192];
|
|
|
|
if (prefix && prefix[0]) {
|
|
idStr::snPrintf(finalBuffer, sizeof(finalBuffer), "%s%s", prefix, text);
|
|
}
|
|
else {
|
|
idStr::snPrintf(finalBuffer, sizeof(finalBuffer), "%s", text);
|
|
}
|
|
|
|
finalBuffer[sizeof(finalBuffer) - 1] = '\0';
|
|
|
|
if (redirectBuffer && redirectBufferSize > 0) {
|
|
const int len = (int)strlen(finalBuffer);
|
|
const int remaining = redirectBufferSize - redirectBufferUsed - 1;
|
|
|
|
if (remaining > 0) {
|
|
const int copyLen = len < remaining ? len : remaining;
|
|
memcpy(redirectBuffer + redirectBufferUsed, finalBuffer, copyLen);
|
|
redirectBufferUsed += copyLen;
|
|
redirectBuffer[redirectBufferUsed] = '\0';
|
|
}
|
|
|
|
if (redirectFlush) {
|
|
redirectFlush(finalBuffer);
|
|
}
|
|
}
|
|
|
|
fputs(finalBuffer, stdout);
|
|
fflush(stdout);
|
|
|
|
#ifdef _WIN32
|
|
OutputDebugStringA(finalBuffer);
|
|
#endif
|
|
}
|
|
|
|
void idCommonStub::VOutputf(const char* prefix, const char* fmt, va_list args) {
|
|
if (!fmt) {
|
|
OutputString(prefix, "\n");
|
|
return;
|
|
}
|
|
|
|
char buffer[8192];
|
|
idStr::vsnPrintf(buffer, sizeof(buffer), fmt, args);
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
|
|
|
OutputString(prefix, buffer);
|
|
}
|
|
|
|
void idCommonStub::Init(int argc, const char** argv, const char* cmdline) {
|
|
initialized = true;
|
|
quitRequested = false;
|
|
|
|
Printf("idCommonStub::Init argc=%d cmdline=\"%s\"\n", argc, cmdline ? cmdline : "");
|
|
}
|
|
|
|
void idCommonStub::Shutdown(void) {
|
|
if (initialized) {
|
|
Printf("idCommonStub::Shutdown\n");
|
|
}
|
|
|
|
initialized = false;
|
|
}
|
|
|
|
void idCommonStub::Quit(void) {
|
|
quitRequested = true;
|
|
Printf("idCommonStub::Quit\n");
|
|
}
|
|
|
|
bool idCommonStub::IsInitialized(void) const {
|
|
return initialized;
|
|
}
|
|
|
|
void idCommonStub::Frame(void) {
|
|
// Stub.
|
|
}
|
|
|
|
void idCommonStub::GUIFrame(bool execCmd, bool network) {
|
|
// Stub.
|
|
}
|
|
|
|
void idCommonStub::StartupVariable(const char* match, bool once) {
|
|
// Stub.
|
|
}
|
|
|
|
#ifdef QUAKE4
|
|
|
|
int idCommonStub::GetUserCmdHz(void) const {
|
|
return 60;
|
|
}
|
|
|
|
int idCommonStub::GetUserCmdMSec(void) const {
|
|
return 16;
|
|
}
|
|
|
|
int idCommonStub::GetFrameTime(void) const {
|
|
return 16;
|
|
}
|
|
|
|
bool idCommonStub::IsRenderableGameFrame(void) const {
|
|
return renderableGameFrame;
|
|
}
|
|
|
|
void idCommonStub::SetRenderableGameFrame(bool in) {
|
|
renderableGameFrame = in;
|
|
}
|
|
|
|
const char* idCommonStub::GetErrorMessage(void) const {
|
|
return errorMessage;
|
|
}
|
|
|
|
bool idCommonStub::IsToolActive(void) const {
|
|
return toolActive;
|
|
}
|
|
|
|
#ifdef _RV_MEM_SYS_SUPPORT
|
|
void idCommonStub::InitHeaps(void) {
|
|
// Stub.
|
|
}
|
|
|
|
void idCommonStub::ShutdownHeaps(void) {
|
|
// Stub.
|
|
}
|
|
#endif
|
|
|
|
void idCommonStub::RunAlwaysThinkGUIs(int time) {
|
|
// Stub.
|
|
}
|
|
|
|
bool idCommonStub::DoingDeclValidation(void) {
|
|
return false;
|
|
}
|
|
|
|
void idCommonStub::SetCrashReportAutoSendString(const char* psString) {
|
|
// Stub.
|
|
}
|
|
|
|
#endif
|
|
|
|
void idCommonStub::InitTool(const toolFlag_t tool, const idDict* dict) {
|
|
#ifdef QUAKE4
|
|
toolActive = true;
|
|
#endif
|
|
|
|
Printf("idCommonStub::InitTool\n");
|
|
}
|
|
|
|
void idCommonStub::ActivateTool(bool active) {
|
|
#ifdef QUAKE4
|
|
toolActive = active;
|
|
#endif
|
|
|
|
Printf("idCommonStub::ActivateTool active=%d\n", active ? 1 : 0);
|
|
}
|
|
|
|
void idCommonStub::WriteConfigToFile(const char* filename) {
|
|
Printf("idCommonStub::WriteConfigToFile \"%s\"\n", filename ? filename : "");
|
|
}
|
|
|
|
void idCommonStub::WriteFlaggedCVarsToFile(const char* filename, int flags, const char* setCmd) {
|
|
Printf("idCommonStub::WriteFlaggedCVarsToFile \"%s\" flags=%d setCmd=\"%s\"\n",
|
|
filename ? filename : "",
|
|
flags,
|
|
setCmd ? setCmd : "");
|
|
}
|
|
|
|
#ifdef QUAKE4
|
|
void idCommonStub::BeginRedirect(char* buffer, int buffersize, void (*flush)(const char*), bool rcon) {
|
|
#else
|
|
void idCommonStub::BeginRedirect(char* buffer, int buffersize, void (*flush)(const char*)) {
|
|
#endif
|
|
redirectBuffer = buffer;
|
|
redirectBufferSize = buffersize;
|
|
redirectBufferUsed = 0;
|
|
redirectFlush = flush;
|
|
|
|
if (redirectBuffer && redirectBufferSize > 0) {
|
|
redirectBuffer[0] = '\0';
|
|
}
|
|
|
|
#ifdef QUAKE4
|
|
Printf("idCommonStub::BeginRedirect rcon=%d\n", rcon ? 1 : 0);
|
|
#else
|
|
Printf("idCommonStub::BeginRedirect\n");
|
|
#endif
|
|
}
|
|
|
|
void idCommonStub::EndRedirect(void) {
|
|
if (redirectFlush && redirectBuffer) {
|
|
redirectFlush(redirectBuffer);
|
|
}
|
|
|
|
redirectBuffer = NULL;
|
|
redirectBufferSize = 0;
|
|
redirectBufferUsed = 0;
|
|
redirectFlush = NULL;
|
|
}
|
|
|
|
void idCommonStub::SetRefreshOnPrint(bool set) {
|
|
refreshOnPrint = set;
|
|
}
|
|
|
|
void idCommonStub::Printf(const char* fmt, ...) {
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
VPrintf(fmt, args);
|
|
va_end(args);
|
|
}
|
|
|
|
void idCommonStub::VPrintf(const char* fmt, va_list arg) {
|
|
VOutputf("", fmt, arg);
|
|
}
|
|
|
|
void idCommonStub::DPrintf(const char* fmt, ...) {
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
VOutputf("DEBUG: ", fmt, args);
|
|
va_end(args);
|
|
}
|
|
|
|
void idCommonStub::Warning(const char* fmt, ...) {
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
VOutputf("WARNING: ", fmt, args);
|
|
va_end(args);
|
|
}
|
|
|
|
void idCommonStub::DWarning(const char* fmt, ...) {
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
VOutputf("DWARNING: ", fmt, args);
|
|
va_end(args);
|
|
}
|
|
|
|
void idCommonStub::PrintWarnings(void) {
|
|
Printf("idCommonStub::PrintWarnings: no queued warnings.\n");
|
|
}
|
|
|
|
void idCommonStub::ClearWarnings(const char* reason) {
|
|
Printf("idCommonStub::ClearWarnings reason=\"%s\"\n", reason ? reason : "");
|
|
}
|
|
|
|
void idCommonStub::Error(const char* fmt, ...) {
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
VOutputf("ERROR: ", fmt, args);
|
|
va_end(args);
|
|
|
|
#ifdef QUAKE4
|
|
va_list args2;
|
|
va_start(args2, fmt);
|
|
idStr::vsnPrintf(errorMessage, sizeof(errorMessage), fmt ? fmt : "", args2);
|
|
errorMessage[sizeof(errorMessage) - 1] = '\0';
|
|
va_end(args2);
|
|
#endif
|
|
|
|
// Stub behavior: do not throw unless you want this to behave like real common.
|
|
// throw idException( "idCommonStub::Error" );
|
|
}
|
|
|
|
void idCommonStub::FatalError(const char* fmt, ...) {
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
VOutputf("FATAL: ", fmt, args);
|
|
va_end(args);
|
|
|
|
#ifdef QUAKE4
|
|
va_list args2;
|
|
va_start(args2, fmt);
|
|
idStr::vsnPrintf(errorMessage, sizeof(errorMessage), fmt ? fmt : "", args2);
|
|
errorMessage[sizeof(errorMessage) - 1] = '\0';
|
|
va_end(args2);
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
MessageBeep(MB_ICONERROR);
|
|
#endif
|
|
|
|
// Stub behavior: do not exit unless you want this to behave like real common.
|
|
// Sys_Quit();
|
|
}
|
|
|
|
#ifdef QUAKE4
|
|
void idCommonStub::DumpWarnings(void) {
|
|
Printf("idCommonStub::DumpWarnings: no queued warnings.\n");
|
|
}
|
|
#endif
|
|
|
|
const idLangDict* idCommonStub::GetLanguageDict(void) {
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef QUAKE4
|
|
|
|
const char* idCommonStub::GetLocalizedString(const char* token, int langIndex) {
|
|
return token ? token : "";
|
|
}
|
|
|
|
const idLangKeyValue* idCommonStub::GetLocalizedString(int index, int langIndex) {
|
|
return NULL;
|
|
}
|
|
|
|
int idCommonStub::GetNumLanguages(void) const {
|
|
return 1;
|
|
}
|
|
|
|
int idCommonStub::GetNumLocalizedStrings(void) const {
|
|
return 0;
|
|
}
|
|
|
|
const char* idCommonStub::GetLanguage(int index) const {
|
|
return "english";
|
|
}
|
|
|
|
bool idCommonStub::LanguageHasVO(int index) const {
|
|
return false;
|
|
}
|
|
|
|
#endif
|
|
|
|
const char* idCommonStub::KeysFromBinding(const char* bind) {
|
|
return "";
|
|
}
|
|
|
|
const char* idCommonStub::BindingFromKey(const char* key) {
|
|
return "";
|
|
}
|
|
|
|
int idCommonStub::ButtonState(int key) {
|
|
return 0;
|
|
}
|
|
|
|
int idCommonStub::KeyState(int key) {
|
|
return 0;
|
|
}
|
|
|
|
#ifdef QUAKE4
|
|
|
|
int idCommonStub::GetRModeForMachineSpec(int machineSpec) const {
|
|
return -1;
|
|
}
|
|
|
|
void idCommonStub::SetDesiredMachineSpec(int machineSpec) {
|
|
Printf("idCommonStub::SetDesiredMachineSpec %d\n", machineSpec);
|
|
}
|
|
|
|
bool idCommonStub::IsRCon(void) const {
|
|
return false;
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef PREY
|
|
|
|
void idCommonStub::MaterialKeyForBinding(const char* binding, char* materialName, char* keyText, bool* wideKey) {
|
|
if (materialName) {
|
|
materialName[0] = '\0';
|
|
}
|
|
|
|
if (keyText) {
|
|
keyText[0] = '\0';
|
|
}
|
|
|
|
if (wideKey) {
|
|
*wideKey = false;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
float idCommonStub::Get_com_engineHz_latched(void) {
|
|
return 60.0f;
|
|
}
|
|
|
|
int64_t idCommonStub::Get_com_engineHz_numerator(void) {
|
|
return 60;
|
|
}
|
|
|
|
int64_t idCommonStub::Get_com_engineHz_denominator(void) {
|
|
return 1;
|
|
}
|
|
|
|
class idDeclManagerStub : public idDeclManager {
|
|
public:
|
|
idDeclManagerStub() {
|
|
initialized = false;
|
|
checksum = 0;
|
|
}
|
|
|
|
virtual ~idDeclManagerStub(void) {
|
|
Shutdown();
|
|
}
|
|
|
|
private:
|
|
bool initialized;
|
|
int checksum;
|
|
|
|
void StubPrint(const char* fmt, ...) const {
|
|
char buffer[4096];
|
|
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
|
|
#if defined(_WIN32)
|
|
_vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, fmt ? fmt : "", args);
|
|
#else
|
|
vsnprintf(buffer, sizeof(buffer), fmt ? fmt : "", args);
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
|
#endif
|
|
|
|
va_end(args);
|
|
|
|
if (common) {
|
|
common->Printf("%s", buffer);
|
|
}
|
|
else {
|
|
fputs(buffer, stdout);
|
|
fflush(stdout);
|
|
|
|
#ifdef _WIN32
|
|
OutputDebugStringA(buffer);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
public:
|
|
virtual void Init(void) {
|
|
initialized = true;
|
|
StubPrint("idDeclManagerStub::Init\n");
|
|
}
|
|
|
|
virtual void Shutdown(void) {
|
|
if (initialized) {
|
|
StubPrint("idDeclManagerStub::Shutdown\n");
|
|
}
|
|
|
|
initialized = false;
|
|
}
|
|
|
|
virtual void Reload(bool force) {
|
|
StubPrint("idDeclManagerStub::Reload force=%d\n", force ? 1 : 0);
|
|
}
|
|
|
|
virtual void BeginLevelLoad(void) {
|
|
StubPrint("idDeclManagerStub::BeginLevelLoad\n");
|
|
}
|
|
|
|
virtual void EndLevelLoad(void) {
|
|
StubPrint("idDeclManagerStub::EndLevelLoad\n");
|
|
}
|
|
|
|
virtual void RegisterDeclType(const char* typeName, declType_t type, idDecl* (*allocator)(void)) {
|
|
StubPrint("idDeclManagerStub::RegisterDeclType typeName=\"%s\" type=%d\n", typeName ? typeName : "", (int)type);
|
|
}
|
|
|
|
virtual void RegisterDeclFolder(const char* folder, const char* extension, declType_t defaultType) {
|
|
StubPrint(
|
|
"idDeclManagerStub::RegisterDeclFolder folder=\"%s\" extension=\"%s\" defaultType=%d\n",
|
|
folder ? folder : "",
|
|
extension ? extension : "",
|
|
(int)defaultType
|
|
);
|
|
}
|
|
|
|
virtual int GetChecksum(void) const {
|
|
return checksum;
|
|
}
|
|
|
|
virtual int GetNumDeclTypes(void) const {
|
|
return 0;
|
|
}
|
|
|
|
virtual const char* GetDeclNameFromType(declType_t type) const {
|
|
return "";
|
|
}
|
|
|
|
virtual declType_t GetDeclTypeFromName(const char* typeName) const {
|
|
return DECL_MAX_TYPES;
|
|
}
|
|
|
|
virtual const idDecl* FindType(declType_t type, const char* name, bool makeDefault = true) {
|
|
StubPrint(
|
|
"idDeclManagerStub::FindType type=%d name=\"%s\" makeDefault=%d\n",
|
|
(int)type,
|
|
name ? name : "",
|
|
makeDefault ? 1 : 0
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef QUAKE4
|
|
virtual const idDecl* FindType(declType_t type, const char* name, bool makeDefault, bool noCaching) {
|
|
StubPrint(
|
|
"idDeclManagerStub::FindType type=%d name=\"%s\" makeDefault=%d noCaching=%d\n",
|
|
(int)type,
|
|
name ? name : "",
|
|
makeDefault ? 1 : 0,
|
|
noCaching ? 1 : 0
|
|
);
|
|
|
|
return FindType(type, name, makeDefault);
|
|
}
|
|
#endif
|
|
|
|
virtual const idDecl* FindDeclWithoutParsing(declType_t type, const char* name, bool makeDefault = true) {
|
|
StubPrint(
|
|
"idDeclManagerStub::FindDeclWithoutParsing type=%d name=\"%s\" makeDefault=%d\n",
|
|
(int)type,
|
|
name ? name : "",
|
|
makeDefault ? 1 : 0
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
virtual void ReloadFile(const char* filename, bool force) {
|
|
StubPrint(
|
|
"idDeclManagerStub::ReloadFile filename=\"%s\" force=%d\n",
|
|
filename ? filename : "",
|
|
force ? 1 : 0
|
|
);
|
|
}
|
|
|
|
virtual int GetNumDecls(declType_t type) {
|
|
return 0;
|
|
}
|
|
|
|
virtual const idDecl* DeclByIndex(declType_t type, int index, bool forceParse = true) {
|
|
StubPrint(
|
|
"idDeclManagerStub::DeclByIndex type=%d index=%d forceParse=%d\n",
|
|
(int)type,
|
|
index,
|
|
forceParse ? 1 : 0
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
virtual void ListType(const idCmdArgs& args, declType_t type) {
|
|
StubPrint("idDeclManagerStub::ListType type=%d\n", (int)type);
|
|
}
|
|
|
|
virtual void PrintType(const idCmdArgs& args, declType_t type) {
|
|
StubPrint("idDeclManagerStub::PrintType type=%d\n", (int)type);
|
|
}
|
|
|
|
virtual bool CreateDeclFile(const char* fileName, declType_t defaultType) {
|
|
StubPrint(
|
|
"idDeclManagerStub::CreateDeclFile fileName=\"%s\" defaultType=%d\n",
|
|
fileName ? fileName : "",
|
|
(int)defaultType
|
|
);
|
|
|
|
return false;
|
|
}
|
|
|
|
virtual idDecl* CreateNewDecl(declType_t type, const char* name, const char* fileName, bool save = true) {
|
|
StubPrint(
|
|
"idDeclManagerStub::CreateNewDecl type=%d name=\"%s\" fileName=\"%s\" save=%d\n",
|
|
(int)type,
|
|
name ? name : "",
|
|
fileName ? fileName : "",
|
|
save ? 1 : 0
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
virtual bool SetDeclText(declType_t type, const char* name, const char* text, bool parse = true, bool save = false) {
|
|
StubPrint(
|
|
"idDeclManagerStub::SetDeclText type=%d name=\"%s\" parse=%d save=%d\n",
|
|
(int)type,
|
|
name ? name : "",
|
|
parse ? 1 : 0,
|
|
save ? 1 : 0
|
|
);
|
|
|
|
return false;
|
|
}
|
|
|
|
virtual bool SaveDecl(declType_t type, const char* name) {
|
|
StubPrint(
|
|
"idDeclManagerStub::SaveDecl type=%d name=\"%s\"\n",
|
|
(int)type,
|
|
name ? name : ""
|
|
);
|
|
|
|
return false;
|
|
}
|
|
|
|
virtual bool DeleteDecl(declType_t type, const char* name, bool deleteSourceText = true) {
|
|
StubPrint(
|
|
"idDeclManagerStub::DeleteDecl type=%d name=\"%s\" deleteSourceText=%d\n",
|
|
(int)type,
|
|
name ? name : "",
|
|
deleteSourceText ? 1 : 0
|
|
);
|
|
|
|
return false;
|
|
}
|
|
|
|
virtual bool RenameDecl(declType_t type, const char* oldName, const char* newName) {
|
|
StubPrint(
|
|
"idDeclManagerStub::RenameDecl type=%d oldName=\"%s\" newName=\"%s\"\n",
|
|
(int)type,
|
|
oldName ? oldName : "",
|
|
newName ? newName : ""
|
|
);
|
|
|
|
return false;
|
|
}
|
|
|
|
virtual void MediaPrint(const char* fmt, ...) id_attribute((format(printf, 2, 3))) {
|
|
char buffer[4096];
|
|
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
|
|
#if defined(_WIN32)
|
|
_vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, fmt ? fmt : "", args);
|
|
#else
|
|
vsnprintf(buffer, sizeof(buffer), fmt ? fmt : "", args);
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
|
#endif
|
|
|
|
va_end(args);
|
|
|
|
StubPrint("MEDIA: %s", buffer);
|
|
}
|
|
|
|
virtual void WritePrecacheCommands(idFile* f) {
|
|
StubPrint("idDeclManagerStub::WritePrecacheCommands\n");
|
|
}
|
|
|
|
#ifdef QUAKE4
|
|
virtual void ParseGuides(void) {
|
|
StubPrint("idDeclManagerStub::ParseGuides\n");
|
|
}
|
|
|
|
virtual void ShutdownGuides(void) {
|
|
StubPrint("idDeclManagerStub::ShutdownGuides\n");
|
|
}
|
|
|
|
virtual bool EvaluateGuide(idStr& name, idLexer* src, idStr& definition) {
|
|
StubPrint("idDeclManagerStub::EvaluateGuide name=\"%s\"\n", name.c_str());
|
|
return false;
|
|
}
|
|
|
|
virtual bool EvaluateInlineGuide(idStr& name, idStr& definition) {
|
|
StubPrint("idDeclManagerStub::EvaluateInlineGuide name=\"%s\"\n", name.c_str());
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
virtual const idMaterial* FindMaterial(const char* name, bool makeDefault = true) {
|
|
StubPrint(
|
|
"idDeclManagerStub::FindMaterial name=\"%s\" makeDefault=%d\n",
|
|
name ? name : "",
|
|
makeDefault ? 1 : 0
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
virtual const idDeclSkin* FindSkin(const char* name, bool makeDefault = true) {
|
|
StubPrint(
|
|
"idDeclManagerStub::FindSkin name=\"%s\" makeDefault=%d\n",
|
|
name ? name : "",
|
|
makeDefault ? 1 : 0
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
virtual const idSoundShader* FindSound(const char* name, bool makeDefault = true) {
|
|
StubPrint(
|
|
"idDeclManagerStub::FindSound name=\"%s\" makeDefault=%d\n",
|
|
name ? name : "",
|
|
makeDefault ? 1 : 0
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
virtual const idMaterial* MaterialByIndex(int index, bool forceParse = true) {
|
|
StubPrint(
|
|
"idDeclManagerStub::MaterialByIndex index=%d forceParse=%d\n",
|
|
index,
|
|
forceParse ? 1 : 0
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
virtual const idDeclSkin* SkinByIndex(int index, bool forceParse = true) {
|
|
StubPrint(
|
|
"idDeclManagerStub::SkinByIndex index=%d forceParse=%d\n",
|
|
index,
|
|
forceParse ? 1 : 0
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
virtual const idSoundShader* SoundByIndex(int index, bool forceParse = true) {
|
|
StubPrint(
|
|
"idDeclManagerStub::SoundByIndex index=%d forceParse=%d\n",
|
|
index,
|
|
forceParse ? 1 : 0
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
virtual const class idDeclTable* FindTable(const char* name, bool makeDefault = true) {
|
|
StubPrint(
|
|
"idDeclManagerStub::FindTable name=\"%s\" makeDefault=%d\n",
|
|
name ? name : "",
|
|
makeDefault ? 1 : 0
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef QUAKE4
|
|
virtual const class rvDeclMatType* FindMaterialType(const char* name, bool makeDefault = true) {
|
|
StubPrint(
|
|
"idDeclManagerStub::FindMaterialType name=\"%s\" makeDefault=%d\n",
|
|
name ? name : "",
|
|
makeDefault ? 1 : 0
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
virtual const class rvDeclLipSync* FindLipSync(const char* name, bool makeDefault = true) {
|
|
StubPrint(
|
|
"idDeclManagerStub::FindLipSync name=\"%s\" makeDefault=%d\n",
|
|
name ? name : "",
|
|
makeDefault ? 1 : 0
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
virtual const class rvDeclPlayback* FindPlayback(const char* name, bool makeDefault = true) {
|
|
StubPrint(
|
|
"idDeclManagerStub::FindPlayback name=\"%s\" makeDefault=%d\n",
|
|
name ? name : "",
|
|
makeDefault ? 1 : 0
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
virtual const class rvDeclEffect* FindEffect(const char* name, bool makeDefault = true) {
|
|
StubPrint(
|
|
"idDeclManagerStub::FindEffect name=\"%s\" makeDefault=%d\n",
|
|
name ? name : "",
|
|
makeDefault ? 1 : 0
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
virtual const class rvDeclMatType* MaterialTypeByIndex(int index, bool forceParse = true) {
|
|
StubPrint(
|
|
"idDeclManagerStub::MaterialTypeByIndex index=%d forceParse=%d\n",
|
|
index,
|
|
forceParse ? 1 : 0
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
virtual const class rvDeclLipSync* LipSyncByIndex(int index, bool forceParse = true) {
|
|
StubPrint(
|
|
"idDeclManagerStub::LipSyncByIndex index=%d forceParse=%d\n",
|
|
index,
|
|
forceParse ? 1 : 0
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
virtual const class rvDeclPlayback* PlaybackByIndex(int index, bool forceParse = true) {
|
|
StubPrint(
|
|
"idDeclManagerStub::PlaybackByIndex index=%d forceParse=%d\n",
|
|
index,
|
|
forceParse ? 1 : 0
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
virtual const class rvDeclEffect* EffectByIndex(int index, bool forceParse = true) {
|
|
StubPrint(
|
|
"idDeclManagerStub::EffectByIndex index=%d forceParse=%d\n",
|
|
index,
|
|
forceParse ? 1 : 0
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
#endif
|
|
};
|
|
|
|
idDeclManagerStub declManagerLocal;
|
|
idDeclManager* declManager = &declManagerLocal;
|
|
|
|
#ifndef MAX_OSPATH
|
|
#define MAX_OSPATH 256
|
|
#endif
|
|
|
|
#ifndef MAX_SYS_STUB_EVENTS
|
|
#define MAX_SYS_STUB_EVENTS 64
|
|
#endif
|
|
|
|
#ifndef MAX_SYS_STUB_CRITICAL_SECTIONS
|
|
#define MAX_SYS_STUB_CRITICAL_SECTIONS 64
|
|
#endif
|
|
|
|
#ifndef MAX_SYS_STUB_THREADS
|
|
#define MAX_SYS_STUB_THREADS 64
|
|
#endif
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Globals expected by other code
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
idSys* sys = NULL;
|
|
idEventLoop* eventLoop = NULL;
|
|
|
|
int g_thread_count = 0;
|
|
|
|
static xthreadInfo* sys_stub_thread_storage[MAX_SYS_STUB_THREADS];
|
|
xthreadInfo* g_threads[MAX_THREADS];
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
com_developer
|
|
|
|
If this constructor does not match your branch, change only this one line.
|
|
|
|
Doom 3-style branches usually support:
|
|
|
|
idCVar( name, value, flags, description )
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
#ifndef CVAR_BOOL
|
|
#define CVAR_BOOL 0
|
|
#endif
|
|
|
|
#ifndef CVAR_SYSTEM
|
|
#define CVAR_SYSTEM 0
|
|
#endif
|
|
|
|
idCVar com_developer(
|
|
"developer",
|
|
"0",
|
|
CVAR_SYSTEM | CVAR_BOOL,
|
|
"Stubbed developer cvar"
|
|
);
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Debug/helper functions
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
static void SysStub_DebugPrint(const char* text) {
|
|
if (!text) {
|
|
return;
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
OutputDebugStringA(text);
|
|
#endif
|
|
|
|
fputs(text, stdout);
|
|
fflush(stdout);
|
|
}
|
|
|
|
static void SysStub_NormalizeSlashes(char* path) {
|
|
if (!path) {
|
|
return;
|
|
}
|
|
|
|
for (char* p = path; *p; p++) {
|
|
if (*p == '\\') {
|
|
*p = '/';
|
|
}
|
|
}
|
|
}
|
|
|
|
static void SysStub_CopyString(char* dst, int dstSize, const char* src) {
|
|
if (!dst || dstSize <= 0) {
|
|
return;
|
|
}
|
|
|
|
if (!src) {
|
|
src = "";
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
strncpy_s(dst, dstSize, src, _TRUNCATE);
|
|
#else
|
|
strncpy(dst, src, dstSize - 1);
|
|
dst[dstSize - 1] = '\0';
|
|
#endif
|
|
}
|
|
|
|
static bool SysStub_StringEndsWith(const char* text, const char* suffix) {
|
|
if (!text || !suffix) {
|
|
return false;
|
|
}
|
|
|
|
const size_t textLen = strlen(text);
|
|
const size_t suffixLen = strlen(suffix);
|
|
|
|
if (suffixLen > textLen) {
|
|
return false;
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
return _stricmp(text + textLen - suffixLen, suffix) == 0;
|
|
#else
|
|
return strcasecmp(text + textLen - suffixLen, suffix) == 0;
|
|
#endif
|
|
}
|
|
|
|
static const char* SysStub_GetExePathFull(void) {
|
|
static char exePath[MAX_OSPATH];
|
|
|
|
exePath[0] = '\0';
|
|
|
|
#ifdef _WIN32
|
|
GetModuleFileNameA(NULL, exePath, sizeof(exePath));
|
|
exePath[sizeof(exePath) - 1] = '\0';
|
|
#else
|
|
ssize_t len = readlink("/proc/self/exe", exePath, sizeof(exePath) - 1);
|
|
if (len > 0) {
|
|
exePath[len] = '\0';
|
|
}
|
|
else if (getcwd(exePath, sizeof(exePath)) == NULL) {
|
|
strcpy(exePath, ".");
|
|
}
|
|
#endif
|
|
|
|
SysStub_NormalizeSlashes(exePath);
|
|
|
|
if (exePath[0] == '\0') {
|
|
strcpy(exePath, ".");
|
|
}
|
|
|
|
return exePath;
|
|
}
|
|
|
|
static const char* SysStub_GetExeDirectory(void) {
|
|
static char exeDir[MAX_OSPATH];
|
|
|
|
SysStub_CopyString(exeDir, sizeof(exeDir), SysStub_GetExePathFull());
|
|
SysStub_NormalizeSlashes(exeDir);
|
|
|
|
char* lastSlash = strrchr(exeDir, '/');
|
|
if (lastSlash) {
|
|
*lastSlash = '\0';
|
|
}
|
|
|
|
if (exeDir[0] == '\0') {
|
|
strcpy(exeDir, ".");
|
|
}
|
|
|
|
return exeDir;
|
|
}
|
|
|
|
static bool SysStub_IsDirectory(const char* path) {
|
|
if (!path || !path[0]) {
|
|
return false;
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
DWORD attribs = GetFileAttributesA(path);
|
|
if (attribs == INVALID_FILE_ATTRIBUTES) {
|
|
return false;
|
|
}
|
|
|
|
return (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
|
#else
|
|
struct stat st;
|
|
if (stat(path, &st) != 0) {
|
|
return false;
|
|
}
|
|
|
|
return S_ISDIR(st.st_mode);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Sys_FileTimeStamp
|
|
|
|
Required linker symbol:
|
|
|
|
__int64 __cdecl Sys_FileTimeStamp( struct _iobuf * )
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
int64_t Sys_FileTimeStamp(FILE* fp) {
|
|
if (!fp) {
|
|
return 0;
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
const int fd = _fileno(fp);
|
|
if (fd < 0) {
|
|
return 0;
|
|
}
|
|
|
|
HANDLE hFile = (HANDLE)_get_osfhandle(fd);
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
return 0;
|
|
}
|
|
|
|
FILETIME writeTime;
|
|
if (!GetFileTime(hFile, NULL, NULL, &writeTime)) {
|
|
return 0;
|
|
}
|
|
|
|
ULARGE_INTEGER uli;
|
|
uli.LowPart = writeTime.dwLowDateTime;
|
|
uli.HighPart = writeTime.dwHighDateTime;
|
|
|
|
// FILETIME is 100ns ticks since Jan 1 1601.
|
|
// Unix timestamp is seconds since Jan 1 1970.
|
|
const uint64_t windowsTicks = uli.QuadPart;
|
|
const uint64_t unixTicks = windowsTicks - 116444736000000000ULL;
|
|
|
|
return (int64_t)(unixTicks / 10000000ULL);
|
|
#else
|
|
const int fd = fileno(fp);
|
|
if (fd < 0) {
|
|
return 0;
|
|
}
|
|
|
|
struct stat st;
|
|
if (fstat(fd, &st) != 0) {
|
|
return 0;
|
|
}
|
|
|
|
return (int64_t)st.st_mtime;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Paths
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
const char* Sys_EXEPath(void) {
|
|
return SysStub_GetExeDirectory();
|
|
}
|
|
|
|
const char* Sys_DefaultBasePath(void) {
|
|
return SysStub_GetExeDirectory();
|
|
}
|
|
|
|
const char* Sys_DefaultSavePath(void) {
|
|
return SysStub_GetExeDirectory();
|
|
}
|
|
|
|
const char* Sys_DefaultCDPath(void) {
|
|
return "";
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Sys_Mkdir
|
|
|
|
Recursive mkdir.
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
void Sys_Mkdir(const char* path) {
|
|
if (!path || !path[0]) {
|
|
return;
|
|
}
|
|
|
|
char temp[MAX_OSPATH * 4];
|
|
SysStub_CopyString(temp, sizeof(temp), path);
|
|
SysStub_NormalizeSlashes(temp);
|
|
|
|
const int len = (int)strlen(temp);
|
|
if (len <= 0) {
|
|
return;
|
|
}
|
|
|
|
// Do not try to create "C:" by itself.
|
|
for (char* p = temp; *p; p++) {
|
|
if (*p != '/') {
|
|
continue;
|
|
}
|
|
|
|
// Skip drive root, for example C:/.
|
|
if (p == temp + 2 && temp[1] == ':') {
|
|
continue;
|
|
}
|
|
|
|
// Skip leading slash.
|
|
if (p == temp) {
|
|
continue;
|
|
}
|
|
|
|
*p = '\0';
|
|
|
|
if (temp[0] && !SysStub_IsDirectory(temp)) {
|
|
#ifdef _WIN32
|
|
_mkdir(temp);
|
|
#else
|
|
mkdir(temp, 0755);
|
|
#endif
|
|
}
|
|
|
|
*p = '/';
|
|
}
|
|
|
|
if (!SysStub_IsDirectory(temp)) {
|
|
#ifdef _WIN32
|
|
_mkdir(temp);
|
|
#else
|
|
mkdir(temp, 0755);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Sys_ListFiles
|
|
|
|
Real directory listing.
|
|
|
|
Returns count added.
|
|
|
|
Behavior:
|
|
- extension NULL / empty: lists everything except "." and ".."
|
|
- extension "/" : lists folders only
|
|
- extension ".ext" : lists files ending in .ext
|
|
- extension "ext" : also treated like ".ext"
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
int Sys_ListFiles(const char* directory, const char* extension, idList<idStr>& list) {
|
|
if (!directory || !directory[0]) {
|
|
return 0;
|
|
}
|
|
|
|
const int startCount = list.Num();
|
|
|
|
const bool listFoldersOnly = extension && strcmp(extension, "/") == 0;
|
|
const bool hasExtensionFilter = extension && extension[0] && !listFoldersOnly;
|
|
|
|
char normalizedExtension[128];
|
|
normalizedExtension[0] = '\0';
|
|
|
|
if (hasExtensionFilter) {
|
|
if (extension[0] == '.') {
|
|
SysStub_CopyString(normalizedExtension, sizeof(normalizedExtension), extension);
|
|
}
|
|
else {
|
|
#ifdef _WIN32
|
|
_snprintf_s(normalizedExtension, sizeof(normalizedExtension), _TRUNCATE, ".%s", extension);
|
|
#else
|
|
snprintf(normalizedExtension, sizeof(normalizedExtension), ".%s", extension);
|
|
normalizedExtension[sizeof(normalizedExtension) - 1] = '\0';
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
char searchPath[MAX_OSPATH * 4];
|
|
SysStub_CopyString(searchPath, sizeof(searchPath), directory);
|
|
SysStub_NormalizeSlashes(searchPath);
|
|
|
|
const int searchLen = (int)strlen(searchPath);
|
|
if (searchLen > 0 && searchPath[searchLen - 1] != '/') {
|
|
strcat_s(searchPath, sizeof(searchPath), "/");
|
|
}
|
|
|
|
strcat_s(searchPath, sizeof(searchPath), "*");
|
|
|
|
WIN32_FIND_DATAA findData;
|
|
HANDLE hFind = FindFirstFileA(searchPath, &findData);
|
|
|
|
if (hFind == INVALID_HANDLE_VALUE) {
|
|
return 0;
|
|
}
|
|
|
|
do {
|
|
const char* name = findData.cFileName;
|
|
|
|
if (!strcmp(name, ".") || !strcmp(name, "..")) {
|
|
continue;
|
|
}
|
|
|
|
const bool isDirectory = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
|
|
|
if (listFoldersOnly) {
|
|
if (!isDirectory) {
|
|
continue;
|
|
}
|
|
}
|
|
else {
|
|
if (isDirectory) {
|
|
continue;
|
|
}
|
|
|
|
if (hasExtensionFilter && !SysStub_StringEndsWith(name, normalizedExtension)) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
list.Append(idStr(name));
|
|
|
|
} while (FindNextFileA(hFind, &findData));
|
|
|
|
FindClose(hFind);
|
|
#else
|
|
DIR* dir = opendir(directory);
|
|
if (!dir) {
|
|
return 0;
|
|
}
|
|
|
|
struct dirent* entry;
|
|
while ((entry = readdir(dir)) != NULL) {
|
|
const char* name = entry->d_name;
|
|
|
|
if (!strcmp(name, ".") || !strcmp(name, "..")) {
|
|
continue;
|
|
}
|
|
|
|
char fullPath[MAX_OSPATH * 4];
|
|
snprintf(fullPath, sizeof(fullPath), "%s/%s", directory, name);
|
|
fullPath[sizeof(fullPath) - 1] = '\0';
|
|
|
|
const bool isDirectory = SysStub_IsDirectory(fullPath);
|
|
|
|
if (listFoldersOnly) {
|
|
if (!isDirectory) {
|
|
continue;
|
|
}
|
|
}
|
|
else {
|
|
if (isDirectory) {
|
|
continue;
|
|
}
|
|
|
|
if (hasExtensionFilter && !SysStub_StringEndsWith(name, normalizedExtension)) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
list.Append(idStr(name));
|
|
}
|
|
|
|
closedir(dir);
|
|
#endif
|
|
|
|
return list.Num() - startCount;
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Critical sections
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
#ifdef _WIN32
|
|
|
|
static CRITICAL_SECTION sys_stub_criticalSections[MAX_SYS_STUB_CRITICAL_SECTIONS];
|
|
static bool sys_stub_criticalSectionsInitialized[MAX_SYS_STUB_CRITICAL_SECTIONS];
|
|
|
|
static void SysStub_InitCriticalSection(int index) {
|
|
if (index < 0 || index >= MAX_SYS_STUB_CRITICAL_SECTIONS) {
|
|
return;
|
|
}
|
|
|
|
if (!sys_stub_criticalSectionsInitialized[index]) {
|
|
InitializeCriticalSection(&sys_stub_criticalSections[index]);
|
|
sys_stub_criticalSectionsInitialized[index] = true;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
void Sys_EnterCriticalSection(int index) {
|
|
#ifdef _WIN32
|
|
if (index < 0 || index >= MAX_SYS_STUB_CRITICAL_SECTIONS) {
|
|
return;
|
|
}
|
|
|
|
SysStub_InitCriticalSection(index);
|
|
EnterCriticalSection(&sys_stub_criticalSections[index]);
|
|
#else
|
|
(void)index;
|
|
#endif
|
|
}
|
|
|
|
void Sys_LeaveCriticalSection(int index) {
|
|
#ifdef _WIN32
|
|
if (index < 0 || index >= MAX_SYS_STUB_CRITICAL_SECTIONS) {
|
|
return;
|
|
}
|
|
|
|
SysStub_InitCriticalSection(index);
|
|
LeaveCriticalSection(&sys_stub_criticalSections[index]);
|
|
#else
|
|
(void)index;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Events
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
#ifdef _WIN32
|
|
|
|
static HANDLE sys_stub_events[MAX_SYS_STUB_EVENTS];
|
|
|
|
static HANDLE SysStub_GetEvent(int index) {
|
|
if (index < 0 || index >= MAX_SYS_STUB_EVENTS) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!sys_stub_events[index]) {
|
|
sys_stub_events[index] = CreateEventA(
|
|
NULL,
|
|
FALSE, // auto reset
|
|
FALSE, // initially not signaled
|
|
NULL
|
|
);
|
|
}
|
|
|
|
return sys_stub_events[index];
|
|
}
|
|
|
|
#endif
|
|
|
|
void Sys_WaitForEvent(int index) {
|
|
#ifdef _WIN32
|
|
HANDLE eventHandle = SysStub_GetEvent(index);
|
|
if (!eventHandle) {
|
|
return;
|
|
}
|
|
|
|
WaitForSingleObject(eventHandle, INFINITE);
|
|
#else
|
|
(void)index;
|
|
#endif
|
|
}
|
|
|
|
void Sys_TriggerEvent(int index) {
|
|
#ifdef _WIN32
|
|
HANDLE eventHandle = SysStub_GetEvent(index);
|
|
if (!eventHandle) {
|
|
return;
|
|
}
|
|
|
|
SetEvent(eventHandle);
|
|
#else
|
|
(void)index;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Thread creation
|
|
|
|
Required linker symbol:
|
|
|
|
void Sys_CreateThread(
|
|
unsigned int (__cdecl*)(void *),
|
|
void *,
|
|
enum xthreadPriority,
|
|
struct xthreadInfo &,
|
|
char const *,
|
|
struct xthreadInfo ** const,
|
|
int *
|
|
)
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
#ifdef _WIN32
|
|
|
|
struct sysStubThreadStart_t {
|
|
unsigned int (*function)(void*);
|
|
void* parameter;
|
|
};
|
|
|
|
static unsigned __stdcall SysStub_ThreadTrampoline(void* arg) {
|
|
sysStubThreadStart_t* start = (sysStubThreadStart_t*)arg;
|
|
|
|
unsigned int result = 0;
|
|
|
|
if (start && start->function) {
|
|
result = start->function(start->parameter);
|
|
}
|
|
|
|
delete start;
|
|
return result;
|
|
}
|
|
|
|
#endif
|
|
|
|
void Sys_CreateThread(
|
|
unsigned int (*function)(void*),
|
|
void* parameter,
|
|
xthreadPriority priority,
|
|
xthreadInfo& info,
|
|
const char* name,
|
|
xthreadInfo** const threads,
|
|
int* thread_count
|
|
) {
|
|
#ifdef _WIN32
|
|
memset(&info, 0, sizeof(info));
|
|
|
|
sysStubThreadStart_t* start = new sysStubThreadStart_t;
|
|
start->function = function;
|
|
start->parameter = parameter;
|
|
|
|
unsigned int threadId = 0;
|
|
HANDLE handle = (HANDLE)_beginthreadex(
|
|
NULL,
|
|
0,
|
|
SysStub_ThreadTrampoline,
|
|
start,
|
|
0,
|
|
&threadId
|
|
);
|
|
|
|
if (!handle) {
|
|
delete start;
|
|
SysStub_DebugPrint("Sys_CreateThread failed\n");
|
|
return;
|
|
}
|
|
|
|
// This assumes your xthreadInfo has these common Doom 3 fields.
|
|
// If your struct differs, comment these out or adjust names.
|
|
info.threadHandle = (int)handle;
|
|
info.threadId = threadId;
|
|
info.name = name;
|
|
|
|
switch (priority) {
|
|
|
|
|
|
case THREAD_NORMAL:
|
|
SetThreadPriority(handle, THREAD_PRIORITY_NORMAL);
|
|
break;
|
|
|
|
|
|
default:
|
|
SetThreadPriority(handle, THREAD_PRIORITY_NORMAL);
|
|
break;
|
|
}
|
|
|
|
if (threads && thread_count) {
|
|
if (*thread_count >= 0 && *thread_count < MAX_SYS_STUB_THREADS) {
|
|
threads[*thread_count] = &info;
|
|
(*thread_count)++;
|
|
}
|
|
}
|
|
|
|
g_thread_count++;
|
|
|
|
char buffer[512];
|
|
#ifdef _WIN32
|
|
_snprintf_s(
|
|
buffer,
|
|
sizeof(buffer),
|
|
_TRUNCATE,
|
|
"Sys_CreateThread created \"%s\" id=%u\n",
|
|
name ? name : "",
|
|
threadId
|
|
);
|
|
#else
|
|
snprintf(buffer, sizeof(buffer), "Sys_CreateThread created\n");
|
|
#endif
|
|
|
|
SysStub_DebugPrint(buffer);
|
|
#else
|
|
(void)function;
|
|
(void)parameter;
|
|
(void)priority;
|
|
(void)info;
|
|
(void)name;
|
|
(void)threads;
|
|
(void)thread_count;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
idEventLoop::JournalLevel
|
|
|
|
Stubbed to 0 so file system reads do not try to journal.
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
int idEventLoop::JournalLevel(void) const {
|
|
return 0;
|
|
} |