1
0
forked from 0ad/0ad

merged in rich's demo

This was SVN commit r236.
This commit is contained in:
janwas 2004-05-16 03:31:29 +00:00
parent fb8ea69062
commit fbba2e463d
8 changed files with 648 additions and 598 deletions

View File

@ -96,13 +96,14 @@ static int mk_native_path(const char* const path, char* const n_path)
}
// rationale for data dir being root:
// xxxxxxxx yyyyyyyyy zzzzzzzzzz sandbox; vfs users (untrusted scripts) can't overwrite critical game files
// rationale for data dir being root: untrusted scripts must not be allowed
// to overwrite critical game (or worse, OS) files. the VFS prevents any
// accesses to files above this directory.
int file_set_root_dir(const char* argv0, const char* root_dir)
{
// security check: only allow attempting to set root dir once
// (prevents malicious scripts from overwriting important files
// above the intended VFS root)
// (this is called early at startup, so any subsequent
// call is most likely malicious).
static bool already_attempted;
if(already_attempted)
{
@ -131,10 +132,10 @@ int file_set_root_dir(const char* argv0, const char* root_dir)
if(chdir(path) < 0)
return -errno;
char* native_root = path; // reuse path[] (no longer needed)
CHECK_ERR(mk_native_path(root_dir, native_root));
char* n_root = path; // reuse path[] (no longer needed)
CHECK_ERR(mk_native_path(root_dir, n_root));
if(chdir(native_root) < 0)
if(chdir(n_root) < 0)
return -errno;
return 0;
@ -148,25 +149,26 @@ int file_set_root_dir(const char* argv0, const char* root_dir)
// need to store entries returned by readdir so they can be sorted.
struct DirEnt
{
std::string name;
uint flags;
ssize_t size;
const std::string name;
const uint flags;
const ssize_t size;
DirEnt(const char* _name, uint _flags, ssize_t _size)
DirEnt(const char* const _name, const uint _flags, const ssize_t _size)
: name(_name), flags(_flags), size(_size) {}
};
typedef std::vector<DirEnt> DirEnts;
typedef DirEnts::iterator DirEntsIt;
typedef std::vector<const DirEnt*> DirEnts;
typedef DirEnts::const_iterator DirEntIt;
static bool dirent_less(DirEnt& d1, DirEnt& d2)
{ return d1.name.compare(d2.name) < 0; }
static bool dirent_less(const DirEnt* const d1, const DirEnt* const d2)
{ return d1->name.compare(d2->name) < 0; }
// rationale: we pass the directory entry name only to the callback -
// not the absolute path, nor <dir> prepended. some users don't need it,
// and would need to strip it. this routine generates the absolute path,
// but in native form - can't use that.
int file_enum(const char* dir, FileCB cb, uintptr_t user)
// we give the callback the directory-entry-name only - not the
// absolute path, nor <dir> prepended. rationale: some users don't need it,
// and would need to strip it. there are not enough users requiring it to
// justify that. this routine does actually generate the absolute path
// for use with stat, but in native form - can't use that.
int file_enum(const char* const dir, const FileCB cb, const uintptr_t user)
{
char n_path[PATH_MAX+1];
n_path[PATH_MAX] = '\0';
@ -174,14 +176,15 @@ int file_enum(const char* dir, FileCB cb, uintptr_t user)
// 0-terminate simplifies filename strncpy below.
CHECK_ERR(mk_native_path(dir, n_path));
// all entries are enumerated (adding to list), sorted, then passed to cb
// all entries are enumerated (adding to this container),
// std::sort-ed, then all passed to cb.
DirEnts dirents;
int stat_err = 0;
int cb_err = 0;
int ret;
DIR* os_dir = opendir(n_path);
DIR* const os_dir = opendir(n_path);
if(!os_dir)
return -1;
@ -190,15 +193,19 @@ int file_enum(const char* dir, FileCB cb, uintptr_t user)
char* fn_start = n_path + n_path_len;
*fn_start++ = DIR_SEP;
struct dirent* ent;
while((ent = readdir(os_dir)))
struct dirent* os_ent;
while((os_ent = readdir(os_dir)))
{
const char* fn = ent->d_name;
const char* fn = os_ent->d_name;
strncpy(fn_start, fn, PATH_MAX-n_path_len);
// stat needs the relative path. this is easier than changing
// stat needs the full path. this is easier than changing
// directory every time, and should be fast enough.
// BTW, direct strcpy is faster than path_append -
// we save a strlen every iteration.
// no need to go through file_stat -
// we already have the native path.
struct stat s;
ret = stat(n_path, &s);
if(ret < 0)
@ -225,23 +232,29 @@ int file_enum(const char* dir, FileCB cb, uintptr_t user)
else if(!(s.st_mode & S_IFREG))
continue;
dirents.push_back(DirEnt(fn, flags, size));
const DirEnt* const ent = new DirEnt(fn, flags, size);
dirents.push_back(ent);
}
closedir(os_dir);
std::sort(dirents.begin(), dirents.end(), dirent_less);
for(DirEntsIt it = dirents.begin(); it != dirents.end(); ++it)
DirEntIt it;
for(it = dirents.begin(); it != dirents.end(); ++it)
{
const char* name_c = it->name.c_str();
const uint flags = it->flags;
const ssize_t size = it->size;
const DirEnt* const ent = *it;
const char* name_c = ent->name.c_str();
const uint flags = ent->flags;
const ssize_t size = ent->size;
ret = cb(name_c, flags, size, user);
if(ret < 0)
if(cb_err == 0)
cb_err = ret;
}
for(it = dirents.begin(); it != dirents.end(); ++it)
delete *it;
if(cb_err < 0)
return cb_err;
return stat_err;
@ -832,7 +845,7 @@ Handle file_start_io(File* f, size_t user_ofs, size_t user_size, void* user_p)
return -1;
}
size_t bytes_left = f->size - user_ofs; // > 0
const size_t bytes_left = f->size - user_ofs; // > 0
int op = (f->flags & FILE_WRITE)? LIO_WRITE : LIO_READ;
// don't read beyond EOF
@ -841,6 +854,7 @@ Handle file_start_io(File* f, size_t user_ofs, size_t user_size, void* user_p)
u64 block_id = block_make_id(f->fn_hash, user_ofs);
// reset to 0 if transferring more than 1 block.
// allocate IO slot
Handle hio = io_alloc();
@ -852,8 +866,9 @@ Handle file_start_io(File* f, size_t user_ofs, size_t user_size, void* user_p)
// notes: io->cached, io->pending and io->block are already zeroed;
// cb will receive the actual IO request (aligned offset and size).
#ifdef PARANOIA
debug_out("file_start_io hio=%I64x ofs=%d size=%d\n", hio, user_ofs, user_size);
#endif
// aio already safely handles unaligned buffers or offsets.
// when reading zip files, we don't want to repeat a read
@ -875,7 +890,9 @@ debug_out("file_start_io hio=%I64x ofs=%d size=%d\n", hio, user_ofs, user_size);
// if already cached, we're done
if(size == BLOCK_SIZE && block_retrieve(block_id, io->block) == 0)
{
debug_out("file_start_io: cached! block # = %d\n", block_id & 0xffffffff);
#ifdef PARANOIA
debug_out("file_start_io: cached! block # = %d\n", block_id & 0xffffffff);
#endif
io->cached = 1;
return hio;
}
@ -922,7 +939,9 @@ fail:
int file_wait_io(const Handle hio, void*& p, size_t& size)
{
#ifdef PARANOIA
debug_out("file_wait_io: hio=%I64x\n", hio);
#endif
int ret = 0;
@ -1003,7 +1022,9 @@ int file_discard_io(Handle& hio)
ssize_t file_io(File* const f, const size_t raw_ofs, size_t raw_size, void** const p,
const FILE_IO_CB cb, const uintptr_t ctx) // optional
{
#ifdef PARANOIA
debug_out("file_io fd=%d size=%d ofs=%d\n", f->fd, raw_size, raw_ofs);
#endif
CHECK_FILE(f)
@ -1100,8 +1121,6 @@ debug_out("file_io fd=%d size=%d ofs=%d\n", f->fd, raw_size, raw_ofs);
const int MAX_IOS = 2;
Handle ios[MAX_IOS] = { 0 };
if(ios[0] || ios[1])abort();
int head = 0;
int tail = 0;
int pending_ios = 0;
@ -1119,11 +1138,6 @@ if(ios[0] || ios[1])abort();
ssize_t err = +1; // loop terminates if <= 0
static int seq;
seq++;
if(seq == 4)
seq=4;
for(;;)
{
// queue not full, data remaining to transfer, and no error:

View File

@ -883,21 +883,30 @@ Handle vfs_open(const char* fn, uint flags /* = 0 */)
Handle h = h_alloc(H_VFile, fn, 0, flags);
// pass file flags to init
#ifdef PARANOIA
debug_out("vfs_open fn=%s %I64x\n", fn, h);
return h;
#endif
return h;
}
inline int vfs_close(Handle& h)
{
#ifdef PARANOIA
debug_out("vfs_close %I64x\n", h);
#endif
return h_free(h, H_VFile);
}
ssize_t vfs_io(Handle hf, size_t ofs, size_t size, void*& p)
{
#ifdef PARANOIA
debug_out("vfs_io ofs=%d size=%d\n", ofs, size);
#endif
H_DEREF(hf, VFile, vf);
// (vfs_open makes sure it's not opened for writing if zip)
@ -913,7 +922,10 @@ debug_out("vfs_io ofs=%d size=%d\n", ofs, size);
Handle vfs_load(const char* fn, void*& p, size_t& size)
{
#ifdef PARANOIA
debug_out("vfs_load fn=%s\n", fn);
#endif
p = 0; // vfs_io needs initial 0 value
size = 0; // in case open or deref fails

View File

@ -164,9 +164,9 @@ static inline void pre_main_init()
atexit(at_exit);
// real SDL will do this as well. no matter.
// ignore BoundsChecker warning here.
freopen("stdout.txt", "wt", stdout);
// no point redirecting stdout yet - the current directory
// may be incorrect (file_set_root not yet called).
// (w)sdl will take care of it anyway.
}

View File

@ -366,6 +366,16 @@ int SDL_GL_SetAttribute(SDL_GLattr attr, int value)
}
int SDL_Init(Uint32 flags)
{
FILE* const ret = freopen("stdout.txt", "w", stdout);
if(!ret)
debug_warn("SDL_Init freopen failed");
return 0;
}
/*
* set video mode wxh:bpp if necessary.
* w = h = bpp = 0 => no change.

View File

@ -14,12 +14,17 @@
extern "C" {
#endif
#define Uint32 u32
/* 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(Uint32 flags);
extern void SDL_Quit();
@ -86,8 +91,6 @@ extern int __stdcall SDL_WarpMouse(int, int);
/* macros */
#define SDL_Init
#define SDL_GRAB_ON 0
#define SDL_WM_GrabInput(a)
#define SDL_GetError() ""

View File

@ -47,45 +47,54 @@ extern void terr_init();
extern void terr_update(float time);
extern bool terr_handler(const SDL_Event& ev);
extern int allow_reload();
extern int dir_add_watch(const char* const dir, bool watch_subdirs);
static void write_sys_info()
static int write_sys_info()
{
get_gfx_info();
struct utsname un;
uname(&un);
freopen("stdout.txt", "w", stdout);
FILE* const f = fopen("../system/system_info.txt", "w");
if(!f)
return -1;
// .. OS
printf("%s %s (%s)\n", un.sysname, un.release, un.version);
fprintf(f, "%s %s (%s)\n", un.sysname, un.release, un.version);
// .. CPU
printf("%s, %s", un.machine, cpu_type);
fprintf(f, "%s, %s", un.machine, cpu_type);
if(cpu_freq != 0.0f)
{
if(cpu_freq < 1e9)
printf(", %.2f MHz\n", cpu_freq*1e-6);
fprintf(f, ", %.2f MHz\n", cpu_freq*1e-6);
else
printf(", %.2f GHz\n", cpu_freq*1e-9);
fprintf(f, ", %.2f GHz\n", cpu_freq*1e-9);
}
else
printf("\n");
fprintf(f, "\n");
// .. memory
printf("%lu MB RAM; %lu MB free\n", tot_mem/MB, avl_mem/MB);
fprintf(f, "%lu MB RAM; %lu MB free\n", tot_mem/MB, avl_mem/MB);
// .. graphics card
printf("%s\n", gfx_card);
printf("%s\n", gfx_drv);
fprintf(f, "%s\n", gfx_card);
fprintf(f, "%s\n", gfx_drv);
// .. network name / ips
char hostname[100]; // possibly nodename != hostname
gethostname(hostname, sizeof(hostname));
printf("%s\n", hostname);
fprintf(f, "%s\n", 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");
fprintf(f, "%s ", inet_ntoa(*ips[i]));
fprintf(f, "\n");
}
fflush(stdout);
fclose(f);
}
@ -149,12 +158,6 @@ static bool handler(const SDL_Event& ev)
case SDLK_ESCAPE:
quit = true;
break;
case '1':
case SDLK_F1:
res_reload("art/textures/terrain/types/grass/Base1.tga");
break;
}
break;
@ -348,8 +351,13 @@ void ParseArgs(int argc, char* argv[])
int main(int argc, char* argv[])
{
ParseArgs(argc,argv);
file_set_root_dir(argv[0], "../data");
argc=2;
argv[1] = "-m=test01.pmp";
ParseArgs(argc,argv);
/*
chdir("\\games\\bf\\ScreenShots");
int a,b;
char fn[100];
@ -395,12 +403,14 @@ sprintf(fn, "ScreenShot%d.jpg", i);
if(access(fn, F_OK) < 0)
break;
}
*/
__asm cpuid __asm rdtsc __asm mov b, eax
int c = b-a;
*/
lib_init();
// set 24 bit (float) FPU precision for faster divides / sqrts
@ -451,8 +461,8 @@ int c = b-a;
new CConfig;
file_set_root_dir(argv[0], "../data");
vfs_mount("", "mods/official/", 0);
dir_add_watch("mods\\official", false);
#ifndef NO_GUI
// GUI uses VFS, so this must come after VFS init.
@ -507,6 +517,9 @@ in_add_handler(terr_handler);
{
g_Config.Update();
allow_reload();
// TODO: limiter in case simulation can't keep up?
#if 0
double time1 = get_time();

View File

@ -1,201 +1,201 @@
#include "TextureManager.h"
#include "lib.h"
#include "ogl.h"
#include "res/tex.h"
#ifdef _WIN32
#include <io.h>
#endif
#include <algorithm>
const char* SupportedTextureFormats[] = { "png", "dds", "tga", "bmp" };
CTextureManager g_TexMan;
CTextureManager::CTextureManager()
{
m_TerrainTextures.reserve(32);
}
void CTextureManager::AddTextureType(const char* name)
{
m_TerrainTextures.resize(m_TerrainTextures.size()+1);
STextureType& ttype=m_TerrainTextures.back();
ttype.m_Name=name;
ttype.m_Index=m_TerrainTextures.size()-1;
}
CTextureEntry* CTextureManager::FindTexture(const char* filename)
{
// check if file already loaded
for (uint k=0;k<m_TerrainTextures.size();k++) {
STextureType& ttype=m_TerrainTextures[k];
for (uint i=0;i<ttype.m_Textures.size();i++) {
if (strcmp((const char*) ttype.m_Textures[i]->m_Name,filename)==0) {
return ttype.m_Textures[i];
}
}
}
return 0;
}
CTextureEntry* CTextureManager::FindTexture(Handle handle)
{
for (uint k=0;k<m_TerrainTextures.size();k++) {
STextureType& ttype=m_TerrainTextures[k];
for (uint i=0;i<ttype.m_Textures.size();i++) {
if (handle==ttype.m_Textures[i]->m_Handle) {
return ttype.m_Textures[i];
}
}
}
return 0;
}
CTextureEntry* CTextureManager::AddTexture(const char* filename,int type)
{
assert((uint)type<m_TerrainTextures.size());
CStr pathname("art/textures/terrain/types/");
pathname+=m_TerrainTextures[type].m_Name;
pathname+='/';
pathname+=filename;
Handle h=tex_load((const char*) pathname);
if (!h) {
return 0;
} else {
int tw;
int th;
tex_info(h, &tw, &th, NULL, NULL, NULL);
tw &= (tw-1);
th &= (th-1);
if (tw || th) {
return 0;
}
}
// create new texture entry
CTextureEntry* texentry=new CTextureEntry;
texentry->m_Name=filename;
texentry->m_Handle=h;
texentry->m_Type=type;
// upload texture for future GL use
tex_upload(h,GL_LINEAR_MIPMAP_LINEAR);
// setup texture to repeat
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// get root color for coloring minimap by querying root level of the texture
// (this should decompress any compressed textures for us),
// then scaling it down to a 1x1 size
// - an alternative approach of just grabbing the top level of the mipmap tree fails
// (or gives an incorrect colour) in some cases:
// - suspect bug on Radeon cards when SGIS_generate_mipmap is used
// - any textures without mipmaps
// we'll just take the basic approach here:
int width,height;
glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_WIDTH,&width);
glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_HEIGHT,&height);
unsigned char* buf=new unsigned char[width*height*4];
glGetTexImage(GL_TEXTURE_2D,0,GL_BGRA_EXT,GL_UNSIGNED_BYTE,buf);
gluScaleImage(GL_BGRA_EXT,width,height,GL_UNSIGNED_BYTE,buf,
1,1,GL_UNSIGNED_BYTE,&texentry->m_BaseColor);
delete[] buf;
// add entry to list ..
m_TerrainTextures[type].m_Textures.push_back(texentry);
// .. and return it
return texentry;
}
void CTextureManager::DeleteTexture(CTextureEntry* entry)
{
// find entry in list
std::vector<CTextureEntry*>& textures=m_TerrainTextures[entry->m_Type].m_Textures;
typedef std::vector<CTextureEntry*>::iterator Iter;
Iter i=std::find(textures.begin(),textures.end(),entry);
if (i!=textures.end()) {
textures.erase(i);
}
delete entry;
}
void CTextureManager::LoadTerrainTextures(int terraintype,const char* fileext)
{
#ifdef _WIN32
struct _finddata_t file;
long handle;
// build pathname
CStr pathname("mods\\official\\art\\textures\\terrain\\types\\");
pathname+=m_TerrainTextures[terraintype].m_Name;
pathname+="\\";
CStr findname(pathname);
findname+="*.";
findname+=fileext;
// Find first matching file in directory for this terrain type
if ((handle=_findfirst((const char*) findname,&file))!=-1) {
AddTexture(file.name,terraintype);
// Find the rest of the matching files
while( _findnext(handle,&file)==0) {
AddTexture((const char*) file.name,terraintype);
}
_findclose(handle);
}
#endif
}
void CTextureManager::BuildTerrainTypes()
{
#ifdef _WIN32
struct _finddata_t file;
long handle;
// Find first matching directory in terrain\textures
if ((handle=_findfirst("mods\\official\\art\\textures\\terrain\\types\\*",&file))!=-1) {
if ((file.attrib & _A_SUBDIR) && file.name[0]!='.') {
AddTextureType(file.name);
}
// Find the rest of the matching files
while( _findnext(handle,&file)==0) {
if ((file.attrib & _A_SUBDIR) && file.name[0]!='.') {
AddTextureType(file.name);
}
}
_findclose(handle);
}
#endif
}
void CTextureManager::LoadTerrainTextures()
{
// find all the terrain types by directory name
BuildTerrainTypes();
// now iterate through terrain types loading all textures of that type
for (uint i=0;i<m_TerrainTextures.size();i++) {
for (uint j=0;j<sizeof(SupportedTextureFormats)/sizeof(const char*);j++) {
LoadTerrainTextures(i,SupportedTextureFormats[j]);
}
}
}
#include "TextureManager.h"
#include "lib.h"
#include "ogl.h"
#include "res/tex.h"
#ifdef _WIN32
#include <io.h>
#endif
#include <algorithm>
const char* SupportedTextureFormats[] = { "png", "dds", "tga", "bmp" };
CTextureManager g_TexMan;
CTextureManager::CTextureManager()
{
m_TerrainTextures.reserve(32);
}
void CTextureManager::AddTextureType(const char* name)
{
m_TerrainTextures.resize(m_TerrainTextures.size()+1);
STextureType& ttype=m_TerrainTextures.back();
ttype.m_Name=name;
ttype.m_Index=m_TerrainTextures.size()-1;
}
CTextureEntry* CTextureManager::FindTexture(const char* filename)
{
// check if file already loaded
for (uint k=0;k<m_TerrainTextures.size();k++) {
STextureType& ttype=m_TerrainTextures[k];
for (uint i=0;i<ttype.m_Textures.size();i++) {
if (strcmp((const char*) ttype.m_Textures[i]->m_Name,filename)==0) {
return ttype.m_Textures[i];
}
}
}
return 0;
}
CTextureEntry* CTextureManager::FindTexture(Handle handle)
{
for (uint k=0;k<m_TerrainTextures.size();k++) {
STextureType& ttype=m_TerrainTextures[k];
for (uint i=0;i<ttype.m_Textures.size();i++) {
if (handle==ttype.m_Textures[i]->m_Handle) {
return ttype.m_Textures[i];
}
}
}
return 0;
}
CTextureEntry* CTextureManager::AddTexture(const char* filename,int type)
{
assert((uint)type<m_TerrainTextures.size());
CStr pathname("art/textures/terrain/types/");
pathname+=m_TerrainTextures[type].m_Name;
pathname+='/';
pathname+=filename;
Handle h=tex_load((const char*) pathname);
if (!h) {
return 0;
} else {
int tw;
int th;
tex_info(h, &tw, &th, NULL, NULL, NULL);
tw &= (tw-1);
th &= (th-1);
if (tw || th) {
return 0;
}
}
// create new texture entry
CTextureEntry* texentry=new CTextureEntry;
texentry->m_Name=filename;
texentry->m_Handle=h;
texentry->m_Type=type;
// upload texture for future GL use
tex_upload(h,GL_LINEAR_MIPMAP_LINEAR);
// setup texture to repeat
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// get root color for coloring minimap by querying root level of the texture
// (this should decompress any compressed textures for us),
// then scaling it down to a 1x1 size
// - an alternative approach of just grabbing the top level of the mipmap tree fails
// (or gives an incorrect colour) in some cases:
// - suspect bug on Radeon cards when SGIS_generate_mipmap is used
// - any textures without mipmaps
// we'll just take the basic approach here:
int width,height;
glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_WIDTH,&width);
glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_HEIGHT,&height);
unsigned char* buf=new unsigned char[width*height*4];
glGetTexImage(GL_TEXTURE_2D,0,GL_BGRA_EXT,GL_UNSIGNED_BYTE,buf);
gluScaleImage(GL_BGRA_EXT,width,height,GL_UNSIGNED_BYTE,buf,
1,1,GL_UNSIGNED_BYTE,&texentry->m_BaseColor);
delete[] buf;
// add entry to list ..
m_TerrainTextures[type].m_Textures.push_back(texentry);
// .. and return it
return texentry;
}
void CTextureManager::DeleteTexture(CTextureEntry* entry)
{
// find entry in list
std::vector<CTextureEntry*>& textures=m_TerrainTextures[entry->m_Type].m_Textures;
typedef std::vector<CTextureEntry*>::iterator Iter;
Iter i=std::find(textures.begin(),textures.end(),entry);
if (i!=textures.end()) {
textures.erase(i);
}
delete entry;
}
void CTextureManager::LoadTerrainTextures(int terraintype,const char* fileext)
{
#ifdef _WIN32
struct _finddata_t file;
long handle;
// build pathname
CStr pathname("mods\\official\\art\\textures\\terrain\\types\\");
pathname+=m_TerrainTextures[terraintype].m_Name;
pathname+="\\";
CStr findname(pathname);
findname+="*.";
findname+=fileext;
// Find first matching file in directory for this terrain type
if ((handle=_findfirst((const char*) findname,&file))!=-1) {
AddTexture(file.name,terraintype);
// Find the rest of the matching files
while( _findnext(handle,&file)==0) {
AddTexture((const char*) file.name,terraintype);
}
_findclose(handle);
}
#endif
}
void CTextureManager::BuildTerrainTypes()
{
#ifdef _WIN32
struct _finddata_t file;
long handle;
// Find first matching directory in terrain\textures
if ((handle=_findfirst("mods\\official\\art\\textures\\terrain\\types\\*",&file))!=-1) {
if ((file.attrib & _A_SUBDIR) && file.name[0]!='.') {
AddTextureType(file.name);
}
// Find the rest of the matching files
while( _findnext(handle,&file)==0) {
if ((file.attrib & _A_SUBDIR) && file.name[0]!='.') {
AddTextureType(file.name);
}
}
_findclose(handle);
}
#endif
}
void CTextureManager::LoadTerrainTextures()
{
// find all the terrain types by directory name
BuildTerrainTypes();
// now iterate through terrain types loading all textures of that type
for (uint i=0;i<m_TerrainTextures.size();i++) {
for (uint j=0;j<sizeof(SupportedTextureFormats)/sizeof(const char*);j++) {
LoadTerrainTextures(i,SupportedTextureFormats[j]);
}
}
}

View File

@ -1,327 +1,325 @@
#include "Matrix3D.h"
#include "Renderer.h"
#include "Terrain.h"
#include "LightEnv.h"
#include "TextureManager.h"
#include "ObjectManager.h"
#include "Prometheus.h"
#include "time.h"
#include "sdl.h"
#include "res/tex.h"
#include "detect.h"
#include <malloc.h>
// TODO: fix scrolling hack - framerate independent, use SDL
//#include "win.h" // REMOVEME
void InitScene ();
void InitResources ();
void RenderScene ();
extern bool keys[512]; // SDL also defines non-ascii keys; 512 should be enough
CMatrix3D g_WorldMat;
CRenderer g_Renderer;
CTerrain g_Terrain;
CCamera g_Camera;
CLightEnv g_LightEnv;
int SelPX, SelPY, SelTX, SelTY;
int g_BaseTexCounter = 0;
int g_SecTexCounter = 1;
int g_TransTexCounter = 0;
int g_TickCounter = 0;
double g_LastTime;
const int NUM_ALPHA_MAPS = 13;
int mouse_x=50, mouse_y=50;
void terr_init()
{
int xres,yres;
get_cur_resolution(xres,yres);
g_Renderer.Open(xres,yres,32);
SViewPort vp;
vp.m_X=0;
vp.m_Y=0;
vp.m_Width=xres;
vp.m_Height=yres;
g_Camera.SetViewPort(&vp);
InitResources ();
InitScene ();
}
void terr_update(float time)
{
CVector3D right(time*60,0,time*60);
CVector3D up(time*60,0,-time*60);
if (mouse_x >= g_xres-2)
g_Camera.m_Orientation.Translate(right);
if (mouse_x <= 3)
g_Camera.m_Orientation.Translate(right*-1);
if (mouse_y >= g_yres-2)
g_Camera.m_Orientation.Translate(up);
if (mouse_y <= 3)
g_Camera.m_Orientation.Translate(up*-1);
float fov = g_Camera.GetFOV();
float d = DEGTORAD(0.4f);
if(keys[SDLK_KP_MINUS])
if (fov+d < DEGTORAD(90))
g_Camera.SetProjection(1, 1000, fov + d);
if(keys[SDLK_KP_PLUS])
if (fov-d > DEGTORAD(20))
g_Camera.SetProjection(1, 1000, fov - d);
g_Camera.UpdateFrustum ();
}
bool terr_handler(const SDL_Event& ev)
{
switch(ev.type)
{
case SDL_MOUSEMOTION:
mouse_x = ev.motion.x;
mouse_y = ev.motion.y;
break;
case SDL_KEYDOWN:
switch(ev.key.keysym.sym)
{
case 'W':
if (g_Renderer.GetTerrainRenderMode()==WIREFRAME) {
g_Renderer.SetTerrainRenderMode(SOLID);
} else {
g_Renderer.SetTerrainRenderMode(WIREFRAME);
}
break;
case 'H':
// quick hack to return camera home, for screenshots (after alt+tabbing)
g_Camera.SetProjection (1, 1000, DEGTORAD(20));
g_Camera.m_Orientation.SetXRotation(DEGTORAD(30));
g_Camera.m_Orientation.RotateY(DEGTORAD(-45));
g_Camera.m_Orientation.Translate (100, 150, -100);
break;
/* case 'L':
g_HillShading = !g_HillShading;
break;*/
// tile selection
case SDLK_DOWN:
if(++SelTX > 15)
if(SelPX == g_Terrain.GetPatchesPerSide()-1)
SelTX = 15;
else
SelTX = 0, SelPX++;
break;
case SDLK_UP:
if(--SelTX < 0)
if(SelPX == 0)
SelTX = 0;
else
SelTX = 15, SelPX--;
break;
case SDLK_RIGHT:
if(++SelTY > 15)
if(SelPY == g_Terrain.GetPatchesPerSide()-1)
SelTY = 15;
else
SelTY = 0, SelPY++;
break;
case SDLK_LEFT:
if(--SelTY < 0)
if(SelPY == 0)
SelTY = 0;
else
SelTY = 15, SelPY--;
break;
case SDLK_KP0:
{
CMiniPatch *MPatch = &g_Terrain.GetPatch(SelPY, SelPX)->m_MiniPatches[SelTY][SelTX];
/*if (!MPatch->Tex2)
{
MPatch->m_AlphaMap = AlphaMaps[g_TransTexCounter];
MPatch->Tex2 = BaseTexs[g_SecTexCounter];
}
else
{
MPatch->Tex2 = 0;
MPatch->m_AlphaMap = 0;
}*/
break;
}
/*case SDLK_KP1:
{
CMiniPatch *MPatch = &g_Terrain.GetPatch(SelPY, SelPX)->m_MiniPatches[SelTY][SelTX];
g_BaseTexCounter++;
if (g_BaseTexCounter > 4)
g_BaseTexCounter = 0;
MPatch->Tex1 = BaseTexs[g_BaseTexCounter];
break;
}
case SDLK_KP2:
{
CMiniPatch *MPatch = &g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX];
if (MPatch->Tex2)
{
g_SecTexCounter++;
if (g_SecTexCounter > 4)
g_SecTexCounter = 0;
MPatch->Tex2 = BaseTexs[g_SecTexCounter];
}
break;
}
case SDLK_KP3:
{
CMiniPatch *MPatch = &g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX];
if (MPatch->m_AlphaMap)
{
g_TransTexCounter++;
if (g_TransTexCounter >= NUM_ALPHA_MAPS)
g_TransTexCounter = 0;
MPatch->m_AlphaMap = AlphaMaps[g_TransTexCounter];
}
break;
}*/
}
}
return false;
}
void InitScene ()
{
// setup default lighting environment
g_LightEnv.m_SunColor=RGBColor(1,1,1);
g_LightEnv.m_Rotation=DEGTORAD(270);
g_LightEnv.m_Elevation=DEGTORAD(45);
g_LightEnv.m_TerrainAmbientColor=RGBColor(0,0,0);
g_LightEnv.m_UnitsAmbientColor=RGBColor(0.4f,0.4f,0.4f);
g_Renderer.SetLightEnv(&g_LightEnv);
// load terrain
Handle ht = tex_load("terrain.raw");
if(ht > 0)
{
const u8* p;
int w;
int h;
tex_info(ht, &w, &h, NULL, NULL, (void **)&p);
printf("terrain.raw: %dx%d\n", w, h);
u16 *p16=new u16[w*h];
u16 *p16p=p16;
while (p16p < p16+(w*h))
*p16p++ = (*p++) << 8;
g_Terrain.Resize(20);
g_Terrain.SetHeightMap(p16);
delete[] p16;
tex_free(ht);
}
// get default texture to apply to terrain
CTextureEntry* texture=0;
for (uint ii=0;ii<g_TexMan.m_TerrainTextures.size();ii++) {
if (g_TexMan.m_TerrainTextures[ii].m_Textures.size()) {
texture=g_TexMan.m_TerrainTextures[ii].m_Textures[0];
break;
}
}
// cover entire terrain with default texture
u32 patchesPerSide=g_Terrain.GetPatchesPerSide();
for (uint pj=0; pj<patchesPerSide; pj++) {
for (uint pi=0; pi<patchesPerSide; pi++) {
CPatch* patch=g_Terrain.GetPatch(pi,pj);
for (int j=0;j<16;j++) {
for (int i=0;i<16;i++) {
patch->m_MiniPatches[j][i].Tex1=texture ? texture->m_Handle :0;
}
}
}
}
g_Camera.SetProjection (1, 1000, DEGTORAD(20));
g_Camera.m_Orientation.SetXRotation(DEGTORAD(30));
g_Camera.m_Orientation.RotateY(DEGTORAD(-45));
g_Camera.m_Orientation.Translate (100, 150, -100);
SelPX = SelPY = SelTX = SelTY = 0;
}
void InitResources()
{
#ifndef _WIN32
g_TexMan.AddTextureType("grass");
g_TexMan.AddTexture("Base1.tga", 0);
#else
g_TexMan.LoadTerrainTextures();
g_ObjMan.LoadObjects();
#endif
const char* fns[CRenderer::NumAlphaMaps] = {
"art/textures/terrain/alphamaps/special/blendcircle.png",
"art/textures/terrain/alphamaps/special/blendlshape.png",
"art/textures/terrain/alphamaps/special/blendedge.png",
"art/textures/terrain/alphamaps/special/blendedgecorner.png",
"art/textures/terrain/alphamaps/special/blendedgetwocorners.png",
"art/textures/terrain/alphamaps/special/blendfourcorners.png",
"art/textures/terrain/alphamaps/special/blendtwooppositecorners.png",
"art/textures/terrain/alphamaps/special/blendlshapecorner.png",
"art/textures/terrain/alphamaps/special/blendtwocorners.png",
"art/textures/terrain/alphamaps/special/blendcorner.png",
"art/textures/terrain/alphamaps/special/blendtwoedges.png",
"art/textures/terrain/alphamaps/special/blendthreecorners.png",
"art/textures/terrain/alphamaps/special/blendushape.png",
"art/textures/terrain/alphamaps/special/blendbad.png"
};
g_Renderer.LoadAlphaMaps(fns);
}
#include "Matrix3D.h"
#include "Renderer.h"
#include "Terrain.h"
#include "LightEnv.h"
#include "TextureManager.h"
#include "ObjectManager.h"
#include "Prometheus.h"
#include "time.h"
#include "sdl.h"
#include "res/tex.h"
#include "detect.h"
#include <malloc.h>
// TODO: fix scrolling hack - framerate independent, use SDL
//#include "win.h" // REMOVEME
void InitScene ();
void InitResources ();
void RenderScene ();
extern bool keys[512]; // SDL also defines non-ascii keys; 512 should be enough
CMatrix3D g_WorldMat;
CRenderer g_Renderer;
CTerrain g_Terrain;
CCamera g_Camera;
CLightEnv g_LightEnv;
int SelPX, SelPY, SelTX, SelTY;
int g_BaseTexCounter = 0;
int g_SecTexCounter = 1;
int g_TransTexCounter = 0;
int g_TickCounter = 0;
double g_LastTime;
const int NUM_ALPHA_MAPS = 13;
int mouse_x=50, mouse_y=50;
void terr_init()
{
int xres,yres;
get_cur_resolution(xres,yres);
g_Renderer.Open(xres,yres,32);
SViewPort vp;
vp.m_X=0;
vp.m_Y=0;
vp.m_Width=xres;
vp.m_Height=yres;
g_Camera.SetViewPort(&vp);
InitResources ();
InitScene ();
}
void terr_update(float time)
{
CVector3D right(time*60,0,time*60);
CVector3D up(time*60,0,-time*60);
if (mouse_x >= g_xres-2)
g_Camera.m_Orientation.Translate(right);
if (mouse_x <= 3)
g_Camera.m_Orientation.Translate(right*-1);
if (mouse_y >= g_yres-2)
g_Camera.m_Orientation.Translate(up);
if (mouse_y <= 3)
g_Camera.m_Orientation.Translate(up*-1);
float fov = g_Camera.GetFOV();
float d = DEGTORAD(0.4f);
if(keys[SDLK_KP_MINUS])
if (fov+d < DEGTORAD(90))
g_Camera.SetProjection(1, 1000, fov + d);
if(keys[SDLK_KP_PLUS])
if (fov-d > DEGTORAD(20))
g_Camera.SetProjection(1, 1000, fov - d);
g_Camera.UpdateFrustum ();
}
bool terr_handler(const SDL_Event& ev)
{
switch(ev.type)
{
case SDL_MOUSEMOTION:
mouse_x = ev.motion.x;
mouse_y = ev.motion.y;
break;
case SDL_KEYDOWN:
switch(ev.key.keysym.sym)
{
case 'W':
if (g_Renderer.GetTerrainRenderMode()==WIREFRAME) {
g_Renderer.SetTerrainRenderMode(SOLID);
} else {
g_Renderer.SetTerrainRenderMode(WIREFRAME);
}
break;
case 'H':
// quick hack to return camera home, for screenshots (after alt+tabbing)
g_Camera.SetProjection (1, 1000, DEGTORAD(20));
g_Camera.m_Orientation.SetXRotation(DEGTORAD(30));
g_Camera.m_Orientation.RotateY(DEGTORAD(-45));
g_Camera.m_Orientation.Translate (100, 150, -100);
break;
/* case 'L':
g_HillShading = !g_HillShading;
break;*/
// tile selection
case SDLK_DOWN:
if(++SelTX > 15)
if(SelPX == g_Terrain.GetPatchesPerSide()-1)
SelTX = 15;
else
SelTX = 0, SelPX++;
break;
case SDLK_UP:
if(--SelTX < 0)
if(SelPX == 0)
SelTX = 0;
else
SelTX = 15, SelPX--;
break;
case SDLK_RIGHT:
if(++SelTY > 15)
if(SelPY == g_Terrain.GetPatchesPerSide()-1)
SelTY = 15;
else
SelTY = 0, SelPY++;
break;
case SDLK_LEFT:
if(--SelTY < 0)
if(SelPY == 0)
SelTY = 0;
else
SelTY = 15, SelPY--;
break;
case SDLK_KP0:
{
CMiniPatch *MPatch = &g_Terrain.GetPatch(SelPY, SelPX)->m_MiniPatches[SelTY][SelTX];
/*if (!MPatch->Tex2)
{
MPatch->m_AlphaMap = AlphaMaps[g_TransTexCounter];
MPatch->Tex2 = BaseTexs[g_SecTexCounter];
}
else
{
MPatch->Tex2 = 0;
MPatch->m_AlphaMap = 0;
}*/
break;
}
/*case SDLK_KP1:
{
CMiniPatch *MPatch = &g_Terrain.GetPatch(SelPY, SelPX)->m_MiniPatches[SelTY][SelTX];
g_BaseTexCounter++;
if (g_BaseTexCounter > 4)
g_BaseTexCounter = 0;
MPatch->Tex1 = BaseTexs[g_BaseTexCounter];
break;
}
case SDLK_KP2:
{
CMiniPatch *MPatch = &g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX];
if (MPatch->Tex2)
{
g_SecTexCounter++;
if (g_SecTexCounter > 4)
g_SecTexCounter = 0;
MPatch->Tex2 = BaseTexs[g_SecTexCounter];
}
break;
}
case SDLK_KP3:
{
CMiniPatch *MPatch = &g_Terrain.m_Patches[SelPY][SelPX].m_MiniPatches[SelTY][SelTX];
if (MPatch->m_AlphaMap)
{
g_TransTexCounter++;
if (g_TransTexCounter >= NUM_ALPHA_MAPS)
g_TransTexCounter = 0;
MPatch->m_AlphaMap = AlphaMaps[g_TransTexCounter];
}
break;
}*/
}
}
return false;
}
void InitScene ()
{
// setup default lighting environment
g_LightEnv.m_SunColor=RGBColor(1,1,1);
g_LightEnv.m_Rotation=DEGTORAD(270);
g_LightEnv.m_Elevation=DEGTORAD(45);
g_LightEnv.m_TerrainAmbientColor=RGBColor(0,0,0);
g_LightEnv.m_UnitsAmbientColor=RGBColor(0.4f,0.4f,0.4f);
g_Renderer.SetLightEnv(&g_LightEnv);
// load terrain
Handle ht = tex_load("terrain.raw");
if(ht > 0)
{
const u8* p;
int w;
int h;
tex_info(ht, &w, &h, NULL, NULL, (void **)&p);
printf("terrain.raw: %dx%d\n", w, h);
u16 *p16=new u16[w*h];
u16 *p16p=p16;
while (p16p < p16+(w*h))
*p16p++ = (*p++) << 8;
g_Terrain.Resize(20);
g_Terrain.SetHeightMap(p16);
delete[] p16;
tex_free(ht);
}
// get default texture to apply to terrain
CTextureEntry* texture=0;
for (uint ii=0;ii<g_TexMan.m_TerrainTextures.size();ii++) {
if (g_TexMan.m_TerrainTextures[ii].m_Textures.size()) {
texture=g_TexMan.m_TerrainTextures[ii].m_Textures[0];
break;
}
}
// cover entire terrain with default texture
u32 patchesPerSide=g_Terrain.GetPatchesPerSide();
for (uint pj=0; pj<patchesPerSide; pj++) {
for (uint pi=0; pi<patchesPerSide; pi++) {
CPatch* patch=g_Terrain.GetPatch(pi,pj);
for (int j=0;j<16;j++) {
for (int i=0;i<16;i++) {
patch->m_MiniPatches[j][i].Tex1=texture ? texture->m_Handle :0;
}
}
}
}
g_Camera.SetProjection (1, 1000, DEGTORAD(20));
g_Camera.m_Orientation.SetXRotation(DEGTORAD(30));
g_Camera.m_Orientation.RotateY(DEGTORAD(-45));
g_Camera.m_Orientation.Translate (100, 150, -100);
SelPX = SelPY = SelTX = SelTY = 0;
}
void InitResources()
{
#ifndef _WIN32
g_TexMan.AddTextureType("grass");
g_TexMan.AddTexture("Base1.tga", 0);
#else
g_TexMan.LoadTerrainTextures();
g_ObjMan.LoadObjects();
#endif
const char* fns[CRenderer::NumAlphaMaps] = {
"art/textures/terrain/alphamaps/special/blendcircle.png",
"art/textures/terrain/alphamaps/special/blendlshape.png",
"art/textures/terrain/alphamaps/special/blendedge.png",
"art/textures/terrain/alphamaps/special/blendedgecorner.png",
"art/textures/terrain/alphamaps/special/blendedgetwocorners.png",
"art/textures/terrain/alphamaps/special/blendfourcorners.png",
"art/textures/terrain/alphamaps/special/blendtwooppositecorners.png",
"art/textures/terrain/alphamaps/special/blendlshapecorner.png",
"art/textures/terrain/alphamaps/special/blendtwocorners.png",
"art/textures/terrain/alphamaps/special/blendcorner.png",
"art/textures/terrain/alphamaps/special/blendtwoedges.png",
"art/textures/terrain/alphamaps/special/blendthreecorners.png",
"art/textures/terrain/alphamaps/special/blendushape.png",
"art/textures/terrain/alphamaps/special/blendbad.png"
};
g_Renderer.LoadAlphaMaps(fns);
}