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检测到的代码问题
This commit is contained in:
@@ -185,6 +185,7 @@ impl Engine {
|
||||
texture_ids: &[u32],
|
||||
uvs: &[f32],
|
||||
colors: &[u32],
|
||||
material_ids: &[u32],
|
||||
) -> Result<()> {
|
||||
// Debug: log once
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
@@ -199,6 +200,7 @@ impl Engine {
|
||||
texture_ids,
|
||||
uvs,
|
||||
colors,
|
||||
material_ids,
|
||||
&self.texture_manager,
|
||||
)
|
||||
}
|
||||
@@ -533,4 +535,176 @@ impl Engine {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,6 +142,7 @@ impl GameEngine {
|
||||
/// * `texture_ids` - Uint32Array of texture IDs | 纹理ID数组
|
||||
/// * `uvs` - Float32Array [u0, v0, u1, v1] per sprite | 每个精灵的UV坐标
|
||||
/// * `colors` - Uint32Array of packed RGBA colors | 打包的RGBA颜色数组
|
||||
/// * `material_ids` - Uint32Array of material IDs (0 = default) | 材质ID数组(0 = 默认)
|
||||
#[wasm_bindgen(js_name = submitSpriteBatch)]
|
||||
pub fn submit_sprite_batch(
|
||||
&mut self,
|
||||
@@ -149,9 +150,10 @@ impl GameEngine {
|
||||
texture_ids: &[u32],
|
||||
uvs: &[f32],
|
||||
colors: &[u32],
|
||||
material_ids: &[u32],
|
||||
) -> std::result::Result<(), JsValue> {
|
||||
self.engine
|
||||
.submit_sprite_batch(transforms, texture_ids, uvs, colors)
|
||||
.submit_sprite_batch(transforms, texture_ids, uvs, colors, material_ids)
|
||||
.map_err(|e| JsValue::from_str(&e.to_string()))
|
||||
}
|
||||
|
||||
@@ -463,4 +465,150 @@ impl GameEngine {
|
||||
pub fn get_viewport_ids(&self) -> Vec<String> {
|
||||
self.engine.viewport_ids()
|
||||
}
|
||||
|
||||
// ===== Shader API =====
|
||||
// ===== 着色器 API =====
|
||||
|
||||
/// Compile and register a custom shader.
|
||||
/// 编译并注册自定义着色器。
|
||||
///
|
||||
/// # Arguments | 参数
|
||||
/// * `vertex_source` - Vertex shader GLSL source | 顶点着色器GLSL源代码
|
||||
/// * `fragment_source` - Fragment shader GLSL source | 片段着色器GLSL源代码
|
||||
///
|
||||
/// # Returns | 返回
|
||||
/// The shader ID for referencing this shader | 用于引用此着色器的ID
|
||||
#[wasm_bindgen(js_name = compileShader)]
|
||||
pub fn compile_shader(
|
||||
&mut self,
|
||||
vertex_source: &str,
|
||||
fragment_source: &str,
|
||||
) -> std::result::Result<u32, JsValue> {
|
||||
self.engine
|
||||
.compile_shader(vertex_source, fragment_source)
|
||||
.map_err(|e| JsValue::from_str(&e.to_string()))
|
||||
}
|
||||
|
||||
/// Compile a shader with a specific ID.
|
||||
/// 使用特定ID编译着色器。
|
||||
#[wasm_bindgen(js_name = compileShaderWithId)]
|
||||
pub fn compile_shader_with_id(
|
||||
&mut self,
|
||||
shader_id: u32,
|
||||
vertex_source: &str,
|
||||
fragment_source: &str,
|
||||
) -> std::result::Result<(), JsValue> {
|
||||
self.engine
|
||||
.compile_shader_with_id(shader_id, vertex_source, fragment_source)
|
||||
.map_err(|e| JsValue::from_str(&e.to_string()))
|
||||
}
|
||||
|
||||
/// Check if a shader exists.
|
||||
/// 检查着色器是否存在。
|
||||
#[wasm_bindgen(js_name = hasShader)]
|
||||
pub fn has_shader(&self, shader_id: u32) -> bool {
|
||||
self.engine.has_shader(shader_id)
|
||||
}
|
||||
|
||||
/// Remove a shader.
|
||||
/// 移除着色器。
|
||||
#[wasm_bindgen(js_name = removeShader)]
|
||||
pub fn remove_shader(&mut self, shader_id: u32) -> bool {
|
||||
self.engine.remove_shader(shader_id)
|
||||
}
|
||||
|
||||
// ===== Material API =====
|
||||
// ===== 材质 API =====
|
||||
|
||||
/// Create and register a new material.
|
||||
/// 创建并注册新材质。
|
||||
///
|
||||
/// # Arguments | 参数
|
||||
/// * `name` - Material name for debugging | 材质名称(用于调试)
|
||||
/// * `shader_id` - Shader ID to use | 使用的着色器ID
|
||||
/// * `blend_mode` - Blend mode: 0=None, 1=Alpha, 2=Additive, 3=Multiply, 4=Screen, 5=PremultipliedAlpha
|
||||
///
|
||||
/// # Returns | 返回
|
||||
/// The material ID for referencing this material | 用于引用此材质的ID
|
||||
#[wasm_bindgen(js_name = createMaterial)]
|
||||
pub fn create_material(
|
||||
&mut self,
|
||||
name: &str,
|
||||
shader_id: u32,
|
||||
blend_mode: u8,
|
||||
) -> u32 {
|
||||
self.engine.create_material(name, shader_id, blend_mode)
|
||||
}
|
||||
|
||||
/// Create a material with a specific ID.
|
||||
/// 使用特定ID创建材质。
|
||||
#[wasm_bindgen(js_name = createMaterialWithId)]
|
||||
pub fn create_material_with_id(
|
||||
&mut self,
|
||||
material_id: u32,
|
||||
name: &str,
|
||||
shader_id: u32,
|
||||
blend_mode: u8,
|
||||
) {
|
||||
self.engine.create_material_with_id(material_id, name, shader_id, blend_mode);
|
||||
}
|
||||
|
||||
/// Check if a material exists.
|
||||
/// 检查材质是否存在。
|
||||
#[wasm_bindgen(js_name = hasMaterial)]
|
||||
pub fn has_material(&self, material_id: u32) -> bool {
|
||||
self.engine.has_material(material_id)
|
||||
}
|
||||
|
||||
/// Remove a material.
|
||||
/// 移除材质。
|
||||
#[wasm_bindgen(js_name = removeMaterial)]
|
||||
pub fn remove_material(&mut self, material_id: u32) -> bool {
|
||||
self.engine.remove_material(material_id)
|
||||
}
|
||||
|
||||
/// Set a material's float uniform.
|
||||
/// 设置材质的浮点uniform。
|
||||
#[wasm_bindgen(js_name = setMaterialFloat)]
|
||||
pub fn set_material_float(&mut self, material_id: u32, name: &str, value: f32) -> bool {
|
||||
self.engine.set_material_float(material_id, name, value)
|
||||
}
|
||||
|
||||
/// Set a material's vec2 uniform.
|
||||
/// 设置材质的vec2 uniform。
|
||||
#[wasm_bindgen(js_name = setMaterialVec2)]
|
||||
pub fn set_material_vec2(&mut self, material_id: u32, name: &str, x: f32, y: f32) -> bool {
|
||||
self.engine.set_material_vec2(material_id, name, x, y)
|
||||
}
|
||||
|
||||
/// Set a material's vec3 uniform.
|
||||
/// 设置材质的vec3 uniform。
|
||||
#[wasm_bindgen(js_name = setMaterialVec3)]
|
||||
pub fn set_material_vec3(&mut self, material_id: u32, name: &str, x: f32, y: f32, z: f32) -> bool {
|
||||
self.engine.set_material_vec3(material_id, name, x, y, z)
|
||||
}
|
||||
|
||||
/// Set a material's vec4 uniform (also used for colors).
|
||||
/// 设置材质的vec4 uniform(也用于颜色)。
|
||||
#[wasm_bindgen(js_name = setMaterialVec4)]
|
||||
pub fn set_material_vec4(&mut self, material_id: u32, name: &str, x: f32, y: f32, z: f32, w: f32) -> bool {
|
||||
self.engine.set_material_vec4(material_id, name, x, y, z, w)
|
||||
}
|
||||
|
||||
/// Set a material's color uniform (RGBA, 0.0-1.0).
|
||||
/// 设置材质的颜色uniform(RGBA,0.0-1.0)。
|
||||
#[wasm_bindgen(js_name = setMaterialColor)]
|
||||
pub fn set_material_color(&mut self, material_id: u32, name: &str, r: f32, g: f32, b: f32, a: f32) -> bool {
|
||||
self.engine.set_material_color(material_id, name, r, g, b, a)
|
||||
}
|
||||
|
||||
/// Set a material's blend mode.
|
||||
/// 设置材质的混合模式。
|
||||
///
|
||||
/// # Arguments | 参数
|
||||
/// * `blend_mode` - 0=None, 1=Alpha, 2=Additive, 3=Multiply, 4=Screen, 5=PremultipliedAlpha
|
||||
#[wasm_bindgen(js_name = setMaterialBlendMode)]
|
||||
pub fn set_material_blend_mode(&mut self, material_id: u32, blend_mode: u8) -> bool {
|
||||
self.engine.set_material_blend_mode(material_id, blend_mode)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ use bytemuck::{Pod, Zeroable};
|
||||
///
|
||||
/// # Examples | 示例
|
||||
/// ```rust
|
||||
/// use es_engine::math::Color;
|
||||
/// let red = Color::RED;
|
||||
/// let custom = Color::new(0.5, 0.7, 0.3, 1.0);
|
||||
/// let packed = custom.to_packed(); // For GPU
|
||||
|
||||
@@ -8,6 +8,7 @@ use super::Vec2;
|
||||
///
|
||||
/// # Examples | 示例
|
||||
/// ```rust
|
||||
/// use es_engine::math::{Rect, Vec2};
|
||||
/// let rect = Rect::new(10.0, 20.0, 100.0, 50.0);
|
||||
/// let point = Vec2::new(50.0, 40.0);
|
||||
/// assert!(rect.contains_point(point));
|
||||
|
||||
@@ -9,6 +9,7 @@ use glam::Mat3;
|
||||
///
|
||||
/// # Examples | 示例
|
||||
/// ```rust
|
||||
/// use es_engine::math::{Transform2D, Vec2};
|
||||
/// let mut transform = Transform2D::new();
|
||||
/// transform.position = Vec2::new(100.0, 200.0);
|
||||
/// transform.rotation = std::f32::consts::PI / 4.0; // 45 degrees
|
||||
|
||||
@@ -8,6 +8,7 @@ use bytemuck::{Pod, Zeroable};
|
||||
///
|
||||
/// # Examples | 示例
|
||||
/// ```rust
|
||||
/// use es_engine::math::Vec2;
|
||||
/// let pos = Vec2::new(100.0, 200.0);
|
||||
/// let velocity = Vec2::new(1.0, 0.0);
|
||||
/// let new_pos = pos + velocity * 16.0;
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
mod sprite_batch;
|
||||
mod vertex;
|
||||
|
||||
pub use sprite_batch::SpriteBatch;
|
||||
pub use sprite_batch::{BatchKey, SpriteBatch};
|
||||
pub use vertex::{SpriteVertex, VERTEX_SIZE};
|
||||
|
||||
@@ -27,6 +27,18 @@ const TRANSFORM_STRIDE: usize = 7;
|
||||
/// UV数据步长。
|
||||
const UV_STRIDE: usize = 4;
|
||||
|
||||
/// Batch key combining material and texture IDs.
|
||||
/// 组合材质ID和纹理ID的批次键。
|
||||
#[derive(Hash, Eq, PartialEq, Clone, Copy, Debug)]
|
||||
pub struct BatchKey {
|
||||
/// Material ID (0 = default material).
|
||||
/// 材质ID(0 = 默认材质)。
|
||||
pub material_id: u32,
|
||||
/// Texture ID.
|
||||
/// 纹理ID。
|
||||
pub texture_id: u32,
|
||||
}
|
||||
|
||||
/// Sprite batch renderer.
|
||||
/// 精灵批处理渲染器。
|
||||
///
|
||||
@@ -35,7 +47,7 @@ const UV_STRIDE: usize = 4;
|
||||
///
|
||||
/// # Performance | 性能
|
||||
/// - Uses dynamic vertex buffer for efficient updates | 使用动态顶点缓冲区以高效更新
|
||||
/// - Groups sprites by texture to minimize state changes | 按纹理分组精灵以最小化状态更改
|
||||
/// - Groups sprites by material and texture to minimize state changes | 按材质和纹理分组精灵以最小化状态更改
|
||||
/// - Supports up to 10000+ sprites per batch | 每批次支持10000+精灵
|
||||
pub struct SpriteBatch {
|
||||
/// Vertex array object.
|
||||
@@ -54,9 +66,9 @@ pub struct SpriteBatch {
|
||||
/// 最大精灵数。
|
||||
max_sprites: usize,
|
||||
|
||||
/// Per-texture vertex data buffers.
|
||||
/// 按纹理分组的顶点数据缓冲区。
|
||||
texture_batches: HashMap<u32, Vec<f32>>,
|
||||
/// Per-material-texture vertex data buffers.
|
||||
/// 按材质和纹理分组的顶点数据缓冲区。
|
||||
batches: HashMap<BatchKey, Vec<f32>>,
|
||||
|
||||
/// Total sprite count across all batches.
|
||||
/// 所有批次的总精灵数。
|
||||
@@ -124,7 +136,7 @@ impl SpriteBatch {
|
||||
vbo,
|
||||
ibo,
|
||||
max_sprites,
|
||||
texture_batches: HashMap::new(),
|
||||
batches: HashMap::new(),
|
||||
sprite_count: 0,
|
||||
})
|
||||
}
|
||||
@@ -192,7 +204,7 @@ impl SpriteBatch {
|
||||
/// Clear the batch for a new frame.
|
||||
/// 为新帧清空批处理。
|
||||
pub fn clear(&mut self) {
|
||||
for batch in self.texture_batches.values_mut() {
|
||||
for batch in self.batches.values_mut() {
|
||||
batch.clear();
|
||||
}
|
||||
self.sprite_count = 0;
|
||||
@@ -206,6 +218,7 @@ impl SpriteBatch {
|
||||
/// * `texture_ids` - Texture ID for each sprite | 每个精灵的纹理ID
|
||||
/// * `uvs` - [u0, v0, u1, v1] per sprite | 每个精灵的UV坐标
|
||||
/// * `colors` - Packed RGBA color per sprite | 每个精灵的打包RGBA颜色
|
||||
/// * `material_ids` - Material ID for each sprite (0 = default) | 每个精灵的材质ID(0 = 默认)
|
||||
/// * `_texture_manager` - Texture manager for getting texture sizes | 纹理管理器
|
||||
pub fn add_sprites(
|
||||
&mut self,
|
||||
@@ -213,6 +226,7 @@ impl SpriteBatch {
|
||||
texture_ids: &[u32],
|
||||
uvs: &[f32],
|
||||
colors: &[u32],
|
||||
material_ids: &[u32],
|
||||
_texture_manager: &TextureManager,
|
||||
) -> Result<()> {
|
||||
let sprite_count = texture_ids.len();
|
||||
@@ -242,6 +256,14 @@ impl SpriteBatch {
|
||||
)));
|
||||
}
|
||||
|
||||
if material_ids.len() != sprite_count {
|
||||
return Err(EngineError::InvalidBatchData(format!(
|
||||
"Material ID data length mismatch: expected {}, got {}",
|
||||
sprite_count,
|
||||
material_ids.len()
|
||||
)));
|
||||
}
|
||||
|
||||
// Check capacity | 检查容量
|
||||
if self.sprite_count + sprite_count > self.max_sprites {
|
||||
return Err(EngineError::InvalidBatchData(format!(
|
||||
@@ -250,7 +272,7 @@ impl SpriteBatch {
|
||||
)));
|
||||
}
|
||||
|
||||
// Add each sprite grouped by texture | 按纹理分组添加每个精灵
|
||||
// Add each sprite grouped by material and texture | 按材质和纹理分组添加每个精灵
|
||||
for i in 0..sprite_count {
|
||||
let t_offset = i * TRANSFORM_STRIDE;
|
||||
let uv_offset = i * UV_STRIDE;
|
||||
@@ -276,11 +298,14 @@ impl SpriteBatch {
|
||||
let width = scale_x;
|
||||
let height = scale_y;
|
||||
|
||||
let texture_id = texture_ids[i];
|
||||
let batch_key = BatchKey {
|
||||
material_id: material_ids[i],
|
||||
texture_id: texture_ids[i],
|
||||
};
|
||||
|
||||
// Get or create batch for this texture | 获取或创建此纹理的批次
|
||||
let batch = self.texture_batches
|
||||
.entry(texture_id)
|
||||
// Get or create batch for this material+texture combination | 获取或创建此材质+纹理组合的批次
|
||||
let batch = self.batches
|
||||
.entry(batch_key)
|
||||
.or_insert_with(Vec::new);
|
||||
|
||||
// Calculate transformed vertices and add to batch | 计算变换后的顶点并添加到批次
|
||||
@@ -367,9 +392,9 @@ impl SpriteBatch {
|
||||
}
|
||||
}
|
||||
|
||||
/// Flush a specific texture batch to GPU and render.
|
||||
/// 将特定纹理批次刷新到GPU并渲染。
|
||||
fn flush_texture_batch(&self, gl: &WebGl2RenderingContext, vertices: &[f32]) {
|
||||
/// Flush a batch to GPU and render.
|
||||
/// 将批次刷新到GPU并渲染。
|
||||
fn flush_batch(&self, gl: &WebGl2RenderingContext, vertices: &[f32]) {
|
||||
if vertices.is_empty() {
|
||||
return;
|
||||
}
|
||||
@@ -403,17 +428,17 @@ impl SpriteBatch {
|
||||
gl.bind_vertex_array(None);
|
||||
}
|
||||
|
||||
/// Get texture batches for rendering.
|
||||
/// 获取用于渲染的纹理批次。
|
||||
pub fn texture_batches(&self) -> &HashMap<u32, Vec<f32>> {
|
||||
&self.texture_batches
|
||||
/// Get all batches for rendering.
|
||||
/// 获取所有批次用于渲染。
|
||||
pub fn batches(&self) -> &HashMap<BatchKey, Vec<f32>> {
|
||||
&self.batches
|
||||
}
|
||||
|
||||
/// Flush a specific texture batch.
|
||||
/// 刷新特定纹理批次。
|
||||
pub fn flush_for_texture(&self, gl: &WebGl2RenderingContext, texture_id: u32) {
|
||||
if let Some(vertices) = self.texture_batches.get(&texture_id) {
|
||||
self.flush_texture_batch(gl, vertices);
|
||||
/// Flush a specific batch by key.
|
||||
/// 按键刷新特定批次。
|
||||
pub fn flush_for_batch(&self, gl: &WebGl2RenderingContext, key: &BatchKey) {
|
||||
if let Some(vertices) = self.batches.get(key) {
|
||||
self.flush_batch(gl, vertices);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
207
packages/engine/src/renderer/material/manager.rs
Normal file
207
packages/engine/src/renderer/material/manager.rs
Normal file
@@ -0,0 +1,207 @@
|
||||
//! Material manager for storing and retrieving materials.
|
||||
//! 材质管理器,用于存储和检索材质。
|
||||
|
||||
use std::collections::HashMap;
|
||||
use web_sys::WebGl2RenderingContext;
|
||||
|
||||
use super::material::{Material, BlendMode};
|
||||
|
||||
/// Reserved material IDs for built-in materials.
|
||||
/// 内置材质的保留ID。
|
||||
pub const MATERIAL_ID_DEFAULT: u32 = 0;
|
||||
pub const MATERIAL_ID_ADDITIVE: u32 = 1;
|
||||
pub const MATERIAL_ID_MULTIPLY: u32 = 2;
|
||||
pub const MATERIAL_ID_UNLIT: u32 = 3;
|
||||
|
||||
/// Material manager for creating and caching materials.
|
||||
/// 材质管理器,用于创建和缓存材质。
|
||||
pub struct MaterialManager {
|
||||
/// Stored materials indexed by ID.
|
||||
/// 按ID索引的存储材质。
|
||||
materials: HashMap<u32, Material>,
|
||||
|
||||
/// Next available material ID for custom materials.
|
||||
/// 下一个可用的自定义材质ID。
|
||||
next_material_id: u32,
|
||||
}
|
||||
|
||||
impl MaterialManager {
|
||||
/// Create a new material manager with built-in materials.
|
||||
/// 创建带有内置材质的新材质管理器。
|
||||
pub fn new() -> Self {
|
||||
let mut manager = Self {
|
||||
materials: HashMap::new(),
|
||||
next_material_id: 100, // Reserve 0-99 for built-in materials
|
||||
};
|
||||
|
||||
// Register built-in materials | 注册内置材质
|
||||
manager.materials.insert(MATERIAL_ID_DEFAULT, Material::sprite());
|
||||
manager.materials.insert(MATERIAL_ID_ADDITIVE, Material::additive());
|
||||
manager.materials.insert(MATERIAL_ID_MULTIPLY, Material::multiply());
|
||||
manager.materials.insert(MATERIAL_ID_UNLIT, Material::unlit());
|
||||
|
||||
log::info!("MaterialManager initialized with {} built-in materials | 材质管理器初始化完成,内置材质数量: {}",
|
||||
manager.materials.len(), manager.materials.len());
|
||||
|
||||
manager
|
||||
}
|
||||
|
||||
/// Register a custom material.
|
||||
/// 注册自定义材质。
|
||||
///
|
||||
/// # Returns | 返回
|
||||
/// The material ID for referencing this material | 用于引用此材质的ID
|
||||
pub fn register_material(&mut self, material: Material) -> u32 {
|
||||
let material_id = self.next_material_id;
|
||||
self.next_material_id += 1;
|
||||
|
||||
log::debug!("Registered material '{}' with ID: {} | 注册材质 '{}' ID: {}",
|
||||
material.name, material_id, material.name, material_id);
|
||||
|
||||
self.materials.insert(material_id, material);
|
||||
material_id
|
||||
}
|
||||
|
||||
/// Register a material with a specific ID.
|
||||
/// 使用特定ID注册材质。
|
||||
pub fn register_material_with_id(&mut self, material_id: u32, material: Material) {
|
||||
log::debug!("Registered material '{}' with ID: {} | 注册材质 '{}' ID: {}",
|
||||
material.name, material_id, material.name, material_id);
|
||||
|
||||
self.materials.insert(material_id, material);
|
||||
|
||||
// Update next_material_id if necessary
|
||||
if material_id >= self.next_material_id {
|
||||
self.next_material_id = material_id + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a material by ID.
|
||||
/// 按ID获取材质。
|
||||
#[inline]
|
||||
pub fn get_material(&self, material_id: u32) -> Option<&Material> {
|
||||
self.materials.get(&material_id)
|
||||
}
|
||||
|
||||
/// Get a mutable material by ID.
|
||||
/// 按ID获取可变材质。
|
||||
#[inline]
|
||||
pub fn get_material_mut(&mut self, material_id: u32) -> Option<&mut Material> {
|
||||
self.materials.get_mut(&material_id)
|
||||
}
|
||||
|
||||
/// Get the default material.
|
||||
/// 获取默认材质。
|
||||
#[inline]
|
||||
pub fn get_default_material(&self) -> &Material {
|
||||
self.materials.get(&MATERIAL_ID_DEFAULT)
|
||||
.expect("Default material should always exist | 默认材质应该始终存在")
|
||||
}
|
||||
|
||||
/// Check if a material exists.
|
||||
/// 检查材质是否存在。
|
||||
#[inline]
|
||||
pub fn has_material(&self, material_id: u32) -> bool {
|
||||
self.materials.contains_key(&material_id)
|
||||
}
|
||||
|
||||
/// Remove a material.
|
||||
/// 移除材质。
|
||||
///
|
||||
/// Note: Cannot remove built-in materials (ID < 100).
|
||||
/// 注意:无法移除内置材质(ID < 100)。
|
||||
pub fn remove_material(&mut self, material_id: u32) -> bool {
|
||||
if material_id < 100 {
|
||||
log::warn!("Cannot remove built-in material: {} | 无法移除内置材质: {}", material_id, material_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
self.materials.remove(&material_id).is_some()
|
||||
}
|
||||
|
||||
/// Update a material's uniform value.
|
||||
/// 更新材质的uniform值。
|
||||
pub fn set_material_float(&mut self, material_id: u32, name: &str, value: f32) -> bool {
|
||||
if let Some(material) = self.materials.get_mut(&material_id) {
|
||||
material.uniforms.set_float(name, value);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Update 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 {
|
||||
if let Some(material) = self.materials.get_mut(&material_id) {
|
||||
material.uniforms.set_vec4(name, x, y, z, w);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply blend mode to WebGL context.
|
||||
/// 将混合模式应用到WebGL上下文。
|
||||
pub fn apply_blend_mode(gl: &WebGl2RenderingContext, blend_mode: BlendMode) {
|
||||
match blend_mode {
|
||||
BlendMode::None => {
|
||||
gl.disable(WebGl2RenderingContext::BLEND);
|
||||
}
|
||||
BlendMode::Alpha => {
|
||||
gl.enable(WebGl2RenderingContext::BLEND);
|
||||
gl.blend_func(
|
||||
WebGl2RenderingContext::SRC_ALPHA,
|
||||
WebGl2RenderingContext::ONE_MINUS_SRC_ALPHA,
|
||||
);
|
||||
}
|
||||
BlendMode::Additive => {
|
||||
gl.enable(WebGl2RenderingContext::BLEND);
|
||||
gl.blend_func(
|
||||
WebGl2RenderingContext::SRC_ALPHA,
|
||||
WebGl2RenderingContext::ONE,
|
||||
);
|
||||
}
|
||||
BlendMode::Multiply => {
|
||||
gl.enable(WebGl2RenderingContext::BLEND);
|
||||
gl.blend_func(
|
||||
WebGl2RenderingContext::DST_COLOR,
|
||||
WebGl2RenderingContext::ZERO,
|
||||
);
|
||||
}
|
||||
BlendMode::Screen => {
|
||||
gl.enable(WebGl2RenderingContext::BLEND);
|
||||
gl.blend_func(
|
||||
WebGl2RenderingContext::ONE,
|
||||
WebGl2RenderingContext::ONE_MINUS_SRC_COLOR,
|
||||
);
|
||||
}
|
||||
BlendMode::PremultipliedAlpha => {
|
||||
gl.enable(WebGl2RenderingContext::BLEND);
|
||||
gl.blend_func(
|
||||
WebGl2RenderingContext::ONE,
|
||||
WebGl2RenderingContext::ONE_MINUS_SRC_ALPHA,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get all material IDs.
|
||||
/// 获取所有材质ID。
|
||||
pub fn material_ids(&self) -> Vec<u32> {
|
||||
self.materials.keys().copied().collect()
|
||||
}
|
||||
|
||||
/// Get material count.
|
||||
/// 获取材质数量。
|
||||
#[inline]
|
||||
pub fn material_count(&self) -> usize {
|
||||
self.materials.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MaterialManager {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
177
packages/engine/src/renderer/material/material.rs
Normal file
177
packages/engine/src/renderer/material/material.rs
Normal file
@@ -0,0 +1,177 @@
|
||||
//! Material definition and properties.
|
||||
//! 材质定义和属性。
|
||||
|
||||
use super::uniform::MaterialUniforms;
|
||||
|
||||
/// Blend modes for material rendering.
|
||||
/// 材质渲染的混合模式。
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
|
||||
pub enum BlendMode {
|
||||
/// No blending, fully opaque | 无混合,完全不透明
|
||||
None,
|
||||
/// Standard alpha blending | 标准透明度混合
|
||||
#[default]
|
||||
Alpha,
|
||||
/// Additive blending (good for glow effects) | 加法混合(适用于发光效果)
|
||||
Additive,
|
||||
/// Multiplicative blending (good for shadows) | 乘法混合(适用于阴影)
|
||||
Multiply,
|
||||
/// Screen blending (opposite of multiply) | 滤色混合(与乘法相反)
|
||||
Screen,
|
||||
/// Premultiplied alpha | 预乘透明度
|
||||
PremultipliedAlpha,
|
||||
}
|
||||
|
||||
/// Cull modes for material rendering.
|
||||
/// 材质渲染的剔除模式。
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
|
||||
pub enum CullMode {
|
||||
/// No face culling | 不剔除
|
||||
#[default]
|
||||
None,
|
||||
/// Cull front faces | 剔除正面
|
||||
Front,
|
||||
/// Cull back faces | 剔除背面
|
||||
Back,
|
||||
}
|
||||
|
||||
/// Material definition for 2D rendering.
|
||||
/// 2D渲染的材质定义。
|
||||
///
|
||||
/// A material combines a shader program with uniform parameters and render states.
|
||||
/// 材质将着色器程序与uniform参数和渲染状态组合在一起。
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Material {
|
||||
/// Shader program ID | 着色器程序ID
|
||||
pub shader_id: u32,
|
||||
|
||||
/// Material uniform parameters | 材质uniform参数
|
||||
pub uniforms: MaterialUniforms,
|
||||
|
||||
/// Blend mode | 混合模式
|
||||
pub blend_mode: BlendMode,
|
||||
|
||||
/// Cull mode | 剔除模式
|
||||
pub cull_mode: CullMode,
|
||||
|
||||
/// Depth test enabled | 是否启用深度测试
|
||||
pub depth_test: bool,
|
||||
|
||||
/// Depth write enabled | 是否启用深度写入
|
||||
pub depth_write: bool,
|
||||
|
||||
/// Material name (for debugging) | 材质名称(用于调试)
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
impl Default for Material {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
shader_id: 0, // Default sprite shader
|
||||
uniforms: MaterialUniforms::new(),
|
||||
blend_mode: BlendMode::Alpha,
|
||||
cull_mode: CullMode::None,
|
||||
depth_test: false,
|
||||
depth_write: false,
|
||||
name: "Default".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Material {
|
||||
/// Create a new material with default settings.
|
||||
/// 使用默认设置创建新材质。
|
||||
pub fn new(name: &str) -> Self {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a material with a specific shader.
|
||||
/// 使用特定着色器创建材质。
|
||||
pub fn with_shader(name: &str, shader_id: u32) -> Self {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
shader_id,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the blend mode.
|
||||
/// 设置混合模式。
|
||||
pub fn set_blend_mode(&mut self, mode: BlendMode) -> &mut Self {
|
||||
self.blend_mode = mode;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set a float uniform.
|
||||
/// 设置浮点uniform。
|
||||
pub fn set_float(&mut self, name: &str, value: f32) -> &mut Self {
|
||||
self.uniforms.set_float(name, value);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set a vec2 uniform.
|
||||
/// 设置vec2 uniform。
|
||||
pub fn set_vec2(&mut self, name: &str, x: f32, y: f32) -> &mut Self {
|
||||
self.uniforms.set_vec2(name, x, y);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set a vec3 uniform.
|
||||
/// 设置vec3 uniform。
|
||||
pub fn set_vec3(&mut self, name: &str, x: f32, y: f32, z: f32) -> &mut Self {
|
||||
self.uniforms.set_vec3(name, x, y, z);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set a vec4 uniform.
|
||||
/// 设置vec4 uniform。
|
||||
pub fn set_vec4(&mut self, name: &str, x: f32, y: f32, z: f32, w: f32) -> &mut Self {
|
||||
self.uniforms.set_vec4(name, x, y, z, w);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set a color uniform (RGBA, 0.0-1.0).
|
||||
/// 设置颜色uniform(RGBA,0.0-1.0)。
|
||||
pub fn set_color(&mut self, name: &str, r: f32, g: f32, b: f32, a: f32) -> &mut Self {
|
||||
self.uniforms.set_color(name, r, g, b, a);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
// ============= Built-in material presets =============
|
||||
// ============= 内置材质预设 =============
|
||||
|
||||
impl Material {
|
||||
/// Create a standard sprite material.
|
||||
/// 创建标准精灵材质。
|
||||
pub fn sprite() -> Self {
|
||||
Self::new("Sprite")
|
||||
}
|
||||
|
||||
/// Create an additive (glow) material.
|
||||
/// 创建加法(发光)材质。
|
||||
pub fn additive() -> Self {
|
||||
let mut mat = Self::new("Additive");
|
||||
mat.blend_mode = BlendMode::Additive;
|
||||
mat
|
||||
}
|
||||
|
||||
/// Create a multiply (shadow) material.
|
||||
/// 创建乘法(阴影)材质。
|
||||
pub fn multiply() -> Self {
|
||||
let mut mat = Self::new("Multiply");
|
||||
mat.blend_mode = BlendMode::Multiply;
|
||||
mat
|
||||
}
|
||||
|
||||
/// Create an unlit/opaque material.
|
||||
/// 创建无光照/不透明材质。
|
||||
pub fn unlit() -> Self {
|
||||
let mut mat = Self::new("Unlit");
|
||||
mat.blend_mode = BlendMode::None;
|
||||
mat
|
||||
}
|
||||
}
|
||||
10
packages/engine/src/renderer/material/mod.rs
Normal file
10
packages/engine/src/renderer/material/mod.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
//! Material system for 2D rendering.
|
||||
//! 2D渲染的材质系统。
|
||||
|
||||
mod material;
|
||||
mod manager;
|
||||
mod uniform;
|
||||
|
||||
pub use material::{Material, BlendMode, CullMode};
|
||||
pub use manager::MaterialManager;
|
||||
pub use uniform::{UniformValue, MaterialUniforms};
|
||||
185
packages/engine/src/renderer/material/uniform.rs
Normal file
185
packages/engine/src/renderer/material/uniform.rs
Normal file
@@ -0,0 +1,185 @@
|
||||
//! Material uniform values and types.
|
||||
//! 材质uniform值和类型。
|
||||
|
||||
use std::collections::HashMap;
|
||||
use web_sys::{WebGl2RenderingContext, WebGlUniformLocation};
|
||||
|
||||
use crate::renderer::shader::ShaderProgram;
|
||||
|
||||
/// Uniform value types supported by the material system.
|
||||
/// 材质系统支持的uniform值类型。
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum UniformValue {
|
||||
/// Single float value | 单精度浮点值
|
||||
Float(f32),
|
||||
/// Two component vector | 二维向量
|
||||
Vec2([f32; 2]),
|
||||
/// Three component vector | 三维向量
|
||||
Vec3([f32; 3]),
|
||||
/// Four component vector (also used for colors) | 四维向量(也用于颜色)
|
||||
Vec4([f32; 4]),
|
||||
/// Single integer value | 整数值
|
||||
Int(i32),
|
||||
/// 3x3 matrix | 3x3矩阵
|
||||
Mat3([f32; 9]),
|
||||
/// 4x4 matrix | 4x4矩阵
|
||||
Mat4([f32; 16]),
|
||||
/// Texture sampler slot | 纹理采样器槽位
|
||||
Sampler(i32),
|
||||
}
|
||||
|
||||
impl UniformValue {
|
||||
/// Apply this uniform value to a shader.
|
||||
/// 将此uniform值应用到着色器。
|
||||
pub fn apply(&self, gl: &WebGl2RenderingContext, location: &WebGlUniformLocation) {
|
||||
match self {
|
||||
UniformValue::Float(v) => {
|
||||
gl.uniform1f(Some(location), *v);
|
||||
}
|
||||
UniformValue::Vec2(v) => {
|
||||
gl.uniform2f(Some(location), v[0], v[1]);
|
||||
}
|
||||
UniformValue::Vec3(v) => {
|
||||
gl.uniform3f(Some(location), v[0], v[1], v[2]);
|
||||
}
|
||||
UniformValue::Vec4(v) => {
|
||||
gl.uniform4f(Some(location), v[0], v[1], v[2], v[3]);
|
||||
}
|
||||
UniformValue::Int(v) => {
|
||||
gl.uniform1i(Some(location), *v);
|
||||
}
|
||||
UniformValue::Mat3(v) => {
|
||||
gl.uniform_matrix3fv_with_f32_array(Some(location), false, v);
|
||||
}
|
||||
UniformValue::Mat4(v) => {
|
||||
gl.uniform_matrix4fv_with_f32_array(Some(location), false, v);
|
||||
}
|
||||
UniformValue::Sampler(slot) => {
|
||||
gl.uniform1i(Some(location), *slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Collection of material uniform values.
|
||||
/// 材质uniform值集合。
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct MaterialUniforms {
|
||||
/// Named uniform values | 命名的uniform值
|
||||
values: HashMap<String, UniformValue>,
|
||||
}
|
||||
|
||||
impl MaterialUniforms {
|
||||
/// Create empty uniforms collection.
|
||||
/// 创建空的uniform集合。
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
values: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set a uniform value.
|
||||
/// 设置uniform值。
|
||||
pub fn set(&mut self, name: &str, value: UniformValue) {
|
||||
self.values.insert(name.to_string(), value);
|
||||
}
|
||||
|
||||
/// Get a uniform value.
|
||||
/// 获取uniform值。
|
||||
pub fn get(&self, name: &str) -> Option<&UniformValue> {
|
||||
self.values.get(name)
|
||||
}
|
||||
|
||||
/// Remove a uniform value.
|
||||
/// 移除uniform值。
|
||||
pub fn remove(&mut self, name: &str) -> Option<UniformValue> {
|
||||
self.values.remove(name)
|
||||
}
|
||||
|
||||
/// Check if a uniform exists.
|
||||
/// 检查uniform是否存在。
|
||||
pub fn has(&self, name: &str) -> bool {
|
||||
self.values.contains_key(name)
|
||||
}
|
||||
|
||||
/// Apply all uniforms to a shader program.
|
||||
/// 将所有uniform应用到着色器程序。
|
||||
pub fn apply_to_shader(&self, gl: &WebGl2RenderingContext, shader: &ShaderProgram) {
|
||||
for (name, value) in &self.values {
|
||||
if let Some(location) = shader.get_uniform_location(gl, name) {
|
||||
value.apply(gl, &location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get all uniform names.
|
||||
/// 获取所有uniform名称。
|
||||
pub fn names(&self) -> Vec<&String> {
|
||||
self.values.keys().collect()
|
||||
}
|
||||
|
||||
/// Clear all uniforms.
|
||||
/// 清除所有uniform。
|
||||
pub fn clear(&mut self) {
|
||||
self.values.clear();
|
||||
}
|
||||
|
||||
/// Get uniform count.
|
||||
/// 获取uniform数量。
|
||||
pub fn len(&self) -> usize {
|
||||
self.values.len()
|
||||
}
|
||||
|
||||
/// Check if empty.
|
||||
/// 检查是否为空。
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.values.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
// ============= Convenience setters =============
|
||||
// ============= 便捷设置方法 =============
|
||||
|
||||
impl MaterialUniforms {
|
||||
/// Set a float uniform.
|
||||
/// 设置浮点uniform。
|
||||
pub fn set_float(&mut self, name: &str, value: f32) {
|
||||
self.set(name, UniformValue::Float(value));
|
||||
}
|
||||
|
||||
/// Set a vec2 uniform.
|
||||
/// 设置vec2 uniform。
|
||||
pub fn set_vec2(&mut self, name: &str, x: f32, y: f32) {
|
||||
self.set(name, UniformValue::Vec2([x, y]));
|
||||
}
|
||||
|
||||
/// Set a vec3 uniform.
|
||||
/// 设置vec3 uniform。
|
||||
pub fn set_vec3(&mut self, name: &str, x: f32, y: f32, z: f32) {
|
||||
self.set(name, UniformValue::Vec3([x, y, z]));
|
||||
}
|
||||
|
||||
/// Set a vec4 uniform (also used for colors).
|
||||
/// 设置vec4 uniform(也用于颜色)。
|
||||
pub fn set_vec4(&mut self, name: &str, x: f32, y: f32, z: f32, w: f32) {
|
||||
self.set(name, UniformValue::Vec4([x, y, z, w]));
|
||||
}
|
||||
|
||||
/// Set a color uniform (RGBA, 0.0-1.0).
|
||||
/// 设置颜色uniform(RGBA,0.0-1.0)。
|
||||
pub fn set_color(&mut self, name: &str, r: f32, g: f32, b: f32, a: f32) {
|
||||
self.set(name, UniformValue::Vec4([r, g, b, a]));
|
||||
}
|
||||
|
||||
/// Set an integer uniform.
|
||||
/// 设置整数uniform。
|
||||
pub fn set_int(&mut self, name: &str, value: i32) {
|
||||
self.set(name, UniformValue::Int(value));
|
||||
}
|
||||
|
||||
/// Set a texture sampler uniform.
|
||||
/// 设置纹理采样器uniform。
|
||||
pub fn set_sampler(&mut self, name: &str, slot: i32) {
|
||||
self.set(name, UniformValue::Sampler(slot));
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
pub mod batch;
|
||||
pub mod shader;
|
||||
pub mod texture;
|
||||
pub mod material;
|
||||
|
||||
mod renderer2d;
|
||||
mod camera;
|
||||
@@ -18,3 +19,5 @@ pub use texture::{Texture, TextureManager};
|
||||
pub use grid::GridRenderer;
|
||||
pub use gizmo::{GizmoRenderer, TransformMode};
|
||||
pub use viewport::{RenderTarget, ViewportManager, ViewportConfig};
|
||||
pub use shader::{ShaderManager, ShaderProgram, SHADER_ID_DEFAULT_SPRITE};
|
||||
pub use material::{Material, MaterialManager, BlendMode, CullMode, UniformValue, MaterialUniforms};
|
||||
|
||||
@@ -8,7 +8,8 @@ use crate::core::error::Result;
|
||||
use crate::resource::TextureManager;
|
||||
use super::batch::SpriteBatch;
|
||||
use super::camera::Camera2D;
|
||||
use super::shader::{ShaderProgram, SPRITE_VERTEX_SHADER, SPRITE_FRAGMENT_SHADER};
|
||||
use super::shader::ShaderManager;
|
||||
use super::material::MaterialManager;
|
||||
|
||||
/// 2D renderer with batched sprite rendering.
|
||||
/// 带批处理精灵渲染的2D渲染器。
|
||||
@@ -20,9 +21,13 @@ pub struct Renderer2D {
|
||||
/// 精灵批处理渲染器。
|
||||
sprite_batch: SpriteBatch,
|
||||
|
||||
/// Sprite shader program.
|
||||
/// 精灵Shader程序。
|
||||
shader: ShaderProgram,
|
||||
/// Shader manager.
|
||||
/// 着色器管理器。
|
||||
shader_manager: ShaderManager,
|
||||
|
||||
/// Material manager.
|
||||
/// 材质管理器。
|
||||
material_manager: MaterialManager,
|
||||
|
||||
/// 2D camera.
|
||||
/// 2D相机。
|
||||
@@ -31,6 +36,16 @@ pub struct Renderer2D {
|
||||
/// 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 {
|
||||
@@ -42,7 +57,8 @@ impl Renderer2D {
|
||||
/// * `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 = ShaderProgram::new(gl, SPRITE_VERTEX_SHADER, SPRITE_FRAGMENT_SHADER)?;
|
||||
let shader_manager = ShaderManager::new(gl)?;
|
||||
let material_manager = MaterialManager::new();
|
||||
|
||||
// Get canvas size for camera | 获取canvas尺寸用于相机
|
||||
let canvas = gl.canvas()
|
||||
@@ -59,9 +75,12 @@ impl Renderer2D {
|
||||
|
||||
Ok(Self {
|
||||
sprite_batch,
|
||||
shader,
|
||||
shader_manager,
|
||||
material_manager,
|
||||
camera,
|
||||
clear_color: [0.1, 0.1, 0.12, 1.0],
|
||||
current_shader_id: 0,
|
||||
current_material_id: 0,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -73,6 +92,7 @@ impl Renderer2D {
|
||||
/// * `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) | 每个精灵的材质ID(0 = 默认)
|
||||
/// * `texture_manager` - Texture manager | 纹理管理器
|
||||
pub fn submit_batch(
|
||||
&mut self,
|
||||
@@ -80,6 +100,7 @@ impl Renderer2D {
|
||||
texture_ids: &[u32],
|
||||
uvs: &[f32],
|
||||
colors: &[u32],
|
||||
material_ids: &[u32],
|
||||
texture_manager: &TextureManager,
|
||||
) -> Result<()> {
|
||||
self.sprite_batch.add_sprites(
|
||||
@@ -87,6 +108,7 @@ impl Renderer2D {
|
||||
texture_ids,
|
||||
uvs,
|
||||
colors,
|
||||
material_ids,
|
||||
texture_manager,
|
||||
)
|
||||
}
|
||||
@@ -94,34 +116,61 @@ impl Renderer2D {
|
||||
/// 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(());
|
||||
}
|
||||
|
||||
// Bind shader | 绑定Shader
|
||||
self.shader.bind(gl);
|
||||
|
||||
// Set projection matrix | 设置投影矩阵
|
||||
let projection = self.camera.projection_matrix();
|
||||
self.shader.set_uniform_mat3(gl, "u_projection", &projection.to_cols_array());
|
||||
|
||||
// Set texture sampler | 设置纹理采样器
|
||||
self.shader.set_uniform_i32(gl, "u_texture", 0);
|
||||
|
||||
// Render each texture batch | 渲染每个纹理批次
|
||||
// Only collect non-empty batches | 只收集非空批次
|
||||
let texture_ids: Vec<u32> = self.sprite_batch.texture_batches()
|
||||
// Collect non-empty batch keys | 收集非空批次键
|
||||
let batch_keys: Vec<BatchKey> = self.sprite_batch.batches()
|
||||
.iter()
|
||||
.filter(|(_, vertices)| !vertices.is_empty())
|
||||
.map(|(id, _)| *id)
|
||||
.map(|(key, _)| *key)
|
||||
.collect();
|
||||
|
||||
for texture_id in texture_ids {
|
||||
// Bind texture for this batch | 绑定此批次的纹理
|
||||
texture_manager.bind_texture(texture_id, 0);
|
||||
// Track current state to minimize state changes | 跟踪当前状态以最小化状态切换
|
||||
let mut current_material_id: u32 = u32::MAX;
|
||||
let mut current_texture_id: u32 = u32::MAX;
|
||||
|
||||
// Flush this texture's sprites | 刷新此纹理的精灵
|
||||
self.sprite_batch.flush_for_texture(gl, texture_id);
|
||||
// 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 | 清空批处理以供下一帧使用
|
||||
@@ -161,4 +210,123 @@ impl Renderer2D {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
172
packages/engine/src/renderer/shader/manager.rs
Normal file
172
packages/engine/src/renderer/shader/manager.rs
Normal file
@@ -0,0 +1,172 @@
|
||||
//! Shader manager for runtime shader compilation and caching.
|
||||
//! 着色器管理器,用于运行时着色器编译和缓存。
|
||||
|
||||
use std::collections::HashMap;
|
||||
use web_sys::WebGl2RenderingContext;
|
||||
|
||||
use crate::core::error::Result;
|
||||
use super::program::ShaderProgram;
|
||||
use super::builtin::{SPRITE_VERTEX_SHADER, SPRITE_FRAGMENT_SHADER};
|
||||
|
||||
/// Reserved shader IDs for built-in shaders.
|
||||
/// 内置着色器的保留ID。
|
||||
pub const SHADER_ID_DEFAULT_SPRITE: u32 = 0;
|
||||
|
||||
/// Shader manager for compiling and caching shader programs.
|
||||
/// 着色器管理器,用于编译和缓存着色器程序。
|
||||
///
|
||||
/// Manages multiple shader programs, allowing runtime compilation of custom shaders.
|
||||
/// 管理多个着色器程序,允许运行时编译自定义着色器。
|
||||
pub struct ShaderManager {
|
||||
/// Compiled shader programs indexed by ID.
|
||||
/// 按ID索引的已编译着色器程序。
|
||||
shaders: HashMap<u32, ShaderProgram>,
|
||||
|
||||
/// Next available shader ID for custom shaders.
|
||||
/// 下一个可用的自定义着色器ID。
|
||||
next_shader_id: u32,
|
||||
|
||||
/// Shader source cache for hot-reloading (optional).
|
||||
/// 着色器源代码缓存,用于热重载(可选)。
|
||||
shader_sources: HashMap<u32, (String, String)>,
|
||||
}
|
||||
|
||||
impl ShaderManager {
|
||||
/// Create a new shader manager with built-in shaders.
|
||||
/// 创建带有内置着色器的新着色器管理器。
|
||||
///
|
||||
/// # Arguments | 参数
|
||||
/// * `gl` - WebGL2 context | WebGL2上下文
|
||||
pub fn new(gl: &WebGl2RenderingContext) -> Result<Self> {
|
||||
let mut manager = Self {
|
||||
shaders: HashMap::new(),
|
||||
next_shader_id: 100, // Reserve 0-99 for built-in shaders
|
||||
shader_sources: HashMap::new(),
|
||||
};
|
||||
|
||||
// Compile built-in sprite shader | 编译内置精灵着色器
|
||||
let default_shader = ShaderProgram::new(gl, SPRITE_VERTEX_SHADER, SPRITE_FRAGMENT_SHADER)?;
|
||||
manager.shaders.insert(SHADER_ID_DEFAULT_SPRITE, default_shader);
|
||||
manager.shader_sources.insert(
|
||||
SHADER_ID_DEFAULT_SPRITE,
|
||||
(SPRITE_VERTEX_SHADER.to_string(), SPRITE_FRAGMENT_SHADER.to_string()),
|
||||
);
|
||||
|
||||
log::info!("ShaderManager initialized with {} built-in shaders | 着色器管理器初始化完成,内置着色器数量: {}",
|
||||
manager.shaders.len(), manager.shaders.len());
|
||||
|
||||
Ok(manager)
|
||||
}
|
||||
|
||||
/// Compile and register a custom shader program.
|
||||
/// 编译并注册自定义着色器程序。
|
||||
///
|
||||
/// # Arguments | 参数
|
||||
/// * `gl` - WebGL2 context | WebGL2上下文
|
||||
/// * `vertex_source` - Vertex shader GLSL source | 顶点着色器GLSL源代码
|
||||
/// * `fragment_source` - Fragment shader GLSL source | 片段着色器GLSL源代码
|
||||
///
|
||||
/// # 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> {
|
||||
let shader = ShaderProgram::new(gl, vertex_source, fragment_source)?;
|
||||
let shader_id = self.next_shader_id;
|
||||
self.next_shader_id += 1;
|
||||
|
||||
self.shaders.insert(shader_id, shader);
|
||||
self.shader_sources.insert(
|
||||
shader_id,
|
||||
(vertex_source.to_string(), fragment_source.to_string()),
|
||||
);
|
||||
|
||||
log::debug!("Custom shader compiled with ID: {} | 自定义着色器编译完成,ID: {}", shader_id, shader_id);
|
||||
|
||||
Ok(shader_id)
|
||||
}
|
||||
|
||||
/// Compile and register a shader with a specific ID.
|
||||
/// 使用特定ID编译并注册着色器。
|
||||
///
|
||||
/// # Arguments | 参数
|
||||
/// * `gl` - WebGL2 context | WebGL2上下文
|
||||
/// * `shader_id` - Desired shader ID | 期望的着色器ID
|
||||
/// * `vertex_source` - Vertex shader GLSL source | 顶点着色器GLSL源代码
|
||||
/// * `fragment_source` - Fragment shader GLSL source | 片段着色器GLSL源代码
|
||||
pub fn compile_shader_with_id(
|
||||
&mut self,
|
||||
gl: &WebGl2RenderingContext,
|
||||
shader_id: u32,
|
||||
vertex_source: &str,
|
||||
fragment_source: &str,
|
||||
) -> Result<()> {
|
||||
let shader = ShaderProgram::new(gl, vertex_source, fragment_source)?;
|
||||
|
||||
// Remove old shader if exists | 如果存在则移除旧着色器
|
||||
self.shaders.remove(&shader_id);
|
||||
|
||||
self.shaders.insert(shader_id, shader);
|
||||
self.shader_sources.insert(
|
||||
shader_id,
|
||||
(vertex_source.to_string(), fragment_source.to_string()),
|
||||
);
|
||||
|
||||
log::debug!("Shader compiled with ID: {} | 着色器编译完成,ID: {}", shader_id, shader_id);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get a shader program by ID.
|
||||
/// 按ID获取着色器程序。
|
||||
#[inline]
|
||||
pub fn get_shader(&self, shader_id: u32) -> Option<&ShaderProgram> {
|
||||
self.shaders.get(&shader_id)
|
||||
}
|
||||
|
||||
/// Get the default sprite shader.
|
||||
/// 获取默认精灵着色器。
|
||||
#[inline]
|
||||
pub fn get_default_shader(&self) -> &ShaderProgram {
|
||||
self.shaders.get(&SHADER_ID_DEFAULT_SPRITE)
|
||||
.expect("Default shader should always exist | 默认着色器应该始终存在")
|
||||
}
|
||||
|
||||
/// Check if a shader exists.
|
||||
/// 检查着色器是否存在。
|
||||
#[inline]
|
||||
pub fn has_shader(&self, shader_id: u32) -> bool {
|
||||
self.shaders.contains_key(&shader_id)
|
||||
}
|
||||
|
||||
/// Remove a shader program.
|
||||
/// 移除着色器程序。
|
||||
///
|
||||
/// Note: Cannot remove built-in shaders (ID < 100).
|
||||
/// 注意:无法移除内置着色器(ID < 100)。
|
||||
pub fn remove_shader(&mut self, shader_id: u32) -> bool {
|
||||
if shader_id < 100 {
|
||||
log::warn!("Cannot remove built-in shader: {} | 无法移除内置着色器: {}", shader_id, shader_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
self.shader_sources.remove(&shader_id);
|
||||
self.shaders.remove(&shader_id).is_some()
|
||||
}
|
||||
|
||||
/// Get all shader IDs.
|
||||
/// 获取所有着色器ID。
|
||||
pub fn shader_ids(&self) -> Vec<u32> {
|
||||
self.shaders.keys().copied().collect()
|
||||
}
|
||||
|
||||
/// Get shader count.
|
||||
/// 获取着色器数量。
|
||||
#[inline]
|
||||
pub fn shader_count(&self) -> usize {
|
||||
self.shaders.len()
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
mod program;
|
||||
mod builtin;
|
||||
mod manager;
|
||||
|
||||
pub use program::ShaderProgram;
|
||||
pub use builtin::{SPRITE_VERTEX_SHADER, SPRITE_FRAGMENT_SHADER};
|
||||
pub use manager::{ShaderManager, SHADER_ID_DEFAULT_SPRITE};
|
||||
|
||||
Reference in New Issue
Block a user