//! 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, /// Whether the engine is running in editor mode. /// 引擎是否在编辑器模式下运行。 /// /// When false (runtime mode), editor-only UI like grid, gizmos, /// and axis indicator are automatically hidden. /// 当为 false(运行时模式)时,编辑器专用 UI(如网格、gizmos、坐标轴指示器)会自动隐藏。 is_editor: 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 { 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, is_editor: true, // 默认为编辑器模式 | Default to editor mode }) } /// 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 { 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, is_editor: true, // 默认为编辑器模式 | Default to editor mode }) } /// 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) - only in editor mode // 首先渲染网格(背景)- 仅在编辑器模式下 if self.is_editor && 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 - only in editor mode // 在顶部渲染 gizmos - 仅在编辑器模式下 if self.is_editor && 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, 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 { 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 { 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 { 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 editor mode. /// 设置编辑器模式。 /// /// When false (runtime mode), editor-only UI like grid, gizmos, /// and axis indicator are automatically hidden regardless of their individual settings. /// 当为 false(运行时模式)时,编辑器专用 UI(如网格、gizmos、坐标轴指示器) /// 会自动隐藏,无论它们的单独设置如何。 pub fn set_editor_mode(&mut self, is_editor: bool) { self.is_editor = is_editor; } /// Get editor mode. /// 获取编辑器模式。 pub fn is_editor(&self) -> bool { self.is_editor } /// 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 - only in editor mode // 渲染网格(如果启用)- 仅在编辑器模式下 if self.is_editor && 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 - only in editor mode // 渲染 gizmos(如果启用)- 仅在编辑器模式下 if self.is_editor && 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 { 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 { 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 } } }