新增图片加载接口,调整目录结构

This commit is contained in:
Nanako 2025-04-01 20:42:27 +08:00
parent 4036ee2ded
commit e966dadc70
78 changed files with 159 additions and 33 deletions

6
.gitmodules vendored
View File

@ -0,0 +1,6 @@
[submodule "third_party/freetype"]
path = third_party/freetype
url = https://github.com/freetype/freetype
[submodule "third_party/harfbuzz"]
path = third_party/harfbuzz
url = https://github.com/harfbuzz/harfbuzz

View File

@ -50,9 +50,10 @@ else ()
endif ()
add_subdirectory(src/sokol)
add_subdirectory(third_party/freetype)
add_subdirectory(third_party/harfbuzz)
add_subdirectory(src/mirage_render)
add_subdirectory(src/mirage_image)
add_subdirectory(src/mirage_stb_image_loader)
add_subdirectory(src/mirage_core)
add_subdirectory(src/mirage_widget)
add_subdirectory(src/mirage_app)

View File

@ -1,14 +1,66 @@
#include <iostream>
#include "mirage.h"
#include "window/mwindow.h"
#include "font/font_system.h"
#include "font/font_renderer/colr_renderer.h"
#include "widget/widget_new.h"
#include "widget/compound_widget/mbutton.h"
#include "widget/leaf_widget/mtext_block.h"
#include "widget/panel_widget/mbox.h"
#include "freetype/freetype.h"
#include "freetype/ftlcdfil.h"
int main(int argc, char* argv[]) {
mirage_app::get().init();
FT_Library ft_library;
if (FT_Init_FreeType(&ft_library)) {
std::cerr << "Failed to initialize FreeType library" << std::endl;
return -1;
}
FT_Library_SetLcdFilter(ft_library, FT_LCD_FILTER_DEFAULT);
FT_Face ft_face;
if (FT_New_Face(ft_library, "C:/Windows/Fonts/msyh.ttc", 0, &ft_face)) {
std::cerr << "Failed to load font face" << std::endl;
return -1;
}
FT_Library_SetLcdFilterWeights(ft_library, nullptr);
FT_Library_SetLcdGeometry(ft_library, nullptr);
FT_Library_SetLcdFilter(ft_library, FT_LCD_FILTER_DEFAULT);
// 渲染一个字符
FT_Set_Pixel_Sizes(ft_face, 0, 24);
FT_Load_Char(ft_face, U'', FT_LOAD_RENDER);
FT_Render_Glyph(ft_face->glyph, FT_RENDER_MODE_LCD);
// 获取渲染的位图
FT_Bitmap bitmap = ft_face->glyph->bitmap;
if (bitmap.buffer) {
std::cout << "Bitmap width: " << bitmap.width << ", height: " << bitmap.rows << std::endl;
} else {
std::cerr << "Failed to get bitmap" << std::endl;
}
// 保存位图到文件
color_emoji_bitmap_t bitmap_;
// 将bitmap数据转换为color_emoji_bitmap_t格式
bitmap_.width = bitmap.width;
bitmap_.height = bitmap.rows;
bitmap_.data.resize(bitmap.width * bitmap.rows * 4); // RGBA格式
for (int y = 0; y < bitmap.rows; ++y) {
for (int x = 0; x < bitmap.width; ++x) {
int index = y * bitmap.width + x;
bitmap_.data[index * 4 + 0] = bitmap.buffer[index]; // R
bitmap_.data[index * 4 + 1] = bitmap.buffer[index]; // G
bitmap_.data[index * 4 + 2] = bitmap.buffer[index]; // B
bitmap_.data[index * 4 + 3] = bitmap.buffer[index]; // A
}
}
save_bitmap("output.bmp", bitmap_);
FT_Done_Face(ft_face);
auto& manager = font_manager::instance();
manager.add_font(L"C:/Users/46944/AppData/Local/Microsoft/Windows/Fonts/MapleMono-NF-CN-Regular.ttf");
manager.add_font(L"C:/Windows/Fonts/msyh.ttc");

View File

@ -2,14 +2,13 @@ cmake_minimum_required(VERSION 3.15)
project(mirage_core LANGUAGES C CXX)
find_package(Freetype REQUIRED)
find_package(Eigen3 REQUIRED)
set(SRC_FILES)
retrieve_files(${CMAKE_CURRENT_SOURCE_DIR} SRC_FILES)
add_library(${PROJECT_NAME} STATIC ${SRC_FILES})
target_link_libraries(${PROJECT_NAME} PUBLIC Freetype::Freetype Eigen3::Eigen mirage_image)
target_link_libraries(${PROJECT_NAME} PUBLIC Eigen3::Eigen mirage_image)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
add_os_definitions(${PROJECT_NAME})
target_compile_definitions(${PROJECT_NAME} PUBLIC -DNOMINMAX)

View File

@ -4,6 +4,7 @@
#include <cstddef>
#include <memory>
#include <filesystem>
#include <span>
class mapped_file {
public:
@ -21,5 +22,19 @@ public:
[[nodiscard]] virtual size_t get_size() const = 0;
[[nodiscard]] virtual bool is_mapped() const = 0;
[[nodiscard]] std::span<std::byte const> get_span() const {
return std::span(static_cast<std::byte const*>(get_data()), get_size());
}
[[nodiscard]] std::span<std::byte> get_span() {
return std::span(static_cast<std::byte*>(get_data()), get_size());
}
[[nodiscard]] uint8_t* get_u8() {
return static_cast<uint8_t*>(get_data());
}
[[nodiscard]] const uint8_t* get_u8() const {
return static_cast<const uint8_t*>(get_data());
}
static std::unique_ptr<mapped_file> create();
};

View File

@ -1,19 +1,14 @@
project(mirage_render)
set(SOURCE_FILES)
retrieve_files(${CMAKE_CURRENT_SOURCE_DIR} SOURCE_FILES)
retrieve_files(${CMAKE_CURRENT_SOURCE_DIR}/src SOURCE_FILES)
add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES})
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(${PROJECT_NAME} PUBLIC mirage_core sokol)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src)
target_link_libraries(${PROJECT_NAME} PUBLIC mirage_core sokol freetype)
option(MIRAGE_STB_IMAGE_LOADER "Use stb load image" ON)
option(MIRAGE_SVG_EMOJI "Use svg emoji" ON)
if (MIRAGE_STB_IMAGE_LOADER)
target_link_libraries(${PROJECT_NAME} PUBLIC mirage_stb_image_loader)
target_compile_definitions(${PROJECT_NAME} PUBLIC HAS_STB_IMAGE)
endif ()
if (MIRAGE_SVG_EMOJI)
find_package(nanosvg REQUIRED)
find_package(ZLIB REQUIRED)
@ -21,6 +16,14 @@ if (MIRAGE_SVG_EMOJI)
target_compile_definitions(${PROJECT_NAME} PUBLIC HAS_NANOSVG)
endif ()
option(MIRAGE_STB_IMAGE_LOADER "Use stb load image" ON)
if (MIRAGE_STB_IMAGE_LOADER)
add_subdirectory(stb_image_loader)
target_link_libraries(${PROJECT_NAME} PUBLIC stb_image_loader)
target_compile_definitions(${PROJECT_NAME} PUBLIC HAS_STB_IMAGE)
endif ()
# shader
add_mirage_shader_directory(${CMAKE_CURRENT_SOURCE_DIR}/shaders)
add_shader_dependencies(${PROJECT_NAME})

