todo
This commit is contained in:
parent
45231d9953
commit
df9732a1bb
@ -1,7 +1,26 @@
|
||||
project(mirage_core)
|
||||
set(CMAKE_CXX_STANDARD 26)
|
||||
|
||||
find_package(HarfBuzz REQUIRED)
|
||||
find_package(HarfBuzz)
|
||||
# 如果HarfBuzz没有找到,则尝试查找harfbuzz
|
||||
if (NOT HarfBuzz_FOUND)
|
||||
find_package(harfbuzz REQUIRED)
|
||||
endif ()
|
||||
# 如果没有harfbuzz则创建别名
|
||||
if (NOT TARGET harfbuzz)
|
||||
# 如果存在HarfBuzz::HarfBuzz则创建别名
|
||||
if (TARGET HarfBuzz::HarfBuzz)
|
||||
add_library(harfbuzz ALIAS HarfBuzz::HarfBuzz)
|
||||
elseif (TARGET harfbuzz::harfbuzz)
|
||||
# 否则创建别名
|
||||
add_library(harfbuzz ALIAS harfbuzz::harfbuzz)
|
||||
endif ()
|
||||
endif ()
|
||||
# 检查是否找到HarfBuzz
|
||||
if (NOT TARGET harfbuzz)
|
||||
message(FATAL_ERROR "HarfBuzz not found")
|
||||
endif ()
|
||||
|
||||
find_package(Eigen3 REQUIRED)
|
||||
find_package(spdlog REQUIRED)
|
||||
find_package(Boost REQUIRED)
|
||||
@ -12,7 +31,7 @@ set(RENDERER_SOURCES "")
|
||||
retrieve_files(${CMAKE_CURRENT_SOURCE_DIR} RENDERER_SOURCES)
|
||||
|
||||
add_library(${PROJECT_NAME} STATIC ${RENDERER_SOURCES})
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Freetype::Freetype harfbuzz::harfbuzz Eigen3::Eigen spdlog::spdlog msdfgen-full Boost::boost Vulkan::Vulkan LLGL)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Freetype::Freetype harfbuzz Eigen3::Eigen spdlog::spdlog msdfgen-full Boost::boost Vulkan::Vulkan LLGL)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE NOMINMAX)
|
||||
add_os_definitions(${PROJECT_NAME})
|
||||
|
@ -78,42 +78,6 @@ namespace mirage {
|
||||
}
|
||||
};
|
||||
|
||||
struct vertex_param_pack {
|
||||
union {
|
||||
float x;
|
||||
float r;
|
||||
};
|
||||
union {
|
||||
float y;
|
||||
float g;
|
||||
};
|
||||
union {
|
||||
float z;
|
||||
float b;
|
||||
};
|
||||
union {
|
||||
float w;
|
||||
float a;
|
||||
};
|
||||
vertex_param_pack(float in_x, float in_y, float in_z, float in_w) : x(in_x), y(in_y), z(in_z), w(in_w) {}
|
||||
vertex_param_pack(const LLGL::ColorRGBAf& in) : r(in.r), g(in.g), b(in.b), a(in.a) {}
|
||||
vertex_param_pack(const LLGL::Offset2D& in) : x(in.x), y(in.y), z(0), w(0) {}
|
||||
vertex_param_pack(const LLGL::Extent2D& in) : x(in.width), y(in.height), z(0), w(0) {}
|
||||
vertex_param_pack(const LLGL::Offset3D& in) : x(in.x), y(in.y), z(in.z), w(0) {}
|
||||
vertex_param_pack(const LLGL::Extent3D& in) : x(in.width), y(in.height), z(in.depth), w(0) {}
|
||||
vertex_param_pack(const Eigen::Vector2f& in) : x(in.x()), y(in.y()), z(0), w(0) {}
|
||||
vertex_param_pack(const Eigen::Vector3f& in) : x(in.x()), y(in.y()), z(in.z()), w(0) {}
|
||||
vertex_param_pack(const Eigen::Vector4f& in) : x(in.x()), y(in.y()), z(in.z()), w(in.w()) {}
|
||||
};
|
||||
|
||||
struct vertex_t {
|
||||
Eigen::Vector3d position;
|
||||
Eigen::Vector2d uv;
|
||||
LLGL::ColorRGBAf color;
|
||||
vertex_param_pack param_a;
|
||||
vertex_param_pack param_b;
|
||||
vertex_param_pack param_c;
|
||||
};
|
||||
|
||||
struct triangle_index_t {
|
||||
int32_t vertex_index[3];
|
||||
|
1
src/core/renderer/element_batcher.cpp
Normal file
1
src/core/renderer/element_batcher.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "element_batcher.h"
|
11
src/core/renderer/element_batcher.h
Normal file
11
src/core/renderer/element_batcher.h
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
namespace mirage {
|
||||
class element_batcher {
|
||||
|
||||
private:
|
||||
struct batch_key {
|
||||
|
||||
};
|
||||
};
|
||||
}
|
@ -29,6 +29,10 @@ namespace mirage {
|
||||
[[nodiscard]] size_t get_index_count() const {
|
||||
return index_buffer.get_size() / sizeof(triangle_index_t);
|
||||
}
|
||||
[[nodiscard]] Eigen::Vector2f get_size() const {
|
||||
const auto& extent_2d = swap_chain->GetResolution();
|
||||
return {extent_2d.width, extent_2d.height};
|
||||
}
|
||||
private:
|
||||
void create_vertex_buffer();
|
||||
void create_index_buffer();
|
||||
|
@ -1 +0,0 @@
|
||||
#include "render_draw_command.h"
|
@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace mirage {
|
||||
class render_draw_command {
|
||||
|
||||
};
|
||||
}
|
1
src/core/renderer/render_draw_element.cpp
Normal file
1
src/core/renderer/render_draw_element.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "render_draw_element.h"
|
14
src/core/renderer/render_draw_element.h
Normal file
14
src/core/renderer/render_draw_element.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
namespace mirage {
|
||||
class render_draw_element {
|
||||
public:
|
||||
enum rotation_space {
|
||||
local, // 相对于元素自身的坐标系 (0, 0)是元素的左上角
|
||||
world // 相对于绘制几何体的坐标系 (0, 0)是屏幕的左上角
|
||||
};
|
||||
|
||||
static void make_debug_quad(, uint32_t in_layer, );
|
||||
};
|
||||
}
|
1
src/core/renderer/render_element_drawer.cpp
Normal file
1
src/core/renderer/render_element_drawer.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "render_element_drawer.h"
|
22
src/core/renderer/render_element_drawer.h
Normal file
22
src/core/renderer/render_element_drawer.h
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
#include "Eigen/Eigen"
|
||||
|
||||
namespace mirage {
|
||||
struct rect_round {
|
||||
float left_top_px;
|
||||
float right_top_px;
|
||||
float left_bottom_px;
|
||||
float right_bottom_px;
|
||||
};
|
||||
enum class draw_effect {
|
||||
none,
|
||||
snap_to_pixel,
|
||||
};
|
||||
|
||||
class element_drawer {
|
||||
public:
|
||||
void draw_rounded_rect(, Eigen::Vector2f in_pos, Eigen::Vector2f in_size, rect_round in_radius, Eigen::Vector4f in_color, draw_effect in_effect);
|
||||
private:
|
||||
|
||||
};
|
||||
}
|
1
src/core/renderer/render_window_element_list.cpp
Normal file
1
src/core/renderer/render_window_element_list.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "render_window_element_list.h"
|
8
src/core/renderer/render_window_element_list.h
Normal file
8
src/core/renderer/render_window_element_list.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
class render_window_element_list {
|
||||
public:
|
||||
render_window_element_list();
|
||||
private:
|
||||
|
||||
};
|
244
src/core/renderer/rendering_common.h
Normal file
244
src/core/renderer/rendering_common.h
Normal file
@ -0,0 +1,244 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include "LLGL/LLGL.h"
|
||||
#include <Eigen/Eigen>
|
||||
|
||||
namespace mirage {
|
||||
using transform_type = Eigen::Projective2d;
|
||||
using color_type = LLGL::ColorRGBAub;
|
||||
using linear_color_type = LLGL::ColorRGBAf;
|
||||
|
||||
/**
|
||||
* 绘制基本类型
|
||||
*/
|
||||
enum class draw_primitive {
|
||||
none,
|
||||
line_list,
|
||||
triangle_list,
|
||||
};
|
||||
|
||||
/**
|
||||
* 着色器类型。注意:在着色器文件中有镜像
|
||||
* 如果在此添加类型,必须同时实现对应的着色器类型(tslate_element_ps)。参见slate_shaders.h
|
||||
*/
|
||||
enum class shader_type {
|
||||
/** 默认着色器类型,简单的纹理查找 */
|
||||
default_ = 0,
|
||||
/** 边框着色器 */
|
||||
border = 1,
|
||||
/** 灰度字体着色器,使用仅alpha纹理 */
|
||||
grayscale_font = 2,
|
||||
/** 颜色字体着色器,使用颜色纹理 */
|
||||
color_font = 3,
|
||||
/** 线段着色器,用于绘制抗锯齿线条 */
|
||||
line_segment = 4,
|
||||
/** 完全自定义材质,不假设使用方式 */
|
||||
custom = 5,
|
||||
/** 后处理着色器 */
|
||||
post_process = 6,
|
||||
/** 圆角矩形着色器 */
|
||||
rounded_box = 7,
|
||||
};
|
||||
|
||||
/**
|
||||
* 元素渲染时可应用的绘制效果
|
||||
* 注意:新增效果应以位掩码形式添加
|
||||
* 如果在此添加新类型,必须同时实现对应的着色器类型(TSlateElementPS)。参见SlateShaders.h
|
||||
*/
|
||||
enum class draw_effect {
|
||||
/** 无效果 */
|
||||
none = 0,
|
||||
/** 高级:无混合模式绘制元素 */
|
||||
no_blending = 1 << 0,
|
||||
/** 高级:使用预乘alpha混合。若设置了no_blending则忽略 */
|
||||
pre_multiplied_alpha = 1 << 1,
|
||||
/** 高级:不进行伽马校正 */
|
||||
no_gamma = 1 << 2,
|
||||
/** 高级:将alpha值取反(1 - Alpha) */
|
||||
invert_alpha = 1 << 3,
|
||||
|
||||
// ^^ 这些与ESlateBatchDrawFlag匹配 ^^
|
||||
|
||||
/** 禁用像素对齐 */
|
||||
no_pixel_snapping = 1 << 4,
|
||||
/** 以禁用效果绘制元素 */
|
||||
disabled_effect = 1 << 5,
|
||||
/** 高级:忽略纹理alpha通道 */
|
||||
ignore_texture_alpha = 1 << 6,
|
||||
|
||||
/** 高级:反转现有伽马校正 */
|
||||
reverse_gamma = 1 << 7
|
||||
};
|
||||
|
||||
enum class line_join_type {
|
||||
// 使用锐边(斜接)连接线段
|
||||
sharp = 0,
|
||||
// 只需将线段拼接在一起
|
||||
simple = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* 枚举色觉缺陷类型。
|
||||
*/
|
||||
enum class color_vision_deficiency {
|
||||
normal_vision, // 正常视觉,
|
||||
deuteranope, // 绿色盲/弱 (男性7%,女性0.4%)
|
||||
protanope, // 红色盲/弱 (男性2%,女性0.01%)
|
||||
tritanope, // 蓝色盲/弱 (男性0.0003%)
|
||||
};
|
||||
|
||||
enum class mirage_vertex_rounding
|
||||
{
|
||||
disabled,
|
||||
enabled
|
||||
};
|
||||
|
||||
struct mirage_pixel_params {
|
||||
union {
|
||||
float x;
|
||||
float r;
|
||||
};
|
||||
union {
|
||||
float y;
|
||||
float g;
|
||||
};
|
||||
union {
|
||||
float z;
|
||||
float b;
|
||||
};
|
||||
union {
|
||||
float w;
|
||||
float a;
|
||||
};
|
||||
mirage_pixel_params(float in_x, float in_y, float in_z, float in_w) : x(in_x), y(in_y), z(in_z), w(in_w) {}
|
||||
mirage_pixel_params(const LLGL::ColorRGBAf& in) : r(in.r), g(in.g), b(in.b), a(in.a) {}
|
||||
mirage_pixel_params(const LLGL::Offset2D& in) : x(in.x), y(in.y), z(0), w(0) {}
|
||||
mirage_pixel_params(const LLGL::Extent2D& in) : x(in.width), y(in.height), z(0), w(0) {}
|
||||
mirage_pixel_params(const LLGL::Offset3D& in) : x(in.x), y(in.y), z(in.z), w(0) {}
|
||||
mirage_pixel_params(const LLGL::Extent3D& in) : x(in.width), y(in.height), z(in.depth), w(0) {}
|
||||
mirage_pixel_params(const Eigen::Vector2f& in) : x(in.x()), y(in.y()), z(0), w(0) {}
|
||||
mirage_pixel_params(const Eigen::Vector3f& in) : x(in.x()), y(in.y()), z(in.z()), w(0) {}
|
||||
mirage_pixel_params(const Eigen::Vector4f& in) : x(in.x()), y(in.y()), z(in.z()), w(in.w()) {}
|
||||
|
||||
bool operator==(const mirage_pixel_params& in_other) const {
|
||||
return x == in_other.x && y == in_other.y && z == in_other.z && w == in_other.w;
|
||||
}
|
||||
};
|
||||
|
||||
struct mirage_shader_params {
|
||||
mirage_pixel_params pixel_params;
|
||||
mirage_pixel_params pixel_params2;
|
||||
mirage_pixel_params pixel_params3;
|
||||
|
||||
bool operator==(const mirage_shader_params& in_other) const {
|
||||
return pixel_params == in_other.pixel_params && pixel_params2 == in_other.pixel_params2 && pixel_params3 == in_other.pixel_params3;
|
||||
}
|
||||
};
|
||||
|
||||
struct mirage_vertex {
|
||||
// 纹理坐标 xy zw
|
||||
float tex_coords[4];
|
||||
// 纹理坐标用作自定义纹理的材质的传递
|
||||
Eigen::Vector2f material_tex_coords;
|
||||
// 顶点在窗口中的位置
|
||||
Eigen::Vector2f position;
|
||||
// 顶点颜色
|
||||
color_type color;
|
||||
// 次顶点颜色 一般用于轮廓
|
||||
color_type secondary_color;
|
||||
// 元素的局部大小
|
||||
uint16_t pixel_size[2];
|
||||
|
||||
public:
|
||||
template <mirage_vertex_rounding Rounding>
|
||||
static mirage_vertex make(const transform_type& in_render_transform, const Eigen::Vector2f& in_local_position, const Eigen::Vector2f& in_tex_coord, const Eigen::Vector2f& in_tex_coord2, const color_type& in_color, const color_type& in_secondary_color = {}) {
|
||||
mirage_vertex vertex{};
|
||||
vertex.set_tex_coords(Eigen::Vector4f{in_tex_coord, in_tex_coord2});
|
||||
vertex.init_common<Rounding>(in_render_transform, in_local_position, in_color, in_secondary_color);
|
||||
|
||||
return vertex;
|
||||
}
|
||||
|
||||
template <mirage_vertex_rounding Rounding>
|
||||
static mirage_vertex make(const transform_type& in_render_transform, const Eigen::Vector2f& in_local_position, const Eigen::Vector2f& in_tex_coord, const color_type& in_color, const color_type& in_secondary_color = {}) {
|
||||
mirage_vertex vertex{};
|
||||
vertex.set_tex_coords(in_tex_coord);
|
||||
vertex.init_common<Rounding>(in_render_transform, in_local_position, in_color, in_secondary_color);
|
||||
|
||||
return vertex;
|
||||
}
|
||||
|
||||
|
||||
template <mirage_vertex_rounding Rounding>
|
||||
static mirage_vertex make(const transform_type& in_render_transform, const Eigen::Vector2f& in_local_position, const Eigen::Vector4f& in_tex_coord, const color_type& in_color, const color_type& in_secondary_color = {}) {
|
||||
mirage_vertex vertex{};
|
||||
vertex.set_tex_coords(in_tex_coord);
|
||||
vertex.init_common<Rounding>(in_render_transform, in_local_position, in_color, in_secondary_color);
|
||||
|
||||
return vertex;
|
||||
}
|
||||
|
||||
template <mirage_vertex_rounding Rounding>
|
||||
static mirage_vertex make(const transform_type& in_render_transform, const Eigen::Vector2f& in_local_position, const Eigen::Vector2f& in_local_size, float in_scale, const Eigen::Vector4f& in_tex_coord, const color_type& in_color, const color_type& in_secondary_color = {}) {
|
||||
mirage_vertex vertex{};
|
||||
vertex.set_tex_coords(in_tex_coord);
|
||||
|
||||
vertex.material_tex_coords = in_local_position.array() / in_local_size.array();
|
||||
vertex.init_common<Rounding>(in_render_transform, in_local_position, in_color, in_secondary_color);
|
||||
|
||||
const Eigen::Vector2i temp_pixel_size = in_local_size * in_scale;
|
||||
vertex.pixel_size[0] = static_cast<uint16_t>(temp_pixel_size.x());
|
||||
vertex.pixel_size[1] = static_cast<uint16_t>(temp_pixel_size.y());
|
||||
return vertex;
|
||||
}
|
||||
|
||||
static mirage_vertex make(const transform_type& in_render_transform, const Eigen::Vector2f& in_local_position, const Eigen::Vector2f& in_tex_coord, const Eigen::Vector2f& in_tex_coord2, const color_type& in_color, const color_type& in_secondary_color = {}, mirage_vertex_rounding in_rounding = mirage_vertex_rounding::disabled) {
|
||||
return in_rounding == mirage_vertex_rounding::enabled
|
||||
? make<mirage_vertex_rounding::enabled>(in_render_transform, in_local_position, in_tex_coord, in_tex_coord2, in_color, in_secondary_color)
|
||||
: make<mirage_vertex_rounding::disabled>(in_render_transform, in_local_position, in_tex_coord,in_tex_coord2, in_color, in_secondary_color);
|
||||
}
|
||||
static mirage_vertex make(const transform_type& in_render_transform, const Eigen::Vector2f& in_local_position, const Eigen::Vector2f& in_tex_coord, const color_type& in_color, const color_type& in_secondary_color = {}, mirage_vertex_rounding in_rounding = mirage_vertex_rounding::disabled) {
|
||||
return in_rounding == mirage_vertex_rounding::enabled
|
||||
? make<mirage_vertex_rounding::enabled>(in_render_transform, in_local_position, in_tex_coord, in_color, in_secondary_color)
|
||||
: make<mirage_vertex_rounding::disabled>(in_render_transform, in_local_position, in_tex_coord, in_color, in_secondary_color);
|
||||
}
|
||||
static mirage_vertex make(const transform_type& in_render_transform, const Eigen::Vector2f& in_local_position, const Eigen::Vector4f& in_tex_coord, const color_type& in_color, const color_type& in_secondary_color = {}, mirage_vertex_rounding in_rounding = mirage_vertex_rounding::disabled) {
|
||||
return in_rounding == mirage_vertex_rounding::enabled
|
||||
? make<mirage_vertex_rounding::enabled>(in_render_transform, in_local_position, in_tex_coord, in_color, in_secondary_color)
|
||||
: make<mirage_vertex_rounding::disabled>(in_render_transform, in_local_position, in_tex_coord, in_color, in_secondary_color);
|
||||
}
|
||||
static mirage_vertex make(const transform_type& in_render_transform, const Eigen::Vector2f& in_local_position, const Eigen::Vector2f& in_local_size, float in_scale, const Eigen::Vector4f& in_tex_coord, const color_type& in_color, const color_type& in_secondary_color = {},
|
||||
mirage_vertex_rounding in_rounding = mirage_vertex_rounding::disabled) {
|
||||
return in_rounding == mirage_vertex_rounding::enabled
|
||||
? make<mirage_vertex_rounding::enabled>(in_render_transform, in_local_position, in_local_size, in_scale, in_tex_coord, in_color, in_secondary_color)
|
||||
: make<mirage_vertex_rounding::disabled>(in_render_transform, in_local_position, in_local_size, in_scale, in_tex_coord, in_color, in_secondary_color);
|
||||
}
|
||||
|
||||
void set_tex_coords(const Eigen::Vector4f& in_coords) {
|
||||
tex_coords[0] = in_coords.x();
|
||||
tex_coords[1] = in_coords.y();
|
||||
tex_coords[2] = in_coords.z();
|
||||
tex_coords[3] = in_coords.w();
|
||||
}
|
||||
void set_tex_coords(const Eigen::Vector2f& in_coords) {
|
||||
tex_coords[0] = in_coords.x();
|
||||
tex_coords[1] = in_coords.y();
|
||||
tex_coords[2] = 1.f;
|
||||
tex_coords[3] = 1.f;
|
||||
}
|
||||
|
||||
void set_position(const Eigen::Vector2f& in_position) {
|
||||
position = in_position;
|
||||
}
|
||||
private:
|
||||
template <mirage_vertex_rounding Rounding>
|
||||
void init_common(const transform_type& in_render_transform, const Eigen::Vector2f& in_local_position, const color_type& in_color, const color_type& in_secondary_color) {
|
||||
position = in_render_transform * in_local_position;
|
||||
if constexpr (Rounding == mirage_vertex_rounding::enabled) {
|
||||
position = position.array().round().matrix();
|
||||
}
|
||||
color = in_color;
|
||||
secondary_color = in_secondary_color;
|
||||
}
|
||||
};
|
||||
}
|
@ -3,15 +3,15 @@
|
||||
cbuffer ParamBuffer : register(b0)
|
||||
{
|
||||
matrix transform;
|
||||
float2 size; // 矩形大小 像素单位
|
||||
float2 pos; // 矩形位置 像素单位
|
||||
float4 radius; // 四角圆角像素单位 左上 右上 左下 右下
|
||||
};
|
||||
|
||||
struct PSInput {
|
||||
float4 position : SV_POSITION; // 裁剪空间坐标
|
||||
float2 uv : TEXCOORD0; // 纹理坐标
|
||||
float4 color : COLOR; // 颜色
|
||||
|
||||
float2 size : TEXCOORD1; // 矩形大小 像素单位
|
||||
float4 radius : TEXCOORD3; // 四角圆角像素单位 左上 右上 左下 右下
|
||||
};
|
||||
|
||||
[shader("vertex")]
|
||||
@ -21,10 +21,12 @@ PSInput vertex_main(VSInput input)
|
||||
output.position = mul(float4(input.position, 0.0, 1.0), transform);
|
||||
output.uv = input.uv;
|
||||
output.color = input.color;
|
||||
output.size = input.param_a.xy;
|
||||
output.radius = input.param_b;
|
||||
return output;
|
||||
}
|
||||
|
||||
float distance_from_rect_uv(float2 p, float corner_radius) {
|
||||
float distance_from_rect_uv(float2 p, float2 size, float corner_radius) {
|
||||
corner_radius *= 2;
|
||||
float2 corner_radius_uv = corner_radius / size;
|
||||
float2 inner_rect = float2(1) - corner_radius_uv; // 圆心
|
||||
@ -41,8 +43,8 @@ float4 pixel_main(PSInput input) : SV_Target
|
||||
// 象限
|
||||
int2 quadrant = sign(p);
|
||||
int idx = (quadrant.x > 0 ? 1 : 0) + (quadrant.y > 0 ? 2 : 0);
|
||||
float r = radius[idx];
|
||||
float d = distance_from_rect_uv(p, r);
|
||||
float r = input.radius[idx];
|
||||
float d = distance_from_rect_uv(p, input.size, r);
|
||||
|
||||
float edge_width = fwidth(d);
|
||||
// 根据dd计算抗锯齿
|
||||
|
Loading…
x
Reference in New Issue
Block a user