diff --git a/src/mirage_image/pixel.h b/src/mirage_image/pixel.h index e2b5531..fe705ae 100644 --- a/src/mirage_image/pixel.h +++ b/src/mirage_image/pixel.h @@ -10,6 +10,8 @@ #include #include +#include "sokol_gfx.h" + /** * @brief 像素格式信息命名空间 * 提供sg_pixel_format格式的辅助函数 diff --git a/src/mirage_render/font/freetype_font/src/freetype_interface.cpp b/src/mirage_render/font/freetype_font/src/freetype_interface.cpp index 7bb40e4..6222c67 100644 --- a/src/mirage_render/font/freetype_font/src/freetype_interface.cpp +++ b/src/mirage_render/font/freetype_font/src/freetype_interface.cpp @@ -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,14 +66,17 @@ std::shared_ptr 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(new image_heap_t(), freetype_bitmap_deleter); - image->width = face_->glyph->bitmap.width; - image->height = face_->glyph->bitmap.rows; - image->pixel_format = SG_PIXELFORMAT_R8; - image->data = new uint8_t[image->width * image->height]; + 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); return image; @@ -83,19 +88,25 @@ std::shared_ptr 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(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(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; diff --git a/src/mirage_render/font/freetype_font/src/freetype_interface.h b/src/mirage_render/font/freetype_font/src/freetype_interface.h index 2c84e86..8e99ee1 100644 --- a/src/mirage_render/font/freetype_font/src/freetype_interface.h +++ b/src/mirage_render/font/freetype_font/src/freetype_interface.h @@ -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_{}; }; diff --git a/src/mirage_render/font/stb_truetype_font/stb_truetype_interface.cpp b/src/mirage_render/font/stb_truetype_font/stb_truetype_interface.cpp index 84457f0..06c1b32 100644 --- a/src/mirage_render/font/stb_truetype_font/stb_truetype_interface.cpp +++ b/src/mirage_render/font/stb_truetype_font/stb_truetype_interface.cpp @@ -140,7 +140,7 @@ std::shared_ptr 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(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; diff --git a/src/mirage_render/src/render/render_elements.cpp b/src/mirage_render/src/render/render_elements.cpp index 3713eda..35d9d93 100644 --- a/src/mirage_render/src/render/render_elements.cpp +++ b/src/mirage_render/src/render/render_elements.cpp @@ -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