1
0
forked from 0ad/0ad

no message

This was SVN commit r53.
This commit is contained in:
janwas 2003-11-12 14:47:38 +00:00
parent d963d9c046
commit 40ca60014c
21 changed files with 629 additions and 871 deletions

View File

@ -57,6 +57,8 @@ void get_cur_resolution(int& xres, int& yres)
size_t tot_mem = 0;
size_t avl_mem = 0;
size_t page_size = 0;
void get_mem_status()
{
// Win32
@ -68,10 +70,19 @@ void get_mem_status()
// fixes results for my machine - off by 528 KB. why?!
avl_mem = ms.dwAvailPhys;
// Sys V derived (GNU/Linux, Solaris)
#elif defined(_SC_PAGESIZE) && defined(_SC_AVPHYS_PAGES)
SYSTEM_INFO si;
GetSystemInfo(&si);
page_size = si.dwPageSize;
#else // !_WIN32
#ifdef _SC_PAGESIZE
page_size = (size_t)sysconf(_SC_PAGESIZE);
#endif
// Sys V derived (GNU/Linux, Solaris)
#ifdef _SC_AVPHYS_PAGES
long page_size = sysconf(_SC_PAGESIZE);
tot_mem = sysconf(_SC_PHYS_PAGES ) * page_size;
avl_mem = sysconf(_SC_AVPHYS_PAGES) * page_size;
@ -85,6 +96,8 @@ void get_mem_status()
sysctl(mib, 2, &avl_mem, &len, 0, 0);
#endif
#endif // _WIN32
}

View File

@ -25,6 +25,7 @@
#include "font.h"
#include "res.h"
#include "vfs.h"
#include "tex.h"
#include "ogl.h"
#include "posix.h"
@ -126,13 +127,21 @@ static void font_dtor(void* p)
}
u32 font_load(const char* fn)
Handle font_load(const char* fn)
{
const u32 fn_hash = fnv_hash(fn, strlen(fn));
FONT* font;
Handle h = h_alloc(fn_hash, H_FONT, font_dtor, (void**)&font);
if(!h)
return 0;
if(font->tex)
return h;
void* p;
size_t size;
HDATA* hd;
Handle h = res_load(fn, H_FONT, font_dtor, p, size, hd);
if(!h)
Handle hm = vfs_load(fn, p, size);
if(!hm)
return 0;
int pos; // current position in the file
@ -159,6 +168,8 @@ u32 font_load(const char* fn)
}
}
h_free(hm, H_MEM);
// load glyph texture
const Handle tex = tex_load(tex_filename);
if(!tex)
@ -191,7 +202,6 @@ u32 font_load(const char* fn)
u = 0.f, v += th;
}
FONT* font = (FONT*)hd->user;
font->tex = tex;
font->list_base = list_base;
@ -201,10 +211,9 @@ u32 font_load(const char* fn)
int font_bind(const Handle h)
{
HDATA* hd = h_data(h, H_FONT);
if(!hd)
FONT* font = (FONT*)h_user_data(h, H_FONT);
if(!font)
return -1;
FONT* font = (FONT*)hd->user;
tex_bind(font->tex);
glListBase(font->list_base);

View File

@ -1,6 +1,7 @@
// malloc layer for less fragmentation, alignment, and automatic release
#include <cstdlib>
#include <cassert>
#include <map>
@ -11,58 +12,43 @@
#include "posix.h"
struct MEM
static void heap_free(MEM* m)
{
uint type;
// MEM_HEAP only
void* org_p;
// MEM_POOL only
size_t ofs;
size_t size;
};
static void heap_dtor(void* p)
{
MEM* mem = (MEM*)p;
free(mem->org_p);
free(m->org_p);
}
static void* heap_alloc(const size_t size, const int align, MEM& mem)
static void* heap_alloc(const size_t size, const int align, MEM* mem)
{
u8* org_p = (u8*)malloc(size+align-1);
u8* p = (u8*)round_up((long)org_p, align);
mem.org_p = org_p;
mem->org_p = org_p;
return p;
}
//////////////////////////////////////////////////////////////////////////////
static u8* pool;
static size_t pool_pos;
static const size_t POOL_CAP = 64*MB; // TODO: user editable
static void pool_dtor(void* p)
static void pool_free(MEM* m)
{
MEM* mem = (MEM*)p;
// at end of pool? if so, 'free' it
if(mem->ofs + mem->size == pool_pos)
pool_pos -= mem->size;
if(m->ofs + m->size == pool_pos)
pool_pos -= m->size;
}
static void* pool_alloc(const size_t size, const uint align, MEM& mem)
static void* pool_alloc(const size_t size, const uint align, MEM* mem)
{
if(!pool)
{
pool = (u8*)mem_alloc(size, MEM_HEAP, align);
pool = (u8*)mem_alloc(size, align, MEM_HEAP);
if(!pool)
return 0;
}
@ -73,52 +59,47 @@ static void* pool_alloc(const size_t size, const uint align, MEM& mem)
void* p = (u8*)pool + ofs;
mem.size = size;
mem.ofs = ofs;
mem->size = size;
mem->ofs = ofs;
pool_pos = ofs+size;
return p;
}
//////////////////////////////////////////////////////////////////////////////
static void mem_dtor(void* p)
static void mmap_free(MEM* m)
{
MEM* mem = (MEM*)p;
if(mem->type == MEM_HEAP)
heap_dtor(p);
else if(mem->type == MEM_POOL)
pool_dtor(p);
munmap(m->p, m->size);
}
void* mem_alloc(size_t size, const MemType type, const uint align, Handle* ph)
static void* mmap_alloc(const size_t size, const int fd, MEM* mem)
{
if(size == 0)
size = 1;
mem->p = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0);
mem->size = size;
mem->fd = fd;
HDATA* hd;
Handle h = h_alloc(0, H_MEM, mem_dtor, &hd);
if(!h)
return 0;
return mem->p;
}
MEM& mem = (MEM&)hd->user;
void* p;
if(type == MEM_HEAP)
p = heap_alloc(size, align, mem);
else if(type == MEM_POOL)
p = pool_alloc(size, align, mem);
//////////////////////////////////////////////////////////////////////////////
static void mem_dtor(void* p)
{
MEM* m = (MEM*)p;
if(m->type == MEM_HEAP)
heap_free(m);
else if(m->type == MEM_POOL)
pool_free(m);
else if(m->type == MEM_MAPPED)
mmap_free(m);
else
{
h_free(h, H_MEM);
return 0;
}
if(ph)
*ph = h;
return p;
assert(0 && "mem_dtor: MEM.type invalid!");
}
@ -127,9 +108,60 @@ int mem_free(void* p)
if(!p)
return 1;
HDATA* hd;
Handle h = h_find(p, H_MEM, &hd);
Handle h = h_find((u32)p, H_MEM, 0);
if(h)
return h_free(h, H_MEM);
return -1;
}
int mem_free(Handle hm)
{
return h_free(hm, H_MEM);
}
void* mem_alloc(size_t size, const uint align, const MemType type, const int fd, Handle* ph)
{
assert(size != 0 && "mem_alloc: why is size = 0?");
// bit of a hack: the allocators require space for bookkeeping,
// but we can't allocate a handle until we know the key
// (the pointer address), which is used to find the corresponding
// handle when freeing memory.
// we fill a temp MEM, and then copy it into the handle's user data space
MEM mem;
void* p;
if(type == MEM_HEAP)
p = heap_alloc(size, align, &mem);
else if(type == MEM_POOL)
p = pool_alloc(size, align, &mem);
else if(type == MEM_MAPPED)
p = mmap_alloc(size, fd, &mem);
else
{
assert(0 && "mem_alloc: invalid type parameter");
return 0;
}
if(!p)
return 0;
MEM* pmem;
Handle h = h_alloc((u32)p, H_MEM, mem_dtor, (void**)&pmem);
if(!h) // failed to allocate a handle
{
mem_dtor(&mem);
return 0;
}
*pmem = mem; // copy our memory info into the handle's user data space
// caller is asking for the handle
// (freeing the memory via handle is faster than mem_free, because
// we wouldn't have to scan all handles looking for the pointer)
if(ph)
*ph = h;
return p;
}