View File

@ -2,6 +2,8 @@
#include "font_renderer.h"
#include "font/stb_truetype.h"
void save_bitmap(const std::string& filename, const color_emoji_bitmap_t& bitmap);
/**
* @class colr_renderer_t
* @brief COLR/CPAL表的彩色表情渲染器

View File

@ -0,0 +1,28 @@
#pragma once
#include <cstdint>
#include <span>
#include <filesystem>
#include "pixel.h"
#include "sokol_gfx.h"
#include "misc/mapped_file/mapped_file.h"
struct image_heap_t {
int32_t width; // 图像宽度
int32_t height; // 图像高度
sg_pixel_format pixel_format; // 像素格式
void* data; // 图像数据指针
template<typename P>
image_accessor<P> make_accessor() {
return image_accessor<P>(data, width, height);
}
};
std::shared_ptr<image_heap_t> load_image(const std::span<std::byte>& in_raw_data);
inline std::shared_ptr<image_heap_t> load_image(const std::filesystem::path& in_file) {
auto mapped = mapped_file::create();
if (!mapped->map_file(in_file))
return nullptr;
return load_image(mapped->get_span());
}

View File

@ -1,6 +1,6 @@
#pragma once
/**
* @file sampler.h
* @file texture_sampler.h
* @brief
*/
@ -210,13 +210,13 @@ public:
* @brief
* @return sg_make_sampler
*/
sg_sampler_desc build() const;
[[nodiscard]] sg_sampler_desc build() const;
/**
* @brief
* @return
*/
std::shared_ptr<texture_sampler> create() const;
[[nodiscard]] std::shared_ptr<texture_sampler> create() const;
static std::shared_ptr<texture_sampler> get_sampler(sampler_type in_type);
static void clear();

