Compare commits
2 Commits
8d8c9ed9d1
...
046c21d47a
| Author | SHA1 | Date |
|---|---|---|
|
|
046c21d47a | |
|
|
b248bd5cff |
|
|
@ -9,6 +9,7 @@ if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE)
|
|||
endif()
|
||||
|
||||
option(USE_FRAMEBUFFER "Use Linux framebuffer instead of SDL2" OFF)
|
||||
option(USE_RGB565_BACKBUFFER "Use RGB565 internal backbuffer to eliminate present conversion on RGB565 fb0" OFF)
|
||||
|
||||
set(CORE_SOURCES
|
||||
src/Core/Asset/ObjLoader.cpp
|
||||
|
|
@ -58,6 +59,13 @@ target_include_directories(imx6u_core PUBLIC ${CORE_INCLUDE_DIRS})
|
|||
|
||||
if(USE_FRAMEBUFFER)
|
||||
target_compile_definitions(imx6u_core PUBLIC USE_FRAMEBUFFER)
|
||||
endif()
|
||||
|
||||
if(USE_RGB565_BACKBUFFER)
|
||||
target_compile_definitions(imx6u_core PUBLIC USE_RGB565_BACKBUFFER)
|
||||
endif()
|
||||
|
||||
if(USE_FRAMEBUFFER)
|
||||
else()
|
||||
if(WIN32)
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
|
|
@ -119,6 +127,15 @@ function(imx6u_configure_app_target target_name)
|
|||
"${SDL2_DLL}"
|
||||
"$<TARGET_FILE_DIR:${target_name}>"
|
||||
)
|
||||
elseif(SDL2_image_FOUND)
|
||||
add_executable(SpriteAssetTool ${SPRITE_ASSET_TOOL_SOURCES})
|
||||
target_include_directories(SpriteAssetTool PRIVATE
|
||||
src/Core/Asset
|
||||
src/Core/RenderData
|
||||
)
|
||||
target_link_libraries(SpriteAssetTool PRIVATE SDL2::SDL2 SDL2_image::SDL2_image)
|
||||
else()
|
||||
message(STATUS "SpriteAssetTool disabled: SDL2_image was not found")
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
|
|
|
|||
|
|
@ -1,34 +1,51 @@
|
|||
#include "DepthBuffer.h"
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
namespace Core
|
||||
{
|
||||
void DepthBuffer::clear(const float depth)
|
||||
DepthBuffer::DepthBuffer(int32_t w, int32_t h)
|
||||
: width(w), height(h), buffer(static_cast<size_t>(w) * h, 0xFFFFu)
|
||||
{
|
||||
std::fill(buffer.begin(), buffer.end(), depth);
|
||||
}
|
||||
|
||||
float DepthBuffer::get_depth(const int32_t x, const int32_t y) const
|
||||
void DepthBuffer::clear(uint16_t depth)
|
||||
{
|
||||
// 对 0x0000 或 0xFFFF 走 memset 快速路径
|
||||
if (depth == 0xFFFFu || depth == 0x0000u)
|
||||
{
|
||||
std::memset(buffer.data(), depth == 0xFFFFu ? 0xFF : 0x00, buffer.size() * sizeof(uint16_t));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::fill(buffer.begin(), buffer.end(), depth);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t DepthBuffer::get_depth_unsafe(int32_t x, int32_t y) const
|
||||
{
|
||||
return buffer[static_cast<size_t>(y) * width + x];
|
||||
}
|
||||
|
||||
void DepthBuffer::set_depth_unsafe(int32_t x, int32_t y, uint16_t depth)
|
||||
{
|
||||
buffer[static_cast<size_t>(y) * width + x] = depth;
|
||||
}
|
||||
|
||||
uint16_t DepthBuffer::get_depth(int32_t x, int32_t y) const
|
||||
{
|
||||
if (x < 0 || x >= width || y < 0 || y >= height)
|
||||
{
|
||||
return INFINITY;
|
||||
return 0xFFFFu;
|
||||
}
|
||||
// Row-major layout with y = 0 on the first row, matching a top-left screen origin.
|
||||
size_t index = static_cast<size_t>(y) * width + x;
|
||||
return buffer.at(index);
|
||||
return get_depth_unsafe(x, y);
|
||||
}
|
||||
|
||||
void DepthBuffer::set_depth(const int32_t x, const int32_t y, const float depth)
|
||||
void DepthBuffer::set_depth(int32_t x, int32_t y, uint16_t depth)
|
||||
{
|
||||
if (x < 0 || x >= width || y < 0 || y >= height)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Row-major layout with y = 0 on the first row, matching a top-left screen origin.
|
||||
size_t index = static_cast<size_t>(y) * width + x;
|
||||
buffer.at(index) = depth;
|
||||
set_depth_unsafe(x, y, depth);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include "Vector2.h"
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
|
||||
namespace Core
|
||||
|
|
@ -12,7 +11,7 @@ namespace Core
|
|||
private:
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
std::vector<float> buffer;
|
||||
std::vector<uint16_t> buffer;
|
||||
|
||||
public:
|
||||
int32_t get_width() const { return width; }
|
||||
|
|
@ -23,16 +22,20 @@ namespace Core
|
|||
|
||||
void* get_buffer() const { return (void*)buffer.data(); }
|
||||
|
||||
DepthBuffer(int32_t width, int32_t height) :width(width), height(height), buffer(std::vector<float>(width* height, INFINITY)) {}
|
||||
DepthBuffer(int32_t width, int32_t height);
|
||||
|
||||
void clear(const float depth = INFINITY);
|
||||
// 默认清为 0xFFFF(最远),语义保持"越小越近"
|
||||
void clear(uint16_t depth = 0xFFFFu);
|
||||
|
||||
float get_depth(const Math::Vector2Int position) const { return get_depth(position.x, position.y); }
|
||||
// 热路径快路径:无边界检查,调用方需确保坐标合法
|
||||
uint16_t get_depth_unsafe(int32_t x, int32_t y) const;
|
||||
void set_depth_unsafe(int32_t x, int32_t y, uint16_t depth);
|
||||
|
||||
float get_depth(const int32_t x, const int32_t y) const;
|
||||
// 安全版本:带边界检查,越界返回最远深度
|
||||
uint16_t get_depth(const Math::Vector2Int position) const { return get_depth(position.x, position.y); }
|
||||
uint16_t get_depth(int32_t x, int32_t y) const;
|
||||
|
||||
void set_depth(const Math::Vector2Int position, const float depth) { set_depth(position.x, position.y, depth); }
|
||||
|
||||
void set_depth(const int32_t x, const int32_t y, const float depth);
|
||||
void set_depth(const Math::Vector2Int position, uint16_t depth) { set_depth(position.x, position.y, depth); }
|
||||
void set_depth(int32_t x, int32_t y, uint16_t depth);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,18 +6,16 @@ namespace Core
|
|||
{
|
||||
void FrameBuffer::clear(const uint32_t color)
|
||||
{
|
||||
std::fill(buffer.begin(), buffer.end(), color);
|
||||
std::fill(buffer.begin(), buffer.end(), rgba_to_frame_pixel(color));
|
||||
}
|
||||
|
||||
|
||||
void FrameBuffer::set_pixel(const int32_t x, const int32_t y, const uint32_t color)
|
||||
{
|
||||
if (x < 0 || x >= width || y < 0 || y >= height)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Row-major layout with y = 0 on the first row, matching a top-left screen origin.
|
||||
size_t index = static_cast<size_t>(y) * width + x;
|
||||
buffer[index] = color;
|
||||
}
|
||||
}
|
||||
void FrameBuffer::set_pixel(const int32_t x, const int32_t y, const uint32_t color)
|
||||
{
|
||||
if (x < 0 || x >= width || y < 0 || y >= height)
|
||||
{
|
||||
return;
|
||||
}
|
||||
set_pixel_unsafe(x, y, color);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,12 +7,26 @@
|
|||
|
||||
namespace Core
|
||||
{
|
||||
#ifdef USE_RGB565_BACKBUFFER
|
||||
typedef uint16_t FramePixel;
|
||||
inline uint16_t rgba_to_frame_pixel(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));
|
||||
}
|
||||
#else
|
||||
typedef uint32_t FramePixel;
|
||||
inline uint32_t rgba_to_frame_pixel(uint32_t rgba) { return rgba; }
|
||||
#endif
|
||||
|
||||
class FrameBuffer
|
||||
{
|
||||
private:
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
std::vector<uint32_t> buffer;
|
||||
std::vector<FramePixel> buffer;
|
||||
|
||||
public:
|
||||
int32_t get_width() const { return width; }
|
||||
|
|
@ -23,14 +37,15 @@ namespace Core
|
|||
|
||||
void* get_buffer() const { return (void*)buffer.data(); }
|
||||
|
||||
FrameBuffer(int32_t width, int32_t height) :width(width), height(height), buffer(std::vector<uint32_t>(width * height, 0)) {}
|
||||
FrameBuffer(int32_t width, int32_t height)
|
||||
: width(width), height(height), buffer(static_cast<size_t>(width) * height, 0) {}
|
||||
|
||||
void clear(const RenderData::Color& color)
|
||||
{
|
||||
clear(color.to_rgba());
|
||||
}
|
||||
|
||||
void clear(const uint32_t color);
|
||||
void clear(uint32_t color);
|
||||
|
||||
void set_pixel(const int32_t x, const int32_t y, const RenderData::Color& color)
|
||||
{
|
||||
|
|
@ -43,5 +58,11 @@ namespace Core
|
|||
}
|
||||
|
||||
void set_pixel(const int32_t x, const int32_t y, const uint32_t color);
|
||||
|
||||
// 热路径快路径:无边界检查,调用方需确保坐标在 [0, width) x [0, height) 内
|
||||
void set_pixel_unsafe(int32_t x, int32_t y, uint32_t color)
|
||||
{
|
||||
buffer[static_cast<size_t>(y) * width + x] = rgba_to_frame_pixel(color);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ namespace Core
|
|||
|
||||
if (has_key && pixel == key) continue;
|
||||
|
||||
frameBuffer->set_pixel(dst_x + sx, dst_y_abs, pixel);
|
||||
frameBuffer->set_pixel_unsafe(dst_x + sx, dst_y_abs, pixel);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
|
@ -164,7 +164,7 @@ namespace Core
|
|||
|
||||
if (has_key && pixel == key) continue;
|
||||
|
||||
frameBuffer->set_pixel(dst_x + dx_abs, dst_y_abs, pixel);
|
||||
frameBuffer->set_pixel_unsafe(dst_x + dx_abs, dst_y_abs, pixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -263,11 +263,23 @@ namespace Core
|
|||
void DrawContext::fill_rect(int32_t x, int32_t y, int32_t w, int32_t h, const RenderData::Color& color)
|
||||
{
|
||||
const uint32_t rgba = color.to_rgba();
|
||||
for (int32_t row = y; row < y + h; ++row)
|
||||
const int32_t fb_w = frameBuffer->get_width();
|
||||
const int32_t fb_h = frameBuffer->get_height();
|
||||
|
||||
int32_t x0 = std::max(0, x);
|
||||
int32_t y0 = std::max(0, y);
|
||||
int32_t x1 = std::min(fb_w, x + w);
|
||||
int32_t y1 = std::min(fb_h, y + h);
|
||||
|
||||
if (x0 >= x1 || y0 >= y1) return;
|
||||
|
||||
uint32_t* buf = static_cast<uint32_t*>(frameBuffer->get_buffer());
|
||||
for (int32_t row = y0; row < y1; ++row)
|
||||
{
|
||||
for (int32_t col = x; col < x + w; ++col)
|
||||
uint32_t* dst = buf + row * fb_w + x0;
|
||||
for (int32_t i = 0; i < x1 - x0; ++i)
|
||||
{
|
||||
frameBuffer->set_pixel(col, row, rgba);
|
||||
dst[i] = rgba;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -282,6 +294,8 @@ namespace Core
|
|||
const int32_t ch = font.char_h;
|
||||
const int32_t atlas_w = font.atlas.width;
|
||||
const uint32_t* src = font.atlas.pixels;
|
||||
const int32_t screen_w = frameBuffer->get_width();
|
||||
const int32_t screen_h = frameBuffer->get_height();
|
||||
|
||||
int32_t cursor_x = x;
|
||||
for (const char* p = text; *p; ++p)
|
||||
|
|
@ -294,15 +308,29 @@ namespace Core
|
|||
const int32_t src_x = col * cw;
|
||||
const int32_t src_y = row * ch;
|
||||
|
||||
for (int32_t sy = 0; sy < ch; ++sy)
|
||||
// 整字符在屏幕外则跳过
|
||||
if (cursor_x + cw <= 0 || cursor_x >= screen_w || y + ch <= 0 || y >= screen_h)
|
||||
{
|
||||
cursor_x += cw;
|
||||
continue;
|
||||
}
|
||||
|
||||
int32_t sy_start = 0, sy_end = ch;
|
||||
int32_t sx_start = 0, sx_end = cw;
|
||||
if (y < 0) sy_start = -y;
|
||||
if (y + ch > screen_h) sy_end = screen_h - y;
|
||||
if (cursor_x < 0) sx_start = -cursor_x;
|
||||
if (cursor_x + cw > screen_w) sx_end = screen_w - cursor_x;
|
||||
|
||||
for (int32_t sy = sy_start; sy < sy_end; ++sy)
|
||||
{
|
||||
const uint32_t* atlas_row = src + (src_y + sy) * atlas_w;
|
||||
const int32_t dst_y_abs = y + sy;
|
||||
for (int32_t sx = 0; sx < cw; ++sx)
|
||||
for (int32_t sx = sx_start; sx < sx_end; ++sx)
|
||||
{
|
||||
const uint32_t pixel = atlas_row[src_x + sx];
|
||||
if ((pixel & 0xFF) == 0) continue;
|
||||
frameBuffer->set_pixel(cursor_x + sx, dst_y_abs, rgba);
|
||||
frameBuffer->set_pixel_unsafe(cursor_x + sx, dst_y_abs, rgba);
|
||||
}
|
||||
}
|
||||
cursor_x += cw;
|
||||
|
|
|
|||
|
|
@ -119,6 +119,23 @@ 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)
|
||||
{
|
||||
std::memcpy(fb_mem, src_bytes, static_cast<size_t>(dst_height) * dst_width * 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = 0; y < dst_height; ++y)
|
||||
{
|
||||
std::memcpy(fb_mem + y * finfo.line_length,
|
||||
src_bytes + y * src_width * 2,
|
||||
dst_width * 2);
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (int y = 0; y < dst_height; ++y)
|
||||
{
|
||||
const uint32_t* src_row = src + y * src_width;
|
||||
|
|
@ -128,6 +145,7 @@ namespace Platform
|
|||
dst_row[x] = rgba_to_rgb565(src_row[x]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,9 +42,16 @@ 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_PIXELFORMAT_RGBA8888,
|
||||
sdl_pixel_format,
|
||||
SDL_TEXTUREACCESS_STREAMING,
|
||||
width,
|
||||
height
|
||||
|
|
@ -60,7 +67,12 @@ namespace Platform
|
|||
|
||||
void SDLDisplay::present(const Core::FrameBuffer* framebuffer)
|
||||
{
|
||||
SDL_UpdateTexture(texture, nullptr, framebuffer->get_buffer(), width * sizeof(uint32_t));
|
||||
#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);
|
||||
SDL_RenderPresent(renderer);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,19 @@
|
|||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
|
||||
namespace
|
||||
{
|
||||
// 临时边界:将 float 深度映射到 uint16_t 定点深度。
|
||||
// 约定:0.0 ~ 1.0 映射到 0 ~ 65535,越小越近。
|
||||
// TODO: 等 TriangleRasterizer 重构为定点后删除此转换。
|
||||
inline uint16_t temp_float_depth_to_uint16(float z)
|
||||
{
|
||||
if (z <= 0.0f) return 0u;
|
||||
if (z >= 1.0f) return 0xFFFFu;
|
||||
return static_cast<uint16_t>(z * 65535.0f + 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Rasterizer
|
||||
{
|
||||
void TriangleRasterizer::DrawTriangle2D(const RenderData::Triangle& triangle, const RenderData::Color color)
|
||||
|
|
@ -42,13 +55,14 @@ namespace Rasterizer
|
|||
|
||||
if (depthBuffer)
|
||||
{
|
||||
const uint16_t depth_u16 = temp_float_depth_to_uint16(depth);
|
||||
// 深度越小离相机越近
|
||||
if (depthBuffer->get_depth(x, y) < depth)
|
||||
if (depthBuffer->get_depth(x, y) < depth_u16)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
depthBuffer->set_depth(x, y, depth);
|
||||
depthBuffer->set_depth(x, y, depth_u16);
|
||||
frameBuffer->set_pixel(x, y, color.to_rgba());
|
||||
}
|
||||
else
|
||||
|
|
|
|||
Loading…
Reference in New Issue