1
0
forked from 0ad/0ad

Initial revision

This was SVN commit r5.
This commit is contained in:
janwas 2003-09-21 21:24:53 +00:00
commit 2ebc9e2cb6
53 changed files with 9199 additions and 0 deletions

11
.gitattributes vendored Normal file
View File

@ -0,0 +1,11 @@
*.dae filter=lfs diff=lfs merge=lfs -text
*.dds filter=lfs diff=lfs merge=lfs -text
*.hmap filter=lfs diff=lfs merge=lfs -text
*.icns filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text
*.pmd filter=lfs diff=lfs merge=lfs -text
*.pmp filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.psa filter=lfs diff=lfs merge=lfs -text
*.ttf filter=lfs diff=lfs merge=lfs -text
binaries/data/mods/official/maps/**/*.xml filter=lfs diff=lfs merge=lfs -text

3
binaries/data/verdana.fnt Executable file
View File

@ -0,0 +1,3 @@
verdana.raw
24 24
6 6 7 14 10 18 11 4 7 7 9 14 5 7 6 8 10 10 10 10 10 9 11 10 11 11 8 7 13 13 13 9 16 12 12 12 13 11 11 13 13 7 7 12 9 15 13 13 11 13 12 11 10 11 12 16 12 10 11 7 8 7 12 10 10 10 10 9 10 10 6 10 10 4 6 11 4 15 10 11 10 10 7 9 7 10 10 14 10 10 9 10 8 9 13 17

BIN
binaries/data/verdana.raw Executable file

Binary file not shown.

301
source/detect.cpp Executable file
View File

@ -0,0 +1,301 @@
// system detect
//
// 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/
// things missing in POSIX and SDL :P
#include <cstdio>
#include <cstring>
#ifdef _WIN32
#include "win.h"
#endif
#include "detect.h"
#include "time.h"
#include "ogl.h"
#include "wsdl.h"
// useful for choosing a video mode. not called by detect().
// currently not implemented for non-Win32 systems (returns 800x600).
void get_cur_resolution(int& xres, int& yres)
{
// guess
xres = 800; yres = 600;
#ifdef _WIN32
static DEVMODE dm;
dm.dmSize = sizeof(dm);
EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &dm);
xres = dm.dmPelsWidth;
yres = dm.dmPelsHeight;
#endif
}
unsigned long tot_mem = 0;
unsigned long avl_mem = 0;
void get_mem_status()
{
// Win32
#ifdef _WIN32
MEMORYSTATUS ms;
GlobalMemoryStatus(&ms);
tot_mem = round_up(ms.dwTotalPhys, 1*MB);
// 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)
long page_size = sysconf(_SC_PAGESIZE);
tot_mem = sysconf(_SC_PHYS_PAGES ) * page_size;
avl_mem = sysconf(_SC_AVPHYS_PAGES) * page_size;
// BSD / Mac OS X
#elif HAVE_SYSCTL && defined(HW_PHYSMEM)
size_t len = sizeof(tot_mem);
int mib[2] = { CTL_HW, HW_PHYSMEM };
sysctl(mib, 2, &tot_mem, &len, 0, 0);
mib[1] = HW_USERMEM;
sysctl(mib, 2, &avl_mem, &len, 0, 0);
#endif
}
char gfx_card[512] = ""; // = D3D8 MAX_DEVICE_IDENTIFIER_STRING
#ifdef D3D8
#include <d3d8.h>
#ifdef _MSC_VER
#pragma comment(lib, "d3d8.lib")
#endif
#endif
// no-op on non-Win32 systems until OpenGL is initialized.
void get_gfx_card()
{
// already successfully detected
if(gfx_card[0] != 0)
return;
#ifdef D3D8
IDirect3D8* d3d = Direct3DCreate8(D3D_SDK_VERSION);
D3DADAPTER_IDENTIFIER8 id;
d3d->GetAdapterIdentifier(D3DADAPTER_DEFAULT, D3DENUM_NO_WHQL_LEVEL, &id);
d3d->Release();
strcpy(gfx_card, id.Description);
#else
char* v = (char*)glGetString(GL_VENDOR);
if(!v) // OpenGL probably not initialized yet
return;
strncpy(gfx_card, v, sizeof(gfx_card));
if(!strcmp(gfx_card, "ATI Technologies Inc."))
gfx_card[3] = 0;
if(!strcmp(gfx_card, "NVIDIA Corporation"))
gfx_card[6] = 0;
strcat(gfx_card, (char*)glGetString(GL_RENDERER));
#endif
}
//
// CPU
//
char cpu_type[49] = "unknown CPU"; // processor brand string is 48 chars
double cpu_freq = 0.f;
long cpu_caps = 0;
long cpu_ext_caps = 0;
// -1 if detect not yet called, or cannot be determined
int cpus = -1;
int is_notebook = -1;
#ifdef _M_IX86
int has_tsc = -1;
inline u64 rdtsc()
{
u64 c;
__asm
{
cpuid
rdtsc
mov dword ptr [c], eax
mov dword ptr [c+4], edx
}
// 64 bit values are returned in edx:eax, but we do it the safe way
return c;
}
#endif
static void get_cpu_info()
{
#ifdef _M_IX86
static char cpu_vendor[13];
int family, model;
__asm
{
; make sure CPUID is supported (size opt.)
pushfd
or byte ptr [esp+2], 32
popfd
pushfd
pop eax
shr eax, 22 ; bit 21 toggled?
jnc no_cpuid
; get vendor string
xor eax, eax
cpuid
mov dword ptr [cpu_vendor], ebx
mov dword ptr [cpu_vendor+4], edx
mov dword ptr [cpu_vendor+8], ecx
; (already 0 terminated)
; get CPU signature and std feature bits
mov eax, 1
cpuid
mov [cpu_caps], edx
mov edx, eax
shr edx, 4
and edx, 0x0f
mov [model], edx
shr eax, 8
and eax, 0x0f
mov [family], eax
; make sure CPUID ext functions are supported
mov eax, 0x80000000
cpuid
cmp eax, 0x80000000
jbe no_brand_str
; get CPU brand string (>= Athlon XP, P4)
mov edi, offset cpu_type
mov esi, -2 ; loop counter: -2 to 0
$1: lea eax, [0x80000004+esi]
cpuid
stosd
xchg eax, ebx
stosd
xchg eax, ecx
stosd
xchg eax, edx
stosd
inc esi
jle $1
; already 0 terminated
; get extended feature flags
mov eax, 0x80000001
cpuid
mov [cpu_ext_caps], edx
}
// strip (tm) from Athlon string
if(!strncmp(cpu_type, "AMD Athlon(tm)", 14))
memmove(cpu_type+10, cpu_type+14, 34);
// fixup Intel's as well
int a, b; // not needed, but sscanf returns # fields actually stored
if(sscanf(cpu_type, "Intel ® Pentium 4 CPU %d.%d GHz", &a, &b) == 2)
strcpy(cpu_type, "Intel Pentium 4");
goto have_brand_str;
no_brand_str:
// AMD
if(!strcmp(cpu_vendor, "AuthenticAMD"))
{
if(family == 6)
strcpy(cpu_type, (model == 3)? "AMD Duron" : "AMD Athlon");
}
// Intel
else if(!strcmp(cpu_vendor, "GenuineIntel"))
{
if(family == 6 && model >= 7)
strcpy(cpu_type, "Intel Pentium III / Celeron");
}
have_brand_str:
// calc CPU freq (count clocks in 50 ms)
if(cpu_caps & TSC)
{
u64 clocks1 = rdtsc();
// .. wait at at least 50 ms
double t1 = get_time();
double t2;
do
t2 = get_time();
while(t2 < t1 + 50e-3);
u64 clocks2 = rdtsc();
// .. freq = (clocks / 50 [ms]) / 50 [ms] * 1000
// cpuid/rdtsc overhead is negligible
cpu_freq = (__int64)(clocks2-clocks1) / (t2-t1);
// VC6 can't convert u64 -> double, and we don't need full range
}
// don't bother with a WAG timing loop
no_cpuid:
#endif // #ifdef _M_IX86
#ifdef _WIN32
HW_PROFILE_INFO hi;
GetCurrentHwProfile(&hi);
is_notebook = !(hi.dwDockInfo & DOCKINFO_DOCKED) ^
!(hi.dwDockInfo & DOCKINFO_UNDOCKED);
// both flags set <==> this is a desktop machine.
// both clear is unspecified; we assume it's not a notebook.
SYSTEM_INFO si;
GetSystemInfo(&si);
cpus = si.dwNumberOfProcessors;
#endif
}
void detect()
{
get_mem_status();
get_gfx_card();
get_cpu_info();
}

88
source/detect.h Executable file
View File

@ -0,0 +1,88 @@
// system detect
//
// 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 __DETECT_H__
#define __DETECT_H__
#include "misc.h"
#ifdef __cplusplus
extern "C" {
#endif
// useful for choosing a video mode. not called by detect().
// currently not implemented for non-Win32 systems (returns 800x600).
extern void get_cur_resolution(int& xres, int& yres);
extern char gfx_card[];
// no-op on non-Win32 systems until OpenGL is initialized.
extern void get_gfx_card();
//
// mem
//
extern unsigned long tot_mem;
extern unsigned long avl_mem;
// updates *_mem above
extern void get_mem_status();
//
// CPU
//
extern char cpu_type[];
extern double cpu_freq;
enum
{
TSC = BIT(4),
CMOV = BIT(15),
MMX = BIT(23),
SSE = BIT(25),
SSE2 = BIT(26)
};
extern long cpu_caps;
// define instead of enum to avoid stupid sign conversion warning
#define EXT_3DNOW_PRO BIT(30)
#define EXT_3DNOW BIT(31)
extern long cpu_ext_caps;
// -1 if detect not yet called, or cannot be determined
extern int cpus;
extern int is_notebook;
extern void detect();
#ifdef __cplusplus
}
#endif
#endif // #ifndef __DETECT_H__

226
source/font.cpp Executable file
View File

@ -0,0 +1,226 @@
/*
* OpenGL texture font
*
* Copyright (c) 2002 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 <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include "font.h"
#include "res.h"
#include "tex.h"
#include "ogl.h"
#include "posix.h"
#include "misc.h"
typedef struct
{
Handle tex;
uint list_base;
}
FONT;
#if 0
#include <ft2build.h>
//#include FT_FREETYPE_H
static FT_Library lib;
static void cleanup(void)
{
FT_Done_FreeType(lib);
}
int build_font(const char* in_ttf, const char* out_fnt, const char* out_raw, int height)
{
if(!lib)
{
FT_Init_FreeType(&lib);
atexit(cleanup);
}
FT_Face face;
if(FT_New_Face(lib, in_ttf, 0, &face))
return -1;
FT_Set_Pixel_Sizes(face, 0, height);
const int tex_dim = 256;
const int w = 24, h = 24;
FILE* f = fopen(out_fnt, "w");
if(!f)
return -1;
fprintf(f, "%s\n%d %d\n", out_raw, w, h); /* header */
u8* tex = (u8*)calloc(tex_dim*tex_dim, 2); /* GL_LUMINANCE_ALPHA fmt */
int x = 0, y = 0;
for(int c = 32; c < 128; c++) /* for each (printable) char */
{
FT_Load_Char(face, c, FT_LOAD_RENDER);
const u8* bmp = face->glyph->bitmap.buffer;
/* copy glyph's bitmap into texture */
for(int j = 0; j < face->glyph->bitmap.rows; j++)
{
u8* pos = &tex[(y+h-8-face->glyph->bitmap_top+j)*tex_dim*2 + (x+face->glyph->bitmap_left)*2];
for(int i = 0; i < face->glyph->bitmap.width; i++)
{
*pos++ = *bmp; /* luminance */
*pos++ = (*bmp)? 0xff : 0x00; /* alpha */
bmp++;
}
}
x += w;
if(x + w >= tex_dim)
x = 0, y += h;
fprintf(f, "%d ", face->glyph->advance.x / 64);
}
fclose(f);
/* write texture */
f = fopen(out_raw, "wb");
fwrite(tex, 2, tex_dim*tex_dim, f);
fclose(f);
free(tex);
return 0;
}
#endif
static void font_dtor(HDATA* hd)
{
FONT* font = (FONT*)hd->internal;
glDeleteLists(font->list_base, 96);
}
u32 font_load(const char* fn)
{
void* p;
size_t size;
HDATA* hd;
u32 h = res_load(fn, RES_FONT, font_dtor, p, size, hd);
if(!h || !hd || !p)
return 0;
int pos; // current position in the file
const char* file = (const char*)p;
// read header
char tex_filename[PATH_MAX];
int x_stride, y_stride; // glyph spacing in texture
if(sscanf(file, "%s\n%d %d\n%n", tex_filename, &x_stride, &y_stride, &pos) != 3)
{
printf("Problem loading \"%s\": header is invalid", fn);
return 0;
}
// read glyph widths
int adv[128];
for(int i = 32; i < 128; i++)
{
file += pos;
if(sscanf(file, "%d %n", &adv[i], &pos) != 1)
{
printf("Problem loading \"%s\": glyph width array is invalid", fn);
return 0;
}
}
// load glyph texture
const Handle tex = tex_load(tex_filename);
if(!tex)
return 0;
tex_upload(tex);
const int tex_dim = 256;
const float du = (float)x_stride / (float)tex_dim;
float u = 0, v = 0;
// create a display list for each glyph
const uint list_base = glGenLists(128);
for(int c = 32; c < 128; c++)
{
const float w = (float)adv[c], h = (float)y_stride; // glyph quad width/height
const float tw = w / tex_dim, th = h / tex_dim; // texture space width/height
glNewList(list_base+c, GL_COMPILE);
glBegin(GL_QUADS);
glTexCoord2f(u, v+th); glVertex2f(0, 0);
glTexCoord2f(u+tw, v+th); glVertex2f(w, 0);
glTexCoord2f(u+tw, v); glVertex2f(w, h);
glTexCoord2f(u, v); glVertex2f(0, h);
glEnd();
glTranslatef(w, 0, 0);
glEndList();
u += du;
if(u + du > 1.f)
u = 0.f, v += th;
}
FONT* font = (FONT*)hd->internal;
font->tex = tex;
font->list_base = list_base;
return h;
}
int font_bind(const u32 h)
{
HDATA* hd = h_data(h, RES_FONT);
if(!hd)
return -1;
FONT* font = (FONT*)hd->internal;
tex_bind(font->tex);
glListBase(font->list_base);
return 0;
}
void glprintf(const char* fmt, ...)
{
va_list args;
char buf[1024]; buf[1023] = 0;
va_start(args, fmt);
vsnprintf(buf, sizeof(buf)-1, fmt, args);
va_end(args);
glCallLists(strlen(buf), GL_UNSIGNED_BYTE, buf);
}

79
source/font.h Executable file
View File

@ -0,0 +1,79 @@
// OpenGL texture font
// 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 __FONT_H__
#define __FONT_H__
#include "types.h"
// load and return a handle to the font defined in <fn>
extern u32 font_load(const char* fn);
// use the font referenced by h for all subsequent glprintf() calls
extern int font_bind(u32 h);
// output text at current OpenGL modelview pos.
// assumes ortho projection with texturing, alpha test, and blending enabled.
// must bind a font before calling!
extern void glprintf(const char* fmt, ...);
#endif // #ifndef __FONT_H__
/*
EXAMPLE:
#include "font.h"
u32 h;
void init()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, xres, 0, yres, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.5);
h = font_load("font.fnt");
if(!h)
abort();
}
void render()
{
font_bind(h);
glprintf("string");
}
// FONT FILE FORMAT:
%s // texture file name
%d %d // width/height of glyphs in the texture
%d [...] %d // advance width for chars 32..127
*/

25
source/glext_funcs.h Executable file
View File

@ -0,0 +1,25 @@
/* GL 1.2 */
FUNC(void, glActiveTexture, (int))
/* EXT_swap_control */
FUNC(int, wglSwapIntervalEXT, (int))
/* NV_vertex_array */
FUNC(void, glVertexArrayRangeNV, (int, void*))
FUNC(void, glFlushVertexArrayRangeNV, ())
FUNC(void*, wglAllocateMemoryNV, (int, float, float, float))
FUNC(void, wglFreeMemoryNV, (void*))
/* NV_fence */
FUNC(void, glGenFencesNV, (int, unsigned int*))
FUNC(void, glDeleteFencesNV, (int, const unsigned int*))
FUNC(void, glSetFenceNV, (unsigned int, int))
FUNC(int, glTestFenceNV, (unsigned int))
FUNC(void, glFinishFenceNV, (unsigned int))
FUNC(int, glIsFenceNV, (unsigned int))
FUNC(void, glGetFenceivNV, (unsigned int, int, int*))
FUNC(void, glCompressedTexImage2DARB, (int, int, int, unsigned int, unsigned int, int, unsigned int, const void*))
FUNC(void, glCompressedTexSubImage2DARB, (int, int, int, int, unsigned int, int, int, unsigned int, const void*))

164
source/input.cpp Executable file
View File

@ -0,0 +1,164 @@
/*
* input layer (dispatch events to multiple handlers; record/playback events)
*
* Copyright (c) 2002 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 <stdio.h>
#include <stdlib.h>
#include "input.h"
#define MAX_HANDLERS 4
static IN_HANDLER handler_stack[MAX_HANDLERS];
static int handler_stack_top = 0;
int in_add_handler(IN_HANDLER handler)
{
if(handler_stack_top >= MAX_HANDLERS || !handler)
return -1;
handler_stack[handler_stack_top++] = handler;
return 0;
}
/* send event to each handler (newest first) until one returns true */
static void dispatch_event(const SDL_Event& event)
{
for(int i = handler_stack_top-1; i >= 0; i--)
if(handler_stack[i](event))
return;
}
static enum
{
INIT, /* first call to in_record() or in_playback(): register cleanup routine */
IDLE,
RECORD,
PLAYBACK
}
state = INIT;
static FILE* f;
extern u32 game_ticks;
static u32 time_adjust = 0;
static u32 next_event_time;
void in_stop()
{
if(f)
{
fclose(f);
f = 0;
}
state = IDLE;
}
int in_record(const char* fn)
{
if(state == INIT)
atexit(in_stop);
in_stop();
f = fopen(fn, "wb");
if(!f)
return -1;
fwrite(&game_ticks, sizeof(u32), 1, f);
state = RECORD;
return 0;
}
int in_playback(const char* fn)
{
if(state == INIT)
atexit(in_stop);
in_stop();
f = fopen(fn, "rb");
if(!f)
return -1;
u32 rec_start_time;
fread(&rec_start_time, sizeof(u32), 1, f);
time_adjust = game_ticks-rec_start_time;
fread(&next_event_time, sizeof(u32), 1, f);
next_event_time += time_adjust;
state = PLAYBACK;
return 0;
}
void in_get_events()
{
SDL_Event event;
while(state == PLAYBACK && next_event_time <= game_ticks)
{
fread(&event, sizeof(SDL_Event), 1, f);
/*
* do this before dispatch_event(),
* in case a handler calls in_stop() (setting f to 0)
*/
if(!fread(&next_event_time, sizeof(u32), 1, f))
{
in_stop();
exit(0x73c07d);
// TODO: 'disconnect'?
}
next_event_time += time_adjust;
dispatch_event(event);
}
/* get new events */
while(SDL_PollEvent(&event))
{
if(state == RECORD)
{
fwrite(&game_ticks, sizeof(u32), 1, f);
fwrite(&event, sizeof(SDL_Event), 1, f);
}
if(state == PLAYBACK)
if(event.type == SDL_KEYDOWN)
in_stop();
dispatch_event(event);
}
}

56
source/input.h Executable file
View File

@ -0,0 +1,56 @@
/*
* input layer (dispatch events to multiple handlers; record/playback events)
*
* Copyright (c) 2002 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 __INPUT_H__
#define __INPUT_H__
#include "wsdl.h"
#include "types.h"
#ifdef __cplusplus
extern "C" {
#endif
extern u32 game_ticks;
typedef bool (*IN_HANDLER)(const SDL_Event& event);
/*
* register an input handler, which will receive all subsequent events first.
* events are passed to other handlers if handler returns false.
*/
extern int in_add_handler(IN_HANDLER handler);
extern void in_get_events();
extern int in_record(const char* fn);
extern int in_playback(const char* fn);
extern void in_stop();
#ifdef __cplusplus
}
#endif
#endif /* #ifndef __INPUT_H__ */

260
source/main.cpp Executable file
View File

