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:
YHH
2025-12-03 22:15:22 +08:00
committed by GitHub
parent caf7622aa0
commit 63f006ab62
496 changed files with 77601 additions and 4067 deletions

View File

@@ -0,0 +1,152 @@
use crate::dynamics::{RawImpulseJointSet, RawMultibodyJointSet, RawRigidBodySet};
use crate::geometry::{RawColliderSet, RawNarrowPhase};
use js_sys::Float32Array;
use palette::convert::IntoColorUnclamped;
use palette::rgb::Rgba;
use palette::Hsla;
use rapier::dynamics::{RigidBody, RigidBodySet};
use rapier::geometry::ColliderSet;
use rapier::math::{Point, Real};
use rapier::pipeline::{DebugRenderBackend, DebugRenderObject, DebugRenderPipeline};
use rapier::prelude::{QueryFilter, QueryFilterFlags};
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub struct RawDebugRenderPipeline {
pub(crate) raw: DebugRenderPipeline,
vertices: Vec<f32>,
colors: Vec<f32>,
}
#[wasm_bindgen]
impl RawDebugRenderPipeline {
#[wasm_bindgen(constructor)]
pub fn new() -> Self {
RawDebugRenderPipeline {
raw: DebugRenderPipeline::default(),
vertices: vec![],
colors: vec![],
}
}
pub fn vertices(&self) -> Float32Array {
let output = Float32Array::new_with_length(self.vertices.len() as u32);
output.copy_from(&self.vertices);
output
}
pub fn colors(&self) -> Float32Array {
let output = Float32Array::new_with_length(self.colors.len() as u32);
output.copy_from(&self.colors);
output
}
pub fn render(
&mut self,
bodies: &RawRigidBodySet,
colliders: &RawColliderSet,
impulse_joints: &RawImpulseJointSet,
multibody_joints: &RawMultibodyJointSet,
narrow_phase: &RawNarrowPhase,
filter_flags: u32,
filter_predicate: &js_sys::Function,
) {
self.vertices.clear();
self.colors.clear();
crate::utils::with_filter(filter_predicate, |predicate| {
let mut backend = CopyToBuffersBackend {
filter: QueryFilter {
flags: QueryFilterFlags::from_bits(filter_flags)
.unwrap_or(QueryFilterFlags::empty()),
groups: None,
exclude_collider: None,
exclude_rigid_body: None,
predicate,
},
bodies: &bodies.0,
colliders: &colliders.0,
vertices: &mut self.vertices,
colors: &mut self.colors,
};
self.raw.render(
&mut backend,
&bodies.0,
&colliders.0,
&impulse_joints.0,
&multibody_joints.0,
&narrow_phase.0,
)
})
}
}
struct CopyToBuffersBackend<'a> {
filter: QueryFilter<'a>,
bodies: &'a RigidBodySet,
colliders: &'a ColliderSet,
vertices: &'a mut Vec<f32>,
colors: &'a mut Vec<f32>,
}
impl<'a> DebugRenderBackend for CopyToBuffersBackend<'a> {
fn filter_object(&self, object: DebugRenderObject) -> bool {
let test_rigid_body = |rb: &RigidBody| {
rb.colliders().iter().all(|handle| {
let Some(co) = self.colliders.get(*handle) else {
return false;
};
self.filter.test(self.bodies, *handle, co)
})
};
match object {
DebugRenderObject::Collider(handle, co)
| DebugRenderObject::ColliderAabb(handle, co, _) => {
self.filter.test(self.bodies, handle, co)
}
DebugRenderObject::ContactPair(pair, co1, co2) => {
self.filter.test(self.bodies, pair.collider1, co1)
&& self.filter.test(self.bodies, pair.collider2, co2)
}
DebugRenderObject::ImpulseJoint(_, joint) => {
let Some(rb1) = self.bodies.get(joint.body1) else {
return false;
};
let Some(rb2) = self.bodies.get(joint.body2) else {
return false;
};
test_rigid_body(rb1) && test_rigid_body(rb2)
}
DebugRenderObject::MultibodyJoint(_, _, link) => {
let Some(rb) = self.bodies.get(link.rigid_body_handle()) else {
return false;
};
test_rigid_body(rb)
}
DebugRenderObject::RigidBody(_, rb) => test_rigid_body(rb),
}
}
/// Draws a colored line.
///
/// Note that this method can be called multiple time for the same `object`.
fn draw_line(
&mut self,
_object: DebugRenderObject,
a: Point<Real>,
b: Point<Real>,
color: [f32; 4],
) {
self.vertices.extend_from_slice(a.coords.as_slice());
self.vertices.extend_from_slice(b.coords.as_slice());
// Convert to RGB which will be easier to handle in JS.
let hsl = Hsla::new(color[0], color[1], color[2], color[3]);
let rgb: Rgba = hsl.into_color_unclamped();
self.colors.extend_from_slice(&[
rgb.red, rgb.green, rgb.blue, rgb.alpha, rgb.red, rgb.green, rgb.blue, rgb.alpha,
]);
}
}

