mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-06-21 01:29:50 +00:00
Moves frame rendering function to CRenderer and combines with making screenshots.
Tested By: Stan Differential Revision: https://code.wildfiregames.com/D4414 This was SVN commit r26166.
This commit is contained in:
+3
-15
@@ -219,19 +219,12 @@ static InReaction MainInputHandler(const SDL_Event_* ev)
|
||||
}
|
||||
else if (hotkey == "screenshot")
|
||||
{
|
||||
WriteScreenshot(L".png");
|
||||
g_Renderer.MakeScreenShotOnNextFrame(CRenderer::ScreenShotType::DEFAULT);
|
||||
return IN_HANDLED;
|
||||
}
|
||||
else if (hotkey == "bigscreenshot")
|
||||
{
|
||||
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);
|
||||
g_Renderer.MakeScreenShotOnNextFrame(CRenderer::ScreenShotType::BIG);
|
||||
return IN_HANDLED;
|
||||
}
|
||||
else if (hotkey == "togglefullscreen")
|
||||
@@ -456,12 +449,7 @@ static void Frame()
|
||||
if (g_SoundManager)
|
||||
g_SoundManager->IdleTask();
|
||||
|
||||
if (ShouldRender())
|
||||
{
|
||||
Render();
|
||||
|
||||
g_VideoMode.GetBackendDevice()->Present();
|
||||
}
|
||||
g_Renderer.RenderFrame(true);
|
||||
|
||||
g_Profiler.Frame();
|
||||
|
||||
|
||||
+3
-3
@@ -317,11 +317,11 @@ PSRETURN CGame::ReallyStartGame()
|
||||
// all be invisible)
|
||||
Interpolate(0, 0);
|
||||
|
||||
m_GameStarted=true;
|
||||
m_GameStarted = true;
|
||||
|
||||
// Render a frame to begin loading assets
|
||||
// Preload resources to avoid blinking on a first game frame.
|
||||
if (CRenderer::IsInitialised())
|
||||
Render();
|
||||
g_Renderer.PreloadResourcesBeforeNextFrame();
|
||||
|
||||
if (g_NetClient)
|
||||
g_NetClient->LoadFinished();
|
||||
|
||||
@@ -19,14 +19,8 @@
|
||||
|
||||
#include "ps/GameSetup/GameSetup.h"
|
||||
|
||||
#include "graphics/Canvas2D.h"
|
||||
#include "graphics/CinemaManager.h"
|
||||
#include "graphics/Color.h"
|
||||
#include "graphics/GameView.h"
|
||||
#include "graphics/LightEnv.h"
|
||||
#include "graphics/MapReader.h"
|
||||
#include "graphics/MaterialManager.h"
|
||||
#include "graphics/ModelDef.h"
|
||||
#include "graphics/TerrainTextureManager.h"
|
||||
#include "gui/CGUI.h"
|
||||
#include "gui/GUIManager.h"
|
||||
@@ -41,7 +35,6 @@
|
||||
#include "lib/res/h_mgr.h"
|
||||
#include "lib/timer.h"
|
||||
#include "lobby/IXmppClient.h"
|
||||
#include "maths/MathUtil.h"
|
||||
#include "network/NetServer.h"
|
||||
#include "network/NetClient.h"
|
||||
#include "network/NetMessage.h"
|
||||
@@ -74,7 +67,6 @@
|
||||
#include "ps/VideoMode.h"
|
||||
#include "ps/VisualReplay.h"
|
||||
#include "ps/World.h"
|
||||
#include "renderer/ModelRenderer.h"
|
||||
#include "renderer/Renderer.h"
|
||||
#include "renderer/SceneRenderer.h"
|
||||
#include "renderer/VertexBufferManager.h"
|
||||
@@ -88,7 +80,6 @@
|
||||
#include "soundmanager/scripting/JSInterface_Sound.h"
|
||||
#include "soundmanager/ISoundManager.h"
|
||||
#include "tools/atlas/GameInterface/GameLoop.h"
|
||||
#include "tools/atlas/GameInterface/View.h"
|
||||
|
||||
#if !(OS_WIN || OS_MACOSX || OS_ANDROID) // assume all other platforms use X11 for wxWidgets
|
||||
#define MUST_INIT_X11 1
|
||||
@@ -111,9 +102,6 @@ ERROR_TYPE(System, SDLInitFailed);
|
||||
ERROR_TYPE(System, VmodeFailed);
|
||||
ERROR_TYPE(System, RequiredExtensionsMissing);
|
||||
|
||||
bool g_DoRenderGui = true;
|
||||
bool g_DoRenderLogger = true;
|
||||
|
||||
thread_local std::shared_ptr<ScriptContext> g_ScriptContext;
|
||||
|
||||
static const int SANE_TEX_QUALITY_DEFAULT = 5; // keep in sync with code
|
||||
@@ -178,112 +166,6 @@ retry:
|
||||
ogl_tex_set_defaults(q_flags, filter);
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// GUI integration
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
bool ShouldRender()
|
||||
{
|
||||
return !g_app_minimized && (g_app_has_focus || !g_VideoMode.IsInFullscreen());
|
||||
}
|
||||
|
||||
|
||||
void Render()
|
||||
{
|
||||
// Do not render if not focused while in fullscreen or minimised,
|
||||
// as that triggers a difficult-to-reproduce crash on some graphic cards.
|
||||
if (!ShouldRender())
|
||||
return;
|
||||
|
||||
PROFILE3("render");
|
||||
|
||||
g_Profiler2.RecordGPUFrameStart();
|
||||
ogl_WarnIfError();
|
||||
|
||||
// prepare before starting the renderer frame
|
||||
if (g_Game && g_Game->IsGameStarted())
|
||||
g_Game->GetView()->BeginFrame();
|
||||
|
||||
if (g_Game)
|
||||
g_Renderer.GetSceneRenderer().SetSimulation(g_Game->GetSimulation2());
|
||||
|
||||
// start new frame
|
||||
g_Renderer.BeginFrame();
|
||||
|
||||
ogl_WarnIfError();
|
||||
|
||||
if (g_Game && g_Game->IsGameStarted())
|
||||
{
|
||||
g_Game->GetView()->Render();
|
||||
ogl_WarnIfError();
|
||||
}
|
||||
|
||||
g_Renderer.GetSceneRenderer().RenderTextOverlays();
|
||||
|
||||
// If we're in Atlas game view, render special tools
|
||||
if (g_AtlasGameLoop && g_AtlasGameLoop->view)
|
||||
{
|
||||
g_AtlasGameLoop->view->DrawCinemaPathTool();
|
||||
ogl_WarnIfError();
|
||||
}
|
||||
|
||||
if (g_Game && g_Game->IsGameStarted())
|
||||
{
|
||||
g_Game->GetView()->GetCinema()->Render();
|
||||
ogl_WarnIfError();
|
||||
}
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
if (g_DoRenderGui)
|
||||
{
|
||||
OGL_SCOPED_DEBUG_GROUP("Draw GUI");
|
||||
// All GUI elements are drawn in Z order to render semi-transparent
|
||||
// objects correctly.
|
||||
g_GUI->Draw();
|
||||
ogl_WarnIfError();
|
||||
}
|
||||
|
||||
// If we're in Atlas game view, render special overlays (e.g. editor bandbox).
|
||||
if (g_AtlasGameLoop && g_AtlasGameLoop->view)
|
||||
{
|
||||
CCanvas2D canvas;
|
||||
g_AtlasGameLoop->view->DrawOverlays(canvas);
|
||||
ogl_WarnIfError();
|
||||
}
|
||||
|
||||
g_Console->Render();
|
||||
ogl_WarnIfError();
|
||||
|
||||
if (g_DoRenderLogger)
|
||||
{
|
||||
g_Logger->Render();
|
||||
ogl_WarnIfError();
|
||||
}
|
||||
|
||||
// Profile information
|
||||
g_ProfileViewer.RenderProfile();
|
||||
ogl_WarnIfError();
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
g_Renderer.EndFrame();
|
||||
|
||||
PROFILE2_ATTR("draw calls: %d", (int)g_Renderer.GetStats().m_DrawCalls);
|
||||
PROFILE2_ATTR("terrain tris: %d", (int)g_Renderer.GetStats().m_TerrainTris);
|
||||
PROFILE2_ATTR("water tris: %d", (int)g_Renderer.GetStats().m_WaterTris);
|
||||
PROFILE2_ATTR("model tris: %d", (int)g_Renderer.GetStats().m_ModelTris);
|
||||
PROFILE2_ATTR("overlay tris: %d", (int)g_Renderer.GetStats().m_OverlayTris);
|
||||
PROFILE2_ATTR("blend splats: %d", (int)g_Renderer.GetStats().m_BlendSplats);
|
||||
PROFILE2_ATTR("particles: %d", (int)g_Renderer.GetStats().m_Particles);
|
||||
|
||||
ogl_WarnIfError();
|
||||
|
||||
g_Profiler2.RecordGPUFrameEnd();
|
||||
ogl_WarnIfError();
|
||||
}
|
||||
|
||||
ErrorReactionInternal psDisplayError(const wchar_t* UNUSED(text), size_t UNUSED(flags))
|
||||
{
|
||||
// If we're fullscreen, then sometimes (at least on some particular drivers on Linux)
|
||||
@@ -475,37 +357,6 @@ static void ShutdownPs()
|
||||
UnloadHotkeys();
|
||||
}
|
||||
|
||||
|
||||
static void InitRenderer()
|
||||
{
|
||||
TIMER(L"InitRenderer");
|
||||
|
||||
// create renderer
|
||||
new CRenderer;
|
||||
|
||||
// create terrain related stuff
|
||||
new CTerrainTextureManager;
|
||||
|
||||
g_Renderer.Open(g_xres, g_yres);
|
||||
|
||||
// Setup lighting environment. Since the Renderer accesses the
|
||||
// lighting environment through a pointer, this has to be done before
|
||||
// the first Frame.
|
||||
g_Renderer.GetSceneRenderer().SetLightEnv(&g_LightEnv);
|
||||
|
||||
// I haven't seen the camera affecting GUI rendering and such, but the
|
||||
// viewport has to be updated according to the video mode
|
||||
SViewPort vp;
|
||||
vp.m_X = 0;
|
||||
vp.m_Y = 0;
|
||||
vp.m_Width = g_xres;
|
||||
vp.m_Height = g_yres;
|
||||
g_Renderer.SetViewport(vp);
|
||||
ModelDefActivateFastImpl();
|
||||
ColorActivateFastImpl();
|
||||
ModelRenderer::Init();
|
||||
}
|
||||
|
||||
static void InitSDL()
|
||||
{
|
||||
#if OS_LINUX
|
||||
@@ -931,7 +782,8 @@ void InitGraphics(const CmdLineArgs& args, int flags, const std::vector<CStr>& i
|
||||
|
||||
g_RenderingOptions.ReadConfigAndSetupHooks();
|
||||
|
||||
InitRenderer();
|
||||
// create renderer
|
||||
new CRenderer;
|
||||
|
||||
InitInput();
|
||||
|
||||
@@ -981,16 +833,6 @@ void InitNonVisual(const CmdLineArgs& args)
|
||||
Autostart(args);
|
||||
}
|
||||
|
||||
void RenderGui(bool RenderingState)
|
||||
{
|
||||
g_DoRenderGui = RenderingState;
|
||||
}
|
||||
|
||||
void RenderLogger(bool RenderingState)
|
||||
{
|
||||
g_DoRenderLogger = RenderingState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporarily loads a scenario map and retrieves the "ScriptSettings" JSON
|
||||
* data from it.
|
||||
|
||||
@@ -25,14 +25,6 @@
|
||||
class CmdLineArgs;
|
||||
class Paths;
|
||||
|
||||
//
|
||||
// GUI integration
|
||||
//
|
||||
|
||||
extern void Render();
|
||||
|
||||
extern bool ShouldRender();
|
||||
|
||||
/**
|
||||
* initialize global modules that are be needed before Init.
|
||||
* must be called from the very beginning of main.
|
||||
@@ -72,12 +64,6 @@ enum ShutdownFlags
|
||||
SHUTDOWN_FROM_CONFIG = 1
|
||||
};
|
||||
|
||||
/**
|
||||
* enable/disable rendering of the GUI (intended mainly for screenshots)
|
||||
*/
|
||||
extern void RenderGui(bool RenderingState);
|
||||
extern void RenderLogger(bool RenderingState);
|
||||
|
||||
extern const std::vector<CStr>& GetMods(const CmdLineArgs& args, int flags);
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,10 +20,7 @@
|
||||
#include "ps/Util.h"
|
||||
|
||||
#include "graphics/GameView.h"
|
||||
#include "i18n/L10n.h"
|
||||
#include "lib/allocators/shared_ptr.h"
|
||||
#include "lib/bits.h" // round_up
|
||||
#include "lib/ogl.h"
|
||||
#include "lib/posix/posix_utsname.h"
|
||||
#include "lib/sysdep/cpu.h"
|
||||
#include "lib/sysdep/os_cpu.h"
|
||||
@@ -31,17 +28,13 @@
|
||||
#include "lib/sysdep/sysdep.h" // sys_OpenFile
|
||||
#include "lib/tex/tex.h"
|
||||
#include "lib/timer.h"
|
||||
#include "lib/utf8.h"
|
||||
#include "maths/MathUtil.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/Filesystem.h"
|
||||
#include "ps/Game.h"
|
||||
#include "ps/GameSetup/Config.h"
|
||||
#include "ps/GameSetup/GameSetup.h"
|
||||
#include "ps/Pyrogenesis.h"
|
||||
#include "ps/VideoMode.h"
|
||||
#include "renderer/backend/gl/Device.h"
|
||||
#include "renderer/Renderer.h"
|
||||
|
||||
#if CONFIG2_AUDIO
|
||||
#include "soundmanager/SoundManager.h"
|
||||
@@ -206,207 +199,6 @@ OsPath createDateIndexSubdirectory(const OsPath& parentDir)
|
||||
return path;
|
||||
}
|
||||
|
||||
static size_t s_nextScreenshotNumber;
|
||||
|
||||
// <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 VfsPath& extension)
|
||||
{
|
||||
// get next available numbered filename
|
||||
// note: %04d -> always 4 digits, so sorting by filename works correctly.
|
||||
const VfsPath basenameFormat(L"screenshots/screenshot%04d");
|
||||
const VfsPath filenameFormat = basenameFormat.ChangeExtension(extension);
|
||||
VfsPath filename;
|
||||
vfs::NextNumberedFilename(g_VFS, filenameFormat, s_nextScreenshotNumber, filename);
|
||||
|
||||
const size_t w = (size_t)g_xres, h = (size_t)g_yres;
|
||||
const size_t 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(extension == L".bmp")
|
||||
{
|
||||
#if !CONFIG2_GLES // GLES doesn't support BGR
|
||||
fmt = GL_BGR;
|
||||
flags |= TEX_BGR;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Hide log messages and re-render
|
||||
RenderLogger(false);
|
||||
Render();
|
||||
RenderLogger(true);
|
||||
|
||||
const size_t img_size = w * h * bpp/8;
|
||||
const size_t hdr_size = tex_hdr_size(filename);
|
||||
std::shared_ptr<u8> buf;
|
||||
AllocateAligned(buf, hdr_size+img_size, maxSectorSize);
|
||||
GLvoid* img = buf.get() + hdr_size;
|
||||
Tex t;
|
||||
if(t.wrap(w, h, bpp, flags, buf, hdr_size) < 0)
|
||||
return;
|
||||
glReadPixels(0, 0, (GLsizei)w, (GLsizei)h, fmt, GL_UNSIGNED_BYTE, img);
|
||||
|
||||
if (tex_write(&t, filename) == INFO::OK)
|
||||
{
|
||||
OsPath realPath;
|
||||
g_VFS->GetRealPath(filename, realPath);
|
||||
|
||||
LOGMESSAGERENDER(g_L10n.Translate("Screenshot written to '%s'"), realPath.string8());
|
||||
|
||||
debug_printf(
|
||||
CStr(g_L10n.Translate("Screenshot written to '%s'") + "\n").c_str(),
|
||||
realPath.string8().c_str());
|
||||
}
|
||||
else
|
||||
LOGERROR("Error writing screenshot to '%s'", filename.string8());
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 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 == nullptr)
|
||||
{
|
||||
WriteScreenshot(L".bmp");
|
||||
return;
|
||||
}
|
||||
|
||||
// get next available numbered filename
|
||||
// note: %04d -> always 4 digits, so sorting by filename works correctly.
|
||||
const VfsPath basenameFormat(L"screenshots/screenshot%04d");
|
||||
const VfsPath filenameFormat = basenameFormat.ChangeExtension(extension);
|
||||
VfsPath filename;
|
||||
vfs::NextNumberedFilename(g_VFS, filenameFormat, s_nextScreenshotNumber, filename);
|
||||
|
||||
// Slightly ugly and inflexible: Always draw 640*480 tiles onto the screen, and
|
||||
// hope the screen is actually large enough for that.
|
||||
ENSURE(g_xres >= tileWidth && g_yres >= tileHeight);
|
||||
|
||||
const int img_w = tileWidth * tiles, img_h = tileHeight * 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.
|
||||
if(extension == L".bmp")
|
||||
{
|
||||
#if !CONFIG2_GLES // GLES doesn't support BGR
|
||||
fmt = GL_BGR;
|
||||
flags |= TEX_BGR;
|
||||
#endif
|
||||
}
|
||||
|
||||
const size_t img_size = img_w * img_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)
|
||||
{
|
||||
WARN_IF_ERR(ERR::NO_MEM);
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<u8> img_buf;
|
||||
AllocateAligned(img_buf, hdr_size + img_size, maxSectorSize);
|
||||
|
||||
Tex t;
|
||||
GLvoid* img = img_buf.get() + hdr_size;
|
||||
if(t.wrap(img_w, img_h, bpp, flags, img_buf, hdr_size) < 0)
|
||||
{
|
||||
free(tile_data);
|
||||
return;
|
||||
}
|
||||
|
||||
ogl_WarnIfError();
|
||||
|
||||
CCamera oldCamera = *g_Game->GetView()->GetCamera();
|
||||
|
||||
// Resize various things so that the sizes and aspect ratios are correct
|
||||
{
|
||||
g_Renderer.Resize(tileWidth, tileHeight);
|
||||
SViewPort vp = { 0, 0, tileWidth, tileHeight };
|
||||
g_Game->GetView()->SetViewport(vp);
|
||||
}
|
||||
|
||||
#if !CONFIG2_GLES
|
||||
// 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);
|
||||
#endif
|
||||
|
||||
// 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)
|
||||
{
|
||||
// Adjust the camera to render the appropriate region
|
||||
if (oldCamera.GetProjectionType() == CCamera::ProjectionType::PERSPECTIVE)
|
||||
{
|
||||
projection.SetPerspectiveTile(oldCamera.GetFOV(), aspectRatio, oldCamera.GetNearPlane(), oldCamera.GetFarPlane(), tiles, tile_x, tile_y);
|
||||
}
|
||||
g_Game->GetView()->GetCamera()->SetProjection(projection);
|
||||
|
||||
RenderLogger(false);
|
||||
RenderGui(false);
|
||||
Render();
|
||||
RenderGui(true);
|
||||
RenderLogger(true);
|
||||
|
||||
// Copy the tile pixels into the main image
|
||||
glReadPixels(0, 0, tileWidth, tileHeight, fmt, GL_UNSIGNED_BYTE, tile_data);
|
||||
for (int y = 0; y < tileHeight; ++y)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !CONFIG2_GLES
|
||||
// Restore the buffer settings
|
||||
glDrawBuffer(oldDrawBuffer);
|
||||
glReadBuffer(oldReadBuffer);
|
||||
#endif
|
||||
|
||||
// Restore the viewport settings
|
||||
{
|
||||
g_Renderer.Resize(g_xres, g_yres);
|
||||
SViewPort vp = { 0, 0, g_xres, g_yres };
|
||||
g_Game->GetView()->SetViewport(vp);
|
||||
g_Game->GetView()->GetCamera()->SetProjectionFromCamera(oldCamera);
|
||||
}
|
||||
|
||||
if (tex_write(&t, filename) == INFO::OK)
|
||||
{
|
||||
OsPath realPath;
|
||||
g_VFS->GetRealPath(filename, realPath);
|
||||
|
||||
LOGMESSAGERENDER(g_L10n.Translate("Screenshot written to '%s'"), realPath.string8());
|
||||
|
||||
debug_printf(
|
||||
CStr(g_L10n.Translate("Screenshot written to '%s'") + "\n").c_str(),
|
||||
realPath.string8().c_str());
|
||||
}
|
||||
else
|
||||
LOGERROR("Error writing screenshot to '%s'", filename.string8());
|
||||
|
||||
free(tile_data);
|
||||
}
|
||||
|
||||
std::string Hexify(const std::string& s)
|
||||
{
|
||||
std::stringstream str;
|
||||
|
||||
+1
-4
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2022 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -29,9 +29,6 @@ const wchar_t* ErrorString(int err);
|
||||
|
||||
OsPath createDateIndexSubdirectory(const OsPath& parentDir);
|
||||
|
||||
void WriteScreenshot(const VfsPath& extension);
|
||||
void WriteBigScreenshot(const VfsPath& extension, int tiles = 4, int tileWidth = 640, int tileHeight = 480);
|
||||
|
||||
Status tex_write(Tex* t, const VfsPath& filename);
|
||||
|
||||
std::string Hexify(const std::string& s);
|
||||
|
||||
@@ -15,24 +15,33 @@
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* higher level interface on top of OpenGL to render basic objects:
|
||||
* terrain, models, sprites, particles etc.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "Renderer.h"
|
||||
|
||||
#include "graphics/Canvas2D.h"
|
||||
#include "graphics/CinemaManager.h"
|
||||
#include "graphics/GameView.h"
|
||||
#include "graphics/LightEnv.h"
|
||||
#include "graphics/ModelDef.h"
|
||||
#include "graphics/TerrainTextureManager.h"
|
||||
#include "i18n/L10n.h"
|
||||
#include "lib/allocators/shared_ptr.h"
|
||||
#include "lib/ogl.h"
|
||||
#include "lib/res/graphics/ogl_tex.h"
|
||||
#include "gui/GUIManager.h"
|
||||
#include "ps/CConsole.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/ConfigDB.h"
|
||||
#include "ps/CStrInternStatic.h"
|
||||
#include "ps/Game.h"
|
||||
#include "ps/GameSetup/Config.h"
|
||||
#include "ps/GameSetup/GameSetup.h"
|
||||
#include "ps/Globals.h"
|
||||
#include "ps/Loader.h"
|
||||
#include "ps/Profile.h"
|
||||
#include "ps/Filesystem.h"
|
||||
#include "ps/World.h"
|
||||
#include "ps/Loader.h"
|
||||
#include "ps/ProfileViewer.h"
|
||||
#include "graphics/Camera.h"
|
||||
#include "graphics/FontManager.h"
|
||||
@@ -40,7 +49,9 @@
|
||||
#include "graphics/Terrain.h"
|
||||
#include "graphics/Texture.h"
|
||||
#include "graphics/TextureManager.h"
|
||||
#include "ps/Util.h"
|
||||
#include "ps/VideoMode.h"
|
||||
#include "renderer/backend/gl/Device.h"
|
||||
#include "renderer/DebugRenderer.h"
|
||||
#include "renderer/PostprocManager.h"
|
||||
#include "renderer/RenderingOptions.h"
|
||||
@@ -48,9 +59,16 @@
|
||||
#include "renderer/SceneRenderer.h"
|
||||
#include "renderer/TimeManager.h"
|
||||
#include "renderer/VertexBufferManager.h"
|
||||
#include "tools/atlas/GameInterface/GameLoop.h"
|
||||
#include "tools/atlas/GameInterface/View.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
size_t g_NextScreenShotNumber = 0;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// CRendererStatsTable - Profile display of rendering stats
|
||||
|
||||
@@ -212,6 +230,8 @@ AbstractProfileTable* CRendererStatsTable::GetChild(size_t UNUSED(row))
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// CRenderer implementation
|
||||
|
||||
@@ -258,6 +278,8 @@ public:
|
||||
|
||||
CRenderer::CRenderer()
|
||||
{
|
||||
TIMER(L"InitRenderer");
|
||||
|
||||
m = std::make_unique<Internals>();
|
||||
|
||||
g_ProfileViewer.AddRootTable(&m->profileTable);
|
||||
@@ -266,6 +288,28 @@ CRenderer::CRenderer()
|
||||
m_Height = 0;
|
||||
|
||||
m_Stats.Reset();
|
||||
|
||||
// Create terrain related stuff.
|
||||
new CTerrainTextureManager;
|
||||
|
||||
Open(g_xres, g_yres);
|
||||
|
||||
// Setup lighting environment. Since the Renderer accesses the
|
||||
// lighting environment through a pointer, this has to be done before
|
||||
// the first Frame.
|
||||
GetSceneRenderer().SetLightEnv(&g_LightEnv);
|
||||
|
||||
// I haven't seen the camera affecting GUI rendering and such, but the
|
||||
// viewport has to be updated according to the video mode
|
||||
SViewPort vp;
|
||||
vp.m_X = 0;
|
||||
vp.m_Y = 0;
|
||||
vp.m_Width = g_xres;
|
||||
vp.m_Height = g_yres;
|
||||
SetViewport(vp);
|
||||
ModelDefActivateFastImpl();
|
||||
ColorActivateFastImpl();
|
||||
ModelRenderer::Init();
|
||||
}
|
||||
|
||||
CRenderer::~CRenderer()
|
||||
@@ -408,6 +452,317 @@ void CRenderer::SetRenderPath(RenderPath rp)
|
||||
g_Game->GetWorld()->GetTerrain()->MakeDirty(RENDERDATA_UPDATE_COLOR);
|
||||
}
|
||||
|
||||
bool CRenderer::ShouldRender() const
|
||||
{
|
||||
return !g_app_minimized && (g_app_has_focus || !g_VideoMode.IsInFullscreen());
|
||||
}
|
||||
|
||||
void CRenderer::RenderFrame(bool needsPresent)
|
||||
{
|
||||
// Do not render if not focused while in fullscreen or minimised,
|
||||
// as that triggers a difficult-to-reproduce crash on some graphic cards.
|
||||
if (!ShouldRender())
|
||||
return;
|
||||
|
||||
if (m_ShouldPreloadResourcesBeforeNextFrame)
|
||||
{
|
||||
m_ShouldPreloadResourcesBeforeNextFrame = false;
|
||||
// We don't meed to render logger for the preload.
|
||||
RenderFrameImpl(true, false);
|
||||
}
|
||||
|
||||
if (m_ScreenShotType == ScreenShotType::BIG)
|
||||
{
|
||||
RenderBigScreenShot();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_ScreenShotType == ScreenShotType::DEFAULT)
|
||||
RenderScreenShot();
|
||||
else
|
||||
RenderFrameImpl(true, true);
|
||||
|
||||
if (needsPresent)
|
||||
g_VideoMode.GetBackendDevice()->Present();
|
||||
}
|
||||
}
|
||||
|
||||
void CRenderer::RenderFrameImpl(bool renderGUI, bool renderLogger)
|
||||
{
|
||||
PROFILE3("render");
|
||||
|
||||
g_Profiler2.RecordGPUFrameStart();
|
||||
ogl_WarnIfError();
|
||||
|
||||
// prepare before starting the renderer frame
|
||||
if (g_Game && g_Game->IsGameStarted())
|
||||
g_Game->GetView()->BeginFrame();
|
||||
|
||||
if (g_Game)
|
||||
m->sceneRenderer.SetSimulation(g_Game->GetSimulation2());
|
||||
|
||||
// start new frame
|
||||
BeginFrame();
|
||||
|
||||
ogl_WarnIfError();
|
||||
|
||||
if (g_Game && g_Game->IsGameStarted())
|
||||
{
|
||||
g_Game->GetView()->Render();
|
||||
ogl_WarnIfError();
|
||||
}
|
||||
|
||||
m->sceneRenderer.RenderTextOverlays();
|
||||
|
||||
// If we're in Atlas game view, render special tools
|
||||
if (g_AtlasGameLoop && g_AtlasGameLoop->view)
|
||||
{
|
||||
g_AtlasGameLoop->view->DrawCinemaPathTool();
|
||||
ogl_WarnIfError();
|
||||
}
|
||||
|
||||
if (g_Game && g_Game->IsGameStarted())
|
||||
{
|
||||
g_Game->GetView()->GetCinema()->Render();
|
||||
ogl_WarnIfError();
|
||||
}
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
if (renderGUI)
|
||||
{
|
||||
OGL_SCOPED_DEBUG_GROUP("Draw GUI");
|
||||
// All GUI elements are drawn in Z order to render semi-transparent
|
||||
// objects correctly.
|
||||
g_GUI->Draw();
|
||||
ogl_WarnIfError();
|
||||
}
|
||||
|
||||
// If we're in Atlas game view, render special overlays (e.g. editor bandbox).
|
||||
if (g_AtlasGameLoop && g_AtlasGameLoop->view)
|
||||
{
|
||||
CCanvas2D canvas;
|
||||
g_AtlasGameLoop->view->DrawOverlays(canvas);
|
||||
ogl_WarnIfError();
|
||||
}
|
||||
|
||||
g_Console->Render();
|
||||
ogl_WarnIfError();
|
||||
|
||||
if (renderLogger)
|
||||
{
|
||||
g_Logger->Render();
|
||||
ogl_WarnIfError();
|
||||
}
|
||||
|
||||
// Profile information
|
||||
g_ProfileViewer.RenderProfile();
|
||||
ogl_WarnIfError();
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
EndFrame();
|
||||
|
||||
const Stats& stats = GetStats();
|
||||
PROFILE2_ATTR("draw calls: %zu", stats.m_DrawCalls);
|
||||
PROFILE2_ATTR("terrain tris: %zu", stats.m_TerrainTris);
|
||||
PROFILE2_ATTR("water tris: %zu", stats.m_WaterTris);
|
||||
PROFILE2_ATTR("model tris: %zu", stats.m_ModelTris);
|
||||
PROFILE2_ATTR("overlay tris: %zu", stats.m_OverlayTris);
|
||||
PROFILE2_ATTR("blend splats: %zu", stats.m_BlendSplats);
|
||||
PROFILE2_ATTR("particles: %zu", stats.m_Particles);
|
||||
|
||||
ogl_WarnIfError();
|
||||
|
||||
g_Profiler2.RecordGPUFrameEnd();
|
||||
ogl_WarnIfError();
|
||||
}
|
||||
|
||||
void CRenderer::RenderScreenShot()
|
||||
{
|
||||
m_ScreenShotType = ScreenShotType::NONE;
|
||||
|
||||
// get next available numbered filename
|
||||
// note: %04d -> always 4 digits, so sorting by filename works correctly.
|
||||
const VfsPath filenameFormat(L"screenshots/screenshot%04d.png");
|
||||
VfsPath filename;
|
||||
vfs::NextNumberedFilename(g_VFS, filenameFormat, g_NextScreenShotNumber, filename);
|
||||
|
||||
const size_t w = (size_t)g_xres, h = (size_t)g_yres;
|
||||
const size_t bpp = 24;
|
||||
GLenum fmt = GL_RGB;
|
||||
int flags = TEX_BOTTOM_UP;
|
||||
|
||||
// Hide log messages and re-render
|
||||
RenderFrameImpl(true, false);
|
||||
|
||||
const size_t img_size = w * h * bpp / 8;
|
||||
const size_t hdr_size = tex_hdr_size(filename);
|
||||
std::shared_ptr<u8> buf;
|
||||
AllocateAligned(buf, hdr_size + img_size, maxSectorSize);
|
||||
GLvoid* img = buf.get() + hdr_size;
|
||||
Tex t;
|
||||
if (t.wrap(w, h, bpp, flags, buf, hdr_size) < 0)
|
||||
return;
|
||||
glReadPixels(0, 0, (GLsizei)w, (GLsizei)h, fmt, GL_UNSIGNED_BYTE, img);
|
||||
|
||||
if (tex_write(&t, filename) == INFO::OK)
|
||||
{
|
||||
OsPath realPath;
|
||||
g_VFS->GetRealPath(filename, realPath);
|
||||
|
||||
LOGMESSAGERENDER(g_L10n.Translate("Screenshot written to '%s'"), realPath.string8());
|
||||
|
||||
debug_printf(
|
||||
CStr(g_L10n.Translate("Screenshot written to '%s'") + "\n").c_str(),
|
||||
realPath.string8().c_str());
|
||||
}
|
||||
else
|
||||
LOGERROR("Error writing screenshot to '%s'", filename.string8());
|
||||
}
|
||||
|
||||
void CRenderer::RenderBigScreenShot()
|
||||
{
|
||||
m_ScreenShotType = ScreenShotType::NONE;
|
||||
|
||||
// If the game hasn't started yet then use WriteScreenshot to generate the image.
|
||||
if (!g_Game)
|
||||
return RenderScreenShot();
|
||||
|
||||
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 || tileWidth * tiles % 4 != 0 || tileHeight * tiles % 4 != 0)
|
||||
{
|
||||
LOGWARNING("Invalid big screenshot size: tiles=%d tileWidth=%d tileHeight=%d", tiles, tileWidth, tileHeight);
|
||||
return;
|
||||
}
|
||||
|
||||
// get next available numbered filename
|
||||
// note: %04d -> always 4 digits, so sorting by filename works correctly.
|
||||
const VfsPath filenameFormat(L"screenshots/screenshot%04d.bmp");
|
||||
VfsPath filename;
|
||||
vfs::NextNumberedFilename(g_VFS, filenameFormat, g_NextScreenShotNumber, filename);
|
||||
|
||||
// Slightly ugly and inflexible: Always draw 640*480 tiles onto the screen, and
|
||||
// hope the screen is actually large enough for that.
|
||||
ENSURE(g_xres >= tileWidth && g_yres >= tileHeight);
|
||||
|
||||
const int img_w = tileWidth * tiles, img_h = tileHeight * tiles;
|
||||
const int bpp = 24;
|
||||
// we want writing BMP to be as fast as possible,
|
||||
// so read data from OpenGL in BMP format to obviate conversion.
|
||||
#if CONFIG2_GLES // GLES doesn't support BGR
|
||||
const GLenum fmt = GL_RGB;
|
||||
const int flags = TEX_BOTTOM_UP;
|
||||
#else
|
||||
const GLenum fmt = GL_BGR;
|
||||
const int flags = TEX_BOTTOM_UP | TEX_BGR;
|
||||
#endif
|
||||
|
||||
const size_t img_size = img_w * img_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)
|
||||
{
|
||||
WARN_IF_ERR(ERR::NO_MEM);
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<u8> img_buf;
|
||||
AllocateAligned(img_buf, hdr_size + img_size, maxSectorSize);
|
||||
|
||||
Tex t;
|
||||
GLvoid* img = img_buf.get() + hdr_size;
|
||||
if (t.wrap(img_w, img_h, bpp, flags, img_buf, hdr_size) < 0)
|
||||
{
|
||||
free(tile_data);
|
||||
return;
|
||||
}
|
||||
|
||||
ogl_WarnIfError();
|
||||
|
||||
CCamera oldCamera = *g_Game->GetView()->GetCamera();
|
||||
|
||||
// Resize various things so that the sizes and aspect ratios are correct
|
||||
{
|
||||
g_Renderer.Resize(tileWidth, tileHeight);
|
||||
SViewPort vp = { 0, 0, tileWidth, tileHeight };
|
||||
g_Game->GetView()->SetViewport(vp);
|
||||
}
|
||||
|
||||
#if !CONFIG2_GLES
|
||||
// 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);
|
||||
#endif
|
||||
|
||||
// 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)
|
||||
{
|
||||
// Adjust the camera to render the appropriate region
|
||||
if (oldCamera.GetProjectionType() == CCamera::ProjectionType::PERSPECTIVE)
|
||||
{
|
||||
projection.SetPerspectiveTile(oldCamera.GetFOV(), aspectRatio, oldCamera.GetNearPlane(), oldCamera.GetFarPlane(), tiles, tile_x, tile_y);
|
||||
}
|
||||
g_Game->GetView()->GetCamera()->SetProjection(projection);
|
||||
|
||||
RenderFrameImpl(false, false);
|
||||
|
||||
// Copy the tile pixels into the main image
|
||||
glReadPixels(0, 0, tileWidth, tileHeight, fmt, GL_UNSIGNED_BYTE, tile_data);
|
||||
for (int y = 0; y < tileHeight; ++y)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !CONFIG2_GLES
|
||||
// Restore the buffer settings
|
||||
glDrawBuffer(oldDrawBuffer);
|
||||
glReadBuffer(oldReadBuffer);
|
||||
#endif
|
||||
|
||||
// Restore the viewport settings
|
||||
{
|
||||
g_Renderer.Resize(g_xres, g_yres);
|
||||
SViewPort vp = { 0, 0, g_xres, g_yres };
|
||||
g_Game->GetView()->SetViewport(vp);
|
||||
g_Game->GetView()->GetCamera()->SetProjectionFromCamera(oldCamera);
|
||||
}
|
||||
|
||||
if (tex_write(&t, filename) == INFO::OK)
|
||||
{
|
||||
OsPath realPath;
|
||||
g_VFS->GetRealPath(filename, realPath);
|
||||
|
||||
LOGMESSAGERENDER(g_L10n.Translate("Screenshot written to '%s'"), realPath.string8());
|
||||
|
||||
debug_printf(
|
||||
CStr(g_L10n.Translate("Screenshot written to '%s'") + "\n").c_str(),
|
||||
realPath.string8().c_str());
|
||||
}
|
||||
else
|
||||
LOGERROR("Error writing screenshot to '%s'", filename.string8());
|
||||
|
||||
free(tile_data);
|
||||
}
|
||||
|
||||
void CRenderer::BeginFrame()
|
||||
{
|
||||
PROFILE("begin frame");
|
||||
@@ -488,3 +843,13 @@ CFontManager& CRenderer::GetFontManager()
|
||||
{
|
||||
return m->fontManager;
|
||||
}
|
||||
|
||||
void CRenderer::PreloadResourcesBeforeNextFrame()
|
||||
{
|
||||
m_ShouldPreloadResourcesBeforeNextFrame = true;
|
||||
}
|
||||
|
||||
void CRenderer::MakeScreenShotOnNextFrame(ScreenShotType screenShotType)
|
||||
{
|
||||
m_ScreenShotType = screenShotType;
|
||||
}
|
||||
|
||||
@@ -76,6 +76,13 @@ public:
|
||||
bool m_PrettyWater;
|
||||
};
|
||||
|
||||
enum class ScreenShotType
|
||||
{
|
||||
NONE,
|
||||
DEFAULT,
|
||||
BIG
|
||||
};
|
||||
|
||||
public:
|
||||
CRenderer();
|
||||
~CRenderer();
|
||||
@@ -91,6 +98,8 @@ public:
|
||||
// return view height
|
||||
int GetHeight() const { return m_Height; }
|
||||
|
||||
void RenderFrame(bool needsPresent);
|
||||
|
||||
// signal frame start
|
||||
void BeginFrame();
|
||||
// signal frame end
|
||||
@@ -132,6 +141,20 @@ public:
|
||||
*/
|
||||
const Caps& GetCapabilities() const { return m_Caps; }
|
||||
|
||||
/**
|
||||
* Performs a complete frame without presenting to force loading all needed
|
||||
* resources. It's used for the first frame on a game start.
|
||||
* TODO: It might be better to preload resources without a complete frame
|
||||
* rendering.
|
||||
*/
|
||||
void PreloadResourcesBeforeNextFrame();
|
||||
|
||||
/**
|
||||
* Makes a screenshot on the next RenderFrame according of the given
|
||||
* screenshot type.
|
||||
*/
|
||||
void MakeScreenShotOnNextFrame(ScreenShotType screenShotType);
|
||||
|
||||
protected:
|
||||
friend class CPatchRData;
|
||||
friend class CDecalRData;
|
||||
@@ -140,6 +163,12 @@ protected:
|
||||
friend class InstancingModelRenderer;
|
||||
friend class CRenderingOptions;
|
||||
|
||||
bool ShouldRender() const;
|
||||
|
||||
void RenderFrameImpl(bool renderGUI, bool renderLogger);
|
||||
void RenderScreenShot();
|
||||
void RenderBigScreenShot();
|
||||
|
||||
// SetRenderPath: Select the preferred render path.
|
||||
// This may only be called before Open(), because the layout of vertex arrays and other
|
||||
// data may depend on the chosen render path.
|
||||
@@ -151,9 +180,9 @@ protected:
|
||||
class Internals;
|
||||
std::unique_ptr<Internals> m;
|
||||
// view width
|
||||
int m_Width;
|
||||
int m_Width = 0;
|
||||
// view height
|
||||
int m_Height;
|
||||
int m_Height = 0;
|
||||
|
||||
SViewPort m_Viewport;
|
||||
|
||||
@@ -163,6 +192,10 @@ protected:
|
||||
void EnumCaps();
|
||||
// per-frame renderer stats
|
||||
Stats m_Stats;
|
||||
|
||||
bool m_ShouldPreloadResourcesBeforeNextFrame = false;
|
||||
|
||||
ScreenShotType m_ScreenShotType = ScreenShotType::NONE;
|
||||
};
|
||||
|
||||
#endif // INCLUDED_RENDERER
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2022 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -932,10 +932,10 @@ void ScenarioEditor::OnScreenshot(wxCommandEvent& event)
|
||||
switch (event.GetId())
|
||||
{
|
||||
case ID_BigScreenshot:
|
||||
POST_MESSAGE(Screenshot, (true, 10));
|
||||
POST_MESSAGE(Screenshot, (true));
|
||||
break;
|
||||
case ID_Screenshot:
|
||||
POST_MESSAGE(Screenshot, (false, 0));
|
||||
POST_MESSAGE(Screenshot, (false));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -499,6 +499,7 @@ float ActorViewer::GetRepeatTimeByAttackType(const std::string& type) const
|
||||
|
||||
void ActorViewer::Render()
|
||||
{
|
||||
// TODO: ActorViewer should reuse CRenderer code and not duplicate it.
|
||||
m.Terrain.MakeDirty(RENDERDATA_UPDATE_COLOR);
|
||||
|
||||
// Set simulation context for rendering purposes
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2022 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -28,9 +28,9 @@
|
||||
#include "lib/external_libraries/libsdl.h"
|
||||
#include "maths/MathUtil.h"
|
||||
#include "ps/Game.h"
|
||||
#include "ps/Util.h"
|
||||
#include "ps/GameSetup/Config.h"
|
||||
#include "ps/GameSetup/GameSetup.h"
|
||||
#include "renderer/Renderer.h"
|
||||
#include "scriptinterface/ScriptInterface.h"
|
||||
#include "simulation2/Simulation2.h"
|
||||
#include "simulation2/components/ICmpSoundManager.h"
|
||||
@@ -48,9 +48,9 @@ MESSAGEHANDLER(MessageTrace)
|
||||
MESSAGEHANDLER(Screenshot)
|
||||
{
|
||||
if (msg->big)
|
||||
WriteBigScreenshot(L".bmp", msg->tiles);
|
||||
g_Renderer.MakeScreenShotOnNextFrame(CRenderer::ScreenShotType::BIG);
|
||||
else
|
||||
WriteScreenshot(L".png");
|
||||
g_Renderer.MakeScreenShotOnNextFrame(CRenderer::ScreenShotType::DEFAULT);
|
||||
}
|
||||
|
||||
QUERYHANDLER(Ping)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2022 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -273,7 +273,6 @@ MESSAGE(MessageTrace,
|
||||
|
||||
MESSAGE(Screenshot,
|
||||
((bool, big))
|
||||
((int, tiles)) // For big screenshots: the final image will be (640*tiles)x(480*tiles)
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -229,7 +229,7 @@ void AtlasViewGame::Render()
|
||||
camera.SetProjectionFromCamera(*g_Game->GetView()->GetCamera());
|
||||
camera.UpdateFrustum();
|
||||
|
||||
::Render();
|
||||
g_Renderer.RenderFrame(false);
|
||||
Atlas_GLSwapBuffers((void*)g_AtlasGameLoop->glCanvas);
|
||||
// In case of atlas the device's present will do only internal stuff
|
||||
// without calling a real backbuffer swap.
|
||||
|
||||
Reference in New Issue
Block a user