1
0
forked from 0ad/0ad

Fixes big screenshots with water (reflection or refraction camera), adds big screenshot customization.

Commented By: Stan, wraitii
Differential Revision: https://code.wildfiregames.com/D3557
This was SVN commit r24891.
This commit is contained in:
Vladislav Belov 2021-02-12 21:20:07 +00:00
parent 44dc2ca6f2
commit f175bc4f8d
5 changed files with 63 additions and 40 deletions

View File

@ -59,6 +59,11 @@ forceglprofile = "compatibility" ; Possible values: compatibility, core, es
forceglmajorversion = 3
forceglminorversion = 3
; Big screenshot tiles
screenshot.tiles = 4
screenshot.tilewidth = 480
screenshot.tileheight = 270
; Emulate right-click with Ctrl+Click on Mac mice
macmouse = false

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -208,7 +208,14 @@ static InReaction MainInputHandler(const SDL_Event_* ev)
}
else if (hotkey == "bigscreenshot")
{
WriteBigScreenshot(L".bmp", 10);
int tiles = 4, tileWidth = 256, tileHeight = 256;
CFG_GET_VAL("screenshot.tiles", tiles);
CFG_GET_VAL("screenshot.tilewidth", tileWidth);
CFG_GET_VAL("screenshot.tileheight", tileHeight);
if (tiles > 0 && tileWidth > 0 && tileHeight > 0)
WriteBigScreenshot(L".bmp", tiles, tileWidth, tileHeight);
else
LOGWARNING("Invalid big screenshot size: tiles=%d tileWidth=%d tileHeight=%d", tiles, tileWidth, tileHeight);
return IN_HANDLED;
}
else if (hotkey == "togglefullscreen")

View File

@ -298,11 +298,15 @@ void WriteScreenshot(const VfsPath& extension)
// Similar to WriteScreenshot, but generates an image of size 640*tiles x 480*tiles.
void WriteBigScreenshot(const VfsPath& extension, int tiles)
// Similar to WriteScreenshot, but generates an image of size tileWidth*tiles x tileHeight*tiles.
void WriteBigScreenshot(const VfsPath& extension, int tiles, int tileWidth, int tileHeight)
{
// If the game hasn't started yet then use WriteScreenshot to generate the image.
if(g_Game == NULL){ WriteScreenshot(L".bmp"); return; }
if (g_Game == nullptr)
{
WriteScreenshot(L".bmp");
return;
}
// get next available numbered filename
// note: %04d -> always 4 digits, so sorting by filename works correctly.
@ -313,10 +317,9 @@ void WriteBigScreenshot(const VfsPath& extension, int tiles)
// 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;
ENSURE(g_xres >= tile_w && g_yres >= tile_h);
ENSURE(g_xres >= tileWidth && g_yres >= tileHeight);
const int img_w = tile_w*tiles, img_h = tile_h*tiles;
const int img_w = tileWidth * tiles, img_h = tileHeight * tiles;
const int bpp = 24;
GLenum fmt = GL_RGB;
int flags = TEX_BOTTOM_UP;
@ -331,7 +334,7 @@ void WriteBigScreenshot(const VfsPath& extension, int tiles)
}
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 tile_size = tileWidth * tileHeight * bpp/8;
const size_t hdr_size = tex_hdr_size(filename);
void* tile_data = malloc(tile_size);
if(!tile_data)
@ -340,7 +343,7 @@ void WriteBigScreenshot(const VfsPath& extension, int tiles)
return;
}
shared_ptr<u8> img_buf;
AllocateAligned(img_buf, hdr_size+img_size, maxSectorSize);
AllocateAligned(img_buf, hdr_size + img_size, maxSectorSize);
Tex t;
GLvoid* img = img_buf.get() + hdr_size;
@ -356,8 +359,8 @@ void WriteBigScreenshot(const VfsPath& extension, int tiles)
// 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_Renderer.Resize(tileWidth, tileHeight);
SViewPort vp = { 0, 0, tileWidth, tileHeight };
g_Game->GetView()->SetViewport(vp);
}
@ -380,6 +383,7 @@ void WriteBigScreenshot(const VfsPath& extension, int tiles)
// Render each tile
CMatrix3D projection;
projection.SetIdentity();
const float aspectRatio = 1.0f * tileWidth / tileHeight;
for (int tile_y = 0; tile_y < tiles; ++tile_y)
{
for (int tile_x = 0; tile_x < tiles; ++tile_x)
@ -387,7 +391,7 @@ void WriteBigScreenshot(const VfsPath& extension, int tiles)
// Adjust the camera to render the appropriate region
if (oldCamera.GetProjectionType() == CCamera::PERSPECTIVE)
{
projection.SetPerspectiveTile(oldCamera.GetFOV(), oldCamera.GetAspectRatio(), oldCamera.GetNearPlane(), oldCamera.GetFarPlane(), tiles, tile_x, tile_y);
projection.SetPerspectiveTile(oldCamera.GetFOV(), aspectRatio, oldCamera.GetNearPlane(), oldCamera.GetFarPlane(), tiles, tile_x, tile_y);
}
g_Game->GetView()->GetCamera()->SetProjection(projection);
@ -398,12 +402,12 @@ void WriteBigScreenshot(const VfsPath& extension, int tiles)
RenderLogger(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)
glReadPixels(0, 0, tileWidth, tileHeight, fmt, GL_UNSIGNED_BYTE, tile_data);
for (int y = 0; y < tileHeight; ++y)
{
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;
memcpy(dest, src, tile_w * bpp/8);
void* dest = static_cast<char*>(img) + ((tile_y * tileHeight + y) * img_w + (tile_x * tileWidth)) * bpp / 8;
void* src = static_cast<char*>(tile_data) + y * tileWidth * bpp / 8;
memcpy(dest, src, tileWidth * bpp / 8);
}
}
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2018 Wildfire Games.
/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -30,7 +30,7 @@ const wchar_t* ErrorString(int err);
OsPath createDateIndexSubdirectory(const OsPath& parentDir);
void WriteScreenshot(const VfsPath& extension);
void WriteBigScreenshot(const VfsPath& extension, int tiles);
void WriteBigScreenshot(const VfsPath& extension, int tiles = 4, int tileWidth = 640, int tileHeight = 480);
Status tex_write(Tex* t, const VfsPath& filename);

