Feature/render pipeline (#232)

* refactor(engine): 重构2D渲染管线坐标系统

* feat(engine): 完善2D渲染管线和编辑器视口功能

* feat(editor): 实现Viewport变换工具系统

* feat(editor): 优化Inspector渲染性能并修复Gizmo变换工具显示

* feat(editor): 实现Run on Device移动预览功能

* feat(editor): 添加组件属性控制和依赖关系系统

* feat(editor): 实现动画预览功能和优化SpriteAnimator编辑器

* feat(editor): 修复SpriteAnimator动画预览功能并迁移CI到pnpm

* feat(editor): 修复SpriteAnimator动画预览并迁移到pnpm

* feat(editor): 修复SpriteAnimator动画预览并迁移到pnpm

* feat(editor): 修复SpriteAnimator动画预览并迁移到pnpm

* feat(editor): 修复SpriteAnimator动画预览并迁移到pnpm

* feat(ci): 迁移项目到pnpm并修复CI构建问题

* chore: 迁移CI工作流到pnpm并添加WASM构建支持

* chore: 迁移CI工作流到pnpm并添加WASM构建支持

* chore: 迁移CI工作流到pnpm并添加WASM构建支持

* chore: 迁移CI工作流到pnpm并添加WASM构建支持

* chore: 迁移CI工作流到pnpm并添加WASM构建支持

* chore: 迁移CI工作流到pnpm并添加WASM构建支持

* chore: 移除 network 相关包

* chore: 移除 network 相关包
This commit is contained in:
YHH
2025-11-23 14:49:37 +08:00
committed by GitHub
parent b15cbab313
commit a3f7cc38b1
247 changed files with 33561 additions and 52047 deletions

View File

@@ -2,8 +2,6 @@
//! 纹理加载和管理。
use std::collections::HashMap;
use std::cell::RefCell;
use std::rc::Rc;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use web_sys::{HtmlImageElement, WebGl2RenderingContext, WebGlTexture};
@@ -22,6 +20,14 @@ pub struct TextureManager {
/// 已加载的纹理。
textures: HashMap<u32, Texture>,
/// Path to texture ID mapping.
/// 路径到纹理ID的映射。
path_to_id: HashMap<String, u32>,
/// Next texture ID for auto-assignment.
/// 下一个自动分配的纹理ID。
next_id: u32,
/// Default white texture for untextured rendering.
/// 用于无纹理渲染的默认白色纹理。
default_texture: Option<WebGlTexture>,
@@ -34,6 +40,8 @@ impl TextureManager {
let mut manager = Self {
gl,
textures: HashMap::new(),
path_to_id: HashMap::new(),
next_id: 1, // Start from 1, 0 is reserved for default
default_texture: None,
};
@@ -105,32 +113,34 @@ impl TextureManager {
Some(&placeholder),
);
// Clone texture handle for async loading before storing | 在存储前克隆纹理句柄用于异步加载
let texture_for_closure = texture.clone();
// Store texture with placeholder size | 存储带占位符尺寸的纹理
self.textures.insert(id, Texture::new(texture.clone(), 1, 1));
self.textures.insert(id, Texture::new(texture, 1, 1));
// Load actual image asynchronously | 异步加载实际图片
let gl = self.gl.clone();
let texture_rc = Rc::new(RefCell::new(texture));
let texture_clone = Rc::clone(&texture_rc);
// We need to update the stored texture size after loading
// For MVP, we'll handle this through a callback mechanism
// 加载后需要更新存储的纹理尺寸
// 对于MVP我们通过回调机制处理
let image = HtmlImageElement::new()
.map_err(|_| EngineError::TextureLoadFailed("Failed to create image element".into()))?;
// Set crossOrigin for CORS support | 设置crossOrigin以支持CORS
image.set_cross_origin(Some("anonymous"));
// Clone image for use in closure | 克隆图片用于闭包
let image_clone = image.clone();
// Set up load callback | 设置加载回调
let onload = Closure::wrap(Box::new(move || {
let tex = texture_clone.borrow();
gl.bind_texture(WebGl2RenderingContext::TEXTURE_2D, Some(&tex));
gl.bind_texture(WebGl2RenderingContext::TEXTURE_2D, Some(&texture_for_closure));
// Flip Y axis for correct orientation (image coords vs WebGL coords)
// 翻转Y轴以获得正确的方向图像坐标系 vs WebGL坐标系
gl.pixel_storei(WebGl2RenderingContext::UNPACK_FLIP_Y_WEBGL, 1);
// Use the captured image element | 使用捕获的图片元素
let _ = gl.tex_image_2d_with_u32_and_u32_and_html_image_element(
let result = gl.tex_image_2d_with_u32_and_u32_and_html_image_element(
WebGl2RenderingContext::TEXTURE_2D,
0,
WebGl2RenderingContext::RGBA as i32,
@@ -139,6 +149,10 @@ impl TextureManager {
&image_clone,
);
if let Err(e) = result {
log::error!("Failed to upload texture: {:?} | 纹理上传失败: {:?}", e, e);
}
// Set texture parameters | 设置纹理参数
gl.tex_parameteri(
WebGl2RenderingContext::TEXTURE_2D,
@@ -161,7 +175,6 @@ impl TextureManager {
WebGl2RenderingContext::LINEAR as i32,
);
log::debug!("Texture loaded | 纹理加载完成");
}) as Box<dyn Fn()>);
image.set_onload(Some(onload.as_ref().unchecked_ref()));
@@ -196,7 +209,14 @@ impl TextureManager {
if let Some(texture) = self.textures.get(&id) {
self.gl.bind_texture(WebGl2RenderingContext::TEXTURE_2D, Some(&texture.handle));
} else if let Some(default) = &self.default_texture {
// ID 0 is the default texture, no warning needed
// ID 0 是默认纹理,不需要警告
if id != 0 {
log::warn!("Texture {} not found, using default | 未找到纹理 {},使用默认纹理", id, id);
}
self.gl.bind_texture(WebGl2RenderingContext::TEXTURE_2D, Some(default));
} else {
log::error!("Texture {} not found and no default texture! | 未找到纹理 {} 且没有默认纹理!", id, id);
}
}
@@ -213,5 +233,57 @@ impl TextureManager {
if let Some(texture) = self.textures.remove(&id) {
self.gl.delete_texture(Some(&texture.handle));
}
// Also remove from path mapping | 同时从路径映射中移除
self.path_to_id.retain(|_, &mut v| v != id);
}
/// Load texture by path, returning texture ID.
/// 按路径加载纹理返回纹理ID。
///
/// If the texture is already loaded, returns existing ID.
/// 如果纹理已加载返回现有ID。
pub fn load_texture_by_path(&mut self, path: &str) -> Result<u32> {
// Check if already loaded | 检查是否已加载
if let Some(&id) = self.path_to_id.get(path) {
return Ok(id);
}
// Assign new ID and load | 分配新ID并加载
let id = self.next_id;
self.next_id += 1;
// Store path mapping first | 先存储路径映射
self.path_to_id.insert(path.to_string(), id);
// Load texture with assigned ID | 用分配的ID加载纹理
self.load_texture(id, path)?;
Ok(id)
}
/// Get texture ID by path.
/// 按路径获取纹理ID。
///
/// Returns None if texture is not loaded.
/// 如果纹理未加载返回None。
#[inline]
pub fn get_texture_id_by_path(&self, path: &str) -> Option<u32> {
self.path_to_id.get(path).copied()
}
/// Get or load texture by path.
/// 按路径获取或加载纹理。
///
/// If texture is already loaded, returns existing ID.
/// If not loaded, loads it and returns new ID.
/// 如果纹理已加载返回现有ID。
/// 如果未加载加载它并返回新ID。
pub fn get_or_load_by_path(&mut self, path: &str) -> Result<u32> {
// Empty path means default texture | 空路径表示默认纹理
if path.is_empty() {
return Ok(0);
}
self.load_texture_by_path(path)
}
}