2009-04-18 19:00:33 +02:00
|
|
|
/* Copyright (C) 2009 Wildfire Games.
|
|
|
|
* This file is part of 0 A.D.
|
|
|
|
*
|
|
|
|
* 0 A.D. 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.
|
|
|
|
*
|
|
|
|
* 0 A.D. 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.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2006-04-24 01:14:18 +02:00
|
|
|
#include "precompiled.h"
|
|
|
|
|
2007-01-01 22:25:47 +01:00
|
|
|
#include "lib/posix/posix_utsname.h"
|
|
|
|
#include "lib/posix/posix_sock.h"
|
2006-04-24 01:14:18 +02:00
|
|
|
#include "lib/ogl.h"
|
|
|
|
#include "lib/timer.h"
|
2007-12-22 19:15:52 +01:00
|
|
|
#include "lib/bits.h" // round_up
|
2008-01-07 21:03:19 +01:00
|
|
|
#include "lib/allocators/shared_ptr.h"
|
2006-04-24 01:14:18 +02:00
|
|
|
#include "lib/sysdep/gfx.h"
|
|
|
|
#include "lib/sysdep/snd.h"
|
2010-01-09 20:20:14 +01:00
|
|
|
#include "lib/sysdep/cpu.h"
|
2008-05-12 20:15:08 +02:00
|
|
|
#include "lib/sysdep/os_cpu.h"
|
2008-06-30 19:34:18 +02:00
|
|
|
#include "lib/sysdep/arch/x86_x64/topology.h"
|
2007-12-20 21:21:45 +01:00
|
|
|
#include "lib/tex/tex.h"
|
2008-01-20 22:52:54 +01:00
|
|
|
#include "lib/file/io/io_align.h" // BLOCK_SIZE
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
#include "ps/GameSetup/Config.h"
|
|
|
|
#include "ps/GameSetup/GameSetup.h"
|
|
|
|
#include "ps/Game.h"
|
2007-12-20 21:21:45 +01:00
|
|
|
#include "ps/Filesystem.h"
|
2006-04-24 01:14:18 +02:00
|
|
|
#include "renderer/Renderer.h"
|
|
|
|
#include "maths/MathUtil.h"
|
|
|
|
#include "graphics/GameView.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()
|
|
|
|
{
|
2009-11-03 22:46:35 +01:00
|
|
|
TIMER(L"write_sys_info");
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
// get_cpu_info and gfx_detect already called during init - see call site
|
|
|
|
snd_detect();
|
|
|
|
|
|
|
|
struct utsname un;
|
|
|
|
uname(&un);
|
|
|
|
|
2009-11-03 23:27:25 +01:00
|
|
|
fs::wpath pathname(psLogDir()/L"system_info.txt");
|
|
|
|
FILE* f;
|
|
|
|
errno_t err = _wfopen_s(&f, pathname.string().c_str(), L"w");
|
|
|
|
if(err != 0)
|
2006-04-24 01:14:18 +02:00
|
|
|
return;
|
|
|
|
|
2007-05-09 23:01:11 +02:00
|
|
|
// current timestamp (redundant WRT OS timestamp, but that is not
|
|
|
|
// visible when people are posting this file's contents online)
|
|
|
|
{
|
2009-11-03 22:46:35 +01:00
|
|
|
wchar_t timestampBuf[100] = {'\0'};
|
2007-05-09 23:01:11 +02:00
|
|
|
time_t seconds;
|
|
|
|
time(&seconds);
|
|
|
|
struct tm* t = gmtime(&seconds);
|
2009-11-03 22:46:35 +01:00
|
|
|
const size_t charsWritten = wcsftime(timestampBuf, ARRAY_SIZE(timestampBuf), L"(generated %Y-%m-%d %H:%M:%S UTC)", t);
|
|
|
|
debug_assert(charsWritten != 0);
|
2009-11-04 16:29:28 +01:00
|
|
|
fprintf(f, "%ls\n\n", timestampBuf);
|
2007-05-09 23:01:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// OS
|
2009-11-06 11:59:10 +01:00
|
|
|
fprintf(f, "OS : %s %s (%s)\n", un.sysname, un.release, un.version);
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2007-05-09 23:01:11 +02:00
|
|
|
// CPU
|
2008-05-13 21:43:02 +02:00
|
|
|
const CpuTopology* topology = cpu_topology_Detect();
|
2009-11-06 11:59:10 +01:00
|
|
|
fprintf(f, "CPU : %s, %s (%dx%dx%d)", un.machine, cpu_IdentifierString(), (int)cpu_topology_NumPackages(topology), (int)cpu_topology_CoresPerPackage(topology), (int)cpu_topology_LogicalPerCore(topology));
|
2008-05-13 21:43:02 +02:00
|
|
|
const double cpu_freq = os_cpu_ClockFrequency();
|
2006-04-24 01:14:18 +02:00
|
|
|
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");
|
|
|
|
|
2007-05-09 23:01:11 +02:00
|
|
|
// memory
|
2009-07-25 22:35:48 +02:00
|
|
|
fprintf(f, "Memory : %u MiB; %u MiB free\n", (unsigned)os_cpu_MemorySize(), (unsigned)os_cpu_MemoryAvailable());
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2007-05-09 23:01:11 +02:00
|
|
|
// graphics
|
2009-11-04 16:29:28 +01:00
|
|
|
fprintf(f, "Graphics Card : %ls\n", gfx_card);
|
2009-11-06 11:59:10 +01:00
|
|
|
fprintf(f, "OpenGL Drivers : %s; %ls\n", glGetString(GL_VERSION), gfx_drv_ver);
|
2006-04-24 01:14:18 +02:00
|
|
|
fprintf(f, "Video Mode : %dx%d:%d@%d\n", g_xres, g_yres, g_bpp, g_freq);
|
|
|
|
|
2007-05-09 23:01:11 +02:00
|
|
|
// sound
|
2009-11-04 16:29:28 +01:00
|
|
|
fprintf(f, "Sound Card : %ls\n", snd_card);
|
|
|
|
fprintf(f, "Sound Drivers : %ls\n", snd_drv_ver);
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
|
|
|
|
//
|
2007-05-09 23:01:11 +02:00
|
|
|
// network name / ips
|
2006-04-24 01:14:18 +02:00
|
|
|
//
|
|
|
|
|
|
|
|
// 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.
|
2009-11-06 11:59:10 +01:00
|
|
|
fprintf(f, "Network Name : %s", hostname);
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
{
|
2007-06-24 15:24:40 +02:00
|
|
|
// ignore exception here - see https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=114032
|
2006-04-24 01:14:18 +02:00
|
|
|
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, " (");
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 20:48:32 +02:00
|
|
|
for(size_t i = 0; i < 256 && ips[i]; i++) // safety
|
2006-04-24 01:14:18 +02:00
|
|
|
{
|
|
|
|
// separate entries but avoid trailing comma
|
|
|
|
if(i != 0)
|
|
|
|
fprintf(f, ", ");
|
2009-11-06 11:59:10 +01:00
|
|
|
fprintf(f, "%s", inet_ntoa(*ips[i]));
|
2006-04-24 01:14:18 +02:00
|
|
|
}
|
|
|
|
fprintf(f, ")");
|
|
|
|
}
|
|
|
|
|
|
|
|
no_ip:
|
|
|
|
fprintf(f, "\n");
|
|
|
|
|
|
|
|
|
2007-05-09 23:01:11 +02:00
|
|
|
// OpenGL extensions (write them last, since it's a lot of text)
|
2007-05-02 14:07:08 +02:00
|
|
|
const char* exts = ogl_ExtensionString();
|
2006-04-24 01:14:18 +02:00
|
|
|
if (!exts) exts = "{unknown}";
|
2009-11-06 11:59:10 +01:00
|
|
|
fprintf(f, "\nOpenGL Extensions: \n%s\n", SplitExts(exts).c_str());
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
fclose(f);
|
|
|
|
f = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-05-17 16:48:18 +02:00
|
|
|
// not thread-safe!
|
2006-04-24 01:14:18 +02:00
|
|
|
static const wchar_t* HardcodedErrorString(int err)
|
|
|
|
{
|
2009-11-03 22:46:35 +01:00
|
|
|
static wchar_t description[200];
|
2006-05-17 16:48:18 +02:00
|
|
|
error_description_r((LibError)err, description, ARRAY_SIZE(description));
|
2009-11-03 22:46:35 +01:00
|
|
|
return description;
|
2006-04-24 01:14:18 +02:00
|
|
|
}
|
|
|
|
|
2006-05-17 16:48:18 +02:00
|
|
|
// not thread-safe!
|
2006-04-24 01:14:18 +02:00
|
|
|
const wchar_t* ErrorString(int err)
|
|
|
|
{
|
|
|
|
// language file not available (yet)
|
|
|
|
return HardcodedErrorString(err);
|
|
|
|
|
|
|
|
// TODO: load from language file
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-12-22 19:15:52 +01:00
|
|
|
|
|
|
|
// write the specified texture to disk.
|
|
|
|
// note: <t> cannot be made const because the image may have to be
|
|
|
|
// transformed to write it out in the format determined by <fn>'s extension.
|
2008-01-07 21:03:19 +01:00
|
|
|
static LibError tex_write(Tex* t, const VfsPath& filename)
|
2007-12-22 19:15:52 +01:00
|
|
|
{
|
2009-11-03 22:46:35 +01:00
|
|
|
const std::wstring extension = fs::extension(filename);
|
2007-12-22 19:15:52 +01:00
|
|
|
|
|
|
|
DynArray da;
|
|
|
|
RETURN_ERR(tex_encode(t, extension, &da));
|
|
|
|
|
|
|
|
// write to disk
|
|
|
|
LibError ret = INFO::OK;
|
|
|
|
{
|
|
|
|
(void)da_set_size(&da, round_up(da.cur_size, BLOCK_SIZE));
|
2008-01-10 20:29:52 +01:00
|
|
|
shared_ptr<u8> file = DummySharedPtr(da.base);
|
2008-01-07 21:03:19 +01:00
|
|
|
const ssize_t bytes_written = g_VFS->CreateFile(filename, file, da.pos);
|
2007-12-22 19:15:52 +01:00
|
|
|
if(bytes_written > 0)
|
|
|
|
debug_assert(bytes_written == (ssize_t)da.pos);
|
|
|
|
else
|
|
|
|
ret = (LibError)bytes_written;
|
|
|
|
}
|
|
|
|
|
|
|
|
(void)da_free(&da);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 20:48:32 +02:00
|
|
|
static size_t s_nextScreenshotNumber;
|
2006-04-24 01:14:18 +02:00
|
|
|
|
|
|
|
// <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.
|
2009-11-03 22:46:35 +01:00
|
|
|
void WriteScreenshot(const std::wstring& extension)
|
2006-04-24 01:14:18 +02:00
|
|
|
{
|
|
|
|
// get next available numbered filename
|
|
|
|
// note: %04d -> always 4 digits, so sorting by filename works correctly.
|
2009-11-03 22:46:35 +01:00
|
|
|
const VfsPath basenameFormat(L"screenshots/screenshot%04d");
|
2008-01-07 21:03:19 +01:00
|
|
|
const VfsPath filenameFormat = fs::change_extension(basenameFormat, extension);
|
|
|
|
VfsPath filename;
|
2009-08-04 21:57:53 +02:00
|
|
|
fs_util::NextNumberedFilename(g_VFS, filenameFormat, s_nextScreenshotNumber, filename);
|
2006-04-24 01:14:18 +02:00
|
|
|
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 20:48:32 +02:00
|
|
|
const size_t w = (size_t)g_xres, h = (size_t)g_yres;
|
|
|
|
const size_t bpp = 24;
|
2006-04-24 01:14:18 +02:00
|
|
|
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.
|
2009-11-03 22:46:35 +01:00
|
|
|
if(!wcscasecmp(extension.c_str(), L".bmp"))
|
2006-04-24 01:14:18 +02:00
|
|
|
{
|
|
|
|
fmt = GL_BGR;
|
|
|
|
flags |= TEX_BGR;
|
|
|
|
}
|
|
|
|
|
|
|
|
const size_t img_size = w * h * bpp/8;
|
2008-01-07 21:03:19 +01:00
|
|
|
const size_t hdr_size = tex_hdr_size(filename);
|
2007-12-20 21:21:45 +01:00
|
|
|
shared_ptr<u8> buf = io_Allocate(hdr_size+img_size);
|
|
|
|
GLvoid* img = buf.get() + hdr_size;
|
2006-04-24 01:14:18 +02:00
|
|
|
Tex t;
|
2007-12-20 21:21:45 +01:00
|
|
|
if(tex_wrap(w, h, bpp, flags, buf, hdr_size, &t) < 0)
|
2006-04-24 01:14:18 +02:00
|
|
|
return;
|
had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).
it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.
after several hours, the code now requires fewer casts and less
guesswork.
other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.
This was SVN commit r5942.
2008-05-11 20:48:32 +02:00
|
|
|
glReadPixels(0, 0, (GLsizei)w, (GLsizei)h, fmt, GL_UNSIGNED_BYTE, img);
|
2008-01-07 21:03:19 +01:00
|
|
|
(void)tex_write(&t, filename);
|
2007-12-20 21:21:45 +01:00
|
|
|
tex_free(&t);
|
2006-04-24 01:14:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Similar to WriteScreenshot, but generates an image of size 640*tiles x 480*tiles.
|
2009-11-03 22:46:35 +01:00
|
|
|
void WriteBigScreenshot(const std::wstring& extension, int tiles)
|
2006-04-24 01:14:18 +02:00
|
|
|
{
|
2009-04-18 17:27:38 +02:00
|
|
|
// If the game hasn't started yet then use WriteScreenshot to generate the image.
|
2009-11-03 22:46:35 +01:00
|
|
|
if(g_Game == NULL){ WriteScreenshot(L".bmp"); return; }
|
2009-04-21 17:24:04 +02:00
|
|
|
|
|
|
|
// get next available numbered filename
|
|
|
|
// note: %04d -> always 4 digits, so sorting by filename works correctly.
|
2009-11-03 22:46:35 +01:00
|
|
|
const VfsPath basenameFormat(L"screenshots/screenshot%04d");
|
2009-04-21 17:24:04 +02:00
|
|
|
const VfsPath filenameFormat = fs::change_extension(basenameFormat, extension);
|
|
|
|
VfsPath filename;
|
2009-08-04 21:57:53 +02:00
|
|
|
fs_util::NextNumberedFilename(g_VFS, filenameFormat, s_nextScreenshotNumber, filename);
|
2009-04-21 17:24:04 +02:00
|
|
|
|
|
|
|
// Slightly ugly and inflexible: Always draw 640*480 tiles onto the screen, and
|
|
|
|
// hope the screen is actually large enough for that.
|
|
|
|
const int tile_w = 640, tile_h = 480;
|
|
|
|
debug_assert(g_xres >= tile_w && g_yres >= tile_h);
|
|
|
|
|
|
|
|
const int img_w = tile_w*tiles, img_h = tile_h*tiles;
|
|
|
|
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.
|
2009-11-03 22:46:35 +01:00
|
|
|
if(!wcscasecmp(extension.c_str(), L".bmp"))
|
2006-04-24 01:14:18 +02:00
|
|
|
{
|
2009-04-21 17:24:04 +02:00
|
|
|
fmt = GL_BGR;
|
|
|
|
flags |= TEX_BGR;
|
|
|
|
}
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2009-04-21 17:24:04 +02:00
|
|
|
const size_t img_size = img_w * img_h * bpp/8;
|
|
|
|
const size_t tile_size = tile_w * tile_h * bpp/8;
|
|
|
|
const size_t hdr_size = tex_hdr_size(filename);
|
|
|
|
void* tile_data = malloc(tile_size);
|
|
|
|
if(!tile_data)
|
|
|
|
WARN_ERR_RETURN(ERR::NO_MEM);
|
|
|
|
shared_ptr<u8> img_buf = io_Allocate(hdr_size+img_size);
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2009-04-21 17:24:04 +02:00
|
|
|
Tex t;
|
|
|
|
GLvoid* img = img_buf.get() + hdr_size;
|
|
|
|
if(tex_wrap(img_w, img_h, bpp, flags, img_buf, hdr_size, &t) < 0)
|
|
|
|
return;
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2009-04-21 17:24:04 +02:00
|
|
|
ogl_WarnIfError();
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2009-04-21 17:24:04 +02:00
|
|
|
// Resize various things so that the sizes and aspect ratios are correct
|
|
|
|
{
|
|
|
|
g_Renderer.Resize(tile_w, tile_h);
|
|
|
|
SViewPort vp = { 0, 0, tile_w, tile_h };
|
|
|
|
g_Game->GetView()->GetCamera()->SetViewPort(&vp);
|
|
|
|
g_Game->GetView()->GetCamera()->SetProjection(CGameView::defaultNear, CGameView::defaultFar, CGameView::defaultFOV);
|
|
|
|
}
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2009-04-21 17:24:04 +02:00
|
|
|
// Temporarily move everything onto the front buffer, so the user can
|
|
|
|
// see the exciting progress as it renders (and can tell when it's finished).
|
|
|
|
// (It doesn't just use SwapBuffers, because it doesn't know whether to
|
|
|
|
// call the SDL version or the Atlas version.)
|
|
|
|
GLint oldReadBuffer, oldDrawBuffer;
|
|
|
|
glGetIntegerv(GL_READ_BUFFER, &oldReadBuffer);
|
|
|
|
glGetIntegerv(GL_DRAW_BUFFER, &oldDrawBuffer);
|
|
|
|
glDrawBuffer(GL_FRONT);
|
|
|
|
glReadBuffer(GL_FRONT);
|
|
|
|
|
|
|
|
// Render each tile
|
|
|
|
for (int tile_y = 0; tile_y < tiles; ++tile_y)
|
|
|
|
{
|
|
|
|
for (int tile_x = 0; tile_x < tiles; ++tile_x)
|
2006-04-24 01:14:18 +02:00
|
|
|
{
|
2009-04-21 17:24:04 +02:00
|
|
|
// Adjust the camera to render the appropriate region
|
|
|
|
g_Game->GetView()->GetCamera()->SetProjectionTile(tiles, tile_x, tile_y);
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2009-04-21 17:24:04 +02:00
|
|
|
RenderGui(false);
|
|
|
|
Render();
|
|
|
|
RenderGui(true);
|
|
|
|
|
|
|
|
// Copy the tile pixels into the main image
|
|
|
|
glReadPixels(0, 0, tile_w, tile_h, fmt, GL_UNSIGNED_BYTE, tile_data);
|
|
|
|
for (int y = 0; y < tile_h; ++y)
|
2006-04-24 01:14:18 +02:00
|
|
|
{
|
2009-04-21 17:24:04 +02:00
|
|
|
void* dest = (char*)img + ((tile_y*tile_h + y) * img_w + (tile_x*tile_w)) * bpp/8;
|
|
|
|
void* src = (char*)tile_data + y * tile_w * bpp/8;
|
|
|
|
cpu_memcpy(dest, src, tile_w * bpp/8);
|
2006-04-24 01:14:18 +02:00
|
|
|
}
|
|
|
|
}
|
2009-04-21 17:24:04 +02:00
|
|
|
}
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2009-04-21 17:24:04 +02:00
|
|
|
// Restore the buffer settings
|
|
|
|
glDrawBuffer(oldDrawBuffer);
|
|
|
|
glReadBuffer(oldReadBuffer);
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2009-04-21 17:24:04 +02:00
|
|
|
// Restore the viewport settings
|
|
|
|
{
|
|
|
|
g_Renderer.Resize(g_xres, g_yres);
|
|
|
|
SViewPort vp = { 0, 0, g_xres, g_yres };
|
|
|
|
g_Game->GetView()->GetCamera()->SetViewPort(&vp);
|
|
|
|
g_Game->GetView()->GetCamera()->SetProjection(CGameView::defaultNear, CGameView::defaultFar, CGameView::defaultFOV);
|
2006-04-24 01:14:18 +02:00
|
|
|
|
2009-04-21 17:24:04 +02:00
|
|
|
g_Game->GetView()->GetCamera()->SetProjectionTile(1, 0, 0);
|
2009-04-18 17:27:38 +02:00
|
|
|
}
|
2009-04-21 17:24:04 +02:00
|
|
|
|
|
|
|
(void)tex_write(&t, filename);
|
|
|
|
tex_free(&t);
|
|
|
|
free(tile_data);
|
2006-04-24 01:14:18 +02:00
|
|
|
}
|