CConfig, vfs, misc engine changes.

This was SVN commit r52.
This commit is contained in:
MarkT 2003-11-10 02:02:28 +00:00
parent 296404b5d9
commit d963d9c046
12 changed files with 594 additions and 23 deletions

View File

@ -19,6 +19,8 @@
#include <time.h>
#include <cmath>
#include "win.h"
#include "ia32.h"
#include "posix.h"
#include "detect.h"
@ -26,10 +28,6 @@
#include "types.h"
#include "misc.h"
#ifdef _WIN32
#include "win.h"
#endif
// high resolution (> 1 µs) timestamp [s], starting at or near 0 s.

View File

@ -221,6 +221,29 @@ Handle zopen(Handle hz, const char* fn)
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)
{

View File

@ -28,6 +28,8 @@ 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);

View File

@ -13,7 +13,6 @@
#include "vfs.h"
#include "mem.h"
// 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;
@ -67,7 +66,7 @@ int vfs_set_root(const char* argv0, const char* root)
return -1;
*fn = 0;
chdir(path);
chdir( fn + 1 );
chdir(root);
return vfs_mount(".");
@ -181,11 +180,111 @@ Handle vfs_map(const char* fn)
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
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;
}
if( !_stat( path, buffer ) )
{
buffer->st_nlink = 1;
return( 0 );
}
// Ignore files in an archive.
}
// not found
return -1;
}
Handle vfs_open(const char* fn)
{
char buf[PATH_MAX+1]; buf[PATH_MAX] = 0;
// If a path to an existing file is given, use it.
Handle h = vfs_map( fn );
if( h )
return( h );
char* name = strrchr( fn, '/' );
if( name ) fn = name + 1;
// for each search path:
for(PATH* entry = path_list; entry; entry = entry->next)
{

View File

@ -14,6 +14,9 @@ extern int vfs_umount(const char* path);
extern Handle vfs_map(const char* fn); // actual path in real FS
extern int vfs_access( char* fn );
extern int vfs_stat( const char* fn, struct stat *buffer );
extern Handle vfs_open(const char* fn);
extern int vfs_close(Handle h);

View File

@ -1,8 +1,11 @@
#ifdef _WIN32
#ifndef __WIN_H__
#define __WIN_H__
// Win32 socket decls aren't portable (e.g. problems with socklen_t)
// => skip winsock.h; posix.h should be used instead
#define _WINSOCKAPI_
#define WIN32_LEAN_AND_MEAN
@ -79,4 +82,5 @@ extern __declspec(dllimport) int __stdcall WSAStartup(WORD, char*);
#endif
}
#endif // #ifndef __WIN_H__
#endif
#endif

View File

@ -14,6 +14,7 @@
#include "tex.h"
#include "vfs.h"
#include "ia32.h"
#include "Config.h"
#ifndef NO_GUI
#include "gui/GUI.h"
@ -28,12 +29,9 @@ bool keys[256];
#include <cmath>
static Handle font;
static Handle tex;
extern void terr_init();
extern void terr_update();
extern bool terr_handler(const SDL_Event& ev);
@ -167,9 +165,14 @@ glColor3f(1.0f, 1.0f, 1.0f);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
#ifndef NO_GUI
////// janwas: I changed to some more for the GUI, we can talk about how to set this up
glOrtho(0., xres, 0., yres, -1000., 1.);
//////
#else
// (MT) Above line hides the frame counter behind the terrain.
glOrtho( 0., xres, 0., yres, -1., 1. );
#endif
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
@ -200,7 +203,6 @@ const float x = 600.0f, y = 512.0f;
glLoadIdentity();
glTranslatef(10, 30, 0);
font_bind(font);
glprintf("%d FPS", fps);
#ifndef NO_GUI
@ -221,8 +223,6 @@ const float x = 600.0f, y = 512.0f;
static void do_tick()
{
}
int main(int argc, char* argv[])
{
@ -269,7 +269,7 @@ glEnable (GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
new CConfig;
// TODO: all loading should go through the VFS; for now, we allow normal access
// this has to come before VFS init, as it changes the current dir
@ -280,8 +280,8 @@ glEnable (GL_DEPTH_TEST);
//g_GUI.LoadXMLFile("sprite1.xml");
#endif
vfs_set_root(argv[0], "data");
// tex = tex_load("0adlogo2.bmp");
// tex_upload(tex);
font = font_load("verdana.fnt");
@ -295,12 +295,16 @@ terr_init();
in_add_handler(handler);
in_add_handler(terr_handler);
// fixed timestep main loop
const double TICK_TIME = 30e-3; // [s]
double time0 = get_time();
g_Config.Update();
while(!quit)
{
g_Config.Update();
// TODO: limiter in case simulation can't keep up?
double time1 = get_time();
while((time1-time0) > TICK_TIME)
@ -315,6 +319,7 @@ in_add_handler(terr_handler);
SDL_GL_SwapBuffers();
calc_fps();
}
#ifndef NO_GUI
@ -322,5 +327,7 @@ in_add_handler(terr_handler);
delete CGUI::GetSingletonPtr(); // again, we should have all singleton deletes somewhere
#endif
delete &g_Config;
return 0;
}

View File

@ -16,7 +16,8 @@ Example:
MyString += _T(" I'm the number ") += CStr(MyNumber);
// Prints "Hello, World. I'm the number 126"
_tcout << (LPCTSTR)MyString << endl;
_tcout << (LPCTSTR)MyString << endl;
MyString = _("2341");
MyNum = MyString.ToInt();
@ -35,6 +36,9 @@ More Info:
#include "Prometheus.h"
#include <string> // Used for basic string functionality
#include <iostream>
#include "..\lib\posix.h"
#include <cstdlib>
using namespace std;
@ -56,7 +60,6 @@ typedef wchar_t TCHAR;
#define _totlower towlower
#define _istspace iswspace
#define _tsprintf wsprintf
#define _ultot _ultow
#define _ltot _ltow
#else
@ -77,7 +80,6 @@ typedef char TCHAR;
#endif
enum PS_TRIM_MODE {PS_TRIM_LEFT, PS_TRIM_RIGHT, PS_TRIM_BOTH};

308
source/ps/Config.cpp Executable file
View File

@ -0,0 +1,308 @@
// Last modified: 6 November 2003 (Mark Thompson)
// TODO: A few changes from VFS -> CFile usage if required.
#include "Config.h"
#include "vfs.h"
using namespace std;
DEFINE_ERROR( PS_FILE_NOT_FOUND, "A data file required by the engine could \
not be found. Check that it exists within the game directory or archive tree." );
DEFINE_ERROR( PS_FILE_LOAD_FAILURE, "One or more data files required by the \
engine could not be loaded. These files may have been deleted or corrupted." );
DEFINE_ERROR( PS_FILE_NODYNAMIC, "A data file was modified during execution, \
but the engine cannot make one or more of these alterations while the game is \
running." );
//--------------------------------------------------------
// SConfigData: Internal file representation
//--------------------------------------------------------
SConfigData::SConfigData( CStr _Filename, void* _Data, LoaderFunction _DynamicLoader )
{
Filename = _Filename;
Data = _Data;
DynamicLoader = _DynamicLoader;
Timestamp = TIME_UNREGISTERED;
}
//--------------------------------------------------------
// CConfig: Dynamic Data Manager (singleton)
//--------------------------------------------------------
//--------------------------------------------------------
// CConfig::CConfig()
//--------------------------------------------------------
CConfig::CConfig()
{
Clear();
Attach( NULL );
i = m_FileList.begin();
}
//--------------------------------------------------------
// CConfig::Register()
//
// Add a file to the registered list.
//--------------------------------------------------------
PS_RESULT CConfig::Register( CStr Filename, void* Data, LoaderFunction DynamicLoader )
{
assert( DynamicLoader != NULL );
if( m_LogFile )
{
CStr Report = _T( "Adding file: " );
Report += Filename;
m_LogFile->WriteText( (const TCHAR*)Report );
}
// 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( m_LogFile )
{
CStr Error = _T( "File not found on: " );
Error += Filename;
m_LogFile->WriteError( (const TCHAR*)Error );
}
return( PS_FILE_NOT_FOUND );
}
m_FileList.push_back( SConfigData( CStr( filepath ), Data, DynamicLoader ) );
i = m_FileList.begin();
if( m_LogFile )
{
CStr Report = _T( "Found file: " );
Report += CStr( filepath );
m_LogFile->WriteText( (const TCHAR*)Report );
}
return( PS_OK );
}
//--------------------------------------------------------
// CConfig::Update()
//
// Check timestamps of files and reload as required.
//--------------------------------------------------------
PS_RESULT CConfig::Update()
{
_int slice = 0;
_int failed = 0;
struct stat FileInfo;
for( slice = 0; ( i != m_FileList.end() ) && ( slice < CONFIG_SLICE ); i++, slice++ )
{
// TODO: CFile change on following line.
if( vfs_stat( i->Filename, &FileInfo ) )
{
// We can't find the file; if it exists, it's in an archive.
if( i->Timestamp )
{
// And it's already been loaded once, don't do so again.
continue;
}
// == TIME_UNREGISTERED. Load it, and set the modified date
// to now so that if it does turn up later on with a time
// after the start of the program, it will get loaded.
i->Timestamp = time( NULL );
}
else
{
if( FileInfo.st_nlink )
{
// This flag is set by vfs_stat to indicate that the file's
// gone walkabouts since last we knew its location.
// 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 );
if( m_LogFile )
{
CStr Report = _T( "File " );
Report += i->Filename;
Report += CStr( _T( " moved to: " ) );
Report += CStr( filepath );
m_LogFile->WriteText( (const TCHAR*)Report );
}
i->Filename = CStr( filepath );
}
if( i->Timestamp == FileInfo.st_mtime )
{
// This file has the same modification time as it did last
// time we checked.
continue;
}
i->Timestamp = FileInfo.st_mtime;
}
// If we reach here, the file needs to be (re)loaded.
// Note also that polling every frame via _stat() for a file which
// either does not exist or exists only in an archive could be a
// considerable waste of time, but if not done the game won't pick
// up on modified versions of archived files moved into the main
// directory trees. Also, alternatives to polling don't tend to be
// portable.
slice--;
// Reloaded files do not count against the slice quota.
if( m_LogFile )
{
CStr Report = _T( "Reloading file: " );
Report += i->Filename;
m_LogFile->WriteText( (const TCHAR*)Report );
}
PS_RESULT Result;
if( ( Result = i->DynamicLoader( i->Filename, i->Data ) ) != PS_OK )
{
if( m_LogFile )
{
CStr Error = _T( "Load failed on: " );
Error += CStr( i->Filename );
Error += CStr( "Load function returned: " );
Error += CStr( Result );
m_LogFile->WriteError( (const TCHAR*)Error );
}
failed++;
if( Result != PS_FILE_NODYNAMIC )
return( PS_FILE_LOAD_FAILURE ); // Oops. Serious problem, bail.
}
}
if( i == m_FileList.end() ) i = m_FileList.begin();
if( failed )
return( PS_FILE_NODYNAMIC );
return( PS_OK );
}
//--------------------------------------------------------
// CConfig::ReloadAll()
//
// Reloads all files.
//--------------------------------------------------------
PS_RESULT CConfig::ReloadAll()
{
// Mostly identical to Update(), above.
_int failed = 0;
_int notfound = 0;
struct stat FileInfo;
for( i = m_FileList.begin(); i != m_FileList.end(); i++ )
{
// TODO: CFile change on following line.
if( vfs_stat( i->Filename, &FileInfo ) )
{
// 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 ) )
{
// Oops.
notfound++;
if( m_LogFile )
{
CStr Error = _T( "File not found on: " );
Error += i->Filename;
m_LogFile->WriteError( (const TCHAR*)Error );
}
continue;
}
i->Filename = CStr( filepath );
i->Timestamp = time( NULL );
}
else
{
if( FileInfo.st_nlink )
{
// This flag is set by vfs_stat to indicate that the file's
// gone walkabouts since last we knew its location.
// 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 );
if( m_LogFile )
{
CStr Report = _T( "File " );
Report += i->Filename;
Report += CStr( _T( " moved to: " ) );
Report += CStr( filepath );
m_LogFile->WriteText( (const TCHAR*)Report );
}
i->Filename = CStr( filepath );
}
i->Timestamp = FileInfo.st_mtime;
}
// And load them all again...
if( m_LogFile )
{
CStr Report = _T( "Reloading file: " );
Report += i->Filename;
m_LogFile->WriteText( (const TCHAR*)Report );
}
PS_RESULT Result;
if( ( Result = i->DynamicLoader( i->Filename, i->Data ) ) != PS_OK )
{
if( m_LogFile )
{
CStr Error = _T( "Load failed on: " );
Error += CStr( i->Filename );
Error += CStr( "Load function returned: " );
Error += CStr( Result );
m_LogFile->WriteError( (const TCHAR*)Error );
}
failed++;
if( Result != PS_FILE_NODYNAMIC )
return( PS_FILE_LOAD_FAILURE ); // Oops. Serious problem, bail.
}
}
if( notfound )
return( PS_FILE_NOT_FOUND );
if( failed )
return( PS_FILE_NODYNAMIC );
return( PS_OK );
}
//--------------------------------------------------------
// CConfig::Clear()
//
// Erases registered list.
//--------------------------------------------------------
void CConfig::Clear()
{
m_FileList.clear();
}
//--------------------------------------------------------
// CConfig::Attach()
//
// Attaches (or detaches, with a NULL argument) a logfile class.
//--------------------------------------------------------
void CConfig::Attach( CLogFile* LogFile )
{
m_LogFile = LogFile;
}

116
source/ps/Config.h Executable file
View File

@ -0,0 +1,116 @@
/*
Config.h
CConfig dynamic data file manager class
Mark Thompson (mot20@cam.ac.uk)
Last modified: 6 November 2003 (Mark Thompson)
--Overview--
Maintains a list of data files in use by the engine; reloads any data file
altered during execution when Update() is called.
--Usage--
Load files by calling CConfig::Register() for each. The files are not loaded
until Update() is called; do so at the end of the block.
Update() compares the 'last-modified' timestamps of all registered files,
reloading all that have been altered since the last call (also any newly
registered).
Loader functions passed to Register() must take a CStr argument for a
filename, a void* for additional data, and return PS_OK if successful.
They must also handle the case where modified data is being reloaded. Ideally,
they should release resources allocated to the old version and load the new, at
least functions must leave the system in a predictable state. (e.g. if graphics
files are changed, but the loader functions cannot reload them, they should
do nothing but return PS_FILE_NODYNAMIC)
--Examples--
g_Config.Register( "gameParameters.dat", NULL, paramLoader );
g_Config.Register( "graphicsParameters7.dat", (void*)7, gfxParamLoader );
g_Config.Update();
--More info--
TDD at http://forums.wildfiregames.com/0ad
*/
#ifndef Config_H
#define Config_H
//--------------------------------------------------------
// Includes / Compiler directives
//--------------------------------------------------------
#include "stdlib.h"
#include "Prometheus.h"
#include "Singleton.h"
#include "CStr.h"
#include "LogFile.h"
#include "..\lib\posix.h"
#include "..\lib\unzip.h"
#include "..\lib\misc.h"
#include <vector>
//--------------------------------------------------------
// Macros
//--------------------------------------------------------
// Get singleton
#define g_Config CConfig::GetSingleton()
//Dummy timestamp value
#define TIME_UNREGISTERED 0
#define ACCESS_EXISTS 0
//The maximum number of files processed in one call to Update()
#define CONFIG_SLICE 100
//--------------------------------------------------------
// Declarations
//--------------------------------------------------------
//Possible return codes
DECLARE_ERROR( PS_FILE_NOT_FOUND );
DECLARE_ERROR( PS_FILE_LOAD_FAILURE );
DECLARE_ERROR( PS_FILE_NODYNAMIC );
//Loader function
typedef PS_RESULT (*LoaderFunction)( CStr Filename, void* Data );
//Internal registration type
struct SConfigData
{
CStr Filename;
LoaderFunction DynamicLoader;
void* Data;
time_t Timestamp;
SConfigData( CStr _Filename, void* _Data, LoaderFunction _DynamicLoader );
};
class CConfig : public Singleton<CConfig>
{
public:
CConfig();
//Register a new file with it's associated loader function
PS_RESULT Register( CStr Filename, void* Data, LoaderFunction DynamicLoader );
//Check all registered files, reload as neccessary
PS_RESULT Update();
//Force an update of all files in the registered list.
PS_RESULT ReloadAll();
//Erase the entire list of registered files
void Clear();
//Attach or detach a logfile class.
void Attach( CLogFile* LogFile );
private:
vector<SConfigData> m_FileList;
vector<SConfigData>::iterator i;
CLogFile* m_LogFile;
};
#endif

View File

@ -16,8 +16,13 @@ extern int xres, yres;
CCamera::CCamera ()
{
m_ViewPort.m_Width = 1280;
m_ViewPort.m_Height = 1024;
#ifdef WIDEASPECT
m_ViewPort.m_Width = 1440;
m_ViewPort.m_Height = 900;
#else
m_ViewPort.m_Width = 1600;
m_ViewPort.m_Height = 1200;
#endif
m_ViewPort.m_X = 0;
m_ViewPort.m_Y = 0;
}

View File

@ -9,7 +9,6 @@
// TODO: fix scrolling hack - framerate independent, use SDL
#include "win.h" // REMOVEME
void InitScene ();
void InitResources ();
void RenderScene ();
@ -46,7 +45,11 @@ extern int xres, yres;
void terr_init()
{
g_Renderer.Initialize (1280, 1024, 32);
#ifdef WIDEASPECT
g_Renderer.Initialize( 1440, 900, 32 );
#else
g_Renderer.Initialize (1600, 1200, 32);
#endif
InitResources ();
InitScene ();
@ -298,6 +301,7 @@ int cnt;
"blendtwooppositecorners.raw",
"blendushape.raw"
};
/*
//for(i = 0; i < NUM_ALPHA_MAPS;i++)
i=5;
@ -328,7 +332,7 @@ cnt=5;
for(i = 0; i < cnt; i++)
{
AlphaMaps[i] = tex_load(fns[i]);
AlphaMaps[i] = tex_load(fns[i]);
tex_upload(AlphaMaps[i], GL_LINEAR, GL_INTENSITY4);
}