View File

@ -3,13 +3,36 @@
#include "res.h"
// include memory mappings because the VFS may return either a chunk of
// memory, or the mapped file, and a client doesn't know the difference.
enum MemType
{
MEM_POOL,
MEM_HEAP
MEM_HEAP,
MEM_MAPPED
};
extern void* mem_alloc(size_t size, MemType type = MEM_HEAP, uint align = 1, Handle* ph = 0);
struct MEM
{
void* p;
size_t size;
MemType type;
union
{
size_t ofs; // MEM_POOL only
void* org_p; // MEM_HEAP only
int fd; // MEM_MAPPED only
};
};
extern void* mem_alloc(size_t size, uint align = 1, MemType type = MEM_HEAP, int fd = -1, Handle* ph = 0);
extern int mem_free(void* p);
// faster than mem_free(void*) - no scan of open handles for the pointer
extern int mem_free(Handle hm);
#endif // #ifndef __MEM_H__

View File

@ -477,7 +477,6 @@ int uname(struct utsname* un)
// hardware type
static SYSTEM_INFO si;
GetSystemInfo(&si);
if(si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
strcpy(un->machine, "AMD64");
else

View File

@ -22,13 +22,39 @@
#include <cstdio>
#include "types.h"
#include "unzip.h"
#include "zip.h"
#include "posix.h"
#include "misc.h"
#include "res.h"
#include "mem.h"
#include "vfs.h"
// handle (32 bits)
// .. make sure this is the same handle we opened
const uint HTAG_BITS = 16;
// .. index into array => = log2(max open handles)
const uint HIDX_BITS = 12;
// together, <= 32-TAG_BITS bits
const uint HTYPE_BITS = 4;
const uint HREF_BITS = 8;
const int HDATA_USER_SIZE = 20;
// 32 bytes
struct HDATA
{
u32 key;
u32 tag : HTAG_BITS;
u32 type : HTYPE_BITS; // handle's type (e.g. texture, sound)
u32 refs : HREF_BITS;
u32 unused; // TODO: type pointer?
u8 user[HDATA_USER_SIZE];
};
static const ulong hdata_cap = 1ul << HIDX_BITS;
static const uint type_cap = 1ul << HTYPE_BITS;
@ -70,7 +96,7 @@ static int h_idx(const Handle h, const uint type)
return -1;
const HDATA* hd = h_data(idx);
// cannot fail - it was successfully allocated
// cannot fail - all HDATA up to last_in_use are valid
const u32 tag = h >> HIDX_BITS;
// note: tag = 0 marks unused entries => is invalid
@ -101,17 +127,7 @@ static int h_free(const int idx)
if(--hd->refs)
return 0;
// free its pointer
switch(hd->ptype)
{
case PT_MEM:
mem_free(hd->p);
break;
case PT_MAP:
munmap(hd->p, hd->size);
break;
}
// TODO: keep this handle open (cache)
// call its type's destructor
if(dtors[hd->type])
@ -143,25 +159,7 @@ static void cleanup(void)
}
Handle h_find(const void* p, uint type, HDATA** puser)
{
for(int idx = 0; idx <= last_in_use; idx++)
{
HDATA* hd = h_data(idx); // guaranteed valid
if(hd->p == p && hd->type == type)
{
if(puser)
*puser = hd/*->user*/;
return handle(idx);
}
}
return 0;
}
Handle h_find(const u32 key, uint type, HDATA** puser)
Handle h_find(const u32 key, uint type, void** puser)
{
int idx;
HDATA* hd;
@ -195,32 +193,12 @@ Handle h_find(const u32 key, uint type, HDATA** puser)
found:
Handle h = handle(idx);
if(puser)
*puser = hd/*->user*/;
*puser = hd->user;
return h;
}
int h_assign(Handle h, u8* p, size_t size, bool mem)
{
HDATA* hd = h_data(h);
if(!hd)
return -1;
if(hd->p || hd->size || hd->ptype != PT_NONE)
{
assert(!"h_assign: field(s) already assigned");
return -1;
}
hd->p = p;
hd->size = size;
hd->ptype = mem? PT_MEM : PT_MAP;
return 0;
}
Handle h_alloc(const u32 key, const uint type, /*const size_t user_size,*/ DTOR dtor, HDATA** puser)
Handle h_alloc(const u32 key, const uint type, /*const size_t user_size,*/ H_DTOR dtor, void** puser)
{
ONCE(atexit(cleanup))
/*
@ -253,11 +231,10 @@ Handle h_alloc(const u32 key, const uint type, /*const size_t user_size,*/ DTOR
if(key)
{
// object already loaded?
Handle h = h_find(key, type, &hd);
Handle h = h_find(key, type, 0);
if(h)
{
// only way to decide whether this handle is new, or a reference
assert(hd->size != 0);
hd = h_data(h_idx(h, type));
if(hd->refs == (1ul << HREF_BITS))
{
@ -320,14 +297,15 @@ Handle h_alloc(const u32 key, const uint type, /*const size_t user_size,*/ DTOR
hd->type = type;
if(puser)
*puser = hd/*->user*/;
*puser = hd->user;
return handle(idx);
}
int h_free(const Handle h, const uint type)
int h_free(Handle& h, const uint type)
{
int idx = h_idx(h, type);
h = 0;
if(idx >= 0)
return h_free(idx);
return -1;
@ -335,52 +313,14 @@ int h_free(const Handle h, const uint type)
HDATA* h_data(const Handle h, const uint type)
void* h_user_data(const Handle h, const uint type)
{
int idx = h_idx(h, type);
if(idx >= 0)
return h_data(idx);
return h_data(idx)->user; // pointer is always valid if index is in range
return 0;
}
Handle res_load(const char* fn, uint type, DTOR dtor, void*& p, size_t& size, HDATA*& user)
{
p = 0;
size = 0;
user = 0;
u32 fn_hash = fnv_hash(fn, strlen(fn));
// TODO: fn is usually a constant; pass fn len if too slow
HDATA* hd;
Handle h = h_alloc(fn_hash, type, dtor, &hd);
if(!h)
return 0;
// already open - return a reference
if(hd->size)
return h;
Handle hf = vfs_open(fn);
int err = vfs_read(hf, p, size, 0);
vfs_close(hf);
if(err < 0)
return 0;
if(!p)
{
h_free(h, type);
return 0;
}
hd->p = p;
hd->size = size;
user=hd;
return h;
}

View File

@ -21,16 +21,10 @@
#include "types.h"
// the following are internal to the resource manager,
// but are required for the HDATA definition
// (which is passed around to modules that create handles).
// we don't want to waste memory or fragment the handle data
// by splitting into internal/external
// handle type (for 'type safety' - can't use a texture handle as a sound)
//
// rationale: we could use the destructor passed to res_load to identify
// rationale: we could use the destructor passed to h_alloc to identify
// the handle, but it's good to have a list of all types, and we avoid having
// to create empty destructors for handle types that wouldn't need them.
// finally, we save memory - this fits in a few bits, vs. needing a pointer.
@ -47,41 +41,7 @@ enum HType
NUM_HANDLE_TYPES
};
// handle's pointer type
enum PType
{
PT_NONE,
PT_MEM, // allocated by mem_alloc
PT_MAP // mapped by mmap
};
// handle (32 bits)
// .. make sure this is the same handle we opened
const uint HTAG_BITS = 16;
// .. index into array => = log2(max open handles)
const uint HIDX_BITS = 12;
// <= 32-TAG_BITS bits
const uint HTYPE_BITS = 4;
const uint PTYPE_BITS = 4;
const uint HREF_BITS = 8;
const int HDATA_USER_SIZE = 16;
// 32 bytes
struct HDATA
{
u32 key;
u32 tag : HTAG_BITS;
u32 type : HTYPE_BITS; // handle's type (e.g. texture, sound)
u32 ptype : PTYPE_BITS; // what does p point to?
u32 refs : HREF_BITS;
void* p;
size_t size;
u8 user[HDATA_USER_SIZE];
};
// 0 = invalid handle value.
@ -90,7 +50,7 @@ typedef u32 Handle;
// destructor, registered by h_alloc for a given handle type.
// receives the user data associated with the handle.
typedef void(*DTOR)(void*);
typedef void(*H_DTOR)(void*);
// all functions check the passed tag (part of the handle) and type against
@ -105,20 +65,15 @@ typedef void(*DTOR)(void*);
//// user_size is checked to make sure the user data fits in the handle data space.
// dtor is associated with type and called when the object is freed.
// handle data is initialized to 0; optionally, a pointer to it is returned.
extern Handle h_alloc(u32 key, uint type,/* size_t user_size,*/ DTOR dtor = 0, HDATA** puser = 0);
extern int h_free(Handle h, uint type);
extern Handle h_alloc(u32 key, uint type,/* size_t user_size,*/ H_DTOR dtor = 0, void** puser = 0);
extern int h_free(Handle& h, uint type);
// find and return a handle by type and key (typically filename hash)
// currently O(n).
extern Handle h_find(u32 key, uint type, HDATA** puser = 0);
// same as above, but search for the handle's associated pointer
extern Handle h_find(const void* p, uint type, HDATA** puser = 0);
extern Handle h_find(u32 key, uint type, void** puser = 0);
// return a pointer to handle data
extern HDATA* h_data(Handle h, uint type);
extern Handle res_load(const char* fn, uint type, DTOR dtor, void*& p, size_t& size, HDATA*& user);
extern void* h_user_data(Handle h, uint type);
#endif // #ifndef __RES_H__

View File

@ -21,8 +21,11 @@
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include "vfs.h"
#include "tex.h"
#include "mem.h"
#include "ogl.h"
#include "res.h"
#include "misc.h"
@ -134,8 +137,6 @@ static int dds_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
const u32 img_size = read_le32(&surf->dwLinearSize);
const u32 mipmaps = read_le32(&surf->dwMipMapCount);
const u8* img = ptr + hdr_size;
uint fmt = 0;
switch(surf->ddpfPixelFormat.dwFourCC) // endian-independent
{
@ -154,7 +155,7 @@ static int dds_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
tex->height = h;
tex->fmt = fmt;
tex->bpp = img_size / (w * h);
tex->ptr = img;
tex->ofs = hdr_size;
if(sizeof(DDSURFACEDESC2) != ddsd_size)
err = "DDSURFACEDESC2 size mismatch";
@ -214,7 +215,6 @@ static int tga_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
const u8 alpha_bits = desc & 0x0f;
const u8* img = ptr + hdr_size;
const ulong img_size = (ulong)w * h * bpp / 8;
// determine format
@ -240,7 +240,7 @@ static int tga_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
tex->height = h;
tex->fmt = fmt;
tex->bpp = bpp;
tex->ptr = img;
tex->ofs = hdr_size;
if(fmt == -1)
err = "invalid format or bpp";
@ -323,14 +323,13 @@ static int bmp_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
const u32 compress = read_le32(&bch->biCompression);
const u32 ofs = read_le32(&bfh->bfOffBits);
const u8* img = ptr + ofs;
const u32 img_size = w * h * bpp/8;
tex->width = w;
tex->height = h;
tex->fmt = (bpp == 24)? GL_BGR : GL_BGRA;
tex->bpp = bpp;
tex->ptr = img;
tex->ofs = ofs;
if(h < 0)
err = "top-down";
@ -386,7 +385,7 @@ static int raw_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
tex->height = dim;
tex->fmt = fmts[i];
tex->bpp = i * 8;
tex->ptr = ptr;
tex->ofs = 0;
return 0;
}
@ -591,28 +590,38 @@ static int jp2_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
static void tex_dtor(void* p)
{
TEX* tex = (TEX*)p;
mem_free(tex->hm);
glDeleteTextures(1, &tex->id);
}
// TEX output param is invalid if function fails
Handle tex_load(const char* fn, TEX* ptex)
{
const u32 fn_hash = fnv_hash(fn, strlen(fn));
TEX* tex;
Handle ht = h_alloc(fn_hash, H_TEX, tex_dtor, (void**)&tex);
if(!ht)
return 0;
if(tex->id != 0)
goto already_loaded;
{
// load file
const u8* p;
size_t size;
HDATA* hd;
Handle h = res_load(fn, H_TEX, tex_dtor, (void*&)p, size, hd);
if(!h)
return 0;
TEX* tex = (TEX*)hd->user;
if(!p)
goto already_loaded;
if(size < 4) // guarantee xxx_valid routines 4 bytes
return 0;
Handle hm = vfs_load(fn, (void*&)p, size);
// .. note: xxx_valid routines assume 4 header bytes are available
if(!hm || !p || size < 4)
{
h_free(ht, H_TEX);
return 0;
}
tex->hm = hm;
int err = -1;
#ifndef NO_DDS
@ -643,7 +652,6 @@ Handle tex_load(const char* fn, TEX* ptex)
if(err < 0)
return err;
}
// loaders weren't able to determine type
if(tex->fmt == 0)
@ -653,43 +661,45 @@ Handle tex_load(const char* fn, TEX* ptex)
// TODO: check file name, go to 32 bit if wrong
}
{
uint id;
glGenTextures(1, &id);
tex->id = id;
}
// this can't realistically fail, just note that the already_loaded
// check above assumes (id > 0) <==> texture is loaded and valid
}
already_loaded:
if(ptex)
*ptex = *tex;
return h;
return ht;
}
int tex_bind(const Handle h)
{
HDATA* hd = h_data(h, H_TEX);
if(!hd)
TEX* tex = (TEX*)h_user_data(h, H_TEX);
if(!tex)
{
glBindTexture(GL_TEXTURE_2D, 0);
return -1;
}
TEX* tex = (TEX*)hd->user;
glBindTexture(GL_TEXTURE_2D, tex->id);
return 0;
else
{
glBindTexture(GL_TEXTURE_2D, tex->id);
return 0;
}
}
int tex_filter = GL_LINEAR;
uint tex_bpp = 32; // 16 or 32
int tex_upload(const Handle h, int filter, int int_fmt)
int tex_upload(const Handle ht, int filter, int int_fmt)
{
HDATA* hd = h_data(h, H_TEX);
if(!hd)
TEX* tex = (TEX*)h_user_data(ht, H_TEX);
if(!tex)
return -1;
TEX* tex = (TEX*)hd->user;
// greater than max supported tex dimension?
// no-op if oglInit not yet called
@ -708,7 +718,18 @@ int tex_upload(const Handle h, int filter, int int_fmt)
return 0;
}
tex_bind(h);
tex_bind(ht);
// get pointer to image data
MEM* mem = (MEM*)h_user_data(tex->hm, H_MEM);
if(!mem)
return 0;
void* p = mem->p;
if(!p)
{
assert(0 && "tex_upload: mem object is a NULL pointer");
return 0;
}
// set filter
if(!filter)
@ -726,8 +747,9 @@ int tex_upload(const Handle h, int filter, int int_fmt)
if(tex->fmt >= GL_COMPRESSED_RGB_S3TC_DXT1_EXT &&
tex->fmt <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
{
int img_size = tex->width * tex->height * tex->bpp;
glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, tex->fmt, tex->width, tex->height, 0, img_size, tex->ptr);
const int img_size = tex->width * tex->height * tex->bpp;
assert(4+sizeof(DDSURFACEDESC2)+img_size == mem->size && "tex_upload: dds file size mismatch");
glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, tex->fmt, tex->width, tex->height, 0, img_size, p);
}
// normal
else
@ -756,16 +778,18 @@ int tex_upload(const Handle h, int filter, int int_fmt)
// manual mipmap gen via GLU (box filter)
if(mipmap && !sgm_avl)
gluBuild2DMipmaps(GL_TEXTURE_2D, int_fmt, tex->width, tex->height, tex->fmt, GL_UNSIGNED_BYTE, tex->ptr);
gluBuild2DMipmaps(GL_TEXTURE_2D, int_fmt, tex->width, tex->height, tex->fmt, GL_UNSIGNED_BYTE, p);
// auto mipmap gen, or no mipmap
else
{
if(mipmap)
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
glTexImage2D(GL_TEXTURE_2D, 0, int_fmt, tex->width, tex->height, 0, tex->fmt, GL_UNSIGNED_BYTE, tex->ptr);
glTexImage2D(GL_TEXTURE_2D, 0, int_fmt, tex->width, tex->height, 0, tex->fmt, GL_UNSIGNED_BYTE, p);
}
}
mem_free(tex->hm);
return 0;
}

