0ad/source/ps/Util.cpp
janwas d64e2ed19f dyn_array: use memcpy2
add tex error codes
move memcpy code to ia32
tex: simplify codec call with separate tex_codec_for* calls
codecs: use error code instead of string; remove redundant params
ia32: heavy WIP - testing memcpy implementations
util: prepare for zero-copy improvement to screenshot code

This was SVN commit r2695.
2005-09-10 14:28:55 +00:00

205 lines
4.9 KiB
C++

#include "precompiled.h"
#include "lib/res/file/vfs.h"
#include "lib/ogl.h"
#include "lib/timer.h"
#include "lib/detect.h"
#include "lib/res/res.h"
#include "lib/res/graphics/tex.h"
#include "ps/GameSetup/Config.h"
static std::string SplitExts(const char *exts)
{
std::string str = exts;
std::string ret = "";
size_t idx = str.find_first_of(" ");
while(idx != std::string::npos)
{
if(idx >= str.length() - 1)
{
ret += str;
break;
}
ret += str.substr(0, idx);
ret += "\n";
str = str.substr(idx + 1);
idx = str.find_first_of(" ");
}
return ret;
}
void WriteSystemInfo()
{
TIMER(write_sys_info);
get_gfx_info();
// get_cpu_info already called during init - see call site
get_snd_info();
get_mem_status();
struct utsname un;
uname(&un);
FILE* f = fopen("../logs/system_info.txt", "w");
if(!f)
return;
// .. OS
fprintf(f, "OS : %s %s (%s)\n", un.sysname, un.release, un.version);
// .. CPU
fprintf(f, "CPU : %s, %s", un.machine, cpu_type);
if(cpus > 1)
fprintf(f, " (x%d)", cpus);
if(cpu_freq != 0.0f)
{
if(cpu_freq < 1e9)
fprintf(f, ", %.2f MHz\n", cpu_freq*1e-6);
else
fprintf(f, ", %.2f GHz\n", cpu_freq*1e-9);
}
else
fprintf(f, "\n");
// .. memory
fprintf(f, "Memory : %lu MiB; %lu MiB free\n", tot_mem/MiB, avl_mem/MiB);
// .. graphics
fprintf(f, "Graphics Card : %s\n", gfx_card);
fprintf(f, "OpenGL Drivers : %s; %s\n", glGetString(GL_VERSION), gfx_drv_ver);
fprintf(f, "Video Mode : %dx%d:%d@%d\n", g_xres, g_yres, g_bpp, g_freq);
// .. sound
fprintf(f, "Sound Card : %s\n", snd_card);
fprintf(f, "Sound Drivers : %s\n", snd_drv_ver);
//
// .. network name / ips
//
// note: can't use un.nodename because it is for an
// "implementation-defined communications network".
char hostname[128] = "(unknown)";
(void)gethostname(hostname, sizeof(hostname)-1);
// -1 makes sure it's 0-terminated. if the function fails,
// we display "(unknown)" and will skip IP output below.
fprintf(f, "Network Name : %s", hostname);
{
hostent* host = gethostbyname(hostname);
if(!host)
goto no_ip;
struct in_addr** ips = (struct in_addr**)host->h_addr_list;
if(!ips)
goto no_ip;
// output all IPs (> 1 if using VMware or dual ethernet)
fprintf(f, " (");
for(uint i = 0; i < 256 && ips[i]; i++) // safety
{
// separate entries but avoid trailing comma
if(i != 0)
fprintf(f, ", ");
fprintf(f, "%s", inet_ntoa(*ips[i]));
}
fprintf(f, ")");
}
no_ip:
fprintf(f, "\n");
// .. OpenGL extensions (write them last, since it's a lot of text)
const char* exts = oglExtList();
if (!exts) exts = "{unknown}";
fprintf(f, "\nOpenGL Extensions: \n%s\n", SplitExts(exts).c_str());
fclose(f);
f = 0;
}
static const wchar_t* HardcodedErrorString(int err)
{
#define E(sym) case sym: return L ## #sym;
switch(err)
{
E(ERR_NO_MEM)
E(ERR_FILE_NOT_FOUND)
E(ERR_INVALID_HANDLE)
E(ERR_INVALID_PARAM)
E(ERR_EOF)
E(ERR_PATH_NOT_FOUND)
E(ERR_PATH_LENGTH)
default:
return 0;
}
}
const wchar_t* ErrorString(int err)
{
// language file not available (yet)
return HardcodedErrorString(err);
// TODO: load from language file
}
// <extension> identifies the file format that is to be written
// (case-insensitive). examples: "bmp", "png", "jpg".
// BMP is good for quick output at the expense of large files.
void WriteScreenshot(const char* extension)
{
// determine next screenshot number.
//
// current approach: increment number until that file doesn't yet exist.
// this is fairly slow, but it's typically only done once, since the last
// number is cached. binary search shouldn't be necessary.
//
// known bug: after program restart, holes in the number series are
// filled first. example: add 1st and 2nd; [exit] delete 1st; [restart]
// add 3rd -> it gets number 1, not 3.
// could fix via enumerating all files, but it's not worth it ATM.
char fn[VFS_MAX_PATH];
// %04d -> always 4 digits, so sorting by filename works correctly.
const char* file_format_string = "screenshots/screenshot%04d.%s";
static int next_num = 1;
do
sprintf(fn, file_format_string, next_num++, extension);
while(vfs_exists(fn));
const int w = g_xres, h = g_yres;
const int bpp = 24;
GLenum fmt = GL_RGB;
int flags = TEX_BOTTOM_UP;
// we want writing BMP to be as fast as possible,
// so read data from OpenGL in BMP format to obviate conversion.
if(!stricmp(extension, "bmp"))
{
fmt = GL_BGR;
flags |= TEX_BGR;
}
const size_t img_size = w * h * bpp/8;
const size_t hdr_size = tex_hdr_size(fn);
void* data = mem_alloc(hdr_size+img_size, FILE_BLOCK_SIZE);
GLvoid* img = (u8*)data + hdr_size;
glReadPixels(0, 0, w, h, fmt, GL_UNSIGNED_BYTE, img);
if(tex_write(fn, w, h, bpp, flags, img) < 0)
debug_warn("WriteScreenshot: tex_write failed");
mem_free(img);
}