统一 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:
+10
-2
@@ -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
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)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user