View File

@ -29,7 +29,8 @@ struct TEX
u32 height : 16;
u32 fmt : 16;
u32 bpp : 16;
const u8* ptr;
Handle hm; // H_MEM handle to loaded file
size_t ofs; // WRT image data in file
uint id;
};

View File

@ -1,351 +0,0 @@
// ZIP archiving (on top of ZLib)
//
// Copyright (c) 2003 Jan Wassenberg
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// Contact info:
// Jan.Wassenberg@stud.uni-karlsruhe.de
// http://www.stud.uni-karlsruhe.de/~urkt/
#include <cassert>
#include <cstring>
#include <cstdlib>
#include <zlib.h>
#include "unzip.h"
#include "posix.h"
#include "misc.h"
#include "res.h"
#include "mem.h"
#include "vfs.h"
#ifdef _MSC_VER
#pragma comment(lib, "zlib.lib")
#endif
static const char ecdr_id[] = "PK\5\6"; // End of Central Directory Header identifier
static const char cdfh_id[] = "PK\1\2"; // Central File Header identifier
static const char lfh_id[] = "PK\3\4"; // Local File Header identifier
// H_ZFILE handle
// location and size of an archived file
// no destructor
struct ZFILE
{
u32 ofs;
u32 csize; // bit 31 = compression method (1: deflate; 0: stored)
u32 ucsize;
};
// H_ZARCHIVE handle
// information about a ZIP archive
struct ZARCHIVE
{
Handle hf; // actual ZIP file (H_VFILE)
// file lookup
u32 num_files;
u32* fn_hashs; // split for more efficient search
ZFILE* files;
u32 last_file; // index of last file we found (speed up lookups of sequential files)
};
static void zarchive_dtor(void* p)
{
ZARCHIVE* za = (ZARCHIVE*)p;
vfs_close(za->hf);
za->hf = 0;
}
// open and return a handle to the zip archive indicated by <fn>
Handle zopen(const char* const fn)
{
const u32 fn_hash = fnv_hash(fn, strlen(fn));
// already loaded?
HDATA* hd;
Handle h = h_find(fn_hash, H_ZFILE, &hd);
if(h)
return h;
// map the ZIP file
Handle hf = vfs_map(fn);
hd = h_data(hf, 0);
if(!hd)
return 0;
const size_t size = hd->size;
const u8* zfile = (const u8*)hd->p;
// find end of central dir record
// by scanning last 66000 bytes of file for ecdr_id magic
// (zip comment <= 65535 bytes, sizeof(ECDR) = 22, add some for safety)
// if the zip file is < 66000 bytes, scan the whole file
size_t bytes_left = min(size, 66000);
const u8* ecdr = zfile + size - bytes_left;
while(bytes_left-3 > 0)
{
if(*(u32*)ecdr == *(u32*)&ecdr_id)
goto found_ecdr;
// check next 4 bytes (non aligned!!)
ecdr++;
bytes_left--;
}
// reached EOF and still haven't found the ECDR identifier
fail:
vfs_close(hf);
return 0;
{
found_ecdr:
// read ECDR
const u16 num_files = read_le16(ecdr+10);
const u32 cd_ofs = read_le32(ecdr+16);
// memory for fn_hash and File arrays
void* mem = mem_alloc(num_files * (4 + sizeof(ZFILE)), MEM_HEAP, 4*KB);
if(!mem)
goto fail;
h = h_alloc(fn_hash, H_ZFILE, zarchive_dtor, &hd);
if(!h)
goto fail;
ZARCHIVE* const za = (ZARCHIVE*)hd->user;
za->hf = hf;
za->fn_hashs = (u32*)mem;
za->files = (ZFILE*)((u8*)mem + 4*num_files);
za->last_file = 0;
// cache file list for faster lookups
// currently linear search, comparing filename hash.
// TODO: if too slow, use hash table.
const u8* cdfh = zfile+cd_ofs;
u32* hs = za->fn_hashs;
ZFILE* f = za->files;
uint i;
for(i = 0; i < num_files; i++)
{
// read CDFH
if(*(u32*)cdfh != *(u32*)cdfh_id)
continue;
const u32 csize = read_le32(cdfh+20);
const u32 ucsize = read_le32(cdfh+24);
const u16 fn_len = read_le16(cdfh+28);
const u16 e_len = read_le16(cdfh+30);
const u16 c_len = read_le16(cdfh+32);
const u32 lfh_ofs = read_le32(cdfh+42);
const u8 method = cdfh[10];
if(method & ~8) // neither deflated nor stored
continue;
// read LFH
const u8* const lfh = zfile + lfh_ofs;
if(*(u32*)lfh != *(u32*)lfh_id)
continue;
const u16 lfh_fn_len = read_le16(lfh+26);
const u16 lfh_e_len = read_le16(lfh+28);
const char* lfh_fn = (const char*)lfh+30;
*hs++ = fnv_hash(lfh_fn, lfh_fn_len);
f->ofs = lfh_ofs + 30 + lfh_fn_len + lfh_e_len;
f->csize = csize;
f->ucsize = ucsize;
f++;
(int&)cdfh += 46 + fn_len + e_len + c_len;
}
za->num_files = i;
}
return h;
}
void zclose(const Handle h)
{
if(h_data(h, H_ZFILE))
h_free(h, H_ZFILE);
else
h_free(h, H_ZARCHIVE);
}
Handle zopen(Handle hz, const char* fn)
{
HDATA* hzd = h_data(hz, H_ZFILE);
if(!hzd)
return 0;
ZARCHIVE* za = (ZARCHIVE*)hzd->user;
// find its File descriptor
const u32 fn_hash = fnv_hash(fn, strlen(fn));
uint i = za->last_file+1;
if(i >= za->num_files || za->fn_hashs[i] != fn_hash)
{
for(i = 0; i < za->num_files; i++)
if(za->fn_hashs[i] == fn_hash)
break;
if(i == za->num_files)
return 0;
za->last_file = i;
}
const ZFILE* const f = &za->files[i];
//
HDATA* hfd;
Handle hf = h_alloc(fn_hash, H_ZFILE, 0, &hfd);
return hf;
}
int zaccess(Handle hz, const char* fn)
{
HDATA* hzd = h_data(hz, H_ZFILE);
if(!hzd)
return -1;
ZARCHIVE* za = (ZARCHIVE*)hzd->user;
// find its File descriptor
const u32 fn_hash = fnv_hash(fn, strlen(fn));
uint i = za->last_file+1;
if(i >= za->num_files || za->fn_hashs[i] != fn_hash)
{
for(i = 0; i < za->num_files; i++)
{
if(za->fn_hashs[i] == fn_hash)
break;
}
if(i == za->num_files)
return -1;
}
za->last_file = i;
return( 0 );
}
int zread(Handle hf, void*& p, size_t& size, size_t ofs)
{
HDATA* hfd = h_data(hf, 0);
if(!hfd)
return -1;
ZFILE* zf = (ZFILE*)hfd->user;
const size_t ucsize = zf->ucsize;
const size_t csize = zf->csize;
if(ofs > ucsize)
return -1;
bool deflated = ucsize != csize;
// TODO: async read for uncompressed files?
if(!deflated)
{
p = (u8*)hfd->p + zf->ofs + ofs;
size = hfd->size - ofs;
return 0;
}
// double-buffered
u32 slots[2];
int active_read = 0;
void* out_pos = 0;
void* out_mem = mem_alloc(ucsize, MEM_HEAP, 64*KB);
if(!out_mem)
return -1;
// inflating
z_stream stream;
if(deflated)
{
memset(&stream, 0, sizeof(stream));
if(inflateInit2(&stream, -MAX_WBITS) != Z_OK)
return -1;
// -MAX_WBITS indicates no zlib header present
stream.next_out = (u8*)out_mem;
stream.avail_out = ucsize;
}
// read directly into output buffer
else
out_pos = out_mem;
bool first = true;
bool done = false;
for(;;)
{
// start reading next block
if(!done)
slots[active_read] = vfs_start_read(hf, ofs, &out_pos);
active_read ^= 1;
// process block read in previous iteration
if(!first)
{
void* p;
size_t bytes_read;
vfs_finish_read(slots[active_read], p, bytes_read);
// inflate what we read
if(deflated)
{
stream.next_in = (u8*)p;
stream.avail_in = bytes_read;
inflate(&stream, 0);
}
}
first = false;
// one more iteration to process the last pending block
if(done)
break;
if(ofs >= csize)
done = true;
}
if(deflated)
{
inflateEnd(&stream);
if(stream.total_in != csize || stream.total_out != ucsize)
{
mem_free(out_mem);
return 0;
}
}
p = out_mem;
size = ucsize;
return 0;
}
//1 cache per zip - res layer doesnt know our internals (cache entry=ofs, csize,ucsize)
//cache=array (allow finding next file quickly; need some mechanism for faster random access?)
//sync is not a problem - zip file won't be updated during gameplay because it's still open

