fixed some signed/unsigned warnings; added gamma control via SDL
This was SVN commit r258.
This commit is contained in:
parent
cf5e2524c2
commit
df6fceba62
@ -58,7 +58,40 @@ u32 fnv_hash(const void* buf, const size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// FNV1-A hash - good for strings.
|
||||||
|
// if len = 0 (default), treat buf as a C-string;
|
||||||
|
// otherwise, hash <len> bytes of buf.
|
||||||
|
u64 fnv_hash64(const void* buf, const size_t len)
|
||||||
|
{
|
||||||
|
u64 h = 0xCBF29CE484222325;
|
||||||
|
// give distinct values for different length 0 buffers.
|
||||||
|
// value taken from FNV; it has no special significance.
|
||||||
|
|
||||||
|
const u8* p = (const u8*)buf;
|
||||||
|
|
||||||
|
// expected case: string
|
||||||
|
if(!len)
|
||||||
|
{
|
||||||
|
while(*p)
|
||||||
|
{
|
||||||
|
h ^= *p++;
|
||||||
|
h *= 0x100000001B3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t bytes_left = len;
|
||||||
|
while(bytes_left != 0)
|
||||||
|
{
|
||||||
|
h ^= *p++;
|
||||||
|
h *= 0x100000001B3;
|
||||||
|
|
||||||
|
bytes_left--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void bswap32(const u8* data, int cnt)
|
void bswap32(const u8* data, int cnt)
|
||||||
@ -173,6 +206,26 @@ float fminf(float a, float b)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
long round(double x)
|
||||||
|
{
|
||||||
|
return (long)(x + 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// input in [0, 1); convert to u16 range
|
||||||
|
u16 fp_to_u16(double in)
|
||||||
|
{
|
||||||
|
if(!(0 <= in && in < 1.0))
|
||||||
|
{
|
||||||
|
debug_warn("clampf not in [0,1)");
|
||||||
|
return 65535;
|
||||||
|
}
|
||||||
|
|
||||||
|
long l = round(in * 65535.0);
|
||||||
|
assert((unsigned long)l <= 65535);
|
||||||
|
return (u16)l;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// big endian!
|
// big endian!
|
||||||
void base32(const int len, const u8* in, u8* out)
|
void base32(const int len, const u8* in, u8* out)
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
// if len = 0 (default), treat buf as a C-string;
|
// if len = 0 (default), treat buf as a C-string;
|
||||||
// otherwise, hash <len> bytes of buf.
|
// otherwise, hash <len> bytes of buf.
|
||||||
extern u32 fnv_hash(const void* buf, const size_t len = 0);
|
extern u32 fnv_hash(const void* buf, const size_t len = 0);
|
||||||
|
extern u64 fnv_hash64(const void* buf, const size_t len);
|
||||||
|
|
||||||
// hash (currently FNV) of a filename
|
// hash (currently FNV) of a filename
|
||||||
typedef u32 FnHash;
|
typedef u32 FnHash;
|
||||||
@ -104,6 +105,8 @@ extern float fminf(float, float);
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extern long round(double);
|
||||||
|
extern u16 fp_to_u16(double in);
|
||||||
|
|
||||||
// big endian!
|
// big endian!
|
||||||
extern void base32(const int len, const u8* in, u8* out);
|
extern void base32(const int len, const u8* in, u8* out);
|
||||||
|
@ -22,3 +22,5 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
|
||||||
|
#pragma warning(disable:4996)
|
@ -6,3 +6,11 @@ int res_reload(const char* const fn)
|
|||||||
{
|
{
|
||||||
return h_reload(fn);
|
return h_reload(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// purpose of this routine (intended to be called once a frame):
|
||||||
|
// file notification may come at any time. by forcing the reloads
|
||||||
|
// to take place here, we don't require everything to be thread-safe.
|
@ -96,10 +96,14 @@ __asm
|
|||||||
long cpu_caps = 0;
|
long cpu_caps = 0;
|
||||||
long cpu_ext_caps = 0;
|
long cpu_ext_caps = 0;
|
||||||
|
|
||||||
|
int tsc_is_safe = -1;
|
||||||
|
|
||||||
|
|
||||||
static char cpu_vendor[13];
|
static char cpu_vendor[13];
|
||||||
static int family, model; // used to detect cpu_type
|
static int family, model; // used to detect cpu_type
|
||||||
|
|
||||||
int tsc_is_safe = -1;
|
static int have_brand_string = 0;
|
||||||
|
// int instead of bool for easier setting from asm
|
||||||
|
|
||||||
|
|
||||||
// optimized for size
|
// optimized for size
|
||||||
@ -148,11 +152,11 @@ __asm
|
|||||||
mov esi, 0x80000000
|
mov esi, 0x80000000
|
||||||
mov eax, esi
|
mov eax, esi
|
||||||
cpuid
|
cpuid
|
||||||
cmp eax, esi
|
cmp eax, esi ; max ext <= 0x80000000?
|
||||||
jbe no_ext_funcs
|
jbe no_ext_funcs ; yes - no ext funcs at all
|
||||||
lea esi, [esi+4]
|
lea esi, [esi+4] ; esi = 0x80000004
|
||||||
cmp eax, esi
|
cmp eax, esi ; max ext < 0x80000004?
|
||||||
jb no_brand_str
|
jb no_brand_str ; yes - brand string not available, skip
|
||||||
|
|
||||||
; get CPU brand string (>= Athlon XP, P4)
|
; get CPU brand string (>= Athlon XP, P4)
|
||||||
mov edi, offset cpu_type
|
mov edi, offset cpu_type
|
||||||
@ -171,6 +175,8 @@ $1: lea eax, [ebp+esi] ; 0x80000002 .. 4
|
|||||||
jle $1
|
jle $1
|
||||||
; (already 0 terminated)
|
; (already 0 terminated)
|
||||||
|
|
||||||
|
mov [have_brand_string], ebp ; ebp = 1 = true
|
||||||
|
|
||||||
no_brand_str:
|
no_brand_str:
|
||||||
|
|
||||||
; get extended feature flags
|
; get extended feature flags
|
||||||
@ -194,8 +200,54 @@ void ia32_get_cpu_info()
|
|||||||
if(cpu_caps == 0) // cpuid not supported - can't do the rest
|
if(cpu_caps == 0) // cpuid not supported - can't do the rest
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// cpu_type set from brand string - clean it up some
|
// fall back to manual detect of CPU type if it didn't supply
|
||||||
if(strcmp(cpu_type, "unknown") != 0)
|
// a brand string, or if the brand string is useless (i.e. "Unknown").
|
||||||
|
if(!have_brand_string || strncmp(cpu_type, "Unknow", 6) == 0)
|
||||||
|
// we use an extra flag to detect if we got the brand string:
|
||||||
|
// safer than comparing against the default name, which may change.
|
||||||
|
//
|
||||||
|
// some older boards reprogram the brand string with
|
||||||
|
// "Unknow[n] CPU Type" on CPUs the BIOS doesn't recognize.
|
||||||
|
// in that case, we ignore the brand string and detect manually.
|
||||||
|
{
|
||||||
|
// AMD
|
||||||
|
if(!strcmp(cpu_vendor, "AuthenticAMD"))
|
||||||
|
{
|
||||||
|
// everything else is either too old, or should have a brand string.
|
||||||
|
if(family == 6)
|
||||||
|
{
|
||||||
|
if(model == 3 || model == 7)
|
||||||
|
strcpy(cpu_type, "AMD Duron");
|
||||||
|
else if(model <= 5)
|
||||||
|
strcpy(cpu_type, "AMD Athlon");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(cpu_ext_caps & EXT_MP_CAPABLE)
|
||||||
|
strcpy(cpu_type, "AMD Athlon MP");
|
||||||
|
else
|
||||||
|
strcpy(cpu_type, "AMD Athlon XP");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Intel
|
||||||
|
else if(!strcmp(cpu_vendor, "GenuineIntel"))
|
||||||
|
{
|
||||||
|
// everything else is either too old, or should have a brand string.
|
||||||
|
if(family == 6)
|
||||||
|
{
|
||||||
|
if(model == 1)
|
||||||
|
strcpy(cpu_type, "Intel Pentium Pro");
|
||||||
|
else if(model == 3 || model == 5)
|
||||||
|
strcpy(cpu_type, "Intel Pentium II");
|
||||||
|
else if(model == 6)
|
||||||
|
strcpy(cpu_type, "Intel Celeron");
|
||||||
|
else
|
||||||
|
strcpy(cpu_type, "Intel Pentium III");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// we have a valid brand string; try to pretty it up some
|
||||||
|
else
|
||||||
{
|
{
|
||||||
// strip (tm) from Athlon string
|
// strip (tm) from Athlon string
|
||||||
if(!strncmp(cpu_type, "AMD Athlon(tm)", 14))
|
if(!strncmp(cpu_type, "AMD Athlon(tm)", 14))
|
||||||
@ -209,22 +261,11 @@ void ia32_get_cpu_info()
|
|||||||
if(sscanf(cpu_type, " Intel(R) Pentium(R) 4 CPU %fGHz", &a) == 1)
|
if(sscanf(cpu_type, " Intel(R) Pentium(R) 4 CPU %fGHz", &a) == 1)
|
||||||
strcpy(cpu_type, "Intel Pentium 4");
|
strcpy(cpu_type, "Intel Pentium 4");
|
||||||
}
|
}
|
||||||
// detect cpu_type ourselves
|
|
||||||
else
|
|
||||||
{
|
//
|
||||||
// AMD
|
// measure CPU frequency
|
||||||
if(!strcmp(cpu_vendor, "AuthenticAMD"))
|
//
|
||||||
{
|
|
||||||
if(family == 6)
|
|
||||||
strcpy(cpu_type, (model == 3)? "AMD Duron" : "AMD Athlon");
|
|
||||||
}
|
|
||||||
// Intel
|
|
||||||
else if(!strcmp(cpu_vendor, "GenuineIntel"))
|
|
||||||
{
|
|
||||||
if(family == 6 && model >= 7)
|
|
||||||
strcpy(cpu_type, "Intel Pentium III / Celeron");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// .. get old policy and priority
|
// .. get old policy and priority
|
||||||
int old_policy;
|
int old_policy;
|
||||||
|
@ -52,8 +52,9 @@ enum
|
|||||||
extern long cpu_caps;
|
extern long cpu_caps;
|
||||||
|
|
||||||
// define instead of enum to avoid stupid sign conversion warning
|
// define instead of enum to avoid stupid sign conversion warning
|
||||||
#define EXT_3DNOW_PRO BIT(30)
|
#define EXT_MP_CAPABLE BIT(19)
|
||||||
#define EXT_3DNOW BIT(31)
|
#define EXT_3DNOW_PRO BIT(30)
|
||||||
|
#define EXT_3DNOW BIT(31)
|
||||||
|
|
||||||
extern long cpu_ext_caps;
|
extern long cpu_ext_caps;
|
||||||
|
|
||||||
|
@ -29,10 +29,11 @@
|
|||||||
// powrprof is loaded manually - we only need 1 function.
|
// powrprof is loaded manually - we only need 1 function.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "Tlhelp32.h"
|
||||||
|
|
||||||
|
|
||||||
// EnumDisplayDevices is not available on Win95 or NT.
|
// EnumDisplayDevices is not available on Win95 or NT.
|
||||||
// try to import it manually here; return -1 if not available.
|
// try to import it manually here; return -1 if not available.
|
||||||
// note: FreeLibrary at exit avoids BoundsChecker resource leak warnings.
|
|
||||||
static BOOL (WINAPI *pEnumDisplayDevicesA)(void*, DWORD, void*, DWORD);
|
static BOOL (WINAPI *pEnumDisplayDevicesA)(void*, DWORD, void*, DWORD);
|
||||||
static int import_EnumDisplayDevices()
|
static int import_EnumDisplayDevices()
|
||||||
{
|
{
|
||||||
@ -40,7 +41,10 @@ static int import_EnumDisplayDevices()
|
|||||||
{
|
{
|
||||||
static HMODULE hUser32Dll = LoadLibrary("user32.dll");
|
static HMODULE hUser32Dll = LoadLibrary("user32.dll");
|
||||||
*(void**)&pEnumDisplayDevicesA = GetProcAddress(hUser32Dll, "EnumDisplayDevicesA");
|
*(void**)&pEnumDisplayDevicesA = GetProcAddress(hUser32Dll, "EnumDisplayDevicesA");
|
||||||
ONCE(atexit2(FreeLibrary, (uintptr_t)hUser32Dll, CC_STDCALL_1));
|
FreeLibrary(hUser32Dll);
|
||||||
|
// make sure the reference is released so BoundsChecker
|
||||||
|
// doesn't complain. it won't actually be unloaded anyway -
|
||||||
|
// there is at least one other reference.
|
||||||
}
|
}
|
||||||
|
|
||||||
return pEnumDisplayDevicesA? 0 : -1;
|
return pEnumDisplayDevicesA? 0 : -1;
|
||||||
@ -94,21 +98,53 @@ int win_get_gfx_card()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
get ogl client DLL name
|
||||||
|
enum loaded dlls
|
||||||
|
ogl must be running; ambiguous (need to eliminate MCD and opengl32.dll)
|
||||||
|
*/
|
||||||
|
// no .dll appended
|
||||||
|
//
|
||||||
|
static int get_ogl_drv_name(char* const ogl_drv_name, const size_t max_name_len)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
HKEY hkOglDrivers;
|
||||||
|
const char* key = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\OpenGLDrivers";
|
||||||
|
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_ENUMERATE_SUB_KEYS, &hkOglDrivers) != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
char key_name[32];
|
||||||
|
DWORD key_name_len = sizeof(key_name);
|
||||||
|
if(RegEnumKeyEx(hkOglDrivers, 0, key_name, &key_name_len, 0, 0, 0, 0) == 0)
|
||||||
|
{
|
||||||
|
HKEY hkClass;
|
||||||
|
if(RegOpenKeyEx(hkOglDrivers, key_name, 0, KEY_QUERY_VALUE, &hkClass) == 0)
|
||||||
|
{
|
||||||
|
DWORD size = (DWORD)max_name_len;
|
||||||
|
if(RegQueryValueEx(hkClass, "Dll", 0, 0, (LPBYTE)ogl_drv_name, &size) == 0)
|
||||||
|
ret = 0; // success
|
||||||
|
|
||||||
|
RegCloseKey(hkClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RegCloseKey(hkOglDrivers);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// split out so we can return on failure, instead of goto
|
// split out so we can return on failure, instead of goto
|
||||||
// method: http://www.opengl.org/discussion_boards/ubb/Forum3/HTML/009679.html
|
// method: http://www.opengl.org/discussion_boards/ubb/Forum3/HTML/009679.html
|
||||||
int win_get_gfx_drv()
|
int win_get_gfx_drv()
|
||||||
{
|
{
|
||||||
// get driver DLL name
|
|
||||||
DEVMODEA dm;
|
/* want ogl icd, instead of 2d driver */
|
||||||
// note: dmDriverVersion is not what we're looking for
|
|
||||||
memset(&dm, 0, sizeof(dm));
|
char ogl_drv_name[MAX_PATH];
|
||||||
dm.dmSize = sizeof(dm);
|
CHECK_ERR(get_ogl_drv_name(ogl_drv_name, sizeof(ogl_drv_name)));
|
||||||
// note: dmSize isn't the first member!
|
|
||||||
if(!EnumDisplaySettingsA(0, ENUM_CURRENT_SETTINGS, &dm))
|
|
||||||
return -1;
|
|
||||||
char drv_name[CCHDEVICENAME+5]; // we add ".dll"
|
|
||||||
strcpy(drv_name, (const char*)dm.dmDeviceName);
|
|
||||||
strcat(drv_name, ".dll");
|
|
||||||
|
|
||||||
// don't want to return 0 on success - we'd need to duplicate free(buf).
|
// don't want to return 0 on success - we'd need to duplicate free(buf).
|
||||||
// instead, set this variable and return that.
|
// instead, set this variable and return that.
|
||||||
@ -116,21 +152,21 @@ int win_get_gfx_drv()
|
|||||||
|
|
||||||
// read the DLL's version info
|
// read the DLL's version info
|
||||||
DWORD unused;
|
DWORD unused;
|
||||||
DWORD ver_size = GetFileVersionInfoSize(drv_name, &unused);
|
const DWORD ver_size = GetFileVersionInfoSize(ogl_drv_name, &unused);
|
||||||
if(!ver_size)
|
if(!ver_size)
|
||||||
return -1;
|
return -1;
|
||||||
void* buf = malloc(ver_size);
|
void* const buf = malloc(ver_size);
|
||||||
if(!buf)
|
if(!buf)
|
||||||
return -1;
|
return -1;
|
||||||
if(GetFileVersionInfo(drv_name, 0, ver_size, buf))
|
if(GetFileVersionInfo(ogl_drv_name, 0, ver_size, buf))
|
||||||
{
|
{
|
||||||
u16* lang; // -> 16 bit language ID, 16 bit codepage
|
u16* lang; // -> 16 bit language ID, 16 bit codepage
|
||||||
uint lang_len;
|
uint lang_len;
|
||||||
BOOL ok = VerQueryValue(buf, "\\VarFileInfo\\Translation", (void**)&lang, &lang_len);
|
const BOOL ok = VerQueryValue(buf, "\\VarFileInfo\\Translation", (void**)&lang, &lang_len);
|
||||||
if(ok && lang && lang_len == 4)
|
if(ok && lang && lang_len == 4)
|
||||||
{
|
{
|
||||||
char subblock[64];
|
char subblock[64];
|
||||||
sprintf(subblock, "\\StringFileInfo\\%04X%04X\\ProductName", lang[0], lang[1]);
|
sprintf(subblock, "\\StringFileInfo\\%04X%04X\\FileVersion", lang[0], lang[1]);
|
||||||
const char* ver;
|
const char* ver;
|
||||||
uint ver_len;
|
uint ver_len;
|
||||||
if(VerQueryValue(buf, subblock, (void**)&ver, &ver_len))
|
if(VerQueryValue(buf, subblock, (void**)&ver, &ver_len))
|
||||||
|
@ -17,9 +17,90 @@
|
|||||||
|
|
||||||
#include "precompiled.h"
|
#include "precompiled.h"
|
||||||
|
|
||||||
#include "res/res.h"
|
#include "wfam.h"
|
||||||
|
#include "win_internal.h"
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
static const size_t CHANGE_BUF_SIZE = 15000;
|
||||||
|
// better be enough - if too small, we miss changes made to a directory.
|
||||||
|
|
||||||
|
|
||||||
|
// don't worry about size: the user only passes around a pointer
|
||||||
|
// to this struct, due to the pImpl idiom. this is heap-allocated.
|
||||||
|
struct FAMRequest_
|
||||||
|
{
|
||||||
|
std::string dir_name;
|
||||||
|
HANDLE hDir;
|
||||||
|
|
||||||
|
// history to detect series of notifications, so we can skip
|
||||||
|
// redundant reloads (slow)
|
||||||
|
std::string last_path;
|
||||||
|
DWORD last_action; // FILE_ACTION_* codes or 0
|
||||||
|
DWORD last_ticks; // timestamp via GetTickCount
|
||||||
|
|
||||||
|
OVERLAPPED ovl;
|
||||||
|
// we don't use any of its fields.
|
||||||
|
// overlapped I/O completation notification is via IOCP.
|
||||||
|
// rationale: see below.
|
||||||
|
char changes[CHANGE_BUF_SIZE];
|
||||||
|
|
||||||
|
|
||||||
|
FAMRequest_(const char* _dir_name)
|
||||||
|
: dir_name(_dir_name), last_path("")
|
||||||
|
{
|
||||||
|
last_action = 0;
|
||||||
|
last_ticks = 0;
|
||||||
|
|
||||||
|
memset(&ovl, 0, sizeof(ovl));
|
||||||
|
|
||||||
|
// changes[] doesn't need init
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// don't worry about size: the user only passes around a pointer
|
||||||
|
// to this struct, due to the pImpl idiom. this is heap-allocated.
|
||||||
|
struct FAMConnection_
|
||||||
|
{
|
||||||
|
std::string app_name;
|
||||||
|
|
||||||
|
|
||||||
|
HANDLE hIOCP;
|
||||||
|
|
||||||
|
// queue necessary - race condition if pass to app and re-issue
|
||||||
|
// needs to be FIFO, and don't want to constantly shuffle items (can be rather large)
|
||||||
|
// around => list
|
||||||
|
typedef std::list<FAMEvent> Events;
|
||||||
|
Events pending_events;
|
||||||
|
|
||||||
|
// list of all pending requests to detect duplicates and
|
||||||
|
// for easier cleanup. only store pointer in container -
|
||||||
|
// they're not copy-equivalent.
|
||||||
|
typedef std::map<std::string, FAMRequest*> Requests;
|
||||||
|
typedef Requests::iterator RequestIt;
|
||||||
|
Requests requests;
|
||||||
|
|
||||||
|
FAMConnection_(const char* _app_name)
|
||||||
|
: app_name(_app_name)
|
||||||
|
{
|
||||||
|
hIOCP = 0;
|
||||||
|
// not INVALID_HANDLE_VALUE! (CreateIoCompletionPort requirement)
|
||||||
|
}
|
||||||
|
|
||||||
|
~FAMConnection_()
|
||||||
|
{
|
||||||
|
CloseHandle(hIOCP);
|
||||||
|
hIOCP = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
|
// container holds dynamically allocated Watch structs
|
||||||
|
// for(WatchIt it = watches.begin(); it != watches.end(); ++it)
|
||||||
|
// delete it->second;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "sysdep/win/win_internal.h"
|
|
||||||
|
|
||||||
|
|
||||||
// rationale for using I/O completion ports for notification:
|
// rationale for using I/O completion ports for notification:
|
||||||
@ -43,118 +124,158 @@
|
|||||||
// IOCPs work well and are elegant; have not yet noticed any drawbacks.
|
// IOCPs work well and are elegant; have not yet noticed any drawbacks.
|
||||||
|
|
||||||
|
|
||||||
static HANDLE hIOCP = 0;
|
|
||||||
// not INVALID_HANDLE_VALUE! (CreateIoCompletionPort requirement)
|
|
||||||
|
|
||||||
|
|
||||||
static const size_t WATCH_BUF_SIZE = 16384;
|
|
||||||
// better be enough - if too small, we miss changes made to a directory.
|
|
||||||
|
|
||||||
|
|
||||||
// ReadDirectoryChangesW must be called again after each time it returns data,
|
// ReadDirectoryChangesW must be called again after each time it returns data,
|
||||||
// so we need to pass this struct to the notification "callback".
|
// so we need to pass along the associated Request.
|
||||||
// we do this implicitly with the guarantee that &ovl = &Watch (verified via
|
// since we issue RDC immediately, instead of sending a bogus packet
|
||||||
// assert). rationale: the Key param is already in use (tells the callback to
|
// to the IOCP that triggers the issue, we don't need the key parameter
|
||||||
// call RDC - see KEY_ADD_WATCH_ONLY); this way of passing the parameter is
|
// for anything - use it to pass along the Request.
|
||||||
// cleaner IMO than stuffing the address in an unused member of OVERLAPPED.
|
// cleaner than assuming &ovl = &Request, or stuffing it in an unused
|
||||||
struct Watch
|
// member of OVERLAPPED.
|
||||||
{
|
|
||||||
OVERLAPPED ovl;
|
|
||||||
// we don't use any of its fields.
|
|
||||||
|
|
||||||
void* buf;
|
|
||||||
|
|
||||||
HANDLE hDir;
|
|
||||||
|
|
||||||
bool watch_subdirs;
|
|
||||||
|
|
||||||
// history to detect series of notifications, so we can skip
|
|
||||||
// redundant reloads (slow)
|
|
||||||
std::string last_path;
|
|
||||||
DWORD last_action; // FILE_ACTION_* codes or 0
|
|
||||||
DWORD last_ticks; // timestamp via GetTickCount
|
|
||||||
|
|
||||||
|
|
||||||
Watch(HANDLE hDir, bool watch_subdirs)
|
|
||||||
{
|
|
||||||
this->hDir = hDir;
|
|
||||||
this->watch_subdirs = watch_subdirs;
|
|
||||||
|
|
||||||
buf = mem_alloc(WATCH_BUF_SIZE, 32);
|
|
||||||
// ReadDirectoryChangesW requirement: at least 4-byte alignment.
|
|
||||||
|
|
||||||
memset(&ovl, 0, sizeof(ovl));
|
|
||||||
|
|
||||||
last_action = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
~Watch()
|
|
||||||
{
|
|
||||||
// mem_free(buf);
|
|
||||||
// FIXME: mem has already shut down when this is called.
|
|
||||||
|
|
||||||
CancelIo(hDir);
|
|
||||||
|
|
||||||
CloseHandle(hDir);
|
|
||||||
hDir = INVALID_HANDLE_VALUE;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// don't store directly in container - not copy-equivalent.
|
|
||||||
typedef std::map<std::string, Watch*> Watches;
|
|
||||||
typedef Watches::iterator WatchIt;
|
|
||||||
static Watches watches;
|
|
||||||
|
|
||||||
|
|
||||||
static void cleanup(void)
|
|
||||||
{
|
|
||||||
CloseHandle(hIOCP);
|
|
||||||
|
|
||||||
// container holds dynamically allocated Watch structs
|
|
||||||
for(WatchIt it = watches.begin(); it != watches.end(); ++it)
|
|
||||||
delete it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int dir_watch_abort(const char* const dir)
|
int dir_watch_abort(const char* const dir)
|
||||||
{
|
{
|
||||||
// find watch
|
// find watch
|
||||||
const std::string dir_s(dir);
|
/* const std::string dir_s(dir);
|
||||||
WatchIt it = watches.find(dir_s);
|
WatchIt it = watches.find(dir_s);
|
||||||
if(it == watches.end())
|
if(it == watches.end())
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
delete it->second;
|
delete it->second;
|
||||||
watches.erase(it);
|
watches.erase(it);
|
||||||
|
*/
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// it's nice to have only 1 call site of ReadDirectoryChangesW, namely
|
// it'd be nice to have only 1 call site of ReadDirectoryChangesW, namely
|
||||||
// in the notification "callback". posting an event to the IOCP with
|
// in the notification "callback". however, posting a dummy event to the IOCP
|
||||||
// KEY_ADD_WATCH_ONLY tells it to call RDC; normal events pass KEY_NORMAL.
|
// and having the callback issue RDC is a bit ugly, and loses changes made
|
||||||
static enum
|
// before the poll routine is first called.
|
||||||
|
|
||||||
|
static int dir_watch_issue(FAMRequest_* fr)
|
||||||
{
|
{
|
||||||
KEY_NORMAL,
|
// (re-)request change notification from now on
|
||||||
KEY_ADD_WATCH_ONLY
|
const DWORD filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME |
|
||||||
};
|
FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE |
|
||||||
|
FILE_NOTIFY_CHANGE_CREATION;
|
||||||
|
BOOL ret = ReadDirectoryChangesW(fr->hDir, fr->changes, CHANGE_BUF_SIZE, FALSE, filter, 0, &fr->ovl, 0);
|
||||||
|
return ret? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int dir_add_watch(const char* const dir, const bool watch_subdirs)
|
int dir_add_watch(const char* const dir, const bool watch_subdirs)
|
||||||
{
|
{
|
||||||
ONCE(atexit2(cleanup));
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FAMCancelMonitor(FAMConnection*, FAMRequest* req)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void wfam_shutdown()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int FAMOpen2(FAMConnection* const fc, const char* app_name)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fc->internal = new FAMConnection_(app_name);
|
||||||
|
}
|
||||||
|
catch(std::bad_alloc)
|
||||||
|
{
|
||||||
|
fc->internal = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// either (VC6) new returned 0, or we caught bad_alloc => fail.
|
||||||
|
if(!fc->internal)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int FAMClose(FAMConnection* const fc)
|
||||||
|
{
|
||||||
|
FAMConnection_*& fc_ = (FAMConnection_*)fc->internal;
|
||||||
|
if(!fc_)
|
||||||
|
{
|
||||||
|
debug_warn("FAMClose: already closed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete fc_;
|
||||||
|
fc_ = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int FAMMonitorDirectory(FAMConnection* fc, char* dir, FAMRequest* fr, void* user)
|
||||||
|
{
|
||||||
|
FAMConnection_* fc_ = (FAMConnection_*)fc->internal;
|
||||||
|
|
||||||
|
/*
|
||||||
// make sure dir is not already being watched
|
// make sure dir is not already being watched
|
||||||
const std::string dir_s(dir);
|
const std::string dir_s(dir);
|
||||||
WatchIt it = watches.find(dir_s);
|
WatchIt it = watches.find(dir_s);
|
||||||
if(it != watches.end())
|
if(it != watches.end())
|
||||||
return -1;
|
return -1;
|
||||||
|
*/
|
||||||
|
HANDLE hDir = INVALID_HANDLE_VALUE;
|
||||||
|
HANDLE& hIOCP = fc_->hIOCP;
|
||||||
|
|
||||||
// open handle to directory
|
// open handle to directory
|
||||||
const DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
const DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
||||||
const DWORD flags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED;
|
const DWORD flags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED;
|
||||||
const HANDLE hDir = CreateFile(dir, FILE_LIST_DIRECTORY, share, 0, OPEN_EXISTING, flags, 0);
|
hDir = CreateFile(dir, FILE_LIST_DIRECTORY, share, 0, OPEN_EXISTING, flags, 0);
|
||||||
if(hDir == INVALID_HANDLE_VALUE)
|
if(hDir == INVALID_HANDLE_VALUE)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -162,105 +283,139 @@ int dir_add_watch(const char* const dir, const bool watch_subdirs)
|
|||||||
hIOCP = CreateIoCompletionPort(hDir, hIOCP, KEY_NORMAL, 0);
|
hIOCP = CreateIoCompletionPort(hDir, hIOCP, KEY_NORMAL, 0);
|
||||||
if(hIOCP == 0 || hIOCP == INVALID_HANDLE_VALUE)
|
if(hIOCP == 0 || hIOCP == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
|
fail:
|
||||||
CloseHandle(hDir);
|
CloseHandle(hDir);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// insert
|
// insert
|
||||||
Watch* const w = new Watch(hDir, watch_subdirs);
|
Watch* const w = new Watch(hDir, watch_subdirs);
|
||||||
watches[dir_s] = w;
|
watches[dir_s] = w;
|
||||||
|
|
||||||
// tell the notification "callback" to actually add the watch
|
dir_watch_issue(w);
|
||||||
const DWORD bytes_transferred = 0;
|
|
||||||
PostQueuedCompletionStatus(hIOCP, bytes_transferred, KEY_ADD_WATCH_ONLY, &w->ovl);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int dir_changed(const FILE_NOTIFY_INFORMATION*, Watch*);
|
|
||||||
|
|
||||||
// purpose of this routine (intended to be called once a frame):
|
|
||||||
// file notification may come at any time. by forcing the reloads
|
|
||||||
// to take place here, we don't require everything to be thread-safe.
|
|
||||||
//
|
|
||||||
// added bonus: can actually "poll" for changes here - obviates a worker
|
// added bonus: can actually "poll" for changes here - obviates a worker
|
||||||
// thread, mutex, and 2 queues.
|
// thread, mutex, and 2 queues.
|
||||||
int allow_reload()
|
|
||||||
|
|
||||||
|
|
||||||
|
static int extract_events(FAMConnection* conn, FAMRequest* req)
|
||||||
{
|
{
|
||||||
// deque and process all pending IOCP packets
|
FAMConnection_ conn_ = (FAMConnection_*)conn->internal;
|
||||||
|
const FILE_NOTIFY_INFORMATION* fni = (const FILE_NOTIFY_INFORMATION*)req->changes;
|
||||||
|
Events& events = fc_->pending_events;
|
||||||
|
|
||||||
|
FAMEvent event_template;
|
||||||
|
event_template.conn = conn;
|
||||||
|
event_template.req = req;
|
||||||
|
|
||||||
|
// for every packet in buffer: (there's at least one)
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
// check for change_notification or add_watch packets
|
// many apps save by creating a temp file, deleting the original,
|
||||||
DWORD bytes_transferred; // unused
|
// and renaming the temp file. that leads to 2 reloads, which is slow.
|
||||||
ULONG_PTR key;
|
// try to detect this case with a simple state machine - we assume
|
||||||
OVERLAPPED* povl;
|
// the notification order is always the same.
|
||||||
BOOL got_packet = GetQueuedCompletionStatus(hIOCP, &bytes_transferred, &key, &povl, 0);
|
|
||||||
if(!got_packet)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// retrieve the corresponding Watch
|
// TODO:
|
||||||
// (see Watch definition for rationale)
|
|
||||||
Watch* const w = (Watch*)povl;
|
|
||||||
assert(offsetof(struct Watch, ovl) == 0);
|
|
||||||
|
|
||||||
// (re-)request change notification from now on
|
const char* actions[] = { "", "FILE_ACTION_ADDED", "FILE_ACTION_REMOVED", "FILE_ACTION_MODIFIED", "FILE_ACTION_RENAMED_OLD_NAME", "FILE_ACTION_RENAMED_NEW_NAME" };
|
||||||
const DWORD filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME |
|
const char* action = actions[fni->Action];
|
||||||
FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE |
|
|
||||||
FILE_NOTIFY_CHANGE_CREATION;
|
|
||||||
ReadDirectoryChangesW(w->hDir, w->buf, WATCH_BUF_SIZE, TRUE, filter, 0, &w->ovl, 0);
|
|
||||||
|
|
||||||
// dir_add_watch requests the watch be added;
|
// convert Windows BSTR-style path to
|
||||||
// we didn't actually receive any change notification
|
// portable C string path for the resource manager.
|
||||||
if(key == KEY_ADD_WATCH_ONLY)
|
// HACK: convert in place, we copy it into
|
||||||
continue;
|
char fn[MAX_PATH];
|
||||||
|
char* p = fn;
|
||||||
FILE_NOTIFY_INFORMATION* fni = (FILE_NOTIFY_INFORMATION*)w->buf;
|
const int num_chars = fni->FileNameLength/2;
|
||||||
for(;;)
|
for(int i = 0; i < num_chars; i++)
|
||||||
{
|
{
|
||||||
dir_changed(fni, w);
|
char c = (char)fni->FileName[i];
|
||||||
|
if(c == '\\')
|
||||||
DWORD ofs = fni->NextEntryOffset;
|
c = '/';
|
||||||
// this was the last entry
|
*p++ = c;
|
||||||
if(!ofs)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// advance to next FILE_NOTIFY_INFORMATION (variable length)
|
|
||||||
(char*&)fni += ofs;
|
|
||||||
}
|
}
|
||||||
|
*p = '\0';
|
||||||
|
|
||||||
|
// don't want to expose details
|
||||||
|
|
||||||
|
events.push_back(event_template);
|
||||||
|
|
||||||
|
|
||||||
|
const DWORD ofs = fni->NextEntryOffset;
|
||||||
|
// advance to next FILE_NOTIFY_INFORMATION (variable length)
|
||||||
|
if(ofs)
|
||||||
|
(char*&)fni += ofs;
|
||||||
|
// this was the last entry - no more elements left in buffer.
|
||||||
|
else
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int dir_changed(const FILE_NOTIFY_INFORMATION* const fni, Watch* const w)
|
|
||||||
{
|
|
||||||
// many apps save by creating a temp file, deleting the original,
|
|
||||||
// and renaming the temp file. that leads to 2 reloads, which is slow.
|
|
||||||
// try to detect this case with a simple state machine - we assume
|
|
||||||
// the notification order is always the same.
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
|
|
||||||
const char* actions[] = { "", "FILE_ACTION_ADDED", "FILE_ACTION_REMOVED", "FILE_ACTION_MODIFIED", "FILE_ACTION_RENAMED_OLD_NAME", "FILE_ACTION_RENAMED_NEW_NAME" };
|
|
||||||
const char* action = actions[fni->Action];
|
|
||||||
|
|
||||||
// convert Windows BSTR-style path to
|
|
||||||
// portable C string path for the resource manager.
|
|
||||||
char fn[MAX_PATH];
|
|
||||||
char* p = fn;
|
|
||||||
const int num_chars = fni->FileNameLength/2;
|
|
||||||
for(int i = 0; i < num_chars; i++)
|
|
||||||
{
|
|
||||||
char c = (char)fni->FileName[i];
|
|
||||||
if(c == '\\')
|
|
||||||
c = '/';
|
|
||||||
*p++ = c;
|
|
||||||
}
|
|
||||||
*p = '\0';
|
|
||||||
|
|
||||||
res_reload(fn);
|
res_reload(fn);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int FAMPending(FAMConnection* fc)
|
||||||
|
{
|
||||||
|
FAMConnection_* const fc_ = (FAMConnection_*)fc->internal;
|
||||||
|
Events& pending_events = fc_->pending_events;
|
||||||
|
|
||||||
|
if(!pending_events.empty())
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// check if new buffer has been filled
|
||||||
|
DWORD bytes_transferred; // unused
|
||||||
|
ULONG_PTR key;
|
||||||
|
OVERLAPPED* povl;
|
||||||
|
BOOL got_packet = GetQueuedCompletionStatus(fc_->hIOCP, &bytes_transferred, &key, &povl, 0);
|
||||||
|
if(!got_packet)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
CHECK_ERR(extract_events(conn, req));
|
||||||
|
|
||||||
|
// dir_watch_issue(buf);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fc->fni = (FILE_NOTIFY_INFORMATION*)w->buf;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int FAMNextEvent(FAMConnection* const fc, FAMEvent* const fe)
|
||||||
|
{
|
||||||
|
FAMConnection_* const fc_ = (FAMConnection_*)fc->internal;
|
||||||
|
Events& pending_events = fc_->pending_events;
|
||||||
|
|
||||||
|
if(!fe)
|
||||||
|
{
|
||||||
|
debug_warn("FAMNextEvent: fe = 0");
|
||||||
|
return ERR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pending_events.empty())
|
||||||
|
{
|
||||||
|
debug_warn("FAMNextEvent: no pending events");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*fe = pending_events.front();
|
||||||
|
pending_events.pop_front();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -466,6 +466,41 @@ inline void SDL_GL_SwapBuffers()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int calc_gamma(float gamma, u16* ramp)
|
||||||
|
{
|
||||||
|
if(gamma <= 0.0f)
|
||||||
|
return ERR_INVALID_PARAM;
|
||||||
|
|
||||||
|
// identity
|
||||||
|
// (special-case it to make sure we get the exact value)
|
||||||
|
if(gamma == 1.0f)
|
||||||
|
{
|
||||||
|
for(u16 i = 0; i < 256; i++)
|
||||||
|
ramp[i] = (i << 8);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const double inv_gamma = 1.0 / gamma;
|
||||||
|
for(int i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
const double frac = i / 256.0;
|
||||||
|
// make sure pow arg types are unambiguous
|
||||||
|
ramp[i] = fp_to_u16(pow(frac, inv_gamma));
|
||||||
|
// 8.8 fixed point
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int SDL_SetGamma(float r, float g, float b)
|
||||||
|
{
|
||||||
|
u16 ramp[3][256];
|
||||||
|
CHECK_ERR(calc_gamma(r, ramp[0]));
|
||||||
|
CHECK_ERR(calc_gamma(g, ramp[1]));
|
||||||
|
CHECK_ERR(calc_gamma(b, ramp[2]));
|
||||||
|
return SetDeviceGammaRamp(hDC, ramp)? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ extern int SDL_KillThread(SDL_Thread*);
|
|||||||
extern int __stdcall SDL_WarpMouse(int, int);
|
extern int __stdcall SDL_WarpMouse(int, int);
|
||||||
|
|
||||||
|
|
||||||
|
extern int SDL_SetGamma(float r, float g, float b);
|
||||||
|
|
||||||
/* macros */
|
/* macros */
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "Renderer.h"
|
#include "Renderer.h"
|
||||||
#include "Model.h"
|
#include "Model.h"
|
||||||
#include "UnitManager.h"
|
#include "UnitManager.h"
|
||||||
|
|
||||||
#include "BaseEntityCollection.h"
|
#include "BaseEntityCollection.h"
|
||||||
#include "Entity.h"
|
#include "Entity.h"
|
||||||
#include "EntityHandles.h"
|
#include "EntityHandles.h"
|
||||||
@ -39,6 +40,11 @@ bool keys[SDLK_LAST];
|
|||||||
// flag to disable extended GL extensions until fix found - specifically, crashes
|
// flag to disable extended GL extensions until fix found - specifically, crashes
|
||||||
// using VBOs on laptop Radeon cards
|
// using VBOs on laptop Radeon cards
|
||||||
static bool g_NoGLVBO=false;
|
static bool g_NoGLVBO=false;
|
||||||
|
|
||||||
|
static bool g_VSync = false;
|
||||||
|
|
||||||
|
static float g_Gamma = 1.0f;
|
||||||
|
|
||||||
// mapfile to load or null for no map (and to use default terrain)
|
// mapfile to load or null for no map (and to use default terrain)
|
||||||
static const char* g_MapFile=0;
|
static const char* g_MapFile=0;
|
||||||
|
|
||||||
@ -72,6 +78,8 @@ static int write_sys_info()
|
|||||||
fprintf(f, "%s %s (%s)\n", un.sysname, un.release, un.version);
|
fprintf(f, "%s %s (%s)\n", un.sysname, un.release, un.version);
|
||||||
// .. CPU
|
// .. CPU
|
||||||
fprintf(f, "%s, %s", un.machine, cpu_type);
|
fprintf(f, "%s, %s", un.machine, cpu_type);
|
||||||
|
if(cpus > 1)
|
||||||
|
fprintf(f, " (x%d)", cpus);
|
||||||
if(cpu_freq != 0.0f)
|
if(cpu_freq != 0.0f)
|
||||||
{
|
{
|
||||||
if(cpu_freq < 1e9)
|
if(cpu_freq < 1e9)
|
||||||
@ -315,6 +323,7 @@ void UpdateWorld(float time)
|
|||||||
for (uint i=0;i<units.size();++i) {
|
for (uint i=0;i<units.size();++i) {
|
||||||
units[i]->m_Model->Update(time);
|
units[i]->m_Model->Update(time);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_EntityManager.updateAll( time );
|
g_EntityManager.updateAll( time );
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -342,6 +351,7 @@ void ParseArgs(int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
const int ERR_MSG_SIZE = 1000;
|
const int ERR_MSG_SIZE = 1000;
|
||||||
@ -425,10 +435,21 @@ if(argc < 2)
|
|||||||
if(!oglExtAvail("GL_ARB_multitexture") || !oglExtAvail("GL_ARB_texture_env_combine"))
|
if(!oglExtAvail("GL_ARB_multitexture") || !oglExtAvail("GL_ARB_texture_env_combine"))
|
||||||
display_startup_error(L"required ARB_multitexture or ARB_texture_env_combine extension not available");
|
display_startup_error(L"required ARB_multitexture or ARB_texture_env_combine extension not available");
|
||||||
|
|
||||||
|
// enable/disable VSync
|
||||||
|
// note: "GL_EXT_SWAP_CONTROL" is "historical" according to dox.
|
||||||
|
if(oglExtAvail("WGL_EXT_swap_control"))
|
||||||
|
wglSwapIntervalEXT(g_VSync? 1 : 0);
|
||||||
|
|
||||||
|
|
||||||
|
if(SDL_SetGamma(g_Gamma, g_Gamma, g_Gamma) < 0)
|
||||||
|
{
|
||||||
|
debug_warn("SDL_SetGamma failed");
|
||||||
|
}
|
||||||
|
|
||||||
new CConfig;
|
new CConfig;
|
||||||
|
|
||||||
vfs_mount("", "mods/official/", 0);
|
vfs_mount("", "mods/official/", 0);
|
||||||
dir_add_watch("mods\\official", false);
|
//// dir_add_watch("mods\\official", false);
|
||||||
|
|
||||||
#ifndef NO_GUI
|
#ifndef NO_GUI
|
||||||
// GUI uses VFS, so this must come after VFS init.
|
// GUI uses VFS, so this must come after VFS init.
|
||||||
@ -448,12 +469,14 @@ if(argc < 2)
|
|||||||
// the terrain
|
// the terrain
|
||||||
terr_init();
|
terr_init();
|
||||||
|
|
||||||
|
|
||||||
// This needs to be done after the renderer has loaded all its actors...
|
// This needs to be done after the renderer has loaded all its actors...
|
||||||
new CBaseEntityCollection;
|
new CBaseEntityCollection;
|
||||||
new CEntityManager;
|
new CEntityManager;
|
||||||
|
|
||||||
g_EntityTemplateCollection.loadTemplates();
|
g_EntityTemplateCollection.loadTemplates();
|
||||||
|
|
||||||
|
|
||||||
// load a map if we were given one
|
// load a map if we were given one
|
||||||
if (g_MapFile) {
|
if (g_MapFile) {
|
||||||
CStr mapfilename("mods/official/maps/scenarios/");
|
CStr mapfilename("mods/official/maps/scenarios/");
|
||||||
@ -491,7 +514,7 @@ in_add_handler(terr_handler);
|
|||||||
{
|
{
|
||||||
//g_Config.Update();
|
//g_Config.Update();
|
||||||
|
|
||||||
allow_reload();
|
//// allow_reload();
|
||||||
|
|
||||||
|
|
||||||
// TODO: limiter in case simulation can't keep up?
|
// TODO: limiter in case simulation can't keep up?
|
||||||
|
@ -400,16 +400,9 @@ ostream &operator<<(ostream &os, CStr &Str)
|
|||||||
|
|
||||||
size_t CStr::GetHashCode() const
|
size_t CStr::GetHashCode() const
|
||||||
{
|
{
|
||||||
// FNV-1 hash for 64 bit integers.
|
return (size_t)fnv_hash64(m_String.data(), m_String.length());
|
||||||
size_t hash = 14695981039346656037;
|
// janwas asks: do we care about the hash being 64 bits?
|
||||||
const char* data = m_String.data();
|
// it is truncated here on 32-bit systems; why go 64 bit at all?
|
||||||
for( int t = 0; t < m_String.length(); t++ )
|
|
||||||
{
|
|
||||||
hash *= 1099511628211;
|
|
||||||
hash ^= *(data++);
|
|
||||||
}
|
|
||||||
return( hash );
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint CStr::GetSerializedLength() const
|
uint CStr::GetSerializedLength() const
|
||||||
|
@ -18,7 +18,7 @@ using namespace std;
|
|||||||
|
|
||||||
// use GetDouble and type-cast it to <<type>>
|
// use GetDouble and type-cast it to <<type>>
|
||||||
#define FUNC_IMPL_CAST_GETDOUBLE(func_name,type) \
|
#define FUNC_IMPL_CAST_GETDOUBLE(func_name,type) \
|
||||||
_bool CParserValue::func_name(type &ret) \
|
bool CParserValue::func_name(type &ret) \
|
||||||
{ \
|
{ \
|
||||||
_double d; \
|
_double d; \
|
||||||
if (GetDouble(d)) \
|
if (GetDouble(d)) \
|
||||||
@ -31,7 +31,7 @@ _bool CParserValue::func_name(type &ret) \
|
|||||||
// Get%type% from the CParserValue
|
// Get%type% from the CParserValue
|
||||||
// func_name must belong to CParserFile
|
// func_name must belong to CParserFile
|
||||||
#define FUNC_IMPL_GETARG(func_name, get_name, type) \
|
#define FUNC_IMPL_GETARG(func_name, get_name, type) \
|
||||||
_bool CParserLine::func_name(const _int & arg, type &ret) \
|
bool CParserLine::func_name(const int & arg, type &ret) \
|
||||||
{ \
|
{ \
|
||||||
if (GetArgCount() <= arg) \
|
if (GetArgCount() <= arg) \
|
||||||
return false; \
|
return false; \
|
||||||
@ -42,15 +42,15 @@ _bool CParserLine::func_name(const _int & arg, type &ret) \
|
|||||||
// Function definitions
|
// Function definitions
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
|
|
||||||
static _bool _IsStrictNameChar(const _char& c);
|
static bool _IsStrictNameChar(const _char& c);
|
||||||
static _bool _IsValueChar(const _char& c);
|
static bool _IsValueChar(const _char& c);
|
||||||
|
|
||||||
|
|
||||||
// Functions used for checking a character if it belongs to a value
|
// Functions used for checking a character if it belongs to a value
|
||||||
// or not
|
// or not
|
||||||
|
|
||||||
// Checks ident
|
// Checks ident
|
||||||
static _bool _IsStrictNameChar(const _char& c)
|
static bool _IsStrictNameChar(const _char& c)
|
||||||
{
|
{
|
||||||
return ((c >= 'a' && c <= 'z') ||
|
return ((c >= 'a' && c <= 'z') ||
|
||||||
(c >= 'A' && c <= 'Z') ||
|
(c >= 'A' && c <= 'Z') ||
|
||||||
@ -58,7 +58,7 @@ static _bool _IsStrictNameChar(const _char& c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Checks value
|
// Checks value
|
||||||
static _bool _IsValueChar(const _char& c)
|
static bool _IsValueChar(const _char& c)
|
||||||
{
|
{
|
||||||
return ((c >= 'a' && c <= 'z') ||
|
return ((c >= 'a' && c <= 'z') ||
|
||||||
(c >= 'A' && c <= 'Z') ||
|
(c >= 'A' && c <= 'Z') ||
|
||||||
@ -80,7 +80,7 @@ CParserValue::~CParserValue()
|
|||||||
// Parse the string in Value to different types
|
// Parse the string in Value to different types
|
||||||
|
|
||||||
// bool
|
// bool
|
||||||
_bool CParserValue::GetBool(_bool &ret)
|
bool CParserValue::GetBool(bool &ret)
|
||||||
{
|
{
|
||||||
// TODO Raj Add or remove some? I can make it all lowercase
|
// TODO Raj Add or remove some? I can make it all lowercase
|
||||||
// first so True and TRUE also works, or you could just
|
// first so True and TRUE also works, or you could just
|
||||||
@ -111,16 +111,16 @@ _bool CParserValue::GetBool(_bool &ret)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// double
|
// double
|
||||||
_bool CParserValue::GetDouble(_double &ret)
|
bool CParserValue::GetDouble(_double &ret)
|
||||||
{
|
{
|
||||||
// locals
|
// locals
|
||||||
_double TempRet = 0.0;
|
_double TempRet = 0.0;
|
||||||
_int Size = m_String.size();
|
int Size = m_String.size();
|
||||||
_int i;
|
int i;
|
||||||
_bool AtLeastOne = false; // Checked if at least one of the loops
|
bool AtLeastOne = false; // Checked if at least one of the loops
|
||||||
// run, otherwise "." would parse OK
|
// run, otherwise "." would parse OK
|
||||||
_int DecimalPos;
|
int DecimalPos;
|
||||||
_bool Negative = false; // "-" is found
|
bool Negative = false; // "-" is found
|
||||||
|
|
||||||
// Check if '-' is found
|
// Check if '-' is found
|
||||||
if (m_String[0]=='-')
|
if (m_String[0]=='-')
|
||||||
@ -180,7 +180,7 @@ _bool CParserValue::GetDouble(_double &ret)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// string - only return m_String, can't fail
|
// string - only return m_String, can't fail
|
||||||
_bool CParserValue::GetString(std::string &ret)
|
bool CParserValue::GetString(std::string &ret)
|
||||||
{
|
{
|
||||||
ret = m_String;
|
ret = m_String;
|
||||||
return true;
|
return true;
|
||||||
@ -192,7 +192,7 @@ _bool CParserValue::GetString(std::string &ret)
|
|||||||
FUNC_IMPL_CAST_GETDOUBLE(GetFloat, _float)
|
FUNC_IMPL_CAST_GETDOUBLE(GetFloat, _float)
|
||||||
FUNC_IMPL_CAST_GETDOUBLE(GetChar, _char)
|
FUNC_IMPL_CAST_GETDOUBLE(GetChar, _char)
|
||||||
FUNC_IMPL_CAST_GETDOUBLE(GetShort, _short)
|
FUNC_IMPL_CAST_GETDOUBLE(GetShort, _short)
|
||||||
FUNC_IMPL_CAST_GETDOUBLE(GetInt, _int)
|
FUNC_IMPL_CAST_GETDOUBLE(GetInt, int)
|
||||||
FUNC_IMPL_CAST_GETDOUBLE(GetLong, _long)
|
FUNC_IMPL_CAST_GETDOUBLE(GetLong, _long)
|
||||||
FUNC_IMPL_CAST_GETDOUBLE(GetUnsignedShort, _ushort)
|
FUNC_IMPL_CAST_GETDOUBLE(GetUnsignedShort, _ushort)
|
||||||
FUNC_IMPL_CAST_GETDOUBLE(GetUnsignedInt, _uint)
|
FUNC_IMPL_CAST_GETDOUBLE(GetUnsignedInt, _uint)
|
||||||
@ -264,7 +264,7 @@ CParserLine::~CParserLine()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Clear arguments (deleting m_Memory
|
// Clear arguments (deleting m_Memory
|
||||||
_bool CParserLine::ClearArguments()
|
bool CParserLine::ClearArguments()
|
||||||
{
|
{
|
||||||
// Now we can actually clear it
|
// Now we can actually clear it
|
||||||
m_Arguments.clear();
|
m_Arguments.clear();
|
||||||
@ -275,10 +275,10 @@ _bool CParserLine::ClearArguments()
|
|||||||
// it just checks if argument isn't out of range, and
|
// it just checks if argument isn't out of range, and
|
||||||
// then it uses the the respective function in CParserValue
|
// then it uses the the respective function in CParserValue
|
||||||
FUNC_IMPL_GETARG(GetArgString, GetString, string)
|
FUNC_IMPL_GETARG(GetArgString, GetString, string)
|
||||||
FUNC_IMPL_GETARG(GetArgBool, GetBool, _bool)
|
FUNC_IMPL_GETARG(GetArgBool, GetBool, bool)
|
||||||
FUNC_IMPL_GETARG(GetArgChar, GetChar, _char)
|
FUNC_IMPL_GETARG(GetArgChar, GetChar, _char)
|
||||||
FUNC_IMPL_GETARG(GetArgShort, GetShort, _short)
|
FUNC_IMPL_GETARG(GetArgShort, GetShort, _short)
|
||||||
FUNC_IMPL_GETARG(GetArgInt, GetInt, _int)
|
FUNC_IMPL_GETARG(GetArgInt, GetInt, int)
|
||||||
FUNC_IMPL_GETARG(GetArgLong, GetLong, _long)
|
FUNC_IMPL_GETARG(GetArgLong, GetLong, _long)
|
||||||
FUNC_IMPL_GETARG(GetArgUnsignedShort, GetUnsignedShort, _ushort)
|
FUNC_IMPL_GETARG(GetArgUnsignedShort, GetUnsignedShort, _ushort)
|
||||||
FUNC_IMPL_GETARG(GetArgUnsignedInt, GetUnsignedInt, _uint)
|
FUNC_IMPL_GETARG(GetArgUnsignedInt, GetUnsignedInt, _uint)
|
||||||
@ -293,7 +293,7 @@ FUNC_IMPL_GETARG(GetArgDouble, GetDouble, _double)
|
|||||||
// ex:
|
// ex:
|
||||||
// variable = 5 => variable, =, 5
|
// variable = 5 => variable, =, 5
|
||||||
// CallFunc(4,2) => CallFunc, 4, 2
|
// CallFunc(4,2) => CallFunc, 4, 2
|
||||||
_bool CParserLine::ParseString(const CParser& Parser, string strLine)
|
bool CParserLine::ParseString(const CParser& Parser, string strLine)
|
||||||
{
|
{
|
||||||
// Don't process empty string
|
// Don't process empty string
|
||||||
if (strLine == string())
|
if (strLine == string())
|
||||||
@ -303,13 +303,13 @@ _bool CParserLine::ParseString(const CParser& Parser, string strLine)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Locals
|
// Locals
|
||||||
_bool Extract=false;
|
bool Extract=false;
|
||||||
_int ExtractPos=0;
|
int ExtractPos=0;
|
||||||
_char Buffer[256];
|
_char Buffer[256];
|
||||||
_char Letter[] = {'\0','\0'}; // Letter as string
|
_char Letter[] = {'\0','\0'}; // Letter as string
|
||||||
vector<string> Segments;
|
vector<string> Segments;
|
||||||
string strSub;
|
string strSub;
|
||||||
_int i;
|
int i;
|
||||||
|
|
||||||
// Set result to false, then if a match is found, turn it true
|
// Set result to false, then if a match is found, turn it true
|
||||||
m_ParseOK = false;
|
m_ParseOK = false;
|
||||||
@ -343,7 +343,7 @@ _bool CParserLine::ParseString(const CParser& Parser, string strLine)
|
|||||||
if (strLine[i] == '\"')
|
if (strLine[i] == '\"')
|
||||||
{
|
{
|
||||||
// Extract a string, search for another "
|
// Extract a string, search for another "
|
||||||
_int pos = strLine.find("\"", i+1);
|
int pos = strLine.find("\"", i+1);
|
||||||
|
|
||||||
// If matching can't be found,
|
// If matching can't be found,
|
||||||
// the parsing will fail!
|
// the parsing will fail!
|
||||||
@ -419,23 +419,23 @@ _bool CParserLine::ParseString(const CParser& Parser, string strLine)
|
|||||||
// * * * *
|
// * * * *
|
||||||
|
|
||||||
// Locals
|
// Locals
|
||||||
_int Progress; // progress in Segments index
|
int Progress; // progress in Segments index
|
||||||
_int Lane=0; // Have many alternative routes we are in
|
int Lane=0; // Have many alternative routes we are in
|
||||||
_bool Match; // If a task-type match has been found
|
bool Match; // If a task-type match has been found
|
||||||
// The vector of these three represents the different lanes
|
// The vector of these three represents the different lanes
|
||||||
// LastValidProgress[1] takes you back to lane 1 and how
|
// LastValidProgress[1] takes you back to lane 1 and how
|
||||||
// the variables was set at that point
|
// the variables was set at that point
|
||||||
vector<_int> LastValidProgress; // When diving into a dynamic argument store store
|
vector<int> LastValidProgress; // When diving into a dynamic argument store store
|
||||||
// the last valid so you can go back to it
|
// the last valid so you can go back to it
|
||||||
vector<_int> LastValidArgCount; // If an alternative route turns out to fail, we
|
vector<int> LastValidArgCount; // If an alternative route turns out to fail, we
|
||||||
// need to know the amount of arguments on the last
|
// need to know the amount of arguments on the last
|
||||||
// valid position, so we can remove them.
|
// valid position, so we can remove them.
|
||||||
vector<_bool> LastValidMatch; // Match at that point
|
vector<bool> LastValidMatch; // Match at that point
|
||||||
_bool BlockAltNode = false; // If this turns true, the alternative route
|
bool BlockAltNode = false; // If this turns true, the alternative route
|
||||||
// tested was not a success, and the settings
|
// tested was not a success, and the settings
|
||||||
// should be set back in order to test the
|
// should be set back in order to test the
|
||||||
// next node instead
|
// next node instead
|
||||||
_bool LookNoFurther = false; // If this turns true, it means a definite match has been
|
bool LookNoFurther = false; // If this turns true, it means a definite match has been
|
||||||
// found and no further looking is required
|
// found and no further looking is required
|
||||||
CParserTaskTypeNode *CurNode=NULL; // Current node on task type
|
CParserTaskTypeNode *CurNode=NULL; // Current node on task type
|
||||||
CParserTaskTypeNode *PrevNode=NULL; // Last node
|
CParserTaskTypeNode *PrevNode=NULL; // Last node
|
||||||
@ -626,7 +626,7 @@ _bool CParserLine::ParseString(const CParser& Parser, string strLine)
|
|||||||
{
|
{
|
||||||
// Store argument in CParserValue!
|
// Store argument in CParserValue!
|
||||||
CParserValue value;
|
CParserValue value;
|
||||||
_int i;
|
int i;
|
||||||
|
|
||||||
switch(CurNode->m_Type)
|
switch(CurNode->m_Type)
|
||||||
{
|
{
|
||||||
@ -754,7 +754,7 @@ _bool CParserLine::ParseString(const CParser& Parser, string strLine)
|
|||||||
// if _minus is found as argument, remove it and add "-" to the one after that
|
// if _minus is found as argument, remove it and add "-" to the one after that
|
||||||
// note, it's easier if std::iterator isn't used here
|
// note, it's easier if std::iterator isn't used here
|
||||||
|
|
||||||
for (i=1; i<GetArgCount(); ++i)
|
for (i=1; i<(int)GetArgCount(); ++i)
|
||||||
{
|
{
|
||||||
if (m_Arguments[i-1].m_String == "_minus")
|
if (m_Arguments[i-1].m_String == "_minus")
|
||||||
{
|
{
|
||||||
@ -793,18 +793,18 @@ CParser::~CParser()
|
|||||||
// A task-type is a string representing the acquired syntax when parsing
|
// A task-type is a string representing the acquired syntax when parsing
|
||||||
// This function converts that string into a binary tree, making it easier
|
// This function converts that string into a binary tree, making it easier
|
||||||
// and faster to later parse.
|
// and faster to later parse.
|
||||||
_bool CParser::InputTaskType(const string& strName, const string& strSyntax)
|
bool CParser::InputTaskType(const string& strName, const string& strSyntax)
|
||||||
{
|
{
|
||||||
// Locals
|
// Locals
|
||||||
CParserTaskType TaskType; // Object we acquire to create
|
CParserTaskType TaskType; // Object we acquire to create
|
||||||
_char Buffer[REGULAR_MAX_LENGTH];
|
char Buffer[REGULAR_MAX_LENGTH];
|
||||||
_int ExtractPos = 0;
|
size_t ExtractPos = 0;
|
||||||
_bool Extract = false;
|
bool Extract = false;
|
||||||
_bool Error = false;
|
bool Error = false;
|
||||||
_int i;
|
int i;
|
||||||
_bool ConstructNew = false; // If it's the first input, then don't
|
bool ConstructNew = false; // If it's the first input, then don't
|
||||||
// construct a new node, because we
|
// construct a new node, because we
|
||||||
// we already have m_BaseNode
|
// we already have m_BaseNode
|
||||||
|
|
||||||
// Construct base node
|
// Construct base node
|
||||||
TaskType.m_BaseNode = new CParserTaskTypeNode();
|
TaskType.m_BaseNode = new CParserTaskTypeNode();
|
||||||
@ -837,7 +837,7 @@ _bool CParser::InputTaskType(const string& strName, const string& strSyntax)
|
|||||||
CurNode->m_AltNode->m_ParentNode = CurNode;
|
CurNode->m_AltNode->m_ParentNode = CurNode;
|
||||||
|
|
||||||
// It's repeatable
|
// It's repeatable
|
||||||
CurNode->m_AltNodeRepeatable = _bool(strSyntax[i]==START_DYNAMIC);
|
CurNode->m_AltNodeRepeatable = bool(strSyntax[i]==START_DYNAMIC);
|
||||||
|
|
||||||
// Set to current
|
// Set to current
|
||||||
CurNode = CurNode->m_AltNode;
|
CurNode = CurNode->m_AltNode;
|
||||||
@ -974,7 +974,7 @@ _bool CParser::InputTaskType(const string& strName, const string& strSyntax)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now try finding the second ')'
|
// Now try finding the second ')'
|
||||||
_int Pos = strSyntax.find(")", ExtractPos+5);
|
size_t Pos = strSyntax.find(")", ExtractPos+5);
|
||||||
|
|
||||||
// Check if ')' exists at all
|
// Check if ')' exists at all
|
||||||
if (Pos == string::npos)
|
if (Pos == string::npos)
|
||||||
|
Loading…
Reference in New Issue
Block a user