View File

@@ -0,0 +1,140 @@
use crate::math::RawVector;
use crate::utils;
use crate::utils::FlatHandle;
use rapier::geometry::{CollisionEvent, ContactForceEvent};
use rapier::pipeline::ChannelEventCollector;
use std::sync::mpsc::Receiver;
use wasm_bindgen::prelude::*;
/// A structure responsible for collecting events generated
/// by the physics engine.
#[wasm_bindgen]
pub struct RawEventQueue {
pub(crate) collector: ChannelEventCollector,
collision_events: Receiver<CollisionEvent>,
contact_force_events: Receiver<ContactForceEvent>,
pub(crate) auto_drain: bool,
}
#[wasm_bindgen]
pub struct RawContactForceEvent(ContactForceEvent);
#[wasm_bindgen]
impl RawContactForceEvent {
/// The first collider involved in the contact.
pub fn collider1(&self) -> FlatHandle {
crate::utils::flat_handle(self.0.collider1.0)
}
/// The second collider involved in the contact.
pub fn collider2(&self) -> FlatHandle {
crate::utils::flat_handle(self.0.collider2.0)
}
/// The sum of all the forces between the two colliders.
pub fn total_force(&self) -> RawVector {
RawVector(self.0.total_force)
}
/// The sum of the magnitudes of each force between the two colliders.
///
/// Note that this is **not** the same as the magnitude of `self.total_force`.
/// Here we are summing the magnitude of all the forces, instead of taking
/// the magnitude of their sum.
pub fn total_force_magnitude(&self) -> f32 {
self.0.total_force_magnitude
}
/// The world-space (unit) direction of the force with strongest magnitude.
pub fn max_force_direction(&self) -> RawVector {
RawVector(self.0.max_force_direction)
}
/// The magnitude of the largest force at a contact point of this contact pair.
pub fn max_force_magnitude(&self) -> f32 {
self.0.max_force_magnitude
}
}
// #[wasm_bindgen]
// /// The proximity state of a sensor collider and another collider.
// pub enum RawIntersection {
// /// The sensor is intersecting the other collider.
// Intersecting = 0,
// /// The sensor is within tolerance margin of the other collider.
// WithinMargin = 1,
// /// The sensor is disjoint from the other collider.
// Disjoint = 2,
// }
#[wasm_bindgen]
impl RawEventQueue {
/// Creates a new event collector.
///
/// # Parameters
/// - `autoDrain`: setting this to `true` is strongly recommended. If true, the collector will
/// be automatically drained before each `world.step(collector)`. If false, the collector will
/// keep all events in memory unless it is manually drained/cleared; this may lead to unbounded use of
/// RAM if no drain is performed.
#[wasm_bindgen(constructor)]
pub fn new(autoDrain: bool) -> Self {
let collision_channel = std::sync::mpsc::channel();
let contact_force_channel = std::sync::mpsc::channel();
let collector = ChannelEventCollector::new(collision_channel.0, contact_force_channel.0);
Self {
collector,
collision_events: collision_channel.1,
contact_force_events: contact_force_channel.1,
auto_drain: autoDrain,
}
}
/// Applies the given javascript closure on each collision event of this collector, then clear
/// the internal collision event buffer.
///
/// # Parameters
/// - `f(handle1, handle2, started)`: JavaScript closure applied to each collision event. The
/// closure should take three arguments: two integers representing the handles of the colliders
/// involved in the collision, and a boolean indicating if the collision started (true) or stopped
/// (false).
pub fn drainCollisionEvents(&mut self, f: &js_sys::Function) {
let this = JsValue::null();
while let Ok(event) = self.collision_events.try_recv() {
match event {
CollisionEvent::Started(co1, co2, _) => {
let h1 = utils::flat_handle(co1.0);
let h2 = utils::flat_handle(co2.0);
let _ = f.call3(
&this,
&JsValue::from(h1),
&JsValue::from(h2),
&JsValue::from_bool(true),
);
}
CollisionEvent::Stopped(co1, co2, _) => {
let h1 = utils::flat_handle(co1.0);
let h2 = utils::flat_handle(co2.0);
let _ = f.call3(
&this,
&JsValue::from(h1),
&JsValue::from(h2),
&JsValue::from_bool(false),
);
}
}
}
}
pub fn drainContactForceEvents(&mut self, f: &js_sys::Function) {
let this = JsValue::null();
while let Ok(event) = self.contact_force_events.try_recv() {
let _ = f.call1(&this, &JsValue::from(RawContactForceEvent(event)));
}
}
/// Removes all events contained by this collector.
pub fn clear(&self) {
while let Ok(_) = self.collision_events.try_recv() {}
}
}