View File

@ -1,38 +0,0 @@
// ZIP archiving (on top of ZLib)
//
// Copyright (c) 2003 Jan Wassenberg
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// Contact info:
// Jan.Wassenberg@stud.uni-karlsruhe.de
// http://www.stud.uni-karlsruhe.de/~urkt/
#ifndef __UNZIP_H__
#define __UNZIP_H__
#include "res.h"
// open and return a handle to the zip archive indicated by <fn>
extern Handle zopen(const char* fn);
// open and return a handle to file <fn> in the zip archive <hz>
extern Handle zopen(Handle hz, const char* fn);
extern int zaccess( Handle hz, const char* fn );
extern void zclose(Handle hz);
extern int zread(Handle hf, void*& p, size_t& size, size_t ofs);
#endif // #ifndef __UNZIP_H__

View File

@ -1,3 +1,22 @@
// virtual file system - transparent access to files in archives;
// allows multiple search paths
//
// Copyright (c) 2003 Jan Wassenberg
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// Contact info:
// Jan.Wassenberg@stud.uni-karlsruhe.de
// http://www.stud.uni-karlsruhe.de/~urkt/
#include <cstdio>
#include <cassert>
#include <cstdlib>
@ -8,23 +27,44 @@
#include <algorithm>
#include "posix.h"
#include "unzip.h"
#include "zip.h"
#include "misc.h"
#include "vfs.h"
#include "mem.h"
// H_VFILE handle
struct VFILE
{
int fd;
size_t size; // compressed size, if a Zip file
// Zip only:
size_t ucsize;
size_t ofs;
Handle hm; // memory handle to the file or archive, if a Zip file
};
// rationale for n-archives per PATH entry:
// We need to be able to unmount specific paths (e.g. when switching mods).
// Don't want to remount everything (slow), or specify a mod tag when mounting
// (not this module's job). Instead, we include all archives in one path entry;
// the game keeps track of what paths it mounted for a mod, and unmounts those
// when needed.
// the game keeps track of what path(s) it mounted for a mod,
// and unmounts those when needed.
struct PATH
{
char* dir; // relative to root; points to space at end of this struct
struct PATH* next;
struct PATH* next; // linked list
char* dir; // relative to root dir;
// points to space at end of this struct
int num_archives;
Handle archives[1];
// space allocated here for archive Handles + dir string
};
static PATH* path_list;
@ -34,19 +74,13 @@ static void vfile_dtor(void* p)
{
VFILE* vf = (VFILE*)p;
// in archive
if(vf->ha && vf->hz)
{
zclose(vf->hz);
zclose(vf->ha);
vf->ha = vf->hz = 0;
}
// normal file
if(vf->fd > 0)
{
close(vf->fd);
vf->fd = -1;
}
mem_free(vf->hm);
}
@ -66,7 +100,7 @@ int vfs_set_root(const char* argv0, const char* root)
return -1;
*fn = 0;
chdir( fn + 1 );
chdir(path);
chdir(root);
return vfs_mount(".");
@ -99,8 +133,8 @@ int vfs_mount(const char* path)
// alloc search path entry (add to front)
const int archives_size = num_archives*sizeof(Handle);
const int entry_size = round_up(sizeof(PATH)+archives_size+path_len+1, 8);
PATH* entry = (PATH*)mem_alloc(entry_size);
const int entry_size = round_up(sizeof(PATH)+archives_size+path_len+1, 32);
PATH* entry = (PATH*)mem_alloc(entry_size, 32, MEM_HEAP);
if(!entry)
return -1;
entry->next = path_list;
@ -113,7 +147,7 @@ int vfs_mount(const char* path)
std::sort(archives.begin(), archives.end());
entry->num_archives = num_archives;
for(int i = 0; i < num_archives; i++)
entry->archives[i] = zopen(archives[i].c_str());
entry->archives[i] = zip_open(archives[i].c_str());
return 0;
}
@ -130,7 +164,7 @@ int vfs_umount(const char* path)
{
// close all archives
for(int i = 0; i < entry->num_archives; i++)
zclose(entry->archives[i]);
h_free(entry->archives[i], H_ZARCHIVE);
// remove from list
*prev = entry->next;
@ -148,107 +182,12 @@ int vfs_umount(const char* path)
}
Handle vfs_map(const char* fn)
// call func, passing the data argument, for each mounted path
// fail if its return value is < 0, stop if it returns 0
static int vfs_foreach_path(int (*func)(const char* path, Handle ha, void* data), const char* fn, void* data)
{
struct stat stat_buf;
if(stat(fn, &stat_buf) != 0)
return 0;
size_t size = stat_buf.st_size;
int fd = open(fn, O_RDONLY);
if(fd < 0)
return 0;
u32 fn_hash = fnv_hash(fn, strlen(fn));
void* p = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
if(p != MAP_FAILED)
{
HDATA* hd;
Handle h = h_alloc(0, H_VFILE, vfile_dtor, &hd);
if(h)
{
hd->p = p;
hd->size = size;
// VFILE* vf = (VFILE*)hd->user;
// vf->fd = fd;
return h;
}
}
return 0;
}
int vfs_access( char* fn )
{
// Alters 'fn' to the path of the file, if we find it...
// Mostly identical to vfs_stat, below.
struct stat dy;
// Strim out the path, if provided.
char* name = strrchr( fn, '/' );
if( name ) { name++; } else name = fn;
char buf[PATH_MAX+1]; buf[PATH_MAX] = 0;
// for each search path:
for(PATH* entry = path_list; entry; entry = entry->next)
{
// dir
const char* path = name;
if(entry->dir[0] != '.' || entry->dir[1] != '\0')
{
// only prepend dir if not "." (root) - "./" isn't portable
snprintf(buf, PATH_MAX, "%s/%s", entry->dir, name);
path = buf;
}
if( !_stat( path, &dy ) )
{
strcpy( fn, path );
return( 0 );
}
// archive
for(int i = 0; i < entry->num_archives; i++)
{
if( !zaccess(entry->archives[i], name) )
return( 0 );
}
}
// not found
return -1;
}
int vfs_stat( const char* fn, struct stat *buffer )
{
// Mostly identical to vfs_open, below.
// Note: vfs_stat redefines the nlink member of stat for its own
// nefarious ends.
// Check the specific location 'fn' first.
// If the file's there, it's faster.
if( !_stat( fn, buffer ) )
{
buffer->st_nlink = 0;
return( 0 );
}
// Not there? Drop the old path.
char* name = strrchr( fn, '/' );
if( name )
fn = name + 1;
char buf[PATH_MAX+1]; buf[PATH_MAX] = 0;
// for each search path:
for(PATH* entry = path_list; entry; entry = entry->next)
{
// dir
@ -259,61 +198,150 @@ int vfs_stat( const char* fn, struct stat *buffer )
snprintf(buf, PATH_MAX, "%s/%s", entry->dir, fn);
path = buf;
}
if( !_stat( path, buffer ) )
{
buffer->st_nlink = 1;
return( 0 );
}
// Ignore files in an archive.
int err = func(path, 0, data);
if(err <= 0)
return err;
// archive
for(int i = 0; i < entry->num_archives; i++)
{
err = func(path, entry->archives[i], data);
if(err <= 0)
return err;
}
}
// not found
return -1;
return -1; // func never returned 0
}
static int realpath_cb(const char* path, Handle ha, void* data)
{
char* full_path = (char*)data;
struct stat s;
if(!path && !ha)
{
assert(0 && "realpath_cb: called with invalid path and archive handle");
return 1;
}
if(path)
{
if(!stat(path, &s))
{
strncpy(full_path, path, PATH_MAX);
return 0;
}
}
else if(ha)
{
if(!zip_stat(ha, path, &s))
{
zip_archive_info(ha, full_path, 0);
return 0;
}
}
return 1;
}
int vfs_realpath(const char* fn, char* full_path)
{
return vfs_foreach_path(realpath_cb, fn, full_path);
}
static int stat_cb(const char* path, Handle ha, void* data)
{
struct stat* s = (struct stat*)data;
if(path)
return stat(path, s)? 1 : 0;
else if(ha)
return zip_stat(ha, path, s)? 1 : 0;
assert(0 && "stat_cb: called with invalid path and archive handle");
return 1;
}
int vfs_stat(const char* fn, struct stat* s)
{
return vfs_foreach_path(stat_cb, fn, s);
}
static int open_cb(const char* path, Handle ha, void* data)
{
struct stat s;
VFILE* vf = (VFILE*)data;
// normal file
if(path)
{
if(stat(path, &s) < 0)
return 1;
int fd = open(path, O_RDONLY);
if(fd < 0)
return 1;
vf->fd = fd;
vf->size = s.st_size;
}
// from archive
else if(ha)
{
ZFILE* zf = zip_lookup(ha, path);
if(!zf)
return 1;
Handle hm;
if(zip_archive_info(ha, 0, &hm) < 0)
return 1;
vf->ofs = zf->ofs;
vf->size = zf->csize;
vf->ucsize = zf->ucsize;
vf->fd = -1;
vf->hm = hm;
}
else
{
assert(0 && "open_cb: called with invalid path and archive handle");
return 1;
}
return 0;
}
Handle vfs_open(const char* fn)
{
char buf[PATH_MAX+1]; buf[PATH_MAX] = 0;
u32 fn_hash = fnv_hash(fn, strlen(fn));
// If a path to an existing file is given, use it.
VFILE* vf;
Handle hv = h_alloc(fn_hash, H_VFILE, vfile_dtor, (void**)&vf);
if(!hv)
return 0;
Handle h = vfs_map( fn );
if( h )
return( h );
// already open
if(vf->size)
return hv;
char* name = strrchr( fn, '/' );
if( name ) fn = name + 1;
// for each search path:
for(PATH* entry = path_list; entry; entry = entry->next)
if(vfs_foreach_path(open_cb, fn, vf) < 0)
{
// dir
const char* path = fn;
if(entry->dir[0] != '.' || entry->dir[1] != '\0')
{
// only prepend dir if not "." (root) - "./" isn't portable
snprintf(buf, PATH_MAX, "%s/%s", entry->dir, fn);
path = buf;
}
Handle h = vfs_map(path);
if(h)
return h;
// archive
for(int i = 0; i < entry->num_archives; i++)
{
Handle h = zopen(entry->archives[i], fn);
if(h)
return h;
}
h_free(hv, H_VFILE);
return 0;
}
// not found
return 0;
return hv;
}
const uint IDX_BITS = 4;
const uint NUM_SLOTS = 1ul << IDX_BITS;
const uint TAG_BITS = 32 - IDX_BITS;
@ -326,12 +354,11 @@ slots[NUM_SLOTS];
u32 vfs_start_read(const Handle hf, size_t& ofs, void** buf)
{
HDATA* hfd = h_data(hf, 0);
if(!hfd)
VFILE* vf = (VFILE*)h_user_data(hf, H_VFILE);
if(!vf)
return 0;
VFILE* vf = (VFILE*)hfd->user;
ssize_t bytes_left = hfd->size - ofs;
ssize_t bytes_left = vf->size - ofs;
if(bytes_left < 0)
return 0;
@ -362,12 +389,12 @@ u32 vfs_start_read(const Handle hf, size_t& ofs, void** buf)
// use the buffer given (e.g. read directly into output buffer)
if(buf)
cb->aio_buf = buf;
cb->aio_buf = *buf;
// allocate our own (reused for subsequent requests)
else
if(!cb->aio_buf)
{
cb->aio_buf = mem_alloc(64*KB, MEM_HEAP, 64*KB);
cb->aio_buf = mem_alloc(64*KB, 64*KB, MEM_HEAP);
if(!cb->aio_buf)
return 0;
}
@ -419,29 +446,120 @@ int vfs_finish_read(const u32 slot, void*& p, size_t& size)
int vfs_read(Handle h, void*& p, size_t& size, size_t ofs)
Handle vfs_load(const char* fn, void*& _p, size_t& _size, bool dont_map)
{
p = 0;
size = 0;
_p = 0;
_size = 0;
HDATA* hd = h_data(h, H_VFILE);
if(hd)
Handle hf = vfs_open(fn);
if(!hf)
return 0;
VFILE* vf = (VFILE*)h_user_data(hf, H_VFILE);
const bool deflated = vf->fd == -1 && vf->size != vf->ucsize;
const size_t in_size = vf->size;
const size_t out_size = deflated? vf->ucsize : vf->size;
// already mapped or read
if(vf->hm)
{
if(ofs+size > hd->size)
return -1;
p = (u8*)hd->p + ofs;
if(!size)
size = hd->size - ofs;
MEM* m = (MEM*)h_user_data(vf->hm, H_MEM);
if(m)
{
assert(out_size == m->size && "vfs_load: mismatch between VFILE and MEM size");
_p = m->p;
_size = m->size;
return vf->hm;
}
else
assert(0 && "vfs_load: invalid MEM attached to VFILE");
}
// decide whether to map the file, or read it
MemType mt = MEM_MAPPED;
if(deflated || dont_map)
mt = MEM_POOL;
// allocate memory / map the file
Handle hm;
void* out = mem_alloc(out_size, 64*KB, mt, vf->fd, &hm);
if(!out)
{
vfs_close(hf);
return 0;
}
// H_ZFILE
else
return zread(h, p, size, ofs);
if(mt == MEM_MAPPED)
{
_p = out;
_size = out_size;
return vf->hm = hm;
}
// now we read the file in 64 KB chunks (double buffered);
// if in an archive, we inflate while waiting for the next chunk to finish
u32 slots[2];
int active_read = 0;
void* pos = out; // if not inflating, read directly into output buffer
size_t ofs = vf->ofs;
void* ctx;
if(deflated)
{
pos = 0; // read into separate buffer
ctx = zip_inflate_start(out, out_size);
}
bool first = true;
bool done = false;
for(;;)
{
// start reading next block
if(!done)
slots[active_read] = vfs_start_read(hf, ofs, &pos);
active_read ^= 1;
// process block read in previous iteration
if(!first)
{
void* p;
size_t bytes_read;
vfs_finish_read(slots[active_read], p, bytes_read);
// inflate what we read
if(deflated)
zip_inflate_process(ctx, p, bytes_read);
}
first = false;
if(done)
break;
// one more iteration to process the last pending block
if(ofs >= in_size)
done = true;
}
if(deflated)
{
if(zip_inflate_end(ctx) < 0)
{
mem_free(out);
return 0;
}
}
_p = out;
_size = out_size;
return vf->hm = hm;
}
int vfs_close(Handle h)
{
h_free(h, 0);
return 0;
}
return h_free(h, H_VFILE);
}

