子像素绘制

This commit is contained in:
daiqingshuang 2025-04-02 12:50:17 +08:00
parent 4d0dbbe6c5
commit 9be39399d9
5 changed files with 72 additions and 12 deletions

View File

@ -10,6 +10,8 @@
#include <cmath>
#include <limits>
#include "sokol_gfx.h"
/**
* @brief
* sg_pixel_format格式的辅助函数

View File

@ -4,6 +4,8 @@
#include "freetype_interface.h"
#include "pixel.h"
#include "freetype/ftcolor.h"
#include "freetype/ftglyph.h"
#include "interface/image_interface.h"
@ -64,12 +66,15 @@ std::shared_ptr<image_heap_t> freetype_interface::get_glyph_image(int32_t in_gly
if (face_->glyph->format != FT_GLYPH_FORMAT_BITMAP) {
return nullptr;
}
// FT_Render_Glyph(face_->glyph, FT_RENDER_MODE_LCD);
auto& bitmap = face_->glyph->bitmap;
// 创建位图
// 这里使用了一个自定义的删除器来释放位图数据
std::shared_ptr<image_heap_t> image(new image_heap_t(), freetype_bitmap_deleter);
image->width = face_->glyph->bitmap.width;
image->height = face_->glyph->bitmap.rows;
image->width = bitmap.width;
image->height = bitmap.rows;
image->pixel_format = SG_PIXELFORMAT_R8;
image->data = new uint8_t[image->width * image->height];
std::memcpy(image->data, face_->glyph->bitmap.buffer, image->width * image->height);
@ -83,19 +88,25 @@ std::shared_ptr<image_heap_t> freetype_interface::get_emoji_image(int32_t in_gly
}
// 加载字形
FT_Load_Glyph(face_, in_glyph_id, FT_LOAD_COLOR);
FT_Load_Glyph(face_, in_glyph_id, FT_LOAD_RENDER | FT_LOAD_COLOR);
if (face_->glyph->format != FT_GLYPH_FORMAT_BITMAP) {
return nullptr;
}
FT_Bitmap& bitmap = face_->glyph->bitmap;
// 创建位图
// 这里使用了一个自定义的删除器来释放位图数据
std::shared_ptr<image_heap_t> image(new image_heap_t(), freetype_bitmap_deleter);
image->width = face_->glyph->bitmap.width;
image->height = face_->glyph->bitmap.rows;
image->width = bitmap.width;
image->height = bitmap.rows;
image->pixel_format = SG_PIXELFORMAT_RGBA8;
image->data = new uint8_t[image->width * image->height * 4];
std::memcpy(image->data, face_->glyph->bitmap.buffer, image->width * image->height);
// 其他格式,初始化为透明
clear_bitmap(image.get());
attach_bitmap(bitmap, image.get());
return image;
}
@ -143,6 +154,49 @@ void freetype_interface::on_set_font_size(float in_size) {
FT_Set_Pixel_Sizes(face_, 0, static_cast<FT_UInt>(in_size));
}
void freetype_interface::clear_bitmap(image_heap_t* in_image) {
memset(in_image->data, 0, in_image->width * in_image->height * 4);
}
void freetype_interface::attach_bitmap(const FT_Bitmap& in_bitmap, image_heap_t* in_image) {
// 将FreeType位图数据复制到新分配的内存中
switch (in_bitmap.pixel_mode) {
case FT_PIXEL_MODE_BGRA:
// 彩色emoji (BGRA -> RGBA)
for (unsigned int y = 0; y < in_bitmap.rows; y++) {
for (unsigned int x = 0; x < in_bitmap.width; x++) {
unsigned char* src = in_bitmap.buffer + (y * in_bitmap.pitch + x * 4);
unsigned char* dst = (uint8_t*)in_image->data + (y * in_image->width + x) * 4;
// BGRA -> RGBA
dst[0] += src[2]; // R <- B
dst[1] += src[1]; // G <- G
dst[2] += src[0]; // B <- R
dst[3] += src[3]; // A <- A
}
}
break;
case FT_PIXEL_MODE_GRAY:
// 灰度图转RGBA
for (unsigned int y = 0; y < in_bitmap.rows; y++) {
for (unsigned int x = 0; x < in_bitmap.width; x++) {
unsigned char gray = in_bitmap.buffer[y * in_bitmap.pitch + x];
unsigned char* dst = (uint8_t*) in_image->data + (y * in_image->width + x) * 4;
dst[0] = gray; // R
dst[1] = gray; // G
dst[2] = gray; // B
dst[3] = gray; // A
}
}
break;
default:
break;
}
}
bool init_font_system() {
if (FT_Init_FreeType(&library_)) {
return false;

View File

@ -18,6 +18,9 @@ public:
protected:
bool on_load() override;
void on_set_font_size(float in_size) override;
// 附加位图
static void clear_bitmap(image_heap_t* in_image);
static void attach_bitmap(const FT_Bitmap& in_bitmap, image_heap_t* in_image);
protected:
FT_Face face_{};
};

View File

@ -140,7 +140,7 @@ std::shared_ptr<image_heap_t> stb_font_face_t::get_glyph_image(int32_t in_glyph_
int32_t width, height, xoff, yoff;
// 获取字形图像
const auto bitmap = stbtt_GetGlyphBitmap(&font_info_, scale_, scale_, in_glyph_id, &width, &height, &xoff, &yoff);
const auto bitmap = stbtt_GetGlyphBitmapSubpixel(&font_info_, scale_, scale_, 0.33, 0, in_glyph_id, &width, &height, &xoff, &yoff);
// 创建位图
std::shared_ptr<image_heap_t> image(new image_heap_t(), stb_truetype_deleter);
@ -169,7 +169,7 @@ glyph_shaped_t stb_font_face_t::shape_glyph(uint32_t in_glyph_id) const {
stbtt_GetGlyphHMetrics(&font_info_, in_glyph_id, &advance, &lsb);
// 获取字形的边界框
int32_t x0, y0, x1, y1;
stbtt_GetGlyphBitmapBox(&font_info_, in_glyph_id, scale_, scale_, &x0, &y0, &x1, &y1);
stbtt_GetGlyphBitmapBoxSubpixel(&font_info_, in_glyph_id, scale_, scale_, 0.33, 0, &x0, &y0, &x1, &y1);
glyph_shaped_t out{};
out.glyph_index = in_glyph_id;

View File

@ -251,7 +251,8 @@ void render_elements::make_image(const Eigen::Vector2f& in_pos, const Eigen::Vec
void render_elements::make_text(const text_layout_t& in_layout, const Eigen::Vector2f& in_pos,
const Eigen::Vector2f& in_size, const geometry_t& in_geometry, const rect_color& in_color,
float in_rotation_radians, const Eigen::Vector2f& in_pivot, const Eigen::Vector2f& in_scale) {
const auto& sampler = texture_sampler_builder::get_sampler(sampler_type::pixel_art);
const auto& glyph_sampler = texture_sampler_builder::get_sampler(sampler_type::pixel_art);
const auto& emoji_sampler = texture_sampler_builder::get_sampler(sampler_type::pixel_art);
for (const auto& position : in_layout.glyphs) {
const auto& p = position;
@ -264,7 +265,7 @@ void render_elements::make_text(const text_layout_t& in_layout, const Eigen::Vec
batch_key new_key;
new_key.pipeline = position.is_emoji ? image_pipeline_ : text_pipeline_;
new_key.image = texture->get_image();
new_key.sampler = *sampler;
new_key.sampler = position.is_emoji ? *emoji_sampler : *glyph_sampler;
Eigen::Vector2f real_pos = p.position.array() + in_pos.array();
// snap to pixel grid