Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions inox2d/src/formats/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ fn deserialize_node(obj: JsonObject) -> InoxParseResult<ParsedNode> {
Ok(ParsedNode {
node: InoxNode {
uuid: InoxNodeUuid(obj.get_u32("uuid")?),
name: obj.get_str("name")?.to_owned(),
name: obj.get_str("name")?.trim_end_matches('\0').to_owned(),
enabled: obj.get_bool("enabled")?,
zsort: obj.get_f32("zsort")?,
trans_offset: vals("transform", deserialize_transform(obj.get_object("transform")?))?,
Expand Down Expand Up @@ -226,7 +226,7 @@ fn deserialize_mesh(obj: JsonObject) -> InoxParseResult<Mesh> {

let uvs = match uvs {
Ok(uvs) => uvs,
Err(e) => vec![],
Err(_e) => vec![],
};

Ok(Mesh {
Expand Down Expand Up @@ -415,7 +415,7 @@ fn deserialize_params(vals: &[json::JsonValue]) -> InoxParseResult<HashMap<Strin
}

fn deserialize_param(obj: JsonObject) -> InoxParseResult<(String, Param)> {
let name = obj.get_str("name")?.to_owned();
let name = obj.get_str("name")?.trim_end_matches('\0').to_owned();
Ok((
name.clone(),
Param {
Expand Down
5 changes: 4 additions & 1 deletion inox2d/src/math/deform.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use glam::{Mat2, Vec2};

use crate::node::InoxNodeUuid;

/// Different kinds of deform.
// TODO: Meshgroup.
pub(crate) enum Deform {
/// Specifying a displacement for every vertex.
Direct(Vec<Vec2>),
/// MESHGROUP_ATTEMPT #1
FromMeshGroup(Vec<Vec2>, InoxNodeUuid),
}

/// Element-wise add direct deforms up and write result.
Expand Down
10 changes: 5 additions & 5 deletions inox2d/src/math/triangle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ impl<'mesh> MeshBitMask<'mesh> {
}

/// Return the index of the triangle point `p` is in, if any.
pub fn test(&self, p: Vec2) -> Option<u16> {
pub fn test(&self, p: &Vec2) -> Option<u16> {
// handle empty mesh case
if self.mask.is_empty() {
return None;
Expand All @@ -208,7 +208,7 @@ impl<'mesh> MeshBitMask<'mesh> {

candidates
.into_iter()
.find(|&t| is_point_in_triangle(p, &self.mesh.get_triangle(t)))
.find(|&t| is_point_in_triangle(*p, &self.mesh.get_triangle(t)))
}
}

Expand Down Expand Up @@ -325,7 +325,7 @@ mod tests {
test_with_mesh(*transform, |mesh, ps| {
let bit_mask = MeshBitMask::new(mesh);

ps.into_iter().map(|p| bit_mask.test(p)).collect()
ps.into_iter().map(|p| bit_mask.test(&p)).collect()
})
})
}
Expand All @@ -342,7 +342,7 @@ mod tests {

assert_eq!(bit_mask.width, 0);
assert_eq!(bit_mask.height, 0);
assert_eq!(bit_mask.test(vec2(-1.0, 0.0)), None);
assert_eq!(bit_mask.test(vec2(1.0, 2.0)), None);
assert_eq!(bit_mask.test(&vec2(-1.0, 0.0)), None);
assert_eq!(bit_mask.test(&vec2(1.0, 2.0)), None);
}
}
2 changes: 1 addition & 1 deletion inox2d/src/node/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ pub struct MeshGroup {
#[derive(Hash, PartialEq, Eq, Copy, Clone)]
pub(crate) enum DeformSource {
Param(ParamUuid),
MeshGroup(InoxNodeUuid),
MeshGroup(ParamUuid, InoxNodeUuid),
}

/// Internal component solving for deforms of a node.
Expand Down
124 changes: 91 additions & 33 deletions inox2d/src/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ use crate::math::{
matrix::Matrix2d,
};
use crate::node::{
components::{DeformSource, DeformStack, Mesh, TransformStore, ZSort},
components::{DeformSource, DeformStack, Mesh, MeshGroup, TransformStore, ZSort},
InoxNodeUuid,
};
use crate::puppet::{Puppet, World};
use crate::puppet::{InoxNodeTree, Puppet, World};

/// Parameter binding to a node. This allows to animate a node based on the value of the parameter that owns it.
pub struct Binding {
Expand Down Expand Up @@ -75,7 +75,7 @@ impl Param {
///
/// End users may repeatedly apply a same parameter for multiple times in between frames,
/// but other facilities should be present to make sure this `apply()` is only called once per parameter.
pub(crate) fn apply(&self, val: Vec2, comps: &mut World) {
pub(crate) fn apply(&self, val: Vec2, nodes: &InoxNodeTree, comps: &mut World) {
let val = val.clamp(self.min, self.max);
let val_normed = (val - self.min) / (self.max - self.min);

Expand Down Expand Up @@ -113,8 +113,6 @@ impl Param {
vec2(self.axis_points.x[x_maxdex], self.axis_points.y[y_maxdex]),
);

let val_normed = val_normed.clamp(range_in.beg, range_in.end);

match binding.values {
BindingValues::ZSort(ref matrix) => {
let (out_top, out_bottom) = ranges_out(matrix, x_mindex, x_maxdex, y_mindex, y_maxdex);
Expand Down Expand Up @@ -194,32 +192,70 @@ impl Param {
matrix[(x_maxdex, y_maxdex)].as_slice(),
);

// deform specified by a parameter must be direct, i.e., in the form of displacements of all vertices
let direct_deform = {
let mesh = comps
.get::<Mesh>(binding.node)
.expect("Deform param target must have an associated Mesh.");

let vert_len = mesh.vertices.len();
let mut direct_deform: Vec<Vec2> = Vec::with_capacity(vert_len);
direct_deform.resize(vert_len, Vec2::ZERO);

bi_interpolate_vec2s_additive(
val_normed,
range_in,
out_top,
out_bottom,
binding.interpolate_mode,
&mut direct_deform,
);

direct_deform
};

comps
.get_mut::<DeformStack>(binding.node)
.expect("Nodes being deformed must have a DeformStack component.")
.push(DeformSource::Param(self.uuid), Deform::Direct(direct_deform));
// case Meshgroup
if comps.get::<MeshGroup>(binding.node).is_some() {
let direct_deform = {
let mesh = comps.get::<Mesh>(binding.node).unwrap_or_else(|| {
panic!(
"Deform param target must have an associated Mesh. (Binding Node ID: {:?})",
binding.node.0
)
});

let vert_len = mesh.vertices.len();
let mut direct_deform: Vec<Vec2> = Vec::with_capacity(vert_len);
direct_deform.resize(vert_len, Vec2::ZERO);

bi_interpolate_vec2s_additive(
val_normed,
range_in,
out_top,
out_bottom,
binding.interpolate_mode,
&mut direct_deform,
);
direct_deform
};
comps
.get_mut::<DeformStack>(binding.node)
.expect("Nodes being deformed must have a DeformStack component.")
.push(DeformSource::Param(self.uuid), Deform::Direct(direct_deform.clone()));

// Push deform data of descendants from meshgroup onto deform stack
if comps.get::<MeshGroup>(binding.node).unwrap().dynamic {
push_children(nodes, comps, self.uuid, &direct_deform, binding.node, binding.node);
}
} else {
// deform specified by a parameter must be direct, i.e., in the form of displacements of all vertices
let direct_deform = {
let mesh = comps.get::<Mesh>(binding.node).unwrap_or_else(|| {
panic!(
"Deform param target must have an associated Mesh. (Binding Node ID: {:?})",
binding.node.0
)
});

let vert_len = mesh.vertices.len();
let mut direct_deform: Vec<Vec2> = Vec::with_capacity(vert_len);
direct_deform.resize(vert_len, Vec2::ZERO);

bi_interpolate_vec2s_additive(
val_normed,
range_in,
out_top,
out_bottom,
binding.interpolate_mode,
&mut direct_deform,
);

direct_deform
};

comps
.get_mut::<DeformStack>(binding.node)
.expect("Nodes being deformed must have a DeformStack component.")
.push(DeformSource::Param(self.uuid), Deform::Direct(direct_deform));
}
}
// TODO
BindingValues::Opacity => {}
Expand All @@ -228,6 +264,28 @@ impl Param {
}
}

fn push_children(
nodes: &InoxNodeTree,
comps: &mut World,
param_uuid: ParamUuid,
meshgroup_deform: &Vec<Vec2>,
meshgroup_uuid: InoxNodeUuid,
parent_uuid: InoxNodeUuid,
) {
for child in nodes.get_children(parent_uuid) {
if comps.get::<MeshGroup>(child.uuid).is_some() {
continue;
}
if comps.get::<DeformStack>(child.uuid).is_some() {
comps.get_mut::<DeformStack>(child.uuid).unwrap().push(
DeformSource::MeshGroup(param_uuid, meshgroup_uuid),
Deform::FromMeshGroup(meshgroup_deform.to_vec(), child.uuid),
);
}
push_children(nodes, comps, param_uuid, meshgroup_deform, meshgroup_uuid, child.uuid);
}
}

/// Additional struct attached to a puppet for animating through params.
pub struct ParamCtx {
values: HashMap<String, Vec2>,
Expand Down Expand Up @@ -258,12 +316,12 @@ impl ParamCtx {
}

/// Modify components as specified by all params. Must be called ONCE per frame.
pub(crate) fn apply(&self, params: &HashMap<String, Param>, comps: &mut World) {
pub(crate) fn apply(&self, params: &HashMap<String, Param>, nodes: &InoxNodeTree, comps: &mut World) {
// a correct implementation should not care about the order of `.apply()`
for (param_name, val) in self.values.iter() {
// TODO: a correct implementation should not fail on param value (0, 0)
if *val != Vec2::ZERO {
params.get(param_name).unwrap().apply(*val, comps);
params.get(param_name).unwrap().apply(*val, nodes, comps);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions inox2d/src/puppet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ impl Puppet {
/// Provide elapsed time for physics, if initialized, to run. Provide `0` for the first call.
pub fn end_frame(&mut self, dt: f32) {
if let Some(param_ctx) = self.param_ctx.as_mut() {
param_ctx.apply(&self.params, &mut self.node_comps);
param_ctx.apply(&self.params, &self.nodes, &mut self.node_comps);
}

if let Some(transform_ctx) = self.transform_ctx.as_mut() {
Expand Down Expand Up @@ -158,7 +158,7 @@ impl Puppet {
.set(param_name, *value)
.expect("Param name returned by .step() must exist.");
}
param_ctx.apply(&self.params, &mut self.node_comps);
param_ctx.apply(&self.params, &self.nodes, &mut self.node_comps);

transform_ctx.update(&self.nodes, &mut self.node_comps);
}
Expand Down
26 changes: 24 additions & 2 deletions inox2d/src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,36 @@ impl RenderCtx {
let comps = &mut puppet.node_comps;

let mut nodes_to_deform = HashSet::new();

fn insert_children(
nodes: &InoxNodeTree,
comps: &World,
parent: InoxNodeUuid,
node_set: &mut HashSet<InoxNodeUuid>,
) {
for child in nodes.get_children(parent) {
if comps.get::<Mesh>(child.uuid).is_some() {
node_set.insert(child.uuid);
insert_children(nodes, comps, child.uuid, node_set);
}
}
}

// TODO: Refactoring and nested meshgroup. Maybe putting this into the below loop would be better?
for param in &puppet.params {
param.1.bindings.iter().for_each(|b| {
if matches!(b.values, BindingValues::Deform(_)) {
nodes_to_deform.insert(b.node);
// TODO: what is translate children??

if let Some(meshgroup) = comps.get::<MeshGroup>(b.node) {
if meshgroup.dynamic {
insert_children(nodes, comps, b.node, &mut nodes_to_deform);
}
}
}
});
}
// TODO: Further fill the set when Meshgroup is implemented.

let mut vertex_buffers = VertexBuffers::default();

Expand Down Expand Up @@ -334,7 +356,7 @@ impl<T: InoxRenderer> InoxRendererExt for T {
.expect("All children in zsorted_children_list should be a Drawable.");
match drawable_kind {
DrawableKind::TexturedMesh(components) => {
self.draw_textured_mesh_content(as_mask, &components, comps.get(*uuid).unwrap(), *uuid)
self.draw_textured_mesh_content(as_mask, &components, comps.get(*uuid).unwrap(), *uuid)
}
DrawableKind::Composite { .. } => panic!("Composite inside Composite not allowed."),
}
Expand Down
Loading