View File

@ -1,10 +1,26 @@
struct VFILE
{
int fd;
// virtual file system - transparent access to files in archives;
// allows multiple search paths
//
// Copyright (c) 2003 Jan Wassenberg
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// Contact info:
// Jan.Wassenberg@stud.uni-karlsruhe.de
// http://www.stud.uni-karlsruhe.de/~urkt/
Handle hz; // position within archive (ZFILE)
Handle ha; // archive (ZARCHIVE)
};
#ifndef __VFS_H__
#define __VFS_H__
#include "res.h"
#define VFS_MAX_PATH 40
@ -12,17 +28,14 @@ extern int vfs_set_root(const char* argv0, const char* root);
extern int vfs_mount(const char* path);
extern int vfs_umount(const char* path);
extern Handle vfs_map(const char* fn); // actual path in real FS
extern int vfs_stat(const char* fn, struct stat *buffer);
extern int vfs_realpath(const char* fn, char* realpath);
extern int vfs_access( char* fn );
extern int vfs_stat( const char* fn, struct stat *buffer );
extern Handle vfs_load(const char* fn, void*& p, size_t& size, bool dont_map = false);
extern Handle vfs_open(const char* fn);
extern int vfs_close(Handle h);
// size: in - maximum byte count
// out - bytes actually read
extern int vfs_read(Handle h, void*& p, size_t& size, size_t ofs = 0);
extern u32 vfs_start_read(Handle hf, size_t& ofs, void** buf = 0);
extern int vfs_finish_read(u32 slot, void*& p, size_t& size);
extern int vfs_finish_read(u32 slot, void*& p, size_t& size);
#endif // #ifndef __VFS_H__