@ -0,0 +1,260 @@
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include "wsdl.h"
#include "ogl.h"
#include "detect.h"
#include "time.h"
#include "input.h"
#include "misc.h"
#include "posix.h"
#include "font.h"
#include "res.h"
#include "tex.h"
#include "vfs.h"
u32 game_ticks;
int xres = 800, yres = 600;
u32 font;
u32 tex;
// error in SDL before OpenGL initialized;
// display error message, and quit
// TODO: localization
enum SDLError
{
INIT,
VMODE
};
#ifdef _WIN32
extern "C" {
#define MB_ICONEXCLAMATION 0x30
__declspec(dllimport) unsigned long __stdcall MessageBoxA(void*, const char*, const char*, unsigned int);
}
#endif
static void sdl_error(SDLError err)
{
char msg[1000] = "Problem while setting up OpenGL.\n"\
"Details: ";
char* pos = msg + strlen(msg);
int rem = sizeof(msg)-1 - (pos-msg); // space remaining in buffer
if(err == INIT)
snprintf(pos, rem, "SDL library initialization failed (%s)\n", SDL_GetError());
else if(err == VMODE)
snprintf(pos, rem, "could not set %dx%d graphics mode (%s)\n", xres, yres, SDL_GetError());
fprintf(stderr, msg);
#ifdef _WIN32
MessageBoxA(0, msg, "0ad", MB_ICONEXCLAMATION);
#endif
exit(1);
}
static int set_vmode(int w, int h, int bpp)
{
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
if(!SDL_SetVideoMode(w, h, bpp, SDL_OPENGL|SDL_FULLSCREEN))
return -1;
glViewport(0, 0, w, h);
oglInit(); // required after each mode change
return 0;
}
static bool keys[256];
static bool handler(const SDL_Event& ev)
{
int c;
switch(ev.type)
{
case SDL_KEYDOWN:
c = ev.key.keysym.sym;
keys[c] = true;
switch(c)
{
case SDLK_ESCAPE:
exit(0);
}
break;
case SDL_KEYUP:
c = ev.key.keysym.sym;
keys[c] = false;
break;
}
return 0;
}
static void render()
{
// TODO: not needed with 100% draw coverage
glClear(GL_COLOR_BUFFER_BIT);
// overlay mode
glPushAttrib(GL_ENABLE_BIT);
glDisable(GL_CULL_FACE);
glBlendFunc(GL_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glAlphaFunc(GL_GREATER, 0.5);
glEnable(GL_ALPHA_TEST);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0., xres, 0., yres, -1., 1.);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
// logo
glLoadIdentity();
glTranslatef(50, 100, 0);
tex_bind(tex);
glBegin(GL_QUADS);
const float u = 0.585f, v = 1.0f;
const float x = 600.0f, y = 512.0f;
glTexCoord2f(0, 0); glVertex2f(0, 0);
glTexCoord2f(u, 0); glVertex2f(x, 0);
glTexCoord2f(u, v); glVertex2f(x, y);
glTexCoord2f(0, v); glVertex2f(0, y);
glEnd();
// FPS counter
glLoadIdentity();
glTranslatef(10, 30, 0);
font_bind(font);
glprintf("%d FPS", fps);
// restore
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glPopAttrib();
}
static void do_tick()
{
}
void main(int argc, char* argv[])
{
// set 24 bit (float) FPU precision for faster divides / sqrts
#ifdef _M_IX86
_control87(_PC_24, _MCW_PC);
#endif
detect();
// output system information
struct utsname un;
uname(&un);
freopen("stdout.txt", "w", stdout);
// .. OS
printf("%s %s (%s)\n", un.sysname, un.release, un.version);
// .. CPU
printf("%s, %s", un.machine, cpu_type);
if(cpu_freq != 0.0f)
{
if(cpu_freq < 1e9)
printf(", %.2f MHz\n", cpu_freq*1e-6);
else
printf(", %.2f GHz\n", cpu_freq*1e-9);
}
else
printf("\n");
// .. memory
printf("%lu MB RAM; %lu MB free\n", tot_mem/MB, avl_mem/MB);
// .. graphics card
printf("%s\n", gfx_card);
// .. network name / ips
printf("%s\n", un.nodename);
char hostname[100]; // possibly nodename != hostname
gethostname(hostname, sizeof(hostname));
hostent* h = gethostbyname(hostname);
if(h)
{
struct in_addr** ips = (struct in_addr**)h->h_addr_list;
for(int i = 0; ips && ips[i]; i++)
printf("%s ", inet_ntoa(*ips[i]));
printf("\n");
}
fflush(stdout);
// init SDL
if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_NOPARACHUTE) < 0)
sdl_error(INIT);
atexit(SDL_Quit);
// preferred video mode = current desktop settings
// (command line params may override these)
get_cur_resolution(xres, yres);
for(int a = 1; a < argc; a++)
if(!strncmp(argv[a], "xres", 4))
xres = atoi(argv[a]+4);
else if(!strncmp(argv[a], "yres", 4))
yres = atoi(argv[a]+4);
// TODO: other command line options
if(set_vmode(xres, yres, 32) < 0)
sdl_error(VMODE);
// call again - needs OpenGL to be initialized on non-Win32 systems
#ifndef _WIN32
get_gfx_card();
#endif
glEnable(GL_TEXTURE_2D);
vfs_add_search_path("data");
tex = tex_load("0adlogo1.bmp");
tex_upload(tex);
font = font_load("verdana.fnt");
in_add_handler(handler);
// fixed timestep main loop
const double TICK_TIME = 30e-3; // [s]
double time0 = get_time();
for(;;)
{
// TODO: limiter in case simulation can't keep up?
double time1 = get_time();
while((time1-time0) > TICK_TIME)
{
game_ticks++;
in_get_events();
do_tick();
time0 += TICK_TIME;
}
render();
SDL_GL_SwapBuffers();
calc_fps();
}
}

123
source/mem.cpp Executable file
View File

@ -0,0 +1,123 @@
// malloc layer for less fragmentation, alignment, and automatic release
#include <cstdlib>
#include <map>
#include "types.h"
#include "mem.h"
#include "res.h"
#include "misc.h"
struct MEM
{
uint type;
void* org_p; // MEM_HEAP only
size_t size; // MEM_POOL only
};
static void heap_dtor(HDATA* hd)
{
MEM* mem = (MEM*)hd->internal;
free(mem->org_p);
}
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;
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(HDATA* hd)
{
MEM* mem = (MEM*)hd->internal;
long pool_ofs = (u8*)hd->p - (u8*)pool;
// not at end of pool
if(pool_ofs + mem->size == pool_pos)
pool_pos -= mem->size;
}
static void* pool_alloc(const size_t size, const uint align, MEM& mem)
{
if(!pool)
pool = (u8*)mem_alloc(size, MEM_HEAP, align);
if(!pool)
return 0;
size_t ofs = round_up((ulong)pool+pool_pos, align) - (ulong)pool;
if(ofs+size > POOL_CAP)
return 0;
void* p = (u8*)pool + ofs;
mem.size = size;
pool_pos = ofs+size;
return p;
}
static void mem_dtor(HDATA* hd)
{
MEM* mem = (MEM*)hd->internal;
if(mem->type == MEM_HEAP)
heap_dtor(hd);
else if(mem->type == MEM_POOL)
pool_dtor(hd);
}
void* mem_alloc(size_t size, const MemType type, const uint align)
{
if(size == 0)
size = 1;
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
return 0;
HDATA* hd;
Handle h = h_alloc((u32)p, RES_MEM, mem_dtor, hd);
if(!h || !hd)
return 0;
*(MEM*)hd->internal = mem;
return p;
}
int mem_free(void* p)
{
if(!p)
return 1;
HDATA* hd;
Handle h = h_find((u32)p, RES_MEM, hd);
if(!h)
return -1;
h_free(h, RES_MEM);
return 0;
}

13
source/mem.h Executable file
View File

@ -0,0 +1,13 @@
#ifndef __MEM_H__
#define __MEM_H__
enum MemType
{
MEM_POOL,
MEM_HEAP
};
extern void* mem_alloc(size_t size, MemType type = MEM_HEAP, uint align = 1);
extern int mem_free(void* p);
#endif // #ifndef __MEM_H__

62
source/memcpy.cpp Executable file
View File

@ -0,0 +1,62 @@
/*
* block prefetch memcpy for large, uncached arrays
*
* src and len must be multiples of CHUNK_SIZE.
*/
void memcpy_nt(void* dst, void* src, int len)
{
__asm
{
push esi
mov edx, [dst]
mov esi, [src]
mov ecx, [len]
shr ecx, 12 ; # chunks
; smaller than sub ecx, CHUNK_SIZE below
main_loop:
; prefetch: touch each cache line in chunk
; (backwards to prevent hardware prefetches)
; add esi, CHUNK_SIZE
prefetch_loop:
mov eax, [esi-64]
mov eax, [esi-128]
sub esi, 128
test esi, 4095 ; CHUNK_SIZE-1 (icc doesn't preprocess asm)
jnz prefetch_loop
; copy the chunk 64 bytes at a time
write_loop:
movq mm0, [esi]
movq mm1, [esi+8]
movq mm2, [esi+16]
movq mm3, [esi+24]
movq mm4, [esi+32]
movq mm5, [esi+40]
movq mm6, [esi+48]
movq mm7, [esi+56]
add esi, 64
test esi, 4095 ; CHUNK_SIZE-1
movntq [edx], mm0
movntq [edx+8], mm1
movntq [edx+16], mm2
movntq [edx+24], mm3
movntq [edx+32], mm4
movntq [edx+40], mm5
movntq [edx+48], mm6
movntq [edx+56], mm7
lea edx, [edx+64] ; leave flags intact
jnz write_loop
dec ecx
jnz main_loop
sfence
emms
pop esi
}
}

223
source/misc.cpp Executable file
View File

@ -0,0 +1,223 @@
// miscellany
//
// 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 <cstdlib>
#include <cmath>
#include "time.h"
#include "misc.h"
#include <map>
// FNV1-A
u32 fnv_hash(const char* str, int len)
{
u32 h = 0;
while(len--)
{
h ^= *(const u8*)str++;
h *= 0x01000193;
}
return h;
}
#if defined(_M_IX86) && !defined(_WIN32)
// change FPU control word (used to set precision)
uint _control87(uint new_cw, uint mask)
{
__asm
{
push eax
fnstcw [esp]
pop eax ; old_cw
mov ecx, [new_cw]
mov edx, [mask]
and ecx, edx ; new_cw & mask
not edx ; ~mask
and eax, edx ; old_cw & ~mask
or eax, ecx ; (old_cw & ~mask) | (new_cw & mask)
push eax
fldcw [esp]
pop eax
}
return 0;
}
#endif
u16 bswap16(u16 x)
{
return (u16)(((x & 0xff) << 8) | (x >> 8));
}
u32 bswap32(u32 x)
{
#ifdef _M_IX86
__asm
{
mov eax, [x]
bswap eax
mov [x], eax
}
#else
u32 t = x;
for(int i = 0; i < 4; i++)
{
x <<= 8;
x |= t & 0xff;
}
#endif
return x;
}
void bswap32(const u8* data, int cnt)
{
__asm
{
mov edx, [data]
mov ecx, [cnt]
$loop: dec ecx
js $ret
mov eax, [edx+ecx*4]
bswap eax
mov [edx+ecx*4], eax
jmp $loop
$ret:
}
}
bool is_pow2(const int n)
{
return (n > 0) && !(n & (n-1));
}
// return -1 if not an integral power of 2,
// otherwise the base2 logarithm
int log2(const int n)
{
#ifdef _M_IX86
__asm
{
mov ecx, [n]
or eax, -1 // return value
lea edx, [ecx-1]
test ecx, edx // power of 2?
jnz $ret
bsf eax, ecx
$ret:
mov [n], eax
}
return n;
#else
if(n || n & (n-1))
return -1;
int i = 1, j = 0;
for(; i != n; i += i, j++)
;
return j;
#endif
}
static int log2(const float x)
{
u32 i = (u32&)x;
u32 exp = (i >> 23) & 0xff;
return (int)exp - 127;
}
long round_up(long val, int multiple)
{
val += multiple-1;
val -= val % multiple;
return val;
}
// replace pathetic libc implementation
#if defined(_M_IX86) && defined(_WIN32)
double ceil(double f)
{
double r;
const float _49 = 0.499999f;
__asm
{
fld [f]
fadd [_49]
frndint
fstp [r]
}
return r;
}
#endif
// big endian!
void base32(const int len, const u8* in, u8* out)
{
int bits = 0;
u32 pool = 0;
static u8 tbl[33] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
for(int i = 0; i < len; i++)
{
if(bits < 5)
{
pool <<= 8;
pool |= *in++;
bits += 8;
}
bits -= 5;
int c = (pool >> bits) & 31;
*out++ = tbl[c];
}
}

121
source/misc.h Executable file
View File

@ -0,0 +1,121 @@
// miscellany
//
// 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 __MISC_H__
#define __MISC_H__
#include "types.h"
#ifdef __cplusplus
extern "C" {
#endif
#define UNUSED(param) (void)param;
#define ONCE(code) { static bool done; if(!done) { code; }; done = true; }
const u32 KB = 1 << 10;
const u32 MB = 1 << 20;
#ifdef _WIN32
#define DIR_SEP '\\'
#else
#define DIR_SEP '/'
#endif
#ifndef _MCW_PC
#define _MCW_PC 0x0300 // Precision Control
#endif
#ifndef _PC_24
#define _PC_24 0x0000 // 24 bits
#endif
extern uint _control87(uint new_cw, uint mask);
extern u32 fnv_hash(const char* str, int len);
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#define BIT(n) (1ul << (n))
#ifndef min
inline int min(int a, int b)
{
return (a < b)? a : b;
}
inline int max(int a, int b)
{
return (a > b)? a : b;
}
#endif
extern u16 bswap16(u16);
extern u32 bswap32(u32);
static inline u16 read_le16(const void* p)
{
#ifdef BIG_ENDIAN
const u8* _p = p;
return (u16)_p[0] | (u16)_p[1] << 8;
#else
return *(u16*)p;
#endif
}
static inline u32 read_le32(const void* p)
{
#ifdef BIG_ENDIAN
u32 t = 0;
for(int i = 0; i < 32; i += 8)
t |= (*(const u8*)p++) << i;
return t;
#else
return *(u32*)p;
#endif
}
extern bool is_pow2(int n);
// return -1 if not an integral power of 2,
// otherwise the base2 logarithm
extern int log2(const int n);
extern long round_up(long val, int multiple);
extern double ceil(double f);
#ifdef __cplusplus
}
#endif
#endif // #ifndef __MISC_H__

103
source/ogl.cpp Executable file
View File

@ -0,0 +1,103 @@
#include <cassert>
#include <cstring>
#include <cstdio>
#include "wsdl.h"
#include "ogl.h"
#ifdef _MSC_VER
#pragma comment(lib, "opengl32.lib")
#endif
// define extension function pointers
extern "C"
{
#define FUNC(ret, name, params) ret (__stdcall *name) params;
#include "glext_funcs.h"
#undef FUNC
}
static const char* exts;
// check if the extension <ext> is supported by the OpenGL implementation
bool oglExtAvail(const char* ext)
{
assert(exts && "call oglInit before using this function");
const char *p = exts, *end;
// make sure ext is valid & doesn't contain spaces
if(!ext || ext == '\0' || strchr(ext, ' '))
return false;
for(;;)
{
p = strstr(p, ext);
if(!p)
return false; // <ext> string not found - extension not supported
end = p + strlen(ext); // end of current substring
// make sure the substring found is an entire extension string,
// i.e. it starts and ends with ' '
if(p == exts || *(p-1) == ' ') // valid start?
if(*end == ' ' || *end == '\0') // valid end?
return true;
p = end;
}
}
void oglPrintErrors()
{
#define E(e) case e: printf("%s\n", #e); break;
for(;;)
switch(glGetError())
{
case GL_NO_ERROR:
return;
E(GL_INVALID_ENUM)
E(GL_INVALID_VALUE)
E(GL_INVALID_OPERATION)
E(GL_STACK_OVERFLOW)
E(GL_STACK_UNDERFLOW)
E(GL_OUT_OF_MEMORY)
}
}
int max_tex_size; // [pixels]
int tex_units;
int max_VAR_elements = -1; // GF2: 64K; GF3: 1M
bool tex_compression_avail; // S3TC / DXT{1,3,5}
int video_mem; // [MB]; approximate
#include "time.h"
// call after each video mode change
void oglInit()
{
exts = (const char*)glGetString(GL_EXTENSIONS);
// import functions
#define FUNC(ret, name, params) *(void**)&name = SDL_GL_GetProcAddress(#name);
#include "glext_funcs.h"
#undef FUNC
// detect OpenGL / graphics card caps
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size);
glGetIntegerv(GL_MAX_TEXTURE_UNITS, &tex_units);
// make sure value is -1 if not supported
if(oglExtAvail("GL_NV_vertex_array_range"))
glGetIntegerv(GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV, &max_VAR_elements);
tex_compression_avail = oglExtAvail("GL_ARB_texture_compression") &&
(oglExtAvail("GL_EXT_texture_compression_s3tc") || oglExtAvail("GL_S3_s3tc"));
video_mem = (SDL_GetVideoInfo()->video_mem) / 1048576; // [MB]
// TODO: add sizeof(FB)?
}

65
source/ogl.h Executable file
View File

@ -0,0 +1,65 @@
#ifndef __OGL_H__
#define __OGL_H__
#ifdef __cplusplus
extern "C" {
#endif
// function pointer declarations
#define FUNC(ret, name, params) extern ret (__stdcall *name) params;
#include "glext_funcs.h"
#undef FUNC
#ifdef _WIN32
#ifndef WINGDIAPI
#define WINGDIAPI __declspec(dllimport)
#endif
#ifndef CALLBACK
#define CALLBACK __stdcall
#endif
#ifndef APIENTRY
#define APIENTRY __stdcall
#endif
typedef unsigned short wchar_t; // for glu.h
#endif // #ifndef _WIN32
#ifdef __APPLE__
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#include <OpenGL/glext.h>
#else
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glext.h>
#endif
#define GL_TEXTURE_IMAGE_SIZE_ARB 0x86A0
extern int max_tex_size; // [pixels]
extern int tex_units;
extern int max_VAR_elements; // GF2: 64K; GF3: 1M
extern bool tex_compression_avail; // S3TC / DXT{1,3,5}
extern int video_mem; // [MB]; approximate
// check if the extension <ext> is supported by the OpenGL implementation
extern bool oglExtAvail(const char* ext);
// print all OpenGL errors
extern void oglPrintErrors();
// call before using any of the above, and after each mode change
extern void oglInit();
#ifdef __cplusplus
}
#endif
#endif // #ifndef __OGL_H__

494
source/posix.cpp Executable file
View File

