统一 2D 渲染链路以消除格式分叉和热路径中转

将图片主路径收口为 RGBA5551 输入、RGB565 backbuffer 输出,并删除 USE_RGB565_BACKBUFFER 双路径。sprite/tilemap 主绘制改为直接 RGBA5551 -> RGB565,透明语义固定为 1-bit alpha test。同步收口 SDL/FB present 路径、sprite 资源加载/导出规范,以及相关测试与文档。

Constraint: 运行时图片主路径需统一到 RGBA5551,不能继续保留主要 RGBA8888 分支
Constraint: 透明仅支持 1-bit 语义,不引入 alpha blending
Rejected: 保留 USE_RGB565_BACKBUFFER 宏双路径 | 持续增加维护成本并掩盖真实主链路
Rejected: 主绘制继续走 RGBA5551 -> RGBA8888 -> RGB565 | 热路径存在不必要中转
Confidence: high
Scope-risk: moderate
Directive: 后续图片资源默认按 RGBA5551 接入;不要重新引入通用 RGBA8888 主运行时路径
Directive: 字体 atlas 目前仍属兼容输入;若继续收口,优先改成 1-bit mask 而不是新的图片分支
Tested: render_pipeline_tests;SDL Demo Release 构建;搜索确认无 USE_RGB565_BACKBUFFER 残留
Not-tested: Linux framebuffer 目标实机构建与显示验证
This commit is contained in:
2026-06-08 18:32:04 +08:00
parent 8785368913
commit 5ac61dca0e
19 changed files with 167075 additions and 166993 deletions
+10 -2
View File
@@ -133,13 +133,21 @@ int main(int argc, char* argv[])
Platform::SteadyTimeSource time_source;
RenderData::BitmapFont font;
font.atlas = RenderData::Image(font_atlas_pixels, font_atlas_width, font_atlas_height);
font.atlas = RenderData::Image(
font_atlas_pixels,
font_atlas_width,
font_atlas_height,
RenderData::PixelFormat::RGBA8888);
font.char_w = font_char_w;
font.char_h = font_char_h;
font.columns = font_columns;
font.first_char = font_first_char;
RenderData::Image sprite_img(test_sprite_pixels, test_sprite_width, test_sprite_height, 0x00000000);
RenderData::Image sprite_img(
test_sprite_pixels,
test_sprite_width,
test_sprite_height,
RenderData::PixelFormat::RGBA5551);
RenderData::SpriteRegion sprite_region(&sprite_img, 0, 0, sprite_img.width, sprite_img.height);
const std::array<uint16_t, 8 * 4> tileIds = {
+166658 -166658
View File
File diff suppressed because it is too large Load Diff
@@ -271,12 +271,25 @@ namespace
return atlas_pixels;
}
static void WritePixel(std::ofstream& file, uint32_t pixel)
static uint16_t rgba8888_to_rgba5551(uint32_t c)
{
uint32_t r = (c >> 24) & 0xFFu;
uint32_t g = (c >> 16) & 0xFFu;
uint32_t b = (c >> 8) & 0xFFu;
uint32_t a = c & 0xFFu;
return static_cast<uint16_t>(
((r >> 3) << 11) |
((g >> 3) << 6) |
((b >> 3) << 1) |
(a ? 1u : 0u));
}
static void WritePixel5551(std::ofstream& file, uint16_t pixel)
{
file << "0x"
<< std::uppercase
<< std::hex
<< std::setw(8)
<< std::setw(4)
<< std::setfill('0')
<< pixel
<< std::dec
@@ -305,7 +318,7 @@ namespace
file << "{\n";
file << "\tstatic const int32_t tom_atlas_width = " << AtlasWidth << ";\n";
file << "\tstatic const int32_t tom_atlas_height = " << atlas_height << ";\n\n";
file << "\tstatic const uint32_t tom_atlas_pixels[] = {\n";
file << "\tstatic const uint16_t tom_atlas_pixels[] = {\n";
for (size_t i = 0; i < atlas_pixels.size(); i += 12)
{
@@ -313,7 +326,7 @@ namespace
const size_t end = std::min(i + 12, atlas_pixels.size());
for (size_t j = i; j < end; ++j)
{
WritePixel(file, atlas_pixels[j]);
WritePixel5551(file, rgba8888_to_rgba5551(atlas_pixels[j]));
file << ", ";
}
file << "\n";
@@ -321,7 +334,8 @@ namespace
file << "\t};\n\n";
file << "\tstatic const RenderData::Image image("
<< "tom_atlas_pixels, tom_atlas_width, tom_atlas_height, 0x00000000u);\n\n";
<< "tom_atlas_pixels, tom_atlas_width, tom_atlas_height, 0x0000, "
<< "RenderData::PixelFormat::RGBA5551);\n\n";
for (size_t i = 0; i < regions.size(); ++i)
{
-180
View File
@@ -1,180 +0,0 @@
#include "SpriteAssetLoader.h"
#include <cstdint>
#include <fstream>
#include <limits>
#include <vector>
namespace
{
static const char SpriteMagic[4] = { 'S', 'P', 'R', 'T' };
static const size_t SpriteHeaderSize = 20;
static const uint32_t SpriteVersion = 1;
static const uint32_t SpriteFormatRgba8888 = 1;
static const uint64_t MaxSpritePixels = 8192ull * 8192ull;
static bool ReadExact(std::ifstream& file, char* data, size_t size)
{
file.read(data, static_cast<std::streamsize>(size));
return static_cast<size_t>(file.gcount()) == size;
}
static bool ReadU32LE(const std::vector<uint8_t>& bytes, size_t offset, uint32_t& value)
{
if (offset + 4 > bytes.size())
{
return false;
}
value =
static_cast<uint32_t>(bytes[offset]) |
(static_cast<uint32_t>(bytes[offset + 1]) << 8) |
(static_cast<uint32_t>(bytes[offset + 2]) << 16) |
(static_cast<uint32_t>(bytes[offset + 3]) << 24);
return true;
}
static void WriteU32LE(std::ofstream& file, uint32_t value)
{
const char bytes[4] = {
static_cast<char>(value & 0xFF),
static_cast<char>((value >> 8) & 0xFF),
static_cast<char>((value >> 16) & 0xFF),
static_cast<char>((value >> 24) & 0xFF)
};
file.write(bytes, sizeof(bytes));
}
static bool CheckPixelCount(uint32_t width, uint32_t height, size_t& pixelCount)
{
if (width == 0 || height == 0)
{
return false;
}
const uint64_t total = static_cast<uint64_t>(width) * static_cast<uint64_t>(height);
if (total > MaxSpritePixels ||
total > static_cast<uint64_t>(std::numeric_limits<size_t>::max() / sizeof(uint32_t)))
{
return false;
}
pixelCount = static_cast<size_t>(total);
return true;
}
static bool ReadPixels(std::ifstream& file, std::vector<uint32_t>& pixels)
{
std::vector<uint8_t> bytes(pixels.size() * sizeof(uint32_t), 0);
if (!ReadExact(file, reinterpret_cast<char*>(bytes.data()), bytes.size()))
{
return false;
}
for (size_t i = 0; i < pixels.size(); ++i)
{
uint32_t value = 0;
if (!ReadU32LE(bytes, i * sizeof(uint32_t), value))
{
return false;
}
pixels[i] = value;
}
return true;
}
static void WritePixels(std::ofstream& file, const RenderData::Image& image)
{
for (size_t i = 0; i < image.total_pixels(); ++i)
{
WriteU32LE(file, image.data()[i]);
}
}
}
namespace Asset
{
bool SpriteAssetLoader::Load(const std::string& path, RenderData::Image& image)
{
std::ifstream file(path.c_str(), std::ios::binary);
if (!file.good())
{
return false;
}
std::vector<uint8_t> header(SpriteHeaderSize, 0);
if (!ReadExact(file, reinterpret_cast<char*>(header.data()), header.size()))
{
return false;
}
if (header[0] != SpriteMagic[0] ||
header[1] != SpriteMagic[1] ||
header[2] != SpriteMagic[2] ||
header[3] != SpriteMagic[3])
{
return false;
}
uint32_t version = 0;
uint32_t width = 0;
uint32_t height = 0;
uint32_t format = 0;
if (!ReadU32LE(header, 4, version) ||
!ReadU32LE(header, 8, width) ||
!ReadU32LE(header, 12, height) ||
!ReadU32LE(header, 16, format))
{
return false;
}
size_t pixelCount = 0;
if (version != SpriteVersion ||
format != SpriteFormatRgba8888 ||
!CheckPixelCount(width, height, pixelCount))
{
return false;
}
std::vector<uint32_t> pixels(pixelCount, 0);
if (!ReadPixels(file, pixels))
{
return false;
}
char trailingByte = 0;
file.read(&trailingByte, 1);
if (file.gcount() != 0)
{
return false;
}
image = RenderData::Image(
static_cast<int32_t>(width),
static_cast<int32_t>(height),
pixels);
return image.is_valid();
}
bool SpriteAssetLoader::Save(const std::string& path, const RenderData::Image& image)
{
if (!image.is_valid())
{
return false;
}
std::ofstream file(path.c_str(), std::ios::binary);
if (!file.good())
{
return false;
}
file.write(SpriteMagic, sizeof(SpriteMagic));
WriteU32LE(file, SpriteVersion);
WriteU32LE(file, static_cast<uint32_t>(image.get_width()));
WriteU32LE(file, static_cast<uint32_t>(image.get_height()));
WriteU32LE(file, SpriteFormatRgba8888);
WritePixels(file, image);
return file.good();
}
}
-14
View File
@@ -1,14 +0,0 @@
#pragma once
#include <string>
#include "Image.h"
namespace Asset
{
class SpriteAssetLoader
{
public:
static const char* GetFileExtension() { return ".sprite"; }
static bool Load(const std::string& path, RenderData::Image& image);
static bool Save(const std::string& path, const RenderData::Image& image);
};
}
+40 -18
View File
@@ -8,7 +8,7 @@ namespace
static const char SpriteMagic[4] = { 'S', 'P', 'R', 'T' };
static const size_t SpriteHeaderSize = 20;
static const uint32_t SpriteVersion = 1;
static const uint32_t SpriteFormatRgba8888 = 1;
static const uint32_t SpriteFormatRgba5551 = 2;
static const uint64_t MaxSpritePixels = 8192ull * 8192ull;
static bool ReadExact(std::ifstream& file, char* data, size_t size)
@@ -52,7 +52,7 @@ namespace
const uint64_t total = static_cast<uint64_t>(width) * static_cast<uint64_t>(height);
if (total > MaxSpritePixels ||
total > static_cast<uint64_t>(std::numeric_limits<size_t>::max() / sizeof(uint32_t)))
total > static_cast<uint64_t>(std::numeric_limits<size_t>::max() / sizeof(uint16_t)))
{
return false;
}
@@ -61,9 +61,9 @@ namespace
return true;
}
static bool ReadPixels(std::ifstream& file, std::vector<uint32_t>& pixels)
static bool ReadPixels5551(std::ifstream& file, std::vector<uint16_t>& pixels)
{
std::vector<uint8_t> bytes(pixels.size() * sizeof(uint32_t), 0);
std::vector<uint8_t> bytes(pixels.size() * sizeof(uint16_t), 0);
if (!ReadExact(file, reinterpret_cast<char*>(bytes.data()), bytes.size()))
{
return false;
@@ -71,23 +71,28 @@ namespace
for (size_t i = 0; i < pixels.size(); ++i)
{
uint32_t value = 0;
if (!ReadU32LE(bytes, i * sizeof(uint32_t), value))
{
return false;
}
pixels[i] = value;
pixels[i] = static_cast<uint16_t>(bytes[i * 2]) |
(static_cast<uint16_t>(bytes[i * 2 + 1]) << 8);
}
return true;
}
static void WritePixel5551(std::ofstream& file, uint16_t pixel)
{
const char bytes[2] = {
static_cast<char>(pixel & 0xFF),
static_cast<char>((pixel >> 8) & 0xFF)
};
file.write(bytes, sizeof(bytes));
}
}
namespace Asset
{
bool SpriteAssetLoader::Load(
const std::string& path,
std::vector<uint32_t>& pixels,
std::vector<uint16_t>& pixels,
RenderData::Image& image)
{
std::ifstream file(path.c_str(), std::ios::binary);
@@ -124,14 +129,14 @@ namespace Asset
size_t pixelCount = 0;
if (version != SpriteVersion ||
format != SpriteFormatRgba8888 ||
format != SpriteFormatRgba5551 ||
!CheckPixelCount(width, height, pixelCount))
{
return false;
}
std::vector<uint32_t> loadedPixels(pixelCount, 0);
if (!ReadPixels(file, loadedPixels))
std::vector<uint16_t> loadedPixels(pixelCount, 0);
if (!ReadPixels5551(file, loadedPixels))
{
return false;
}
@@ -144,7 +149,11 @@ namespace Asset
}
pixels.swap(loadedPixels);
image = RenderData::Image(pixels.data(), static_cast<int32_t>(width), static_cast<int32_t>(height));
image = RenderData::Image(
pixels.data(),
static_cast<int32_t>(width),
static_cast<int32_t>(height),
RenderData::PixelFormat::RGBA5551);
return image.pixels != nullptr && image.width > 0 && image.height > 0;
}
@@ -171,10 +180,23 @@ namespace Asset
WriteU32LE(file, SpriteVersion);
WriteU32LE(file, static_cast<uint32_t>(image.width));
WriteU32LE(file, static_cast<uint32_t>(image.height));
WriteU32LE(file, SpriteFormatRgba8888);
for (size_t i = 0; i < pixelCount; ++i)
WriteU32LE(file, SpriteFormatRgba5551);
if (image.format == RenderData::PixelFormat::RGBA5551)
{
WriteU32LE(file, image.pixels[i]);
const uint16_t* pixels16 = static_cast<const uint16_t*>(image.pixels);
for (size_t i = 0; i < pixelCount; ++i)
{
WritePixel5551(file, pixels16[i]);
}
}
else
{
const uint32_t* pixels32 = static_cast<const uint32_t*>(image.pixels);
for (size_t i = 0; i < pixelCount; ++i)
{
WritePixel5551(file, RenderData::rgba8888_to_rgba5551(pixels32[i]));
}
}
return file.good();
+1 -1
View File
@@ -11,7 +11,7 @@ namespace Asset
public:
static const char* GetFileExtension() { return ".sprite"; }
static bool Load(const std::string& path, std::vector<uint32_t>& pixels, RenderData::Image& image);
static bool Load(const std::string& path, std::vector<uint16_t>& pixels, RenderData::Image& image);
static bool Save(const std::string& path, const RenderData::Image& image);
};
}
-5
View File
@@ -7,7 +7,6 @@
namespace Core
{
#ifdef USE_RGB565_BACKBUFFER
typedef uint16_t FramePixel;
inline uint16_t rgba_to_frame_pixel(uint32_t rgba)
{
@@ -16,10 +15,6 @@ namespace Core
const uint32_t b = (rgba >> 8) & 0xFFu;
return static_cast<uint16_t>(((r & 0xF8u) << 8) | ((g & 0xFCu) << 3) | (b >> 3));
}
#else
typedef uint32_t FramePixel;
inline uint32_t rgba_to_frame_pixel(uint32_t rgba) { return rgba; }
#endif
class FrameBuffer
{
+55 -14
View File
@@ -124,25 +124,67 @@ namespace Core
if (dst_x + end_dx > screen_w) end_dx = screen_w - dst_x;
if (dst_y + end_dy > screen_h) end_dy = screen_h - dst_y;
const uint32_t* src = img.pixels;
if (img.format == RenderData::PixelFormat::RGBA5551)
{
Core::FramePixel* dst = static_cast<Core::FramePixel*>(frameBuffer->get_buffer());
const int32_t fb_w = frameBuffer->get_width();
const uint16_t* src = static_cast<const uint16_t*>(img.pixels);
if (scale == 1)
{
for (int32_t sy = start_dy; sy < end_dy; ++sy)
{
const int32_t read_y = flip_v ? (src_y + src_h - 1 - sy) : (src_y + sy);
const int32_t dst_y_abs = dst_y + sy;
Core::FramePixel* dst_row = dst + dst_y_abs * fb_w;
for (int32_t sx = start_dx; sx < end_dx; ++sx)
{
const int32_t read_x = flip_h ? (src_x + src_w - 1 - sx) : (src_x + sx);
const uint16_t pixel = src[read_y * img_w + read_x];
if (!RenderData::rgba5551_is_opaque(pixel)) continue;
dst_row[dst_x + sx] = RenderData::rgba5551_to_rgb565(pixel);
}
}
return;
}
for (int32_t dy_abs = start_dy; dy_abs < end_dy; ++dy_abs)
{
const int32_t sy = dy_abs / scale;
const int32_t read_y = flip_v ? (src_y + src_h - 1 - sy) : (src_y + sy);
const int32_t dst_y_abs = dst_y + dy_abs;
Core::FramePixel* dst_row = dst + dst_y_abs * fb_w;
for (int32_t dx_abs = start_dx; dx_abs < end_dx; ++dx_abs)
{
const int32_t sx = dx_abs / scale;
const int32_t read_x = flip_h ? (src_x + src_w - 1 - sx) : (src_x + sx);
const uint16_t pixel = src[read_y * img_w + read_x];
if (!RenderData::rgba5551_is_opaque(pixel)) continue;
dst_row[dst_x + dx_abs] = RenderData::rgba5551_to_rgb565(pixel);
}
}
return;
}
const bool has_key = img.has_color_key;
const uint32_t key = img.color_key;
const uint32_t key = RenderData::rgba5551_to_rgba8888(img.color_key);
const uint32_t* src32 = static_cast<const uint32_t*>(img.pixels);
if (scale == 1)
{
for (int32_t sy = start_dy; sy < end_dy; ++sy)
{
const int32_t read_y = flip_v ? (src_y + src_h - 1 - sy) : (src_y + sy);
const uint32_t* row = src + read_y * img_w;
const int32_t dst_y_abs = dst_y + sy;
for (int32_t sx = start_dx; sx < end_dx; ++sx)
{
const int32_t read_x = flip_h ? (src_x + src_w - 1 - sx) : (src_x + sx);
const uint32_t pixel = row[read_x];
const uint32_t pixel = src32[read_y * img_w + read_x];
if ((pixel & 0xFFu) == 0u) continue;
if (has_key && pixel == key) continue;
frameBuffer->set_pixel_unsafe(dst_x + sx, dst_y_abs, pixel);
}
}
@@ -153,17 +195,15 @@ namespace Core
{
const int32_t sy = dy_abs / scale;
const int32_t read_y = flip_v ? (src_y + src_h - 1 - sy) : (src_y + sy);
const uint32_t* row = src + read_y * img_w;
const int32_t dst_y_abs = dst_y + dy_abs;
for (int32_t dx_abs = start_dx; dx_abs < end_dx; ++dx_abs)
{
const int32_t sx = dx_abs / scale;
const int32_t read_x = flip_h ? (src_x + src_w - 1 - sx) : (src_x + sx);
const uint32_t pixel = row[read_x];
const uint32_t pixel = src32[read_y * img_w + read_x];
if ((pixel & 0xFFu) == 0u) continue;
if (has_key && pixel == key) continue;
frameBuffer->set_pixel_unsafe(dst_x + dx_abs, dst_y_abs, pixel);
}
}
@@ -273,13 +313,14 @@ namespace Core
if (x0 >= x1 || y0 >= y1) return;
uint32_t* buf = static_cast<uint32_t*>(frameBuffer->get_buffer());
const Core::FramePixel pixel = Core::rgba_to_frame_pixel(rgba);
Core::FramePixel* buf = static_cast<Core::FramePixel*>(frameBuffer->get_buffer());
for (int32_t row = y0; row < y1; ++row)
{
uint32_t* dst = buf + row * fb_w + x0;
Core::FramePixel* dst = buf + row * fb_w + x0;
for (int32_t i = 0; i < x1 - x0; ++i)
{
dst[i] = rgba;
dst[i] = pixel;
}
}
}
@@ -293,7 +334,7 @@ namespace Core
const int32_t cw = font.char_w;
const int32_t ch = font.char_h;
const int32_t atlas_w = font.atlas.width;
const uint32_t* src = font.atlas.pixels;
const uint32_t* src = static_cast<const uint32_t*>(font.atlas.pixels);
const int32_t screen_w = frameBuffer->get_width();
const int32_t screen_h = frameBuffer->get_height();
+22 -27
View File
@@ -15,18 +15,18 @@ namespace Platform
{
namespace
{
inline uint16_t rgba_to_rgb565(uint32_t rgba)
{
const uint32_t r = (rgba >> 24) & 0xFFu;
const uint32_t g = (rgba >> 16) & 0xFFu;
const uint32_t b = (rgba >> 8) & 0xFFu;
return static_cast<uint16_t>(((r & 0xF8u) << 8) | ((g & 0xFCu) << 3) | (b >> 3));
}
inline uint32_t rgba_to_argb8888(uint32_t rgba)
{
return ((rgba >> 8) & 0x00FFFFFFu) | ((rgba & 0xFFu) << 24);
}
inline uint32_t rgb565_to_rgba8888(uint16_t c)
{
uint32_t r = (c >> 11) & 0x1Fu;
uint32_t g = (c >> 5) & 0x3Fu;
uint32_t b = c & 0x1Fu;
return (r << 27) | (r << 24) | (g << 18) | (g << 16) | (b << 11) | (b << 8) | 0xFFu;
}
}
bool FBDisplay::init(int w, int h)
@@ -96,7 +96,7 @@ namespace Platform
if (!fb_mem || !framebuffer)
return;
const uint32_t* src = static_cast<const uint32_t*>(framebuffer->get_buffer());
const uint16_t* src = static_cast<const uint16_t*>(framebuffer->get_buffer());
const int src_width = framebuffer->get_width();
const int dst_width = std::min(src_width, static_cast<int>(vinfo.xres));
const int dst_height = std::min(framebuffer->get_height(), static_cast<int>(vinfo.yres));
@@ -119,8 +119,6 @@ namespace Platform
if (is_rgb565)
{
#ifdef USE_RGB565_BACKBUFFER
// backbuffer 内部已是 RGB565,直接行拷贝提交
const uint8_t* src_bytes = static_cast<const uint8_t*>(framebuffer->get_buffer());
if (static_cast<int>(finfo.line_length) == dst_width * 2)
{
@@ -135,17 +133,6 @@ namespace Platform
dst_width * 2);
}
}
#else
for (int y = 0; y < dst_height; ++y)
{
const uint32_t* src_row = src + y * src_width;
uint16_t* dst_row = reinterpret_cast<uint16_t*>(fb_mem + y * finfo.line_length);
for (int x = 0; x < dst_width; ++x)
{
dst_row[x] = rgba_to_rgb565(src_row[x]);
}
}
#endif
return;
}
@@ -153,19 +140,27 @@ namespace Platform
{
for (int y = 0; y < dst_height; ++y)
{
const uint32_t* src_row = src + y * src_width;
const uint16_t* src_row = src + y * src_width;
uint32_t* dst_row = reinterpret_cast<uint32_t*>(fb_mem + y * finfo.line_length);
for (int x = 0; x < dst_width; ++x)
{
dst_row[x] = rgba_to_argb8888(src_row[x]);
dst_row[x] = rgba_to_argb8888(rgb565_to_rgba8888(src_row[x]));
}
}
return;
}
if (is_rgba8888 && dst_width == src_width && static_cast<int>(finfo.line_length) == dst_width * 4)
if (is_rgba8888)
{
std::memcpy(fb_mem, src, static_cast<size_t>(dst_height) * static_cast<size_t>(dst_width) * sizeof(uint32_t));
for (int y = 0; y < dst_height; ++y)
{
const uint16_t* src_row = src + y * src_width;
uint32_t* dst_row = reinterpret_cast<uint32_t*>(fb_mem + y * finfo.line_length);
for (int x = 0; x < dst_width; ++x)
{
dst_row[x] = rgb565_to_rgba8888(src_row[x]);
}
}
return;
}
@@ -173,7 +168,7 @@ namespace Platform
{
for (int x = 0; x < dst_width; ++x)
{
uint32_t pixel = convert_pixel(src[y * src_width + x]);
uint32_t pixel = convert_pixel(rgb565_to_rgba8888(src[y * src_width + x]));
uint8_t* dst = fb_mem + y * finfo.line_length + x * bytes_per_pixel;
if (vinfo.bits_per_pixel == 32)
{
-9
View File
@@ -42,13 +42,8 @@ namespace Platform
return false;
}
#ifdef USE_RGB565_BACKBUFFER
const Uint32 sdl_pixel_format = SDL_PIXELFORMAT_RGB565;
const int pixel_bytes = 2;
#else
const Uint32 sdl_pixel_format = SDL_PIXELFORMAT_RGBA8888;
const int pixel_bytes = 4;
#endif
texture = SDL_CreateTexture(
renderer,
sdl_pixel_format,
@@ -67,11 +62,7 @@ namespace Platform
void SDLDisplay::present(const Core::FrameBuffer* framebuffer)
{
#ifdef USE_RGB565_BACKBUFFER
const int pixel_bytes = 2;
#else
const int pixel_bytes = 4;
#endif
SDL_UpdateTexture(texture, nullptr, framebuffer->get_buffer(), width * pixel_bytes);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, nullptr, nullptr);
+69 -8
View File
@@ -4,25 +4,86 @@
namespace RenderData
{
enum class PixelFormat
{
RGBA8888,
RGBA5551
};
inline uint16_t rgba5551_to_rgb565(uint16_t c)
{
const uint16_t r = static_cast<uint16_t>((c >> 11) & 0x1Fu);
const uint16_t g = static_cast<uint16_t>((c >> 6) & 0x1Fu);
const uint16_t b = static_cast<uint16_t>((c >> 1) & 0x1Fu);
const uint16_t g6 = static_cast<uint16_t>((g << 1) | (g >> 4));
return static_cast<uint16_t>((r << 11) | (g6 << 5) | b);
}
inline bool rgba5551_is_opaque(uint16_t c)
{
return (c & 0x1u) != 0;
}
inline uint32_t rgba5551_to_rgba8888(uint16_t c)
{
uint32_t r = (c >> 11) & 0x1Fu;
uint32_t g = (c >> 6) & 0x1Fu;
uint32_t b = (c >> 1) & 0x1Fu;
uint32_t a = c & 0x1u;
return (r << 27) | (r << 24) |
(g << 19) | (g << 16) |
(b << 11) | (b << 8) |
(a ? 0xFFu : 0x00u);
}
inline uint16_t rgba8888_to_rgba5551(uint32_t c)
{
uint32_t r = (c >> 24) & 0xFFu;
uint32_t g = (c >> 16) & 0xFFu;
uint32_t b = (c >> 8) & 0xFFu;
uint32_t a = c & 0xFFu;
return static_cast<uint16_t>(
((r >> 3) << 11) |
((g >> 3) << 6) |
((b >> 3) << 1) |
(a ? 1u : 0u));
}
struct Image
{
const uint32_t* pixels;
const void* pixels;
int32_t width;
int32_t height;
uint32_t color_key;
uint16_t color_key;
bool has_color_key;
PixelFormat format;
Image() : pixels(nullptr), width(0), height(0), color_key(0), has_color_key(false) {}
Image()
: pixels(nullptr), width(0), height(0),
color_key(0), has_color_key(false),
format(PixelFormat::RGBA8888) {}
Image(const uint32_t* pixels, int32_t width, int32_t height)
: pixels(pixels), width(width), height(height), color_key(0), has_color_key(false) {}
Image(const void* pixels, int32_t width, int32_t height,
PixelFormat fmt = PixelFormat::RGBA8888)
: pixels(pixels), width(width), height(height),
color_key(0), has_color_key(false),
format(fmt) {}
Image(const uint32_t* pixels, int32_t width, int32_t height, uint32_t color_key)
: pixels(pixels), width(width), height(height), color_key(color_key), has_color_key(true) {}
Image(const void* pixels, int32_t width, int32_t height,
uint16_t color_key,
PixelFormat fmt = PixelFormat::RGBA8888)
: pixels(pixels), width(width), height(height),
color_key(color_key), has_color_key(true),
format(fmt) {}
uint32_t get_pixel(int32_t x, int32_t y) const
{
return pixels[y * width + x];
if (format == PixelFormat::RGBA5551)
{
return rgba5551_to_rgba8888(
static_cast<const uint16_t*>(pixels)[y * width + x]);
}
return static_cast<const uint32_t*>(pixels)[y * width + x];
}
};
}