Files
esengine/packages/engine/src/core/engine.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

711 lines
22 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 engine implementation.
//! 主引擎实现。
use wasm_bindgen::prelude::*;
use super::context::WebGLContext;
use super::error::Result;
use crate::input::InputManager;
use crate::renderer::{Renderer2D, GridRenderer, GizmoRenderer, TransformMode, ViewportManager};
use crate::resource::TextureManager;
/// Engine configuration options.
/// 引擎配置选项。
#[derive(Debug, Clone)]
pub struct EngineConfig {
/// Maximum sprites per batch.
/// 每批次最大精灵数。
pub max_sprites: usize,
/// Enable debug mode.
/// 启用调试模式。
pub debug: bool,
}
impl Default for EngineConfig {
fn default() -> Self {
Self {
max_sprites: 10000,
debug: false,
}
}
}
/// Main game engine.
/// 主游戏引擎。
///
/// Coordinates all engine subsystems including rendering, input, and resources.
/// 协调所有引擎子系统,包括渲染、输入和资源。
pub struct Engine {
/// WebGL context.
/// WebGL上下文。
context: WebGLContext,
/// 2D renderer.
/// 2D渲染器。
renderer: Renderer2D,
/// Grid renderer for editor.
/// 编辑器网格渲染器。
grid_renderer: GridRenderer,
/// Gizmo renderer for editor overlays.
/// 编辑器叠加层Gizmo渲染器。
gizmo_renderer: GizmoRenderer,
/// Texture manager.
/// 纹理管理器。
texture_manager: TextureManager,
/// Input manager.
/// 输入管理器。
input_manager: InputManager,
/// Engine configuration.
/// 引擎配置。
#[allow(dead_code)]
config: EngineConfig,
/// Whether to show grid.
/// 是否显示网格。
show_grid: bool,
/// Viewport manager for multi-viewport rendering.
/// 多视口渲染的视口管理器。
viewport_manager: ViewportManager,
/// Whether to show gizmos.
/// 是否显示辅助工具。
show_gizmos: bool,
}
impl Engine {
/// Create a new engine instance.
/// 创建新的引擎实例。
///
/// # Arguments | 参数
/// * `canvas_id` - The HTML canvas element ID | HTML canvas元素ID
/// * `config` - Engine configuration | 引擎配置
///
/// # Returns | 返回
/// A new Engine instance or an error | 新的Engine实例或错误
pub fn new(canvas_id: &str, config: EngineConfig) -> Result<Self> {
let context = WebGLContext::new(canvas_id)?;
// Initialize WebGL state | 初始化WebGL状态
context.set_viewport();
context.enable_blend();
// Create subsystems | 创建子系统
let renderer = Renderer2D::new(context.gl(), config.max_sprites)?;
let grid_renderer = GridRenderer::new(context.gl())?;
let gizmo_renderer = GizmoRenderer::new(context.gl())?;
let texture_manager = TextureManager::new(context.gl().clone());
let input_manager = InputManager::new();
log::info!("Engine created successfully | 引擎创建成功");
Ok(Self {
context,
renderer,
grid_renderer,
gizmo_renderer,
texture_manager,
input_manager,
config,
show_grid: true,
viewport_manager: ViewportManager::new(),
show_gizmos: true,
})
}
/// Create a new engine instance from external WebGL context.
/// 从外部 WebGL 上下文创建引擎实例。
///
/// This is designed for environments like WeChat MiniGame.
/// 适用于微信小游戏等环境。
pub fn from_external(
gl_context: JsValue,
width: u32,
height: u32,
config: EngineConfig,
) -> Result<Self> {
let context = WebGLContext::from_external(gl_context, width, height)?;
context.set_viewport();
context.enable_blend();
let renderer = Renderer2D::new(context.gl(), config.max_sprites)?;
let grid_renderer = GridRenderer::new(context.gl())?;
let gizmo_renderer = GizmoRenderer::new(context.gl())?;
let texture_manager = TextureManager::new(context.gl().clone());
let input_manager = InputManager::new();
log::info!("Engine created from external context | 从外部上下文创建引擎");
Ok(Self {
context,
renderer,
grid_renderer,
gizmo_renderer,
texture_manager,
input_manager,
config,
show_grid: true,
viewport_manager: ViewportManager::new(),
show_gizmos: true,
})
}
/// Clear the screen with specified color.
/// 使用指定颜色清除屏幕。
pub fn clear(&self, r: f32, g: f32, b: f32, a: f32) {
self.context.clear(r, g, b, a);
}
/// Get canvas width.
/// 获取画布宽度。
#[inline]
pub fn width(&self) -> u32 {
self.context.width()
}
/// Get canvas height.
/// 获取画布高度。
#[inline]
pub fn height(&self) -> u32 {
self.context.height()
}
/// Submit sprite batch data for rendering.
/// 提交精灵批次数据进行渲染。
pub fn submit_sprite_batch(
&mut self,
transforms: &[f32],
texture_ids: &[u32],
uvs: &[f32],
colors: &[u32],
material_ids: &[u32],
) -> Result<()> {
// Debug: log once
use std::sync::atomic::{AtomicBool, Ordering};
static LOGGED: AtomicBool = AtomicBool::new(false);
if !LOGGED.swap(true, Ordering::Relaxed) {
let sprite_count = texture_ids.len();
log::info!("Engine submit_sprite_batch: {} sprites, texture_ids: {:?}", sprite_count, texture_ids);
}
self.renderer.submit_batch(
transforms,
texture_ids,
uvs,
colors,
material_ids,
&self.texture_manager,
)
}
/// Render the current frame.
/// 渲染当前帧。
pub fn render(&mut self) -> Result<()> {
// Clear background with clear color
let [r, g, b, a] = self.renderer.get_clear_color();
self.context.clear(r, g, b, a);
// Render grid first (background)
if self.show_grid {
self.grid_renderer.render(self.context.gl(), self.renderer.camera());
self.grid_renderer.render_axes(self.context.gl(), self.renderer.camera());
}
// Render sprites
self.renderer.render(self.context.gl(), &self.texture_manager)?;
// Render gizmos on top
if self.show_gizmos {
self.gizmo_renderer.render(self.context.gl(), self.renderer.camera());
// Render axis indicator in corner
// 在角落渲染坐标轴指示器
self.gizmo_renderer.render_axis_indicator(
self.context.gl(),
self.context.width() as f32,
self.context.height() as f32,
);
}
self.gizmo_renderer.clear();
Ok(())
}
/// Render sprites only without clearing the screen.
/// 仅渲染精灵,不清除屏幕。
///
/// This is used for overlay rendering (e.g., UI layer on top of world).
/// 用于叠加渲染例如UI 层叠加在世界上)。
pub fn render_overlay(&mut self) -> Result<()> {
// Render sprites without clearing
// 渲染精灵但不清屏
self.renderer.render(self.context.gl(), &self.texture_manager)?;
Ok(())
}
/// Add a rectangle gizmo.
/// 添加矩形Gizmo。
pub fn add_gizmo_rect(
&mut self,
x: f32,
y: f32,
width: f32,
height: f32,
rotation: f32,
origin_x: f32,
origin_y: f32,
r: f32,
g: f32,
b: f32,
a: f32,
show_handles: bool,
) {
self.gizmo_renderer.add_rect(x, y, width, height, rotation, origin_x, origin_y, r, g, b, a, show_handles);
}
/// Add a circle gizmo.
/// 添加圆形Gizmo。
pub fn add_gizmo_circle(
&mut self,
x: f32,
y: f32,
radius: f32,
r: f32,
g: f32,
b: f32,
a: f32,
) {
self.gizmo_renderer.add_circle(x, y, radius, r, g, b, a);
}
/// Add a line gizmo.
/// 添加线条Gizmo。
pub fn add_gizmo_line(
&mut self,
points: Vec<f32>,
r: f32,
g: f32,
b: f32,
a: f32,
closed: bool,
) {
self.gizmo_renderer.add_line(points, r, g, b, a, closed);
}
/// Add a capsule gizmo.
/// 添加胶囊Gizmo。
pub fn add_gizmo_capsule(
&mut self,
x: f32,
y: f32,
radius: f32,
half_height: f32,
rotation: f32,
r: f32,
g: f32,
b: f32,
a: f32,
) {
self.gizmo_renderer.add_capsule(x, y, radius, half_height, rotation, r, g, b, a);
}
/// Set transform tool mode.
/// 设置变换工具模式。
pub fn set_transform_mode(&mut self, mode: u8) {
let transform_mode = match mode {
1 => TransformMode::Move,
2 => TransformMode::Rotate,
3 => TransformMode::Scale,
_ => TransformMode::Select,
};
self.gizmo_renderer.set_transform_mode(transform_mode);
}
/// Load a texture from URL.
/// 从URL加载纹理。
pub fn load_texture(&mut self, id: u32, url: &str) -> Result<()> {
self.texture_manager.load_texture(id, url)
}
/// Load texture by path, returning texture ID.
/// 按路径加载纹理返回纹理ID。
pub fn load_texture_by_path(&mut self, path: &str) -> Result<u32> {
self.texture_manager.load_texture_by_path(path)
}
/// Get texture ID by path.
/// 按路径获取纹理ID。
pub fn get_texture_id_by_path(&self, path: &str) -> Option<u32> {
self.texture_manager.get_texture_id_by_path(path)
}
/// Get or load texture by path.
/// 按路径获取或加载纹理。
pub fn get_or_load_by_path(&mut self, path: &str) -> Result<u32> {
self.texture_manager.get_or_load_by_path(path)
}
/// Check if a key is currently pressed.
/// 检查某个键是否当前被按下。
pub fn is_key_down(&self, key_code: &str) -> bool {
self.input_manager.is_key_down(key_code)
}
/// Update input state.
/// 更新输入状态。
pub fn update_input(&mut self) {
self.input_manager.update();
}
/// Resize viewport.
/// 调整视口大小。
pub fn resize(&mut self, width: f32, height: f32) {
self.context.resize(width as u32, height as u32);
self.renderer.resize(width, height);
}
/// Set camera position, zoom, and rotation.
/// 设置相机位置、缩放和旋转。
///
/// # Arguments | 参数
/// * `x` - Camera X position | 相机X位置
/// * `y` - Camera Y position | 相机Y位置
/// * `zoom` - Zoom level | 缩放级别
/// * `rotation` - Rotation in radians | 旋转角度(弧度)
pub fn set_camera(&mut self, x: f32, y: f32, zoom: f32, rotation: f32) {
let camera = self.renderer.camera_mut();
camera.position.x = x;
camera.position.y = y;
camera.set_zoom(zoom);
camera.rotation = rotation;
}
/// Get camera position.
/// 获取相机位置。
pub fn get_camera(&self) -> (f32, f32, f32, f32) {
let camera = self.renderer.camera();
(camera.position.x, camera.position.y, camera.zoom, camera.rotation)
}
/// Set grid visibility.
/// 设置网格可见性。
pub fn set_show_grid(&mut self, show: bool) {
self.show_grid = show;
}
/// Set gizmo visibility.
/// 设置辅助工具可见性。
pub fn set_show_gizmos(&mut self, show: bool) {
self.show_gizmos = show;
}
/// Get gizmo visibility.
/// 获取辅助工具可见性。
pub fn show_gizmos(&self) -> bool {
self.show_gizmos
}
/// Set clear color for the active viewport.
/// 设置活动视口的清除颜色。
pub fn set_clear_color(&mut self, r: f32, g: f32, b: f32, a: f32) {
if let Some(target) = self.viewport_manager.active_mut() {
target.set_clear_color(r, g, b, a);
} else {
// Fallback to primary renderer
self.renderer.set_clear_color(r, g, b, a);
}
}
// ===== Multi-viewport API =====
// ===== 多视口 API =====
/// Register a new viewport.
/// 注册新视口。
pub fn register_viewport(&mut self, id: &str, canvas_id: &str) -> Result<()> {
self.viewport_manager.register(id, canvas_id)
}
/// Unregister a viewport.
/// 注销视口。
pub fn unregister_viewport(&mut self, id: &str) {
self.viewport_manager.unregister(id);
}
/// Set the active viewport.
/// 设置活动视口。
pub fn set_active_viewport(&mut self, id: &str) -> bool {
self.viewport_manager.set_active(id)
}
/// Get active viewport ID.
/// 获取活动视口ID。
pub fn active_viewport_id(&self) -> Option<&str> {
self.viewport_manager.active().map(|v| v.id.as_str())
}
/// Set camera for a specific viewport.
/// 为特定视口设置相机。
pub fn set_viewport_camera(&mut self, viewport_id: &str, x: f32, y: f32, zoom: f32, rotation: f32) {
if let Some(viewport) = self.viewport_manager.get_mut(viewport_id) {
viewport.set_camera(x, y, zoom, rotation);
}
}
/// Get camera for a specific viewport.
/// 获取特定视口的相机。
pub fn get_viewport_camera(&self, viewport_id: &str) -> Option<(f32, f32, f32, f32)> {
self.viewport_manager.get(viewport_id).map(|v| v.get_camera())
}
/// Set viewport configuration.
/// 设置视口配置。
pub fn set_viewport_config(&mut self, viewport_id: &str, show_grid: bool, show_gizmos: bool) {
if let Some(viewport) = self.viewport_manager.get_mut(viewport_id) {
viewport.config.show_grid = show_grid;
viewport.config.show_gizmos = show_gizmos;
}
}
/// Resize a specific viewport.
/// 调整特定视口大小。
pub fn resize_viewport(&mut self, viewport_id: &str, width: u32, height: u32) {
if let Some(viewport) = self.viewport_manager.get_mut(viewport_id) {
viewport.resize(width, height);
}
}
/// Render to a specific viewport.
/// 渲染到特定视口。
pub fn render_to_viewport(&mut self, viewport_id: &str) -> Result<()> {
let viewport = match self.viewport_manager.get(viewport_id) {
Some(v) => v,
None => return Ok(()),
};
// Get viewport settings
let show_grid = viewport.config.show_grid;
let show_gizmos = viewport.config.show_gizmos;
let camera = viewport.camera.clone();
// Bind viewport and clear
viewport.bind();
viewport.clear();
// Update renderer camera to match viewport camera
let renderer_camera = self.renderer.camera_mut();
renderer_camera.position = camera.position;
renderer_camera.set_zoom(camera.zoom);
renderer_camera.rotation = camera.rotation;
renderer_camera.set_viewport(camera.viewport_width(), camera.viewport_height());
// Render grid if enabled
if show_grid {
self.grid_renderer.render(viewport.gl(), &camera);
self.grid_renderer.render_axes(viewport.gl(), &camera);
}
// Render sprites
self.renderer.render(viewport.gl(), &self.texture_manager)?;
// Render gizmos if enabled
if show_gizmos {
self.gizmo_renderer.render(viewport.gl(), &camera);
// Render axis indicator in corner
// 在角落渲染坐标轴指示器
let (vp_width, vp_height) = viewport.dimensions();
self.gizmo_renderer.render_axis_indicator(
viewport.gl(),
vp_width as f32,
vp_height as f32,
);
}
self.gizmo_renderer.clear();
Ok(())
}
/// Get all registered viewport IDs.
/// 获取所有已注册的视口ID。
pub fn viewport_ids(&self) -> Vec<String> {
self.viewport_manager.viewport_ids().into_iter().cloned().collect()
}
// ===== Shader Management =====
// ===== 着色器管理 =====
/// Compile and register a custom shader.
/// 编译并注册自定义着色器。
pub fn compile_shader(
&mut self,
vertex_source: &str,
fragment_source: &str,
) -> Result<u32> {
self.renderer.compile_shader(self.context.gl(), vertex_source, fragment_source)
}
/// Compile a shader with a specific ID.
/// 使用特定ID编译着色器。
pub fn compile_shader_with_id(
&mut self,
shader_id: u32,
vertex_source: &str,
fragment_source: &str,
) -> Result<()> {
self.renderer.compile_shader_with_id(self.context.gl(), shader_id, vertex_source, fragment_source)
}
/// Check if a shader exists.
/// 检查着色器是否存在。
pub fn has_shader(&self, shader_id: u32) -> bool {
self.renderer.has_shader(shader_id)
}
/// Remove a shader.
/// 移除着色器。
pub fn remove_shader(&mut self, shader_id: u32) -> bool {
self.renderer.remove_shader(shader_id)
}
// ===== Material Management =====
// ===== 材质管理 =====
/// Create and register a new material.
/// 创建并注册新材质。
pub fn create_material(
&mut self,
name: &str,
shader_id: u32,
blend_mode: u8,
) -> u32 {
use crate::renderer::material::{Material, BlendMode};
let blend = match blend_mode {
0 => BlendMode::None,
1 => BlendMode::Alpha,
2 => BlendMode::Additive,
3 => BlendMode::Multiply,
4 => BlendMode::Screen,
5 => BlendMode::PremultipliedAlpha,
_ => BlendMode::Alpha,
};
let mut material = Material::with_shader(name, shader_id);
material.blend_mode = blend;
self.renderer.register_material(material)
}
/// Create a material with a specific ID.
/// 使用特定ID创建材质。
pub fn create_material_with_id(
&mut self,
material_id: u32,
name: &str,
shader_id: u32,
blend_mode: u8,
) {
use crate::renderer::material::{Material, BlendMode};
let blend = match blend_mode {
0 => BlendMode::None,
1 => BlendMode::Alpha,
2 => BlendMode::Additive,
3 => BlendMode::Multiply,
4 => BlendMode::Screen,
5 => BlendMode::PremultipliedAlpha,
_ => BlendMode::Alpha,
};
let mut material = Material::with_shader(name, shader_id);
material.blend_mode = blend;
self.renderer.register_material_with_id(material_id, material);
}
/// Check if a material exists.
/// 检查材质是否存在。
pub fn has_material(&self, material_id: u32) -> bool {
self.renderer.has_material(material_id)
}
/// Remove a material.
/// 移除材质。
pub fn remove_material(&mut self, material_id: u32) -> bool {
self.renderer.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.renderer.set_material_float(material_id, name, value)
}
/// Set a material's vec2 uniform.
/// 设置材质的vec2 uniform。
pub fn set_material_vec2(&mut self, material_id: u32, name: &str, x: f32, y: f32) -> bool {
if let Some(material) = self.renderer.get_material_mut(material_id) {
material.uniforms.set_vec2(name, x, y);
true
} else {
false
}
}
/// Set a material's vec3 uniform.
/// 设置材质的vec3 uniform。
pub fn set_material_vec3(&mut self, material_id: u32, name: &str, x: f32, y: f32, z: f32) -> bool {
if let Some(material) = self.renderer.get_material_mut(material_id) {
material.uniforms.set_vec3(name, x, y, z);
true
} else {
false
}
}
/// 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.renderer.set_material_vec4(material_id, name, x, y, z, w)
}
/// Set a material's color uniform.
/// 设置材质的颜色uniform。
pub fn set_material_color(&mut self, material_id: u32, name: &str, r: f32, g: f32, b: f32, a: f32) -> bool {
if let Some(material) = self.renderer.get_material_mut(material_id) {
material.uniforms.set_color(name, r, g, b, a);
true
} else {
false
}
}
/// Set a material's blend mode.
/// 设置材质的混合模式。
pub fn set_material_blend_mode(&mut self, material_id: u32, blend_mode: u8) -> bool {
use crate::renderer::material::BlendMode;
let blend = match blend_mode {
0 => BlendMode::None,
1 => BlendMode::Alpha,
2 => BlendMode::Additive,
3 => BlendMode::Multiply,
4 => BlendMode::Screen,
5 => BlendMode::PremultipliedAlpha,
_ => return false,
};
if let Some(material) = self.renderer.get_material_mut(material_id) {
material.blend_mode = blend;
true
} else {
false
}
}
}