Files
esengine/packages/engine/src/renderer/renderer2d.rs
YHH 63f006ab62 feat: 添加跨平台运行时、资产系统和UI适配功能 (#256)
* feat(platform-common): 添加WASM加载器和环境检测API

* feat(rapier2d): 新增Rapier2D WASM绑定包

* feat(physics-rapier2d): 添加跨平台WASM加载器

* feat(asset-system): 添加运行时资产目录和bundle格式

* feat(asset-system-editor): 新增编辑器资产管理包

* feat(editor-core): 添加构建系统和模块管理

* feat(editor-app): 重构浏览器预览使用import maps

* feat(platform-web): 添加BrowserRuntime和资产读取

* feat(engine): 添加材质系统和着色器管理

* feat(material): 新增材质系统和着色器编辑器

* feat(tilemap): 增强tilemap编辑器和动画系统

* feat(modules): 添加module.json配置

* feat(core): 添加module.json和类型定义更新

* chore: 更新依赖和构建配置

* refactor(plugins): 更新插件模板使用ModuleManifest

* chore: 添加第三方依赖库

* chore: 移除BehaviourTree-ai和ecs-astar子模块

* docs: 更新README和文档主题样式

* fix: 修复Rust文档测试和添加rapier2d WASM绑定

* fix(tilemap-editor): 修复画布高DPI屏幕分辨率适配问题

* feat(ui): 添加UI屏幕适配系统(CanvasScaler/SafeArea)

* fix(ecs-engine-bindgen): 添加缺失的ecs-framework-math依赖

* fix: 添加缺失的包依赖修复CI构建

* fix: 修复CodeQL检测到的代码问题

* fix: 修复构建错误和缺失依赖

* fix: 修复类型检查错误

* fix(material-system): 修复tsconfig配置支持TypeScript项目引用

* fix(editor-core): 修复Rollup构建配置添加tauri external

* fix: 修复CodeQL检测到的代码问题

* fix: 修复CodeQL检测到的代码问题
2025-12-03 22:15:22 +08:00

333 lines
11 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Main 2D renderer implementation.
//! 主2D渲染器实现。
use wasm_bindgen::JsCast;
use web_sys::WebGl2RenderingContext;
use crate::core::error::Result;
use crate::resource::TextureManager;
use super::batch::SpriteBatch;
use super::camera::Camera2D;
use super::shader::ShaderManager;
use super::material::MaterialManager;
/// 2D renderer with batched sprite rendering.
/// 带批处理精灵渲染的2D渲染器。
///
/// Coordinates sprite batching, shader management, and camera transforms.
/// 协调精灵批处理、Shader管理和相机变换。
pub struct Renderer2D {
/// Sprite batch renderer.
/// 精灵批处理渲染器。
sprite_batch: SpriteBatch,
/// Shader manager.
/// 着色器管理器。
shader_manager: ShaderManager,
/// Material manager.
/// 材质管理器。
material_manager: MaterialManager,
/// 2D camera.
/// 2D相机。
camera: Camera2D,
/// Clear color (RGBA).
/// 清除颜色 (RGBA)。
clear_color: [f32; 4],
/// Current active shader ID.
/// 当前激活的着色器ID。
#[allow(dead_code)]
current_shader_id: u32,
/// Current active material ID.
/// 当前激活的材质ID。
#[allow(dead_code)]
current_material_id: u32,
}
impl Renderer2D {
/// Create a new 2D renderer.
/// 创建新的2D渲染器。
///
/// # Arguments | 参数
/// * `gl` - WebGL2 context | WebGL2上下文
/// * `max_sprites` - Maximum sprites per batch | 每批次最大精灵数
pub fn new(gl: &WebGl2RenderingContext, max_sprites: usize) -> Result<Self> {
let sprite_batch = SpriteBatch::new(gl, max_sprites)?;
let shader_manager = ShaderManager::new(gl)?;
let material_manager = MaterialManager::new();
// Get canvas size for camera | 获取canvas尺寸用于相机
let canvas = gl.canvas()
.and_then(|c| c.dyn_into::<web_sys::HtmlCanvasElement>().ok())
.map(|c| (c.width() as f32, c.height() as f32))
.unwrap_or((800.0, 600.0));
let camera = Camera2D::new(canvas.0, canvas.1);
log::info!(
"Renderer2D initialized | Renderer2D初始化完成: {}x{}, max sprites: {}",
canvas.0, canvas.1, max_sprites
);
Ok(Self {
sprite_batch,
shader_manager,
material_manager,
camera,
clear_color: [0.1, 0.1, 0.12, 1.0],
current_shader_id: 0,
current_material_id: 0,
})
}
/// Submit sprite batch data for rendering.
/// 提交精灵批次数据进行渲染。
///
/// # Arguments | 参数
/// * `transforms` - Transform data for each sprite | 每个精灵的变换数据
/// * `texture_ids` - Texture ID for each sprite | 每个精灵的纹理ID
/// * `uvs` - UV coordinates for each sprite | 每个精灵的UV坐标
/// * `colors` - Packed color for each sprite | 每个精灵的打包颜色
/// * `material_ids` - Material ID for each sprite (0 = default) | 每个精灵的材质ID0 = 默认)
/// * `texture_manager` - Texture manager | 纹理管理器
pub fn submit_batch(
&mut self,
transforms: &[f32],
texture_ids: &[u32],
uvs: &[f32],
colors: &[u32],
material_ids: &[u32],
texture_manager: &TextureManager,
) -> Result<()> {
self.sprite_batch.add_sprites(
transforms,
texture_ids,
uvs,
colors,
material_ids,
texture_manager,
)
}
/// Render the current frame.
/// 渲染当前帧。
pub fn render(&mut self, gl: &WebGl2RenderingContext, texture_manager: &TextureManager) -> Result<()> {
use super::batch::BatchKey;
if self.sprite_batch.sprite_count() == 0 {
return Ok(());
}
// Collect non-empty batch keys | 收集非空批次键
let batch_keys: Vec<BatchKey> = self.sprite_batch.batches()
.iter()
.filter(|(_, vertices)| !vertices.is_empty())
.map(|(key, _)| *key)
.collect();
// Track current state to minimize state changes | 跟踪当前状态以最小化状态切换
let mut current_material_id: u32 = u32::MAX;
let mut current_texture_id: u32 = u32::MAX;
// Get projection matrix once | 一次性获取投影矩阵
let projection = self.camera.projection_matrix();
for batch_key in batch_keys {
// Switch material if needed | 如需切换材质
if batch_key.material_id != current_material_id {
current_material_id = batch_key.material_id;
// Get material (fallback to default if not found) | 获取材质(未找到则回退到默认)
let material = self.material_manager.get_material(batch_key.material_id)
.unwrap_or_else(|| self.material_manager.get_default_material());
// Bind shader | 绑定Shader
let shader = self.shader_manager.get_shader(material.shader_id)
.unwrap_or_else(|| self.shader_manager.get_default_shader());
shader.bind(gl);
// Apply blend mode | 应用混合模式
MaterialManager::apply_blend_mode(gl, material.blend_mode);
// Set projection matrix | 设置投影矩阵
shader.set_uniform_mat3(gl, "u_projection", &projection.to_cols_array());
// Set texture sampler | 设置纹理采样器
shader.set_uniform_i32(gl, "u_texture", 0);
// Apply material uniforms | 应用材质uniform
material.uniforms.apply_to_shader(gl, shader);
}
// Switch texture if needed | 如需切换纹理
if batch_key.texture_id != current_texture_id {
current_texture_id = batch_key.texture_id;
texture_manager.bind_texture(batch_key.texture_id, 0);
}
// Flush this batch | 刷新此批次
self.sprite_batch.flush_for_batch(gl, &batch_key);
}
// Clear batch for next frame | 清空批处理以供下一帧使用
self.sprite_batch.clear();
Ok(())
}
/// Get mutable reference to camera.
/// 获取相机的可变引用。
#[inline]
pub fn camera_mut(&mut self) -> &mut Camera2D {
&mut self.camera
}
/// Get reference to camera.
/// 获取相机的引用。
#[inline]
pub fn camera(&self) -> &Camera2D {
&self.camera
}
/// Set clear color (RGBA, each component 0.0-1.0).
/// 设置清除颜色。
pub fn set_clear_color(&mut self, r: f32, g: f32, b: f32, a: f32) {
self.clear_color = [r, g, b, a];
}
/// Get clear color.
/// 获取清除颜色。
pub fn get_clear_color(&self) -> [f32; 4] {
self.clear_color
}
/// Update camera viewport size.
/// 更新相机视口大小。
pub fn resize(&mut self, width: f32, height: f32) {
self.camera.set_viewport(width, height);
}
// ============= Shader Management =============
// ============= 着色器管理 =============
/// Compile and register a custom shader.
/// 编译并注册自定义着色器。
///
/// # Returns | 返回
/// The shader ID for referencing this shader | 用于引用此着色器的ID
pub fn compile_shader(
&mut self,
gl: &WebGl2RenderingContext,
vertex_source: &str,
fragment_source: &str,
) -> Result<u32> {
self.shader_manager.compile_shader(gl, vertex_source, fragment_source)
}
/// Compile a shader with a specific ID.
/// 使用特定ID编译着色器。
pub fn compile_shader_with_id(
&mut self,
gl: &WebGl2RenderingContext,
shader_id: u32,
vertex_source: &str,
fragment_source: &str,
) -> Result<()> {
self.shader_manager.compile_shader_with_id(gl, shader_id, vertex_source, fragment_source)
}
/// Check if a shader exists.
/// 检查着色器是否存在。
pub fn has_shader(&self, shader_id: u32) -> bool {
self.shader_manager.has_shader(shader_id)
}
/// Remove a shader.
/// 移除着色器。
pub fn remove_shader(&mut self, shader_id: u32) -> bool {
self.shader_manager.remove_shader(shader_id)
}
/// Get shader manager reference.
/// 获取着色器管理器引用。
pub fn shader_manager(&self) -> &ShaderManager {
&self.shader_manager
}
/// Get mutable shader manager reference.
/// 获取可变着色器管理器引用。
pub fn shader_manager_mut(&mut self) -> &mut ShaderManager {
&mut self.shader_manager
}
// ============= Material Management =============
// ============= 材质管理 =============
/// Register a custom material.
/// 注册自定义材质。
///
/// # Returns | 返回
/// The material ID for referencing this material | 用于引用此材质的ID
pub fn register_material(&mut self, material: super::material::Material) -> u32 {
self.material_manager.register_material(material)
}
/// Register a material with a specific ID.
/// 使用特定ID注册材质。
pub fn register_material_with_id(&mut self, material_id: u32, material: super::material::Material) {
self.material_manager.register_material_with_id(material_id, material);
}
/// Get a material by ID.
/// 按ID获取材质。
pub fn get_material(&self, material_id: u32) -> Option<&super::material::Material> {
self.material_manager.get_material(material_id)
}
/// Get a mutable material by ID.
/// 按ID获取可变材质。
pub fn get_material_mut(&mut self, material_id: u32) -> Option<&mut super::material::Material> {
self.material_manager.get_material_mut(material_id)
}
/// Check if a material exists.
/// 检查材质是否存在。
pub fn has_material(&self, material_id: u32) -> bool {
self.material_manager.has_material(material_id)
}
/// Remove a material.
/// 移除材质。
pub fn remove_material(&mut self, material_id: u32) -> bool {
self.material_manager.remove_material(material_id)
}
/// Set a material's float uniform.
/// 设置材质的浮点uniform。
pub fn set_material_float(&mut self, material_id: u32, name: &str, value: f32) -> bool {
self.material_manager.set_material_float(material_id, name, value)
}
/// Set a material's vec4 uniform.
/// 设置材质的vec4 uniform。
pub fn set_material_vec4(&mut self, material_id: u32, name: &str, x: f32, y: f32, z: f32, w: f32) -> bool {
self.material_manager.set_material_vec4(material_id, name, x, y, z, w)
}
/// Get material manager reference.
/// 获取材质管理器引用。
pub fn material_manager(&self) -> &MaterialManager {
&self.material_manager
}
/// Get mutable material manager reference.
/// 获取可变材质管理器引用。
pub fn material_manager_mut(&mut self) -> &mut MaterialManager {
&mut self.material_manager
}
}