View File

@@ -0,0 +1,11 @@
pub use self::debug_render_pipeline::*;
pub use self::event_queue::*;
pub use self::physics_hooks::*;
pub use self::physics_pipeline::*;
pub use self::serialization_pipeline::*;
mod debug_render_pipeline;
mod event_queue;
mod physics_hooks;
mod physics_pipeline;
mod serialization_pipeline;

View File

@@ -0,0 +1,217 @@
use crate::utils;
use rapier::geometry::SolverFlags;
use rapier::pipeline::{ContactModificationContext, PairFilterContext, PhysicsHooks};
use wasm_bindgen::prelude::*;
pub struct RawPhysicsHooks {
pub this: js_sys::Object,
pub filter_contact_pair: js_sys::Function,
pub filter_intersection_pair: js_sys::Function,
// pub modify_solver_contacts: &'a js_sys::Function,
}
// HACK: the RawPhysicsHooks is no longer Send+Sync because the JS objects are
// no longer Send+Sync since https://github.com/rustwasm/wasm-bindgen/pull/955
// As far as this is confined to the bindings this should be fine since we
// never use threading in wasm.
unsafe impl Send for RawPhysicsHooks {}
unsafe impl Sync for RawPhysicsHooks {}
#[wasm_bindgen]
extern "C" {
// Use `js_namespace` here to bind `console.log(..)` instead of just
// `log(..)`
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);
}
impl PhysicsHooks for RawPhysicsHooks {
fn filter_contact_pair(&self, ctxt: &PairFilterContext) -> Option<SolverFlags> {
let rb1 = ctxt
.rigid_body1
.map(|rb| JsValue::from(utils::flat_handle(rb.0)))
.unwrap_or(JsValue::NULL);
let rb2 = ctxt
.rigid_body2
.map(|rb| JsValue::from(utils::flat_handle(rb.0)))
.unwrap_or(JsValue::NULL);
let result = self
.filter_contact_pair
.bind2(
&self.this,
&JsValue::from(utils::flat_handle(ctxt.collider1.0)),
&JsValue::from(utils::flat_handle(ctxt.collider2.0)),
)
.call2(&self.this, &rb1, &rb2)
.ok()?;
let flags = result.as_f64()?;
// TODO: not sure exactly why we have to do `flags as u32` instead
// of `flags.to_bits() as u32`.
SolverFlags::from_bits(flags as u32)
}
fn filter_intersection_pair(&self, ctxt: &PairFilterContext) -> bool {
let rb1 = ctxt
.rigid_body1
.map(|rb| JsValue::from(utils::flat_handle(rb.0)))
.unwrap_or(JsValue::NULL);
let rb2 = ctxt
.rigid_body2
.map(|rb| JsValue::from(utils::flat_handle(rb.0)))
.unwrap_or(JsValue::NULL);
self.filter_intersection_pair
.bind2(
&self.this,
&JsValue::from(utils::flat_handle(ctxt.collider1.0)),
&JsValue::from(utils::flat_handle(ctxt.collider2.0)),
)
.call2(&self.this, &rb1, &rb2)
.ok()
.and_then(|res| res.as_bool())
.unwrap_or(false)
}
fn modify_solver_contacts(&self, _ctxt: &mut ContactModificationContext) {}
}
/* NOTE: the following is an attempt to make contact modification work.
*
#[wasm_bindgen]
#[derive(Copy, Clone, Debug)]
pub struct RawContactManifold(*const ContactManifold);
pub struct RawSolverContact(*const SolverContact);
#[wasm_bindgen]
pub struct RawContactModificationContext {
pub collider1: u32,
pub collider2: u32,
pub rigid_body1: Option<u32>,
pub rigid_body2: Option<u32>,
pub manifold: *const ContactManifold,
pub solver_contacts: *mut Vec<SolverContact>,
normal: *mut Vector<Real>,
user_data: *mut u32,
}
#[wasm_bindgen]
impl RawContactModificationContext {
pub fn collider1(&self) -> u32 {
self.collider1
}
pub fn collider2(&self) -> u32 {
self.collider2
}
#[wasm_bindgen(getter)]
pub fn normal(&self) -> RawVector {
unsafe { RawVector(*self.normal) }
}
#[wasm_bindgen(setter)]
pub fn set_normal(&mut self, normal: RawVector) {
unsafe {
*self.normal = normal.0;
}
}
#[wasm_bindgen(getter)]
pub fn user_data(&self) -> u32 {
unsafe { *self.user_data }
}
#[wasm_bindgen(setter)]
pub fn set_user_data(&mut self, user_data: u32) {
unsafe {
*self.user_data = user_data;
}
}
pub fn num_solver_contacts(&self) -> usize {
unsafe { (*self.solver_contacts).len() }
}
pub fn clear_solver_contacts(&mut self) {
unsafe { (*self.solver_contacts).clear() }
}
pub fn remove_solver_contact(&mut self, i: usize) {
unsafe {
if i < self.num_solver_contacts() {
(*self.solver_contacts).swap_remove(i);
}
}
}
pub fn solver_contact_point(&self, i: usize) -> Option<RawVector> {
unsafe {
(*self.solver_contacts)
.get(i)
.map(|c| c.point.coords.into())
}
}
pub fn set_solver_contact_point(&mut self, i: usize, pt: &RawVector) {
unsafe {
if let Some(c) = (*self.solver_contacts).get_mut(i) {
c.point = pt.0.into()
}
}
}
pub fn solver_contact_dist(&self, i: usize) -> Real {
unsafe {
(*self.solver_contacts)
.get(i)
.map(|c| c.dist)
.unwrap_or(0.0)
}
}
pub fn set_solver_contact_dist(&mut self, i: usize, dist: Real) {
unsafe {
if let Some(c) = (*self.solver_contacts).get_mut(i) {
c.dist = dist
}
}
}
pub fn solver_contact_friction(&self, i: usize) -> Real {
unsafe { (*self.solver_contacts)[i].friction }
}
pub fn set_solver_contact_friction(&mut self, i: usize, friction: Real) {
unsafe {
if let Some(c) = (*self.solver_contacts).get_mut(i) {
c.friction = friction
}
}
}
pub fn solver_contact_restitution(&self, i: usize) -> Real {
unsafe { (*self.solver_contacts)[i].restitution }
}
pub fn set_solver_contact_restitution(&mut self, i: usize, restitution: Real) {
unsafe {
if let Some(c) = (*self.solver_contacts).get_mut(i) {
c.restitution = restitution
}
}
}
pub fn solver_contact_tangent_velocity(&self, i: usize) -> RawVector {
unsafe { (*self.solver_contacts)[i].tangent_velocity.into() }
}
pub fn set_solver_contact_tangent_velocity(&mut self, i: usize, vel: &RawVector) {
unsafe {
if let Some(c) = (*self.solver_contacts).get_mut(i) {
c.tangent_velocity = vel.0.into()
}
}
}
}
*/