View File

@ -1,8 +1,8 @@
project(mirage_stb_image_loader)
project(stb_image_loader)
set(SRC_FILES)
retrieve_files(${CMAKE_CURRENT_SOURCE_DIR} SRC_FILES)
add_library(${PROJECT_NAME} STATIC ${SRC_FILES})
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(${PROJECT_NAME} PUBLIC mirage_image)
target_link_libraries(${PROJECT_NAME} PUBLIC mirage_render)

View File

@ -1,6 +1,7 @@
#include "stb_image_loader.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include "interface/image_interface.h"
sg_pixel_format stb_image_info::get_pixel_format() const {
// 根据通道数和是否HDR选择合适的像素格式
@ -83,9 +84,29 @@ uint8_t* stb_image_loader::load_8_bit() const {
return stbi_load_from_memory(data_, size_, &width, &height, &channels, 4);
}
std::shared_ptr<stb_heap_image> stb_image_loader::load() const {
auto heap = std::make_shared<stb_heap_image>();
heap->info = get_info();
struct stb_heap_image {
stb_image_info info;
void* data;
~stb_heap_image() {
if (data)
stbi_image_free(data);
}
};
void delete_stb_image(image_heap_t* in_data) {
if (in_data->data)
stbi_image_free(in_data->data);
delete in_data;
}
std::shared_ptr<image_heap_t> stb_image_loader::load() const {
std::shared_ptr<image_heap_t> heap(new image_heap_t, delete_stb_image);
const auto& info = get_info();
heap->width = info.width;
heap->height = info.height;
heap->pixel_format = info.get_pixel_format();
if (is_hdr())
heap->data = load_hdr();
else if (is_16_bit())
@ -94,3 +115,9 @@ std::shared_ptr<stb_heap_image> stb_image_loader::load() const {
heap->data = load_8_bit();
return heap;
}
std::shared_ptr<image_heap_t> load_image(const std::span<std::byte>& in_raw_data) {
stb_image_loader loader;
loader.init(in_raw_data.data(), static_cast<int32_t>(in_raw_data.size()));
return loader.load();
}

View File

@ -5,6 +5,8 @@
#include "sokol_gfx.h"
#include "stb_image.h"
struct image_heap_t;
struct stb_image_info {
int32_t width;
int32_t height;
@ -15,16 +17,6 @@ struct stb_image_info {
[[nodiscard]] sg_pixel_format get_pixel_format() const;
};
struct stb_heap_image {
stb_image_info info;
void* data;
~stb_heap_image() {
if (data)
stbi_image_free(data);
}
};
class stb_image_loader {
public:
void init(void* in_data, int32_t in_size);
@ -36,9 +28,8 @@ public:
[[nodiscard]] float* load_hdr() const;
[[nodiscard]] uint16_t* load_16_bit() const;
[[nodiscard]] uint8_t* load_8_bit() const;
[[nodiscard]] std::shared_ptr<stb_heap_image> load() const;
[[nodiscard]] std::shared_ptr<image_heap_t> load() const;
private:
stbi_uc* data_{};
int32_t size_{};
};

View File

@ -43,7 +43,7 @@ private:
std::u32string text_;
text_layout_t layout_{};
float font_size_ = 15.0f;
float font_size_ = 48.0f;
float line_spacing_ = 1.2f;
float max_width_ = 0.0f;
std::shared_ptr<font_face_t> font_;

1
third_party/freetype vendored Submodule

@ -0,0 +1 @@
Subproject commit 82090e67c24259c343c83fd9cefe6ff0be7a7eca

1
third_party/harfbuzz vendored Submodule

@ -0,0 +1 @@
Subproject commit 9f83bbbe64654b45ba5bb06927ff36c2e7588495