View File

@ -926,13 +926,17 @@ void CRenderer::ComputeReflectionCamera(CCamera& camera, const CBoundingBoxAlign
{
WaterManager& wm = m->waterManager;
ENSURE(m_ViewCamera.GetProjectionType() == CCamera::PERSPECTIVE);
float fov = m_ViewCamera.GetFOV();
CMatrix3D projection;
if (m_ViewCamera.GetProjectionType() == CCamera::PERSPECTIVE)
{
const float aspectRatio = 1.0f;
// Expand fov slightly since ripples can reflect parts of the scene that
// are slightly outside the normal camera view, and we want to avoid any
// noticeable edge-filtering artifacts
fov *= 1.05f;
projection.SetPerspective(m_ViewCamera.GetFOV() * 1.05f, aspectRatio, m_ViewCamera.GetNearPlane(), m_ViewCamera.GetFarPlane());
}
else
projection = m_ViewCamera.GetProjection();
camera = m_ViewCamera;
@ -942,7 +946,7 @@ void CRenderer::ComputeReflectionCamera(CCamera& camera, const CBoundingBoxAlign
// the whole screen despite being rendered into a square, and cover slightly more
// of the view so we can see wavy reflections of slightly off-screen objects.
camera.m_Orientation.Scale(1, -1, 1);
camera.m_Orientation.Translate(0, 2*wm.m_WaterHeight, 0);
camera.m_Orientation.Translate(0, 2 * wm.m_WaterHeight, 0);
camera.UpdateFrustum(scissor);
// Clip slightly above the water to improve reflections of objects on the water
// when the reflections are distorted.
@ -954,27 +958,30 @@ void CRenderer::ComputeReflectionCamera(CCamera& camera, const CBoundingBoxAlign
vp.m_X = 0;
vp.m_Y = 0;
camera.SetViewPort(vp);
camera.SetPerspectiveProjection(m_ViewCamera.GetNearPlane(), m_ViewCamera.GetFarPlane(), fov);
camera.SetProjection(projection);
CMatrix3D scaleMat;
scaleMat.SetScaling(m_Height/float(std::max(1, m_Width)), 1.0f, 1.0f);
scaleMat.SetScaling(m_Height / static_cast<float>(std::max(1, m_Width)), 1.0f, 1.0f);
camera.SetProjection(scaleMat * camera.GetProjection());
CVector4D camPlane(0, 1, 0, -wm.m_WaterHeight + 0.5f);
SetObliqueFrustumClipping(camera, camPlane);
}
void CRenderer::ComputeRefractionCamera(CCamera& camera, const CBoundingBoxAligned& scissor) const
{
WaterManager& wm = m->waterManager;
ENSURE(m_ViewCamera.GetProjectionType() == CCamera::PERSPECTIVE);
float fov = m_ViewCamera.GetFOV();
CMatrix3D projection;
if (m_ViewCamera.GetProjectionType() == CCamera::PERSPECTIVE)
{
const float aspectRatio = 1.0f;
// Expand fov slightly since ripples can reflect parts of the scene that
// are slightly outside the normal camera view, and we want to avoid any
// noticeable edge-filtering artifacts
fov *= 1.05f;
projection.SetPerspective(m_ViewCamera.GetFOV() * 1.05f, aspectRatio, m_ViewCamera.GetNearPlane(), m_ViewCamera.GetFarPlane());
}
else
projection = m_ViewCamera.GetProjection();
camera = m_ViewCamera;
@ -991,9 +998,9 @@ void CRenderer::ComputeRefractionCamera(CCamera& camera, const CBoundingBoxAlign
vp.m_X = 0;
vp.m_Y = 0;
camera.SetViewPort(vp);
camera.SetPerspectiveProjection(m_ViewCamera.GetNearPlane(), m_ViewCamera.GetFarPlane(), fov);
camera.SetProjection(projection);
CMatrix3D scaleMat;
scaleMat.SetScaling(m_Height/float(std::max(1, m_Width)), 1.0f, 1.0f);
scaleMat.SetScaling(m_Height / static_cast<float>(std::max(1, m_Width)), 1.0f, 1.0f);
camera.SetProjection(scaleMat * camera.GetProjection());
}