View File

@@ -0,0 +1,170 @@
use crate::dynamics::{
RawCCDSolver, RawImpulseJointSet, RawIntegrationParameters, RawIslandManager,
RawMultibodyJointSet, RawRigidBodySet,
};
use crate::geometry::{RawBroadPhase, RawColliderSet, RawNarrowPhase};
use crate::math::RawVector;
use crate::pipeline::{RawEventQueue, RawPhysicsHooks};
use crate::rapier::pipeline::PhysicsPipeline;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub struct RawPhysicsPipeline(pub(crate) PhysicsPipeline);
#[wasm_bindgen]
impl RawPhysicsPipeline {
#[wasm_bindgen(constructor)]
pub fn new() -> Self {
let mut pipeline = PhysicsPipeline::new();
pipeline.counters.disable(); // Disable perf counters by default.
RawPhysicsPipeline(pipeline)
}
pub fn set_profiler_enabled(&mut self, enabled: bool) {
if enabled {
self.0.counters.enable();
} else {
self.0.counters.disable();
}
}
pub fn is_profiler_enabled(&self) -> bool {
self.0.counters.enabled()
}
pub fn timing_step(&self) -> f64 {
self.0.counters.step_time_ms()
}
pub fn timing_collision_detection(&self) -> f64 {
self.0.counters.collision_detection_time_ms()
}
pub fn timing_broad_phase(&self) -> f64 {
self.0.counters.broad_phase_time_ms()
}
pub fn timing_narrow_phase(&self) -> f64 {
self.0.counters.narrow_phase_time_ms()
}
pub fn timing_solver(&self) -> f64 {
self.0.counters.solver_time_ms()
}
pub fn timing_velocity_assembly(&self) -> f64 {
self.0.counters.solver.velocity_assembly_time.time_ms()
}
pub fn timing_velocity_resolution(&self) -> f64 {
self.0.counters.velocity_resolution_time_ms()
}
pub fn timing_velocity_update(&self) -> f64 {
self.0.counters.velocity_update_time_ms()
}
pub fn timing_velocity_writeback(&self) -> f64 {
self.0.counters.solver.velocity_writeback_time.time_ms()
}
pub fn timing_ccd(&self) -> f64 {
self.0.counters.ccd_time_ms()
}
pub fn timing_ccd_toi_computation(&self) -> f64 {
self.0.counters.ccd.toi_computation_time.time_ms()
}
pub fn timing_ccd_broad_phase(&self) -> f64 {
self.0.counters.ccd.broad_phase_time.time_ms()
}
pub fn timing_ccd_narrow_phase(&self) -> f64 {
self.0.counters.ccd.narrow_phase_time.time_ms()
}
pub fn timing_ccd_solver(&self) -> f64 {
self.0.counters.ccd.solver_time.time_ms()
}
pub fn timing_island_construction(&self) -> f64 {
self.0.counters.island_construction_time_ms()
}
pub fn timing_user_changes(&self) -> f64 {
self.0.counters.stages.user_changes.time_ms()
}
pub fn step(
&mut self,
gravity: &RawVector,
integrationParameters: &RawIntegrationParameters,
islands: &mut RawIslandManager,
broadPhase: &mut RawBroadPhase,
narrowPhase: &mut RawNarrowPhase,
bodies: &mut RawRigidBodySet,
colliders: &mut RawColliderSet,
joints: &mut RawImpulseJointSet,
articulations: &mut RawMultibodyJointSet,
ccd_solver: &mut RawCCDSolver,
) {
self.0.step(
&gravity.0,
&integrationParameters.0,
&mut islands.0,
&mut broadPhase.0,
&mut narrowPhase.0,
&mut bodies.0,
&mut colliders.0,
&mut joints.0,
&mut articulations.0,
&mut ccd_solver.0,
&(),
&(),
);
}
pub fn stepWithEvents(
&mut self,
gravity: &RawVector,
integrationParameters: &RawIntegrationParameters,
islands: &mut RawIslandManager,
broadPhase: &mut RawBroadPhase,
narrowPhase: &mut RawNarrowPhase,
bodies: &mut RawRigidBodySet,
colliders: &mut RawColliderSet,
joints: &mut RawImpulseJointSet,
articulations: &mut RawMultibodyJointSet,
ccd_solver: &mut RawCCDSolver,
eventQueue: &mut RawEventQueue,
hookObject: js_sys::Object,
hookFilterContactPair: js_sys::Function,
hookFilterIntersectionPair: js_sys::Function,
) {
if eventQueue.auto_drain {
eventQueue.clear();
}
let hooks = RawPhysicsHooks {
this: hookObject,
filter_contact_pair: hookFilterContactPair,
filter_intersection_pair: hookFilterIntersectionPair,
};
self.0.step(
&gravity.0,
&integrationParameters.0,
&mut islands.0,
&mut broadPhase.0,
&mut narrowPhase.0,
&mut bodies.0,
&mut colliders.0,
&mut joints.0,
&mut articulations.0,
&mut ccd_solver.0,
&hooks,
&eventQueue.collector,
);
}
}

