mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
hw2: add screenshot pass
This commit is contained in:
parent
b9cf1316bd
commit
e875c8e20d
11 changed files with 184 additions and 27 deletions
|
|
@ -868,8 +868,10 @@ void D_SRB2Loop(void)
|
|||
// Only take screenshots after drawing.
|
||||
if (moviemode)
|
||||
M_SaveFrame();
|
||||
if (takescreenshot)
|
||||
M_DoScreenShot();
|
||||
#ifdef HWRENDER
|
||||
if (rendermode == render_opengl && takescreenshot)
|
||||
M_DoLegacyGLScreenShot();
|
||||
#endif
|
||||
|
||||
// consoleplayer -> displayplayers (hear sounds from viewpoint)
|
||||
S_UpdateSounds(); // move positional sounds
|
||||
|
|
|
|||
|
|
@ -1603,8 +1603,6 @@ void G_PreLevelTitleCard(void)
|
|||
|
||||
if (moviemode)
|
||||
M_SaveFrame();
|
||||
if (takescreenshot) // Only take screenshots after drawing.
|
||||
M_DoScreenShot();
|
||||
|
||||
while (!((nowtime = I_GetTime()) - lasttime))
|
||||
{
|
||||
|
|
@ -4396,7 +4394,7 @@ void G_LoadGameData(void)
|
|||
{
|
||||
// Don't load, but do save. (essentially, reset)
|
||||
gamedata->loaded = true;
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
if (P_SaveBufferFromFile(&save, va(pandf, srb2home, gamedatafilename)) == false)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ target_sources(SRB2SDL2 PRIVATE
|
|||
pass_postprocess.hpp
|
||||
pass_resource_managers.cpp
|
||||
pass_resource_managers.hpp
|
||||
pass_screenshot.cpp
|
||||
pass_screenshot.hpp
|
||||
pass_software.cpp
|
||||
pass_software.hpp
|
||||
pass_twodee.cpp
|
||||
|
|
|
|||
68
src/hwr2/pass_screenshot.cpp
Normal file
68
src/hwr2/pass_screenshot.cpp
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by Ronald "Eidolon" Kinard
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "pass_screenshot.hpp"
|
||||
|
||||
#include <tcb/span.hpp>
|
||||
|
||||
#include "../m_misc.h"
|
||||
|
||||
using namespace srb2;
|
||||
using namespace srb2::hwr2;
|
||||
using namespace srb2::rhi;
|
||||
|
||||
ScreenshotPass::ScreenshotPass() = default;
|
||||
ScreenshotPass::~ScreenshotPass() = default;
|
||||
|
||||
void ScreenshotPass::prepass(Rhi& rhi)
|
||||
{
|
||||
if (!render_pass_)
|
||||
{
|
||||
render_pass_ = rhi.create_render_pass(
|
||||
{
|
||||
std::nullopt,
|
||||
PixelFormat::kRGBA8,
|
||||
AttachmentLoadOp::kLoad,
|
||||
AttachmentStoreOp::kStore
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
doing_screenshot_ = takescreenshot;
|
||||
}
|
||||
|
||||
void ScreenshotPass::transfer(Rhi& rhi, Handle<TransferContext> ctx)
|
||||
{
|
||||
}
|
||||
|
||||
void ScreenshotPass::graphics(Rhi& rhi, Handle<GraphicsContext> ctx)
|
||||
{
|
||||
if (!doing_screenshot_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pixel_data_.clear();
|
||||
pixel_data_.resize(width_ * height_ * 3); // 3 bytes per pixel for RGB8
|
||||
|
||||
rhi.begin_render_pass(ctx, {render_pass_, source_, std::nullopt, {0.f, 0.f, 0.f, 0.f}});
|
||||
rhi.read_pixels(ctx, {0, 0, width_, height_}, PixelFormat::kRGB8, tcb::as_writable_bytes(tcb::span(pixel_data_)));
|
||||
rhi.end_render_pass(ctx);
|
||||
}
|
||||
|
||||
void ScreenshotPass::postpass(Rhi& rhi)
|
||||
{
|
||||
if (!doing_screenshot_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
M_DoScreenShot(width_, height_, tcb::as_bytes(tcb::span(pixel_data_)));
|
||||
doing_screenshot_ = false;
|
||||
}
|
||||
49
src/hwr2/pass_screenshot.hpp
Normal file
49
src/hwr2/pass_screenshot.hpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by Ronald "Eidolon" Kinard
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef __SRB2_HWR2_PASS_SCREENSHOT_HPP__
|
||||
#define __SRB2_HWR2_PASS_SCREENSHOT_HPP__
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
#include "pass.hpp"
|
||||
|
||||
namespace srb2::hwr2
|
||||
{
|
||||
|
||||
class ScreenshotPass : public Pass
|
||||
{
|
||||
bool doing_screenshot_ = false;
|
||||
rhi::Handle<rhi::Texture> source_;
|
||||
rhi::Handle<rhi::RenderPass> render_pass_;
|
||||
std::vector<uint8_t> pixel_data_;
|
||||
uint32_t width_ = 0;
|
||||
uint32_t height_ = 0;
|
||||
|
||||
public:
|
||||
ScreenshotPass();
|
||||
virtual ~ScreenshotPass();
|
||||
|
||||
virtual void prepass(rhi::Rhi& rhi) override;
|
||||
virtual void transfer(rhi::Rhi& rhi, rhi::Handle<rhi::TransferContext> ctx) override;
|
||||
virtual void graphics(rhi::Rhi& rhi, rhi::Handle<rhi::GraphicsContext> ctx) override;
|
||||
virtual void postpass(rhi::Rhi& rhi) override;
|
||||
|
||||
void set_source(rhi::Handle<rhi::Texture> source, uint32_t width, uint32_t height)
|
||||
{
|
||||
source_ = source;
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace srb2::hwr2
|
||||
|
||||
#endif // __SRB2_HWR2_PASS_SCREENSHOT_HPP__
|
||||
|
|
@ -22,6 +22,7 @@
|
|||
#include "hwr2/pass_manager.hpp"
|
||||
#include "hwr2/pass_postprocess.hpp"
|
||||
#include "hwr2/pass_resource_managers.hpp"
|
||||
#include "hwr2/pass_screenshot.hpp"
|
||||
#include "hwr2/pass_software.hpp"
|
||||
#include "hwr2/pass_twodee.hpp"
|
||||
#include "hwr2/twodee.hpp"
|
||||
|
|
@ -118,6 +119,7 @@ static std::shared_ptr<PassManager> build_pass_manager()
|
|||
twodee->ctx_ = &g_2d;
|
||||
std::shared_ptr<BlitRectPass> pp_simple_blit_pass = std::make_shared<BlitRectPass>(false);
|
||||
std::shared_ptr<PostprocessWipePass> pp_wipe_pass = std::make_shared<PostprocessWipePass>();
|
||||
std::shared_ptr<ScreenshotPass> screenshot_pass = std::make_shared<ScreenshotPass>();
|
||||
std::shared_ptr<ImguiPass> imgui_pass = std::make_shared<ImguiPass>();
|
||||
std::shared_ptr<BlitRectPass> final_composite_pass = std::make_shared<BlitRectPass>(true);
|
||||
|
||||
|
|
@ -186,7 +188,7 @@ static std::shared_ptr<PassManager> build_pass_manager()
|
|||
}
|
||||
pp_simple_blit_pass->set_texture(color, vid.width, vid.height);
|
||||
pp_simple_blit_pass
|
||||
->set_output(framebuffer_manager->current_post_color(), vid.width, vid.height, false, true);
|
||||
->set_output(framebuffer_manager->current_post_color(), vid.width, vid.height, false, false);
|
||||
}
|
||||
);
|
||||
manager->insert("pp_final_simple_blit", pp_simple_blit_pass);
|
||||
|
|
@ -209,12 +211,21 @@ static std::shared_ptr<PassManager> build_pass_manager()
|
|||
[framebuffer_manager](PassManager&, Rhi&) { framebuffer_manager->swap_post(); }
|
||||
);
|
||||
|
||||
manager->insert(
|
||||
"screenshot_prepare",
|
||||
[screenshot_pass, framebuffer_manager](PassManager&, Rhi&)
|
||||
{
|
||||
screenshot_pass->set_source(framebuffer_manager->previous_post_color(), vid.width, vid.height);
|
||||
}
|
||||
);
|
||||
manager->insert("screenshot", screenshot_pass);
|
||||
|
||||
manager->insert(
|
||||
"final_composite_prepare",
|
||||
[final_composite_pass, framebuffer_manager](PassManager&, Rhi&)
|
||||
{
|
||||
final_composite_pass->set_texture(framebuffer_manager->previous_post_color(), vid.width, vid.height);
|
||||
final_composite_pass->set_output(kNullHandle, vid.realwidth, vid.realheight, true, true);
|
||||
final_composite_pass->set_output(kNullHandle, vid.realwidth, vid.realheight, true, false);
|
||||
}
|
||||
);
|
||||
manager->insert("final_composite", final_composite_pass);
|
||||
|
|
|
|||
|
|
@ -1509,7 +1509,7 @@ void M_StopMovie(void)
|
|||
* \param palette Palette of image data.
|
||||
* \note if palette is NULL, BGR888 format
|
||||
*/
|
||||
boolean M_SavePNG(const char *filename, void *data, int width, int height, const UINT8 *palette)
|
||||
boolean M_SavePNG(const char *filename, const void *data, int width, int height, const UINT8 *palette)
|
||||
{
|
||||
png_structp png_ptr;
|
||||
png_infop png_info_ptr;
|
||||
|
|
@ -1580,7 +1580,7 @@ boolean M_SavePNG(const char *filename, void *data, int width, int height, const
|
|||
|
||||
png_write_info(png_ptr, png_info_ptr);
|
||||
|
||||
M_PNGImage(png_ptr, png_info_ptr, height, static_cast<png_bytep>(data));
|
||||
M_PNGImage(png_ptr, png_info_ptr, height, (png_bytep)data);
|
||||
|
||||
png_write_end(png_ptr, png_info_ptr);
|
||||
png_destroy_write_struct(&png_ptr, &png_info_ptr);
|
||||
|
|
@ -1688,19 +1688,24 @@ void M_ScreenShot(void)
|
|||
takescreenshot = true;
|
||||
}
|
||||
|
||||
void M_DoLegacyGLScreenShot(void)
|
||||
{
|
||||
const std::byte* fake_data = nullptr;
|
||||
M_DoScreenShot(vid.width, vid.height, tcb::span(fake_data, vid.width * vid.height));
|
||||
}
|
||||
|
||||
/** Takes a screenshot.
|
||||
* The screenshot is saved as "srb2xxxx.png" where xxxx is the lowest
|
||||
* four-digit number for which a file does not already exist.
|
||||
*
|
||||
* \sa HWR_ScreenShot
|
||||
*/
|
||||
void M_DoScreenShot(void)
|
||||
void M_DoScreenShot(UINT32 width, UINT32 height, tcb::span<const std::byte> data)
|
||||
{
|
||||
#if NUMSCREENS > 2
|
||||
const char *freename = NULL;
|
||||
char pathname[MAX_WADPATH];
|
||||
boolean ret = false;
|
||||
UINT8 *linear = NULL;
|
||||
|
||||
// Don't take multiple screenshots, obviously
|
||||
takescreenshot = false;
|
||||
|
|
@ -1733,13 +1738,6 @@ void M_DoScreenShot(void)
|
|||
freename = Newsnapshotfile(pathname,"tga");
|
||||
#endif
|
||||
|
||||
if (rendermode == render_soft)
|
||||
{
|
||||
// munge planar buffer to linear
|
||||
linear = screens[2];
|
||||
I_ReadScreen(linear);
|
||||
}
|
||||
|
||||
if (!freename)
|
||||
goto failure;
|
||||
|
||||
|
|
@ -1750,9 +1748,9 @@ void M_DoScreenShot(void)
|
|||
else
|
||||
#endif
|
||||
{
|
||||
M_CreateScreenShotPalette();
|
||||
const void* pixel_data = static_cast<const void*>(data.data());
|
||||
#ifdef USE_PNG
|
||||
ret = M_SavePNG(va(pandf,pathname,freename), linear, vid.width, vid.height, screenshot_palette);
|
||||
ret = M_SavePNG(va(pandf,pathname,freename), pixel_data, width, height, NULL);
|
||||
#else
|
||||
ret = WritePCXfile(va(pandf,pathname,freename), linear, vid.width, vid.height, screenshot_palette);
|
||||
#endif
|
||||
|
|
|
|||
13
src/m_misc.h
13
src/m_misc.h
|
|
@ -22,6 +22,13 @@
|
|||
#include "command.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <tcb/span.hpp>
|
||||
|
||||
void M_DoScreenShot(uint32_t width, uint32_t height, tcb::span<const std::byte> data);
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
|
@ -82,12 +89,14 @@ void FIL_ForceExtension(char *path, const char *extension);
|
|||
boolean FIL_CheckExtension(const char *in);
|
||||
|
||||
#ifdef HAVE_PNG
|
||||
boolean M_SavePNG(const char *filename, void *data, int width, int height, const UINT8 *palette);
|
||||
boolean M_SavePNG(const char *filename, const void *data, int width, int height, const UINT8 *palette);
|
||||
#endif
|
||||
|
||||
extern boolean takescreenshot;
|
||||
void M_ScreenShot(void);
|
||||
void M_DoScreenShot(void);
|
||||
#ifdef HWRENDER
|
||||
void M_DoLegacyGLScreenShot(void);
|
||||
#endif
|
||||
boolean M_ScreenshotResponder(event_t *ev);
|
||||
|
||||
void M_MinimapGenerate(void);
|
||||
|
|
|
|||
|
|
@ -42,6 +42,12 @@ constexpr GLenum map_pixel_format(rhi::PixelFormat format)
|
|||
{
|
||||
switch (format)
|
||||
{
|
||||
case rhi::PixelFormat::kR8:
|
||||
return GL_R8;
|
||||
case rhi::PixelFormat::kRG8:
|
||||
return GL_RG8;
|
||||
case rhi::PixelFormat::kRGB8:
|
||||
return GL_RGB8;
|
||||
case rhi::PixelFormat::kRGBA8:
|
||||
return GL_RGBA8;
|
||||
case rhi::PixelFormat::kDepth16:
|
||||
|
|
@ -70,6 +76,11 @@ constexpr std::tuple<GLenum, GLenum, GLuint> map_pixel_data_format(rhi::PixelFor
|
|||
type = GL_UNSIGNED_BYTE;
|
||||
size = 2;
|
||||
break;
|
||||
case rhi::PixelFormat::kRGB8:
|
||||
layout = GL_RGB;
|
||||
type = GL_UNSIGNED_BYTE;
|
||||
size = 3;
|
||||
break;
|
||||
case rhi::PixelFormat::kRGBA8:
|
||||
layout = GL_RGBA;
|
||||
type = GL_UNSIGNED_BYTE;
|
||||
|
|
@ -1581,13 +1592,19 @@ void GlCoreRhi::draw_indexed(Handle<GraphicsContext> ctx, uint32_t index_count,
|
|||
GL_ASSERT
|
||||
}
|
||||
|
||||
void GlCoreRhi::read_pixels(Handle<GraphicsContext> ctx, const Rect& rect, tcb::span<std::byte> out)
|
||||
void GlCoreRhi::read_pixels(Handle<GraphicsContext> ctx, const Rect& rect, PixelFormat format, tcb::span<std::byte> out)
|
||||
{
|
||||
SRB2_ASSERT(graphics_context_active_ == true && graphics_context_generation_ == ctx.generation());
|
||||
SRB2_ASSERT(current_render_pass_.has_value());
|
||||
|
||||
SRB2_ASSERT(out.size_bytes() == rect.w * rect.h);
|
||||
gl_->ReadPixels(rect.x, rect.y, rect.w, rect.h, GL_RGBA, GL_UNSIGNED_BYTE, out.data());
|
||||
std::tuple<GLenum, GLenum, GLuint> gl_format = map_pixel_data_format(format);
|
||||
GLenum layout = std::get<0>(gl_format);
|
||||
GLenum type = std::get<1>(gl_format);
|
||||
GLint size = std::get<2>(gl_format);
|
||||
|
||||
SRB2_ASSERT(out.size_bytes() == rect.w * rect.h * size);
|
||||
|
||||
gl_->ReadPixels(rect.x, rect.y, rect.w, rect.h, layout, type, out.data());
|
||||
}
|
||||
|
||||
void GlCoreRhi::finish()
|
||||
|
|
|
|||
|
|
@ -226,7 +226,8 @@ public:
|
|||
virtual void set_viewport(Handle<GraphicsContext> ctx, const Rect& rect) override;
|
||||
virtual void draw(Handle<GraphicsContext> ctx, uint32_t vertex_count, uint32_t first_vertex) override;
|
||||
virtual void draw_indexed(Handle<GraphicsContext> ctx, uint32_t index_count, uint32_t first_index) override;
|
||||
virtual void read_pixels(Handle<GraphicsContext> ctx, const Rect& rect, tcb::span<std::byte> out) override;
|
||||
virtual void
|
||||
read_pixels(Handle<GraphicsContext> ctx, const Rect& rect, PixelFormat format, tcb::span<std::byte> out) override;
|
||||
|
||||
virtual void present() override;
|
||||
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ enum class PixelFormat
|
|||
{
|
||||
kR8,
|
||||
kRG8,
|
||||
kRGB8,
|
||||
kRGBA8,
|
||||
kDepth16,
|
||||
kStencil8
|
||||
|
|
@ -562,7 +563,8 @@ struct Rhi
|
|||
virtual void set_viewport(Handle<GraphicsContext> ctx, const Rect& rect) = 0;
|
||||
virtual void draw(Handle<GraphicsContext> ctx, uint32_t vertex_count, uint32_t first_vertex) = 0;
|
||||
virtual void draw_indexed(Handle<GraphicsContext> ctx, uint32_t index_count, uint32_t first_index) = 0;
|
||||
virtual void read_pixels(Handle<GraphicsContext> ctx, const Rect& rect, tcb::span<std::byte> out) = 0;
|
||||
virtual void
|
||||
read_pixels(Handle<GraphicsContext> ctx, const Rect& rect, PixelFormat format, tcb::span<std::byte> out) = 0;
|
||||
|
||||
virtual void present() = 0;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue