diff --git a/example/src/main.cpp b/example/src/main.cpp index 55550c7..c538de3 100644 --- a/example/src/main.cpp +++ b/example/src/main.cpp @@ -9,7 +9,8 @@ #include "pixel.h" #include "misc/mapped_file/mapped_file.h" #include "stb_image_loader.h" -#include "render/render_image.h" +#include "render/texture2d.h" +#include "widget/leaf_widget/mimage.h" int main(int argc, char* argv[]) { mirage_app::get().init(); @@ -17,17 +18,21 @@ int main(int argc, char* argv[]) { auto file = mapped_file::create(); file->map_file(L"Z:/Root/Local/NanakoDisk/涩图/可爱偷猴计划/东风谷早苗/57092520_p1.jpg"); - stb_image_loader image; - image.init(file->get_data(), file->get_size()); - const auto& heap = image.load(); + auto i = std::make_shared(); - render_image i; - i.create(heap->data, { heap->info.width, heap->info.height }, heap->info.get_pixel_format()); + { + stb_image_loader image_loader; + image_loader.init(file->get_data(), file->get_size()); + const auto& heap = image_loader.load(); + + i->create(heap->data, { heap->info.width, heap->info.height }, heap->info.get_pixel_format()); + } + + auto image = std::make_shared(); + image->set_image(i); const auto& window = mwindow::create({ 800, 600 }, L"Hello, World!"); - window->set_content( - std::make_shared() - ); + window->set_content(image); mirage_app::get().run(); return 0; diff --git a/src/mirage_app/mirage.cpp b/src/mirage_app/mirage.cpp index 26fc7bc..5309a30 100644 --- a/src/mirage_app/mirage.cpp +++ b/src/mirage_app/mirage.cpp @@ -88,6 +88,7 @@ void mirage_app::run() { std::this_thread::sleep_for(std::chrono::milliseconds(1)); } running = false; + texture_sampler_builder::clear(); render_context->cleanup(); delete render_context; } diff --git a/src/mirage_render/render/render_elements.cpp b/src/mirage_render/render/render_elements.cpp index 4ef7f79..2f9a4dc 100644 --- a/src/mirage_render/render/render_elements.cpp +++ b/src/mirage_render/render/render_elements.cpp @@ -1,5 +1,6 @@ #include "render_elements.h" #include "shaders/mirage_rounded_rect.hlsl.h" +#include "shaders/mirage_image.hlsl.h" template void compute_rect_vertices(const Eigen::MatrixBase& in_pos, @@ -62,6 +63,12 @@ void render_elements::set_texture(sg_image image) { ensure_batch_compatibility(new_key); } +void render_elements::set_sampler(sg_sampler sampler) { + batch_key new_key = current_key_; + new_key.sampler = sampler; + ensure_batch_compatibility(new_key); +} + Eigen::Matrix4f render_elements::create_projection_matrix(const Eigen::Vector2i& in_size) { Eigen::Matrix4f projection_matrix = Eigen::Matrix4f::Identity(); @@ -112,16 +119,16 @@ void render_elements::ensure_batch_compatibility(const batch_key& key) { // 添加矩形到当前批次 void render_elements::add_rect_to_batch( - const Eigen::Vector2f& in_pos, - const Eigen::Vector2f& in_size, - const rect_color& in_color, - const mirage_vertex_param_t& in_param_a, - const mirage_vertex_param_t& in_param_b, - const mirage_vertex_param_t& in_param_c, - const rect_uv& in_uv, - float in_rotation_radians, - const Eigen::Vector2f& in_pivot, - const Eigen::Vector2f& in_scale) { + const Eigen::Vector2f& in_pos, + const Eigen::Vector2f& in_size, + const rect_color& in_color, + const mirage_vertex_param_t& in_param_a, + const mirage_vertex_param_t& in_param_b, + const mirage_vertex_param_t& in_param_c, + const rect_uv& in_uv, + float in_rotation_radians, + const Eigen::Vector2f& in_scale, + const Eigen::Vector2f& in_pivot) { // 确保有活跃的批次 if (current_batch_index_ < 0) { set_pipeline(sg_pipeline{}); // 使用默认管线 @@ -130,7 +137,7 @@ void render_elements::add_rect_to_batch( // 计算顶点位置 Eigen::Matrix positions; - compute_rect_vertices(in_pos, in_size, positions, in_rotation_radians, in_pivot, in_scale); + compute_rect_vertices(in_pos, in_size, positions, in_rotation_radians, in_scale, in_pivot); // 记录起始顶点索引 uint32_t base_index = vertices_.size(); @@ -186,8 +193,8 @@ void render_elements::make_rect( in_param_c, in_uv, in_rotation_radians, - in_pivot, - in_scale); + in_scale, + in_pivot); } void render_elements::make_rounded_rect(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, @@ -196,7 +203,43 @@ void render_elements::make_rounded_rect(const Eigen::Vector2f& in_pos, const Eig set_pipeline(rounded_rect_pipeline_); const mirage_vertex_param_t param_a{ in_size }; const mirage_vertex_param_t param_b{ in_round }; - make_rect(in_pos, in_size, in_color, in_geometry, param_a, param_b, {}, in_uv, in_rotation_radians, in_scale, in_pivot); + make_rect(in_pos, in_size, in_color, in_geometry, param_a, param_b, {}, in_uv, in_rotation_radians, in_pivot, in_scale); +} + +void render_elements::make_image(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, + const geometry_t& in_geometry, const sg_image& in_image, sampler_type in_sampler_type, + const linear_color& in_color, const rect_uv& in_uv, float in_rotation_radians, const Eigen::Vector2f& in_pivot, + const Eigen::Vector2f& in_scale) { + const auto& sampler = texture_sampler_builder::get_sampler(in_sampler_type); + make_image(in_pos, + in_size, + in_geometry, + in_image, + sampler, + in_color, + in_uv, + in_rotation_radians, + in_pivot, + in_scale); +} + +void render_elements::make_image(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, + const geometry_t& in_geometry, const sg_image& in_image, std::shared_ptr in_sampler, + const linear_color& in_color, const rect_uv& in_uv, float in_rotation_radians, const Eigen::Vector2f& in_pivot, + const Eigen::Vector2f& in_scale) { + if (!in_sampler) { + return; + } + + // 构建完整的批次键 + batch_key new_key; + new_key.pipeline = image_pipeline_; + new_key.image = in_image; + new_key.sampler = *in_sampler; + + ensure_batch_compatibility(new_key); + + make_rect(in_pos, in_size, { in_color }, in_geometry, {}, {}, {}, in_uv, in_rotation_radians, in_pivot, in_scale); } // 确保缓冲区容量 @@ -247,6 +290,7 @@ void render_elements::flush_batches() { for (const auto& batch: batches_) { // 设置纹理 bind.images[0] = batch.key.image; + bind.samplers[0] = batch.key.sampler; // 绑定管线 sg_apply_pipeline(batch.key.pipeline); @@ -300,8 +344,10 @@ void render_elements::load_mirage_pipelines() { auto format = MIRAGE_PIXEL_FORMAT; #endif auto rounded_rect_shader = sg_make_shader(get_mirage_rounded_rect_shader_desc()); - auto rounded_rect_pipeline_desc = get_mirage_rounded_rect_pipeline_desc(rounded_rect_shader, - format, - 1); + auto rounded_rect_pipeline_desc = get_mirage_rounded_rect_pipeline_desc(rounded_rect_shader, format, 1); rounded_rect_pipeline_ = sg_make_pipeline(rounded_rect_pipeline_desc); + + auto image_shader = sg_make_shader(get_mirage_image_shader_desc()); + auto image_pipeline_desc = get_mirage_image_pipeline_desc(image_shader, format, 1); + image_pipeline_ = sg_make_pipeline(image_pipeline_desc); } diff --git a/src/mirage_render/render/render_elements.h b/src/mirage_render/render/render_elements.h index 79f2795..e174888 100644 --- a/src/mirage_render/render/render_elements.h +++ b/src/mirage_render/render/render_elements.h @@ -11,6 +11,7 @@ #include "geometry/layout_transform.h" #include "sokol_gfx.h" #include "color.h" +#include "texture_sampler.h" #include "misc/mirage_type.h" /** @@ -34,6 +35,10 @@ struct batch_key { /** 使用的纹理 */ sg_image image{}; + + /** 使用的采样器 */ + sg_sampler sampler{}; + // 可选:添加其他影响状态的元素,如着色器、混合模式等 /** @@ -42,8 +47,9 @@ struct batch_key { * @return 如果两个批次键相等则返回true */ bool operator==(const batch_key& other) const { - return pipeline.id == other.pipeline.id && - image.id == other.image.id; + return pipeline.id == other.pipeline.id && + image.id == other.image.id && + sampler.id == other.sampler.id; } /** @@ -51,10 +57,12 @@ struct batch_key { * @param other 要比较的另一个批次键 * @return 如果当前批次键小于另一个则返回true */ - bool operator<(const batch_key& other) const { - if (pipeline.id != other.pipeline.id) - return pipeline.id < other.pipeline.id; - return image.id < other.image.id; + bool operator<(const batch_key& other) const { + if (pipeline.id != other.pipeline.id) + return pipeline.id < other.pipeline.id; + if (image.id != other.image.id) + return image.id < other.image.id; + return sampler.id < other.sampler.id; // 缺少这一行 } }; @@ -181,6 +189,12 @@ public: */ void set_texture(sg_image image); + /** + * @brief 设置当前采样器 + * @param sampler 采样器 + */ + void set_sampler(sg_sampler sampler); + //-------------- 变换和投影 -------------- /** @@ -248,6 +262,49 @@ public: const rect_uv& in_uv = {}, const Eigen::Vector2f& in_scale = Eigen::Vector2f(1.f, 1.f)); + void make_image(const Eigen::Vector2f& in_pos, + const Eigen::Vector2f& in_size, + const geometry_t& in_geometry, + const sg_image& in_image, + sampler_type in_sampler_type, + const linear_color& in_color = { 1, 1, 1, 1 }, + const rect_uv& in_uv = {}, + float in_rotation_radians = 0.0f, + const Eigen::Vector2f& in_pivot = Eigen::Vector2f(0.5f, 0.5f), + const Eigen::Vector2f& in_scale = Eigen::Vector2f(1.f, 1.f)); + + void make_image(const Eigen::Vector2f& in_pos, + const Eigen::Vector2f& in_size, + const geometry_t& in_geometry, + const sg_image& in_image, + std::shared_ptr in_sampler, + const linear_color& in_color = { 1, 1, 1, 1 }, + const rect_uv& in_uv = {}, + float in_rotation_radians = 0.0f, + const Eigen::Vector2f& in_pivot = Eigen::Vector2f(0.5f, 0.5f), + const Eigen::Vector2f& in_scale = Eigen::Vector2f(1.f, 1.f)); + + //-------------- 统计信息 -------------- + + /** + * @brief 获取绘制调用次数 + * @return 绘制调用次数 + */ + [[nodiscard]] uint32_t get_draw_call_count() const { return draw_call_count_; } + + /** + * @brief 获取总三角形数量 + * @return 总三角形数量 + */ + [[nodiscard]] uint32_t get_total_triangles() const { return total_triangles_; } + + //-------------- 禁用拷贝和赋值 -------------- + + render_elements(const render_elements&) = delete; + render_elements& operator=(const render_elements&) = delete; + + render_elements(render_elements&&) = delete; + render_elements& operator=(render_elements&&) = delete; private: //-------------- 内部辅助方法 -------------- @@ -261,19 +318,19 @@ private: * @param in_param_c 顶点参数C * @param in_uv 纹理坐标 * @param in_rotation_radians 旋转角度 - * @param in_pivot 旋转和缩放的枢轴点 * @param in_scale 缩放因子 + * @param in_pivot 旋转和缩放的枢轴点 */ - void add_rect_to_batch(const Eigen::Vector2f& in_pos, - const Eigen::Vector2f& in_size, - const rect_color& in_color, - const mirage_vertex_param_t& in_param_a, - const mirage_vertex_param_t& in_param_b, - const mirage_vertex_param_t& in_param_c, - const rect_uv& in_uv, - float in_rotation_radians, - const Eigen::Vector2f& in_pivot, - const Eigen::Vector2f& in_scale); + void add_rect_to_batch(const Eigen::Vector2f& in_pos, + const Eigen::Vector2f& in_size, + const rect_color& in_color, + const mirage_vertex_param_t& in_param_a, + const mirage_vertex_param_t& in_param_b, + const mirage_vertex_param_t& in_param_c, + const rect_uv& in_uv, + float in_rotation_radians, + const Eigen::Vector2f& in_scale, + const Eigen::Vector2f& in_pivot); /** * @brief 确保当前批次与给定的渲染状态兼容 @@ -342,4 +399,7 @@ private: /** 圆角矩形渲染管线 */ sg_pipeline rounded_rect_pipeline_{}; + + /** 图片渲染管线 */ + sg_pipeline image_pipeline_{}; }; diff --git a/src/mirage_render/render/render_image.h b/src/mirage_render/render/texture2d.h similarity index 77% rename from src/mirage_render/render/render_image.h rename to src/mirage_render/render/texture2d.h index f2e3881..f93a869 100644 --- a/src/mirage_render/render/render_image.h +++ b/src/mirage_render/render/texture2d.h @@ -5,27 +5,25 @@ #include "pixel.h" /** - * @class render_image + * @class texture2d * @brief 渲染图像类 * * 用于静态图片的渲染,提供创建和清除操作。 */ -class render_image { +class texture2d { public: - ~render_image() { + ~texture2d() { clear(); } void create(void* in_data, const Eigen::Vector2i& in_size, sg_pixel_format in_pixel_format); void clear() { - if (clear_func_) { - clear_func_(); - } + if (sg_isvalid()) + sg_destroy_image(image_); } [[nodiscard]] const auto& get_image() const { return image_; } [[nodiscard]] const auto& get_size() const { return size_; } private: - std::function clear_func_{}; sg_image image_{}; Eigen::Vector2i size_{}; }; diff --git a/src/mirage_render/render/texture_sampler.h b/src/mirage_render/render/texture_sampler.h new file mode 100644 index 0000000..89a5b8a --- /dev/null +++ b/src/mirage_render/render/texture_sampler.h @@ -0,0 +1,248 @@ +#pragma once +/** + * @file sampler.h + * @brief 跨平台纹理采样器抽象 + */ + +#include "sokol_gfx.h" +#include +#include +#include +#include + +class texture_sampler; + +enum class sampler_type { + default_, + pixel_art, + bilinear, + trilinear, + tileable, + linear_clamp, + shadow_map, + anisotropic, +}; + +/** + * @class texture_sampler_builder + * @brief 跨平台纹理采样器工具 + * + * 提供简化的创建和管理纹理采样器的接口, + * 支持流式配置风格。 + */ +class texture_sampler_builder { +public: + /** + * @brief 创建默认采样器 + * @return 具有默认配置的采样器(最近点采样,重复包裹) + */ + static texture_sampler_builder create_default(); + + /** + * @brief 创建用于像素艺术的采样器(最近点采样) + * @return 为像素艺术渲染配置的采样器 + */ + static texture_sampler_builder create_pixel_art(); + + /** + * @brief 创建双线性过滤采样器 + * @return 具有双线性过滤的采样器(线性过滤,无MIP映射) + */ + static texture_sampler_builder create_bilinear(); + + /** + * @brief 创建三线性过滤采样器 + * @return 具有三线性过滤的采样器(带MIP映射的线性过滤) + */ + static texture_sampler_builder create_trilinear(); + + /** + * @brief 创建可平铺纹理的采样器 + * @return 为可平铺纹理配置的采样器,使用线性过滤 + */ + static texture_sampler_builder create_tileable(); + + /** + * @brief 创建带边缘限制的线性过滤采样器 + * @return 配置为平滑渲染并带边缘限制的采样器 + */ + static texture_sampler_builder create_linear_clamp(); + + /** + * @brief 创建阴影贴图采样器 + * @param compare_func 阴影采样的比较函数 + * @return 为阴影贴图采样配置的采样器 + */ + static texture_sampler_builder create_shadow_map(sg_compare_func compare_func = SG_COMPAREFUNC_LESS); + + /** + * @brief 创建各向异性过滤采样器 + * @param anisotropy 各向异性程度(1-16) + * @return 具有各向异性过滤的采样器 + */ + static texture_sampler_builder create_anisotropic(uint32_t anisotropy = 4); + + /** + * @brief 设置缩小过滤器 + * @param filter 用于缩小的过滤器 + * @return 采样器引用,用于方法链式调用 + */ + texture_sampler_builder& with_min_filter(sg_filter filter); + + /** + * @brief 设置放大过滤器 + * @param filter 用于放大的过滤器 + * @return 采样器引用,用于方法链式调用 + */ + texture_sampler_builder& with_mag_filter(sg_filter filter); + + /** + * @brief 设置MIP映射过滤器 + * @param filter 用于MIP映射选择的过滤器 + * @return 采样器引用,用于方法链式调用 + */ + texture_sampler_builder& with_mipmap_filter(sg_filter filter); + + /** + * @brief 同时设置所有过滤器 + * @param min_filter 缩小过滤器 + * @param mag_filter 放大过滤器 + * @param mip_filter MIP映射过滤器 + * @return 采样器引用,用于方法链式调用 + */ + texture_sampler_builder& with_filters(sg_filter min_filter, sg_filter mag_filter, sg_filter mip_filter); + + /** + * @brief 将所有过滤器设置为相同值 + * @param filter 用于所有过滤操作的过滤器 + * @return 采样器引用,用于方法链式调用 + */ + texture_sampler_builder& with_all_filters(sg_filter filter); + + /** + * @brief 设置水平包裹模式 + * @param wrap U坐标的包裹模式 + * @return 采样器引用,用于方法链式调用 + */ + texture_sampler_builder& with_wrap_u(sg_wrap wrap); + + /** + * @brief 设置垂直包裹模式 + * @param wrap V坐标的包裹模式 + * @return 采样器引用,用于方法链式调用 + */ + texture_sampler_builder& with_wrap_v(sg_wrap wrap); + + /** + * @brief 设置深度包裹模式(仅3D纹理) + * @param wrap W坐标的包裹模式 + * @return 采样器引用,用于方法链式调用 + */ + texture_sampler_builder& with_wrap_w(sg_wrap wrap); + + /** + * @brief 同时设置所有包裹模式 + * @param wrap 所有坐标的包裹模式 + * @return 采样器引用,用于方法链式调用 + */ + texture_sampler_builder& with_wrap(sg_wrap wrap); + + /** + * @brief 单独设置所有包裹模式 + * @param wrap_u U坐标的包裹模式 + * @param wrap_v V坐标的包裹模式 + * @param wrap_w W坐标的包裹模式 + * @return 采样器引用,用于方法链式调用 + */ + texture_sampler_builder& with_wrap(sg_wrap wrap_u, sg_wrap wrap_v, sg_wrap wrap_w); + + /** + * @brief 设置LOD范围 + * @param min_lod 最小细节级别 + * @param max_lod 最大细节级别 + * @return 采样器引用,用于方法链式调用 + */ + texture_sampler_builder& with_lod_range(float min_lod, float max_lod); + + /** + * @brief 设置最小LOD级别 + * @param min_lod 最小细节级别 + * @return 采样器引用,用于方法链式调用 + */ + texture_sampler_builder& with_min_lod(float min_lod); + + /** + * @brief 设置最大LOD级别 + * @param max_lod 最大细节级别 + * @return 采样器引用,用于方法链式调用 + */ + texture_sampler_builder& with_max_lod(float max_lod); + + /** + * @brief 设置边界颜色 + * @param color 使用的边界颜色 + * @return 采样器引用,用于方法链式调用 + */ + texture_sampler_builder& with_border_color(sg_border_color color); + + /** + * @brief 设置阴影采样器的比较函数 + * @param compare 使用的比较函数 + * @return 采样器引用,用于方法链式调用 + */ + texture_sampler_builder& with_compare(sg_compare_func compare); + + /** + * @brief 设置最大各向异性级别 + * @param anisotropy 最大各向异性(1-16) + * @return 采样器引用,用于方法链式调用 + */ + texture_sampler_builder& with_max_anisotropy(uint32_t anisotropy); + + /** + * @brief 设置调试标签 + * @param label 采样器的调试标签 + * @return 采样器引用,用于方法链式调用 + */ + texture_sampler_builder& with_label(const char* label); + + /** + * @brief 构建最终的采样器描述符 + * @return 完整的采样器描述符,可用于sg_make_sampler + */ + sg_sampler_desc build() const; + + /** + * @brief 创建纹理采样器 + * @return 纹理采样器指针 + */ + std::shared_ptr create() const; + + static std::shared_ptr get_sampler(sampler_type in_type); + static void clear(); +private: + inline static std::unordered_map> sampler_map_; + + // 默认构造函数创建标准采样器配置 + texture_sampler_builder(); + + // 正在构建的采样器描述符 + sg_sampler_desc desc_; +}; + +class texture_sampler { +public: + texture_sampler(const sg_sampler_desc& desc); + ~texture_sampler(); + + /** + * @brief 获取sokol-gfx采样器句柄 + * @return sokol-gfx采样器句柄 + */ + operator const sg_sampler&() const { + return sampler_; + } + const auto& get_sampler() const { return sampler_; } +private: + sg_sampler sampler_{}; +}; diff --git a/src/mirage_render/render/windows/render_image.cpp b/src/mirage_render/render/windows/render_image.cpp deleted file mode 100644 index 3e9212f..0000000 --- a/src/mirage_render/render/windows/render_image.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "render/render_image.h" -#include -#include - -#include "pixel_format_convert.h" -#include "windows_render_context.h" - -void render_image::create(void* in_data, const Eigen::Vector2i& in_size, sg_pixel_format in_pixel_format) { - auto render_context = mirage_render_context::get(); - if (!render_context) - return; - auto windows_render_context = (windows_mirage_render_context*)render_context; - auto pixel_format = sg_pixel_format_to_dxgi(in_pixel_format); - - // 创建D3D纹理 - D3D11_TEXTURE2D_DESC desc = {}; - desc.Width = in_size.x(); - desc.Height = in_size.y(); - desc.MipLevels = 1; - desc.ArraySize = 1; - desc.Format = pixel_format; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_IMMUTABLE; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - desc.CPUAccessFlags = 0; - desc.MiscFlags = 0; - - const auto& format_info = sg_query_pixelformat(in_pixel_format); - - D3D11_SUBRESOURCE_DATA data = {}; - data.pSysMem = in_data; - data.SysMemPitch = in_size.x() * format_info.bytes_per_pixel; - data.SysMemSlicePitch = 0; - - // 创建纹理 - ID3D11Texture2D* texture = nullptr; - auto hr = windows_render_context->get_device()->CreateTexture2D(&desc, &data, &texture); - if (FAILED(hr)) { - std::cerr << "Failed to create texture" << std::endl; - return; - } - - // 创建SRV - D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = {}; - srv_desc.Format = pixel_format; - srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - srv_desc.Texture2D.MostDetailedMip = 0; - srv_desc.Texture2D.MipLevels = 1; - - ID3D11ShaderResourceView* srv = nullptr; - hr = windows_render_context->get_device()->CreateShaderResourceView(texture, &srv_desc, &srv); - if (FAILED(hr)) { - texture->Release(); - std::cerr << "Failed to create shader resource view" << std::endl; - return; - } - - clear_func_ = [=] { - texture->Release(); - srv->Release(); - }; - - sg_image_desc sg_desc{}; - sg_desc.d3d11_texture = texture; - sg_desc.d3d11_shader_resource_view = srv; - - image_ = sg_make_image(sg_desc); -} diff --git a/src/mirage_render/render/windows/texture2d.cpp b/src/mirage_render/render/windows/texture2d.cpp new file mode 100644 index 0000000..2279e5c --- /dev/null +++ b/src/mirage_render/render/windows/texture2d.cpp @@ -0,0 +1,25 @@ +#include "render/texture2d.h" +#include +#include + +#include "pixel_format_convert.h" +#include "windows_render_context.h" + +void texture2d::create(void* in_data, const Eigen::Vector2i& in_size, sg_pixel_format in_pixel_format) { + auto format_info = sg_query_pixelformat(in_pixel_format); + + sg_image_desc sg_desc{}; + sg_desc.type = SG_IMAGETYPE_2D; + sg_desc.render_target = false; + sg_desc.width = in_size.x(); + sg_desc.height = in_size.y(); + sg_desc.num_slices = 1; + sg_desc.num_mipmaps = 1; + sg_desc.usage = SG_USAGE_IMMUTABLE; + sg_desc.pixel_format = in_pixel_format; + sg_desc.sample_count = 1; + sg_desc.data.subimage[0][0].ptr = in_data; + sg_desc.data.subimage[0][0].size = in_size.x() * in_size.y() * format_info.bytes_per_pixel; + + image_ = sg_make_image(sg_desc); +} diff --git a/src/mirage_render/render/windows/texture_sampler.cpp b/src/mirage_render/render/windows/texture_sampler.cpp new file mode 100644 index 0000000..3b5a057 --- /dev/null +++ b/src/mirage_render/render/windows/texture_sampler.cpp @@ -0,0 +1,234 @@ +#include "render/texture_sampler.h" +#include // For std::clamp +#include + +// 默认构造函数,设置标准配置 +texture_sampler_builder::texture_sampler_builder() { + // 初始化默认值 + desc_ = {}; // 零初始化所有字段 + + // 根据sg_sampler_desc默认值设置 + desc_.min_filter = SG_FILTER_NEAREST; + desc_.mag_filter = SG_FILTER_NEAREST; + desc_.mipmap_filter = SG_FILTER_NEAREST; + desc_.wrap_u = SG_WRAP_REPEAT; + desc_.wrap_v = SG_WRAP_REPEAT; + desc_.wrap_w = SG_WRAP_REPEAT; + desc_.min_lod = 0.0f; + desc_.max_lod = std::numeric_limits::max(); + desc_.border_color = SG_BORDERCOLOR_OPAQUE_BLACK; + desc_.compare = SG_COMPAREFUNC_NEVER; + desc_.max_anisotropy = 1; +} + +// 常用采样器类型的静态工厂方法 +texture_sampler_builder texture_sampler_builder::create_default() { + return texture_sampler_builder(); +} + +texture_sampler_builder texture_sampler_builder::create_pixel_art() { + return texture_sampler_builder() + .with_all_filters(SG_FILTER_NEAREST) + .with_wrap(SG_WRAP_CLAMP_TO_EDGE); +} + +texture_sampler_builder texture_sampler_builder::create_bilinear() { + return texture_sampler_builder() + .with_min_filter(SG_FILTER_LINEAR) + .with_mag_filter(SG_FILTER_LINEAR) + .with_mipmap_filter(SG_FILTER_NEAREST); +} + +texture_sampler_builder texture_sampler_builder::create_trilinear() { + return texture_sampler_builder() + .with_all_filters(SG_FILTER_LINEAR); +} + +texture_sampler_builder texture_sampler_builder::create_tileable() { + return texture_sampler_builder() + .with_all_filters(SG_FILTER_LINEAR) + .with_wrap(SG_WRAP_REPEAT); +} + +texture_sampler_builder texture_sampler_builder::create_linear_clamp() { + return texture_sampler_builder() + .with_all_filters(SG_FILTER_LINEAR) + .with_wrap(SG_WRAP_CLAMP_TO_EDGE); +} + +texture_sampler_builder texture_sampler_builder::create_shadow_map(sg_compare_func compare_func) { + return texture_sampler_builder() + .with_min_filter(SG_FILTER_LINEAR) + .with_mag_filter(SG_FILTER_LINEAR) + .with_wrap(SG_WRAP_CLAMP_TO_EDGE) + .with_compare(compare_func) + .with_border_color(SG_BORDERCOLOR_OPAQUE_WHITE); +} + +texture_sampler_builder texture_sampler_builder::create_anisotropic(uint32_t anisotropy) { + return texture_sampler_builder() + .with_all_filters(SG_FILTER_LINEAR) + .with_max_anisotropy(anisotropy); +} + +// 流式接口配置方法 +texture_sampler_builder& texture_sampler_builder::with_min_filter(sg_filter filter) { + desc_.min_filter = filter; + return *this; +} + +texture_sampler_builder& texture_sampler_builder::with_mag_filter(sg_filter filter) { + desc_.mag_filter = filter; + return *this; +} + +texture_sampler_builder& texture_sampler_builder::with_mipmap_filter(sg_filter filter) { + desc_.mipmap_filter = filter; + return *this; +} + +texture_sampler_builder& texture_sampler_builder::with_filters(sg_filter min_filter, sg_filter mag_filter, sg_filter mip_filter) { + desc_.min_filter = min_filter; + desc_.mag_filter = mag_filter; + desc_.mipmap_filter = mip_filter; + return *this; +} + +texture_sampler_builder& texture_sampler_builder::with_all_filters(sg_filter filter) { + return with_filters(filter, filter, filter); +} + +texture_sampler_builder& texture_sampler_builder::with_wrap_u(sg_wrap wrap) { + desc_.wrap_u = wrap; + return *this; +} + +texture_sampler_builder& texture_sampler_builder::with_wrap_v(sg_wrap wrap) { + desc_.wrap_v = wrap; + return *this; +} + +texture_sampler_builder& texture_sampler_builder::with_wrap_w(sg_wrap wrap) { + desc_.wrap_w = wrap; + return *this; +} + +texture_sampler_builder& texture_sampler_builder::with_wrap(sg_wrap wrap) { + desc_.wrap_u = wrap; + desc_.wrap_v = wrap; + desc_.wrap_w = wrap; + return *this; +} + +texture_sampler_builder& texture_sampler_builder::with_wrap(sg_wrap wrap_u, sg_wrap wrap_v, sg_wrap wrap_w) { + desc_.wrap_u = wrap_u; + desc_.wrap_v = wrap_v; + desc_.wrap_w = wrap_w; + return *this; +} + +texture_sampler_builder& texture_sampler_builder::with_lod_range(float min_lod, float max_lod) { + // 确保min_lod <= max_lod + if (min_lod > max_lod) { + std::swap(min_lod, max_lod); + } + + desc_.min_lod = min_lod; + desc_.max_lod = max_lod; + return *this; +} + +texture_sampler_builder& texture_sampler_builder::with_min_lod(float min_lod) { + desc_.min_lod = min_lod; + // 确保min_lod <= max_lod + if (min_lod > desc_.max_lod) { + desc_.max_lod = min_lod; + } + return *this; +} + +texture_sampler_builder& texture_sampler_builder::with_max_lod(float max_lod) { + desc_.max_lod = max_lod; + // 确保min_lod <= max_lod + if (desc_.min_lod > max_lod) { + desc_.min_lod = max_lod; + } + return *this; +} + +texture_sampler_builder& texture_sampler_builder::with_border_color(sg_border_color color) { + desc_.border_color = color; + return *this; +} + +texture_sampler_builder& texture_sampler_builder::with_compare(sg_compare_func compare) { + desc_.compare = compare; + return *this; +} + +texture_sampler_builder& texture_sampler_builder::with_max_anisotropy(uint32_t anisotropy) { + // 确保各向异性在有效范围内 + desc_.max_anisotropy = std::clamp(anisotropy, 1u, 16u); + return *this; +} + +texture_sampler_builder& texture_sampler_builder::with_label(const char* label) { + desc_.label = label; + return *this; +} + +sg_sampler_desc texture_sampler_builder::build() const { + return desc_; +} + +std::shared_ptr texture_sampler_builder::create() const { + return std::make_shared(build()); +} + +std::shared_ptr texture_sampler_builder::get_sampler(sampler_type in_type) { + // 尝试从sampler_map_中查找 + const auto& it = sampler_map_.find(in_type); + if (it != sampler_map_.end()) { + return it->second; + } + + // 如果没有找到,创建新的采样器并存储 + switch (in_type) { + case sampler_type::default_: + return sampler_map_[in_type] = create_default().create(); + case sampler_type::pixel_art: + return sampler_map_[in_type] = create_pixel_art().create(); + case sampler_type::bilinear: + return sampler_map_[in_type] = create_bilinear().create(); + case sampler_type::trilinear: + return sampler_map_[in_type] = create_trilinear().create(); + case sampler_type::tileable: + return sampler_map_[in_type] = create_tileable().create(); + case sampler_type::linear_clamp: + return sampler_map_[in_type] = create_linear_clamp().create(); + case sampler_type::shadow_map: + return sampler_map_[in_type] = create_shadow_map().create(); + case sampler_type::anisotropic: + return sampler_map_[in_type] = create_anisotropic().create(); + } + + // 未知类型 + std::cerr << "Unknown sampler type: " << static_cast(in_type) << std::endl; + return nullptr; +} + +void texture_sampler_builder::clear() { + sampler_map_.clear(); +} + +texture_sampler::texture_sampler(const sg_sampler_desc& desc) { + sampler_ = sg_make_sampler(desc); +} + +texture_sampler::~texture_sampler() { + if (sampler_.id != SG_INVALID_ID) { + if (sg_isvalid()) + sg_destroy_sampler(sampler_); + } +} + diff --git a/src/mirage_render/shaders/mirage_image.slang b/src/mirage_render/shaders/mirage_image.slang new file mode 100644 index 0000000..fcf9c6d --- /dev/null +++ b/src/mirage_render/shaders/mirage_image.slang @@ -0,0 +1,35 @@ +#include "mirage_util.slang" + +cbuffer ParamBuffer +{ + matrix transform; +}; + +SamplerState textureSampler; +Texture2D texture; + +struct PSInput { + float4 position : SV_POSITION; + float2 uv : TEXCOORD0; + float4 color : COLOR; +}; + +[shader("vertex")] +PSInput vertex_main(VSInput input) +{ + PSInput output; + + // 并通过常量缓冲区或结构化缓冲区传递 + output.position = mul(float4(input.position, 0.0, 1.0), transform); + output.uv = input.uv; + output.color = input.color; + + return output; +} + +[shader("pixel")] +float4 pixel_main(PSInput input) : SV_Target +{ + float4 color = texture.Sample(textureSampler, input.uv); + return color * input.color; +} diff --git a/src/mirage_widget/widget/leaf_widget/mimage.cpp b/src/mirage_widget/widget/leaf_widget/mimage.cpp index b00643b..5219f4b 100644 --- a/src/mirage_widget/widget/leaf_widget/mimage.cpp +++ b/src/mirage_widget/widget/leaf_widget/mimage.cpp @@ -1 +1,25 @@ #include "mimage.h" + +#include "render/texture2d.h" + +void mimage::on_paint(mirage_paint_context& in_context) { + if (!image_) { + return; + } + + in_context.drawer().make_image( + { 0, 0 }, + in_context.geo().get_local_size(), + in_context.geo(), + image_->get_image(), + sampler_type::default_, + { color_ } + ); +} + +Eigen::Vector2f mimage::compute_desired_size(float in_layout_scale_multiplier) const { + if (image_) { + return image_->get_size().cast(); + } + return { 20, 20 }; +} diff --git a/src/mirage_widget/widget/leaf_widget/mimage.h b/src/mirage_widget/widget/leaf_widget/mimage.h index 60d6d82..01ca961 100644 --- a/src/mirage_widget/widget/leaf_widget/mimage.h +++ b/src/mirage_widget/widget/leaf_widget/mimage.h @@ -1,10 +1,21 @@ #pragma once +#include "render/texture_sampler.h" #include "widget/mleaf_widget.h" +class texture2d; + class mimage : public mleaf_widget { public: - virtual void on_paint(mirage_paint_context& in_context) override; - virtual Eigen::Vector2f compute_desired_size(float in_layout_scale_multiplier) const override; -private: + void on_paint(mirage_paint_context& in_context) override; + Eigen::Vector2f compute_desired_size(float in_layout_scale_multiplier) const override; + const auto& get_image() const { return image_; } + void set_image(const std::shared_ptr& in_image) { image_ = in_image; } + + const auto& get_color() const { return color_; } + void set_color(const linear_color& in_color) { color_ = in_color; } +private: + std::shared_ptr image_; + std::shared_ptr sampler_; + linear_color color_ = { 1, 1, 1, 1 }; }; diff --git a/tools/win_mirage_shdc.exe b/tools/win_mirage_shdc.exe index f98ff58..0dc377b 100644 Binary files a/tools/win_mirage_shdc.exe and b/tools/win_mirage_shdc.exe differ