@ -0,0 +1,494 @@
// POSIX emulation for Win32
//
// 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/
// collection of hacks :P
#include <cassert>
#include <cstdlib>
#include <cmath>
#include <cstdio>
#include <process.h>
#include "posix.h"
#include "win.h"
#include "time.h"
#include "misc.h"
// VC6 windows.h may not have defined these
#ifndef INVALID_FILE_ATTRIBUTES
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
#endif
#ifndef PROCESSOR_ARCHITECTURE_AMD64
#define PROCESSOR_ARCHITECTURE_AMD64 9
#endif
extern "C"
{
// both hooked to support aio
extern int _open(const char* fn, int mode, ...);
extern int _close(int);
extern int _get_osfhandle(int);
extern void mainCRTStartup();
}
//////////////////////////////////////////////////////////////////////////////
//
// file
//
//////////////////////////////////////////////////////////////////////////////
extern int aio_open(const char*, int, int);
extern int aio_close(int);
int open(const char* fn, int mode, ...)
{
// /dev/tty? => COM?
if(!strncmp(fn, "/dev/tty", 8))
{
static char port[] = "COM ";
port[3] = (char)(fn[8]+1);
fn = port;
}
int fd = _open(fn, mode);
// open it for async I/O as well (_open defaults to deny_none sharing)
if(fd > 2)
aio_open(fn, mode, fd);
return fd;
}
int close(int fd)
{
aio_close(fd);
return _close(fd);
}
int ioctl(int fd, int op, int* data)
{
HANDLE h = (HANDLE)_get_osfhandle(fd);
switch(op)
{
case TIOCMGET:
/* TIOCM_* mapped directly to MS_*_ON */
GetCommModemStatus(h, (DWORD*)data);
break;
case TIOCMBIS:
/* only RTS supported */
if(*data & TIOCM_RTS)
EscapeCommFunction(h, SETRTS);
else
EscapeCommFunction(h, CLRRTS);
break;
case TIOCMIWAIT:
static DWORD mask;
DWORD new_mask = 0;
if(*data & TIOCM_CD)
new_mask |= EV_RLSD;
if(*data & TIOCM_CTS)
new_mask |= EV_CTS;
if(new_mask != mask)
SetCommMask(h, mask = new_mask);
WaitCommEvent(h, &mask, 0);
break;
}
return 0;
}
//////////////////////////////////////////////////////////////////////////////
//
// dir
//
//////////////////////////////////////////////////////////////////////////////
char* realpath(const char* fn, char* path)
{
if(!GetFullPathName(fn, PATH_MAX, path, 0))
return 0;
return path;
}
int mkdir(const char* path, mode_t)
{
return CreateDirectory(path, 0)? 0 : -1;
}
struct _DIR
{
WIN32_FIND_DATA fd;
HANDLE handle;
struct dirent ent; // must not be overwritten by calls for different dirs
bool not_first;
};
DIR* opendir(const char* name)
{
DWORD fa = GetFileAttributes(name);
if(fa == INVALID_FILE_ATTRIBUTES || !(fa & FILE_ATTRIBUTE_DIRECTORY))
return 0;
_DIR* d = (_DIR*)calloc(sizeof(_DIR), 1);
char path[MAX_PATH+1];
strncpy(path, name, MAX_PATH-2);
strcat(path, "\\*");
d->handle = FindFirstFile(path, &d->fd);
return d;
}
struct dirent* readdir(DIR* dir)
{
_DIR* d = (_DIR*)dir;
if(d->not_first)
if(!FindNextFile(d->handle, &d->fd))
return 0;
d->not_first = true;
d->ent.d_ino = 0;
d->ent.d_name = &d->fd.cFileName[0];
return &d->ent;
}
int closedir(DIR* dir)
{
_DIR* d = (_DIR*)dir;
FindClose(d->handle);
free(dir);
return 0;
}
//////////////////////////////////////////////////////////////////////////////
//
// terminal
//
//////////////////////////////////////////////////////////////////////////////
static HANDLE std_h[2] = { (HANDLE)3, (HANDLE)7 };
__declspec(naked) void _get_console()
{ __asm jmp dword ptr [AllocConsole] }
__declspec(naked) void _hide_console()
{ __asm jmp dword ptr [FreeConsole] }
int tcgetattr(int fd, struct termios* termios_p)
{
if(fd > 2)
return -1;
HANDLE h = std_h[fd];
DWORD mode;
GetConsoleMode(h, &mode);
termios_p->c_lflag = mode & (ENABLE_ECHO_INPUT|ENABLE_LINE_INPUT);
return 0;
}
int tcsetattr(int fd, int /* optional_actions */, const struct termios* termios_p)
{
if(fd > 2)
return -1;
HANDLE h = std_h[fd];
SetConsoleMode(h, (DWORD)termios_p->c_lflag);
FlushConsoleInputBuffer(h);
return 0;
}
int poll(struct pollfd /* fds */[], int /* nfds */, int /* timeout */)
{
return -1;
}
//////////////////////////////////////////////////////////////////////////////
//
// thread
//
//////////////////////////////////////////////////////////////////////////////
__declspec(naked) pthread_t pthread_self(void)
{ __asm jmp dword ptr [GetCurrentThread] }
int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param* param)
{
if(policy == SCHED_FIFO)
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
HANDLE hThread = (HANDLE)thread;
SetThreadPriority(hThread, param->sched_priority);
return 0;
}
int pthread_create(pthread_t* /* thread */, const void* /* attr */, void*(* func)(void*), void* arg)
{
/* can't use asm 'cause _beginthread might be a func ptr (with libc) */
return (int)_beginthread((void(*)(void*))func, 0, arg);
}
//////////////////////////////////////////////////////////////////////////////
//
// time
//
//////////////////////////////////////////////////////////////////////////////
int clock_gettime(clockid_t clock_id, struct timespec* tp)
{
static double start_t = -1.0;
static time_t start_s;
if(start_t < 0.0)
{
start_s = time(0);
start_t = get_time();
}
if(clock_id != CLOCK_REALTIME)
{
// errno = EINVAL;
return -1;
}
double t = get_time();
double dt = t-start_t;
start_t = t;
int ds = (int)floor(dt);
int dn = (int)floor((dt-ds) * 1.0e9);
tp->tv_sec = start_s + ds;
tp->tv_nsec = 0 + dn;
return 0;
}
int nanosleep(const struct timespec* rqtp, struct timespec* /* rmtp */)
{
int ms = (int)rqtp->tv_sec * 1000 + rqtp->tv_nsec / 1000000;
if(ms > 0)
Sleep(ms);
else
{
struct timespec t1, t2;
clock_gettime(CLOCK_REALTIME, &t1);
int d_ns;
do
{
clock_gettime(CLOCK_REALTIME, &t2);
d_ns = (int)(t2.tv_sec-t1.tv_sec)*1000000000 + (t2.tv_nsec-t1.tv_nsec);
}
while(d_ns < rqtp->tv_nsec);
}
return 0;
}
uint sleep(uint sec)
{
Sleep(sec * 1000);
return sec;
}
//////////////////////////////////////////////////////////////////////////////
//
// memory mapping
//
//////////////////////////////////////////////////////////////////////////////
void* mmap(void* start, unsigned int len, int prot, int flags, int fd, long offset)
{
if(!(flags & MAP_FIXED))
start = 0;
/* interpret protection/mapping flags. */
SECURITY_ATTRIBUTES sec = { sizeof(SECURITY_ATTRIBUTES), 0, 0 };
DWORD flProtect = PAGE_READONLY; /* mapping object permission */
DWORD dwAccess = FILE_MAP_READ; /* file map access permission */
if(prot & PROT_WRITE)
{
flProtect = PAGE_READWRITE;
/* changes are shared & written to file */
if(flags & MAP_SHARED)
{
sec.bInheritHandle = 1;
dwAccess = FILE_MAP_ALL_ACCESS;
}
/* private copy on write mapping */
else if(flags & MAP_PRIVATE)
{
flProtect = PAGE_WRITECOPY;
dwAccess = FILE_MAP_COPY;
}
}
DWORD len_hi = (u32)((u64)len >> 32), len_lo = (u32)len & 0xffffffff;
HANDLE hFile = (HANDLE)_get_osfhandle(fd);
HANDLE hMap = CreateFileMapping(hFile, &sec, flProtect, len_hi, len_lo, 0);
void* ptr = MapViewOfFileEx(hMap, dwAccess, len_hi, offset, len_lo, start);
/* file mapping object will be freed when ptr is unmapped */
CloseHandle(hMap);
if(!ptr || (flags & MAP_FIXED && ptr != start))
return MAP_FAILED;
return ptr;
}
int munmap(void* start, unsigned int /* len */)
{
return UnmapViewOfFile(start) - 1; /* 0: success; -1: fail */
}
int uname(struct utsname* un)
{
if(!un)
return -1;
static OSVERSIONINFO vi;
vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&vi);
// OS implementation name
const char* family = "??";
int ver = (vi.dwMajorVersion << 8) | vi.dwMinorVersion;
if(vi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
family = (ver == 0x045a)? "ME" : "9x";
if(vi.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
if(ver == 0x0500)
family = "2k";
else if(ver == 0x0501)
family = "XP";
else
family = "NT";
}
sprintf(un->sysname, "Win%s", family);
// release info
const char* vs = vi.szCSDVersion;
int sp;
if(sscanf(vs, "Service Pack %d", &sp) == 1)
sprintf(un->release, "SP %d", sp);
else
{
const char* release = "";
if(vi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
{
if(!strcmp(vs, " C"))
release = "OSR2";
else if(!strcmp(vs, " A"))
release = "SE";
}
strcpy(un->release, release);
}
// version
sprintf(un->version, "%lu.%02lu.%lu", vi.dwMajorVersion, vi.dwMinorVersion, vi.dwBuildNumber & 0xffff);
// node name
u32 buf_size = sizeof(un->nodename);
GetComputerName(un->nodename, &buf_size);
// hardware type
static SYSTEM_INFO si;
GetSystemInfo(&si);
if(si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
strcpy(un->machine, "AMD64");
else
strcpy(un->machine, "x86");
return 0;
}
#ifndef NO_WINSOCK
#ifdef _MSC_VER
#pragma comment(lib, "wsock32.lib")
#endif
extern "C" {
IMP(int, WSAStartup, (WORD, char*))
}
#endif
extern void entry(void);
void entry(void)
{
// alloc __pio, __iob?
// replace CRT init?
// header also removed to prevent calling Winsock functions
#ifndef NO_WINSOCK
char d[1024];
WSAStartup(0x0101, d);
#endif
mainCRTStartup();
}

437
source/posix.h Executable file
View File

@ -0,0 +1,437 @@
// POSIX emulation for Win32
//
// 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 __POSIX_H__
#define __POSIX_H__
#include <sys/stat.h>
#ifdef __cplusplus
extern "C" {
#endif
#define IMP(ret, name, param) extern __declspec(dllimport) ret __stdcall name param;
//
// <inttypes.h>
//
typedef unsigned short u16_t;
//
// <sys/types.h>
//
typedef int ssize_t;
typedef unsigned int size_t;
//
// <limits.h>
//
#define PATH_MAX 260
//
// <errno.h>
//
enum
{
EINPROGRESS = 1000, // Operation in progress.
ENOMEM // Not enough space.
/*
EACCES, // Permission denied.
EADDRINUSE, // Address in use.
EADDRNOTAVAIL, // Address not available.
EAGAIN, // Resource unavailable, try again (may be the same value as EWOULDBLOCK]).
EALREADY, // Connection already in progress.
EBADF, // Bad file descriptor.
ECANCELED, // Operation canceled.
ECONNABORTED, // Connection aborted.
ECONNREFUSED, // Connection refused.
ECONNRESET, // Connection reset.
EDOM, // Mathematics argument out of domain of IMPtion.
EEXIST, // File exists.
EFAULT, // Bad address.
EHOSTUNREACH, // Host is unreachable.
EINTR, // Interrupted IMPtion.
EINVAL, // Invalid argument.
EISCONN, // Socket is connected.
EISDIR, // Is a directory.
ENAMETOOLONG, // Filename too long.
ENETDOWN, // Network is down.
ENETRESET, // Connection aborted by network.
ENETUNREACH, // Network unreachable.
ENOENT, // No such file or directory.
ENOEXEC, // Executable file format error.
ENOSPC, // No space left on device.
ENOSYS, // IMPtion not supported.
ENOTCONN, // The socket is not connected.
ENOTDIR, // Not a directory.
ENOTEMPTY, // Directory not empty.
ENOTSOCK, // Not a socket.
ENOTSUP, // Not supported.
EOVERFLOW, // Value too large to be stored in data type.
EPERM, // Operation not permitted.
EPIPE, // Broken pipe.
EPROTO, // Protocol error.
ERANGE, // Result too large.
ETIMEDOUT, // Connection timed out.
EWOULDBLOCK // Operation would block (may be the same value as EAGAIN]).
*/
};
//
// <time.h>
//
typedef long time_t;
typedef enum
{
CLOCK_REALTIME
}
clockid_t;
struct timespec
{
time_t tv_sec;
long tv_nsec;
};
extern time_t time(time_t*);
extern int clock_gettime(clockid_t clock_id, struct timespec* tp);
extern int nanosleep(const struct timespec* rqtp, struct timespec* rmtp);
//
// sys/stat.h
//
typedef unsigned short ino_t;
typedef unsigned int mode_t;
typedef long off_t;
typedef unsigned int dev_t;
// struct stat defined in VC sys/stat.h
#define stat _stat
extern int mkdir(const char*, mode_t);
//
// dirent.h
//
typedef void DIR;
struct dirent
{
ino_t d_ino;
char* d_name;
};
extern DIR* opendir(const char* name);
extern struct dirent* readdir(DIR*);
extern int closedir(DIR*);
//
// <sys/mman.h>
//
#define PROT_READ 0x01 // page can be read
#define PROT_WRITE 0x02 // page can be written
#define MAP_SHARED 0x01 // share changes across processes
#define MAP_PRIVATE 0x02 // private copy on write mapping
#define MAP_FIXED 0x04
#define MAP_FAILED 0
extern void* mmap(void* start, unsigned int len, int prot, int flags, int fd, long offset);
extern int munmap(void* start, unsigned int len);
//
// <fcntl.h>
//
// values from MS _open - do not change!
#define O_RDONLY 0x0000 // open for reading only
#define O_WRONLY 0x0001 // open for writing only
#define O_RDWR 0x0002 // open for reading and writing
#define O_APPEND 0x0008 // writes done at eof
#define O_CREAT 0x0100 // create and open file
#define O_TRUNC 0x0200 // open and truncate
#define O_EXCL 0x0400 // open only if file doesn't already exist
#define O_BINARY 0x8000 // file mode is binary (untranslated)
#define O_NONBLOCK 0x1000000
extern int open(const char* fn, int mode, ...);
//
// <unistd.h>
//
#define F_OK 0
#define R_OK 1
#define W_OK 2
#define X_OK 4
#define read _read
#define write _write
extern int close(int);
extern int access(const char*, int);
extern int chdir(const char*);
extern unsigned int sleep(unsigned int sec);
IMP(int, gethostname, (char* name, size_t namelen))
//
// <stdlib.h>
//
extern char* realpath(const char*, char*);
//
// <signal.h>
//
union sigval
{
int sival_int; // Integer signal value.
void* sival_ptr; // Pointer signal value.
};
struct sigevent
{
int sigev_notify; // notification mode
int sigev_signo; // signal number
union sigval sigev_value; // signal value
};
//
// <termios.h>
//
#define TCSANOW 0
struct termios
{
long c_lflag;
};
#define ICANON 2 // do not change - correspond to ENABLE_LINE_INPUT / ENABLE_ECHO_INPUT
#define ECHO 4
extern int tcgetattr(int fd, struct termios* termios_p);
extern int tcsetattr(int fd, int optional_actions, const struct termios* termios_p);
//
// <sched.h>
//
struct sched_param
{
int sched_priority;
};
enum
{
SCHED_RR,
SCHED_FIFO,
SCHED_OTHER
};
#define sched_get_priority_max(policy) 15 // TIME_CRITICAL
#define sched_get_priority_min(policy) -15 // IDLE
//
// <pthread.h>
//
typedef unsigned int pthread_t;
extern pthread_t pthread_self();
extern int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param* param);
extern int pthread_create(pthread_t* thread, const void* attr, void*(*IMP)(void*), void* arg);
//
// <sys/socket.h>
//
typedef unsigned long socklen_t;
typedef unsigned short sa_family_t;
// Win32 values - do not change
#define SOCK_STREAM 1
#define SOCK_DGRAM 2
#define AF_INET 2
struct sockaddr;
//
// <netinet/in.h>
//
typedef unsigned long in_addr_t;
typedef unsigned short in_port_t;
struct in_addr
{
in_addr_t s_addr;
};
struct sockaddr_in
{
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[8];
};
#define INADDR_ANY 0
//
// <netdb.h>
//
struct hostent
{
char* h_name; // Official name of the host.
char** h_aliases; // A pointer to an array of pointers to
// alternative host names, terminated by a
// null pointer.
short h_addrtype; // Address type.
short h_length; // The length, in bytes, of the address.
char** h_addr_list; // A pointer to an array of pointers to network
// addresses (in network byte order) for the host,
// terminated by a null pointer.
};
IMP(struct hostent*, gethostbyname, (const char *name))
//
// <arpa/inet.h>
//
extern u16_t htons(u16_t hostshort);
#define ntohs htons
IMP(in_addr_t, inet_addr, (const char*))
IMP(char*, inet_ntoa, (in_addr))
IMP(int, accept, (int, struct sockaddr*, socklen_t*))
IMP(int, bind, (int, const struct sockaddr*, socklen_t))
IMP(int, connect, (int, const struct sockaddr*, socklen_t))
IMP(int, listen, (int, int))
IMP(ssize_t, recv, (int, void*, size_t, int))
IMP(ssize_t, send, (int, const void*, size_t, int))
IMP(int, socket, (int, int, int))
//
// <poll.h>
//
struct pollfd
{
int fd;
short int events, revents;
};
#define POLLIN 1
extern int poll(struct pollfd[], int, int);
//
// <sys/utsname.h>
//
struct utsname
{
char sysname[9]; // Name of this implementation of the operating system.
char nodename[16]; // Name of this node within an implementation-defined
// communications network.
// Win9x requires this minimum buffer size.
char release[9]; // Current release level of this implementation.
char version[16]; // Current version level of this release.
char machine[9]; // Name of the hardware type on which the system is running.
};
extern int uname(struct utsname*);
//
// serial port IOCTL
//
// use with TIOCMBIS
#define TIOCM_RTS 1
// use with TIOCMGET or TIOCMIWAIT
#define TIOCM_CD 0x80 // MS_RLSD_ON
#define TIOCM_CTS 0x10 // MS_CTS_ON
enum
{
TIOCMBIS, // set control line
TIOCMGET, // get line state
TIOCMIWAIT // wait for status change
};
extern int ioctl(int fd, int op, int* data);
extern void _get_console();
extern void _hide_console();
#include "posix/aio.h"
#ifdef __cplusplus
}
#endif
#endif // #ifndef __POSIX_H__

392
source/posix/aio.cpp Executable file
View File

@ -0,0 +1,392 @@
// POSIX asynchronous I/O
//
// 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 <cstdlib>
#include "posix.h"
#include "win.h"
#include "misc.h"
#include "types.h"
// Win32 functions require sector aligned transfers.
// updated by aio_open; changes don't affect aio_return
static u32 sector_size = 4096;
// async-capable handles to each lowio file
static HANDLE* aio_hs;
static uint hs_cap;
// information about active transfers (reused)
struct Req
{
// used to identify this request; != 0 <==> request valid
aiocb* cb;
OVERLAPPED ovl;
// hEvent signals when transfer complete
// read into a separate align buffer if necessary
// (note: unaligned writes aren't supported. see aio_rw)
u32 pad; // offset from starting sector
void* buf; // reused; resize if too small
u32 buf_size;
};
static const int MAX_REQS = 4;
static Req reqs[MAX_REQS];
static HANDLE open_mutex, reqs_mutex;
#define LOCK(what) WaitForSingleObject(what##_mutex, INFINITE);
#define UNLOCK(what) ReleaseMutex(what##_mutex);
// get async capable handle to file <fd>
// current implementation: open both versions of the file on open()
// wastes 1 handle/file, but we don't have to remember the filename/mode
static HANDLE aio_h(int fd)
{
if((unsigned)fd >= hs_cap)
return INVALID_HANDLE_VALUE;
return aio_hs[fd];
}
// find request slot currently in use by cb
// cb = 0 => search for empty slot
static Req* find_req(const aiocb* cb)
{
Req* r = reqs;
for(int i = 0; i < MAX_REQS; i++, r++)
if(r->cb == cb)
return r;
return 0;
}
static void cleanup(void)
{
uint i;
// close files
for(i = 0; i < hs_cap; i++)
{
HANDLE h = aio_h(i);
if(h != INVALID_HANDLE_VALUE)
CloseHandle(h);
}
free(aio_hs);
aio_hs = 0;
hs_cap = 0;
// free requests
Req* r = reqs;
for(i = 0; i < MAX_REQS; i++, r++)
{
r->cb = 0;
CloseHandle(r->ovl.hEvent);
r->ovl.hEvent = INVALID_HANDLE_VALUE;
free(r->buf);
r->buf = 0;
}
CloseHandle(open_mutex);
CloseHandle(reqs_mutex);
}
// called by first aio_open
static void init()
{
for(int i = 0; i < MAX_REQS; i++)
reqs[i].ovl.hEvent = CreateEvent(0,1,0,0); // manual reset
open_mutex = CreateMutex(0,0,0);
reqs_mutex = CreateMutex(0,0,0);
atexit(cleanup);
}
int aio_close(int fd)
{
HANDLE h = aio_h(fd);
if(h == INVALID_HANDLE_VALUE) // out of bounds or already closed
return -1;
CloseHandle(h);
aio_hs[fd] = INVALID_HANDLE_VALUE;
return 0;
}
// open fn in async mode; associate with fd (retrieve via aio_h(fd))
int aio_open(const char* fn, int mode, int fd)
{
LOCK(open)
ONCE(init())
// alloc aio_hs entry
if((unsigned)fd >= hs_cap)
{
uint hs_cap2 = fd+4;
HANDLE* aio_hs2 = (HANDLE*)realloc(aio_hs, hs_cap2*sizeof(HANDLE));
if(!aio_hs2)
{
UNLOCK(open)
return -1;
}
for(uint i = hs_cap; i < hs_cap2; i++)
aio_hs2[i] = INVALID_HANDLE_VALUE;
aio_hs = aio_hs2;
hs_cap = hs_cap2;
}
UNLOCK(open)
// interpret mode
u32 access = GENERIC_READ; // assume O_RDONLY
u32 share = 0;
if(mode & O_WRONLY)
access = GENERIC_WRITE;
else if(mode & O_RDWR)
access = GENERIC_READ|GENERIC_WRITE;
else
share = FILE_SHARE_READ;
u32 create = OPEN_EXISTING;
if(mode & O_CREAT)
create = (mode & O_EXCL)? CREATE_NEW : CREATE_ALWAYS;
u32 flags = FILE_FLAG_OVERLAPPED|FILE_FLAG_NO_BUFFERING|FILE_FLAG_SEQUENTIAL_SCAN;
// open file, store in aio_hs array
aio_hs[fd] = CreateFile(fn, access, share, 0, create, flags, 0);
if(aio_hs[fd] == INVALID_HANDLE_VALUE)
return -1;
// check drive's sector size (Win32 requires alignment)
char path[PATH_MAX];
realpath(fn, path);
path[3] = 0; // cut off after ?:\\
u32 spc, nfc, tnc; // don't need these
u32 sector_size2;
GetDiskFreeSpace(path, &spc, &sector_size2, &nfc, &tnc);
LOCK(open)
if(sector_size < sector_size2)
sector_size = sector_size2;
UNLOCK(open)
return 0;
}
// called by aio_read, aio_write, and lio_listio
// cb->aio_lio_opcode specifies desired operation
static int aio_rw(struct aiocb* cb)
{
if(!cb)
return -1;
if(cb->aio_lio_opcode == LIO_NOP)
return 0;
HANDLE h = aio_h(cb->aio_fildes);
if(h == INVALID_HANDLE_VALUE)
return -1;
LOCK(reqs)
// find free request slot
Req* r = find_req(0);
if(!r)
{
UNLOCK(reqs)
return -1;
}
r->cb = cb;
UNLOCK(reqs)
// align
r->pad = cb->aio_offset % sector_size; // offset to start of sector
const u32 ofs = cb->aio_offset - r->pad;
const u32 size = round_up((long)cb->aio_nbytes+r->pad, sector_size);
void* buf = cb->aio_buf;
if(r->pad || (long)buf % sector_size)
{
// current align buffer is too small - resize
if(r->buf_size < size)
{
void* buf2 = realloc(r->buf, size);
if(!buf2)
return -1;
r->buf = buf2;
r->buf_size = size;
}
// unaligned writes are not supported -
// we'd have to read padding, then write our data. ugh.
if(cb->aio_lio_opcode == LIO_WRITE)
return -1;
buf = r->buf;
}
r->ovl.Offset = ofs;
u32 status = (cb->aio_lio_opcode == LIO_READ)?
ReadFile(h, buf, size, 0, &r->ovl) : WriteFile(h, buf, size, 0, &r->ovl);
if(status || GetLastError() == ERROR_IO_PENDING)
return 0;
return -1;
}
int aio_read(struct aiocb* cb)
{
cb->aio_lio_opcode = LIO_READ;
return aio_rw(cb);
}
int aio_write(struct aiocb* cb)
{
cb->aio_lio_opcode = LIO_WRITE;
return aio_rw(cb);
}
int lio_listio(int mode, struct aiocb* const cbs[], int n, struct sigevent* se)
{
UNUSED(se)
for(int i = 0; i < n; i++)
aio_rw(cbs[i]); // aio_rw checks for 0 param
if(mode == LIO_WAIT)
aio_suspend(cbs, n, 0);
return 0;
}
// return status of transfer
int aio_error(const struct aiocb* cb)
{
Req* const r = find_req(cb);
if(!r)
return -1;
switch(r->ovl.Internal) // I/O status
{
case 0:
return 0;
case STATUS_PENDING:
return -EINPROGRESS;
// TODO: errors
default:
return -1;
}
}
// get bytes transferred. call exactly once for each op.
ssize_t aio_return(struct aiocb* cb)
{
Req* const r = find_req(cb);
if(!r)
return -1;
assert(r->ovl.Internal == 0 && "aio_return with transfer in progress");
// read wasn't aligned - need to copy to user's buffer
if(r->pad || (long)cb->aio_buf % sector_size)
memcpy(cb->aio_buf, (u8*)r->buf + r->pad, cb->aio_nbytes);
// free this request slot
r->cb = 0;
return (ssize_t)cb->aio_nbytes;
}
int aio_cancel(int fd, struct aiocb* cb)
{
UNUSED(cb)
const HANDLE h = aio_h(fd);
if(h == INVALID_HANDLE_VALUE)
return -1;
// Win32 limitation: can't cancel single transfers
CancelIo(h);
return AIO_CANCELED;
}
int aio_fsync(int, struct aiocb*)
{
return -1;
}
int aio_suspend(const struct aiocb* const cbs[], int n, const struct timespec* ts)
{
int cnt = 0; // actual number of valid cbs
HANDLE* hs = (HANDLE*)malloc(n*sizeof(HANDLE));
if(!hs)
return -1;
for(int i = 0; i < n; i++)
{
// ignore NULL list entries
if(!cbs[i])
continue;
Req* r = find_req(cbs[i]);
if(r)
hs[cnt++] = r->ovl.hEvent;
}
// timeout: convert timespec to ms (NULL ptr -> no timeout)
u32 timeout = INFINITE;
if(ts)
timeout = ts->tv_sec*1000 + ts->tv_nsec/1000000;
u32 status = WaitForMultipleObjects(cnt, hs, 0, timeout);
free(hs);
if(status == WAIT_TIMEOUT)
{
//errno = -EAGAIN;
return -1;
}
else if(status == WAIT_FAILED)
return -1;
return 0;
}

63
source/posix/aio.h Executable file
View File

@ -0,0 +1,63 @@
// POSIX asynchronous I/O
//
// 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/
// included by posix.h
// Note: for maximum efficiency, transfer buffers, offsets, and lengths
// should be sector aligned (otherwise, buffer is copied).
struct aiocb
{
int aio_fildes; // File descriptor.
off_t aio_offset; // File offset.
void* aio_buf; // Location of buffer.
size_t aio_nbytes; // Length of transfer.
int aio_reqprio; // Request priority offset.
struct sigevent aio_sigevent; // Signal number and value.
int aio_lio_opcode; // Operation to be performed.
};
enum
{
// aio_cancel return
AIO_ALLDONE, // None of the requested operations could be canceled since they are already complete.
AIO_CANCELED, // All requested operations have been canceled.
AIO_NOTCANCELED, // Some of the requested operations could not be canceled since they are in progress.
// lio_listio mode
LIO_WAIT, // wait until all I/O is complete
LIO_NOWAIT,
// lio_listio ops
LIO_NOP,
LIO_READ,
LIO_WRITE
};
extern int aio_cancel(int, struct aiocb*);
extern int aio_error(const struct aiocb*);
extern int aio_fsync(int, struct aiocb*);
extern int aio_read(struct aiocb*);
extern ssize_t aio_return(struct aiocb*);
extern int aio_suspend(const struct aiocb* const[], int, const struct timespec*);
extern int aio_write(struct aiocb*);
extern int lio_listio(int, struct aiocb* const[], int, struct sigevent*);
extern int aio_close(int fd);
extern int aio_open(const char* fn, int mode, int fd);

211
source/ps/BaseEntity.h Executable file
View File

@ -0,0 +1,211 @@
// base entity for all the Units and Buildings in the game 0AD
// written by Jacob Ricketts
#if !defined( __0AD_BASE_ENTITY_H_ )
#define __0AD_BASE_ENTITY_H_
#include "ai_common.h"
#include <vector>
#include <iostream>
class DLLExport CBaseEntity
{
public:
CBaseEntity( void ) { Clear(); };
virtual ~CBaseEntity( void ) { };
virtual void Clear( void ) { ClearBaseEntity(); };
//virtual bool Update( void ) = 0;
//virtual bool HandleMessage( const Message &msg ) = 0;
// === ID FUNCTIONS ===
inline
USHORT GetID( void ) { return( m_nID ); };
inline
USHORT GetTeamID( void ) { return( m_byteTeamID ); };
inline
BYTE AddAllies( BYTE bitflagTeams ) { return( m_bitflagAllies |= bitflagTeams ); };
inline
BYTE RemoveAllies( BYTE bitflagTeams ) { return( m_bitflagAllies &= ~bitflagTeams ); };
// === HIT POINT FUNCTIONS ===
inline
virtual USHORT GetHitPoints( void ) { std::cout << "CBaseEntity.GetHitPoints() called..." << endl; return( m_nHitPoints ); };
inline
virtual USHORT GetBaseHitPoints( void ) { return( m_nBaseHitPoints ); };
inline
virtual USHORT GetMaxHitPoints( void ) { return( m_nMaxHitPoints ); };
inline
virtual short GetRegenRate( void ) { return( m_nBaseRegenRate ); };
// === ATTACK STAT FUNCTIONS ===
inline
virtual USHORT GetAttackStrength( void ) { return( m_nBaseAttackStrength ); };
inline
virtual USHORT GetAttackRate( void ) { return( m_nBaseAttackRate ); };
inline
virtual USHORT GetAreaOfEffect( void ) { return( m_nBaseAreaOfEffect ); };
inline
virtual USHORT GetMaxRange( void ) { return( m_nBaseMaxRange ); };
inline
virtual USHORT GetMinRange( void ) { return( m_nBaseMinRange ); };
inline
virtual USHORT GetMeleeArmor( void ) { return( m_nBaseMeleeArmor ); } ;
inline
virtual USHORT GetPierceArmor( void ) { return( m_nBasePierceArmor ); };
// === MISC ATTRIBUTES ===
inline
virtual const std::vector<USHORT>& AvailableToCivs( void ) { return( m_vAvailableToCivs ); };
inline
virtual const Vector3D& GetPosition( void ) { return( m_vPos ); };
inline
virtual bool BoostsMorale( void ) { return( m_bBoostsMorale ); };
inline
virtual bool DemoralizesEnemies( void ) { return( m_bDemoralizesEnemies ); };
inline
virtual USHORT GetActionRate( void ) { return( m_nBaseActionRate ); };
inline
virtual USHORT GetAreaOfInfluence( void ) { return( m_nBaseAreaOfInfluence ); };
inline
virtual USHORT GetLOS( void ) { return( m_nBaseLOS ); };
// === BUILD STATS ===
inline
virtual USHORT GetBuildTime( void ) { return( m_nBuildTime ); };
inline
virtual USHORT GetReqFoodToBuild( void ) { return( m_nFoodReqToBuild ); };
inline
virtual USHORT GetReqGoldToBuild( void ) { return( m_nGoldReqToBuild ); };
inline
virtual USHORT GetReqMetalToBuild( void ) { return( m_nMetalReqToBuild ); };
inline
virtual USHORT GetReqStoneToBuild( void ) { return( m_nStoneReqToBuild ); };
inline
virtual USHORT GetReqWoodToBuild( void ) { return( m_nWoodReqToBuild ); };
inline
virtual const std::vector<USHORT>& GetBuildingsReqToBuild( void ) { return( m_vBuildingsReqToBuild ); };
inline
virtual const std::vector<USHORT>& GetTechsReqToBuild( void ) { return( m_vTechsReqToBuild ); };
// === UPGRADE STATS ===
inline
virtual USHORT UpgradesTo( void ) { return( m_nUpgradesTo ); };
inline
virtual USHORT GetUpgradeTime( void ) { return( m_nUpgradeTime ); };
inline
virtual USHORT GetReqFoodToUpgrade( void ) { return( m_nFoodReqToUpgrade ); };
inline
virtual USHORT GetReqGoldToUpgrade( void ) { return( m_nGoldReqToUpgrade ); };
inline
virtual USHORT GetReqMetalToUpgrade( void ) { return( m_nMetalReqToUpgrade ); };
inline
virtual USHORT GetReqStoneToUpgrade( void ) { return( m_nStoneReqToUpgrade ); };
inline
virtual USHORT GetReqWoodToUpgrade( void ) { return( m_nWoodReqToUpgrade ); };
inline
virtual const std::vector<USHORT>& GetBuildingsReqToUpgrade( void ) { return( m_vBuildingsReqToUpgrade ); };
inline
virtual const std::vector<USHORT>& GetTechsReqToUpgrade( void ) { return( m_vTechsReqToUpgrade ); };
BYTE m_nCurrentFrame;
protected:
void ClearBaseEntity( void );
USHORT m_nID; // ID for this entity
BYTE m_byteTeamID; // ID of the team this entity is on
BYTE m_bitflagAllies; // bitflag to contain the list of allies
std::vector<USHORT> m_vAvailableToCivs; // a list of Civs that can create this entity
// === ATTRIBUTES ===
USHORT m_nHitPoints; // current amount of hit points
USHORT m_nBaseHitPoints; // initial hit points
USHORT m_nMaxHitPoints; // maximum hit points
short m_nBaseRegenRate; // rate of health regeneation
USHORT m_nBaseAttackStrength; // base strength
USHORT m_nBaseAttackRate; // rate of attack
USHORT m_nBaseMinRange; // minimum range of attack
USHORT m_nBaseMaxRange; // maximum range of attack
USHORT m_nBaseActionRate; // rate of actions
USHORT m_nBaseAreaOfEffect; // area of effect
USHORT m_nBaseAreaOfInfluence; // area of influence
USHORT m_nBaseMeleeArmor; // armor rating against melee attacks
USHORT m_nBasePierceArmor; // armor rating against projectile attacks
USHORT m_nBaseLOS; // line of sight distance
USHORT m_nBuildTime; // time required to build
USHORT m_nUpgradeTime; // time required to upgrade
USHORT m_nFoodReqToBuild; // amount of food required to build
USHORT m_nGoldReqToBuild; // amount of gold required to build
USHORT m_nMetalReqToBuild; // amount of metal required to build
USHORT m_nStoneReqToBuild; // amount of stone required to build
USHORT m_nWoodReqToBuild; // amount of wood required to build
std::vector<USHORT> m_vBuildingsReqToBuild; // buildings required to build this entity
std::vector<USHORT> m_vTechsReqToBuild; // techs required to build this entity
USHORT m_nFoodReqToUpgrade; // cost to upgrade (food)
USHORT m_nGoldReqToUpgrade; // cost to upgrade (gold)
USHORT m_nMetalReqToUpgrade; // cost to upgrade (metal)
USHORT m_nStoneReqToUpgrade; // cost to upgrade (stone)
USHORT m_nWoodReqToUpgrade; // cost to upgrade (wood)
std::vector<USHORT> m_vBuildingsReqToUpgrade; // buildings required to upgrade this entity
std::vector<USHORT> m_vTechsReqToUpgrade; // techs required to upgrade this entity
USHORT m_nUpgradesTo; // ID of entity this unit will upgrade to if possible
bool m_bBoostsMorale; // does this entity boost Morale?
bool m_bDemoralizesEnemies; // does this entity demoralize enemy units?
Vector3D m_vPos; // position on the map
private:
};
#endif

155
source/ps/CStr.h Executable file
View File

@ -0,0 +1,155 @@
/*
CStr.h
by Caecus
Caecus@0ad.wildfiregames.com
Overview:
Contains CStr class which is a versatile class for making string use easy.
Basic functionality implemented via STL string, so performance is limited
based on the STL implementation we use.
Example:
CStr MyString = _T("Hello, World.");
_int MyNum = 126;
MyString += _T(" I'm the number ") += CStr(MyNumber);
// Prints "Hello, World. I'm the number 126"
_tcout << (LPCTSTR)MyString << endl;
MyString = _("2341");
MyNum = MyString.ToInt();
// Prints "2341"
_tcout << MyNum << endl;
More Info:
http://wildfiregames.com/0ad/codepit/TDD/CStr.html
*/
#ifndef CSTR_H
#define CSTR_H
#include "Prometheus.h"
#include <string> // Used for basic string functionality
#include <iostream>
#include <windows.h>
#include <TCHAR.h> // TCHAR of course
#include <cstdlib>
using namespace std;
// DEFINES/ENUMS
#define CONVERSION_BUFFER_SIZE 32
#define FLOAT_CONVERSION _T("%.6f")
#ifdef _UNICODE
typedef wstring tstring;
#define _tcout wcout
#define _tstod wcstod
#else
typedef string tstring;
#define _tcout cout
#define _tstod strtod
#endif
enum PS_TRIM_MODE {PS_TRIM_LEFT, PS_TRIM_RIGHT, PS_TRIM_BOTH};
// CStr class, the mother of all strings
class CStr
{
public:
// CONSTRUCTORS
CStr(); // Default constructor
CStr(const CStr &Str); // Copy Constructor
CStr(tstring String); // Creates CStr from C++ string
CStr(LPCTSTR String); // Creates CStr from C-Style TCHAR string
CStr(TCHAR Char); // Creates CStr from a TCHAR
CStr(_int Number); // Creates CStr from a int
CStr(_uint Number); // Creates CStr from a uint
CStr(_long Number); // Creates CStr from a long
CStr(_ulong Number); // Creates CStr from a ulong
CStr(_float Number); // Creates CStr from a float
CStr(_double Number); // Creates CStr from a double
~CStr(); // Destructor
// Conversions
_int ToInt();
_uint ToUInt();
_long ToLong();
_ulong ToULong();
_float ToFloat();
_double ToDouble();
_long Length(){return m_String.length();}
// Retrieves the substring within the string
CStr GetSubstring(_long start, _long len);
//Search the string for another string
_long Find(const CStr &Str);
//You can also do a "ReverseFind"- i.e. search starting from the end
_long ReverseFind(const CStr &Str);
// Lowercase and uppercase
CStr LowerCase();
CStr UpperCase();
// Lazy funcs
CStr LCase();
CStr UCase();
// Retreive the substring of the first n characters
CStr Left(_long len);
// Retreive the substring of the last n characters
CStr Right(_long len);
//Remove all occurences of some character or substring
void Remove(const CStr &Str);
//Replace all occurences of some substring by another
void Replace(const CStr &StrToReplace, const CStr &ReplaceWith);
// Returns a trimed string, removes whitespace from the left/right/both
CStr Trim(PS_TRIM_MODE Mode);
// Overload operations
CStr &operator=(const CStr &Str);
CStr &operator=(LPCTSTR String);
CStr &operator=(TCHAR Char);
CStr &operator=(_int Number);
CStr &operator=(_long Number);
CStr &operator=(_uint Number);
CStr &operator=(_ulong Number);
CStr &operator=(_float Number);
CStr &operator=(_double Number);
_bool operator==(const CStr &Str) const;
_bool operator!=(const CStr &Str) const;
_bool operator<(const CStr &Str) const;
_bool operator<=(const CStr &Str) const;
_bool operator>(const CStr &Str) const;
_bool operator>=(const CStr &Str) const;
CStr &operator+=(CStr &Str);
CStr operator+(CStr &Str);
operator LPCTSTR();
TCHAR &operator[](_int n);
TCHAR &operator[](_uint n);
TCHAR &operator[](_long n);
TCHAR &operator[](_ulong n);
private:
tstring m_String;
TCHAR m_ConversionBuffer[CONVERSION_BUFFER_SIZE];
};
// overloaded operator for ostreams
ostream &operator<<(ostream &os, CStr &Str);
#endif

86
source/ps/Encryption.cpp Executable file
View File

@ -0,0 +1,86 @@
// last modified Friday, May 09, 2003
#include "Encryption.h"
//--------------------------------------------------------------------
// EncryptData - Takes A pointer to data in memory, the length of that data,
// Along with a key in memory and its length. It will allocated space
// for the encrypted copy of the data via new[], It is the responsiblity of the user
// to call delete[].
//--------------------------------------------------------------------
_byte *EncryptData(_byte *Data, _long DataLength, _byte *Key, _long KeyLength)
{
// Allocate space for new Encrypted data
_byte *NewData = new _byte[DataLength];
// A counter to hold our absolute position in data
_long DataOffset = 0;
// Loop through Data until end is reached
while (DataOffset < DataLength)
{
// Loop through the key
for (_long KeyOffset = 0; KeyOffset < KeyLength; KeyOffset++)
{
// If were at end of data break and the the while loop should end as well.
if (DataOffset >= DataLength)
break;
// Otherwise Add the previous element of the key from the newdata
// (just something a little extra to confuse the hackers)
if (KeyOffset > 0) // Don't mess with the first byte
NewData[DataOffset] += Key[KeyOffset - 1];
// Xor the Data byte with the key byte and get new data
NewData[DataOffset] = Data[DataOffset] ^ Key[KeyOffset];
// Increase position in data
DataOffset++;
}
}
// return the new data
return NewData;
}
//--------------------------------------------------------------------
// DecryptData - Takes A pointer to data in memory, the length of that data,
// Along with a key in memory and its length. It will allocated space
// for the decrypted copy of the data via new[], It is the responsiblity of the user
// to call delete[].
//--------------------------------------------------------------------
_byte *DecryptData(_byte *Data, _long DataLength, _byte *Key, _long KeyLength)
{
// Allocate space for new Decrypted data
_byte *NewData = new _byte[DataLength];
// A counter to hold our absolute position in data
_long DataOffset = 0;
// Loop through Data until end is reached
while (DataOffset < DataLength)
{
// Loop through the key
for (_long KeyOffset = 0; KeyOffset < KeyLength; KeyOffset++)
{
// If were at end of data break and the the while loop should end as well.
if (DataOffset >= DataLength)
break;
// Otherwise Xor the Data byte with the key byte and get new data
NewData[DataOffset] = Data[DataOffset] ^ Key[KeyOffset];
// Subtract the previous element of the key from the newdata
// (just something a little extra to confuse the hackers)
if (KeyOffset > 0) // Don't mess with the first byte
NewData[DataOffset] -= Key[KeyOffset - 1];
// Increase position in data
DataOffset++;
}
}
// return the new data
return NewData;
}

30
source/ps/Encryption.h Executable file
View File

@ -0,0 +1,30 @@
/*
Encryption.h
by Caecus
caecus18@hotmail.com
Two simple functions for encrypting and decrypting data. The KeyLength is
specified in bytes, therefore Keys must be in multiples of 8 bits. I'd
advice using 128bit keys which you can define as such.
_byte MyKey[16] = { _byte(0xAF), _byte(0x2B), _byte(0x80), _byte(0x7E),
_byte(0x09), _byte(0x23), _byte(0xCC), _byte(0x95),
_byte(0xB4), _byte(0x2D), _byte(0xF4), _byte(0x90),
_byte(0xB3), _byte(0xC4), _byte(0x2A), _byte(0x3B) };
There may be a better way to do this but this looks alright to me.
*/
#include "Prometheus.h"
#ifndef ENCRYPTION_H
#define ENCRYPTION_H
// Simple Encryption function
_byte *EncryptData(_byte *Data, _long DataLength, _byte *Key, _long KeyLength);
// Simple Decryption function
_byte *DecryptData(_byte *Data, _long DataLength, _byte *Key, _long KeyLength);
#endif

157
source/ps/Error.h Executable file
View File

@ -0,0 +1,157 @@
//////////////////////////////////////////////////////////////////////////////
// AUTHOR: Michael Reiland
// FILENAME: Error.h
// PURPOSE: Provides a simple Error Mechanism
//
// USEAGE:
// SetError_Long(PS_FAIL,"A Sample Error",__FILE__,__LINE__);
// SetError_Short(PS_FAIL,"A Sample Error");
// TestError(PS_FAIL);
//
// TODO: Figure out how we're going to clean up and exit upon failure of
// SetError()
//
// MODIFIED: 07.20.2003 mreiland
#ifndef _ERROR_H_
#define _ERROR_H_
#include "Singleton.h"
#include "Prometheus.h"
#include <string>
// Used to specify Null pointers.
const int NullPtr = 0;
/****************************************************************************/
// USER DEFINED TYPES //
/****************************************************************************/
//////////////////////////////////////////////////////////////////////////////
//
// NAME: CError
// PURPOSE: Encapsulation of the data for our error framework.
//
class CError
{
public:
PS_RESULT ErrorName; // Actual name of the error
std::string Description; // Description of the error
std::string FileName; // File where the error occured
unsigned int LineNumber; // Line where the file occured
CError()
:ErrorName(NullPtr), LineNumber(-1){;}
};
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
// NAME: ErrorMechanism
// PURPOSE: Provides the interface for the Error mechanism we are using. It's
// implemented as a singleton so that only one framework is in
// existence at one time.
//
class ErrorMechanism : Singleton<ErrorMechanism>
{
public:
inline bool ErrorMechanism_Error();
inline void ErrorMechanism_ClearError();
inline bool ErrorMechanism_TestError( PS_RESULT);
inline void ErrorMechanism_SetError(
PS_RESULT,
std::string,
std::string,
unsigned int);
inline CError ErrorMechanism_GetError();
private:
CError ErrorVar;
};
//////////////////////////////////////////////////////////////////////////////
/******************************************************************************/
// FUNCTION DEFINITIONS //
/******************************************************************************/
//////////////////////////////////////////////////////////////////////////////
//
// Tests if an error exists. If so, returns true
//
bool ErrorMechanism::ErrorMechanism_Error()
{
return ( ErrorVar.ErrorName != NullPtr );
}
//////////////////////////////////////////////////////////////////////////////
//
// The error has been dealt with, and needs to be cleared.
//
void ErrorMechanism::ErrorMechanism_ClearError()
{
ErrorVar.ErrorName = NullPtr;
}
//////////////////////////////////////////////////////////////////////////////
//
// Checks if the error passed in is the error that's occurred
//
bool ErrorMechanism::ErrorMechanism_TestError( PS_RESULT TErrorName)
{
return ( ErrorVar.ErrorName == TErrorName );
}
//////////////////////////////////////////////////////////////////////////////
//
// Set's an error that's just occured.
//
void ErrorMechanism::ErrorMechanism_SetError( PS_RESULT TErrorName, std::string TDescription,
std::string TFileName, unsigned int TLineNumber)
{
if( ErrorMechanism::ErrorVar.ErrorName == NullPtr )
{
ErrorVar.ErrorName = TErrorName;
ErrorVar.Description = TDescription;
ErrorVar.FileName = TFileName;
ErrorVar.LineNumber = TLineNumber;
}
else
{
// We need to clean up properly and exit.
exit(EXIT_FAILURE);
}
}
//////////////////////////////////////////////////////////////////////////////
//
// Getter for the error
//
CError ErrorMechanism::ErrorMechanism_GetError()
{
return ErrorVar;
}
#endif

355
source/ps/LogFile.cpp Executable file
View File

@ -0,0 +1,355 @@
// last modified Thursday, May 08, 2003
#include "LogFile.h"
//-------------------------------------------------
//Add a hyperlink to Link.
//-------------------------------------------------
PS_RESULT CLogFile::AddLink(string LinkText,string Link, string Colour)
{
if(m_IsFileOpen)
{
m_TheFile << "<a href=" << Link << "><font color=" << Colour << ">" << LinkText << "</font></a><br>";
}
else
{
return PS_FAIL;
}
return PS_OK;
}
//-------------------------------------------------
//Standard destructor.
//-------------------------------------------------
CLogFile::~CLogFile()
{
if(m_IsFileOpen)
{
m_TheFile << "</font></body></html>";
m_TheFile.close();
if(m_HasFrame)
{
m_ErrorFile.close();
}
m_IsFileOpen = false;
}
}
//-------------------------------------------------
//Standard constructor.
//-------------------------------------------------
CLogFile::CLogFile()
{
m_CurrentColour = "Black";
m_IsFileOpen = false;
}
//-------------------------------------------------
// Constructor that opens a file.
// 3rd parameter determines whether the error frame is shown.
//-------------------------------------------------
CLogFile::CLogFile(string FileName, string PageTitle, _bool WithFrame)
{
Open(FileName,PageTitle,WithFrame);
m_IsFileOpen = true;
}
//-------------------------------------------------
//Closes the open files, if open.
//-------------------------------------------------
PS_RESULT CLogFile::Close()
{
if(m_IsFileOpen)
{
m_CurrentColour = "Black";
m_TheFile << "</font></body></html>";
m_TheFile.close();
if(m_HasFrame)
{
m_ErrorFile.close();
}
m_IsFileOpen = false;
}
else
{
return PS_FAIL;
}
return PS_OK;
}
//-------------------------------------------------
//Inserts a horzontal divide in the page.
//-------------------------------------------------
PS_RESULT CLogFile::InsertDivide()
{
if(m_IsFileOpen)
{
m_TheFile << "<hr>";
}
else
{
return PS_FAIL;
}
return PS_OK;
}
//-------------------------------------------------
//Opens an error file. If WithFrame is true then it constructs a framed page.
//-------------------------------------------------
PS_RESULT CLogFile::Open(string FileName, string PageTitle, _bool WithFrame)
{
if(m_IsFileOpen)
return PS_FAIL;
m_HasFrame=false;
m_CurrentColour = "Black";
//If there are no frames then create a normal page.
if(!WithFrame)
{
FileName = FileName + ".html";
m_TheFile.open(FileName.c_str());
m_TheFile << "<html><head><title>" << PageTitle << "</title></head><body><font color = black>";
}
else
{
//Open a temporary file to write the frameset.
ofstream TempStream;
string TempString;
TempString = FileName;
TempString = FileName + ".html";
TempStream.open(TempString.c_str());
FileName = FileName + "b.html";
//Write the proper details to the frame file.
TempStream << "<html><head><title>" << PageTitle << "</title></head>";
TempStream << "<frameset frameborder = 1 framespacing = 1 frameborder=yes border=1 rows=70,*>";
TempStream << "<frame src=ErrorLinks.html name =title scrolling =yes><frame src=";
TempStream << FileName << " name =main scrolling=yes ></frameset>";
TempStream << "</frameset></html>";
TempStream.close();
//Open the two pages to be displayed within the frames.
m_TheFile.open(FileName.c_str());
m_ErrorFile.open("ErrorLinks.html");
m_FileName = FileName.c_str();
//Start writing the two pages that will be displayed.
m_TheFile << "<html><head><title>" << PageTitle << "</title></head><body><font color = black>";
m_ErrorFile << "<html><head><title>" << PageTitle << "</title><BASE TARGET=main></head><body><font color = black>";
m_HasFrame = true;
m_ErrNo = 0;
}
m_IsFileOpen = true;
return PS_OK;
}
//-------------------------------------------------
//Sets the current alignment.
//-------------------------------------------------
PS_RESULT CLogFile::SetAlignment(PS_TEXT_ALIGN Align)
{
if(m_IsFileOpen)
{
switch(Align){
case PS_ALIGN_LEFT:
m_TheFile << "<p align = left>";
break;
case PS_ALIGN_CENTER:
m_TheFile << "<p align = center>";
break;
case PS_ALIGN_RIGHT:
m_TheFile << "<p align = right>";
break;
}
}
else
{
return PS_FAIL;
}
return PS_OK;
}
//-------------------------------------------------
//Changes the current colour.
//-------------------------------------------------
PS_RESULT CLogFile::SetColour(string ColourName)
{
if(m_IsFileOpen)
{
m_CurrentColour = ColourName;
m_TheFile << "</font><font color=" << m_CurrentColour << ">";
}
else
{
return PS_FAIL;
}
return PS_OK;
}
//-------------------------------------------------
//Writes an error, always in red.
//-------------------------------------------------
PS_RESULT CLogFile::WriteError(string Text, PS_DISPLAY_SETTINGS displayOptions)
{
if(m_IsFileOpen)
{
//If there is a frame then add an anchor and link to the appropriate places.
if(m_HasFrame)
{
m_TheFile << "<a name=" << m_ErrNo << "></a>";
m_ErrorFile << "<a href=" << m_FileName << "#" << m_ErrNo << ">Error: " << m_ErrNo << "</a><br>";
m_ErrNo++;
}
m_TheFile << "</font><font color=red>" << Line(displayOptions) << Text << Date(displayOptions) << "</font><font color =" << m_CurrentColour << "><br>";
}
else
{
return PS_FAIL;
}
return PS_OK;
}
PS_RESULT CLogFile::WriteError(string Text, PS_TEXT_ALIGN Align, PS_DISPLAY_SETTINGS displayOptions)
{
if(m_IsFileOpen)
{
SetAlignment(Align);
//If there is a frame then add an anchor and link to the appropriate places.
if(m_HasFrame)
{
m_TheFile << "<a name=" << m_ErrNo << "></a>";
m_ErrorFile << "<a href=" << m_FileName << "#" << m_ErrNo << ">Error: " << m_ErrNo << "</a><br>";
m_ErrNo++;
}
m_TheFile << "</font><font color=red>" << Line(displayOptions) << Text << Date(displayOptions) << "</font></p><font color =" << m_CurrentColour << "><br>";
}
else
{
return PS_FAIL;
}
return PS_OK;
}
//-------------------------------------------------
//Writes a header in larger text.
//-------------------------------------------------
PS_RESULT CLogFile::WriteHeader(string Text, PS_DISPLAY_SETTINGS displayOptions)
{
if(m_IsFileOpen)
{
m_TheFile << "</font><font size=6 color= " << m_CurrentColour << ">"
<< Line(displayOptions) << Text << Date(displayOptions) << "</font><font size =3><br>";
}
else
{
return PS_FAIL;
}
return PS_OK;
}
//-------------------------------------------------
//Writes a header in larger text, with alignment.
//-------------------------------------------------
PS_RESULT CLogFile::WriteHeader(string Text, PS_TEXT_ALIGN Align, PS_DISPLAY_SETTINGS displayOptions)
{
if(m_IsFileOpen)
{
SetAlignment(Align);
m_TheFile << "</font><font size=6 color=" << m_CurrentColour << ">"
<< Line(displayOptions) << Text << Date(displayOptions) << "</font></p><font size =3><br>";
}
else
{
return PS_FAIL;
}
return PS_OK;
}
//-------------------------------------------------
//Write a normal string.
//-------------------------------------------------
PS_RESULT CLogFile::WriteText(string Text, PS_DISPLAY_SETTINGS displayOptions)
{
if(m_IsFileOpen)
{
m_TheFile << Line(displayOptions) << Text << Date(displayOptions) << "<br>";
}
else
{
return PS_FAIL;
}
return PS_OK;
}
//-------------------------------------------------
//Write a normal string, with alignment.
//-------------------------------------------------
PS_RESULT CLogFile::WriteText(string Text, PS_TEXT_ALIGN Align, PS_DISPLAY_SETTINGS displayOptions)
{
if(m_IsFileOpen)
{
SetAlignment(Align);
m_TheFile << Line(displayOptions) << Text << Date(displayOptions) << "</p><br>";
}
else
{
return PS_FAIL;
}
return PS_OK;
}
//-------------------------------------------------
//Retrieve a string to display the line number
//-------------------------------------------------
string CLogFile::Line(const PS_DISPLAY_SETTINGS &options)
{
string lineText;
if (options.displayMode == PS_DISPLAY_MODE_SHOW_LINE_NUMBER )
{
lineText = options.file;
char temp[8];
itoa(options.line, temp, 10);
lineText += ", Line ";
lineText += temp;
lineText += ": ";
}
return lineText;
}
//-------------------------------------------------
//Retrieve a string to display the date
//-------------------------------------------------
string CLogFile::Date(const PS_DISPLAY_SETTINGS &options)
{
string dateText;
if (options.displayMode == PS_DISPLAY_MODE_SHOW_DATE )
{
dateText = "<font color=#AAAAAA> &nbsp;&nbsp;(";
dateText += options.date;
dateText += ")</font>";
}
return dateText;
}

155
source/ps/LogFile.h Executable file
View File

@ -0,0 +1,155 @@
/*
Log File Writer.
by Mark Ellis
mark@markdellis.co.uk
--Overview--
Writes specified output to a formatted html file.
--Usage--
First open a file for writing using either the constructor
or the Open() function. Then use the formatting functions to
write to the HTML file. You may use Close() but the destructor
will handle all cleanup of the class.
You can enable a frame at the top of the page that will link to the errors,
this is enabled by passing true as the 3rd parameter when opening.
--More Info--
http://wildfiregames.com/0ad/codepit/tdd/logfile.html
*/
#ifndef LOGFILE_H
#define LOGFILE_H
//--------------------------------------------------------
// Includes / Compiler directives
//--------------------------------------------------------
#include "Prometheus.h"
#include <string>
#include <fstream>
using std::string;
using std::ofstream;
//--------------------------------------------------------
// Macros
//--------------------------------------------------------
// Extra parameters for displaying text
#define PS_SHOW_LINE_NUMBER PS_DISPLAY_SETTINGS ( __LINE__, __FILE__, __DATE__, PS_DISPLAY_MODE_SHOW_LINE_NUMBER )
#define PS_SHOW_DATE PS_DISPLAY_SETTINGS ( __LINE__, __FILE__, __DATE__, PS_DISPLAY_MODE_SHOW_DATE )
#define PS_NONE PS_DISPLAY_SETTINGS ( __LINE__, __FILE__, __DATE__, PS_DISPLAY_MODE_NONE )
//-------------------------------------------------
// Types
//-------------------------------------------------
enum PS_DISPLAY_MODE { PS_DISPLAY_MODE_SHOW_LINE_NUMBER,
PS_DISPLAY_MODE_SHOW_DATE,
PS_DISPLAY_MODE_NONE };
enum PS_TEXT_ALIGN { PS_ALIGN_LEFT, PS_ALIGN_CENTER, PS_ALIGN_RIGHT };
//-------------------------------------------------
// Declarations
//-------------------------------------------------
class PS_DISPLAY_SETTINGS
{
public:
PS_DISPLAY_SETTINGS(_int Line, _char *File, _char *Date, PS_DISPLAY_MODE DisplayMode)
{
line=Line;
file=File;
date=Date;
displayMode=DisplayMode;
}
_int line;
_char *file;
_char *date;
PS_DISPLAY_MODE displayMode;
};
class CLogFile
{
public:
//Standard Constructor and destructor.
CLogFile();
~CLogFile();
CLogFile(string FileName, string PageTitle, _bool WithFrame=false);
//Opens a file for output the 3rd parameter can be set to true to enable the error frame.
PS_RESULT Open(string FileName, string PageTitle, _bool WithFrame=false);
//Closes the file.
PS_RESULT Close();
//The following functions edit the html file.
//Writes a header to the file.
PS_RESULT WriteHeader(string Text, PS_DISPLAY_SETTINGS displayOptions=PS_NONE);
//Writes a header to the file. Align can be 0=left, 1=centre, 2=left
PS_RESULT WriteHeader(string Text, PS_TEXT_ALIGN Align, PS_DISPLAY_SETTINGS displayOptions=PS_NONE);
//Writes some text to the file.
PS_RESULT WriteText(string Text, PS_DISPLAY_SETTINGS displayOptions=PS_NONE);
//Writes some text at a specified alignment.
PS_RESULT WriteText(string Text, PS_TEXT_ALIGN Align, PS_DISPLAY_SETTINGS displayOptions=PS_NONE);
//Writes an error - in red.
PS_RESULT WriteError(string Text, PS_DISPLAY_SETTINGS displayOptions=PS_NONE);
//Writes an aligned error.
PS_RESULT WriteError(string Text, PS_TEXT_ALIGN Align, PS_DISPLAY_SETTINGS displayOptions=PS_NONE);
//Inserts a page break.
PS_RESULT InsertDivide();
//Sets the current colour to colourname.
PS_RESULT SetColour(string ColourName);
//Adds a hyperlink.
PS_RESULT AddLink(string LinkText, string Link, string Colour);
private:
_bool m_IsFileOpen; //Is the file open.
_bool m_HasFrame; //Have frames been enabled.
ofstream m_TheFile; //The main file.
ofstream m_ErrorFile; //The error link file, used only for frames.
string m_CurrentColour; //The current colour.
string m_FileName; //The name of the main file.
_int m_ErrNo; //The error number.
//Sets the current alignment of the text.
PS_RESULT SetAlignment(PS_TEXT_ALIGN Align);
//Writes the current line of text
string Line(const PS_DISPLAY_SETTINGS &options);
//Writes today's date
string Date(const PS_DISPLAY_SETTINGS &options);
};
#endif

246
source/ps/MathUtil.cpp Executable file
View File

@ -0,0 +1,246 @@
// last modified Thursday, May 08, 2003
#include <time.h>
#include <cstdlib>
#include "MathUtil.h"
// MathUtil Errors
DEFINE_ERROR(ERRONEOUS_BOUND_ERROR, "Lower Bound is >= Upper Bound");
//////////////////////////////////////////////////////////////////////
// NAME: CompareFloat
// PURPOSE: Returns true if two floating point numbers are within
// FL_FP_TOLERANCE of each other.
//
_bool MathUtil::CompareFloat(const _double &num1, const _double &num2)
{
if( Abs(num1 - num2) < FL_FP_TOLERANCE )
return true;
else
return false;
}
//////////////////////////////////////////////////////////////////////
// NAME: RadiansToDegrees
// PURPOSE: Converts from Radians to Degrees
//
inline _double MathUtil::RadiansToDegrees(const _double &num)
{
return num*(PI/180);
}
//////////////////////////////////////////////////////////////////////
// NAME: RadiansToDegrees
// PURPOSE: Converts from Degrees to Radians
//
inline _double MathUtil::DegreesToRadians(const _double &num)
{
return (num*180)/PI;
}
/*
//////////////////////////////////////////////////////////////////////
// NAME: Random
// PURPOSE: returns a random floating point number between lowerBound
// and upperBound
// NOTES: returns -1 if lowerBound >= upperBound
//
_float MathUtil::Random(const _float &lowerBound, const _float &upperBound)
{
if( lowerBound >= upperBound)
return -1;
else
{
// seed generator with current time
srand( static_cast<unsigned>( time(NULL) ) );
// finds a floating point number between 0 and 1.0
_float randVar = ( static_cast<_float>( rand() )/RAND_MAX );
// maps the number onto the set from 0 to upperBound
randVar *= Abs(lowerBound - upperBound ) + 1;
//translate to the proper range
randVar += lowerBound;
return randVar;
}
}
//////////////////////////////////////////////////////////////////////
// NAME: Random
// PURPOSE: returns a random number between lowerBound and upperBound
// NOTES: returns -1 if lowerBound >= upperBound
//
_int MathUtil::Random(const _int &lowerBound,const _int &upperBound)
{
if( lowerBound >= upperBound)
return -1;
else
{
// seed generator with current time
srand( static_cast<unsigned>( time(NULL) ) );
// find a random variable between 0 and range size
_int randVar = rand()%( Abs(upperBound - lowerBound) + 1);
// translate to proper range
randVar += lowerBound;
return randVar;
}
}
*/
//////////////////////////////////////////////////////////
// NAME: Round
// PURPOSE: Rounds a number.
// NOTES: Round rounds to the nearest representable number
// float version.
//
_int MathUtil::Round(const float &num)
{
if( num > 0 )
return static_cast<_int>(num + .5);
else if (num < 0 )
return static_cast<_int>(num - .5);
else
return 0;
}
//////////////////////////////////////////////////////////
// NAME: Round
// PURPOSE: Rounds a number.
// NOTES: Round rounds to the nearest representable number
// double version.
//
_int MathUtil::Round(const double &num)
{
if( num > 0 )
return static_cast<_int>(num + .5);
else if (num < 0 )
return static_cast<_int>(num - .5);
else
return 0;
}
//////////////////////////////////////////////////////////////////////
// NAME: SignedModulus
// PURPOSE: returns a mathematically correct modulus for int
//
_int MathUtil::SignedModulus(const _int &num, const _int &n)
{
if( num >= 0 )
return num%n;
else
{
// the % operator reflects the range if num < 0, so
// we have to multiply by -1 to reflect it back. This method
// is faster than calling Abs() and then doing the modulus.
_int Tnum = -1*(num%n);
// if num%n equals 0, then n - Tnum will be n, which, logically
// speaking, is 0 in a different form, but we have to make sure it's
// in the form 0, and not n. Therefore, if Tnum = 0, simply leave
// it like that.
if( Tnum != 0)
Tnum = n - Tnum;
return Tnum;
}
}
//////////////////////////////////////////////////////////////////////
// NAME: SignedModulus
// PURPOSE: returns a mathematically correct modulus for long
//
_long MathUtil::SignedModulus(const _long &num, const _long &n)
{
if( num >= 0 )
return num%n;
else
{
// the % operator reflects the range if num < 0, so
// we have to multiply by -1 to reflect it back. This method
// is faster than calling Abs() and then doing the modulus.
_long Tnum = -1*(num%n);
// if num%n equals 0, then n - Tnum will be n, which, logically
// speaking, is 0 in a different form, but we have to make sure it's
// in the form 0, and not n. Therefore, if Tnum = 0, simply leave
// it like that.
if( Tnum != 0)
Tnum = n - Tnum;
return Tnum;
}
}
//////////////////////////////////////////////////////////////////////
// NAME: SignedModulus
// PURPOSE: returns a mathematically correct modulus for float
// NOTES: uses fmod() in math.h, which returns the modulus of floats
//
_float MathUtil::SignedModulus(const _float &num, const _float &n)
{
if( num >=0 )
return static_cast<_float>( fmod(num,n) );
else
{
// the % operator reflects the range if num < 0, so
// we have to multiply by -1 to reflect it back. This method
// is faster than calling Abs() and then doing the modulus.
_float Tnum = -1*( static_cast<_float>( fmod(num,n) ) );
// if num%n equals 0, then n - Tnum will be n, which, logically
// speaking, is 0 in a different form, but we have to make sure it's
// in the form 0, and not n. Therefore, if Tnum = 0, simply leave
// it like that.
if( Tnum != 0)
Tnum = n - Tnum;
return Tnum;
}
}
//////////////////////////////////////////////////////////////////////
// NAME: SignedModulus
// PURPOSE: returns a mathematically correct modulus for double
// NOTES: uses fmod() in math.h, which returns the modulus of floats
//
_double MathUtil::SignedModulus(const _double &num, const _double &n)
{
if( num >=0 )
return fmod(num,n);
else
{
// the % operator reflects the range if num < 0, so
// we have to multiply by -1 to reflect it back. This method
// is faster than calling Abs() and then doing the modulus.
_double Tnum = -1*( fmod(num,n) );
// if num%n equals 0, then n - Tnum will be n, which, logically
// speaking, is 0 in a different form, but we have to make sure it's
// in the form 0, and not n. Therefore, if Tnum = 0, simply leave
// it like that.
if( Tnum != 0)
Tnum = n - Tnum;
return Tnum;
}
}

204
source/ps/MathUtil.h Executable file
View File

@ -0,0 +1,204 @@
/*
Math utility functions
by Michael Reiland
recondite_phreak@yahool.com
--Overview--
Contains common math functions like Abs, Sign, Max, Min, etc.
--More info--
TODO: actually write corresponding documentation
http://wildfiregames.com/0ad/codepit/TDD/math_utils.html
*/
#ifndef MATH_UTIL_H
#define MATH_UTIL_H
//--------------------------------------------------------
// Includes / Compiler directives
//--------------------------------------------------------
#include "Prometheus.h" // Standard Engine Include
#include <math.h> // Needed for fmod()
//--------------------------------------------------------
// Error declarations
//--------------------------------------------------------
// MathUtil Errors
DECLARE_ERROR(ERRONEOUS_BOUND_ERROR);
//--------------------------------------------------------
// Declarations
//--------------------------------------------------------
namespace MathUtil
{
const _double PI = 3.14159265358932384;
const _double FL_FP_TOLERANCE = .000000001;
//--------------------------------------------------------
// Template functions
//--------------------------------------------------------
//--------------------------------------------------------
// Declarations
//--------------------------------------------------------
//////////////////////////////////////////////////////////
// NAME: Abs
// PURPOSE: Calculates the Absolute value
//
template <class T>
T Abs(const T &num)
{
if( num < 0)
return -1*num;
return num;
}
//////////////////////////////////////////////////////////
// NAME: Clamp
// PURPOSE: Forces num to be between lowerBound and upperBound
//
template <class T>
T Clamp(T &num, const _int &lowerBound,const _int &upperBound)
{
if(num <= lowerBound)
num = static_cast<T>(lowerBound);
else if( num >= upperBound)
num = static_cast<T>(upperBound);
}
//////////////////////////////////////////////////////////
// NAME: Max
// PURPOSE: Returns the largest number.
//
template <class T>
T Max(const T &num1, const T &num2)
{
if( num1 > num2)
return num1;
else
return num2;
}
//////////////////////////////////////////////////////////
// NAME: Min
// PURPOSE: Returns the smallest number.
//
template <class T>
T Min(const T &num1, const T &num2)
{
if( num1 < num2)
return num1;
else
return num2;
}
//////////////////////////////////////////////////////////
// NAME: Sign
// PURPOSE: Returns 1 if the number is > 0, -1 if it's < 0,
// otherwise returns 0.
//
template <class T>
_int Sign(const T &num)
{
if( num > 0 )
return 1;
else if( num < 0 )
return -1;
else
return 0;
}
//////////////////////////////////////////////////////////
// NAME: Square
// PURPOSE: Returns the square of a number
// NOTES: Num should be less than the square root of the
// maximum representable number for the data type.
//
template <class T>
inline _double Square(const T &num)
{
return num*num;
}
//////////////////////////////////////////////////////////
// NAME: Swap
// PURPOSE: Swaps two numbers
//
template <class T>
void Swap(T *num1, T *num2)
{
T temp = num1;
num1 = num2;
num2 = temp;
}
//////////////////////////////////////////////////////////
// NAME: Wrap
// PURPOSE: Wraps num between lowerBound and upperBound.
//
template <class T>
PS_RESULT Wrap(T *num,const T &lowerBound, const T &upperBound)
{
if(lowerBound >= upperBound)
return ERRONEOUS_BOUND_ERROR;
else
{
// translate to range 0 to n-1, find the modulus, then
// translate back to range lowerBound to upperBound.
num -= lowerBound;
num = SignedModulus( num, Abs(upperBound - lowerBound) );
num += lowerBound;
}
return PS_OK;
}
//--------------------------------------------------------
// Non-template functions
//--------------------------------------------------------
_int Ceiling(const float &num);
_int Ceiling(const double &num);
_bool CompareFloat(const _double &, const _double &);
_int Floor(const float &num);
_int Floor(const double &num);
inline _double RadiansToDegrees(const _double &num);
inline _double DegreesToRadians(const _double &num);
_float Random(const _float &, const _float &);
_int Random(const _int &,const _int &);
_int Round(const float &num);
_int Round(const double &num);
_int SignedModulus(const _int &num, const _int &n);
_long SignedModulus(const _long &num, const _long &n);
_float SignedModulus(const _float &num, const _float &n);
_double SignedModulus(const _double &num, const _double &n);
}
#endif

1015
source/ps/Parser.cpp Executable file

File diff suppressed because it is too large Load Diff

217
source/ps/Parser.h Executable file
View File

@ -0,0 +1,217 @@
/*
Customizeable Text Parser
by Gee
Gee@pyro.nu
--Overview--
CParserValue Data! (an int, real, string etc), basically an argument
CParserTaskType Syntax description for a line (ex. "variable=value")
CParserLine Parse _one_ line
CParser Include all syntax (CParserTaskTypes)
The whole CParser* class group is used to read in config files and
give instruction on how that should be made. The CParserTaskType
declares what in a line is arguments, of course different CParserTaskTypes
will exist, and it's up to the system to figure out which one acquired.
--More Info--
TODO: Write URL of documentation
*/
#ifndef __PARSER_H
#define __PARSER_H
#include "Prometheus.h"
#pragma warning(disable:4786)
//--------------------------------------------------------
// Includes / Compiler directives
//--------------------------------------------------------
#include <vector>
#include <string>
#include <map>
#include <deque>
#include <cmath>
//-------------------------------------------------
// Types
//-------------------------------------------------
enum _ParserValueType
{
typeIdent,
typeValue,
typeRest,
typeAddArg
};
//-------------------------------------------------
// Declarations
//-------------------------------------------------
class CParserValue;
class CParserTaskType;
class CParserLine;
class CParser;
// CParserValue
// ---------------------------------------------------------------------
// A parser value represents an argument
// color=r, g, b
// r, g and b will be CParserValues, or the arguments as they are called.
// This class can store only a string, but can try parsing it to different
// types
class CParserValue
{
public:
CParserValue();
~CParserValue();
// return is error status
_bool GetString(std::string &ret);
_bool GetBool(_bool &ret);
_bool GetChar(_char &ret); // As number! otherwise use GetString make sure size=1
_bool GetShort(_short &ret);
_bool GetInt(_int &ret);
_bool GetLong(_long &ret);
_bool GetUnsignedShort(_ushort &ret);
_bool GetUnsignedInt(_uint &ret);
_bool GetUnsignedLong(_ulong &ret);
_bool GetFloat(float &ret);
_bool GetDouble(double &ret);
// Memory regardless if it's an int, real, string or whatever
std::string m_String;
};
// CParserTaskTypeNode
// ---------------------------------------------------------------------| Class
// A task type is basically a tree, this is because dynamic arguments
// requires alternative routes, so basically it's a binary tree with an
// obligatory next node (if it's not the end of the tree) and an alternative
// dynamic arguments node
//
// If we are at the beginning of this string, this will be the layout of the node
// "<$value_>:_"
//
// m_Element ":"
// m_AltNode => "$value"
// m_NextNode => "_"
//
class CParserTaskTypeNode
{
public:
CParserTaskTypeNode();
~CParserTaskTypeNode();
// Free node pointers that are below this
void DeleteChildren();
// Either the node is a letter or a type, if m_Leter is '\0'
// then check m_Type what it is
_char m_Letter;
_ParserValueType m_Type;
std::string m_String; // Used for diverse storage
// mainly for the typeAddArg
// Parent node
CParserTaskTypeNode *m_ParentNode;
// Next node
CParserTaskTypeNode *m_NextNode;
// true means AltNode can be looped <...>
// false means AltNode is just an optional part [...]
_bool m_AltNodeRepeatable;
// Whenever a dynamic argument is used, it's first node is stored in this
// as an alternative node. The parser first checks if there is an
// alternative route, and if it applies to the next node. If not, proceed
// as usual with m_String and the next node
CParserTaskTypeNode *m_AltNode;
// There are different kinds of alternative routes
//int m_AltRouteType;
};
// CParserTaskType
// ---------------------------------------------------------------------| Class
// A task type is basically different kinds of lines for the parser
// variable=value is one type...
class CParserTaskType
{
public:
CParserTaskType();
~CParserTaskType();
// Delete the whole tree
void DeleteTree();
CParserTaskTypeNode *m_BaseNode;
// Something to identify it with
std::string m_Name;
};
// CParserLine
// ---------------------------------------------------------------------| Class
// Representing one line, i.e. one task, in a config file
class CParserLine
{
public:
CParserLine();
~CParserLine();
std::deque<CParserValue> m_Arguments;
_bool m_ParseOK; // same as ParseString will return
std::string m_TaskTypeName; // Name of the task type found
protected:
_bool ClearArguments();
public:
// Interface
_bool ParseString(const CParser& parser, std::string line);
// Methods for getting arguments
// it returns success
_bool GetArgString (const _int& arg, std::string &ret);
_bool GetArgBool (const _int& arg, _bool &ret);
_bool GetArgChar (const _int& arg, _char &ret);
_bool GetArgShort (const _int& arg, _short &ret);
_bool GetArgInt (const _int& arg, _int &ret);
_bool GetArgLong (const _int& arg, _long &ret);
_bool GetArgUnsignedShort (const _int& arg, _ushort &ret);
_bool GetArgUnsignedInt (const _int& arg, _uint &ret);
_bool GetArgUnsignedLong (const _int& arg, _ulong &ret);
_bool GetArgFloat (const _int& arg, float &ret);
_bool GetArgDouble (const _int& arg, double &ret);
// Get Argument count
_int GetArgCount() const { return m_Arguments.size(); }
};
// CParser
// ---------------------------------------------------------------------| Class
// Includes parsing instruction, i.e. task-types
class CParser
{
public:
CParser::CParser();
CParser::~CParser();
std::vector<CParserTaskType> m_TaskTypes;
// Interface
_bool InputTaskType(const std::string& strName, const std::string& strSyntax);
};
#endif

4
source/ps/Prometheus.cpp Executable file
View File

@ -0,0 +1,4 @@
#include "Prometheus.h"
DEFINE_ERROR(PS_OK, "OK");
DEFINE_ERROR(PS_FAIL, "Fail");

80
source/ps/Prometheus.h Executable file
View File

@ -0,0 +1,80 @@
/*
Prometheus.h
by Raj Sharma
rsharma@uiuc.edu
Standard declarations which are included in all projects.
*/
#ifndef PROMETHEUS_H
#define PROMETHEUS_H
#pragma warning (disable : 4786)
#pragma warning (disable : 4291)
#include <stdio.h>
#include <math.h>
#include <assert.h>
// Standard typedefs
typedef int _int;
typedef unsigned int _unsigned_int;
typedef long _long;
typedef unsigned long _unsigned_long;
typedef bool _bool;
typedef char _char;
typedef unsigned char _unsigned_char;
typedef char _byte;
typedef unsigned char _unsigned_byte;
typedef float _float;
typedef double _double;
typedef unsigned short _unsigned_short;
typedef unsigned short _ushort;
typedef short _short;
typedef unsigned long _ulong;
typedef unsigned int _uint;
// Error handling
typedef const char * PS_RESULT;
#define DEFINE_ERROR(x, y) PS_RESULT x=y;
#define DECLARE_ERROR(x) extern PS_RESULT x;
DECLARE_ERROR(PS_OK);
DECLARE_ERROR(PS_FAIL);
/*
inline bool ErrorMechanism_Error();
inline void ErrorMechanism_ClearError();
inline bool ErrorMechanism_TestError( PS_RESULT);
inline void ErrorMechanism_SetError(
PS_RESULT,
std::string,
std::string,
unsigned int);
inline CError ErrorMechanism_GetError();
*/
// Setup error interface
#define IsError() GError.ErrorMechanism_Error()
#define ClearError() GError.ErrorMechanism_ClearError()
#define TestError(TError) GError.ErrorMechanism_TestError(TError)
#define SetError_Short(w,x) GError.ErrorMechanism_SetError(w,x,__FILE__,__LINE__)
#define SetError_Long(w,x,y,z) GError.ErrorMechanism_SetError(w,x,y,z)
#define GetError() GError.ErrorMechanism_GetError()
#endif

63
source/ps/Singleton.h Executable file
View File

@ -0,0 +1,63 @@
//////////////////////////////////////////////////////////////////////////////
// AUTHOR: Michael Reiland
// FILENAME: Singleton.h
// PURPOSE: Provides a base template class for Singletons
//
// USEAGE: class myClass : Singleton<myClass>{};
//
// INFO: This implementation was copied from:
//
// Enginuity, Part II
// Memory Management, Error Logging, and Utility Classes;
// or, How To Forget To Explode Your Underwear
// by Richard "superpig" Fine
//
// hosted at Gamedev.net at
// http://gamedev.net/reference/articles/article1954.asp
//
// MODIFIED: 07.09.2003 mreiland
#ifndef _TEMPLATE_SINGLETON
#define _TEMPLATE_SINGLETON
#include <assert.h>
template<typename T>
class Singleton
{
static T* ms_singleton;
public:
Singleton()
{
assert( !ms_singleton );
//use a cunning trick to get the singleton pointing to the start of
//the whole, rather than the start of the Singleton part of the object
int offset = (int)(T*)1 - (int)(Singleton<T>*)(T*)1;
ms_singleton = (T*)((int)this + offset);
}
~Singleton()
{
assert( ms_singleton );
ms_singleton=0;
}
static T& GetSingleton()
{
assert( ms_singleton );
return *ms_singleton;
}
static T* GetSingletonPtr()
{
assert( ms_singleton );
return ms_singleton;
}
};
template <typename T>
T* Singleton<T>::ms_singleton = 0;
#endif

163
source/ps/Sound.h Executable file
View File

@ -0,0 +1,163 @@
/*
Sound.h
by Raj
Classes to play sounds or music using FMOD
Usage: Create a CWindow object, call Create, call Run.
If you want to handle events like mouse clicks, you need to derive your
own class from CBaseWindow, and override the OnXXX() functions. For example,
OnActivate() or OnPaint().
*/
-----support pan, volume, and crossfading
struct SSoundEffect
{
Position
Radius
Volume
Actual sound effect
Layer
};
struct SoundScheme
{
include several different sounds
specify the looping time for this scheme
and,
}
Class methods
-SetCrossFadeSpeed: how quickly it takes to crossfade between current music and new music
#ifndef SOUND_H
#define SOUND_H
#pragma warning (disable: 4786)
//--------------------------------------------------------
// Includes / Compiler directives
//--------------------------------------------------------
#include <Flamer.h>
#include <Sound.h>
#include <map>
#include <fmod.h>
#include <string>
#include <FileIO.h>
using namespace std;
DECLARE_ERROR(PS_SOUND_INIT);
typedef bool STREAM_OPTION;
const int STREAMING = true;
const int NO_STREAMING = false;
class CSample
{
public:
operator FSOUND_STREAM * ();
operator FSOUND_SAMPLE * ();
operator = (FSOUND_STREAM *);
operator = (FSOUND_SAMPLE *);
private:
union
{
FSOUND_STREAM *stream;
FSOUND_SAMPLE *sample;
};
};
// CSound: Class which plays sounds or music
class CSound
{
public:
CSound();
~CSound();
PS_RESULT Init();
PS_RESULT Release();
PS_RESULT Load(string filename, string nickname, STREAM_OPTION useStreaming=false);
PS_RESULT Play(string nickname);
PS_RESULT SetMasterVolume(float vol);
PS_RESULT SetSampleVolume(string sample, float vol);
PS_RESULT Pause();
PS_RESULT Resume();
private:
map <string, CSample> soundList;
};
PS_RESULT CSound::Load(string filename, string nickname, STREAM_OPTION useStreaming)
{
CSample newFile;
if(useStreaming == STREAMING)
{
}
else if(useStreaming == NO_STREAMING)
{
FSOUND_Sample_Load(FSOUND_FREE, //let FSOUND select an arbitrary sample slot
filename.c_str(), //name of the file to load
FSOUND_LOADMEMORY,
);
}
return PS_OK;
}
PS_RESULT CSound::Play(string nickname)
{
return PS_OK;
}
PS_RESULT CSound::Release()
{
return PS_OK;
}
PS_RESULT CSound::SetMasterVolume(float vol)
{
return PS_OK;
}
PS_RESULT CSound::SetSampleVolume(string sample, float vol)
{
return PS_OK;
}
PS_RESULT CSound::Pause()
{
return PS_OK;
}
PS_RESULT CSound::Resume()
{
return PS_OK;
}
#endif

7
source/readme.txt Executable file
View File

@ -0,0 +1,7 @@
- download http://oss.sgi.com/projects/ogl-sample/ABI/glext.h , put in compiler's include\gl dir
- leave out debug* for now (requires dbghelp, included with vc7)
- leave out memcpy.cpp, unless processor pack installed (not currently used anyway)
- don't define D3D8 unless the SDK is installed (=> less accurate graphics card info)
- dito for DDRAW7 (=> video card memory size not available)
- set code generation to multithreaded
- set entry point to entry (=>

289
source/res.cpp Executable file
View File

@ -0,0 +1,289 @@
// handle-based resource manager
//
// 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 <cstdlib>
#include <cstring>
#include <cstdio>
#include "types.h"
#include "unzip.h"
#include "posix.h"
#include "misc.h"
#include "res.h"
#include "vfs.h"
// handle (32 bits)
// .. detect use of already freed handles
static const uint TAG_BITS = 18;
// .. index into array => = log2(max open handles)
static const uint IDX_BITS = 14;
static const uint TYPE_BITS = 5;
static const uint REF_BITS = 9;
struct Res
{
u32 key;
u32 tag : TAG_BITS;
u32 type : TYPE_BITS;
u32 refs : REF_BITS;
};
static const ulong res_array_cap = 1ul << IDX_BITS;
static const uint max_types = 1ul << TYPE_BITS;
// static allocation for simplicity; mem usage isn't significant
static Res res_array[res_array_cap];
static int first_free = -1;
static int max_idx = -1; // index of last in-use entry
// array of pages for better locality, less fragmentation
static const uint PAGE_SIZE = 4096;
static const uint hdata_per_page = PAGE_SIZE / sizeof(HDATA);
static const uint num_pages = res_array_cap / hdata_per_page;
static HDATA* pages[num_pages];
static void(*dtors[max_types])(HDATA*);
static Handle handle(const uint idx)
{
if(idx >= (1 << IDX_BITS))
{
assert(!"invalid index passed to handle()");
return 0;
}
return (res_array[idx].tag << IDX_BITS) | idx;
}
static int h_idx(Handle h, uint type)
{
int idx = h & ((1 << IDX_BITS)-1);
const Res& r = res_array[idx];
u32 tag = h >> IDX_BITS;
if(!tag || r.tag != tag || r.type != type)
return -1;
return idx;
}
static void cleanup(void)
{
int i;
// close open handles
for(i = 0; i < max_idx; i++)
h_free(handle(i));
// free internal data space
for(i = 0; i < (int)num_pages; i++)
{
free(pages[i]);
pages[i] = 0;
}
}
Handle h_alloc(const u32 key, const uint type, DTOR dtor, HDATA*& hd)
{
ONCE(atexit(cleanup))
if(type >= max_types)
return 0;
if(dtor)
{
// registering a second dtor for type
if(dtors[type] && dtors[type] != dtor)
return 0;
dtors[type] = dtor;
}
Handle h;
int idx;
Res* r = res_array;
h = h_find(key, type, hd);
if(h)
{
idx = h_idx(h, type);
r = &res_array[idx];
if(r->refs == 1ul << REF_BITS)
{
assert(!"too many references to a handle - increase REF_BITS");
return 0;
}
r->refs++;
return h;
}
// cached
if(first_free != -1)
{
idx = first_free;
r = &res_array[idx];
}
// search res_array for first entry
else
for(idx = 0; idx < res_array_cap; idx++, r++)
if(!r->tag)
break;
// check if next entry is free
if(idx+1 < res_array_cap && !r[1].key)
first_free = idx+1;
else
first_free = -1;
if(idx >= res_array_cap)
{
assert(!"too many open handles (increase IDX_BITS)");
return 0;
}
if(idx > max_idx)
max_idx = idx;
static u32 tag;
if(++tag >= (1 << TAG_BITS))
{
assert(!"tag overflow - may not notice stale handle reuse (increase TAG_BITS)");
tag = 1;
}
r->key = key;
r->tag = tag;
r->type = type;
h = handle(idx);
hd = h_data(h, type);
return h;
}
Handle h_find(const u32 key, uint type, HDATA*& hd)
{
int idx;
const Res* r = res_array;
// already have first free entry cached - just search
if(first_free != -1)
{
for(idx = 0; idx <= max_idx; idx++, r++)
if(r->key == key && r->type == type)
goto found;
}
// search and remember first free entry (slower)
else
{
for(idx = 0; idx <= max_idx; idx++, r++)
if(!r->tag && first_free == -1)
first_free = idx;
else if(r->key == key && r->type == type)
goto found;
}
// not found
return 0;
found:
Handle h = handle(idx);
hd = h_data(h, type);
return h;
}
int h_free(const Handle h, const uint type)
{
int idx = h_idx(h, type);
if(idx == -1)
return -1;
Res& r = res_array[idx];
if(--r.refs)
return 0;
HDATA* hd = h_data(h, type);
if(hd && dtors[type])
dtors[type](hd);
r.key = 0;
r.tag = 0;
if(first_free == -1 || idx < first_free)
first_free = idx;
return 0;
}
HDATA* h_data(const Handle h, const uint type)
{
int idx = h_idx(h, type);
if(idx == -1)
return 0;
HDATA*& page = pages[idx / hdata_per_page];
if(!page)
page = (HDATA*)malloc(PAGE_SIZE);
if(!page)
return 0;
return &page[idx % hdata_per_page];
}
Handle res_load(const char* fn, uint type, DTOR dtor, void*& p, size_t& size, HDATA*& hd)
{
p = 0;
size = 0;
hd = 0;
u32 fn_hash = fnv_hash(fn, strlen(fn));
// TODO: fn is usually a constant; pass fn len if too slow
Handle h = h_alloc(fn_hash, type, dtor, hd);
if(!h || !hd)
return 0;
Handle hf = vfs_open(fn);
int err = vfs_read(hf, p, size, 0);
vfs_close(hf);
if(err < 0)
return 0;
hd->p = p;
hd->size = size;
return h;
}

60
source/res.h Executable file
View File

@ -0,0 +1,60 @@
// handle based caching resource manager
//
// 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 __RES_H__
#define __RES_H__
#include "types.h"
enum
{
RES_MEM = 1,
RES_BIN = 2,
RES_TEX = 3,
RES_FONT = 4,
RES_ZIP = 5,
RES_VFILE = 6,
NUM_RES_TYPES
};
typedef unsigned long Handle;
const int HDATA_INTERNAL_SIZE = 24;
struct HDATA
{
void* p;
size_t size;
u8 internal[HDATA_INTERNAL_SIZE];
};
typedef void(*DTOR)(HDATA*);
extern Handle h_alloc(u32 key, uint type, DTOR dtor, HDATA*& hd);
extern int h_free(Handle h, uint type = 0);
extern Handle h_find(u32 key, uint type, HDATA*& hd);
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*& hd);
#endif // #ifndef __RES_H__

22
source/resource.h Executable file
View File

@ -0,0 +1,22 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by assert_dlg.rc
//
#define IDD_DIALOG1 101
#define IDC_EDIT1 1001
#define IDC_COPY 1002
#define IDC_CONTINUE 2000
#define IDC_SUPPRESS 2001
#define IDC_BREAK 2002
#define IDC_EXIT 2003
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1003
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

694
source/tex.cpp Executable file
View File

@ -0,0 +1,694 @@
// 2d texture format decoders
//
// 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/
// supported formats: DDS, TGA, PNG, JP2, BMP, RAW
#include <cassert>
#include <cmath>
#include <cstdio>
#include "tex.h"
#include "ogl.h"
#include "res.h"
#include "misc.h"
#define NO_JP2
#define NO_PNG
#ifndef NO_JP2
#include <jasper/jasper.h>
#endif
#ifndef NO_PNG
#include <png.h>
#pragma comment(lib, "libpng.lib")
#endif
//////////////////////////////////////////////////////////////////////////////
//
// DDS
//
//////////////////////////////////////////////////////////////////////////////
#ifndef NO_DDS
// converts 4 character string to u32 for easy comparison
// can't pass code as string, and use s[0]..s[3], because
// VC6/7 don't realize the macro is constant (and it's used in a switch{})
#ifdef BIG_ENDIAN
#define FOURCC(a,b,c,d) ( ((u32)a << 24) | ((u32)b << 16) | \
((u32)c << 8 ) | ((u32)d << 0 ) )
#else
#define FOURCC(a,b,c,d) ( ((u32)a << 0 ) | ((u32)b << 8 ) | \
((u32)c << 16) | ((u32)d << 24) )
#endif
// modified from ddraw header
#pragma pack(push, 1)
typedef struct { u32 lo, hi; } DDCOLORKEY;
typedef struct
{
u32 dwSize; // size of structure
u32 dwFlags; // pixel format flags
u32 dwFourCC; // (FOURCC code)
u32 dwRGBBitCount; // how many bits per pixel
u32 dwRBitMask; // mask for red bit
u32 dwGBitMask; // mask for green bits
u32 dwBBitMask; // mask for blue bits
u32 dwRGBAlphaBitMask; // mask for alpha channel
}
DDPIXELFORMAT;
typedef struct
{
u32 dwCaps; // capabilities of surface wanted
u32 dwCaps2;
u32 dwCaps3;
u32 dwCaps4;
}
DDSCAPS2;
typedef struct
{
u32 dwSize; // size of the DDSURFACEDESC structure
u32 dwFlags; // determines what fields are valid
u32 dwHeight; // height of surface to be created
u32 dwWidth; // width of input surface
u32 dwLinearSize; // surface size
u32 dwBackBufferCount; // number of back buffers requested
u32 dwMipMapCount; // number of mip-map levels requestde
u32 dwAlphaBitDepth; // depth of alpha buffer requested
u32 dwReserved; // reserved
void* lpSurface; // pointer to the associated surface memory
DDCOLORKEY unused[4]; // src/dst overlay, blt
DDPIXELFORMAT ddpfPixelFormat; // pixel format description of the surface
DDSCAPS2 ddsCaps; // direct draw surface capabilities
u32 dwTextureStage; // stage in multitexture cascade
}
DDSURFACEDESC2;
#pragma pack(pop)
static inline bool dds_valid(const u8* ptr, size_t size)
{
UNUSED(size) // only need first 4 chars
return *(u32*)ptr == FOURCC('D','D','S',' ');
}
// TODO: DXT1a?
static int dds_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
{
const char* err = 0;
const DDSURFACEDESC2* surf = (const DDSURFACEDESC2*)(ptr+4);
const u32 hdr_size = 4+sizeof(DDSURFACEDESC2);
if(size < hdr_size)
err = "header not completely read";
else
{
const u32 w = read_le32(&surf->dwWidth);
const u32 h = read_le32(&surf->dwHeight);
const u32 ddsd_size = read_le32(&surf->dwSize);
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
{
case FOURCC('D','X','T','1'):
fmt = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
break;
case FOURCC('D','X','T','3'):
fmt = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
break;
case FOURCC('D','X','T','5'):
fmt = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
break;
}
tex->width = w;
tex->height = h;
tex->fmt = fmt;
tex->ptr = img;
tex->img_size = img_size;
if(sizeof(DDSURFACEDESC2) != ddsd_size)
err = "DDSURFACEDESC2 size mismatch";
if(size < hdr_size + img_size)
err = "not completely loaded";
if(mipmaps > 0)
err = "contains mipmaps";
if(fmt == 0)
err = "invalid pixel format (not DXT{1,3,5})";
}
if(err)
{
printf("load_dds: %s: %s\n", fn, err);
return -1;
}
return 0;
}
#endif
//////////////////////////////////////////////////////////////////////////////
//
// TGA
//
//////////////////////////////////////////////////////////////////////////////
#ifndef NO_TGA
static inline bool tga_valid(const u8* ptr, size_t size)
{
UNUSED(size)
// no color map; uncompressed grayscale or true color
return (ptr[1] == 0 && (ptr[2] == 2 || ptr[2] == 3));
}
static int tga_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
{
const char* err = "";
const u8 img_id_len = ptr[0];
const uint hdr_size = 18+img_id_len;
if(size < hdr_size)
err = "header not completely read";
else
{
const u8 type = ptr[2];
const u16 w = read_le16(ptr+12);
const u16 h = read_le16(ptr+14);
const u8 bpp = ptr[16];
const u8 desc = ptr[17];
const u8 alpha_bits = desc & 0x0f;
const u8* img = ptr + hdr_size;
const ulong img_size = (ulong)w * h * bpp / 8;
// determine format
u32 fmt = 0;
// .. grayscale
if(type == 3)
{
if(bpp == 8)
fmt = GL_LUMINANCE;
else if(bpp == 16 && alpha_bits == 8)
fmt = GL_LUMINANCE_ALPHA;
}
// .. true color
else if(type == 2)
{
if(bpp == 16 || bpp == 24)
fmt = GL_BGR;
else if(bpp == 32 && alpha_bits == 8)
fmt = GL_BGRA;
}
tex->width = w;
tex->height = h;
tex->fmt = fmt;
tex->ptr = img;
if(!fmt)
err = "unknown format / invalid bpp";
if(desc & 0x18)
err = "image is not bottom-up and left-to-right";
if(size < hdr_size + img_size)
err = "size < image size";
}
if(err)
{
printf("load_tga: %s: %s\n", fn, err);
return -1;
}
return 0;
}
#endif
//////////////////////////////////////////////////////////////////////////////
//
// BMP
//
//////////////////////////////////////////////////////////////////////////////
#ifndef NO_BMP
#pragma pack(push, 1)
struct BITMAPFILEHEADER
{
u16 bfType; // "BM"
u32 bfSize; // of file
u32 reserved;
u32 bfOffBits; // offset to image data
};
// BITMAPCOREHEADER + compression field
struct BITMAPCOREHEADER2
{
u32 biSize;
long biWidth;
long biHeight;
u16 biPlanes; // = 1
u16 biBitCount; // bpp
u32 biCompression;
};
#pragma pack(pop)
#define BI_RGB 0 // bch->biCompression
static inline bool bmp_valid(const u8* ptr, size_t size)
{
UNUSED(size)
// bfType == BM? (check single bytes => endian safe)
return ptr[0] == 'B' && ptr[1] == 'M';
}
// requirements: bpp = 24, uncompressed, bottom up
static int bmp_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
{
const char* err = 0;
BITMAPFILEHEADER* bfh = (BITMAPFILEHEADER*)ptr;
BITMAPCOREHEADER2* bch = (BITMAPCOREHEADER2*)(ptr+sizeof(BITMAPFILEHEADER));
const int hdr_size = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPCOREHEADER2);
if(size < hdr_size)
err = "header not completely read";
else
{
const long w = read_le32(&bch->biWidth);
const long h = read_le32(&bch->biHeight);
const u16 bpp = read_le16(&bch->biBitCount);
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->ptr = img;
tex->fmt = GL_BGR;
if(h < 0)
err = "top-down";
if(compress != BI_RGB)
err = "compressed";
if(bpp != 24)
err = "not 24 bpp";
if(size < ofs+img_size)
err = "image not completely read";
}
if(err)
{
printf("load_bmp: %s: %s\n", fn, err);
return -1;
}
return 0;
}
// TODO: no extra buffer needed here; dealloc?
#endif
//////////////////////////////////////////////////////////////////////////////
//
// RAW
//
//////////////////////////////////////////////////////////////////////////////
#ifndef NO_RAW
static inline bool raw_valid(const u8* p, size_t size)
{
UNUSED(p)
UNUSED(size)
return true;
}
// requirements: width = height = 2^n, bpp = {16|24|32}
static int raw_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
{
// 8bpp textures aren't supported,
// b/c it's impossible to differentiate 8bpp 2n*2n and 32bpp n*n
static GLenum fmts[5] = { 0, 0, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA };
for(int i = 2; i <= 4; i++)
{
u32 dim = (u32)sqrt(size/i);
if(size % i || // size is not a multiple of i components
!is_pow2(dim) || dim*dim*i != size)
continue;
tex->width = tex->height = dim;
tex->fmt = fmts[i];
tex->ptr = ptr;
return 0;
}
printf("load_raw: %s: %s\n", fn, "no matching format found");
return -1;
}
#endif
//////////////////////////////////////////////////////////////////////////////
//
// PNG
//
//////////////////////////////////////////////////////////////////////////////
#ifndef NO_PNG
struct MemRange
{
const u8* p;
size_t size;
};
static void png_read_fn(png_struct* png_ptr, u8* data, png_size_t length)
{
MemRange* const mr = (MemRange*)png_ptr->io_ptr;
mr->size -= length;
if(mr->size < 0)
png_error(png_ptr, "png_read_fn: no data remaining");
memcpy(data, mr->ptr, length);
mr->ptr += length;
}
static inline bool png_valid(const u8* ptr, size_t size)
{
return png_sig_cmp((u8*)ptr, 0, min(size, 8)) == 0;
}
static int png_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
{
const char* err = 0;
// allocate PNG structures
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
if(!png_ptr)
return -1;
png_infop info_ptr = png_create_info_struct(png_ptr);
if(!info_ptr)
{
png_destroy_read_struct(&png_ptr, 0, 0);
return -1;
}
// setup error handling
if(setjmp(png_jmpbuf(png_ptr)))
{
fail:
printf("load_png: %s: %s\n", fn, err? err : "");
png_destroy_read_struct(&png_ptr, &info_ptr, 0);
return -1;
}
MemRange mr = { ptr, size };
png_set_read_fn(png_ptr, &mr, png_read_fn);
png_read_info(png_ptr, info_ptr);
unsigned long width, height;
int bit_depth, color_type;
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
// can only handle 8 bits per channel
if(bit_depth != 8)
{
err = "bit depth != 8";
goto fail;
}
// allocate mem for image - rows point into buffer (sequential)
int pitch = png_get_rowbytes(png_ptr, info_ptr);
u8* img = (u8*)malloc(pitch * (height+1));
u8** rows = (u8**)png_malloc(png_ptr, (height+1)*sizeof(void*));
for(u32 i = 0; i < height+1; i++)
rows[i] = img + i*pitch;
png_read_image(png_ptr, rows);
png_read_end(png_ptr, 0);
png_destroy_read_struct(&png_ptr, &info_ptr, 0);
// store info in ti
tex->width = width; tex->height = height;
tex->ptr = img;
uint fmts[8] = { GL_LUMINANCE, 0, GL_RGB, 0, GL_LUMINANCE_ALPHA, 0, GL_RGBA, 0 };
assert(color_type < 8);
tex->fmt = fmts[color_type];
if(!tex->fmt) // <==> palette image
{
printf("load_png: %s: %s\n", fn, "palettes not supported");
return -1;
}
return 0;
}
#endif
//////////////////////////////////////////////////////////////////////////////
//
// JP2
//
//////////////////////////////////////////////////////////////////////////////
#ifndef NO_JP2
static inline bool jp2_valid(const u8* p, size_t size)
{
static bool initialized;
if(!initialized)
{
jas_init();
initialized = true;
}
jas_stream_t* stream = jas_stream_memopen((char*)ptr, size);
return jp2_validate(stream) >= 0;
}
static int jp2_load(const char* fn, const u8* ptr, size_t size, TEX* tex)
{
jas_stream_t* stream = jas_stream_memopen((char*)ptr, size);
jas_image_t* image = jas_image_decode(stream, -1, 0);
if(!image)
return -1;
int num_cmpts = jas_image_numcmpts(image);
jas_matrix_t* matr[4] = {0};
jas_seqent_t* rows[4] = {0};
int width = jas_image_cmptwidth (image, 0);
int height = jas_image_cmptheight(image, 0);
int depth = jas_image_cmptprec (image, 0);
if(depth != 8)
return -1;
u8* img = (u8*)malloc(width*height*num_cmpts);
u8* out = img;
int cmpt;
for(cmpt = 0; cmpt < num_cmpts; cmpt++)
matr[cmpt] = jas_matrix_create(1, width);
for(int y = 0; y < height; y++)
{
for(cmpt = 0; cmpt < num_cmpts; cmpt++)
{
jas_image_readcmpt(image, cmpt, 0, y, width, 1, matr[cmpt]);
rows[cmpt] = jas_matrix_getref(matr[cmpt], 0, 0);
}
for(int x = 0; x < width; x++)
for(cmpt = 0; cmpt < num_cmpts; cmpt++)
*out++ = *rows[cmpt]++;
}
for(cmpt = 0; cmpt < num_cmpts; cmpt++)
jas_matrix_destroy(matr[cmpt]);
tex->width = width;
tex->height = height;
tex->fmt = GL_RGB;
tex->ptr = img;
return 0;
}
#endif
static void tex_dtor(HDATA* hd)
{
TEX* tex = (TEX*)hd->internal;
glDeleteTextures(1, &tex->id);
}
u32 tex_load(const char* fn, TEX* ptex)
{
// load file
const u8* p;
size_t size;
HDATA* hd;
u32 h = res_load(fn, RES_TEX, tex_dtor, (void*&)p, size, hd);
if(h != 0 && !p) // already loaded
return h;
if(!p || size < 4) // is_* require a valid pointer, and >= 4 bytes
return 0;
TEX* tex = (TEX*)hd->internal;
int err = -1;
#ifndef NO_DDS
if(dds_valid(p, size))
err = dds_load(fn, p, size, tex); else
#endif
#ifndef NO_PNG
if(png_valid(p, size))
err = png_load(fn, p, size, tex); else
#endif
#ifndef NO_JP2
if(jp2_valid(p, size))
err = jp2_load(fn, p, size, tex); else
#endif
#ifndef NO_BMP
if(bmp_valid(p, size))
err = bmp_load(fn, p, size, tex); else
#endif
#ifndef NO_TGA
if(tga_valid(p, size))
err = tga_load(fn, p, size, tex); else
#endif
#ifndef NO_RAW
if(raw_valid(p, size))
err = raw_load(fn, p, size, tex); else
#endif
; // make sure else chain is ended
if(err < 0)
return err;
uint id;
glGenTextures(1, &id);
tex->id = id;
if(ptex)
*ptex = *tex;
return h;
}
int tex_bind(u32 h)
{
HDATA* hd = h_data(h, RES_TEX);
if(!hd)
{
glBindTexture(GL_TEXTURE_2D, 0);
return -1;
}
TEX* tex = (TEX*)hd->internal;
glBindTexture(GL_TEXTURE_2D, tex->id);
return 0;
}
uint tex_filter_quality = BILINEAR; // 1..6
uint tex_bpp = 32; // 16 or 32
int tex_upload(const u32 h, const uint q_ovr, uint int_fmt)
{
HDATA* hd = h_data(h, RES_TEX);
if(!hd)
return -1;
TEX* tex = (TEX*)hd->internal;
// TODO: texture_rectangle or subtexture
if(!is_pow2(tex->width) || !is_pow2(tex->height))
return 0;
tex_bind(h);
// filter quality
uint q = q_ovr? q_ovr : tex_filter_quality;
if(q > 6)
return 0;
const uint filters[7] = { 0, GL_NEAREST, GL_LINEAR,
GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_NEAREST,
GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_LINEAR };
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filters[q]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filters[min(q, 2)]);
// internal format
if(!int_fmt)
{
if(tex->fmt == GL_RGBA || tex->fmt == GL_BGRA)
int_fmt = (tex_bpp == 32)? 4 : GL_RGBA4;
else
int_fmt = (tex_bpp == 32)? 3 : GL_RGB5;
}
if(tex->fmt >= GL_COMPRESSED_RGB_S3TC_DXT1_EXT &&
tex->fmt <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, tex->fmt, tex->width, tex->height, 0, tex->img_size, tex->ptr);
else
glTexImage2D(GL_TEXTURE_2D, 0, int_fmt, tex->width, tex->height, 0, tex->fmt, GL_UNSIGNED_BYTE, tex->ptr);
return 0;
}

