fteqw/engine/common/fs_win32.c
Spoike bae63427a5 Desperate attempt to boost framerates with webgl.
Models now use static vbos, because we ought to. Yeah yeah, extra memory usage etc.
Reduced size of streamed ebo by reallocating on each mesh. Hopefully the browser won't scan so much memory now.
Reordered attribute indicies in an attempt to comply with possible absurd gl behaviour that emscripten warns about.
Fixed an issue with if statements in shaders.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4289 fc73d0e0-1445-4013-8a0c-d673dee63da5
2013-04-06 03:36:00 +00:00

337 lines
8.5 KiB
C

#include "quakedef.h"
#include "fs.h"
#include <windows.h>
#ifndef INVALID_SET_FILE_POINTER
#define INVALID_SET_FILE_POINTER ~0
#endif
//read-only memory mapped files.
//for write access, we use the stdio module as a fallback.
#define VFSW32_Open VFSOS_Open
#define w32filefuncs osfilefuncs
typedef struct {
searchpathfuncs_t funcs;
HANDLE changenotification;
int hashdepth;
char rootpath[1];
} vfsw32path_t;
typedef struct {
vfsfile_t funcs;
HANDLE hand;
HANDLE mmh;
void *mmap;
unsigned int length;
unsigned int offset;
} vfsw32file_t;
static int VFSW32_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestoread)
{
DWORD read;
vfsw32file_t *intfile = (vfsw32file_t*)file;
if (intfile->mmap)
{
if (intfile->offset+bytestoread > intfile->length)
bytestoread = intfile->length-intfile->offset;
memcpy(buffer, (char*)intfile->mmap + intfile->offset, bytestoread);
intfile->offset += bytestoread;
return bytestoread;
}
if (!ReadFile(intfile->hand, buffer, bytestoread, &read, NULL))
return 0;
return read;
}
static int VFSW32_WriteBytes (struct vfsfile_s *file, const void *buffer, int bytestoread)
{
DWORD written;
vfsw32file_t *intfile = (vfsw32file_t*)file;
if (intfile->mmap)
{
if (intfile->offset+bytestoread > intfile->length)
bytestoread = intfile->length-intfile->offset;
memcpy((char*)intfile->mmap + intfile->offset, buffer, bytestoread);
intfile->offset += bytestoread;
return bytestoread;
}
if (!WriteFile(intfile->hand, buffer, bytestoread, &written, NULL))
return 0;
return written;
}
static qboolean VFSW32_Seek (struct vfsfile_s *file, unsigned long pos)
{
unsigned long upper, lower;
vfsw32file_t *intfile = (vfsw32file_t*)file;
if (intfile->mmap)
{
intfile->offset = pos;
return true;
}
lower = (pos & 0xffffffff);
upper = ((pos>>16)>>16);
return SetFilePointer(intfile->hand, lower, &upper, FILE_BEGIN) != INVALID_SET_FILE_POINTER;
}
static unsigned long VFSW32_Tell (struct vfsfile_s *file)
{
vfsw32file_t *intfile = (vfsw32file_t*)file;
if (intfile->mmap)
return intfile->offset;
return SetFilePointer(intfile->hand, 0, NULL, FILE_CURRENT);
}
static void VFSW32_Flush(struct vfsfile_s *file)
{
vfsw32file_t *intfile = (vfsw32file_t*)file;
if (intfile->mmap)
FlushViewOfFile(intfile->mmap, intfile->length);
FlushFileBuffers(intfile->hand);
}
static unsigned long VFSW32_GetSize (struct vfsfile_s *file)
{
vfsw32file_t *intfile = (vfsw32file_t*)file;
if (intfile->mmap)
return intfile->length;
return GetFileSize(intfile->hand, NULL);
}
static void VFSW32_Close(vfsfile_t *file)
{
vfsw32file_t *intfile = (vfsw32file_t*)file;
if (intfile->mmap)
{
UnmapViewOfFile(intfile->mmap);
CloseHandle(intfile->mmh);
}
CloseHandle(intfile->hand);
Z_Free(file);
COM_FlushFSCache();
}
vfsfile_t *VFSW32_Open(const char *osname, const char *mode)
{
HANDLE h, mh;
unsigned int fsize;
void *mmap;
vfsw32file_t *file;
qboolean read = !!strchr(mode, 'r');
qboolean write = !!strchr(mode, 'w');
qboolean append = !!strchr(mode, 'a');
qboolean text = !!strchr(mode, 't');
write |= append;
if (strchr(mode, '+'))
read = write = true;
if ((write && read) || append)
h = CreateFileA(osname, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
else if (write)
h = CreateFileA(osname, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
else if (read)
h = CreateFileA(osname, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
else
h = INVALID_HANDLE_VALUE;
if (h == INVALID_HANDLE_VALUE)
return NULL;
if (write || append || text)
{
fsize = 0;
mh = INVALID_HANDLE_VALUE;
mmap = NULL;
/*if appending, set the access position to the end of the file*/
if (append)
SetFilePointer(h, 0, NULL, FILE_END);
}
else
{
fsize = GetFileSize(h, NULL);
mh = CreateFileMapping(h, NULL, PAGE_READONLY, 0, 0, NULL);
if (mh == INVALID_HANDLE_VALUE)
mmap = NULL;
else
{
mmap = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, fsize);
if (mmap == NULL)
{
CloseHandle(mh);
mh = INVALID_HANDLE_VALUE;
}
}
}
file = Z_Malloc(sizeof(vfsw32file_t));
#ifdef _DEBUG
Q_strncpyz(file->funcs.dbgname, osname, sizeof(file->funcs.dbgname));
#endif
file->funcs.ReadBytes = read?VFSW32_ReadBytes:NULL;
file->funcs.WriteBytes = (write||append)?VFSW32_WriteBytes:NULL;
file->funcs.Seek = VFSW32_Seek;
file->funcs.Tell = VFSW32_Tell;
file->funcs.GetLen = VFSW32_GetSize;
file->funcs.Close = VFSW32_Close;
file->funcs.Flush = VFSW32_Flush;
file->hand = h;
file->mmh = mh;
file->mmap = mmap;
file->offset = 0;
file->length = fsize;
return (vfsfile_t*)file;
}
static vfsfile_t *VFSW32_OpenVFS(void *handle, flocation_t *loc, const char *mode)
{
//path is already cleaned, as anything that gets a valid loc needs cleaning up first.
return VFSW32_Open(loc->rawname, mode);
}
static void VFSW32_GetDisplayPath(void *handle, char *out, unsigned int outlen)
{
vfsw32path_t *wp = handle;
Q_strncpyz(out, wp->rootpath, outlen);
}
static void VFSW32_ClosePath(void *handle)
{
vfsw32path_t *wp = handle;
if (wp->changenotification != INVALID_HANDLE_VALUE)
FindCloseChangeNotification(wp->changenotification);
Z_Free(wp);
}
static qboolean VFSW32_PollChanges(void *handle)
{
qboolean result = false;
vfsw32path_t *wp = handle;
if (wp->changenotification == INVALID_HANDLE_VALUE)
return true;
for(;;)
{
switch(WaitForSingleObject(wp->changenotification, 0))
{
case WAIT_OBJECT_0:
result = true;
break;
case WAIT_TIMEOUT:
return result;
default:
FindCloseChangeNotification(wp->changenotification);
wp->changenotification = INVALID_HANDLE_VALUE;
return true;
}
FindNextChangeNotification(wp->changenotification);
}
return result;
}
static void *VFSW32_OpenPath(vfsfile_t *mustbenull, const char *desc)
{
vfsw32path_t *np;
int dlen = strlen(desc);
if (mustbenull)
return NULL;
np = Z_Malloc(sizeof(*np) + dlen);
if (np)
{
memcpy(np->rootpath, desc, dlen+1);
np->changenotification = FindFirstChangeNotification(np->rootpath, true, FILE_NOTIFY_CHANGE_FILE_NAME);
}
return np;
}
static int VFSW32_RebuildFSHash(const char *filename, int filesize, void *handle, void *spath)
{
vfsw32path_t *wp = handle;
if (filename[strlen(filename)-1] == '/')
{ //this is actually a directory
char childpath[256];
Q_snprintfz(childpath, sizeof(childpath), "%s*", filename);
Sys_EnumerateFiles(wp->rootpath, childpath, VFSW32_RebuildFSHash, wp, handle);
return true;
}
FS_AddFileHash(wp->hashdepth, filename, NULL, wp);
return true;
}
static void VFSW32_BuildHash(void *handle, int hashdepth)
{
vfsw32path_t *wp = handle;
wp->hashdepth = hashdepth;
Sys_EnumerateFiles(wp->rootpath, "*", VFSW32_RebuildFSHash, handle, handle);
}
static qboolean VFSW32_FLocate(void *handle, flocation_t *loc, const char *filename, void *hashedresult)
{
vfsw32path_t *wp = handle;
FILE *f;
int len;
char netpath[MAX_OSPATH];
if (hashedresult && (void *)hashedresult != wp)
return false;
/*
if (!static_registered)
{ // if not a registered version, don't ever go beyond base
if ( strchr (filename, '/') || strchr (filename,'\\'))
continue;
}
*/
// check a file in the directory tree
snprintf (netpath, sizeof(netpath)-1, "%s/%s", wp->rootpath, filename);
f = fopen(netpath, "rb");
if (!f)
return false;
fseek(f, 0, SEEK_END);
len = ftell(f);
fclose(f);
if (loc)
{
loc->len = len;
loc->offset = 0;
loc->index = 0;
snprintf(loc->rawname, sizeof(loc->rawname), "%s/%s", wp->rootpath, filename);
}
return true;
}
static void VFSW32_ReadFile(void *handle, flocation_t *loc, char *buffer)
{
// vfsw32path_t *wp = handle;
FILE *f;
f = fopen(loc->rawname, "rb");
if (!f) //err...
return;
fseek(f, loc->offset, SEEK_SET);
fread(buffer, 1, loc->len, f);
fclose(f);
}
static int VFSW32_EnumerateFiles (void *handle, const char *match, int (*func)(const char *, int, void *, void *spath), void *parm)
{
vfsw32path_t *wp = handle;
return Sys_EnumerateFiles(wp->rootpath, match, func, parm, handle);
}
searchpathfuncs_t w32filefuncs = {
VFSW32_GetDisplayPath,
VFSW32_ClosePath,
VFSW32_BuildHash,
VFSW32_FLocate,
VFSW32_ReadFile,
VFSW32_EnumerateFiles,
VFSW32_OpenPath,
NULL,
VFSW32_OpenVFS,
VFSW32_PollChanges
};