View File

@ -14,7 +14,7 @@
#include "tex.h"
#include "vfs.h"
#include "ia32.h"
#include "Config.h"
#include "ps/Config.h"
#ifndef NO_GUI
#include "gui/GUI.h"

View File

@ -61,11 +61,10 @@ PS_RESULT CConfig::Register( CStr Filename, void* Data, LoaderFunction DynamicLo
// Might as well check we can find the thing.
char filepath[PATH_MAX];
strcpy( filepath, Filename );
if( vfs_access( filepath ) ) // This changes filepath to the disk location
// of the file, if we know it, to speed up
// checks later.
if( vfs_realpath( Filename, filepath ) ) // This changes filepath to the disk location
// of the file, if we know it, to speed up
// checks later.
{
if( m_LogFile )
{
@ -127,8 +126,7 @@ PS_RESULT CConfig::Update()
// Find its new path and copy it back to the data we maintain
// here to speed up future queries.
char filepath[PATH_MAX];
strcpy( filepath, i->Filename );
vfs_access( filepath );
vfs_realpath( i->Filename, filepath );
if( m_LogFile )
{
CStr Report = _T( "File " );
@ -212,8 +210,7 @@ PS_RESULT CConfig::ReloadAll()
// We can't find the file. Seeing as this should reload everything,
// check that it exists.
char filepath[PATH_MAX];
strcpy( filepath, i->Filename );
if( vfs_access( filepath ) )
if( vfs_realpath( i->Filename, filepath ) )
{
// Oops.
notfound++;
@ -237,8 +234,7 @@ PS_RESULT CConfig::ReloadAll()
// Find its new path and copy it back to the data we maintain
// here to speed up future queries.
char filepath[PATH_MAX];
strcpy( filepath, i->Filename );
vfs_access( filepath );
vfs_realpath( i->Filename, filepath );
if( m_LogFile )
{
CStr Report = _T( "File " );

View File

@ -52,9 +52,9 @@ TDD at http://forums.wildfiregames.com/0ad
#include "Singleton.h"
#include "CStr.h"
#include "LogFile.h"
#include "..\lib\posix.h"
#include "..\lib\unzip.h"
#include "..\lib\misc.h"
#include "posix.h"
#include "zip.h"
#include "misc.h"
#include <vector>

View File

@ -16,6 +16,7 @@
#include "Terrain.H"
#include "tex.h"
#include "mem.h"
bool g_HillShading = true;
@ -46,7 +47,9 @@ TEX tex;
Handle h = tex_load(filename, &tex);
if(!h)
return false;
const u8* data = tex.ptr;
Handle hm = tex.hm;
MEM* mem = (MEM*)h_user_data(hm, H_MEM);
const u8* data = (const u8*)mem->p;
m_pVertices = new STerrainVertex[MAP_SIZE*MAP_SIZE];
if (m_pVertices == NULL)

View File

@ -299,14 +299,6 @@ SOURCE=..\lib\types.h
# End Source File
# Begin Source File
SOURCE=..\lib\unzip.cpp
# End Source File
# Begin Source File
SOURCE=..\lib\unzip.h
# End Source File
# Begin Source File
SOURCE=..\lib\vfs.cpp
# End Source File
# Begin Source File
@ -325,6 +317,14 @@ SOURCE=..\lib\wsdl.cpp
SOURCE=..\lib\wsdl.h
# End Source File
# Begin Source File
SOURCE=..\lib\zip.cpp
# End Source File
# Begin Source File
SOURCE=..\lib\zip.h
# End Source File
# End Group
# Begin Group "ps"
@ -335,6 +335,14 @@ SOURCE=..\ps\BaseEntity.h
# End Source File
# Begin Source File
SOURCE=..\ps\Config.cpp
# End Source File
# Begin Source File
SOURCE=..\ps\Config.h
# End Source File
# Begin Source File
SOURCE=..\ps\CStr.cpp
# End Source File
# Begin Source File

View File

@ -8,4 +8,14 @@ Known problems:
Ultimately the xml file reading's root dir should be
binaries/ too.
/Gee
/Gee
Known solution :))
- I put the GUI init code before VFS init (which changes the dir
as you mention to binaries/data), so that it'd work as you had it.
When you're ready, just move all data to binaries/data, move
the GUI init after vfs_set_root in main.cpp, and we're go.
p.s. we only need .vsproj and .sln in CVS; .ncb is built by VC.
janwas

View File

@ -225,6 +225,10 @@
Filter="">
<File
RelativePath="..\ps\BaseEntity.h"/>
<File
RelativePath="..\ps\Config.cpp"/>
<File
RelativePath="..\ps\Config.h"/>
<File
RelativePath="..\ps\CStr.cpp"/>
<File
@ -309,10 +313,6 @@
RelativePath="..\lib\time.h"/>
<File
RelativePath="..\lib\types.h"/>
<File
RelativePath="..\lib\unzip.cpp"/>
<File
RelativePath="..\lib\unzip.h"/>
<File
RelativePath="..\lib\vfs.cpp"/>
<File
@ -323,6 +323,10 @@
RelativePath="..\lib\wsdl.cpp"/>
<File
RelativePath="..\lib\wsdl.h"/>
<File
RelativePath="..\lib\zip.cpp"/>
<File
RelativePath="..\lib\zip.h"/>
<Filter
Name="posix"
Filter="">

View File

@ -1 +0,0 @@
Microsoft C/C++ MSF 7.00