48
source/tex.h Executable file
View File

@ -0,0 +1,48 @@
//
// Copyright (c) 2002 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 __TEX_H__
#define __TEX_H__
#include "types.h"
struct TEX
{
uint width;
uint height;
uint fmt;
const u8* ptr;
uint id;
uint img_size; // currently only used for S3TC
};
extern u32 tex_load(const char* fn, TEX* ti = 0);
extern int tex_bind(u32 h);
const int BILINEAR = 2;
const int TRINILEAR = 6;
extern uint tex_filter_quality; // 1..6; default: BILINEAR
extern uint tex_bpp; // 16 or 32; default: 32
extern int tex_upload(u32 h, uint filter_quality = 0, uint internal_fmt = 0);
#endif // __TEX_H__

167
source/time.cpp Executable file
View File

@ -0,0 +1,167 @@
// platform indepentend high resolution timer
//
// 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 <time.h>
#include <cmath>
#include "detect.h"
#include "time.h"
#include "types.h"
#ifdef _WIN32
#include "win.h"
#endif
// high resolution (> 1 µs) timestamp [s], starting at or near 0 s.
//
// uses TSC on single processor x86 desktop systems unless NO_TSC is defined,
// otherwise platform specific timers (QueryPerformanceCounter, gettimeofday).
double get_time()
{
static double to_s;
double t;
#if defined(_M_IX86) && !defined(NO_TSC)
extern u64 rdtsc();
static int use_tsc = -1;
static u64 tsc_start;
// spaghetti code for minimum timing overhead
first_tsc:
if(use_tsc == 1)
return (__int64)(rdtsc() - tsc_start) * to_s;
// VC6 can't convert u64 -> double; we don't need full range anyway
// don't know yet
if(use_tsc == -1)
// don't use yet - need a time reference for CPU freq calculation.
if(cpu_freq != 0.0f)
// use only on single processor desktop systems
// (otherwise CPU freq may change, clocks may get out of sync)
if(cpus == 1 && !is_notebook && (cpu_caps & TSC))
{
use_tsc = 1;
to_s = 1.0 / cpu_freq;
tsc_start = rdtsc();
goto first_tsc; // using the other timers now would trash to_s
}
else
use_tsc = 0;
#endif
#ifdef _WIN32
static LARGE_INTEGER start;
LARGE_INTEGER i;
if(!to_s)
{
QueryPerformanceFrequency(&i);
to_s = 1.0 / i.QuadPart;
QueryPerformanceCounter(&start);
}
QueryPerformanceCounter(&i);
t = (i.QuadPart - start.QuadPart) * to_s;
#else
static struct timeval start;
struct timeval tv;
if(!start.tv_sec)
gettimeofday(&start, 0);
gettimeofday(&tv, 0);
t = (tv.tv_sec - start.tv_sec) + (tv.tv_usec - start.tv_usec)*1e-6;
#endif
return t;
}
// calculate fps (call once per frame)
// several smooth filters:
// - throw out single spikes / dips
// - average via small history buffer
// - update final value iff the difference (% or absolute) is too great,
// or if the change is consistent with the trend over the last few frames.
//
// => less fluctuation, but rapid tracking.
// filter values are tuned for 100 FPS.
int fps = 0;
void calc_fps()
{
// history buffer - smooth out slight variations
#define H 10 // # buffer entries
static float fps_sum = 0; // sum of last H frames' cur_fps
static float fps_hist[H]; // last H frames' cur_fps
// => don't need to re-average every time
static uint head = 0; // oldest entry in fps_hist
// must be unsigned, b/c we do (head-1)%H
// get elapsed time [s] since last frame; approximate current fps
static double last_t;
double t = get_time();
float cur_fps = 30.0f; // start value => history converges faster
if(last_t != 0.0)
cur_fps = 1.0f / (float)(t-last_t); // = 1 / elapsed time
last_t = t;
// calculate fps activity over 3 frames (used below to prevent fluctuation)
// -1: decreasing, +1: increasing, 0: neither or fluctuating
float h1 = fps_hist[(head-1)%H]; // last frame's cur_fps
float h2 = fps_hist[(head-2)%H]; // 2nd most recent frame's cur_fps
int trend = 0;
if(h2 > h1 && h1 > cur_fps) // \
trend = -1;
else if(cur_fps < h1 && h1 < h2) // /
trend = 1;
// ignore onetime skips in fps (probably page faults or similar)
static int bad = 0; // bad > 0 <==> last value was skipped
if(fabs(h1-cur_fps) > .05f*h1) // > 5% difference
{
// first 'bad' value: don't update fps_hist/fps; otherwise, reset bad
if(!bad++)
return;
}
else
bad = 0;
// remove oldest cur_fps value in fps_hist from the sum
// and add cur_fps; also insert cur_fps in fps_hist
fps_sum -= fps_hist[head];
fps_sum += (fps_hist[head] = cur_fps);
head = (head+1)%H;
// update fps counter if update threshold is exceeded
float avg_fps = fps_sum / H;
if((trend > 0 && (avg_fps > fps || avg_fps-fps < -4.f)) || // going up, or large drop
(trend < 0 && (avg_fps < fps || avg_fps-fps > 4.f)) || // going down, or large raise
(fabs(fps-avg_fps) > min(5.f, 0.05f*fps))) // significant difference
fps = (int)avg_fps;
}

