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 {
|
struct TexHeader {
|
||||||
char magic[4]; // 'YATF'
|
char magic[4]; // 'YATF'
|
||||||
|
|
||||||
|
// FIXME: this is completely wrong
|
||||||
|
|
||||||
// Flag descriptions:
|
// Flag descriptions:
|
||||||
//
|
//
|
||||||
// 0x1 - unknown? (always pressent)
|
// 0x1 - unknown? (always pressent)
|
||||||
|
|
|
@ -16,23 +16,22 @@
|
||||||
namespace europa::structs {
|
namespace europa::structs {
|
||||||
|
|
||||||
struct [[gnu::packed]] YatfHeader {
|
struct [[gnu::packed]] YatfHeader {
|
||||||
constexpr static u32 TextureFlag_Unknown = 0x1;
|
enum class TextureFormat : u8 {
|
||||||
|
kTextureFormat8Bpp = 0,
|
||||||
/**
|
kTextureFormatUnknown = 1, // possibly 16bpp?
|
||||||
* Texture does not have a palette
|
kTextureFormat24Bpp = 2,
|
||||||
*/
|
kTextureFormat32Bpp = 3
|
||||||
constexpr static u32 TextureFlag_NoPalette = 0x30000;
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Texture uses alpha.
|
|
||||||
*/
|
|
||||||
constexpr static u32 TextureFlag_UsesAlpha = 0x1000000;
|
|
||||||
|
|
||||||
constexpr static auto ValidMagic = util::FourCC<"YATF", std::endian::big>();
|
constexpr static auto ValidMagic = util::FourCC<"YATF", std::endian::big>();
|
||||||
|
|
||||||
u32 magic;
|
u32 magic;
|
||||||
|
|
||||||
u32 flags;
|
u16 unkThing; // always 0x1
|
||||||
|
|
||||||
|
TextureFormat format;
|
||||||
|
|
||||||
|
u8 unkThing2; // flags?
|
||||||
|
|
||||||
// Always zeroed.
|
// Always zeroed.
|
||||||
u32 zero;
|
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.
|
/// A RGBA8888 image surface.
|
||||||
struct ImageSurface {
|
struct ImageSurface {
|
||||||
ImageSurface();
|
ImageSurface();
|
||||||
|
|
|
@ -55,11 +55,11 @@ namespace europa::util {
|
||||||
}
|
}
|
||||||
|
|
||||||
T& operator[](std::size_t index) {
|
T& operator[](std::size_t index) {
|
||||||
return (*array)[index];
|
return (array.get())[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
const T& operator[](std::size_t index) const {
|
const T& operator[](std::size_t index) const {
|
||||||
return (*array)[index];
|
return (array.get())[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
T* Data() {
|
T* Data() {
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
// simpler/faster utilities for image buffers.
|
// simpler/faster utilities for image buffers.
|
||||||
|
|
||||||
#include <europa/io/yatf/Reader.hpp>
|
#include <europa/io/yatf/Reader.hpp>
|
||||||
|
#include <format>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "../StreamUtils.h"
|
#include "../StreamUtils.h"
|
||||||
#include "europa/structs/Yatf.hpp"
|
#include "europa/structs/Yatf.hpp"
|
||||||
|
@ -31,27 +31,53 @@ namespace europa::io::yatf {
|
||||||
return false;
|
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) {
|
surface.Resize(imageSize);
|
||||||
stream.read(reinterpret_cast<char*>(surface.GetBuffer()), (header.width * header.height) * 4);
|
|
||||||
} else {
|
using enum structs::YatfHeader::TextureFormat;
|
||||||
/*
|
switch(header.format) {
|
||||||
pixel::RgbaColor palette[256];
|
case kTextureFormat8Bpp: {
|
||||||
std::vector<std::uint8_t> tempBuffer((header.width * header.height));
|
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*>(&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();
|
auto* pDestBuffer = reinterpret_cast<util::Pixel*>(surface.GetBuffer());
|
||||||
const auto* data = &tempBuffer[0];
|
|
||||||
|
|
||||||
for(std::size_t i = 0; i < header.width * header.height; ++i)
|
for(std::size_t y = 0; y < imageSize.height; ++y) {
|
||||||
*(buffer++) = palette[data[i]];
|
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;
|
return true;
|
||||||
|
|
Loading…
Reference in a new issue