mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2025-04-10 19:15:14 +00:00
Added support for A1RGB5 to BMP file writer and added a (commented-out) example of how to use it to dump texture memory in ~CReal3D()
This commit is contained in:
parent
c459772f8e
commit
fa65542d76
|
@ -42,6 +42,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Supermodel.h"
|
#include "Supermodel.h"
|
||||||
|
#include "Util/BMPFile.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
// Macros that divide memory regions into pages and mark them as dirty when they are written to
|
// Macros that divide memory regions into pages and mark them as dirty when they are written to
|
||||||
|
@ -1109,6 +1110,7 @@ CReal3D::~CReal3D(void)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
printf("unable to dump %s\n", "texram");
|
printf("unable to dump %s\n", "texram");
|
||||||
|
Util::WriteSurfaceToBMP<Util::A1RGB5>("textures.bmp", reinterpret_cast<uint8_t *>(textureRAM), 2048, 2048, false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Render3D = NULL;
|
Render3D = NULL;
|
||||||
|
|
|
@ -430,7 +430,7 @@ static void SaveFrameBuffer(const std::string &file)
|
||||||
{
|
{
|
||||||
std::shared_ptr<uint8_t> pixels(new uint8_t[totalXRes*totalYRes*4], std::default_delete<uint8_t[]>());
|
std::shared_ptr<uint8_t> pixels(new uint8_t[totalXRes*totalYRes*4], std::default_delete<uint8_t[]>());
|
||||||
glReadPixels(0, 0, totalXRes, totalYRes, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get());
|
glReadPixels(0, 0, totalXRes, totalYRes, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get());
|
||||||
Util::WriteRGBA8SurfaceToBMP(file, pixels.get(), totalXRes, totalYRes, true);
|
Util::WriteSurfaceToBMP<Util::RGBA8>(file, pixels.get(), totalXRes, totalYRes, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool g_forceFlushModels = false;
|
bool g_forceFlushModels = false;
|
||||||
|
|
|
@ -1,115 +0,0 @@
|
||||||
#include "Util/BMPFile.h"
|
|
||||||
#include "OSD/Logger.h"
|
|
||||||
#include <memory>
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
namespace Util
|
|
||||||
{
|
|
||||||
#pragma pack(push, 1)
|
|
||||||
|
|
||||||
struct BMPHeader
|
|
||||||
{
|
|
||||||
uint8_t id[2];
|
|
||||||
uint32_t file_size;
|
|
||||||
uint16_t reserved1;
|
|
||||||
uint16_t reserved2;
|
|
||||||
uint32_t bitmap_offset;
|
|
||||||
BMPHeader(uint32_t _file_size, uint32_t _bitmap_offset)
|
|
||||||
: file_size(_file_size),
|
|
||||||
reserved1(0),
|
|
||||||
reserved2(0),
|
|
||||||
bitmap_offset(_bitmap_offset)
|
|
||||||
{
|
|
||||||
id[0] = 'B';
|
|
||||||
id[1] = 'M';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BMPInfoHeader
|
|
||||||
{
|
|
||||||
uint32_t size;
|
|
||||||
int32_t width;
|
|
||||||
int32_t height;
|
|
||||||
uint16_t num_planes;
|
|
||||||
uint16_t bits_per_pixel;
|
|
||||||
uint32_t compression_method;
|
|
||||||
uint32_t bitmap_size;
|
|
||||||
int32_t horizontal_resolution;
|
|
||||||
int32_t vertical_resolution;
|
|
||||||
uint32_t num_palette_colors;
|
|
||||||
uint32_t num_important_colors;
|
|
||||||
BMPInfoHeader(int32_t _width, int32_t _height)
|
|
||||||
: size(sizeof(BMPInfoHeader)),
|
|
||||||
width(_width),
|
|
||||||
height(_height),
|
|
||||||
num_planes(1),
|
|
||||||
bits_per_pixel(24),
|
|
||||||
compression_method(0),
|
|
||||||
bitmap_size(_width*_height*3),
|
|
||||||
horizontal_resolution(2835), // 72 dpi
|
|
||||||
vertical_resolution(2835),
|
|
||||||
num_palette_colors(0),
|
|
||||||
num_important_colors(0)
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FileHeader
|
|
||||||
{
|
|
||||||
BMPHeader bmp_header;
|
|
||||||
BMPInfoHeader bmp_info_header;
|
|
||||||
FileHeader(int32_t width, int32_t height)
|
|
||||||
: bmp_header(sizeof(FileHeader) + width*height*3, sizeof(FileHeader)),
|
|
||||||
bmp_info_header(width, height)
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
bool WriteRGBA8SurfaceToBMP(const std::string &file_name, const uint8_t *pixels, int32_t width, int32_t height, bool flip_vertical)
|
|
||||||
{
|
|
||||||
size_t file_size = sizeof(FileHeader) + width*height*3;
|
|
||||||
std::shared_ptr<uint8_t> file(new uint8_t[file_size], std::default_delete<uint8_t[]>());
|
|
||||||
FileHeader *header = new (file.get()) FileHeader(width, height);
|
|
||||||
uint8_t *bmp = file.get() + sizeof(*header);
|
|
||||||
if (!flip_vertical)
|
|
||||||
{
|
|
||||||
for (int32_t y = height - 1; y >= 0; y--)
|
|
||||||
{
|
|
||||||
const uint8_t *src = &pixels[y*width*4];
|
|
||||||
for (int32_t x = 0; x < width; x++)
|
|
||||||
{
|
|
||||||
*bmp++ = src[2]; // b
|
|
||||||
*bmp++ = src[1]; // g
|
|
||||||
*bmp++ = src[0]; // r
|
|
||||||
src += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int32_t y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
const uint8_t *src = &pixels[y*width*4];
|
|
||||||
for (int32_t x = 0; x < width; x++)
|
|
||||||
{
|
|
||||||
*bmp++ = src[2]; // b
|
|
||||||
*bmp++ = src[1]; // g
|
|
||||||
*bmp++ = src[0]; // r
|
|
||||||
src += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FILE *fp = fopen(file_name.c_str(), "wb");
|
|
||||||
if (fp)
|
|
||||||
{
|
|
||||||
fwrite(file.get(), sizeof(uint8_t), file_size, fp);
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ErrorLog("Unable to open '%s' for writing.", file_name.c_str());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} // Util
|
|
|
@ -1,12 +1,168 @@
|
||||||
#ifndef INCLUDED_BMPFILE_HPP
|
#ifndef INCLUDED_BMPFILE_HPP
|
||||||
#define INCLUDED_BMPFILE_HPP
|
#define INCLUDED_BMPFILE_HPP
|
||||||
|
|
||||||
|
#include "OSD/Logger.h"
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <cstdio>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
namespace Util
|
namespace Util
|
||||||
{
|
{
|
||||||
extern bool WriteRGBA8SurfaceToBMP(const std::string &file_name, const uint8_t *pixels, int32_t width, int32_t height, bool flip_vertical);
|
namespace detail
|
||||||
|
{
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
|
struct BMPHeader
|
||||||
|
{
|
||||||
|
uint8_t id[2];
|
||||||
|
uint32_t file_size;
|
||||||
|
uint16_t reserved1;
|
||||||
|
uint16_t reserved2;
|
||||||
|
uint32_t bitmap_offset;
|
||||||
|
BMPHeader(uint32_t _file_size, uint32_t _bitmap_offset)
|
||||||
|
: file_size(_file_size),
|
||||||
|
reserved1(0),
|
||||||
|
reserved2(0),
|
||||||
|
bitmap_offset(_bitmap_offset)
|
||||||
|
{
|
||||||
|
id[0] = 'B';
|
||||||
|
id[1] = 'M';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BMPInfoHeader
|
||||||
|
{
|
||||||
|
uint32_t size;
|
||||||
|
int32_t width;
|
||||||
|
int32_t height;
|
||||||
|
uint16_t num_planes;
|
||||||
|
uint16_t bits_per_pixel;
|
||||||
|
uint32_t compression_method;
|
||||||
|
uint32_t bitmap_size;
|
||||||
|
int32_t horizontal_resolution;
|
||||||
|
int32_t vertical_resolution;
|
||||||
|
uint32_t num_palette_colors;
|
||||||
|
uint32_t num_important_colors;
|
||||||
|
BMPInfoHeader(int32_t _width, int32_t _height)
|
||||||
|
: size(sizeof(BMPInfoHeader)),
|
||||||
|
width(_width),
|
||||||
|
height(_height),
|
||||||
|
num_planes(1),
|
||||||
|
bits_per_pixel(24),
|
||||||
|
compression_method(0),
|
||||||
|
bitmap_size(_width*_height*3),
|
||||||
|
horizontal_resolution(2835), // 72 dpi
|
||||||
|
vertical_resolution(2835),
|
||||||
|
num_palette_colors(0),
|
||||||
|
num_important_colors(0)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FileHeader
|
||||||
|
{
|
||||||
|
BMPHeader bmp_header;
|
||||||
|
BMPInfoHeader bmp_info_header;
|
||||||
|
FileHeader(int32_t width, int32_t height)
|
||||||
|
: bmp_header(sizeof(FileHeader) + width*height*3, sizeof(FileHeader)),
|
||||||
|
bmp_info_header(width, height)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RGBA8
|
||||||
|
{
|
||||||
|
static constexpr const unsigned bytes_per_pixel = 4;
|
||||||
|
static inline uint8_t GetRed(const uint8_t *pixel)
|
||||||
|
{
|
||||||
|
return pixel[0];
|
||||||
|
}
|
||||||
|
static inline uint8_t GetGreen(const uint8_t *pixel)
|
||||||
|
{
|
||||||
|
return pixel[1];
|
||||||
|
}
|
||||||
|
static inline uint8_t GetBlue(const uint8_t *pixel)
|
||||||
|
{
|
||||||
|
return pixel[2];
|
||||||
|
}
|
||||||
|
static inline uint8_t GetAlpha(const uint8_t *pixel)
|
||||||
|
{
|
||||||
|
return pixel[3];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct A1RGB5
|
||||||
|
{
|
||||||
|
static constexpr const unsigned bytes_per_pixel = 2;
|
||||||
|
static inline uint8_t GetRed(const uint8_t *pixel)
|
||||||
|
{
|
||||||
|
return uint8_t((255.0f / 31.0f) * float((*reinterpret_cast<const uint16_t *>(pixel) >> 10) & 0x1f));
|
||||||
|
}
|
||||||
|
static inline uint8_t GetGreen(const uint8_t *pixel)
|
||||||
|
{
|
||||||
|
return uint8_t((255.0f / 31.0f) * float((*reinterpret_cast<const uint16_t *>(pixel) >> 5) & 0x1f));
|
||||||
|
}
|
||||||
|
static inline uint8_t GetBlue(const uint8_t *pixel)
|
||||||
|
{
|
||||||
|
return uint8_t((255.0f / 31.0f) * float((*reinterpret_cast<const uint16_t *>(pixel) >> 0) & 0x1f));
|
||||||
|
}
|
||||||
|
static inline uint8_t GetAlpha(const uint8_t *pixel)
|
||||||
|
{
|
||||||
|
return uint8_t((255.0f / 1.0f) * float((*reinterpret_cast<const uint16_t *>(pixel) >> 15) & 0x1));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class SurfaceFormat>
|
||||||
|
static bool WriteSurfaceToBMP(const std::string &file_name, const uint8_t *pixels, int32_t width, int32_t height, bool flip_vertical)
|
||||||
|
{
|
||||||
|
using namespace detail;
|
||||||
|
size_t file_size = sizeof(FileHeader) + width*height*3;
|
||||||
|
std::shared_ptr<uint8_t> file(new uint8_t[file_size], std::default_delete<uint8_t[]>());
|
||||||
|
FileHeader *header = new (file.get()) FileHeader(width, height);
|
||||||
|
uint8_t *bmp = file.get() + sizeof(*header);
|
||||||
|
if (!flip_vertical)
|
||||||
|
{
|
||||||
|
for (int32_t y = height - 1; y >= 0; y--)
|
||||||
|
{
|
||||||
|
const uint8_t *src = &pixels[y * width * SurfaceFormat::bytes_per_pixel];
|
||||||
|
for (int32_t x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
*bmp++ = SurfaceFormat::GetBlue(src);
|
||||||
|
*bmp++ = SurfaceFormat::GetGreen(src);
|
||||||
|
*bmp++ = SurfaceFormat::GetRed(src);
|
||||||
|
src += SurfaceFormat::bytes_per_pixel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int32_t y = 0; y < height; y++)
|
||||||
|
{
|
||||||
|
const uint8_t *src = &pixels[y * width * SurfaceFormat::bytes_per_pixel];
|
||||||
|
for (int32_t x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
*bmp++ = SurfaceFormat::GetBlue(src);
|
||||||
|
*bmp++ = SurfaceFormat::GetGreen(src);
|
||||||
|
*bmp++ = SurfaceFormat::GetRed(src);
|
||||||
|
src += SurfaceFormat::bytes_per_pixel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FILE *fp = fopen(file_name.c_str(), "wb");
|
||||||
|
if (fp)
|
||||||
|
{
|
||||||
|
fwrite(file.get(), sizeof(uint8_t), file_size, fp);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ErrorLog("Unable to open '%s' for writing.", file_name.c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} // Util
|
} // Util
|
||||||
|
|
||||||
#endif // INCLUDED_BMPFILE_HPP
|
#endif // INCLUDED_BMPFILE_HPP
|
Loading…
Reference in a new issue