44
source/time.h Executable file
View File

@ -0,0 +1,44 @@
// platform indepentend high resolution timer
//
// 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 __TIME_H__
#define __TIME_H__
#ifdef __cplusplus
extern "C" {
#endif
// high resolution (> 1 µs) timestamp [s], starting at or near 0 s.
extern double get_time();
// calculate fps (call once per frame)
// several smooth filters (tuned for ~100 FPS)
// => less fluctuation, but rapid tracking
extern int fps;
extern void calc_fps();
#ifdef __cplusplus
}
#endif
#endif // #ifndef __TIME_H__

18
source/types.h Executable file
View File

@ -0,0 +1,18 @@
#ifndef __TYPES_H__
#define __TYPES_H__
// defines instead of typedefs so we can #undef conflicting decls
#define uint unsigned int
#define ulong unsigned long
#define int8 signed char
#define int16 short
#define int32 long
#define u8 unsigned char
#define u16 unsigned short
#define u32 unsigned long // compatibility with Win32 DWORD
#define u64 unsigned __int64
#endif // #ifndef __TYPES_H__

351
source/unzip.cpp Executable file
View File

@ -0,0 +1,351 @@
// 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"
#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
// Location and size of an archived file
struct File
{
u32 ofs;
u32 csize; // bit 31 = compression method (1: deflate; 0: stored)
u32 ucsize;
};
struct ZIP
{
int fd;
// file lookup
u32 num_files;
u32* fn_hashs; // split for more efficient search
File* files;
u32 last_file; // index of last file we found (speed up lookups of sequential files)
};
static void zip_dtor(HDATA* hd)
{
ZIP* const z = (ZIP*)hd->internal;
close(z->fd);
z->fd = -1;
}
// 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, RES_ZIP, hd);
if(h)
return h;
// file size
struct stat stat_buf;
if(stat(fn, &stat_buf))
return 0;
const size_t size = stat_buf.st_size;
if(size < 4) // ECDR scan below would overrun
return 0;
// map zip file (easy access while getting list of files)
const int fd = open(fn, O_RDONLY);
if(fd < 0)
return 0;
u8* zfile = (u8*)mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0);
if(zfile == MAP_FAILED)
return 0;
// 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
u32 bytes_left = min(size, 66000);
u8* ecdr = zfile + size - bytes_left;
while(bytes_left)
{
if(*(u32*)ecdr == *(u32*)&ecdr_id)
break;
// check next 4 bytes (non aligned!!)
ecdr++;
bytes_left--;
}
{
// reached EOF and still haven't found the ECDR identifier
if(bytes_left == 0)
goto fail;
// read ECDR
u16 num_files = read_le16(ecdr+10);
u32 cd_ofs = read_le32(ecdr+16);
h = h_alloc(fn_hash, RES_ZIP, zip_dtor, hd);
if(!h || !hd)
goto fail;
ZIP* const zip = (ZIP*)hd->internal;
zip->fd = fd;
zip->fn_hashs = ( u32*)mem_alloc(num_files * sizeof(u32 ), MEM_HEAP, 64);
zip->files = (File*)mem_alloc(num_files * sizeof(File), MEM_HEAP, 64);
if(!zip->fn_hashs || !zip->files)
{
h_free(h, RES_ZIP);
mem_free(zip->fn_hashs);
mem_free(zip->files);
goto fail;
}
zip->num_files = num_files;
zip->last_file = 0;
// cache file list for faster lookups
// currently linear search, comparing filename hash.
// if too slow, use hash table
const u8* cdfh = zfile+cd_ofs;
u32* hs = zip->fn_hashs;
File* f = zip->files;
for(uint i = 0; i < zip->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];
// 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 | ((method == 8)? BIT(31) : 0);
f->ucsize = ucsize;
f++;
(int&)cdfh += 46 + fn_len + e_len + c_len;
}
}
// unmap file and return 0
fail:
munmap(zfile, size);
// actual reading is done with aio
return h;
}
// close the zip file zd
void zclose(const Handle h)
{
h_free(h, RES_ZIP);
}
// make file <fn> in zip <zd> available
// returns a pointer to the data, and optionally its size (0 on error)
//
// returns 0 on error.
int zread(Handle h, const char* fn, void*& p, size_t& size, size_t ofs)
{
// size = 0 if we fail
size = 0;
HDATA* hd = h_data(h, RES_ZIP);
if(!hd)
return 0;
ZIP* zip = (ZIP*)hd->internal;
// find its File descriptor
u32 fn_hash = fnv_hash(fn, strlen(fn));
uint i = zip->last_file+1;
if(i >= zip->num_files || zip->fn_hashs[i] != fn_hash)
{
for(i = 0; i < zip->num_files; i++)
if(zip->fn_hashs[i] == fn_hash)
break;
if(i == zip->num_files)
return 0;
zip->last_file = i;
}
const File* const f = &zip->files[i];
const bool deflated = (f->csize & BIT(31)) != 0;
ofs += f->ofs;
const u32 csize = f->csize & ~BIT(31);
const u32 ucsize = f->ucsize;
aiocb cbs[2];
memset(cbs, 0, sizeof(cbs));
cbs[0].aio_fildes = cbs[1].aio_fildes = zip->fd;
// decompress only:
void* read_bufs = 0;
const int BLOCK_SIZE = 64*KB;
int active_read = 0;
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
read_bufs = mem_alloc(BLOCK_SIZE*2, MEM_HEAP, 64*KB);
if(!read_bufs)
return -1;
cbs[0].aio_buf = read_bufs;
cbs[1].aio_buf = (u8*)read_bufs + BLOCK_SIZE;
}
void* out_mem = mem_alloc(ucsize, MEM_HEAP, 64*KB);
// pos in output buffer when reading uncompressed data
u8* out_pos = (u8*)out_mem;
stream.next_out = (u8*)out_mem;
stream.avail_out = ucsize;
long cbytes_left = csize;
bool first = true;
bool done = false;
for(;;)
{
aiocb* cb = &cbs[active_read];
// start reading next block
if(cbytes_left)
{
// align to 64 KB for speed
u32 rsize = min(64*KB - (ofs & 0xffff), cbytes_left);
// if uncompressed, read directly into output buffer
if(!deflated)
{
cb->aio_buf = out_pos;
out_pos += rsize;
}
cb->aio_offset = ofs;
cb->aio_nbytes = rsize;
aio_read(cb);
ofs += rsize;
cbytes_left -= rsize;
assert(cbytes_left >= 0); // read size clamped => never negative
}
active_read ^= 1;
// process block read in previous iteration
if(first)
first = false;
else
{
// wait for read to complete
cb = &cbs[active_read];
while(aio_error(cb) == -EINPROGRESS)
aio_suspend(&cb, 1, 0);
ssize_t bytes_read = aio_return(cb);
// inflate
if(deflated)
{
stream.next_in = (u8*)cb->aio_buf;
stream.avail_in = bytes_read;
inflate(&stream, 0);
}
}
// one more iteration to process the last pending block
if(done)
break;
if(!cbytes_left)
done = true;
}
if(deflated)
{
inflateEnd(&stream);
mem_free(read_bufs);
if(stream.total_in != csize || stream.total_out != ucsize)
{
// read_bufs is not yet allocated, or already freed
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

33
source/unzip.h Executable file
View File

@ -0,0 +1,33 @@
// 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);
extern void zclose(Handle h);
extern int zread(Handle h, const char* fn, void*& p, size_t& size, size_t ofs);
#endif // #ifndef __UNZIP_H__

169
source/vfs.cpp Executable file
View File

@ -0,0 +1,169 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "posix.h"
#include "unzip.h"
#include "misc.h"
#include "vfs.h"
#include "mem.h"
struct PATH
{
Handle zip;
const char* path;
struct PATH* next;
};
static PATH* path_list;
int vfs_goto_app_dir(char* argv0)
{
if(access(argv0, X_OK) != 0)
return -1;
char path[PATH_MAX+1];
path[PATH_MAX] = 0;
if(!realpath(argv0, path))
return -1;
// remove executable name
char* fn = strrchr(path, DIR_SEP);
if(!fn)
return -1;
*fn = 0;
return chdir(path);
}
// TODO: check CD drives?
int vfs_add_search_path(const char* p)
{
// copy path string - need to append .zip / save a copy if dir
const size_t path_len = strlen(p);
char* path = (char*)mem_alloc(path_len+4+1);
if(!p)
return -1;
strcpy(path, p);
// ZIP file?
strcpy(path+path_len, ".zip"); // append zip extension
Handle zip = zopen(path);
// dir?
path[path_len] = 0; // remove .zip extension
DIR* dir = opendir(path);
if(dir)
closedir(dir);
else
mem_free(path);
// neither
if(!zip && !dir)
return -1;
PATH* entry = (PATH*)mem_alloc(sizeof(PATH));
if(!entry)
return -1;
entry->next = path_list;
path_list = entry;
entry->zip = zip;
entry->path = dir? path : 0;
return 0;
}
int vfs_remove_first_path()
{
PATH* const p = path_list;
if(!p)
return -1;
mem_free((void*)p->path);
path_list = p->next;
zclose(p->zip);
mem_free(p);
return 0;
}
static void vfile_dtor(HDATA* hd)
{
}
Handle vfs_open(const char* fn)
{
char path[PATH_MAX+1]; path[PATH_MAX] = 0;
// for each search path:
for(PATH* entry = path_list; entry; entry = entry->next)
{
// dir - memory map the file
{
if(!entry->path)
goto not_dir;
struct stat stat_buf;
snprintf(path, PATH_MAX, "%s%c%s", entry->path, DIR_SEP, fn);
if(stat(path, &stat_buf) != 0)
goto not_dir;
int fd = open(path, O_RDONLY);
if(fd < 0)
goto not_dir;
size_t size = stat_buf.st_size;
void* p = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
if(p != MAP_FAILED)
{
HDATA* hd;
Handle h = h_alloc(0, RES_VFILE, vfile_dtor, hd);
if(h && hd)
{
hd->p = p;
hd->size = size;
return h;
}
}
}
not_dir:
// archive
if(entry->zip)
return entry->zip;
}
// not found
return 0;
}
int vfs_read(Handle h, void*& p, size_t& size, size_t ofs)
{
p = 0;
size = 0;
HDATA* hd = h_data(h, RES_VFILE);
if(hd)
{
p = (u8*)hd->p + ofs;
if(!size || size > hd->size)
size = hd->size;
return 0;
}
// else
// return zread(h, fn, p, size, ofs);
return -1;
}
int vfs_close(Handle h)
{
h_free(h, RES_ZIP);
h_free(h, RES_VFILE);
return 0;
}

8
source/vfs.h Executable file
View File

@ -0,0 +1,8 @@
extern int vfs_add_search_path(const char* path);
extern int vfs_remove_first_path();
extern Handle vfs_open(const char* fn);
extern int vfs_close(Handle h);
extern int vfs_read(Handle h, void*& p, size_t& size, size_t ofs = 0);

5
source/win.h Executable file
View File

@ -0,0 +1,5 @@
#define _WINSOCKAPI_ // sockets already defined by posix.h
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#define _WIN32_WINNT 0x0400 // needed for e.g. mousewheel support
#include <windows.h>

547
source/wsdl.cpp Executable file
View File

@ -0,0 +1,547 @@
/*
* emulation of a subset of SDL and GLUT for Win32
*
* Copyright (c) 2002 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 <stdio.h>
#include <stdlib.h>
#include <process.h>
#include "wsdl.h"
#include "win.h"
#include "misc.h"
/* state */
static bool app_active; /* is window active & on top?
if not, msg loop should yield */
static bool fullscreen; /* in fullscreen mode?
if so, restore mode when app is deactivated */
HWND hWnd = 0; /* available to the app for ShowWindow calls, etc. */
static DEVMODE dm; /* current video mode */
static HDC hDC;
static HGLRC hGLRC;
static int z_depth = 24; /* depth buffer size; set via SDL_GL_SetAttribute */
static u16 mouse_x, mouse_y;
/*
* shared msg handler
* SDL and GLUT have separate pumps; messages are handled there
*/
static LRESULT CALLBACK wndproc(HWND hWnd, unsigned int uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_PAINT:
PAINTSTRUCT ps;
BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
return 0;
case WM_ERASEBKGND:
return 0;
// prevent screensaver / monitor power off
case WM_SYSCOMMAND:
if(wParam == SC_SCREENSAVE || wParam == SC_MONITORPOWER)
return 0;
break;
case WM_ACTIVATE:
app_active = (wParam & 0xffff) != 0;
if(fullscreen)
{
if(app_active)
ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
else
ChangeDisplaySettings(0, 0);
}
break;
case WM_CLOSE:
exit(0);
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
int SDL_PollEvent(SDL_Event* ev) /* ev must be valid */
{
/* windows messages */
MSG msg;
while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
/* key */
if(msg.message == WM_KEYUP || msg.message == WM_KEYDOWN)
{
ev->type = (u8)((msg.message == WM_KEYUP)? SDL_KEYUP : SDL_KEYDOWN);
ev->key.keysym.sym = (SDLKey)msg.wParam;
return 1;
}
if(msg.message == WM_SYSCOMMAND)
ev->type = 0;
/* mouse click */
uint button;
for(button = 0; button < 3; button++)
{
if(msg.message == button+WM_LBUTTONDOWN)
ev->type = SDL_MOUSEBUTTONDOWN;
else if(msg.message == button+WM_LBUTTONUP)
ev->type = SDL_MOUSEBUTTONUP;
}
if(button < 3)
{
ev->button.button = (u8)button;
ev->button.x = (u16)(msg.lParam & 0xffff);
ev->button.y = (u16)((msg.lParam >> 16) & 0xffff);
return 1;
}
/* active */
if(msg.message == WM_ACTIVATE)
{
ev->type = SDL_ACTIVE;
ev->active.gain = app_active;
ev->active.state = 0;
return 1;
}
}
/*
* mouse motion
*
* don't use DirectInput, because we want to respect the user's mouse sensitivity
* Windows messages are laggy, so poll instead.
*/
POINT p;
GetCursorPos(&p);
if(mouse_x != p.x || mouse_y != p.y)
{
ev->type = SDL_MOUSEMOTION;
ev->motion.x = mouse_x = (u16)p.x;
ev->motion.y = mouse_y = (u16)p.y;
return 1;
}
return 0;
}
int SDL_GL_SetAttribute(SDL_GLattr attr, int value)
{
if(attr == SDL_GL_DEPTH_SIZE)
z_depth = value;
return 0;
}
/*
* set video mode wxh:bpp if necessary.
* w = h = bpp = 0 => no change.
*/
int SDL_SetVideoMode(int w, int h, int bpp, u32 flags)
{
fullscreen = (flags & SDL_FULLSCREEN);
/* get current mode settings */
dm.dmSize = sizeof(DEVMODE);
EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &dm);
int cur_w = dm.dmPelsWidth, cur_h = dm.dmPelsHeight;
int cur_bpp = dm.dmBitsPerPel;
/*
* check if mode needs to be changed
* (could split this out, but depends on fullscreen and dm)
*/
if(w != 0 && h != 0 && bpp != 0)
if(/* wrong bit depth */
(bpp != cur_bpp) ||
/* higher res mode needed */
(w > cur_w || h > cur_h) ||
/* fullscreen, and not exact mode */
(fullscreen && (w != cur_w || h != cur_h)))
{
dm.dmPelsWidth = w;
dm.dmPelsHeight = h;
dm.dmBitsPerPel = bpp;
dm.dmFields = DM_PELSWIDTH|DM_PELSHEIGHT|DM_BITSPERPEL;
}
// mode set at first WM_ACTIVATE
/*
* window init
* create new window every time (instead of once at startup), 'cause
* pixel format isn't supposed to be changed more than once
*/
HINSTANCE hInst = GetModuleHandle(0);
/* register window class */
static WNDCLASS wc;
wc.style = CS_OWNDC;
wc.lpfnWndProc = wndproc;
wc.lpszClassName = "ogl";
wc.hInstance = hInst;
RegisterClass(&wc);
hWnd = CreateWindowEx(0, "ogl", APP_NAME, WS_POPUP|WS_VISIBLE, 0, 0, dm.dmPelsWidth, dm.dmPelsHeight, 0, 0, hInst, 0);
if(!hWnd)
return 0;
hDC = GetDC(hWnd);
/* set pixel format */
static PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_SUPPORT_OPENGL|PFD_DRAW_TO_WINDOW|PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA,
(BYTE)bpp,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
(BYTE)z_depth,
0, 0,
PFD_MAIN_PLANE,
0, 0, 0, 0
};
int pf = ChoosePixelFormat(hDC, &pfd);
if(!SetPixelFormat(hDC, pf, &pfd))
return 0;
hGLRC = wglCreateContext(hDC);
if(!hGLRC)
return 0;
if(!wglMakeCurrent(hDC, hGLRC))
return 0;
return 1;
}
inline void SDL_GL_SwapBuffers()
{
SwapBuffers(hDC);
}
static SDL_VideoInfo video_info;
#ifdef DDRAW7
#include <ddraw.h>
#ifdef _MSC_VER
#pragma comment(lib, "ddraw.lib")
#pragma comment(lib, "dxguid.lib")
#endif
#endif
int SDL_Init(u32 flags)
{
UNUSED(flags)
#ifdef DDRAW7
LPDIRECTDRAW7 dd;
DirectDrawCreateEx(0, (void**)&dd, IID_IDirectDraw7, 0);
static DDSCAPS2 caps;
caps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
dd->GetAvailableVidMem(&caps, (DWORD*)&video_info.video_mem, 0);
dd->Release();
#endif
dm.dmSize = sizeof(DEVMODE);
EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &dm);
return 0;
}
void SDL_Quit()
{
DestroyWindow(hWnd);
wglMakeCurrent(0, 0);
wglDeleteContext(hGLRC);
ChangeDisplaySettings(0, 0);
}
SDL_VideoInfo* SDL_GetVideoInfo()
{
return &video_info;
}
SDL_Surface* SDL_GetVideoSurface()
{
static SDL_Surface surf;
surf.w = dm.dmPelsWidth;
surf.h = dm.dmPelsHeight;
return &surf;
}
__declspec(naked) u32 SDL_GetTicks()
{
__asm jmp dword ptr [GetTickCount]
}
void* SDL_GL_GetProcAddress(const char* name)
{
return wglGetProcAddress(name);
}
SDL_sem* SDL_CreateSemaphore(int cnt)
{
return (SDL_sem*)CreateSemaphore(0, cnt, 0x7fffffff, 0);
}
void __stdcall SDL_DestroySemaphore(SDL_sem*)
{
__asm jmp dword ptr [CloseHandle]
}
int SDL_SemPost(SDL_sem* sem)
{
return ReleaseSemaphore(sem, 1, 0);
}
int SDL_SemWait(SDL_sem* sem)
{
return WaitForSingleObject(sem, INFINITE);
}
SDL_Thread* SDL_CreateThread(int(*func)(void*), void* param)
{
return (SDL_Thread*)_beginthread((void(*)(void*))func, 0, param);
}
int SDL_KillThread(SDL_Thread* thread)
{
return TerminateThread(thread, 0);
}
__declspec(naked) int __stdcall SDL_WarpMouse(int, int)
{
__asm jmp dword ptr [SetCursorPos]
}
static bool need_redisplay; /* display callback should be called in next main loop iteration */
/* glut callbacks */
static void (*idle)();
static void (*display)();
static void (*key)(int, int, int);
static void (*special)(int, int, int);
static void (*mouse)(int, int, int, int);
void glutIdleFunc(void (*func)())
{ idle = func; }
void glutDisplayFunc(void (*func)())
{ display = func; }
void glutKeyboardFunc(void (*func)(int, int, int))
{ key = func; }
void glutSpecialFunc(void (*func)(int, int, int))
{ special = func; }
void glutMouseFunc(void (*func)(int, int, int, int))
{ mouse = func; }
void glutInit(int* argc, char* argv[])
{
UNUSED(argc)
UNUSED(argv)
SDL_Init(0);
atexit(SDL_Quit);
}
int glutGet(int arg)
{
if(arg == GLUT_ELAPSED_TIME)
return GetTickCount();
dm.dmSize = sizeof(DEVMODE);
EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &dm);
if(arg == GLUT_SCREEN_WIDTH)
return dm.dmPelsWidth;
if(arg == GLUT_SCREEN_HEIGHT)
return dm.dmPelsHeight;
return 0;
}
static int w, h, bpp, refresh;
int glutGameModeString(const char* str)
{
/* default = "don't care", in case string doesn't specify all values */
w = 0, h = 0, bpp = 0, refresh = 0;
sscanf(str, "%dx%d:%d@%d", &w, &h, &bpp, &refresh);
return 1;
}
/*
*/
int glutEnterGameMode()
{
return SDL_SetVideoMode(w, h, bpp, SDL_OPENGL|SDL_FULLSCREEN);
}
inline void glutPostRedisplay()
{
need_redisplay = true;
}
void glutSetCursor(int cursor)
{
SetCursor(LoadCursor(NULL, (const char*)cursor));
}
/*
* GLUT message handler
* message also goes to the shared wndproc
*
* not done in wndproc to separate GLUT and SDL;
* split out of glutMainLoop for clarity.
*/
static void glut_process_msg(MSG* msg)
{
switch(msg->message)
{
case WM_PAINT:
need_redisplay = true;
break;
case WM_CHAR:
if(key)
key((int)msg->wParam, mouse_x, mouse_y);
break;
case WM_KEYDOWN:
if(special)
special((int)msg->wParam, mouse_x, mouse_y);
break;
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN: /* FIXME: only left/right clicks, assume GLUT_LEFT|RIGHT_BUTTON == 0, 1 */
if(mouse)
mouse(msg->message == WM_RBUTTONDOWN, GLUT_DOWN, (int)(msg->lParam & 0xffff), (int)(msg->lParam >> 16));
break;
case WM_MOUSEWHEEL:
if(mouse)
mouse(GLUT_MIDDLE_BUTTON, ((short)(msg->wParam >> 16) > 0)? GLUT_UP : GLUT_DOWN, 0, 0);
break;
}
}
void glutMainLoop()
{
for(;;)
{
if(!app_active)
WaitMessage();
MSG msg;
if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
glut_process_msg(&msg);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if(idle)
idle();
if(need_redisplay)
{
need_redisplay = false;
display();
}
}
}

