save screenshots as PNG

This commit is contained in:
Edu García 2024-05-09 22:38:54 +01:00
parent 5d8affda0e
commit 80c207d41c
14 changed files with 1917 additions and 77 deletions

View File

@ -150,7 +150,7 @@ include_directories(
${PLATFORM_INCLUDES}
)
# file(GLOB_RECURSE INCS "*.h")
add_subdirectory(third_party)
add_subdirectory(2dlib)
add_subdirectory(AudioEncode)

View File

@ -694,6 +694,8 @@
#include "osiris_share.h"
#include "demofile.h"
#include <NewBitmap.h>
///////////////////////////////////////////////////////////////////////////////
// Variables
@ -1293,7 +1295,6 @@ void EndFrame() {
// Does a screenshot and tells the bitmap lib to save out the picture as a tga
void DoScreenshot() {
int bm_handle;
int count;
char str[255], filename[255];
CFILE *infile;
@ -1307,21 +1308,20 @@ void DoScreenshot() {
height = rs.screen_height;
}
bm_handle = bm_AllocBitmap(width, height, 0);
if (bm_handle < 0) {
StopTime();
// Tell our renderer lib to take a screen shot
auto screenshot = rend_Screenshot();
if (!screenshot || screenshot->getData() == nullptr) {
AddHUDMessage(TXT_ERRSCRNSHT);
return;
}
StopTime();
// Tell our renderer lib to take a screen shot
rend_Screenshot(bm_handle);
// Find a valid filename
count = 1;
while (!done) {
snprintf(str, sizeof(str), "Screenshot%.3d.tga", count);
snprintf(str, sizeof(str), "Screenshot%.3d.png", count);
ddio_MakePath(filename, Base_directory, str, NULL);
infile = (CFILE *)cfopen(filename, "rb");
if (infile == NULL) {
@ -1335,16 +1335,12 @@ void DoScreenshot() {
break;
}
strcpy(GameBitmaps[bm_handle].name, str);
// Now save it
bm_SaveBitmapTGA(filename, bm_handle);
screenshot->saveAsPNG(filename);
if (Demo_flags != DF_PLAYBACK) {
AddHUDMessage(TXT_SCRNSHT, filename);
}
// Free memory
bm_FreeBitmap(bm_handle);
StartTime();
}

View File

@ -1,5 +1,8 @@
set(HEADERS iff.h)
set(CPPS
NewBitmap.cpp
NewBitmap.h
bitmain.cpp
bumpmap.cpp
iff.cpp
@ -11,4 +14,6 @@ add_library(bitmap STATIC ${HEADERS} ${CPPS})
target_link_libraries(bitmap PRIVATE
cfile
ddebug
stb
)
target_include_directories(bitmap PUBLIC .)

57
bitmap/NewBitmap.cpp Normal file
View File

@ -0,0 +1,57 @@
/*
* Descent 3
* Copyright (C) 2024 Descent Developers
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "NewBitmap.h"
#include "pserror.h"
#include <stb_image_write.h>
NewBitmap::NewBitmap(uint32_t w, uint32_t h, PixelDataFormat format, bool flippedY)
: _w(w), _h(h), _format(format), _flippedY(flippedY), _data(allocateData(w, h, format)) {
ASSERT(_data.get());
}
std::unique_ptr<uint8_t[]> NewBitmap::allocateData(uint32_t w, uint32_t h, PixelDataFormat format) {
switch (format) {
case PixelDataFormat::RGBA32: return std::make_unique<uint8_t[]>(w * h * 4);
default: return nullptr;
}
}
uint32_t NewBitmap::getNumComponents() const {
switch (_format) {
case PixelDataFormat::RGBA32: return 4;
default: return 0;
}
}
uint32_t NewBitmap::getStride() const {
switch (_format) {
case PixelDataFormat::RGBA32: return _w * 4;
default: return 0;
}
}
bool NewBitmap::saveAsPNG(const char *filePath) {
// TODO: Support more formats? stb_write supports at least RGB and RGBA
ASSERT(_format == PixelDataFormat::RGBA32);
stbi_flip_vertically_on_write(_flippedY);
return stbi_write_png(filePath, _w, _h, getNumComponents(), _data.get(), getStride()) == 0;
}

60
bitmap/NewBitmap.h Normal file
View File

@ -0,0 +1,60 @@
/*
* Descent 3
* Copyright (C) 2024 Descent Developers
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DESCENT3_NEWBITMAP_H
#define DESCENT3_NEWBITMAP_H
#include <cstdint>
#include <memory>
enum class PixelDataFormat {
Unknown,
RGBA32
};
class NewBitmap {
private:
uint32_t _w, _h;
PixelDataFormat _format;
bool _flippedY;
std::unique_ptr<uint8_t[]> _data;
static std::unique_ptr<uint8_t[]> allocateData(uint32_t w, uint32_t h, PixelDataFormat format);
[[nodiscard]] uint32_t getStride() const;
public:
/// Creates a new bitmap of size "w * h" and the specified format. Will allocate enough memory to store it.
NewBitmap(uint32_t w, uint32_t h, PixelDataFormat format, bool flippedY = false);
void getSize(uint32_t &w, uint32_t &h) const {
w = _w;
h = _h;
}
/// @returns raw pointer to image data
[[nodiscard]] uint8_t *getData() const { return _data.get(); }
/// @returns number of components for the bitmap format (i.e. 4 for "RGBA")
[[nodiscard]] uint32_t getNumComponents() const;
/// @returns true on success, false otherwise
bool saveAsPNG(const char* filePath);
};
#endif // DESCENT3_NEWBITMAP_H

View File

@ -1403,51 +1403,6 @@ int bm_SetBitmapIfTransparent(int handle) {
return 0;
}
// Saves the passed bitmap handle as a 32 bit uncompressed tga
int bm_SaveBitmapTGA(const char *filename, int handle) {
int height, width;
int i, t;
CFILE *fp;
fp = (CFILE *)cfopen(filename, "wb");
if (fp == NULL) {
mprintf((0, "SaveTGA:couldn't open %s!\n", filename));
return 0;
}
ASSERT(GameBitmaps[handle].format == BITMAP_FORMAT_1555); // Can only save 1555
width = bm_w(handle, 0);
height = bm_h(handle, 0);
cf_WriteByte(fp, 0); // image_id_len
cf_WriteByte(fp, 0); // color map type
cf_WriteByte(fp, 2); // image type: 2= uncompressed tga
for (i = 0; i < 9; i++) // ingore next 9 bytes
cf_WriteByte(fp, 0);
cf_WriteShort(fp, width);
cf_WriteShort(fp, height);
cf_WriteByte(fp, 32);
cf_WriteByte(fp, 32 + 8);
// for (i=0;i<image_id_len;i++)
// cf_ReadByte (infile);
// upside_down=(descriptor & 0x20)>>5;
// upside_down=1-upside_down;
ushort *src_data = (ushort *)bm_data(handle, 0);
for (i = 0; i < height; i++) {
for (t = 0; t < width; t++) {
ushort pix;
ddgr_color color;
pix = src_data[i * width + t];
color = GR_16_TO_COLOR(pix);
color |= 0xFF000000;
cf_WriteInt(fp, color);
}
}
// Finis!
cfclose(fp);
return 1;
}
// clears bitmap
void bm_ClearBitmap(int handle) {
int dx, dy;

View File

@ -131,8 +131,6 @@ void bm_ScaleBitmapToBitmap(int dest, int src);
int bm_rowsize(int handle, int miplevel);
// Goes through the bitmap and sees if there is any transparency...if so, flag it!
int bm_SetBitmapIfTransparent(int handle);
// Saves the passed bitmap handle as a 24 bit uncompressed tga
int bm_SaveBitmapTGA(const char *filename, int handle);
// Allocs and loads a bitmap but doesn't actually load texel data!
// Returns the handle of the loaded bitmap
// Returns -1 if something is wrong

View File

@ -294,6 +294,7 @@
#ifndef RENDERER_H
#define RENDERER_H
#include <memory>
#include "pstypes.h"
#include "grdefs.h"
@ -352,6 +353,8 @@ extern bool UseMipmap; // DAJ
extern bool ATIRagePro; // DAJ
extern bool Formac; // DAJ
class NewBitmap;
// various state setting functions
//------------------------------------
@ -580,6 +583,9 @@ float rend_GetAlphaFactor(void);
// Sets the wrap parameter
void rend_SetWrapType(wrap_type val);
/// Takes a screenshot of the current frame and returns a NewBitmap
std::unique_ptr<NewBitmap> rend_Screenshot();
// Takes a screenshot of the current frame and puts it into the handle passed
void rend_Screenshot(int bm_handle);

View File

@ -24,3 +24,4 @@ endif()
#Direct3D.cpp
add_library(renderer STATIC ${HEADERS} ${CPPS})
target_link_libraries(renderer PRIVATE bitmap)

View File

@ -46,6 +46,8 @@
#include "HardwareInternal.h"
#include "../Descent3/args.h"
#include <NewBitmap.h>
#define DECLARE_OPENGL
#include "dyna_gl.h"
@ -2532,28 +2534,38 @@ void rend_DrawSpecialLine(g3Point *p0, g3Point *p1) {
}
// Takes a screenshot of the current frame and puts it into the handle passed
void rend_Screenshot(int bm_handle) {
std::unique_ptr<NewBitmap> rend_Screenshot() {
ushort *dest_data;
uint *temp_data;
int i, t;
int total = gpu_state.screen_width * gpu_state.screen_height;
auto result = std::make_unique<NewBitmap>(gpu_state.screen_width, gpu_state.screen_height, PixelDataFormat::RGBA32, true);
if (!result || result->getData() == nullptr) {
return nullptr;
}
dglReadPixels(0, 0, gpu_state.screen_width, gpu_state.screen_height, GL_RGBA, GL_UNSIGNED_BYTE,
(GLvoid *)result->getData());
return result;
}
// Takes a screenshot of the current frame and puts it into the handle passed
void rend_Screenshot(int bm_handle) {
auto screenshot = rend_Screenshot();
auto *temp_data = reinterpret_cast<uint*>(screenshot->getData());
uint32_t w, h;
screenshot->getSize(w, h);
ASSERT((bm_w(bm_handle, 0)) == gpu_state.screen_width);
ASSERT((bm_h(bm_handle, 0)) == gpu_state.screen_height);
int w = bm_w(bm_handle, 0);
int h = bm_h(bm_handle, 0);
ushort* dest_data = bm_data(bm_handle, 0);
temp_data = (uint *)mem_malloc(total * 4);
ASSERT(temp_data); // Ran out of memory?
dest_data = bm_data(bm_handle, 0);
dglReadPixels(0, 0, gpu_state.screen_width, gpu_state.screen_height, GL_RGBA, GL_UNSIGNED_BYTE,
(GLvoid *)temp_data);
for (i = 0; i < h; i++) {
for (t = 0; t < w; t++) {
for (int i = 0; i < h; i++) {
for (int t = 0; t < w; t++) {
uint spix = temp_data[i * w + t];
int r = spix & 0xff;

1
third_party/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1 @@
add_subdirectory(stb)

5
third_party/stb/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,5 @@
add_library(stb STATIC
stb.cpp
stb_image_write.h
)
target_include_directories(stb PUBLIC .)

20
third_party/stb/stb.cpp vendored Normal file
View File

@ -0,0 +1,20 @@
/*
* Descent 3
* Copyright (C) 2024 Descent Developers
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"

1724
third_party/stb/stb_image_write.h vendored Normal file

File diff suppressed because it is too large Load Diff