libeuropa/io/yatf: Fix YATF 24-bpp support
This completely redoes the garbage flags stuff I did before. OOPS. This seems a lot closer to the format, and also exports everything Starfighter has properly.
This commit is contained in:
parent
9c6448a817
commit
d0b8d0f3ea
5 changed files with 92 additions and 31 deletions
|
@ -17,6 +17,8 @@ namespace europa {
|
|||
struct TexHeader {
|
||||
char magic[4]; // 'YATF'
|
||||
|
||||
// FIXME: this is completely wrong
|
||||
|
||||
// Flag descriptions:
|
||||
//
|
||||
// 0x1 - unknown? (always pressent)
|
||||
|
|
|
@ -16,23 +16,22 @@
|
|||
namespace europa::structs {
|
||||
|
||||
struct [[gnu::packed]] YatfHeader {
|
||||
constexpr static u32 TextureFlag_Unknown = 0x1;
|
||||
|
||||
/**
|
||||
* Texture does not have a palette
|
||||
*/
|
||||
constexpr static u32 TextureFlag_NoPalette = 0x30000;
|
||||
|
||||
/**
|
||||
* Texture uses alpha.
|
||||
*/
|
||||
constexpr static u32 TextureFlag_UsesAlpha = 0x1000000;
|
||||
enum class TextureFormat : u8 {
|
||||
kTextureFormat8Bpp = 0,
|
||||
kTextureFormatUnknown = 1, // possibly 16bpp?
|
||||
kTextureFormat24Bpp = 2,
|
||||
kTextureFormat32Bpp = 3
|
||||
};
|
||||
|
||||
constexpr static auto ValidMagic = util::FourCC<"YATF", std::endian::big>();
|
||||
|
||||
u32 magic;
|
||||
|
||||
u32 flags;
|
||||
u16 unkThing; // always 0x1
|
||||
|
||||
TextureFormat format;
|
||||
|
||||
u8 unkThing2; // flags?
|
||||
|
||||
// Always zeroed.
|
||||
u32 zero;
|
||||
|
|
|
@ -31,6 +31,40 @@ namespace europa::util {
|
|||
}
|
||||
};
|
||||
|
||||
// Avoid dependency on <pshpack*> header
|
||||
// while still allowing Pixel to be properly packed
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
|
||||
struct [[gnu::packed]] PixelRGB {
|
||||
std::uint8_t r;
|
||||
std::uint8_t g;
|
||||
std::uint8_t b;
|
||||
};
|
||||
|
||||
struct [[gnu::packed]] Pixel {
|
||||
std::uint8_t r;
|
||||
std::uint8_t g;
|
||||
std::uint8_t b;
|
||||
std::uint8_t a;
|
||||
|
||||
static constexpr Pixel FromPixelRGB(const PixelRGB& rgb) {
|
||||
return {
|
||||
.r = rgb.r,
|
||||
.g = rgb.g,
|
||||
.b = rgb.b,
|
||||
.a = 0xff
|
||||
};
|
||||
}
|
||||
|
||||
// FIXME: Implement Pixel::FromRgb565 method for 16bpp
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
/// A RGBA8888 image surface.
|
||||
struct ImageSurface {
|
||||
ImageSurface();
|
||||
|
|
|
@ -55,11 +55,11 @@ namespace europa::util {
|
|||
}
|
||||
|
||||
T& operator[](std::size_t index) {
|
||||
return (*array)[index];
|
||||
return (array.get())[index];
|
||||
}
|
||||
|
||||
const T& operator[](std::size_t index) const {
|
||||
return (*array)[index];
|
||||
return (array.get())[index];
|
||||
}
|
||||
|
||||
T* Data() {
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
// simpler/faster utilities for image buffers.
|
||||
|
||||
#include <europa/io/yatf/Reader.hpp>
|
||||
#include <format>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
#include "../StreamUtils.h"
|
||||
#include "europa/structs/Yatf.hpp"
|
||||
|
@ -31,27 +31,53 @@ namespace europa::io::yatf {
|
|||
return false;
|
||||
}
|
||||
|
||||
surface.Resize({ static_cast<std::uint16_t>(header.width), static_cast<std::uint16_t>(header.height) });
|
||||
auto imageSize = util::Size { static_cast<std::uint16_t>(header.width), static_cast<std::uint16_t>(header.height) };
|
||||
|
||||
if(header.flags & structs::YatfHeader::TextureFlag_NoPalette) {
|
||||
stream.read(reinterpret_cast<char*>(surface.GetBuffer()), (header.width * header.height) * 4);
|
||||
} else {
|
||||
/*
|
||||
pixel::RgbaColor palette[256];
|
||||
std::vector<std::uint8_t> tempBuffer((header.width * header.height));
|
||||
surface.Resize(imageSize);
|
||||
|
||||
using enum structs::YatfHeader::TextureFormat;
|
||||
switch(header.format) {
|
||||
case kTextureFormat8Bpp: {
|
||||
util::Pixel palette[256] {};
|
||||
util::UniqueArray<std::uint8_t> palettizedData(imageSize.Linear());
|
||||
|
||||
// NB: sizeof() does pre-multiplication, so it's 100% ok for us to do this.
|
||||
stream.read(reinterpret_cast<char*>(&palette[0]), sizeof(palette));
|
||||
stream.read(reinterpret_cast<char*>(&tempBuffer[0]), tempBuffer.size());
|
||||
stream.read(reinterpret_cast<char*>(&palettizedData[0]), imageSize.Linear());
|
||||
|
||||
auto* buffer = image.GetBuffer();
|
||||
const auto* data = &tempBuffer[0];
|
||||
auto* pDestBuffer = reinterpret_cast<util::Pixel*>(surface.GetBuffer());
|
||||
|
||||
for(std::size_t i = 0; i < header.width * header.height; ++i)
|
||||
*(buffer++) = palette[data[i]];
|
||||
*/
|
||||
for(std::size_t y = 0; y < imageSize.height; ++y) {
|
||||
for(std::size_t x = 0; x < imageSize.width; ++x) {
|
||||
auto& pp = palettizedData[y * imageSize.width + x];
|
||||
auto& dst = pDestBuffer[y * imageSize.width + x];
|
||||
dst = palette[static_cast<std::size_t>(pp)];
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
throw std::runtime_error("FIXME: Port this path properly :(");
|
||||
case kTextureFormat24Bpp: {
|
||||
util::UniqueArray<util::PixelRGB> rgbPixelData(imageSize.Linear());
|
||||
stream.read(reinterpret_cast<char*>(&rgbPixelData[0]), imageSize.LinearWithStride<util::PixelRGB>());
|
||||
auto* pDestBuffer = reinterpret_cast<util::Pixel*>(surface.GetBuffer());
|
||||
|
||||
for(std::size_t y = 0; y < imageSize.height; ++y) {
|
||||
for(std::size_t x = 0; x < imageSize.width; ++x) {
|
||||
auto& pp = rgbPixelData[y * imageSize.width + x];
|
||||
auto& dst = pDestBuffer[y * imageSize.width + x];
|
||||
dst = util::Pixel::FromPixelRGB(pp);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case kTextureFormat32Bpp:
|
||||
// We can directly read data
|
||||
stream.read(reinterpret_cast<char*>(surface.GetBuffer()), imageSize.LinearWithStride<util::Pixel>());
|
||||
break;
|
||||
|
||||
case kTextureFormatUnknown:
|
||||
default:
|
||||
throw std::runtime_error(std::format("Unknown/unsupported texture format {:02x}!", (std::uint16_t)header.format));
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
Loading…
Reference in a new issue