绘制功能
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,3 +2,4 @@
|
|||||||
/cmake-build-release
|
/cmake-build-release
|
||||||
/.idea
|
/.idea
|
||||||
/scripts/shader_paths.txt
|
/scripts/shader_paths.txt
|
||||||
|
/cache/shader_loader.h
|
||||||
|
|||||||
@@ -12,6 +12,11 @@ message(STATUS "Python解释器: ${PYTHON_EXECUTABLE}")
|
|||||||
message(STATUS "SLANG编译器: ${SLANG_COMPILER}")
|
message(STATUS "SLANG编译器: ${SLANG_COMPILER}")
|
||||||
|
|
||||||
set(SHADER_PATH_FILE ${CMAKE_CURRENT_SOURCE_DIR}/scripts/shader_paths.txt)
|
set(SHADER_PATH_FILE ${CMAKE_CURRENT_SOURCE_DIR}/scripts/shader_paths.txt)
|
||||||
|
set(SHADER_HEADER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/cache)
|
||||||
|
set(SHADER_HEADER_FILE ${SHADER_HEADER_DIR}/shader_loader.h)
|
||||||
|
# 创建文件
|
||||||
|
file(WRITE ${SHADER_HEADER_FILE} "")
|
||||||
|
|
||||||
# 删除文件
|
# 删除文件
|
||||||
file(REMOVE ${SHADER_PATH_FILE})
|
file(REMOVE ${SHADER_PATH_FILE})
|
||||||
|
|
||||||
@@ -45,7 +50,7 @@ message(STATUS "着色器编译输出路径: ${SHADER_OUTPUT_DIR}")
|
|||||||
|
|
||||||
# 添加自定义命令, 用于编译着色器, 调用scripts/compile_shaders.py
|
# 添加自定义命令, 用于编译着色器, 调用scripts/compile_shaders.py
|
||||||
add_custom_target(compile_shaders
|
add_custom_target(compile_shaders
|
||||||
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/scripts/compile_shaders.py --shader-list ${SHADER_PATH_FILE} --output-dir ${SHADER_OUTPUT_DIR} ${SLANGC_ARGS}
|
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/scripts/compile_shaders.py --header ${SHADER_HEADER_FILE} --shader-list ${SHADER_PATH_FILE} --output-dir ${SHADER_OUTPUT_DIR} ${SLANGC_ARGS}
|
||||||
COMMENT "编译着色器"
|
COMMENT "编译着色器"
|
||||||
VERBATIM
|
VERBATIM
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
from typing import List, Tuple, Iterator, Optional
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from typing import List, Tuple, Iterator
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import argparse
|
import argparse
|
||||||
import subprocess
|
import subprocess
|
||||||
@@ -6,21 +9,26 @@ import sys
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
# 设置控制台输出编码
|
# 设置控制台输出编码
|
||||||
if sys.platform.startswith('win'):
|
# if sys.platform.startswith('win'):
|
||||||
# Windows系统下设置
|
# # Windows系统下设置
|
||||||
sys.stdout.reconfigure(encoding='utf-8')
|
# sys.stdout.reconfigure(encoding='utf-8')
|
||||||
sys.stderr.reconfigure(encoding='utf-8')
|
# sys.stderr.reconfigure(encoding='utf-8')
|
||||||
|
|
||||||
def print_utf8(message: str):
|
def print_utf8(message: str):
|
||||||
"""
|
"""以UTF-8编码打印消息"""
|
||||||
以UTF-8编码打印消息
|
print(message)
|
||||||
|
|
||||||
Args:
|
# 着色器类型和扩展名定义
|
||||||
message: 要打印的消息
|
SHADER_TYPES = {
|
||||||
"""
|
'vertex': 'LLGL::ShaderType::Vertex',
|
||||||
print(message.encode('utf-8').decode(sys.stdout.encoding))
|
'pixel': 'LLGL::ShaderType::Fragment',
|
||||||
|
'fragment': 'LLGL::ShaderType::Fragment',
|
||||||
|
'compute': 'LLGL::ShaderType::Compute',
|
||||||
|
'geometry': 'LLGL::ShaderType::Geometry',
|
||||||
|
'tess_control': 'LLGL::ShaderType::TessControl',
|
||||||
|
'tess_evaluation': 'LLGL::ShaderType::TessEvaluation'
|
||||||
|
}
|
||||||
|
|
||||||
# 常量定义
|
|
||||||
SHADER_EXTENSIONS = {
|
SHADER_EXTENSIONS = {
|
||||||
'glsl': 'glsl',
|
'glsl': 'glsl',
|
||||||
'spirv': 'spirv',
|
'spirv': 'spirv',
|
||||||
@@ -34,104 +42,87 @@ SHADER_EXTENSIONS = {
|
|||||||
TARGET_PROFILES = {
|
TARGET_PROFILES = {
|
||||||
'glsl': ['-profile', 'glsl_460'],
|
'glsl': ['-profile', 'glsl_460'],
|
||||||
'spirv': ['-profile', 'glsl_460', '-capability', 'glsl_spirv_1_6'],
|
'spirv': ['-profile', 'glsl_460', '-capability', 'glsl_spirv_1_6'],
|
||||||
'dxbc': ['-profile', 'sm_5_1'],
|
'dxbc': ['-profile', 'sm_5_0'],
|
||||||
'dxil': ['-profile', 'sm_6_6'],
|
'dxil': ['-profile', 'sm_6_6'],
|
||||||
'metallib': ['-capability', 'metallib_3_1']
|
'metallib': ['-capability', 'metallib_3_1']
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ShaderEntry:
|
||||||
|
"""着色器入口点信息"""
|
||||||
|
def __init__(self, name: str, shader_type: str):
|
||||||
|
self.name = name
|
||||||
|
self.shader_type = shader_type
|
||||||
|
|
||||||
|
class CompiledShaderInfo:
|
||||||
|
"""编译后的着色器信息"""
|
||||||
|
def __init__(self, output_file: str, base: str, entry: ShaderEntry):
|
||||||
|
self.output_file = output_file
|
||||||
|
self.base = base
|
||||||
|
self.entry = entry
|
||||||
|
if entry.shader_type == 'pixel':
|
||||||
|
self.entry.shader_type = 'fragment'
|
||||||
|
|
||||||
|
# 存放所有编译成功的着色器信息
|
||||||
|
compiled_shaders: List[CompiledShaderInfo] = []
|
||||||
|
|
||||||
def find_shader_files(input_dir: Path, extensions: List[str]) -> Iterator[Path]:
|
def find_shader_files(input_dir: Path, extensions: List[str]) -> Iterator[Path]:
|
||||||
"""
|
"""递归查找指定目录下的着色器文件"""
|
||||||
递归查找指定目录下的着色器文件
|
|
||||||
|
|
||||||
Args:
|
|
||||||
input_dir: 输入目录路径
|
|
||||||
extensions: 着色器文件扩展名列表
|
|
||||||
|
|
||||||
Yields:
|
|
||||||
符合扩展名的着色器文件路径
|
|
||||||
"""
|
|
||||||
for file_path in Path(input_dir).rglob('*'):
|
for file_path in Path(input_dir).rglob('*'):
|
||||||
if file_path.suffix in extensions:
|
if file_path.suffix in extensions:
|
||||||
yield file_path
|
yield file_path
|
||||||
|
|
||||||
def find_slang_entries(input_file: Path) -> List[str]:
|
def find_slang_entries(input_file: Path) -> List[ShaderEntry]:
|
||||||
"""
|
"""从着色器文件中提取入口点函数名和类型"""
|
||||||
从着色器文件中提取入口点函数名
|
# 匹配 [shader("xxx")] 形式的着色器类型声明,以及后面的函数名
|
||||||
|
pattern = re.compile(
|
||||||
Args:
|
r'\[\s*shader\s*\(\s*"([^"]+)"\s*\)\s*\]\s*' # 匹配 [shader("xxx")]
|
||||||
input_file: 着色器文件路径
|
r'(?:\[\s*[^\]]+\])*' # 可选:匹配其他属性如 [numthreads(8,8,1)]
|
||||||
|
r'\s*\w+\s+(\w+)\s*\(' # 匹配函数声明:返回类型 函数名(
|
||||||
Returns:
|
)
|
||||||
入口点函数名列表
|
|
||||||
"""
|
|
||||||
# 匹配 [shader("xxx")] 形式的着色器入口点声明
|
|
||||||
pattern = re.compile(r'\[shader\(\s*"(?:\w+)"\s*\)\]\s*\n\s*\w+\s+(\w+)\s*\(')
|
|
||||||
try:
|
try:
|
||||||
content = input_file.read_text(encoding='utf-8')
|
content = input_file.read_text(encoding='utf-8')
|
||||||
return list(set(pattern.findall(content)))
|
matches = pattern.findall(content)
|
||||||
|
print_utf8(f"**调试**: 在文件 {input_file} 中找到的匹配: {matches}")
|
||||||
|
|
||||||
|
entries = []
|
||||||
|
for shader_type, name in matches:
|
||||||
|
if shader_type in SHADER_TYPES:
|
||||||
|
entries.append(ShaderEntry(name, shader_type))
|
||||||
|
else:
|
||||||
|
print_utf8(f"**警告**: 未知的着色器类型 {shader_type}")
|
||||||
|
return entries
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print_utf8(f"**错误**: 解析文件 {input_file} 失败: {e}")
|
print_utf8(f"**错误**: 解析文件 {input_file} 失败: {e}")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
def get_shader_extension(build_type: str) -> str:
|
def get_shader_extension(build_type: str) -> str:
|
||||||
"""
|
"""根据构建类型获取对应的着色器文件扩展名"""
|
||||||
根据构建类型获取对应的着色器文件扩展名
|
|
||||||
|
|
||||||
Args:
|
|
||||||
build_type: 构建类型
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
对应的文件扩展名
|
|
||||||
"""
|
|
||||||
return SHADER_EXTENSIONS.get(build_type, 'dat')
|
return SHADER_EXTENSIONS.get(build_type, 'dat')
|
||||||
|
|
||||||
def create_compiler_command(
|
def create_compiler_command(
|
||||||
input_file: Path,
|
input_file: Path,
|
||||||
entry: str,
|
entry: ShaderEntry,
|
||||||
output_file: Path,
|
output_file: Path,
|
||||||
target_type: str,
|
target_type: str,
|
||||||
args: argparse.Namespace
|
args: argparse.Namespace
|
||||||
) -> List[str]:
|
) -> List[str]:
|
||||||
"""
|
"""生成着色器编译命令"""
|
||||||
生成着色器编译命令
|
|
||||||
|
|
||||||
Args:
|
|
||||||
input_file: 输入文件路径
|
|
||||||
entry: 着色器入口点
|
|
||||||
output_file: 输出文件路径
|
|
||||||
target_type: 目标平台类型
|
|
||||||
args: 命令行参数
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
编译命令列表
|
|
||||||
"""
|
|
||||||
cmd = [args.slangc,
|
cmd = [args.slangc,
|
||||||
str(input_file),
|
str(input_file),
|
||||||
"-entry", entry,
|
"-entry", entry.name,
|
||||||
"-o", str(output_file),
|
"-o", str(output_file),
|
||||||
"-target", target_type,
|
"-target", target_type,
|
||||||
"-g3" if args.debug else "-O3"
|
"-g3" if args.debug else "-O3",
|
||||||
]
|
]
|
||||||
|
|
||||||
# 添加优化或调试标志
|
|
||||||
|
|
||||||
# 添加目标平台特定的编译选项
|
|
||||||
if target_type in TARGET_PROFILES:
|
if target_type in TARGET_PROFILES:
|
||||||
cmd.extend(TARGET_PROFILES[target_type])
|
cmd.extend(TARGET_PROFILES[target_type])
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
|
|
||||||
def needs_recompile(input_file: Path, output_file: Path) -> bool:
|
def needs_recompile(input_file: Path, output_file: Path) -> bool:
|
||||||
"""
|
"""检查是否需要重新编译着色器"""
|
||||||
检查是否需要重新编译着色器
|
|
||||||
|
|
||||||
Args:
|
|
||||||
input_file: 输入文件路径
|
|
||||||
output_file: 输出文件路径
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
是否需要重新编译
|
|
||||||
"""
|
|
||||||
if not output_file.exists():
|
if not output_file.exists():
|
||||||
return True
|
return True
|
||||||
try:
|
try:
|
||||||
@@ -140,74 +131,287 @@ def needs_recompile(input_file: Path, output_file: Path) -> bool:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def compile_shader(
|
def compile_shader(
|
||||||
input_file: Path,
|
input_file: Path,
|
||||||
target_types: List[Tuple[str, bool]],
|
target_types: List[Tuple[str, bool]],
|
||||||
output_dir: Path,
|
output_dir: Path,
|
||||||
args: argparse.Namespace
|
args: argparse.Namespace
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""
|
"""编译单个着色器文件"""
|
||||||
编译单个着色器文件
|
|
||||||
|
|
||||||
Args:
|
|
||||||
input_file: 输入文件路径
|
|
||||||
target_types: 目标平台类型列表
|
|
||||||
output_dir: 输出目录
|
|
||||||
args: 命令行参数
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
编译是否成功
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
# 获取着色器入口点
|
|
||||||
entries = find_slang_entries(input_file)
|
entries = find_slang_entries(input_file)
|
||||||
if not entries:
|
if not entries:
|
||||||
print_utf8(f"**跳过**: {input_file} - 未找到着色器入口点")
|
print_utf8(f"**跳过**: {input_file} - 未找到着色器入口点")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# 创建输出目录
|
|
||||||
output_dir.mkdir(parents=True, exist_ok=True)
|
output_dir.mkdir(parents=True, exist_ok=True)
|
||||||
base = input_file.stem
|
base = input_file.stem
|
||||||
success = True
|
success = True
|
||||||
|
|
||||||
# 针对每个目标平台编译
|
|
||||||
|
for entry in entries:
|
||||||
|
compiled_shaders.append(CompiledShaderInfo(f"{base}_{entry.name}", base, entry))
|
||||||
|
|
||||||
for target_type, enabled in target_types:
|
for target_type, enabled in target_types:
|
||||||
if not enabled:
|
if not enabled:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for entry in entries:
|
for entry in entries:
|
||||||
output_file = output_dir / f"{base}_{entry}.{get_shader_extension(target_type)}"
|
output_file = output_dir / f"{base}_{entry.name}.{get_shader_extension(target_type)}"
|
||||||
|
|
||||||
# 检查是否需要重新编译
|
|
||||||
if not needs_recompile(input_file, output_file):
|
if not needs_recompile(input_file, output_file):
|
||||||
print_utf8(f"**跳过**: {output_file} - 文件已是最新")
|
print_utf8(f"**跳过**: {output_file} - 文件已是最新")
|
||||||
continue
|
else:
|
||||||
|
cmd = create_compiler_command(input_file, entry, output_file, target_type, args)
|
||||||
# 执行编译
|
try:
|
||||||
cmd = create_compiler_command(input_file, entry, output_file, target_type, args)
|
subprocess.run(cmd, check=True, capture_output=True, text=True)
|
||||||
try:
|
print_utf8(f"**成功**: 编译 {input_file}:{entry.name} -> {output_file}")
|
||||||
result = subprocess.run(cmd, check=True, capture_output=True, text=True)
|
except subprocess.CalledProcessError as e:
|
||||||
print_utf8(f"**成功**: 编译 {input_file}:{entry} -> {output_file}")
|
print_utf8(f"**错误**: 编译 {input_file}:{entry.name} 失败")
|
||||||
except subprocess.CalledProcessError as e:
|
print_utf8(e.stderr)
|
||||||
print_utf8(f"**错误**: 编译 {input_file}:{entry} 失败")
|
success = False
|
||||||
print_utf8(e.stderr)
|
continue
|
||||||
success = False
|
|
||||||
|
|
||||||
return success
|
return success
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print_utf8(f"**错误**: 处理 {input_file} 时发生异常: {e}")
|
print_utf8(f"**错误**: 处理 {input_file} 时发生异常: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def generate_pipeline_header_preamble() -> List[str]:
|
||||||
|
"""Generate the header file preamble"""
|
||||||
|
|
||||||
|
return [
|
||||||
|
"#pragma once",
|
||||||
|
"",
|
||||||
|
"#include \"mirage.h\"",
|
||||||
|
"#include \"misc/mirage_type.h\"",
|
||||||
|
"#include <LLGL/LLGL.h>",
|
||||||
|
"#include <LLGL/Utils/VertexFormat.h>",
|
||||||
|
"#include <memory>",
|
||||||
|
"#include <string>",
|
||||||
|
"#include <vector>",
|
||||||
|
"#include <fstream>",
|
||||||
|
"#include <stdexcept>",
|
||||||
|
"",
|
||||||
|
"namespace generated_pipelines {",
|
||||||
|
"",
|
||||||
|
"// 辅助函数:加载着色器",
|
||||||
|
"inline auto LoadShader(",
|
||||||
|
" LLGL::RenderSystem* renderer,",
|
||||||
|
" const std::string& filename,",
|
||||||
|
" const LLGL::ShaderType type,",
|
||||||
|
" const char* entryPoint,",
|
||||||
|
" const LLGL::ShaderDescriptor& shaderDesc = {}) {",
|
||||||
|
"",
|
||||||
|
" // 根据渲染器类型选择着色器文件后缀",
|
||||||
|
" auto rendererID = renderer->GetRendererID();",
|
||||||
|
" std::string ext;",
|
||||||
|
" // 选择对应的文件扩展名",
|
||||||
|
" if (rendererID == LLGL::RendererID::OpenGL) {",
|
||||||
|
" ext = \".glsl\";",
|
||||||
|
" } else if (rendererID == LLGL::RendererID::Vulkan) {",
|
||||||
|
" ext = \".spirv\";",
|
||||||
|
" } else if (rendererID == LLGL::RendererID::Direct3D11) {",
|
||||||
|
" ext = \".dxbc\";",
|
||||||
|
" } else if (rendererID == LLGL::RendererID::Direct3D12) {",
|
||||||
|
" ext = \".dxil\";",
|
||||||
|
" } else if (rendererID == LLGL::RendererID::Metal) {",
|
||||||
|
" ext = \".metallib\";",
|
||||||
|
" } else {",
|
||||||
|
" ext = \".dat\";",
|
||||||
|
" }",
|
||||||
|
"",
|
||||||
|
" // 构造最终的文件名",
|
||||||
|
" std::string finalFilename = filename;",
|
||||||
|
" size_t pos = finalFilename.find_last_of('.');",
|
||||||
|
" if (pos != std::string::npos) {",
|
||||||
|
" finalFilename = finalFilename.substr(0, pos) + ext;",
|
||||||
|
" } else {",
|
||||||
|
" finalFilename += ext;",
|
||||||
|
" }",
|
||||||
|
" finalFilename = (mirage::get_shader_path() / finalFilename).string();",
|
||||||
|
"",
|
||||||
|
" // 读取着色器文件",
|
||||||
|
" std::vector<char> shaderData;",
|
||||||
|
" try {",
|
||||||
|
" std::ifstream file(finalFilename, std::ios::binary | std::ios::ate);",
|
||||||
|
" if (!file.is_open()) {",
|
||||||
|
" throw std::runtime_error(\"Failed to open shader file: \" + finalFilename);",
|
||||||
|
" }",
|
||||||
|
" size_t fileSize = static_cast<size_t>(file.tellg());",
|
||||||
|
" shaderData.resize(fileSize);",
|
||||||
|
" file.seekg(0);",
|
||||||
|
" file.read(shaderData.data(), fileSize);",
|
||||||
|
" } catch (const std::exception& e) {",
|
||||||
|
" throw std::runtime_error(\"Failed to read shader file: \" + std::string(e.what()));",
|
||||||
|
" }",
|
||||||
|
"",
|
||||||
|
" // 创建着色器",
|
||||||
|
" LLGL::ShaderDescriptor desc = shaderDesc;",
|
||||||
|
" desc.source = shaderData.data();",
|
||||||
|
" desc.sourceSize = shaderData.size();",
|
||||||
|
" desc.entryPoint = entryPoint;",
|
||||||
|
" desc.type = type;",
|
||||||
|
" desc.sourceType = rendererID == LLGL::RendererID::OpenGL ? LLGL::ShaderSourceType::CodeString : LLGL::ShaderSourceType::BinaryBuffer;",
|
||||||
|
"",
|
||||||
|
" auto shader = renderer->CreateShader(desc);",
|
||||||
|
" if (auto report = shader->GetReport()) {",
|
||||||
|
" spdlog::error(\"Shader compilation report: {}\", report->GetText());",
|
||||||
|
" }",
|
||||||
|
" return mirage::shader_ptr(shader, mirage::llgl_deleter<LLGL::Shader>);",
|
||||||
|
"}",
|
||||||
|
""
|
||||||
|
"inline auto create_pipeline_layout(LLGL::RenderSystem* renderer, const LLGL::PipelineLayoutDescriptor& in_desc) {",
|
||||||
|
" auto pipelineLayout = renderer->CreatePipelineLayout(in_desc);",
|
||||||
|
" return mirage::pipeline_layout_ptr(pipelineLayout, mirage::llgl_deleter<LLGL::PipelineLayout>);",
|
||||||
|
"}",
|
||||||
|
]
|
||||||
|
|
||||||
|
def generate_compute_pipeline(header_lines: List[str], shader: CompiledShaderInfo):
|
||||||
|
"""Generate compute pipeline creation function"""
|
||||||
|
func_name = f"create_{shader.base}_{shader.entry.name}_pipeline"
|
||||||
|
|
||||||
|
header_lines.extend([
|
||||||
|
f"// 计算管线: {shader.base} - {shader.entry.name}",
|
||||||
|
f"inline auto {func_name}(LLGL::RenderSystem* renderer) {{",
|
||||||
|
" // 加载计算着色器",
|
||||||
|
f" auto computeShader = LoadShader(renderer, \"{shader.output_file.name}\", {SHADER_TYPES['compute']}, \"{shader.entry.name}\");",
|
||||||
|
"",
|
||||||
|
" // 创建管线布局",
|
||||||
|
" LLGL::PipelineLayoutDescriptor layoutDesc;",
|
||||||
|
" auto pipelineLayout = create_pipeline_layout(renderer, layoutDesc);",
|
||||||
|
"",
|
||||||
|
" // 创建计算管线",
|
||||||
|
" LLGL::ComputePipelineDescriptor pipelineDesc;",
|
||||||
|
" pipelineDesc.computeShader = computeShader.get();",
|
||||||
|
" pipelineDesc.pipelineLayout = pipelineLayout.get();",
|
||||||
|
"",
|
||||||
|
" auto pipeline = renderer->CreatePipelineState(pipelineDesc);",
|
||||||
|
" mirage::pipeline_info info;",
|
||||||
|
" info.pipeline_state = mirage::pipeline_state_ptr(pipeline, mirage::llgl_deleter<LLGL::PipelineState>);",
|
||||||
|
" info.pipeline_layout = pipelineLayout;",
|
||||||
|
" info.shaders = {computeShader};",
|
||||||
|
" return info;",
|
||||||
|
"}",
|
||||||
|
""
|
||||||
|
])
|
||||||
|
|
||||||
|
def generate_graphics_pipeline(header_lines: List[str], base: str, shaders: List[CompiledShaderInfo]):
|
||||||
|
"""Generate graphics pipeline creation function"""
|
||||||
|
func_name = f"create_{base}_pipeline"
|
||||||
|
|
||||||
|
header_lines.extend([
|
||||||
|
f"// 图形管线: {base}",
|
||||||
|
f"inline auto {func_name}(LLGL::RenderSystem* renderer, const LLGL::RenderPass* render_pass, const LLGL::PipelineLayoutDescriptor& in_pipeline_layout_desc, const LLGL::VertexFormat& vertex_format = mirage::create_vertex_format()) {{",
|
||||||
|
f" // 加载各个阶段的着色器",
|
||||||
|
f" LLGL::ShaderDescriptor vertexShaderDesc, fragShaderDesc;",
|
||||||
|
f" vertexShaderDesc.vertex.inputAttribs = vertex_format.attributes;",
|
||||||
|
])
|
||||||
|
|
||||||
|
SHADER_DESC_NAME = {
|
||||||
|
'vertex': 'vertexShaderDesc',
|
||||||
|
'pixel': 'fragShaderDesc',
|
||||||
|
'fragment': 'fragShaderDesc',
|
||||||
|
}
|
||||||
|
|
||||||
|
# Load all shader stages
|
||||||
|
for shader in shaders:
|
||||||
|
shader_type = shader.entry.shader_type
|
||||||
|
if shader_type in SHADER_TYPES:
|
||||||
|
header_lines.append(
|
||||||
|
f" auto {shader_type}Shader = LoadShader(renderer, "
|
||||||
|
f"\"{shader.output_file}\", {SHADER_TYPES[shader_type]}, "
|
||||||
|
f"\"{shader.entry.name}\", {SHADER_DESC_NAME[shader_type]});"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create pipeline layout and descriptor
|
||||||
|
header_lines.extend([
|
||||||
|
" // 创建管线布局",
|
||||||
|
" auto pipelineLayout = create_pipeline_layout(renderer, in_pipeline_layout_desc);",
|
||||||
|
"",
|
||||||
|
" // 创建图形管线",
|
||||||
|
" LLGL::GraphicsPipelineDescriptor pipelineDesc;",
|
||||||
|
])
|
||||||
|
|
||||||
|
# Set all shader stages
|
||||||
|
for shader in shaders:
|
||||||
|
shader_type = shader.entry.shader_type
|
||||||
|
if shader_type in SHADER_TYPES:
|
||||||
|
header_lines.append(f" pipelineDesc.{shader_type}Shader = {shader_type}Shader.get();")
|
||||||
|
|
||||||
|
# Set basic render states
|
||||||
|
header_lines.extend([
|
||||||
|
" pipelineDesc.pipelineLayout = pipelineLayout.get();",
|
||||||
|
"",
|
||||||
|
" // 设置基本渲染状态",
|
||||||
|
" pipelineDesc.renderPass = render_pass;",
|
||||||
|
" pipelineDesc.rasterizer.multiSampleEnabled = true;",
|
||||||
|
" pipelineDesc.blend.targets[0].blendEnabled = true;",
|
||||||
|
" pipelineDesc.depth.testEnabled = true;",
|
||||||
|
" pipelineDesc.depth.writeEnabled = true;",
|
||||||
|
"",
|
||||||
|
" auto pipeline = renderer->CreatePipelineState(pipelineDesc);",
|
||||||
|
])
|
||||||
|
|
||||||
|
# Finish function
|
||||||
|
header_lines.extend([
|
||||||
|
" mirage::pipeline_info info;",
|
||||||
|
" info.pipeline_state = mirage::pipeline_state_ptr(pipeline, mirage::llgl_deleter<LLGL::PipelineState>);",
|
||||||
|
" info.pipeline_layout = pipelineLayout;",
|
||||||
|
" info.shaders = {",
|
||||||
|
])
|
||||||
|
|
||||||
|
for shader in shaders:
|
||||||
|
shader_type = shader.entry.shader_type
|
||||||
|
if shader_type in SHADER_TYPES:
|
||||||
|
header_lines.append(f" {shader_type}Shader,")
|
||||||
|
|
||||||
|
header_lines.append(" };")
|
||||||
|
|
||||||
|
header_lines.extend([
|
||||||
|
" return info;",
|
||||||
|
"}",
|
||||||
|
""
|
||||||
|
])
|
||||||
|
|
||||||
|
def generate_pipeline_header(header_path: Path):
|
||||||
|
"""Generate the complete pipeline header file"""
|
||||||
|
header_lines = generate_pipeline_header_preamble()
|
||||||
|
|
||||||
|
# Group shaders by base name
|
||||||
|
shader_groups = {}
|
||||||
|
for shader in compiled_shaders:
|
||||||
|
if shader.base not in shader_groups:
|
||||||
|
shader_groups[shader.base] = []
|
||||||
|
shader_groups[shader.base].append(shader)
|
||||||
|
|
||||||
|
# Generate pipeline functions
|
||||||
|
for base, shaders in shader_groups.items():
|
||||||
|
has_compute = any(s.entry.shader_type == "compute" for s in shaders)
|
||||||
|
if has_compute:
|
||||||
|
for shader in shaders:
|
||||||
|
if shader.entry.shader_type == "compute":
|
||||||
|
generate_compute_pipeline(header_lines, shader)
|
||||||
|
else:
|
||||||
|
generate_graphics_pipeline(header_lines, base, shaders)
|
||||||
|
|
||||||
|
# Close namespace
|
||||||
|
header_lines.extend([
|
||||||
|
"} // namespace generated_pipelines",
|
||||||
|
""
|
||||||
|
])
|
||||||
|
|
||||||
|
try:
|
||||||
|
header_path.write_text("\n".join(header_lines), encoding="utf-8")
|
||||||
|
print_utf8(f"**成功**: 生成管线 C++ 头文件 {header_path}")
|
||||||
|
except Exception as e:
|
||||||
|
print_utf8(f"**错误**: 写入头文件 {header_path} 失败: {e}")
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""
|
"""主函数:解析命令行参数并执行编译流程"""
|
||||||
主函数:解析命令行参数并执行编译流程
|
|
||||||
"""
|
|
||||||
# 设置UTF-8编码
|
|
||||||
if sys.platform.startswith('win'):
|
if sys.platform.startswith('win'):
|
||||||
# Windows下设置控制台代码页
|
|
||||||
subprocess.run(['chcp', '65001'], shell=True)
|
subprocess.run(['chcp', '65001'], shell=True)
|
||||||
|
|
||||||
# 设置命令行参数
|
parser = argparse.ArgumentParser(description="使用 slangc 编译着色器并生成 LLGL 渲染管线 C++ 头文件")
|
||||||
parser = argparse.ArgumentParser(description="使用 slangc 编译着色器")
|
|
||||||
parser.add_argument("--shader-list", help="着色器列表文件路径")
|
parser.add_argument("--shader-list", help="着色器列表文件路径")
|
||||||
parser.add_argument("--output-dir", help="输出目录")
|
parser.add_argument("--output-dir", help="输出目录")
|
||||||
parser.add_argument("--slangc", default="slangc", help="slangc 编译器路径")
|
parser.add_argument("--slangc", default="slangc", help="slangc 编译器路径")
|
||||||
@@ -217,10 +421,10 @@ def main():
|
|||||||
parser.add_argument("--d3d11", action="store_true", help="编译 D3D11 着色器")
|
parser.add_argument("--d3d11", action="store_true", help="编译 D3D11 着色器")
|
||||||
parser.add_argument("--d3d12", action="store_true", help="编译 D3D12 着色器")
|
parser.add_argument("--d3d12", action="store_true", help="编译 D3D12 着色器")
|
||||||
parser.add_argument("--metal", action="store_true", help="编译 Metal 着色器")
|
parser.add_argument("--metal", action="store_true", help="编译 Metal 着色器")
|
||||||
|
parser.add_argument("--header", help="生成的头文件路径")
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# 配置目标平台
|
|
||||||
target_types = [
|
target_types = [
|
||||||
['glsl', args.opengl],
|
['glsl', args.opengl],
|
||||||
['spirv', args.vulkan],
|
['spirv', args.vulkan],
|
||||||
@@ -229,21 +433,28 @@ def main():
|
|||||||
['metallib', args.metal],
|
['metallib', args.metal],
|
||||||
]
|
]
|
||||||
|
|
||||||
# 设置输出目录和着色器列表文件
|
|
||||||
output_dir = Path(args.output_dir or "shaders")
|
output_dir = Path(args.output_dir or "shaders")
|
||||||
shader_list = Path(args.shader_list or "shader_paths.txt")
|
shader_list = Path(args.shader_list or "shader_paths.txt")
|
||||||
|
|
||||||
# 读取着色器路径列表
|
try:
|
||||||
shader_paths = shader_list.read_text().splitlines()
|
shader_paths = shader_list.read_text(encoding="utf-8").splitlines()
|
||||||
|
except Exception as e:
|
||||||
|
print_utf8(f"**错误**: 读取着色器列表文件 {shader_list} 失败: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
# 编译所有着色器
|
|
||||||
all_success = True
|
all_success = True
|
||||||
for shader_path in shader_paths:
|
for shader_path in shader_paths:
|
||||||
shader_path = shader_path.strip()
|
shader_path = shader_path.strip()
|
||||||
for file in find_shader_files(shader_path, ['.slang']):
|
if not shader_path:
|
||||||
|
continue
|
||||||
|
for file in find_shader_files(Path(shader_path), ['.slang']):
|
||||||
if not compile_shader(file, target_types, output_dir, args):
|
if not compile_shader(file, target_types, output_dir, args):
|
||||||
all_success = False
|
all_success = False
|
||||||
|
|
||||||
|
# 输出到shader_list所在目录
|
||||||
|
header_file = Path(args.header or shader_list.parent / "generated_pipelines.h")
|
||||||
|
generate_pipeline_header(header_file)
|
||||||
|
|
||||||
if not all_success:
|
if not all_success:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|||||||
@@ -29,10 +29,12 @@ find_package(Vulkan REQUIRED)
|
|||||||
|
|
||||||
set(RENDERER_SOURCES "")
|
set(RENDERER_SOURCES "")
|
||||||
retrieve_files(${CMAKE_CURRENT_SOURCE_DIR} RENDERER_SOURCES)
|
retrieve_files(${CMAKE_CURRENT_SOURCE_DIR} RENDERER_SOURCES)
|
||||||
|
# 添加着色器头文件
|
||||||
|
list(APPEND RENDERER_SOURCES ${SHADER_HEADER_FILE})
|
||||||
|
|
||||||
add_library(${PROJECT_NAME} STATIC ${RENDERER_SOURCES})
|
add_library(${PROJECT_NAME} STATIC ${RENDERER_SOURCES})
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC Freetype::Freetype 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_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${SHADER_HEADER_DIR})
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE NOMINMAX)
|
target_compile_definitions(${PROJECT_NAME} PRIVATE NOMINMAX)
|
||||||
add_os_definitions(${PROJECT_NAME})
|
add_os_definitions(${PROJECT_NAME})
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
@@ -44,3 +46,19 @@ endif ()
|
|||||||
shader_compile_target(${CMAKE_CURRENT_SOURCE_DIR}/shaders)
|
shader_compile_target(${CMAKE_CURRENT_SOURCE_DIR}/shaders)
|
||||||
# 添加依赖, 当编译mirage_core时, 会先执行compile_shaders
|
# 添加依赖, 当编译mirage_core时, 会先执行compile_shaders
|
||||||
add_dependencies(${PROJECT_NAME} compile_shaders)
|
add_dependencies(${PROJECT_NAME} compile_shaders)
|
||||||
|
|
||||||
|
if (LLGL_BUILD_RENDERER_OPENGL OR LLGL_BUILD_RENDERER_OPENGLES3 OR LLGL_BUILD_RENDERER_WEBGL)
|
||||||
|
add_dependencies(${PROJECT_NAME} LLGL_OpenGL)
|
||||||
|
endif ()
|
||||||
|
if (LLGL_BUILD_RENDERER_VULKAN)
|
||||||
|
add_dependencies(${PROJECT_NAME} LLGL_Vulkan)
|
||||||
|
endif ()
|
||||||
|
if (LLGL_BUILD_RENDERER_DIRECT3D11)
|
||||||
|
add_dependencies(${PROJECT_NAME} LLGL_Direct3D11)
|
||||||
|
endif ()
|
||||||
|
if (LLGL_BUILD_RENDERER_DIRECT3D12)
|
||||||
|
add_dependencies(${PROJECT_NAME} LLGL_Direct3D12)
|
||||||
|
endif ()
|
||||||
|
if (LLGL_BUILD_RENDERER_METAL)
|
||||||
|
add_dependencies(${PROJECT_NAME} LLGL_Metal)
|
||||||
|
endif ()
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ mirage::duration_type delta_time = {};
|
|||||||
mirage::time_type begin_time = {};
|
mirage::time_type begin_time = {};
|
||||||
mirage::time_type last_time = {};
|
mirage::time_type last_time = {};
|
||||||
LLGL::RenderSystemPtr renderer = nullptr;
|
LLGL::RenderSystemPtr renderer = nullptr;
|
||||||
|
uint64_t frame_index = 0;
|
||||||
|
std::filesystem::path shader_path = "resource/shaders";
|
||||||
|
|
||||||
namespace mirage {
|
namespace mirage {
|
||||||
void on_llgl_log(LLGL::Log::ReportType type, const char* text, void* user_data) {
|
void on_llgl_log(LLGL::Log::ReportType type, const char* text, void* user_data) {
|
||||||
@@ -128,6 +130,7 @@ namespace mirage {
|
|||||||
}
|
}
|
||||||
while (!should_exit()) {
|
while (!should_exit()) {
|
||||||
update();
|
update();
|
||||||
|
frame_index++;
|
||||||
}
|
}
|
||||||
destroy();
|
destroy();
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
@@ -153,4 +156,15 @@ namespace mirage {
|
|||||||
LLGL::CommandQueue* get_main_command_queue() {
|
LLGL::CommandQueue* get_main_command_queue() {
|
||||||
return renderer->GetCommandQueue();
|
return renderer->GetCommandQueue();
|
||||||
}
|
}
|
||||||
|
uint64_t get_frame_index() {
|
||||||
|
return frame_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::path get_shader_path() {
|
||||||
|
return shader_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_shader_path(const std::filesystem::path& in_shader_path) {
|
||||||
|
shader_path = in_shader_path;
|
||||||
|
}
|
||||||
} // namespace mirage
|
} // namespace mirage
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "LLGL/LLGL.h"
|
#include "LLGL/LLGL.h"
|
||||||
#include "misc/mirage_type.h"
|
#include "misc/mirage_type.h"
|
||||||
#include "window/window.h"
|
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
#define MIRAGE_VERSION_MAJOR 0
|
#define MIRAGE_VERSION_MAJOR 0
|
||||||
#define MIRAGE_VERSION_MINOR 1
|
#define MIRAGE_VERSION_MINOR 1
|
||||||
@@ -21,4 +21,15 @@ namespace mirage {
|
|||||||
|
|
||||||
LLGL::RenderSystem* get_renderer();
|
LLGL::RenderSystem* get_renderer();
|
||||||
LLGL::CommandQueue* get_main_command_queue();
|
LLGL::CommandQueue* get_main_command_queue();
|
||||||
|
uint64_t get_frame_index();
|
||||||
|
|
||||||
|
std::filesystem::path get_shader_path();
|
||||||
|
void set_shader_path(const std::filesystem::path& in_shader_path);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void llgl_deleter(T* ptr) {
|
||||||
|
if (auto renderer = get_renderer()) {
|
||||||
|
renderer->Release(*ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
52
src/core/misc/enum_class_flags.h
Normal file
52
src/core/misc/enum_class_flags.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Defines all bitwise operators for enum classes so it can be (mostly) used as a regular flags enum
|
||||||
|
#define ENUM_CLASS_FLAGS(Enum) \
|
||||||
|
inline Enum& operator|=(Enum& Lhs, Enum Rhs) { return Lhs = (Enum)((__underlying_type(Enum))Lhs | (__underlying_type(Enum))Rhs); } \
|
||||||
|
inline Enum& operator&=(Enum& Lhs, Enum Rhs) { return Lhs = (Enum)((__underlying_type(Enum))Lhs & (__underlying_type(Enum))Rhs); } \
|
||||||
|
inline Enum& operator^=(Enum& Lhs, Enum Rhs) { return Lhs = (Enum)((__underlying_type(Enum))Lhs ^ (__underlying_type(Enum))Rhs); } \
|
||||||
|
inline constexpr Enum operator| (Enum Lhs, Enum Rhs) { return (Enum)((__underlying_type(Enum))Lhs | (__underlying_type(Enum))Rhs); } \
|
||||||
|
inline constexpr Enum operator& (Enum Lhs, Enum Rhs) { return (Enum)((__underlying_type(Enum))Lhs & (__underlying_type(Enum))Rhs); } \
|
||||||
|
inline constexpr Enum operator^ (Enum Lhs, Enum Rhs) { return (Enum)((__underlying_type(Enum))Lhs ^ (__underlying_type(Enum))Rhs); } \
|
||||||
|
inline constexpr bool operator! (Enum E) { return !(__underlying_type(Enum))E; } \
|
||||||
|
inline constexpr Enum operator~ (Enum E) { return (Enum)~(__underlying_type(Enum))E; }
|
||||||
|
|
||||||
|
// Friends all bitwise operators for enum classes so the definition can be kept private / protected.
|
||||||
|
#define FRIEND_ENUM_CLASS_FLAGS(Enum) \
|
||||||
|
friend Enum& operator|=(Enum& Lhs, Enum Rhs); \
|
||||||
|
friend Enum& operator&=(Enum& Lhs, Enum Rhs); \
|
||||||
|
friend Enum& operator^=(Enum& Lhs, Enum Rhs); \
|
||||||
|
friend constexpr Enum operator| (Enum Lhs, Enum Rhs); \
|
||||||
|
friend constexpr Enum operator& (Enum Lhs, Enum Rhs); \
|
||||||
|
friend constexpr Enum operator^ (Enum Lhs, Enum Rhs); \
|
||||||
|
friend constexpr bool operator! (Enum E); \
|
||||||
|
friend constexpr Enum operator~ (Enum E);
|
||||||
|
|
||||||
|
template<typename Enum>
|
||||||
|
constexpr bool enum_has_all_flags(Enum Flags, Enum Contains)
|
||||||
|
{
|
||||||
|
using UnderlyingType = __underlying_type(Enum);
|
||||||
|
return ((UnderlyingType)Flags & (UnderlyingType)Contains) == (UnderlyingType)Contains;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Enum>
|
||||||
|
constexpr bool enum_has_any_flags(Enum Flags, Enum Contains)
|
||||||
|
{
|
||||||
|
using UnderlyingType = __underlying_type(Enum);
|
||||||
|
return ((UnderlyingType)Flags & (UnderlyingType)Contains) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Enum>
|
||||||
|
void enum_add_flags(Enum& Flags, Enum FlagsToAdd)
|
||||||
|
{
|
||||||
|
using UnderlyingType = __underlying_type(Enum);
|
||||||
|
Flags = (Enum)((UnderlyingType)Flags | (UnderlyingType)FlagsToAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Enum>
|
||||||
|
void enum_remove_flags(Enum& Flags, Enum FlagsToRemove)
|
||||||
|
{
|
||||||
|
using UnderlyingType = __underlying_type(Enum);
|
||||||
|
Flags = (Enum)((UnderlyingType)Flags & ~(UnderlyingType)FlagsToRemove);
|
||||||
|
}
|
||||||
|
|
||||||
8
src/core/misc/enums.h
Normal file
8
src/core/misc/enums.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace mirage {
|
||||||
|
enum class orientation {
|
||||||
|
horizontal,
|
||||||
|
vertical
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -2,10 +2,14 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include "LLGL/LLGL.h"
|
#include "LLGL/LLGL.h"
|
||||||
#include <Eigen/Eigen>
|
#include <Eigen/Eigen>
|
||||||
|
#include "LLGL/Utils/VertexFormat.h"
|
||||||
|
|
||||||
namespace mirage {
|
namespace mirage {
|
||||||
using time_type = decltype(std::chrono::high_resolution_clock::now());
|
using time_type = decltype(std::chrono::high_resolution_clock::now());
|
||||||
using duration_type = decltype(std::chrono::high_resolution_clock::now() - std::chrono::high_resolution_clock::now());
|
using duration_type = decltype(std::chrono::high_resolution_clock::now() - std::chrono::high_resolution_clock::now());
|
||||||
|
using pipeline_state_ptr = std::shared_ptr<LLGL::PipelineState>;
|
||||||
|
using shader_ptr = std::shared_ptr<LLGL::Shader>;
|
||||||
|
using pipeline_layout_ptr = std::shared_ptr<LLGL::PipelineLayout>;
|
||||||
|
|
||||||
enum class renderer_api {
|
enum class renderer_api {
|
||||||
dx11,
|
dx11,
|
||||||
@@ -57,6 +61,18 @@ namespace mirage {
|
|||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline LLGL::VertexFormat create_vertex_format() {
|
||||||
|
LLGL::VertexFormat vertex_format;
|
||||||
|
vertex_format.AppendAttribute({"POSITION", 0, LLGL::Format::RG32Float}); // float2 position
|
||||||
|
vertex_format.AppendAttribute({"TEXCOORD", 0, LLGL::Format::RG32Float}); // float2 uv
|
||||||
|
vertex_format.AppendAttribute({"COLOR", 0, LLGL::Format::RGBA32Float}); // float4 color
|
||||||
|
vertex_format.AppendAttribute({"TEXCOORD", 1, LLGL::Format::RGBA32Float}); // float4 param_a
|
||||||
|
vertex_format.AppendAttribute({"TEXCOORD", 2, LLGL::Format::RGBA32Float}); // float4 param_b
|
||||||
|
vertex_format.AppendAttribute({"TEXCOORD", 3, LLGL::Format::RGBA32Float}); // float4 param_c
|
||||||
|
return vertex_format;
|
||||||
|
}
|
||||||
|
|
||||||
struct swap_chain_descriptor {
|
struct swap_chain_descriptor {
|
||||||
int color_bits = 32;
|
int color_bits = 32;
|
||||||
int depth_bits = 0;
|
int depth_bits = 0;
|
||||||
@@ -78,12 +94,13 @@ namespace mirage {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct triangle_index_t {
|
struct triangle_index_t {
|
||||||
int32_t vertex_index[3];
|
int32_t vertex_index[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct triangle_t {
|
struct pipeline_info {
|
||||||
vertex_t vertex[3];
|
pipeline_state_ptr pipeline_state;
|
||||||
|
pipeline_layout_ptr pipeline_layout;
|
||||||
|
std::vector<shader_ptr> shaders;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
1
src/core/renderer/draw_element.cpp
Normal file
1
src/core/renderer/draw_element.cpp
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#include "draw_element.h"
|
||||||
34
src/core/renderer/draw_element.h
Normal file
34
src/core/renderer/draw_element.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "rendering_common.h"
|
||||||
|
#include <Eigen/Eigen>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace mirage {
|
||||||
|
|
||||||
|
template<typename ElementType>
|
||||||
|
struct draw_element {
|
||||||
|
virtual ~draw_element() = default;
|
||||||
|
|
||||||
|
static uint64_t batch_id() {
|
||||||
|
static uint32_t id = 0;
|
||||||
|
return reinterpret_cast<uint64_t>(&id);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void submit(LLGL::CommandBuffer& in_command_buffer) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rounded_rect : draw_element<rounded_rect> {
|
||||||
|
struct param {
|
||||||
|
Eigen::Matrix4f projection_matrix;
|
||||||
|
rect rect;
|
||||||
|
float left_top_radius;
|
||||||
|
float right_top_radius;
|
||||||
|
float right_bottom_radius;
|
||||||
|
float left_bottom_radius;
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual void submit(LLGL::CommandBuffer& in_command_buffer) override {
|
||||||
|
}
|
||||||
|
param data;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1 +0,0 @@
|
|||||||
#include "element_batcher.h"
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
namespace mirage {
|
|
||||||
class element_batcher {
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct batch_key {
|
|
||||||
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "render_buffer.h"
|
#include "render_buffer.h"
|
||||||
|
|
||||||
|
#include "render_command_pool.h"
|
||||||
|
|
||||||
namespace mirage {
|
namespace mirage {
|
||||||
render_buffer::~render_buffer() {
|
render_buffer::~render_buffer() {
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
@@ -12,7 +14,6 @@ namespace mirage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LLGL::BufferDescriptor desc = in_desc;
|
LLGL::BufferDescriptor desc = in_desc;
|
||||||
desc.size = std::max(desc.size, DEFAULT_INITIAL_SIZE);
|
|
||||||
|
|
||||||
buffer = get_renderer()->CreateBuffer(desc);
|
buffer = get_renderer()->CreateBuffer(desc);
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
@@ -92,6 +93,30 @@ namespace mirage {
|
|||||||
}
|
}
|
||||||
size += in_data_size;
|
size += in_data_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void render_buffer::update(const void* data, size_t offset, size_t size) {
|
||||||
|
if (offset + size > capacity) {
|
||||||
|
throw std::out_of_range("Buffer update out of bounds");
|
||||||
|
}
|
||||||
|
// 更新缓冲区
|
||||||
|
get_renderer()->WriteBuffer(*buffer, offset, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_buffer::set(const void* in_data, size_t in_size) {
|
||||||
|
if (in_size > capacity) {
|
||||||
|
resize(in_size);
|
||||||
|
}
|
||||||
|
if (access_flags & LLGL::CPUAccessFlags::Write) {
|
||||||
|
if (auto mapped = get_renderer()->MapBuffer(*buffer, LLGL::CPUAccess::WriteDiscard)) {
|
||||||
|
std::memcpy(mapped, in_data, in_size);
|
||||||
|
get_renderer()->UnmapBuffer(*buffer);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
get_renderer()->WriteBuffer(*buffer, 0, in_data, in_size);
|
||||||
|
}
|
||||||
|
size = in_size;
|
||||||
|
}
|
||||||
|
|
||||||
void render_buffer::update_async(const void* data, size_t offset, size_t size) {
|
void render_buffer::update_async(const void* data, size_t offset, size_t size) {
|
||||||
if (offset + size > capacity) {
|
if (offset + size > capacity) {
|
||||||
throw std::out_of_range("Buffer update out of bounds");
|
throw std::out_of_range("Buffer update out of bounds");
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "LLGL/LLGL.h"
|
#include "LLGL/LLGL.h"
|
||||||
#include "mirage.h"
|
#include "mirage.h"
|
||||||
#include "render_command_pool.h"
|
#include "rendering_common.h"
|
||||||
#include <span>
|
#include <span>
|
||||||
|
|
||||||
namespace mirage {
|
namespace mirage {
|
||||||
@@ -67,14 +67,46 @@ namespace mirage {
|
|||||||
|
|
||||||
void push(const void* data, size_t in_data_size);
|
void push(const void* data, size_t in_data_size);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void push(std::span<const T> data) {
|
void push(const std::span<T>& data) {
|
||||||
push(data.data(), data.size_bytes());
|
push(data.data(), data.size_bytes());
|
||||||
}
|
}
|
||||||
|
template<typename T>
|
||||||
|
void push(const std::vector<T>& data) {
|
||||||
|
push(std::span(data));
|
||||||
|
}
|
||||||
template <class T>
|
template <class T>
|
||||||
void push(const T& data) {
|
void push(const T& data) {
|
||||||
push(&data, sizeof(T));
|
push(&data, sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void update(const void* data, size_t offset, size_t size);
|
||||||
|
template<typename T>
|
||||||
|
void update(std::span<const T> data, const size_t offset = 0) {
|
||||||
|
update(data.data(), offset, data.size_bytes());
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
void update(const std::vector<T>& data, const size_t offset = 0) {
|
||||||
|
update(std::span(data), offset);
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
void update(const T& data, const size_t offset = 0) {
|
||||||
|
update(&data, offset, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(const void* in_data, size_t in_size);
|
||||||
|
template<typename T>
|
||||||
|
void set(std::span<const T> in_data) {
|
||||||
|
set(in_data.data(), in_data.size_bytes());
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
void set(const std::vector<T>& in_data) {
|
||||||
|
set(std::span(in_data));
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
void set(const T& in_data) {
|
||||||
|
set(&in_data, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
// 异步更新缓冲区
|
// 异步更新缓冲区
|
||||||
struct update_info {
|
struct update_info {
|
||||||
const void* data;
|
const void* data;
|
||||||
@@ -100,11 +132,54 @@ namespace mirage {
|
|||||||
operator bool() const {
|
operator bool() const {
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
auto& get_raw() const {
|
||||||
|
return *buffer;
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
LLGL::Buffer* buffer;
|
LLGL::Buffer* buffer;
|
||||||
size_t size;
|
size_t size;
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
long access_flags;
|
long access_flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::shared_ptr<render_buffer> create_constant_buffer(long in_cpu_access_flags = LLGL::CPUAccessFlags::ReadWrite) {
|
||||||
|
LLGL::BufferDescriptor desc;
|
||||||
|
desc.size = sizeof(T);
|
||||||
|
desc.cpuAccessFlags = in_cpu_access_flags;
|
||||||
|
desc.bindFlags = LLGL::BindFlags::ConstantBuffer;
|
||||||
|
desc.miscFlags = LLGL::MiscFlags::DynamicUsage;
|
||||||
|
|
||||||
|
auto buffer = std::make_shared<render_buffer>();
|
||||||
|
buffer->init(desc);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T = vertex>
|
||||||
|
std::shared_ptr<render_buffer> create_vertex_buffer(const size_t in_count, const LLGL::VertexFormat& in_vertex_format = create_vertex_format()) {
|
||||||
|
LLGL::BufferDescriptor vertex_buffer_descriptor{};
|
||||||
|
vertex_buffer_descriptor.size = sizeof(T) * in_count;
|
||||||
|
vertex_buffer_descriptor.bindFlags = LLGL::BindFlags::VertexBuffer;
|
||||||
|
vertex_buffer_descriptor.miscFlags = LLGL::MiscFlags::DynamicUsage;
|
||||||
|
vertex_buffer_descriptor.cpuAccessFlags = LLGL::CPUAccessFlags::Write;
|
||||||
|
vertex_buffer_descriptor.vertexAttribs = in_vertex_format.attributes;
|
||||||
|
|
||||||
|
auto vertex_buffer = std::make_shared<render_buffer>();
|
||||||
|
vertex_buffer->init(vertex_buffer_descriptor);
|
||||||
|
return vertex_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T = triangle_index_t>
|
||||||
|
std::shared_ptr<render_buffer> create_index_buffer(const size_t in_count) {
|
||||||
|
LLGL::BufferDescriptor index_buffer_descriptor{};
|
||||||
|
index_buffer_descriptor.size = sizeof(T) * in_count;
|
||||||
|
index_buffer_descriptor.bindFlags = LLGL::BindFlags::IndexBuffer;
|
||||||
|
index_buffer_descriptor.miscFlags = LLGL::MiscFlags::DynamicUsage;
|
||||||
|
index_buffer_descriptor.cpuAccessFlags = LLGL::CPUAccessFlags::Write;
|
||||||
|
index_buffer_descriptor.format = LLGL::Format::R32UInt;
|
||||||
|
|
||||||
|
auto index_buffer = std::make_shared<render_buffer>();
|
||||||
|
index_buffer->init(index_buffer_descriptor);
|
||||||
|
return index_buffer;
|
||||||
|
}
|
||||||
} // namespace mirage
|
} // namespace mirage
|
||||||
|
|||||||
@@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
#include "LLGL/Utils/VertexFormat.h"
|
#include "LLGL/Utils/VertexFormat.h"
|
||||||
#include "mirage.h"
|
#include "mirage.h"
|
||||||
|
#include "rendering_common.h"
|
||||||
|
#include "shader_loader.h"
|
||||||
|
#include "LLGL/Utils/Parse.h"
|
||||||
|
|
||||||
|
struct pipeline_param {
|
||||||
|
Eigen::Matrix4f mvp;
|
||||||
|
};
|
||||||
|
|
||||||
namespace mirage {
|
namespace mirage {
|
||||||
render_context::~render_context() {
|
render_context::~render_context() {
|
||||||
@@ -23,8 +30,47 @@ namespace mirage {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
set_vsync(in_desc.vsync);
|
set_vsync(in_desc.vsync);
|
||||||
create_vertex_buffer();
|
vertex_buffer = create_vertex_buffer(64);
|
||||||
create_index_buffer();
|
index_buffer = create_index_buffer(64);
|
||||||
|
param_buffer = create_constant_buffer<pipeline_param>();
|
||||||
|
|
||||||
|
pipeline_param param;
|
||||||
|
param.mvp = get_projection_matrix();
|
||||||
|
param_buffer->set(param);
|
||||||
|
|
||||||
|
LLGL::PipelineLayoutDescriptor pipeline_layout_desc;
|
||||||
|
pipeline_layout_desc.bindings.emplace_back(
|
||||||
|
LLGL::ResourceType::Buffer,
|
||||||
|
LLGL::BindFlags::ConstantBuffer,
|
||||||
|
LLGL::StageFlags::VertexStage,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
pipeline = generated_pipelines::create_aorii_rect_pipeline(get_renderer(), swap_chain->GetRenderPass(), pipeline_layout_desc);
|
||||||
|
|
||||||
|
vertex va{};
|
||||||
|
va.position = {0.0f, 0.0f};
|
||||||
|
va.uv = {0.0f, 0.0f};
|
||||||
|
va.color = {1.0f, 1.0f, 0.0f, 1.0f};
|
||||||
|
vertex vb{};
|
||||||
|
vb.position = {100.0f, 0.0f};
|
||||||
|
vb.uv = {1.0f, 0.0f};
|
||||||
|
vb.color = {1.0f, 0.0f, 1.0f, 1.0f};
|
||||||
|
vertex vc{};
|
||||||
|
vc.position = {100.0f, 100.0f};
|
||||||
|
vc.uv = {1.0f, 1.0f};
|
||||||
|
vc.color = {0.0f, 1.0f, 1.0f, 1.0f};
|
||||||
|
vertex vd{};
|
||||||
|
vd.position = {0.0f, 100.0f};
|
||||||
|
vd.uv = {0.0f, 1.0f};
|
||||||
|
vd.color = {0.0f, 1.0f, 0.0f, 1.0f};
|
||||||
|
|
||||||
|
std::vector quad_vertices = {va, vb, vc, vd};
|
||||||
|
vertex_buffer->push(quad_vertices);
|
||||||
|
|
||||||
|
triangle_index_t ta{0, 1, 2};
|
||||||
|
triangle_index_t tb{0, 2, 3};
|
||||||
|
std::vector quad_indices = {ta, tb};
|
||||||
|
index_buffer->push(quad_indices);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
render_context::update_status render_context::update(const duration_type& in_delta_time) {
|
render_context::update_status render_context::update(const duration_type& in_delta_time) {
|
||||||
@@ -36,17 +82,33 @@ namespace mirage {
|
|||||||
}
|
}
|
||||||
command_buffer->Begin();
|
command_buffer->Begin();
|
||||||
{
|
{
|
||||||
|
command_buffer->SetViewport(swap_chain->GetResolution());
|
||||||
|
command_buffer->SetVertexBuffer(vertex_buffer->get_raw());
|
||||||
|
command_buffer->SetIndexBuffer(index_buffer->get_raw());
|
||||||
|
|
||||||
command_buffer->BeginRenderPass(*swap_chain);
|
command_buffer->BeginRenderPass(*swap_chain);
|
||||||
command_buffer->Clear(LLGL::ClearFlags::Color, {0.1f, 0.1f, 0.2f, 1.0f});
|
{
|
||||||
|
command_buffer->Clear(LLGL::ClearFlags::Color, {0.1f, 0.1f, 0.2f, 1.0f});
|
||||||
|
|
||||||
|
command_buffer->SetPipelineState(*pipeline.pipeline_state);
|
||||||
|
command_buffer->SetResource(0, param_buffer->get_raw());
|
||||||
|
|
||||||
|
command_buffer->DrawIndexed(index_buffer->get_size() / sizeof(uint32_t), 0);
|
||||||
|
}
|
||||||
command_buffer->EndRenderPass();
|
command_buffer->EndRenderPass();
|
||||||
}
|
}
|
||||||
command_buffer->End();
|
command_buffer->End();
|
||||||
|
get_renderer()->GetCommandQueue()->Submit(*command_buffer);
|
||||||
swap_chain->Present();
|
swap_chain->Present();
|
||||||
return update_status::success;
|
return update_status::success;
|
||||||
}
|
}
|
||||||
void render_context::resize_swap_chain(const LLGL::Extent2D& in_size, long in_flag) {
|
void render_context::resize_swap_chain(const LLGL::Extent2D& in_size, long in_flag) {
|
||||||
if (swap_chain) {
|
if (swap_chain) {
|
||||||
swap_chain->ResizeBuffers(in_size, in_flag);
|
swap_chain->ResizeBuffers(in_size, in_flag);
|
||||||
|
|
||||||
|
pipeline_param param;
|
||||||
|
param.mvp = get_projection_matrix();
|
||||||
|
param_buffer->set(param);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,28 +120,27 @@ namespace mirage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void render_context::create_vertex_buffer() {
|
Eigen::Matrix4f render_context::get_projection_matrix() const {
|
||||||
// 创建顶点格式布局
|
const bool is_clip_range_unit_cube = get_renderer()->GetRenderingCaps().clippingRange == LLGL::ClippingRange::MinusOneToOne;
|
||||||
LLGL::VertexFormat vertexFormat;
|
const auto& size = swap_chain->GetResolution();
|
||||||
|
// 创建一个单位矩阵
|
||||||
// 添加顶点属性
|
Eigen::Matrix4f matrix = Eigen::Matrix4f::Identity();
|
||||||
vertexFormat.AppendAttribute({"position", LLGL::Format::RGB32Float}); // float3 position
|
// 透视投影矩阵
|
||||||
vertexFormat.AppendAttribute({"texCoord0", LLGL::Format::RG32Float}); // float2 uv
|
if (is_clip_range_unit_cube) {
|
||||||
vertexFormat.AppendAttribute({"color", LLGL::Format::RGBA32Float}); // float4 color
|
matrix(0, 0) = 2.0f / size.width;
|
||||||
vertexFormat.AppendAttribute({"texCoord1", LLGL::Format::RGBA32Float}); // float4 param_a
|
matrix(1, 1) = 2.0f / size.height;
|
||||||
vertexFormat.AppendAttribute({"texCoord2", LLGL::Format::RGBA32Float}); // float4 param_b
|
matrix(2, 2) = 1.0f;
|
||||||
vertexFormat.AppendAttribute({"texCoord3", LLGL::Format::RGBA32Float}); // float4 param_c
|
matrix(3, 3) = 1.0f;
|
||||||
|
matrix(3, 0) = -1.0f;
|
||||||
LLGL::BufferDescriptor vertex_buffer_descriptor{};
|
matrix(3, 1) = -1.0f;
|
||||||
vertex_buffer_descriptor.size = sizeof(vertex_t) * 512;
|
} else {
|
||||||
vertex_buffer_descriptor.bindFlags = LLGL::BindFlags::VertexBuffer;
|
matrix(0, 0) = 2.0f / size.width;
|
||||||
vertex_buffer_descriptor.vertexAttribs = vertexFormat.attributes;
|
matrix(1, 1) = -2.0f / size.height;
|
||||||
vertex_buffer.init(vertex_buffer_descriptor);
|
matrix(2, 2) = 1.0f;
|
||||||
}
|
matrix(3, 3) = 1.0f;
|
||||||
void render_context::create_index_buffer() {
|
matrix(3, 0) = -1.0f;
|
||||||
LLGL::BufferDescriptor index_buffer_descriptor{};
|
matrix(3, 1) = 1.0f;
|
||||||
index_buffer_descriptor.size = sizeof(triangle_index_t) * 512;
|
}
|
||||||
index_buffer_descriptor.bindFlags = LLGL::BindFlags::IndexBuffer;
|
return matrix;
|
||||||
index_buffer.init(index_buffer_descriptor);
|
|
||||||
}
|
}
|
||||||
} // namespace mirage
|
} // namespace mirage
|
||||||
|
|||||||
@@ -23,24 +23,19 @@ namespace mirage {
|
|||||||
return swap_chain;
|
return swap_chain;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] size_t get_vertex_count() const {
|
|
||||||
return vertex_buffer.get_size() / sizeof(vertex_t);
|
|
||||||
}
|
|
||||||
[[nodiscard]] size_t get_index_count() const {
|
|
||||||
return index_buffer.get_size() / sizeof(triangle_index_t);
|
|
||||||
}
|
|
||||||
[[nodiscard]] Eigen::Vector2f get_size() const {
|
[[nodiscard]] Eigen::Vector2f get_size() const {
|
||||||
const auto& extent_2d = swap_chain->GetResolution();
|
const auto& extent_2d = swap_chain->GetResolution();
|
||||||
return {extent_2d.width, extent_2d.height};
|
return {extent_2d.width, extent_2d.height};
|
||||||
}
|
}
|
||||||
private:
|
|
||||||
void create_vertex_buffer();
|
|
||||||
void create_index_buffer();
|
|
||||||
|
|
||||||
render_buffer vertex_buffer;
|
[[nodiscard]] Eigen::Matrix4f get_projection_matrix() const;
|
||||||
render_buffer index_buffer;
|
private:
|
||||||
|
std::shared_ptr<render_buffer> vertex_buffer;
|
||||||
|
std::shared_ptr<render_buffer> index_buffer;
|
||||||
|
std::shared_ptr<render_buffer> param_buffer;
|
||||||
LLGL::CommandBuffer* command_buffer = nullptr;
|
LLGL::CommandBuffer* command_buffer = nullptr;
|
||||||
LLGL::SwapChain* swap_chain = nullptr;
|
LLGL::SwapChain* swap_chain = nullptr;
|
||||||
bool vsync = true;
|
bool vsync = true;
|
||||||
|
pipeline_info pipeline;
|
||||||
};
|
};
|
||||||
} // namespace mirage
|
} // namespace mirage
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
#include "render_draw_element.h"
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
#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 +0,0 @@
|
|||||||
#include "render_element_drawer.h"
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
#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 +0,0 @@
|
|||||||
#include "render_window_element_list.h"
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
class render_window_element_list {
|
|
||||||
public:
|
|
||||||
render_window_element_list();
|
|
||||||
private:
|
|
||||||
|
|
||||||
};
|
|
||||||
@@ -1,244 +1,81 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <cstdint>
|
|
||||||
#include "LLGL/LLGL.h"
|
#include "LLGL/LLGL.h"
|
||||||
|
#include "misc/enum_class_flags.h"
|
||||||
#include <Eigen/Eigen>
|
#include <Eigen/Eigen>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
namespace mirage {
|
namespace mirage {
|
||||||
using transform_type = Eigen::Affine2d;
|
using transform_type = Eigen::Affine2d;
|
||||||
using color_type = LLGL::ColorRGBAub;
|
using color_type = LLGL::ColorRGBAub;
|
||||||
using linear_color_type = LLGL::ColorRGBAf;
|
using linear_color_type = LLGL::ColorRGBAf;
|
||||||
|
using point_type = Eigen::Vector2f;
|
||||||
|
|
||||||
/**
|
struct vertex_shader_param {
|
||||||
* 绘制基本类型
|
|
||||||
*/
|
|
||||||
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 {
|
union {
|
||||||
float x;
|
float x, a;
|
||||||
float r;
|
|
||||||
};
|
};
|
||||||
union {
|
union {
|
||||||
float y;
|
float y, b;
|
||||||
float g;
|
|
||||||
};
|
};
|
||||||
union {
|
union {
|
||||||
float z;
|
float z, c;
|
||||||
float b;
|
|
||||||
};
|
};
|
||||||
union {
|
union {
|
||||||
float w;
|
float w, d;
|
||||||
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 {
|
template<typename T>
|
||||||
return x == in_other.x && y == in_other.y && z == in_other.z && w == in_other.w;
|
vertex_shader_param(Eigen::Matrix<T, 4, 1> in_vec) : x(in_vec.x()), y(in_vec.y()), z(in_vec.z()), w(in_vec.w()) {}
|
||||||
}
|
vertex_shader_param() : x(0), y(0), z(0), w(0) {}
|
||||||
};
|
|
||||||
|
|
||||||
struct mirage_shader_params {
|
float operator[](const std::size_t index) const {
|
||||||
mirage_pixel_params pixel_params;
|
switch (index) {
|
||||||
mirage_pixel_params pixel_params2;
|
case 0:
|
||||||
mirage_pixel_params pixel_params3;
|
return x;
|
||||||
|
case 1:
|
||||||
bool operator==(const mirage_shader_params& in_other) const {
|
return y;
|
||||||
return pixel_params == in_other.pixel_params && pixel_params2 == in_other.pixel_params2 && pixel_params3 == in_other.pixel_params3;
|
case 2:
|
||||||
}
|
return z;
|
||||||
};
|
case 3:
|
||||||
|
return w;
|
||||||
struct mirage_vertex {
|
default:
|
||||||
// 纹理坐标 xy zw
|
return {};
|
||||||
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;
|
};
|
||||||
|
|
||||||
|
struct vertex {
|
||||||
|
point_type position;
|
||||||
|
point_type uv;
|
||||||
|
linear_color_type color;
|
||||||
|
vertex_shader_param param[3];
|
||||||
|
};
|
||||||
|
struct triangle {
|
||||||
|
uint32_t index[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rect {
|
||||||
|
Eigen::Vector2f pos;
|
||||||
|
Eigen::Vector2f size;
|
||||||
|
|
||||||
|
[[nodiscard]] Eigen::Vector2f get_center() const {
|
||||||
|
return pos + size * 0.5f;
|
||||||
|
}
|
||||||
|
[[nodiscard]] Eigen::Vector2f get_top_left() const {
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
[[nodiscard]] Eigen::Vector2f get_top_right() const {
|
||||||
|
return {pos.x() + size.x(), pos.y()};
|
||||||
|
}
|
||||||
|
[[nodiscard]] Eigen::Vector2f get_bottom_left() const {
|
||||||
|
return {pos.x(), pos.y() + size.y()};
|
||||||
|
}
|
||||||
|
[[nodiscard]] Eigen::Vector2f get_bottom_right() const {
|
||||||
|
return pos + size;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool contains_point(const Eigen::Vector2f& in_point) const {
|
||||||
|
return in_point.x() >= pos.x() && in_point.x() <= pos.x() + size.x() && in_point.y() >= pos.y() && in_point.y() <= pos.y() + size.y();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
struct VSInput {
|
struct VSInput {
|
||||||
float3 position : POSITION;
|
float2 position : POSITION;
|
||||||
float2 uv : TEXCOORD0;
|
float2 uv : TEXCOORD0;
|
||||||
float4 color : COLOR0;
|
float4 color : COLOR0;
|
||||||
float4 param_a : TEXCOORD1;
|
float4 param_a : TEXCOORD1;
|
||||||
|
|||||||
Reference in New Issue
Block a user