Skip to content
This repository has been archived by the owner on Jan 5, 2024. It is now read-only.

Commit

Permalink
Merge pull request #545 from cortex-command-community/screenshot-fixes
Browse files Browse the repository at this point in the history
Screenshot fixes
  • Loading branch information
Causeless authored Oct 25, 2023
2 parents 399719f + 98216bf commit ef29fec
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 41 deletions.
1 change: 1 addition & 0 deletions Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ namespace RTE {
g_LuaMan.Destroy();
ContentFile::FreeAllLoaded();
g_ConsoleMan.Destroy();
g_WindowMan.Destroy();

#ifdef DEBUG_BUILD
Entity::ClassInfo::DumpPoolMemoryInfo(Writer("MemCleanupInfo.txt"));
Expand Down
2 changes: 1 addition & 1 deletion Managers/ConsoleMan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ namespace RTE {
SetReadOnly();
}

if (!g_UInputMan.FlagShiftState() && (!g_UInputMan.FlagCtrlState() && g_UInputMan.KeyPressed(SDL_SCANCODE_GRAVE))) {
if (!g_UInputMan.FlagShiftState() && (!g_UInputMan.FlagCtrlState() && (g_UInputMan.KeyPressed(SDL_SCANCODE_GRAVE) || (IsEnabled() && g_UInputMan.KeyPressed(SDL_SCANCODE_ESCAPE))))) {
if (IsEnabled()) {
if (!m_ReadOnly) {
m_InputTextBox->SetEnabled(false);
Expand Down
28 changes: 6 additions & 22 deletions Managers/FrameMan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ namespace RTE {
}

// TODO: Remove this once GCC13 is released and switched to. std::format and std::chrono::time_zone are not part of latest libstdc++.
#if _LINUX_OR_MACOSX_
#if defined(__GNUC__) && __GNUC__ < 13
std::chrono::time_point now = std::chrono::system_clock::now();
time_t currentTime = std::chrono::system_clock::to_time_t(now);
tm *localCurrentTime = std::localtime(&currentTime);
Expand Down Expand Up @@ -540,7 +540,7 @@ namespace RTE {
SaveScreenToBitmap();

// Make a copy of the buffer because it may be overwritten mid thread and everything will be on fire.
BITMAP *outputBitmap = create_bitmap_ex(bitmap_color_depth(m_ScreenDumpBuffer.get()), m_ScreenDumpBuffer->w * g_WindowMan.GetResMultiplier(), m_ScreenDumpBuffer->h * g_WindowMan.GetResMultiplier());
BITMAP *outputBitmap = create_bitmap_ex(bitmap_color_depth(m_ScreenDumpBuffer.get()), m_ScreenDumpBuffer->w, m_ScreenDumpBuffer->h);
stretch_blit(m_ScreenDumpBuffer.get(), outputBitmap, 0, 0, m_ScreenDumpBuffer->w, m_ScreenDumpBuffer->h, 0, 0, outputBitmap->w, outputBitmap->h);

auto saveScreenDump = [fullFileName](BITMAP *bitmapToSaveCopy) {
Expand Down Expand Up @@ -604,26 +604,10 @@ namespace RTE {
if (!m_ScreenDumpBuffer) {
return;
}
int drawSizeX, drawSizeY;
SDL_GL_GetDrawableSize(g_WindowMan.GetWindow(), &drawSizeX, &drawSizeY);
BITMAP* screenBitmap = create_bitmap_ex(32, drawSizeX, drawSizeY);
GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
GL_CHECK(glReadBuffer(GL_FRONT));
GL_CHECK(glPixelStorei(GL_PACK_ALIGNMENT, 1));
GL_CHECK(glReadPixels(0, 0, screenBitmap->w, screenBitmap->h, GL_RGBA, GL_UNSIGNED_BYTE, screenBitmap->line[0]));
GL_CHECK(glReadBuffer(GL_BACK));

BITMAP* depthBitmap = create_bitmap_ex(bitmap_color_depth(m_ScreenDumpBuffer.get()), screenBitmap->w, screenBitmap->h);
blit(screenBitmap, depthBitmap, 0, 0, 0, 0, screenBitmap->w, screenBitmap->h);

BITMAP* flipBitmap = create_bitmap_ex(bitmap_color_depth(depthBitmap), depthBitmap->w, depthBitmap->h);
draw_sprite_v_flip(flipBitmap, depthBitmap, 0, 0);

stretch_blit(flipBitmap, m_ScreenDumpBuffer.get(), 0, 0, screenBitmap->w, screenBitmap->h, 0, 0, m_ScreenDumpBuffer->w, m_ScreenDumpBuffer->h);
destroy_bitmap(screenBitmap);
destroy_bitmap(depthBitmap);
destroy_bitmap(flipBitmap);

glBindTexture(GL_TEXTURE_2D, g_WindowMan.GetScreenBufferTexture());
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, m_ScreenDumpBuffer->line[0]);

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down
8 changes: 6 additions & 2 deletions Managers/PresetMan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -334,8 +334,12 @@ bool PresetMan::IsModuleUserdata(const std::string &moduleName) const {
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

std::string PresetMan::GetFullModulePath(const std::string &modulePath) const {
const std::string modulePathGeneric = std::filesystem::path(modulePath).generic_string();
const std::string pathTopDir = modulePathGeneric.substr(0, modulePathGeneric.find_first_of("/\\") + 1);
// Note: Mods may use mixed path separators, which aren't supported on non Windows systems.
// Since Windows supports both forward and backslash separators it's safe to replace all backslashes with forward slashes.
std::string modulePathGeneric = std::filesystem::path(modulePath).generic_string();
std::replace(modulePathGeneric.begin(), modulePathGeneric.end(), '\\', '/');

const std::string pathTopDir = modulePathGeneric.substr(0, modulePathGeneric.find_first_of("/") + 1);
const std::string moduleName = GetModuleNameFromPath(modulePathGeneric);

std::string moduleTopDir = System::GetModDirectory();
Expand Down
1 change: 0 additions & 1 deletion Managers/UInputMan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -903,7 +903,6 @@ namespace RTE {
}
// Ctrl+R or Back button for controllers to reset activity.
if (!g_MetaMan.GameInProgress() && !g_ActivityMan.ActivitySetToRestart()) {
g_ActivityMan.SetRestartActivity(FlagCtrlState() && KeyPressed(SDLK_r) || AnyBackPress());
g_ActivityMan.SetRestartActivity((FlagCtrlState() && KeyPressed(SDLK_r)) || AnyBackPress());
}
if (g_ActivityMan.ActivitySetToRestart()) {
Expand Down
37 changes: 29 additions & 8 deletions Managers/WindowMan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ namespace RTE {

WindowMan::~WindowMan() = default;

void WindowMan::Destroy() {
glDeleteTextures(1, &m_BackBuffer32Texture);
glDeleteBuffers(1, &m_ScreenVBO);
glDeleteVertexArrays(1, &m_ScreenVAO);
glDeleteTextures(1, &m_ScreenBufferTexture);
glDeleteFramebuffers(1, &m_ScreenBufferFBO);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void WindowMan::Initialize() {
Expand Down Expand Up @@ -205,17 +213,22 @@ namespace RTE {
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)(2 * sizeof(float)));
glEnableVertexAttribArray(1);
glBindVertexArray(0);
glGenTextures(1, &m_BackBuffer32Texture);
glGenTextures(1, &m_ScreenBufferTexture);
glGenFramebuffers(1, &m_ScreenBufferFBO);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void WindowMan::CreateBackBufferTexture() {
glDeleteTextures(1, &m_BackBuffer32Texture);
glGenTextures(1, &m_BackBuffer32Texture);
glBindTexture(GL_TEXTURE_2D, m_BackBuffer32Texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_ResX, m_ResY, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, m_ScreenBufferTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_ResX, m_ResY, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -724,12 +737,13 @@ namespace RTE {

void WindowMan::UploadFrame() {
glDisable(GL_DEPTH_TEST);
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
GL_CHECK(glActiveTexture(GL_TEXTURE0));

int windowW, windowH;
SDL_GL_GetDrawableSize(m_PrimaryWindow.get(), &windowW, &windowH);
GL_CHECK(glViewport(0, 0, windowW, windowH));
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_ScreenBufferFBO));
GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_ScreenBufferTexture, 0));
GL_CHECK(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
GL_CHECK(glClear(GL_COLOR_BUFFER_BIT));
GL_CHECK(glActiveTexture(GL_TEXTURE0));
glViewport(0, 0, m_ResX, m_ResY);

glEnable(GL_BLEND);
if (m_DrawPostProcessBuffer) {
Expand All @@ -750,9 +764,16 @@ namespace RTE {
m_ScreenBlitShader->Use();
m_ScreenBlitShader->SetInt(m_ScreenBlitShader->GetTextureUniform(), 0);
m_ScreenBlitShader->SetInt(m_ScreenBlitShader->GetUniformLocation("rteGUITexture"), 1);
m_ScreenBlitShader->SetMatrix4f(m_ScreenBlitShader->GetProjectionUniform(), glm::mat4(1.0f));
m_ScreenBlitShader->SetMatrix4f(m_ScreenBlitShader->GetTransformUniform(), glm::scale(glm::mat4(1.0f), {1.0f, -1.0f, 1.0f}));
GL_CHECK(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
GL_CHECK(glActiveTexture(GL_TEXTURE0));
GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
GL_CHECK(glActiveTexture(GL_TEXTURE1));
GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_ScreenBufferTexture));
if (m_MultiDisplayWindows.empty()) {
glViewport(m_PrimaryWindowViewport->x, m_PrimaryWindowViewport->y, m_PrimaryWindowViewport->w, m_PrimaryWindowViewport->h);
m_ScreenBlitShader->SetMatrix4f(m_ScreenBlitShader->GetProjectionUniform(), glm::mat4(1.0f));
m_ScreenBlitShader->SetMatrix4f(m_ScreenBlitShader->GetTransformUniform(), glm::mat4(1.0f));
GL_CHECK(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
SDL_GL_SwapWindow(m_PrimaryWindow.get());
Expand Down
15 changes: 14 additions & 1 deletion Managers/WindowMan.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ namespace RTE {
/// Destructor method used to clean up a WindowMan object before deletion from system memory.
/// </summary>
~WindowMan();

/// <summary>
/// Clean up GL pointers.
/// </summary>
void Destroy();
#pragma endregion

#pragma region Getters and Setters
Expand Down Expand Up @@ -164,6 +169,12 @@ namespace RTE {
/// </summary>
/// <returns>The absolute top-most position in the OS display arrangement.</returns>
int GetDisplayArrangementAbsOffsetY() const { return std::abs(m_DisplayArrangementTopMostOffset); }

/// <summary>
/// Get the screen buffer texture.
/// </summary>
/// <returns>The screen buffer texture.</returns>
GLuint GetScreenBufferTexture() const { return m_ScreenBufferTexture; }
#pragma endregion

#pragma region Resolution Change Handling
Expand Down Expand Up @@ -247,7 +258,9 @@ namespace RTE {
bool m_FocusEventsDispatchedByDisplaySwitchIn; //!< Whether queued events were dispatched due to raising windows when taking focus of any game window in the previous update.

std::shared_ptr<SDL_Window> m_PrimaryWindow; //!< The main window.
GLuint m_BackBuffer32Texture; //!< The main window renderer's drawing surface.
GLuint m_BackBuffer32Texture; //!< Streaming texture for the software rendered stuff.
GLuint m_ScreenBufferTexture; //!< Internal backbuffer for the final blit and sceenshots, only clear immediately before drawing.
GLuint m_ScreenBufferFBO; //!< Framebuffer object for the screen buffer texture.
glm::mat4 m_PrimaryWindowProjection; //!< Projection Matrix for the main window.
std::unique_ptr<SDL_Rect> m_PrimaryWindowViewport; //!< Viewport for the main window.

Expand Down
28 changes: 22 additions & 6 deletions System/RTEError.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -391,12 +391,28 @@ namespace RTE {

bool RTEError::DumpAbortScreen() {
int success = -1;
if (BITMAP *backbuffer = g_FrameMan.GetBackBuffer32(); backbuffer) {
// Have to convert the 32bpp backbuffer to 24bpp otherwise the saved file is blank for reasons that don't matter.
BITMAP *abortScreenBuffer = create_bitmap_ex(24, backbuffer->w, backbuffer->h);
blit(backbuffer, abortScreenBuffer, 0, 0, 0, 0, backbuffer->w, backbuffer->h);
success = save_png("AbortScreen.png", abortScreenBuffer, nullptr);
destroy_bitmap(abortScreenBuffer);
if (glReadPixels != nullptr) {
int w ,h;
SDL_GL_GetDrawableSize(g_WindowMan.GetWindow(), &w, &h);
if (!(w>0 && h>0)) {
return false;
}
BITMAP* readBuffer = create_bitmap_ex(24, w, h);
// Read screen from the front buffer since that is the only framebuffer guaranteed to exist at this point.
// Read twice because front buffer content is technically undefined, but most drivers still eventually give up the contents correctly.
glReadBuffer(GL_FRONT);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, readBuffer->line[0]);
glFinish();
glReadBuffer(GL_BACK);
glReadBuffer(GL_FRONT);
glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, readBuffer->line[0]);
glFinish();

BITMAP* flipBuffer = create_bitmap_ex(24, w, h);
draw_sprite_v_flip(flipBuffer, readBuffer, 0, 0);

success = save_png("AbortScreen.png", flipBuffer, nullptr);
}
return success == 0;
}
Expand Down

0 comments on commit ef29fec

Please sign in to comment.