287
source/wsdl.h Executable file
View File

@ -0,0 +1,287 @@
#ifndef __WSDL_H__
#define __WSDL_H__
#ifndef _WIN32
#include <SDL/sdl.h>
#else
#include "types.h"
/* allow apps to override window name */
#ifndef APP_NAME
#define APP_NAME "ogl"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* SDL_Init flags */
#define SDL_INIT_VIDEO 0
#define SDL_INIT_AUDIO 0
#define SDL_INIT_TIMER 0
#define SDL_INIT_NOPARACHUTE 0
extern int SDL_Init(u32);
extern void SDL_Quit();
typedef enum
{
SDL_GL_DEPTH_SIZE,
SDL_GL_DOUBLEBUFFER /* ignored - always double buffered */
}
SDL_GLattr;
extern int SDL_GL_SetAttribute(SDL_GLattr attr, int value);
/* SDL_SetVideoMode() flags */
#define SDL_OPENGL 0
#define SDL_FULLSCREEN 1
extern int SDL_SetVideoMode(int w, int h, int bpp, u32 flags);
typedef struct
{
int w, h;
}
SDL_Surface;
extern SDL_Surface* SDL_GetVideoSurface();
typedef struct
{
int video_mem;
}
SDL_VideoInfo;
extern SDL_VideoInfo* SDL_GetVideoInfo();
/*
* threads / sync
*/
typedef void SDL_sem;
typedef void SDL_Thread;
extern void* SDL_GL_GetProcAddress(const char*);
extern void SDL_GL_SwapBuffers();
extern u32 SDL_GetTicks();
extern SDL_sem* SDL_CreateSemaphore(int cnt);
extern void __stdcall SDL_DestroySemaphore(SDL_sem*);
extern int SDL_SemPost(SDL_sem*);
extern int SDL_SemWait(SDL_sem* sem);
extern SDL_Thread* SDL_CreateThread(int(*)(void*), void*);
extern int SDL_KillThread(SDL_Thread*);
extern int __stdcall SDL_WarpMouse(int, int);
/* macros */
#define SDL_GRAB_ON 0
#define SDL_WM_GrabInput(a)
#define SDL_GetError() ""
/************************************************************************************************
* events
************************************************************************************************/
/* SDLKey (mapped to VK_* codes) */
typedef enum
{
SDLK_ESCAPE = 0x1b,
SDLK_8 = '8',
SDLK_9 = '9',
SDLK_0 = '0',
SDLK_p = 'P',
SDLK_r = 'R',
SDLK_s = 'S'
}
SDLKey;
typedef struct
{
SDLKey sym;
}
SDL_keysym;
typedef struct
{
SDL_keysym keysym;
}
SDL_KeyboardEvent;
typedef struct
{
u16 x, y;
}
SDL_MouseMotionEvent;
/* SDL_MouseButtonEvent.button */
enum
{
SDL_BUTTON_LEFT,
SDL_BUTTON_MIDDLE,
SDL_BUTTON_RIGHT
};
typedef struct
{
u8 button;
u8 state;
u16 x, y;
}
SDL_MouseButtonEvent;
typedef struct
{
u8 gain;
u8 state;
}
SDL_ActiveEvent;
/* SDL_Event.type */
enum
{
SDL_KEYDOWN,
SDL_KEYUP,
SDL_MOUSEMOTION,
SDL_MOUSEBUTTONDOWN,
SDL_MOUSEBUTTONUP,
SDL_ACTIVE
};
typedef struct
{
u8 type;
union
{
SDL_KeyboardEvent key;
SDL_MouseMotionEvent motion;
SDL_MouseButtonEvent button;
SDL_ActiveEvent active;
};
}
SDL_Event;
extern int SDL_PollEvent(SDL_Event* ev);
/* glutInitDisplayMode */
#define GLUT_RGB 0
#define GLUT_DOUBLE 0
#define GLUT_DEPTH 0
/* mouse buttons */
enum
{
GLUT_LEFT_BUTTON,
GLUT_RIGHT_BUTTON,
GLUT_MIDDLE_BUTTON /* also wheel, if avail */
};
/* mouse button state */
enum
{
GLUT_DOWN,
GLUT_UP
};
/* keys */
enum
{
GLUT_KEY_LEFT = 0x25, /* VK_* */
GLUT_KEY_RIGHT = 0x27,
GLUT_KEY_UP = 0x26,
GLUT_KEY_DOWN = 0x28
};
/* glutSetCursor */
#define GLUT_CURSOR_INHERIT 32512 /* IDC_* */
#define GLUT_CURSOR_WAIT 32514
#define GLUT_CURSOR_DESTROY 32648
#define GLUT_CURSOR_NONE 0
/* glutGet */
enum
{
GLUT_ELAPSED_TIME,
GLUT_SCREEN_WIDTH,
GLUT_SCREEN_HEIGHT,
GLUT_GAME_MODE_WIDTH,
GLUT_GAME_MODE_HEIGHT,
GLUT_GAME_MODE_PIXEL_DEPTH,
GLUT_GAME_MODE_REFRESH_RATE
};
extern void glutIdleFunc(void(*)());
extern void glutDisplayFunc(void(*)());
extern void glutKeyboardFunc(void(*)(int, int, int));
extern void glutSpecialFunc(void(*)(int, int, int));
extern void glutMouseFunc(void(*)(int, int, int, int));
#define glutInitDisplayMode(a) /* pixel format is hardwired */
extern int glutGameModeString(const char* str);
extern void glutInit(int* argc, char* argv[]);
extern int glutGet(int arg);
extern int glutEnterGameMode();
extern void glutMainLoop();
extern void glutPostRedisplay();
extern void glutSetCursor(int);
#define glutSwapBuffers SDL_GL_SwapBuffers
#ifdef __cplusplus
}
#endif
#endif /* #else / #ifndef WIN32 */
#endif /* #ifndef __WSDL_H__ */