If you have comments or questions concerning this source file, discuss them in the forum.
/*
Copyright (c) 2002 Nicolai Haehnle
See the license.txt for details. If that file was not included in the
source distributions, please email <prefect@rtts.org>
*/
// library.h -- collection of useful functions and classes
#ifdef _WIN32
// eliminate dumb warnings
#pragma warning(disable : 4244)
// conversion from 'double' to 'float'
#pragma warning(disable : 4305)
// shorten 'const double' to 'float'
#endif
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <setjmp.h>
#include <assert.h>
#include <math.h>
#include <algorithm>
#include <vector>
#include <list>
#ifdef _WIN32
// some more windows fixups
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#define strcasecmp stricmp
#define strncasecmp strnicmp
#define DLLEXPORT __declspec(dllexport)
#
else
#define DLLEXPORT
#endif
#ifdef _DEBUG
#ifndef DEBUG
#define DEBUG
#endif
#endif
/*
==============================================================================
DATA TYPES
==============================================================================
*/
typedef unsigned char byte;
typedef unsigned short u16;
typedef signed short s16;
typedef unsigned long u32;
typedef signed long s32;
#ifndef offsetof
#define offsetof(_struct,_field) ((
int)(&((_struct *)0)->_field))
#endif
#define atoffset(_type,_struct,_idx) (*(_type *)((byte *)&(_struct) + (_idx)))
#define arraysize(_array) (
sizeof((_array)) / sizeof((_array)[0]))
#define P_LITTLE_ENDIAN
#undef P_BIG_ENDIAN
#ifdef P_LITTLE_ENDIAN
#define LittleShort(x) (x)
#define LittleInt(x) (x)
#define LittleFloat(x) (x)
#define BigShort(x) SwapShort((x))
#define BigInt(x) SwapInt((x))
#define BigFloat(x) SwapFloat((x))
#endif
#ifdef P_BIG_ENDIAN
#define LittleShort(x) SwapShort((x))
#define LittleInt(x) SwapInt((x))
#define LittleFloat(x) SwapFloat((x))
#define BigShort(x) (x)
#define BigInt(x) (x)
#define BigFloat(x) (x)
#endif
short SwapShort(short x);
int SwapInt(int x);
float SwapFloat(float x);
/*
==============================================================================
MATH LIBRARY
==============================================================================
*/
#ifndef M_PI
#define M_PI 3.14159265358979323846
// from glibc's math.h
#endif
// Return a floating point variable in the range [0..1[
#define RandFloat() ((
double)rand() / (double)RAND_MAX)
// A non-negative integer rectangle
template<class T>
class LRectTmpl {
public:
T pos[2];
T size[2];
public:
LRectTmpl() { }
LRectTmpl(T x, T y, T w, T h) {
pos[0] = x;
pos[1] = y;
size[0] = w;
size[1] = h;
}
inline bool Contains(T x, T y) {
if (x < pos[0] || y < pos[1] || x >= pos[0]+size[0] || y >= pos[1]+size[1])
return false;
return true;
}
template<class P>
inline void WorldToRect(P *x, P *y) {
*x -= pos[0];
*y -= pos[1];
}
template<class P>
inline void RectToWorld(P *x, P *y) {
*x += pos[0];
*y += pos[1];
}
template<class P>
inline void ClipLocal(LRectTmpl<P> *rc) {
if (rc->pos[0] < 0) {
rc->size[0] += rc->pos[0];
rc->pos[0] = 0;
}
if (rc->pos[0]+rc->size[0] > size[0])
rc->size[0] = size[0] - rc->pos[0];
if (rc->pos[1] < 0) {
rc->size[1] += rc->pos[1];
rc->pos[1] = 0;
}
if (rc->pos[1]+rc->size[1] > size[1])
rc->size[1] = size[1] - rc->pos[1];
}
template<class P, class Q>
inline void ClipLocalOffset(LRectTmpl<P> *rc, Q *ofsx, Q *ofsy) {
if (rc->pos[0] < 0) {
rc->size[0] += rc->pos[0];
*ofsx -= rc->pos[0];
rc->pos[0] = 0;
}
if (rc->pos[0]+rc->size[0] > size[0])
rc->size[0] = size[0] - rc->pos[0];
if (rc->pos[1] < 0) {
rc->size[1] += rc->pos[1];
*ofsy -= rc->pos[1];
rc->pos[1] = 0;
}
if (rc->pos[1]+rc->size[1] > size[1])
rc->size[1] = size[1] - rc->pos[1];
}
};
typedef LRectTmpl<int> LRect;
typedef LRectTmpl<float> LFloatRect;
/*
==============================================================================
ERRORS
==============================================================================
*/
#define ERR_FATAL 0
// default
#define ERR_CONT 1
// it's possible to continue normally
class LError {
public:
int m_iSeverity;
char m_szMessage[256];
public:
LError(const char *fmt, ...);
LError(int iSeverity, const char *fmt, ...);
const char *Get() const { return m_szMessage; }
};
#ifdef DEBUG
#define lassert(expr)
do { \
if (!(expr)) throw LError("%s, line %i: assert %s", __FILE__, __LINE__, #expr ); \
} while(0)
#
else
#define lassert(expr) /* */
#endif
/*
==============================================================================
HEAP MANAGEMENT
==============================================================================
*/
// 100 and above are free for you to use
#define TAG_CLASS 0
#define TAG_POOL 1
#define TAG_FILES 2
#define TAG_PARSER 3
#define TAG_IMAGE 4
#define TAG_SIGNAL 5
#define TAG_CONFIG 6
#define TAG_HAL 10
#define TAG_SPRITE 11
#define TAG_GUI 20
//
// lib_heap.cpp
//
void *L_Malloc(int bytes, int tag);
char *L_Strdup(const char *string, int tag);
void L_Free(void *block);
void *L_Realloc(void *block, int bytes, int tag);
void L_TagFree(int start, int end);
/*
==============================================================================
CONSOLE
==============================================================================
*/
//
// lib_console.cpp
//
void L_Printf(const char *fmt, ...);
/*
==============================================================================
MISCELLANEOUS LIBRARY
==============================================================================
*/
// misc constants and functions
#define MAX_OSPATH 128
//
// lib_main.cpp
//
void *memnchr(const void *buf, int c, int bytes);
void xstrcpy(char *dest, int size, const char *src);
void xstrcat(char *dest, int size, const char *src);
int BitMaskSect(byte *mask0, int w0, int h0, byte *mask1, int w1, int h1,
int dx, int dy);
int L_Tokenize(char **tokv, int max_tokc, char *string);
/*
==============================================================================
LObject -- SIGNAL/SLOT CAPABLE CLASS
==============================================================================
*/
class LObject;
class LSignalMgr;
typedef void (LObject::*l_objectfn_t)(void);
typedef struct l_connection_s {
struct l_connection_s *signext;
LObject *obj;
l_objectfn_t fn;
struct l_connection_s *objnext;
LSignalMgr *signal;
} l_connection_t;
class LObject {
friend class LSignalMgr;
public:
LObject() { conns = 0; }
virtual ~LObject();
void Disconnect(LSignalMgr *pSig, l_objectfn_t fn);
private:
l_connection_t *conns;
void RemoveConn(l_connection_t *conn);
};
class LSignalMgr {
friend class LObject;
protected:
l_connection_t *conns;
public:
LSignalMgr() { conns = 0; }
~LSignalMgr();
void AddSlot(LObject *pObj, l_objectfn_t fn);
void DelSlot(LObject *pObj, l_objectfn_t fn);
private:
void RemoveConn(l_connection_t *conn);
};
#define impSIGNAL_head(plist) \
public: \
typedef void (LObject::*fntype) plist;
#define impSIGNAL_conn(plist) \
template<class T> \
inline void Connect(LObject *pObj, void (T::*fn)plist) \
{ AddSlot(pObj, (l_objectfn_t)static_cast<void (LObject::*)plist>(fn)); } \
template<class T> \
inline void Disconnect(LObject *pObj, void (T::*fn)plist) \
{ DelSlot(pObj, (l_objectfn_t)static_cast<void (LObject::*)plist>(fn)); }
#define impSIGNAL_tail(plist,pcall) \
inline void Emit plist { \
for(l_connection_t *c = conns; c; c = c->signext) \
(c->obj->*(fntype)(c->fn)) pcall; \
} \
};
// LSignal
class LSignal : public LSignalMgr {
impSIGNAL_head(())
impSIGNAL_conn(())
impSIGNAL_tail((),())
template<class P1>
class LSignal1 : public LSignalMgr {
impSIGNAL_head((P1 p1))
impSIGNAL_conn((P1 p1))
impSIGNAL_tail((P1 p1),(p1))
template<class P1, class P2>
class LSignal2 : public LSignalMgr {
impSIGNAL_head((P1 p1, P2 p2))
impSIGNAL_conn((P1 p1, P2 p2))
impSIGNAL_tail((P1 p1, P2 p2),(p1, p2))
/*
==============================================================================
FILE SYSTEM
==============================================================================
*/
//
// lib_files.c
//
char *L_AutoExtension(char *buf, int bufsize, const char *ext);
char *L_StripExtension(char *fname);
char *L_RelativePath(char *buf, int buflen, const char *basefile, const char *filename);
int L_FindFiles(const char *path, const char *pattern, char ***results);
void L_FreeFindFiles(char **results);
bool L_FileExists(const char *path);
class LFileRead {
public:
void *data;
int filepos;
int length;
public:
LFileRead();
~LFileRead();
void Open(const char *fname);
bool TryOpen(const char *fname);
void Close();
void SetFilePos(int pos);
byte Byte(int pos = -1) { return *(byte *)Data(1, pos); }
short Short(int pos = -1) { return LittleShort(*(short *)Data(2, pos)); }
int Integer(int pos = -1) { return LittleInt(*(int *)Data(4, pos)); }
float Float(int pos = -1) { return LittleFloat(*(float *)Data(4, pos)); }
char *CString(int pos = -1);
void *Data(int bytes, int pos = -1) {
int i;
lassert(data);
i = pos;
if (pos < 0) {
i = filepos;
filepos += bytes;
}
if (i+bytes > length)
throw LError("File boundary exceeded");
return (byte *)data + i;
}
};
class LFileWrite {
public:
void *data;
int length;
int maxsize;
int filepos;
public:
LFileWrite();
~LFileWrite();
void Write(const char *filename);
bool TryWrite(const char *filename);
void Clear();
void SetFilePos(int pos);
void Data(const void *data, int size, int pos = -1);
void Printf(const char *fmt, ...);
void Byte(byte x, int pos = -1) { Data(&x, 1, pos); }
void Short(short x, int pos = -1) { short y = LittleShort(x); Data(&y, 2, pos); }
void Integer(int x, int pos = -1) { int y = LittleInt(x); Data(&y, 4, pos); }
void Float(float x, int pos = -1) { float y = LittleFloat(x); Data(&y, 4, pos); }
void CString(const char *x, int pos = -1) { Data(x, strlen(x)+1, pos); }
};
/*
==============================================================================
PARSER
==============================================================================
*/
#define TOK_EOF 0
#define TOK_STRING (-1)
#define TOK_QUOTED (-2)
#define TOK_INT (-3)
#define TOK_FLOAT (-4)
typedef struct l_token_s {
int type; // positive values are special chars like '{'
union {
double f;
} v;
char *string; // the original, uninterpreted string
} l_token_t;
struct l_buffer_s;
typedef struct l_buffer_s l_buffer_t;
class LParser {
public:
const char *m_pszControlChars;
l_buffer_t *m_pBuffer;
char m_szBestName[MAX_OSPATH];
l_token_t tok;
public:
LParser();
~LParser();
LError Error(const char *fmt, ...);
void AddString(const char *pszString);
void AddFile(const char *pszFilename);
bool TryNextToken();
void NextToken();
void Expect(const char *pszExpect);
const char *AnyString();
const char *TryString();
const char *String();
float Float();
int Integer();
unsigned Unsigned();
void RelativePath(char *buf, int buflen, const char *fname);
inline void SetControlChars(const char *pszControlChars) {
m_pszControlChars = pszControlChars;
}
private:
void AddBuffer(const char *pszName, const char *pszData);
void EndBuffer();
};
/*
==============================================================================
CONFIG SYSTEM
==============================================================================
*/
struct l_configitem_s;
typedef struct l_configitem_s l_configitem_t;
typedef struct l_configrecord_s {
l_configitem_t *items;
} l_configrecord_t;
#define CI_STRING 0
#define CI_INT 1
#define CI_FLOAT 2
#define CI_RECORD 3
#define CI_BOOL 4
typedef struct l_configitem_s {
int type;
char *name;
char *dflt;
l_configrecord_t *record;
} l_configitem_t;
class LConfig {
public:
char *m_pszName;
public:
LConfig(const char *pszName);
virtual ~LConfig();
bool TryLoad(const char *filename);
bool TrySave(const char *filename);
char *GetString(const char *name) const;
int GetInt(const char *name) const;
float GetFloat(const char *name) const;
bool GetBool(const char *name) const;
const LConfig *GetItem(const char *name) const;
LConfig *GetItem(const char *name);
void SetString(const char *name, const char *value);
void SetInt(const char *name, int value);
void SetFloat(const char *name, float value);
void SetBool(const char *name, bool value);
public:
static LConfig *Create(l_configrecord_t *definition);
virtual void Parse(LParser *p) = 0;
virtual void Store(LFileWrite *fw) = 0;
virtual bool MustStore() = 0;
virtual char *intGetString() const;
virtual int intGetInt() const;
virtual float intGetFloat() const;
virtual bool intGetBool() const;
virtual LConfig *intGetItem(const char *name) const;
virtual void intSetString(const char *value);
virtual void intSetInt(int value);
virtual void intSetFloat(float value);
virtual void intSetBool(bool value);
LConfig *m_pPrev; // these are maintained by the parent record!
LConfig *m_pNext;
};
/*
==============================================================================
IMAGE LIBRARY
==============================================================================
*/
//
// lib_image.cpp
//
void L_ScaleImage(byte *out, int outw, int outh, const byte *in, int inw, int inh);
u32 *L_ImageBorder(const u32 *pixels, const int *size);
byte *L_ImageBitmask(const byte *pixels, const int *size);
void LoadPCX(const char *fname, int *sizes, byte **ppal, byte **pdata);
void LoadTGA(const char *fname, int *sizes, byte **ppal, byte **pdata, bool *palpha);
void LoadBMP(const char *fname, int *sizes, byte **ppal, byte **pdata);
void WriteBMP(const char *fname, const int *size, const byte *pal, const byte *data,
bool alpha);
/*
==============================================================================
STRUCTURES
==============================================================================
*/
/* -- apparently, recreating placement operators is not allowed --
inline void *operator new(unsigned int iBytes, void *block)
{
return block;
}
inline void operator delete(void *pBlock, void *block)
{
}
*/
/*
The pool is an extremely simple expandable packed array of items;
Indices will change when items are removed.
*/
template<class T>
class LPool {
public:
int size;
T *items;
private:
int max;
public:
LPool() { size = 0; max = 0; items = 0; }
~LPool() { Resize(0); }
void Add(const T &it) {
if (size >= max)
Resize(max + 10);
new(&items[size]) T;
items[size++] = it;
}
void RemoveAt(int idx) {
delete(&items[size]) &items[size];
size--;
if (idx != size)
memcpy(&items[idx], &items[size], sizeof(T));
}
int Find(const T &it) {
int i;
for(i = 0; i < size; i++)
if (items[i] == it)
return i;
return -1;
}
private:
void Resize(int newsize) {
max = newsize;
items = (T *)L_Realloc(items, sizeof(T)*max, TAG_POOL);
}
};