From d1036b9a186cd49ce030731947f4b27eb9292991 Mon Sep 17 00:00:00 2001 From: janwas Date: Thu, 13 May 2004 13:52:48 +0000 Subject: [PATCH] VFS updates; texture reloading now works, tex.cpp is WIP This was SVN commit r223. --- source/lib/lib.cpp | 2 +- source/lib/lib.h | 18 +- source/lib/res/file.cpp | 4 + source/lib/res/file.h | 1 + source/lib/res/h_mgr.cpp | 33 +++- source/lib/res/h_mgr.h | 2 + source/lib/res/tex.cpp | 32 ++- source/lib/res/vfs.cpp | 313 ++++++++++++++++++------------ source/lib/res/vfs.h | 16 +- source/lib/res/zip.cpp | 38 +++- source/lib/res/zip.h | 1 + source/lib/sysdep/win/hrt.cpp | 17 +- source/lib/sysdep/win/hrt.h | 4 +- source/main.cpp | 7 +- source/terrain/TextureManager.cpp | 1 + 15 files changed, 326 insertions(+), 163 deletions(-) diff --git a/source/lib/lib.cpp b/source/lib/lib.cpp index 609ed40eac..7e2700bf7d 100755 --- a/source/lib/lib.cpp +++ b/source/lib/lib.cpp @@ -36,7 +36,7 @@ // - call atexit (our exit handler would be called before its handler, // so we may have shut down something important already). -const int MAX_EXIT_FUNCS = 32; +const int MAX_EXIT_FUNCS = 64; static struct ExitFunc diff --git a/source/lib/lib.h b/source/lib/lib.h index 051258767b..ee28f46731 100755 --- a/source/lib/lib.h +++ b/source/lib/lib.h @@ -51,18 +51,24 @@ STMT(\ STMT(\ int err = (int)(func);\ if(err < 0)\ + {\ + assert(0 && "FYI: CHECK_ERR reports that a function failed."\ + "feel free to ignore or suppress this warning.");\ return err;\ + }\ ) enum LibError { - ERR_INVALID_HANDLE = -1000, - ERR_NO_MEM = -1001, - ERR_EOF = -1002, // attempted to read beyond EOF - ERR_INVALID_PARAM = -1003, - ERR_FILE_NOT_FOUND = -1004, - ERR_PATH_NOT_FOUND = -1005, + ERR_INVALID_HANDLE = -1000, + ERR_NO_MEM = -1001, + ERR_EOF = -1002, // attempted to read beyond EOF + ERR_INVALID_PARAM = -1003, + ERR_FILE_NOT_FOUND = -1004, + ERR_PATH_NOT_FOUND = -1005, + + ERR_VFS_PATH_LENGTH = -1006, ERR_LAST }; diff --git a/source/lib/res/file.cpp b/source/lib/res/file.cpp index 976c430ff4..9f46ec48af 100755 --- a/source/lib/res/file.cpp +++ b/source/lib/res/file.cpp @@ -162,6 +162,10 @@ typedef DirEnts::iterator DirEntsIt; static bool dirent_less(DirEnt& d1, DirEnt& d2) { return d1.name.compare(d2.name) < 0; } +// rationale: we pass the directory entry name only to the callback - +// not the absolute path, nor prepended. some users don't need it, +// and would need to strip it. this routine generates the absolute path, +// but in native form - can't use that. int file_enum(const char* dir, FileCB cb, uintptr_t user) { char n_path[PATH_MAX+1]; diff --git a/source/lib/res/file.h b/source/lib/res/file.h index 16d1e4336f..6e244b2fc4 100755 --- a/source/lib/res/file.h +++ b/source/lib/res/file.h @@ -68,6 +68,7 @@ extern int file_set_root_dir(const char* argv0, const char* root); typedef int(*FileCB)(const char* name, uint flags, ssize_t size, uintptr_t user); +// not recursive - only the files in ! extern int file_enum(const char* dir, FileCB cb, uintptr_t user); extern int file_stat(const char* path, struct stat*); diff --git a/source/lib/res/h_mgr.cpp b/source/lib/res/h_mgr.cpp index 986453502d..1dd00f6611 100755 --- a/source/lib/res/h_mgr.cpp +++ b/source/lib/res/h_mgr.cpp @@ -78,7 +78,7 @@ cassert(IDX_BITS + TAG_BITS <= sizeof(Handle)*CHAR_BIT); // return the handle's index field (always non-negative). // no error checking! static inline u32 h_idx(const Handle h) -{ return (u32)((h >> IDX_SHIFT) & IDX_MASK); } +{ return (u32)((h >> IDX_SHIFT) & IDX_MASK) - 1; } // return the handle's tag field. // no error checking! @@ -86,14 +86,15 @@ static inline u32 h_tag(const Handle h) { return (u32)((h >> TAG_SHIFT) & TAG_MASK); } // build a handle from index and tag -static inline Handle handle(const u32 idx, const u32 tag) +static inline Handle handle(const u32 _idx, const u32 tag) { + const u32 idx = _idx+1; assert(idx <= IDX_MASK && tag <= TAG_MASK && "handle: idx or tag too big"); // somewhat clunky, but be careful with the shift: // *_SHIFT may be larger than its field's type. - Handle _idx = idx & IDX_MASK; _idx <<= IDX_SHIFT; - Handle _tag = tag & TAG_MASK; _tag <<= TAG_SHIFT; - return _idx | _tag; + Handle h_idx = idx & IDX_MASK; h_idx <<= IDX_SHIFT; + Handle h_tag = tag & TAG_MASK; h_tag <<= TAG_SHIFT; + return h_idx | h_tag; } @@ -119,9 +120,10 @@ cassert(REF_BITS + TYPE_BITS <= IDX_BITS); // and array page usage). static const size_t HDATA_USER_SIZE = 48; -static const size_t HDATA_MAX_PATH = 64; +///static const size_t HDATA_MAX_PATH = 64; // 64 bytes +// TODO: not anymore, fix later struct HDATA { uintptr_t key; @@ -132,7 +134,7 @@ struct HDATA u8 user[HDATA_USER_SIZE]; - char fn[HDATA_MAX_PATH]; + const char* fn; }; @@ -363,7 +365,7 @@ int h_free(Handle& h, H_Type type) // any further params are passed to type's init routine Handle h_alloc(H_Type type, const char* fn, uint flags, ...) { - ONCE(atexit(cleanup)); + ONCE(atexit2(cleanup)); Handle err; @@ -437,6 +439,20 @@ Handle h_alloc(H_Type type, const char* fn, uint flags, ...) hd->type = type; Handle h = handle(idx, tag); +// regular filename +hd->fn = 0; +if(!(flags & RES_KEY)) +{ + if(fn) + { + const size_t fn_len = strlen(fn); + hd->fn = (const char*)malloc(fn_len+1); + strcpy((char*)hd->fn, fn); + } +} + + + H_VTbl* vtbl = type; va_list args; @@ -476,7 +492,6 @@ const char* h_filename(const Handle h) return hd? hd->fn : 0; } - int h_reload(const char* fn) { if(!fn) diff --git a/source/lib/res/h_mgr.h b/source/lib/res/h_mgr.h index d441556e11..2d685cbb57 100755 --- a/source/lib/res/h_mgr.h +++ b/source/lib/res/h_mgr.h @@ -181,6 +181,8 @@ extern void* h_user_data(Handle h, H_Type type); extern const char* h_filename(Handle h); +extern int h_reload(const char* fn); + extern int res_cur_scope; #ifdef __cplusplus diff --git a/source/lib/res/tex.cpp b/source/lib/res/tex.cpp index 2b7b43efda..61834e3d61 100755 --- a/source/lib/res/tex.cpp +++ b/source/lib/res/tex.cpp @@ -58,6 +58,8 @@ struct Tex size_t ofs; // offset to image data in file Handle hm; // H_MEM handle to loaded file uint id; + +bool uploaded; }; H_TYPE_DEFINE(Tex) @@ -673,10 +675,12 @@ fail: #endif + static void Tex_init(Tex* t, va_list args) { } + static void Tex_dtor(Tex* t) { mem_free_h(t->hm); @@ -685,6 +689,9 @@ static void Tex_dtor(Tex* t) } +// HACK HACK +static int tex_upload_t(Tex* t, int filter, int int_fmt); + // TEX output param is invalid if function fails static int Tex_reload(Tex* t, const char* fn) { @@ -748,12 +755,16 @@ static int Tex_reload(Tex* t, const char* fn) // TODO: check file name, go to 32 bit if wrong } + uint id; glGenTextures(1, &id); t->id = id; // this can't realistically fail, just note that the already_loaded // check above assumes (id > 0) <==> texture is loaded and valid +if(t->uploaded) +tex_upload_t(t, 0,0); + return 0; } @@ -789,9 +800,9 @@ int tex_bind(const Handle h) int tex_filter = GL_LINEAR; uint tex_bpp = 32; // 16 or 32 -int tex_upload(const Handle ht, int filter, int int_fmt) +static int tex_upload_t(Tex* t, int filter, int int_fmt) { - H_DEREF(ht, Tex, t); +t->uploaded = true; // data we will take from Tex GLsizei w; @@ -846,22 +857,25 @@ int tex_upload(const Handle ht, int filter, int int_fmt) if(err) { - const char* fn = h_filename(ht); +/* const char* fn = h_filename(ht); if(!fn) { fn = "(could not determine filename)"; assert(0); } debug_out("tex_upload: %s: %s\n", fn, err); +*/ debug_warn("tex_upload failed"); return -1; } - int ret = tex_bind(ht); +// CHECK_ERR(tex_bind(ht)); // we know ht is valid (H_DEREF above), but tex_bind can // fail in debug builds if Tex.id isn't a valid texture name - if(ret < 0) - return ret; + + +glBindTexture(GL_TEXTURE_2D, t->id); +// HACK HACK HACK // set filter if(!filter) @@ -976,6 +990,12 @@ int tex_upload(const Handle ht, int filter, int int_fmt) return 0; } +int tex_upload(const Handle ht, int filter, int int_fmt) +{ + H_DEREF(ht, Tex, t); + return tex_upload_t(t, filter, int_fmt); +} + int tex_free(Handle& ht) { diff --git a/source/lib/res/vfs.cpp b/source/lib/res/vfs.cpp index b43cd6ea6a..45b97ac42d 100755 --- a/source/lib/res/vfs.cpp +++ b/source/lib/res/vfs.cpp @@ -1,7 +1,7 @@ // virtual file system - transparent access to files in archives; -// allows multiple search paths +// allows multiple mount points // -// Copyright (c) 2003 Jan Wassenberg +// Copyright (c) 2004 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 @@ -28,8 +28,8 @@ #include "adts.h" -// currently not thread safe, but that will most likely change -// (if prefetch thread is to be used). +// currently not thread safe. will have to change that if +// a prefetch thread is to be used. // not safe to call before main! @@ -62,8 +62,6 @@ // version - that's what they're for). - - /////////////////////////////////////////////////////////////////////////////// // // path @@ -71,24 +69,35 @@ /////////////////////////////////////////////////////////////////////////////// // path types: -// portable (/ as directory separator; no ':' or '\\') -// v_* : VFS -// f_* : no path at all, filename only +// fn : filename only, no path at all. +// f_* : path intended directly for underlying file layer. +// component separator is '/'; no ':' or '\\' allowed. +// * : as above, but path within the VFS. -static int path_append(char* dst, const char* path, const char* path2) +// path1 and path2 may be empty, filenames, or full paths. +static int path_append(char* dst, const char* path1, const char* path2) { - const size_t path_len = strlen(path); + const size_t path1_len = strlen(path1); const size_t path2_len = strlen(path2); - if(path_len+path2_len+1 > VFS_MAX_PATH) - return -1; + bool need_separator = false; + + size_t total_len = path1_len + path2_len + 1; // includes '\0' + if(path1_len > 0 && path1[path1_len-1] != '/') + { + total_len++; // for '/' + need_separator = true; + } + + if(total_len+1 > VFS_MAX_PATH) + return ERR_VFS_PATH_LENGTH; char* p = dst; - strcpy(p, path); - p += path_len; - if(path_len > 0 && p[-1] != '/') + strcpy(p, path1); + p += path1_len; + if(need_separator) *p++ = '/'; strcpy(p, path2); return 0; @@ -102,7 +111,7 @@ static int path_validate(const uint line, const char* const path) const char* msg = 0; // error occurred <==> != 0 int err = -1; // pass error code to caller - // disallow absolute path + // disallow absolute path for safety, in case of *nix systems. if(path[0] == '/') { msg = "absolute path"; @@ -169,7 +178,6 @@ ok: /////////////////////////////////////////////////////////////////////////////// - // the VFS stores the location (archive or directory) of each file; // this allows multiple search paths without having to check each one // when opening a file (slow). @@ -202,14 +210,12 @@ struct Loc }; - - struct VDir; typedef std::map SubDirs; typedef SubDirs::iterator SubDirIt; -typedef std::map Files; +typedef std::map Files; typedef Files::iterator FileIt; // note: priority is accessed by following the Loc pointer. // keeping a copy in the map would lead to better cache coherency, @@ -223,11 +229,11 @@ struct VDir void* watch; - int file_add(const char* const fn, const uint pri, Loc* const loc) + int file_add(const char* const fn, const uint pri, const Loc* const loc) { std::string _fn(fn); - typedef std::pair Ent; + typedef std::pair Ent; Ent ent = std::make_pair(_fn, loc); std::pair ret; ret = files.insert(ent); @@ -235,7 +241,7 @@ struct VDir if(!ret.second) { FileIt it = ret.first; - Loc*& old_loc = it->second; + const Loc*& old_loc = it->second; // new Loc is of higher priority; replace pointer if(old_loc->pri <= loc->pri) @@ -251,7 +257,7 @@ struct VDir return 0; } - Loc* file_find(const char* fn) + const Loc* file_find(const char* fn) { std::string _fn(fn); FileIt it = files.find(_fn); @@ -263,7 +269,7 @@ struct VDir VDir* subdir_add(const char* name) { VDir* vdir = new VDir; - std::string _name(name); + const std::string _name(name); vdir->v_name = _name; std::pair item = std::make_pair(_name, vdir); @@ -277,15 +283,22 @@ struct VDir return it->second; } - VDir* subdir_find(const char* fn) + VDir* subdir_find(const char* name) { - std::string _fn(fn); - SubDirIt it = subdirs.find(_fn); + const std::string _name(name); + SubDirIt it = subdirs.find(_name); if(it == subdirs.end()) return 0; return it->second; } + void subdir_clear() + { + for(SubDirIt it = subdirs.begin(); it != subdirs.end(); ++it) + delete(it->second); + subdirs.clear(); + } + friend void tree_clearR(VDir*); SubDirs subdirs; // can't make private; needed for iterator @@ -303,11 +316,12 @@ static VDir vfs_root; enum LookupFlags { - LF_DEFAULT, + LF_DEFAULT = 0, LF_CREATE_MISSING_COMPONENTS = 1 }; -static int tree_lookup(const char* vfs_path, Loc** loc = 0, VDir** dir = 0, LookupFlags flags = LF_DEFAULT) + +static int tree_lookup(const char* vfs_path, const Loc** const loc = 0, VDir** const dir = 0, LookupFlags flags = LF_DEFAULT) { CHECK_PATH(vfs_path); @@ -376,7 +390,7 @@ static void tree_clearR(VDir* const dir) } dir->files.clear(); - dir->subdirs.clear(); + dir->subdir_clear(); } @@ -386,25 +400,12 @@ static inline void tree_clear() } - - - - - - struct FileCBParams { VDir* dir; - Loc* loc; + const Loc* loc; }; - // somewhat of a hack. which archives are mounted into the VFS is stored - // in an Archives list in the Mount struct; they don't have anything to - // do with a VFS dir. we want to enumerate the archives in a dir via the - // normal populate(), though, so have to pass this to its callback. - - - // called for each OS dir ent. // add each file and directory to the VFS dir. // @@ -416,60 +417,61 @@ struct FileCBParams // to try to open it as an archive - not good. // this restriction also simplifies the code a bit, but if it's a problem, // just generate a list of archives here and mount them from the caller. -static int add_dirent_cb(const char* fn, uint flags, ssize_t size, uintptr_t user) +static int add_dirent_cb(const char* const fn, const uint flags, const ssize_t size, const uintptr_t user) { - FileCBParams* params = (FileCBParams*)user; - VDir* cur_dir = params->dir; - Loc* cur_loc = params->loc; + const FileCBParams* const params = (FileCBParams*)user; + VDir* const cur_dir = params->dir; + const Loc* const cur_loc = params->loc; // directory if(flags & LOC_DIR) cur_dir->subdir_add(fn); // file else - cur_dir->file_add(fn, cur_loc->pri, cur_loc); + CHECK_ERR(cur_dir->file_add(fn, cur_loc->pri, cur_loc)); return 0; } -static int tree_add_dirR(VDir* vdir, const char* dir, Loc* loc) +static int tree_add_dirR(VDir* const vdir, const char* const f_path, const Loc* const loc) { + CHECK_PATH(f_path); + // add watch if(!vdir->watch) vdir->watch = 0; - // add files and subdirs to dir - FileCBParams params = { vdir, loc }; - file_enum(dir, add_dirent_cb, (uintptr_t)¶ms); + // add files and subdirs to vdir + const FileCBParams params = { vdir, loc }; + file_enum(f_path, add_dirent_cb, (uintptr_t)¶ms); for(SubDirIt it = vdir->subdirs.begin(); it != vdir->subdirs.end(); ++it) { - VDir* subdir = it->second; + VDir* const vsubdir = it->second; - char v_subdir_path[PATH_MAX]; - const char* v_subdir_name_c = subdir->v_name.c_str(); - CHECK_ERR(path_append(v_subdir_path, dir, v_subdir_name_c)); + char f_subdir_path[VFS_MAX_PATH]; + const char* const v_subdir_name_c = vsubdir->v_name.c_str(); + CHECK_ERR(path_append(f_subdir_path, f_path, v_subdir_name_c)); - tree_add_dirR(subdir, v_subdir_path, loc); + tree_add_dirR(vsubdir, f_subdir_path, loc); } return 0; } -static int tree_add_loc(VDir* vdir, Loc* loc) +static int tree_add_loc(VDir* const vdir, const Loc* const loc) { - const char* dir = loc->dir.c_str(); - - FileCBParams params = { vdir, loc }; - if(loc->archive > 0) + { + FileCBParams params = { vdir, loc }; return zip_enum(loc->archive, add_dirent_cb, (uintptr_t)¶ms); + } else { - CHECK_PATH(dir); - return tree_add_dirR(vdir, dir, loc); + const char* f_path_c = loc->dir.c_str(); + return tree_add_dirR(vdir, f_path_c, loc); } } @@ -481,23 +483,43 @@ static int tree_add_loc(VDir* vdir, Loc* loc) /////////////////////////////////////////////////////////////////////////////// - -typedef std::vector Locs; +// container must not invalidate iterators after insertion! +// (we keep and pass around pointers to Mount.archive_locs elements) +// see below. +typedef std::list Locs; typedef Locs::iterator LocIt; + struct Mount { - std::string vfs_mount_point; - std::string name; + // mounting into this VFS directory ("" for root) + std::string v_path; + + // what is being mounted; either directory, + // or archive filename (=> is_single_archive = true) + std::string f_name; uint pri; - Loc loc; + // storage for all Locs ensuing from this mounting. + // the VFS tree only holds pointers to Loc, which is why the + // Locs container must not invalidate its contents after adding, + // and also why the VFS tree must be rebuilt after unmounting something. + Loc dir_loc; Locs archive_locs; + // if not is_single_archive, contains one Loc for every archive + // in the directory (but not its children - see remount()). + // otherwise, contains exactly one Loc for the single archive. + + // is f_name an archive filename? if not, it's a directory. + bool is_single_archive; Mount() {} - Mount(const char* _vfs_mount_point, const char* _name, uint _pri) - : vfs_mount_point(_vfs_mount_point), name(_name), pri(_pri) {} + Mount(const char* _v_path, const char* _f_name, uint _pri) + : v_path(_v_path), f_name(_f_name), pri(_pri), + dir_loc(0, "", 0), archive_locs(), is_single_archive(false) + { + } }; typedef std::vector Mounts; @@ -505,34 +527,58 @@ typedef Mounts::iterator MountIt; static Mounts mounts; +// support for mounting multiple archives in a directory +// (useful for mix-in mods and patches). +// all archives are enumerated, added to a Locs list, +// and mounted (in alphabetical order!) - -// called for each OS dir ent. -// add each archive to list. -static int archive_cb(const char* fn, uint flags, ssize_t size, uintptr_t user) +struct ArchiveCBParams { - Locs* archive_locs = (Locs*)user; - // only add to list; don't enumerate its files yet for easier debugging - // (we see which files are in a dir / archives) - // also somewhat faster, due to better locality. - // + // we need a full path to open the archive, and only receive + // the filename, so prepend this (the directory being searched). + const char* f_dir; + + // priority at which the archive is to be mounted. + // specify here, instead of when actually adding the archive, + // because Locs are created const. + uint pri; + + // will add one Loc to this container for + // every archive successfully opened. + Locs* archive_locs; +}; + +// called for each directory entry. +// add each successfully opened archive to list. +static int archive_cb(const char* const fn, const uint flags, const ssize_t size, const uintptr_t user) +{ + // not interested in subdirectories + if(flags & LOC_DIR) + return 0; + + const ArchiveCBParams* const params = (ArchiveCBParams*)user; + const char* const f_dir = params->f_dir; + const uint pri = params->pri; + Locs* const archive_locs = params->archive_locs; + + // get full path (fn is filename only) + char f_path[VFS_MAX_PATH]; + CHECK_ERR(path_append(f_path, f_dir, fn)); + // don't check filename extension - archives won't necessarily // be called .zip (example: Quake III .pk3). // just try to open the file. - const Handle archive = zip_archive_open(fn); + const Handle archive = zip_archive_open(f_path); if(archive > 0) - archive_locs->push_back(Loc(archive, "", 0)); + archive_locs->push_back(Loc(archive, "", pri)); -/// HACK HACK HACK pass along pri - - - // tree_add_loc them here? + // only add archive to list; don't add its files into the VFS yet, + // to simplify debugging (we see which files are in which archive) return 0; } - // actually mount the specified entry (either Zip archive or dir). // split out of vfs_mount because we need to mount without changing the // mount list, when invalidating (reloading) the VFS. @@ -540,32 +586,43 @@ static int remount(Mount& m) { int err; - const char* vfs_mount_point = m.vfs_mount_point.c_str(); - const char* name = m.name.c_str(); - const uint pri = m.pri; + const char* const v_path = m.v_path.c_str(); + const char* const f_name = m.f_name.c_str(); + const uint pri = m.pri; + Loc& dir_loc = m.dir_loc; + Locs& archive_locs = m.archive_locs; VDir* vdir; - CHECK_ERR(tree_lookup(vfs_mount_point, 0, &vdir, LF_CREATE_MISSING_COMPONENTS)); + CHECK_ERR(tree_lookup(v_path, 0, &vdir, LF_CREATE_MISSING_COMPONENTS)); // check if target is a single Zip archive // order doesn't matter; can't have both an archive and dir - - const Handle archive = zip_archive_open(name); + const Handle archive = zip_archive_open(f_name); if(archive > 0) { - m.archive_locs.push_back(Loc(archive, "", pri)); - LocIt it = m.archive_locs.end(); - Loc* loc = &*(--it); + m.is_single_archive = true; + archive_locs.push_back(Loc(archive, "", pri)); + const Loc* loc = &archive_locs.front(); return tree_add_loc(vdir, loc); } - m.loc.dir.assign(m.name); - err = tree_add_loc(vdir, &m.loc); + // enumerate all archives + ArchiveCBParams params = { f_name, pri, &archive_locs }; + file_enum(f_name, archive_cb, (uintptr_t)¶ms); + + for(LocIt it = archive_locs.begin(); it != archive_locs.end(); ++it) + { + const Loc* const loc = &*it; + tree_add_loc(vdir, loc); + } + + + dir_loc.dir = f_name; + err = tree_add_loc(vdir, &dir_loc); if(err < 0) err = err; - // enumerate all archives - return file_enum(name, archive_cb, (uintptr_t)&m.archive_locs); +return 0; } @@ -582,22 +639,27 @@ static int unmount(Mount& m) } -static void unmount_all(void) +static inline void unmount_all(void) { std::for_each(mounts.begin(), mounts.end(), unmount); } -static void remount_all() +static inline void remount_all() { std::for_each(mounts.begin(), mounts.end(), remount); } +static void cleanup(void) +{ + tree_clear(); + unmount_all(); +} + + int vfs_mount(const char* const vfs_mount_point, const char* const name, const uint pri) { - ONCE(atexit(unmount_all)); - - MountIt it; + ONCE(atexit2(cleanup)); // make sure it's not already mounted, i.e. in mounts - for(it = mounts.begin(); it != mounts.end(); ++it) - if(it->name == name) + for(MountIt it = mounts.begin(); it != mounts.end(); ++it) + if(it->f_name == name) { debug_warn("vfs_mount: already mounted"); return -1; @@ -606,8 +668,7 @@ int vfs_mount(const char* const vfs_mount_point, const char* const name, const u mounts.push_back(Mount(vfs_mount_point, name, pri)); // actually mount the entry - it = mounts.end(); - Mount& m = *(--it); + Mount& m = mounts.back(); return remount(m); } @@ -626,7 +687,7 @@ int vfs_unmount(const char* name) { for(MountIt it = mounts.begin(); it != mounts.end(); ++it) // found the corresponding entry - if(it->name == name) + if(it->f_name == name) { Mount& m = *it; unmount(m); @@ -639,8 +700,6 @@ int vfs_unmount(const char* name) } - - /////////////////////////////////////////////////////////////////////////////// // // @@ -656,9 +715,15 @@ int vfs_unmount(const char* name) // and unmounts those when needed. +int vfs_reload(const char* fn) +{ + return h_reload(fn); +} + + int vfs_realpath(const char* fn, char* full_path) { - Loc* loc; + const Loc* loc; CHECK_ERR(tree_lookup(fn, &loc)); if(loc->archive > 0) @@ -679,7 +744,7 @@ int vfs_realpath(const char* fn, char* full_path) int vfs_stat(const char* fn, struct stat* s) { - Loc* loc; + const Loc* loc; CHECK_ERR(tree_lookup(fn, &loc)); if(loc->archive > 0) @@ -774,7 +839,7 @@ static void VFile_dtor(VFile* vf) -static int VFile_reload(VFile* vf, const char* fn) +static int VFile_reload(VFile* vf, const char* path) { int& flags = vf_flags(vf); @@ -786,15 +851,15 @@ static int VFile_reload(VFile* vf, const char* fn) int err = -1; - Loc* loc; - CHECK_ERR(tree_lookup(fn, &loc)); + const Loc* loc; + CHECK_ERR(tree_lookup(path, &loc)); if(loc->archive <= 0) { - char path[PATH_MAX]; + char f_path[PATH_MAX]; const char* dir = loc->dir.c_str(); - CHECK_ERR(path_append(path, dir, fn)); - CHECK_ERR(file_open(path, vf_flags(vf), &vf->f)); + CHECK_ERR(path_append(f_path, dir, path)); + CHECK_ERR(file_open(f_path, vf_flags(vf), &vf->f)); } else { @@ -804,7 +869,7 @@ static int VFile_reload(VFile* vf, const char* fn) return -1; } - CHECK_ERR(zip_open(loc->archive, fn, &vf->zf)); + CHECK_ERR(zip_open(loc->archive, path, &vf->zf)); flags |= VF_ZIP; } diff --git a/source/lib/res/vfs.h b/source/lib/res/vfs.h index f9f6bb187a..eed9432f0a 100755 --- a/source/lib/res/vfs.h +++ b/source/lib/res/vfs.h @@ -1,7 +1,7 @@ // virtual file system - transparent access to files in archives; -// allows multiple search paths +// allows multiple mount points // -// Copyright (c) 2003 Jan Wassenberg +// Copyright (c) 2004 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 @@ -23,7 +23,12 @@ #include "h_mgr.h" #include "posix.h" // struct stat -#define VFS_MAX_PATH 256 // includes trailing '\0' +// the VFS doesn't require this length restriction - VFS internal storage +// is not fixed-length. the purpose here is to allow fixed-sized path buffers +// allocated on the stack. +// +// length includes trailing '\0'. +#define VFS_MAX_PATH 256 extern int vfs_mount(const char* vfs_mount_point, const char* name, uint pri); extern int vfs_umount(const char* name); @@ -39,6 +44,11 @@ extern int vfs_close(Handle& h); extern Handle vfs_map(Handle hf, uint flags, void*& p, size_t& size); +extern int vfs_reload(const char* fn); +extern int vfs_rebuild(); + + + // // async read interface diff --git a/source/lib/res/zip.cpp b/source/lib/res/zip.cpp index c168f9fb29..abc4a65ec2 100755 --- a/source/lib/res/zip.cpp +++ b/source/lib/res/zip.cpp @@ -58,6 +58,19 @@ struct ZFileLoc }; +static inline int zip_validate(const void* const file, const size_t size) +{ + if(size < 2) + return -1; + + const u8* p = (const u8*)file; + if(p[0] != 'P' || p[1] != 'K') + return -1; + + return 0; +} + + // find end of central dir record in file (loaded or mapped). static int zip_find_ecdr(const void* const file, const size_t size, const u8*& ecdr_) { @@ -356,7 +369,7 @@ static int lookup_add_file_cb(const uintptr_t user, const i32 idx, const char* c ZEnt* ent = li->ents + idx; - FnHash fn_hash = fnv_hash(fn); + FnHash fn_hash = fnv_hash(fn, fn_len); (*li->idx)[fn_hash] = idx; li->fn_hashes[idx] = fn_hash; @@ -367,7 +380,8 @@ static int lookup_add_file_cb(const uintptr_t user, const i32 idx, const char* c ent->fn = (const char*)malloc(fn_len+1); if(!ent->fn) return ERR_NO_MEM; - strcpy((char*)ent->fn, fn); + strncpy((char*)ent->fn, fn, fn_len); + ((char*)ent->fn)[fn_len] = '\0'; ent->loc = *loc; } @@ -388,7 +402,14 @@ static int lookup_init(LookupInfo* const li, const void* const file, const size_ li->idx = new LookupIdx; - return zip_enum_files(file, size, lookup_add_file_cb, (uintptr_t)li); + int err = zip_enum_files(file, size, lookup_add_file_cb, (uintptr_t)li); + if(err < 0) + { + delete li->idx; + return err; + } + + return 0; } @@ -439,7 +460,7 @@ static int lookup_file(LookupInfo* const li, const char* const fn, i32& idx) // return file information, given file key (from lookup_file). static int lookup_get_file_info(LookupInfo* const li, const i32 idx, const char*& fn, ZFileLoc* const loc) { - if(idx < 0 || idx >= li->num_files-1) + if(idx < 0 || idx > li->num_files-1) { debug_warn("lookup_get_file_info: index out of bounds"); return -1; @@ -524,10 +545,19 @@ static int ZArchive_reload(ZArchive* za, const char* fn) if(err < 0) goto exit_close; + // early out: check if it's even a Zip file + err = zip_validate(file, size); + if(err < 0) + goto exit_unmap_close; + err = lookup_init(&za->li, file, size); if(err < 0) goto exit_unmap_close; + // we map the file only for convenience when loading; + // extraction is via aio (faster, better mem use). + file_unmap(&za->f); + za->is_open = true; return 0; diff --git a/source/lib/res/zip.h b/source/lib/res/zip.h index 5fdce45bde..2c5f641735 100755 --- a/source/lib/res/zip.h +++ b/source/lib/res/zip.h @@ -56,6 +56,7 @@ enum ZIP_CB_FLAGS LOC_ZIP = BIT(1) }; +// all files in archive! typedef int(*ZipFileCB)(const char* const fn, const uint flags, const ssize_t size, const uintptr_t user); extern int zip_enum(const Handle ha, const ZipFileCB cb, const uintptr_t user); diff --git a/source/lib/sysdep/win/hrt.cpp b/source/lib/sysdep/win/hrt.cpp index d825568520..1fafb2a84c 100755 --- a/source/lib/sysdep/win/hrt.cpp +++ b/source/lib/sysdep/win/hrt.cpp @@ -24,6 +24,9 @@ #include "detect.h" #include "win_internal.h" + +// we no longer use TGT, due to issues on Win9x; GTC is just as good. +// still need the header for the event timer (triggers periodic recalibration) #include // not included by win_internal due to its WIN32_LEAN_AND_MEAN define #ifdef _MSC_VER @@ -53,7 +56,7 @@ static i64 hrt_nominal_freq = -1; // decide upon a HRT implementation, checking if we can work around // each timer's issues on this platform, but allow user override // in case there are unforeseen problems with one of them. -// order of preference (due to resolution and speed): TSC, QPC, TGT. +// order of preference (due to resolution and speed): TSC, QPC, GTC. // split out of reset_impl so we can just return when impl is chosen. static void choose_impl() { @@ -157,11 +160,11 @@ static void choose_impl() #endif // QPC // - // TGT + // GTC // if(1) { - hrt_impl = HRT_TGT; + hrt_impl = HRT_GTC; hrt_nominal_freq = 1000; return; } @@ -202,8 +205,8 @@ static i64 ticks_lk() // TGT #ifdef _WIN32 - case HRT_TGT: - t = (i64)timeGetTime(); + case HRT_GTC: + t = (i64)GetTickCount(); break; #endif @@ -369,7 +372,7 @@ unlock(); int hrt_override_impl(HRTOverride ovr, HRTImpl impl) { if((ovr != HRT_DISABLE && ovr != HRT_FORCE && ovr != HRT_DEFAULT) || - (impl != HRT_TSC && impl != HRT_QPC && impl != HRT_TGT && impl != HRT_NONE)) + (impl != HRT_TSC && impl != HRT_QPC && impl != HRT_GTC && impl != HRT_NONE)) { debug_warn("hrt_override: invalid ovr or impl param"); return -1; @@ -452,7 +455,7 @@ unlock(); // setup calibration thread // note: winmm event is better than a thread or just checking elapsed time -// in hrt_ticks, because it's called right after TGT is updated; +// in hrt_ticks, because it's called right after GTC is updated; // otherwise, we may be in the middle of a tick. static UINT mm_event; diff --git a/source/lib/sysdep/win/hrt.h b/source/lib/sysdep/win/hrt.h index 78db0ead7c..a3b7dfe09d 100755 --- a/source/lib/sysdep/win/hrt.h +++ b/source/lib/sysdep/win/hrt.h @@ -28,8 +28,8 @@ enum HRTImpl // Windows QueryPerformanceCounter HRT_QPC, - // Windows timeGetTime - HRT_TGT, + // Windows GetTickCount + HRT_GTC, // there will always be a valid timer in use. // this is only used with hrt_override_impl. diff --git a/source/main.cpp b/source/main.cpp index 04bf2db3ad..566b1ca42a 100755 --- a/source/main.cpp +++ b/source/main.cpp @@ -124,6 +124,12 @@ static bool handler(const SDL_Event& ev) case SDLK_ESCAPE: quit = true; break; + + + case '1': + case SDLK_F1: + vfs_reload("art/textures/terrain/types/grass/Base1.tga"); + break; } break; @@ -216,7 +222,6 @@ static void do_tick() - int main(int argc, char* argv[]) { diff --git a/source/terrain/TextureManager.cpp b/source/terrain/TextureManager.cpp index 0cbdd22da5..0e77642afe 100755 --- a/source/terrain/TextureManager.cpp +++ b/source/terrain/TextureManager.cpp @@ -113,6 +113,7 @@ CTextureEntry* CTextureManager::AddTexture(const char* filename,int type) } else { tex_upload(h,GL_LINEAR_MIPMAP_LINEAR); } + // setup texture to repeat glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);