Initial revision
This was SVN commit r5.
This commit is contained in:
commit
2ebc9e2cb6
11
.gitattributes
vendored
Normal file
11
.gitattributes
vendored
Normal 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
3
binaries/data/verdana.fnt
Executable 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
BIN
binaries/data/verdana.raw
Executable file
Binary file not shown.
301
source/detect.cpp
Executable file
301
source/detect.cpp
Executable 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
88
source/detect.h
Executable 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
226
source/font.cpp
Executable 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
79
source/font.h
Executable 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
25
source/glext_funcs.h
Executable 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
164
source/input.cpp
Executable 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
56
source/input.h
Executable 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
260
source/main.cpp
Executable 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
123
source/mem.cpp
Executable 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
13
source/mem.h
Executable 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
62
source/memcpy.cpp
Executable 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
223
source/misc.cpp
Executable 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
121
source/misc.h
Executable 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
103
source/ogl.cpp
Executable 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
65
source/ogl.h
Executable 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
494
source/posix.cpp
Executable 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
437
source/posix.h
Executable 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
392
source/posix/aio.cpp
Executable 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, §or_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
63
source/posix/aio.h
Executable 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
211
source/ps/BaseEntity.h
Executable 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
155
source/ps/CStr.h
Executable 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
86
source/ps/Encryption.cpp
Executable 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
30
source/ps/Encryption.h
Executable 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
157
source/ps/Error.h
Executable 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
355
source/ps/LogFile.cpp
Executable 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> (";
|
||||||
|
dateText += options.date;
|
||||||
|
dateText += ")</font>";
|
||||||
|
}
|
||||||
|
|
||||||
|
return dateText;
|
||||||
|
}
|
155
source/ps/LogFile.h
Executable file
155
source/ps/LogFile.h
Executable 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
246
source/ps/MathUtil.cpp
Executable 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
204
source/ps/MathUtil.h
Executable 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
1015
source/ps/Parser.cpp
Executable file
File diff suppressed because it is too large
Load Diff
217
source/ps/Parser.h
Executable file
217
source/ps/Parser.h
Executable 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
4
source/ps/Prometheus.cpp
Executable 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
80
source/ps/Prometheus.h
Executable 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
63
source/ps/Singleton.h
Executable 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
163
source/ps/Sound.h
Executable 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
7
source/readme.txt
Executable 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
289
source/res.cpp
Executable 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
60
source/res.h
Executable 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
22
source/resource.h
Executable 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
694
source/tex.cpp
Executable 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
48
source/tex.h
Executable 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
167
source/time.cpp
Executable 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
44
source/time.h
Executable 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
18
source/types.h
Executable 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
351
source/unzip.cpp
Executable 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
33
source/unzip.h
Executable 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
169
source/vfs.cpp
Executable 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
8
source/vfs.h
Executable 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
5
source/win.h
Executable 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
547
source/wsdl.cpp
Executable 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
287
source/wsdl.h
Executable 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__ */
|
Loading…
Reference in New Issue
Block a user