View File

@@ -0,0 +1,145 @@
use crate::dynamics::{
RawImpulseJointSet, RawIntegrationParameters, RawIslandManager, RawMultibodyJointSet,
RawRigidBodySet,
};
use crate::geometry::{RawBroadPhase, RawColliderSet, RawNarrowPhase};
use crate::math::RawVector;
use js_sys::Uint8Array;
use rapier::dynamics::{
ImpulseJointSet, IntegrationParameters, IslandManager, MultibodyJointSet, RigidBodySet,
};
use rapier::geometry::{ColliderSet, DefaultBroadPhase, NarrowPhase};
use rapier::math::Vector;
use wasm_bindgen::prelude::*;
#[derive(Serialize)]
struct SerializableWorld<'a> {
gravity: &'a Vector<f32>,
integration_parameters: &'a IntegrationParameters,
islands: &'a IslandManager,
broad_phase: &'a DefaultBroadPhase,
narrow_phase: &'a NarrowPhase,
bodies: &'a RigidBodySet,
colliders: &'a ColliderSet,
impulse_joints: &'a ImpulseJointSet,
multibody_joints: &'a MultibodyJointSet,
}
#[derive(Deserialize)]
struct DeserializableWorld {
gravity: Vector<f32>,
integration_parameters: IntegrationParameters,
islands: IslandManager,
broad_phase: DefaultBroadPhase,
narrow_phase: NarrowPhase,
bodies: RigidBodySet,
colliders: ColliderSet,
impulse_joints: ImpulseJointSet,
multibody_joints: MultibodyJointSet,
}
#[wasm_bindgen]
pub struct RawDeserializedWorld {
gravity: Option<RawVector>,
integrationParameters: Option<RawIntegrationParameters>,
islands: Option<RawIslandManager>,
broadPhase: Option<RawBroadPhase>,
narrowPhase: Option<RawNarrowPhase>,
bodies: Option<RawRigidBodySet>,
colliders: Option<RawColliderSet>,
impulse_joints: Option<RawImpulseJointSet>,
multibody_joints: Option<RawMultibodyJointSet>,
}
#[wasm_bindgen]
impl RawDeserializedWorld {
pub fn takeGravity(&mut self) -> Option<RawVector> {
self.gravity.take()
}
pub fn takeIntegrationParameters(&mut self) -> Option<RawIntegrationParameters> {
self.integrationParameters.take()
}
pub fn takeIslandManager(&mut self) -> Option<RawIslandManager> {
self.islands.take()
}
pub fn takeBroadPhase(&mut self) -> Option<RawBroadPhase> {
self.broadPhase.take()
}
pub fn takeNarrowPhase(&mut self) -> Option<RawNarrowPhase> {
self.narrowPhase.take()
}
pub fn takeBodies(&mut self) -> Option<RawRigidBodySet> {
self.bodies.take()
}
pub fn takeColliders(&mut self) -> Option<RawColliderSet> {
self.colliders.take()
}
pub fn takeImpulseJoints(&mut self) -> Option<RawImpulseJointSet> {
self.impulse_joints.take()
}
pub fn takeMultibodyJoints(&mut self) -> Option<RawMultibodyJointSet> {
self.multibody_joints.take()
}
}
#[wasm_bindgen]
pub struct RawSerializationPipeline;
#[wasm_bindgen]
impl RawSerializationPipeline {
#[wasm_bindgen(constructor)]
pub fn new() -> Self {
RawSerializationPipeline
}
pub fn serializeAll(
&self,
gravity: &RawVector,
integrationParameters: &RawIntegrationParameters,
islands: &RawIslandManager,
broadPhase: &RawBroadPhase,
narrowPhase: &RawNarrowPhase,
bodies: &RawRigidBodySet,
colliders: &RawColliderSet,
impulse_joints: &RawImpulseJointSet,
multibody_joints: &RawMultibodyJointSet,
) -> Option<Uint8Array> {
let to_serialize = SerializableWorld {
gravity: &gravity.0,
integration_parameters: &integrationParameters.0,
islands: &islands.0,
broad_phase: &broadPhase.0,
narrow_phase: &narrowPhase.0,
bodies: &bodies.0,
colliders: &colliders.0,
impulse_joints: &impulse_joints.0,
multibody_joints: &multibody_joints.0,
};
let snap = bincode::serialize(&to_serialize).ok()?;
Some(Uint8Array::from(&snap[..]))
}
pub fn deserializeAll(&self, data: Uint8Array) -> Option<RawDeserializedWorld> {
let data = data.to_vec();
let d: DeserializableWorld = bincode::deserialize(&data[..]).ok()?;
Some(RawDeserializedWorld {
gravity: Some(RawVector(d.gravity)),
integrationParameters: Some(RawIntegrationParameters(d.integration_parameters)),
islands: Some(RawIslandManager(d.islands)),
broadPhase: Some(RawBroadPhase(d.broad_phase)),
narrowPhase: Some(RawNarrowPhase(d.narrow_phase)),
bodies: Some(RawRigidBodySet(d.bodies)),
colliders: Some(RawColliderSet(d.colliders)),
impulse_joints: Some(RawImpulseJointSet(d.impulse_joints)),
multibody_joints: Some(RawMultibodyJointSet(d.multibody_joints)),
})
}
}