Display object refactoring (#3877)

This commit is contained in:
Wojciech Daniło 2022-11-25 07:49:52 +01:00 committed by GitHub
parent 4e30b3036d
commit d60e3835f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
101 changed files with 3498 additions and 3588 deletions

1
Cargo.lock generated
View File

@ -2373,6 +2373,7 @@ dependencies = [
name = "enso-types"
version = "0.1.0"
dependencies = [
"enso-prelude",
"enso-reflect",
"nalgebra",
"num-traits",

View File

@ -180,7 +180,7 @@ impl EntryData {
fn update_layout(&self, contour: Contour, text_size: text::Size, text_padding: f32) {
let size = contour.size;
self.text.set_position_xy(Vector2(text_padding - size.x / 2.0, text_size.value / 2.0));
self.text.set_xy(Vector2(text_padding - size.x / 2.0, text_size.value / 2.0));
self.separator.size.set(size);
self.ellipsis.size.set(size);
}

View File

@ -249,7 +249,7 @@ impl Model {
fn update_layout(&self, content_size: Vector2, size: Vector2) {
self.mask.size.set(size);
let grid_view_center = Vector2(size.x / 2.0, -size.y / 2.0);
self.mask.set_position_xy(grid_view_center);
self.mask.set_xy(grid_view_center);
let offset = self.offset(content_size, size);
// Additional padding is added to the viewport width to avoid rare glitches when the last
// entry is cropped because it is placed right on the border of the viewport. Even 1px seems
@ -505,7 +505,7 @@ impl Breadcrumbs {
model.offset(*content_size, *size)
})
);
eval scroll_anim.value((offset) model.grid.set_position_x(-offset));
eval scroll_anim.value((offset) model.grid.set_x(-offset));
eval_ input.move_up(model.move_up());
eval_ input.move_down(model.move_down());
entries_height <- all(&entries_height, &init)._0();

View File

@ -18,7 +18,6 @@ use ensogl_core::data::color;
use ensogl_core::display;
use ensogl_core::display::scene::Layer;
use ensogl_core::display::shape::StyleWatchFrp;
use ensogl_core::display::Scene;
use ensogl_grid_view as grid_view;
use ensogl_grid_view::entry::Contour;
use ensogl_grid_view::entry::MovedHeaderPosition;
@ -267,7 +266,7 @@ impl CurrentIcon {
}
impl display::Object for CurrentIcon {
fn display_object(&self) -> &display::object::Instance<Scene> {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}
@ -332,16 +331,16 @@ impl Data {
let shadow_addition = self.background.size.get().y - self.background.height.get();
let bg_sprite_height = bg_height + shadow_addition;
let bg_y = -gap_over_header / 2.0 + overlap / 2.0 + local_scope_offset;
self.background.set_position_y(bg_y);
self.background.set_y(bg_y);
self.background.size.set(Vector2(bg_width, bg_sprite_height));
self.background.height.set(bg_height);
let left = -entry_size.x / 2.0 + style.padding;
let icon_x = left + style.icon_size / 2.0;
let icon_y = local_scope_offset;
self.icon.borrow().set_position_xy(Vector2(icon_x, icon_y));
self.icon.borrow().set_xy(Vector2(icon_x, icon_y));
let text_x = Self::text_x_position(kind, style, grid_style);
let text_y = style.text_size / 2.0 + local_scope_offset;
self.label.set_position_xy(Vector2(text_x, text_y));
self.label.set_xy(Vector2(text_x, text_y));
}
fn contour(kind: Kind, grid_style: &GridStyle, entry_size: Vector2) -> Contour {
@ -517,7 +516,7 @@ impl grid_view::Entry for View {
}
impl display::Object for View {
fn display_object(&self) -> &display::object::Instance<Scene> {
fn display_object(&self) -> &display::object::Instance {
&self.data.display_object
}
}

View File

@ -658,7 +658,7 @@ impl component::Frp<Model> for Frp {
selection_entries_style.map(f!((input) model.selection_entries_params(input)));
grid_scroll_frp.resize <+ style_and_content_size.map(Model::grid_size);
grid_position <- style_and_content_size.map(Model::grid_position);
eval grid_position ((pos) model.grid.set_position_xy(*pos));
eval grid_position ((pos) model.grid.set_xy(*pos));
grid_scroll_frp.set_corner_radius_bottom_right <+ all(&corners_radius, &style.init)._0();
grid.set_entries_size <+ style.update.map(|s| s.entry_size());
grid.set_column_width <+ style.update.map(|s| (column::CENTER, s.middle_column_width()));

View File

@ -282,13 +282,13 @@ impl Model {
self.section_navigator.update_layout(style);
let navigator_shadow_x = -style.grid.width / 2.0;
self.navigator_shadow.set_position_x(navigator_shadow_x);
self.navigator_shadow.set_x(navigator_shadow_x);
let section_navigator_shadow_size = Vector2(style.navigator.width, style.size().y);
self.navigator_shadow.size.set(section_navigator_shadow_size);
self.breadcrumbs.set_position_xy(style.breadcrumbs_pos());
self.breadcrumbs.set_xy(style.breadcrumbs_pos());
self.breadcrumbs.set_size(style.breadcrumbs_size());
self.grid.set_position_xy(style.grid_pos());
self.grid.set_xy(style.grid_pos());
}
/// Set the navigator so it can be disabled on hover.

View File

@ -220,8 +220,8 @@ impl Navigator {
let x_pos = -style.grid.width / 2.0;
let top_buttons_y = top - top_buttons_height / 2.0 - top_padding;
let bottom_buttons_y = bottom + bottom_buttons_height / 2.0 + bottom_padding;
self.top_buttons.set_position_xy(Vector2(x_pos, top_buttons_y));
self.bottom_buttons.set_position_xy(Vector2(x_pos, bottom_buttons_y));
self.top_buttons.set_xy(Vector2(x_pos, top_buttons_y));
self.bottom_buttons.set_xy(Vector2(x_pos, bottom_buttons_y));
}
}

View File

@ -83,7 +83,7 @@ pub fn entry_point_searcher_icons() {
let shape = id.create_shape(Vector2(icon::SIZE, icon::SIZE));
shape.set_vivid_color(color::Rgba(0.243, 0.541, 0.160, 1.0).into());
shape.set_dull_color(color::Rgba(0.655, 0.788, 0.624, 1.0).into());
shape.set_position_x(x);
shape.set_x(x);
x += 20.0;
world.add_child(&shape);
mem::forget(shape);

View File

@ -86,7 +86,7 @@ mod entry {
}
fn set_position_and_size(&self, pos: &Vector2, size: &Vector2) {
self.text.set_position_xy(*pos);
self.text.set_xy(*pos);
self.text.set_style_or_warn("left", format!("{}px", pos.x - size.x / 2.0));
self.text.set_style_or_warn("top", format!("{}px", -pos.y - size.y / 2.0));
@ -205,10 +205,10 @@ impl<T: TextProvider> Model<T> {
}
fn set_size(&self, size: Vector2) {
self.scroll_bar_horizontal.set_position_y(-size.y / 2.0);
self.scroll_bar_horizontal.set_y(-size.y / 2.0);
self.scroll_bar_horizontal.set_length(size.x);
self.scroll_bar_vertical.set_position_x(size.x / 2.0);
self.scroll_bar_vertical.set_x(size.x / 2.0);
self.scroll_bar_vertical.set_length(size.y);
self.clipping_div.set_size(size);

View File

@ -129,8 +129,8 @@ impl AddNodeButton {
let screen = camera.screen();
let x = -screen.width / 2.0 + margin + size / 2.0;
let y = -screen.height / 2.0 + margin + size / 2.0;
view.set_position_x(x.round());
view.set_position_y(y.round());
view.set_x(x.round());
view.set_y(y.round());
}
}

View File

@ -264,8 +264,8 @@ impl BreadcrumbsModel {
let gap_width = self.gap_width.get();
let project_name_width = self.project_name.width.value().round();
self.project_name.set_position_x(gap_width);
self.breadcrumbs_container.set_position_x(gap_width + project_name_width);
self.project_name.set_x(gap_width);
self.breadcrumbs_container.set_x(gap_width + project_name_width);
let width = gap_width + project_name_width + self.breadcrumbs_container_width();
let background_width = width + 2.0 * BACKGROUND_PADDING;
@ -274,8 +274,8 @@ impl BreadcrumbsModel {
let width_with_shadow = background_width + MAGIC_SHADOW_MARGIN * 2.0;
let height_with_shadow = background_height + MAGIC_SHADOW_MARGIN * 2.0;
self.background.size.set(Vector2(width_with_shadow, height_with_shadow));
self.background.set_position_x(width / 2.0);
self.background.set_position_y(-HEIGHT / 2.0);
self.background.set_x(width / 2.0);
self.background.set_y(-HEIGHT / 2.0);
}
fn get_breadcrumb(&self, index: usize) -> Option<Breadcrumb> {
@ -352,7 +352,7 @@ impl BreadcrumbsModel {
}
debug!("Pushing {} breadcrumb.", breadcrumb.info.method_pointer.name);
breadcrumb.set_position_x(self.breadcrumbs_container_width().round());
breadcrumb.set_x(self.breadcrumbs_container_width().round());
self.breadcrumbs_container.add_child(&breadcrumb);
self.breadcrumbs.borrow_mut().push(breadcrumb);
}

View File

@ -341,8 +341,8 @@ impl BreadcrumbModel {
self.label.set_property_default(color);
self.label.set_property_default(text::formatting::Size::from(TEXT_SIZE));
self.label.set_single_line_mode(true);
self.label.set_position_x(ICON_RADIUS + ICON_RIGHT_MARGIN);
self.label.set_position_y(TEXT_SIZE / 2.0);
self.label.set_x(ICON_RADIUS + ICON_RIGHT_MARGIN);
self.label.set_y(TEXT_SIZE / 2.0);
self.label.set_content(&self.info.method_pointer.name);
let width = self.width();
@ -354,10 +354,10 @@ impl BreadcrumbModel {
let separator_size = (SEPARATOR_SIZE + PADDING * 2.0).max(0.0);
let icon_size = (ICON_SIZE + PADDING * 2.0).max(0.0);
self.separator.size.set(Vector2::new(separator_size, separator_size));
self.separator.set_position_x((offset - width / 2.0).round());
self.separator.set_x((offset - width / 2.0).round());
self.icon.size.set(Vector2::new(icon_size, icon_size));
let x_position = offset + PADDING + ICON_SIZE / 2.0 + LEFT_MARGIN + ICON_LEFT_MARGIN;
self.icon.set_position_x(x_position.round());
self.icon.set_x(x_position.round());
self
}

View File

@ -680,25 +680,25 @@ impl LayoutLine for front::line::View {
let pos = Vector2(start.x, start.y + len / 2.0);
let size = Vector2(LINE_SHAPE_WIDTH, len.abs() + LINE_SIDES_OVERLAP);
self.size.set(size);
self.set_position_xy(pos);
self.set_xy(pos);
}
fn layout_h(&self, start: Vector2<f32>, len: f32) {
let pos = Vector2(start.x + len / 2.0, start.y);
let size = Vector2(LINE_SHAPE_WIDTH, len.abs() + LINE_SIDES_OVERLAP);
self.size.set(size);
self.set_position_xy(pos);
self.set_xy(pos);
}
fn layout_v_no_overlap(&self, start: Vector2<f32>, len: f32) {
let pos = Vector2(start.x, start.y + len / 2.0);
let size = Vector2(LINE_SHAPE_WIDTH, len.abs());
self.size.set(size);
self.set_position_xy(pos);
self.set_xy(pos);
}
fn layout_h_no_overlap(&self, start: Vector2<f32>, len: f32) {
let pos = Vector2(start.x + len / 2.0, start.y);
let size = Vector2(LINE_SHAPE_WIDTH, len.abs());
self.size.set(size);
self.set_position_xy(pos);
self.set_xy(pos);
}
}
@ -707,25 +707,25 @@ impl LayoutLine for back::line::View {
let pos = Vector2(start.x, start.y + len / 2.0);
let size = Vector2(LINE_SHAPE_WIDTH, len.abs() + LINE_SIDES_OVERLAP);
self.size.set(size);
self.set_position_xy(pos);
self.set_xy(pos);
}
fn layout_h(&self, start: Vector2<f32>, len: f32) {
let pos = Vector2(start.x + len / 2.0, start.y);
let size = Vector2(LINE_SHAPE_WIDTH, len.abs() + LINE_SIDES_OVERLAP);
self.size.set(size);
self.set_position_xy(pos);
self.set_xy(pos);
}
fn layout_v_no_overlap(&self, start: Vector2<f32>, len: f32) {
let pos = Vector2(start.x, start.y + len / 2.0);
let size = Vector2(LINE_SHAPE_WIDTH, len.abs());
self.size.set(size);
self.set_position_xy(pos);
self.set_xy(pos);
}
fn layout_h_no_overlap(&self, start: Vector2<f32>, len: f32) {
let pos = Vector2(start.x + len / 2.0, start.y);
let size = Vector2(LINE_SHAPE_WIDTH, len.abs());
self.size.set(size);
self.set_position_xy(pos);
self.set_xy(pos);
}
}
@ -1398,7 +1398,7 @@ impl EdgeModelData {
self.try_enable_focus_split(hover_position, hover_target, focus_part);
if let Ok(snap_data) = focus_split_result {
let joint_position = snap_data.position - self.display_object.position().xy();
self.joint.set_position_xy(joint_position);
self.joint.set_xy(joint_position);
let joint_size = LINE_WIDTH + PADDING;
self.joint.size.set(Vector2(joint_size, joint_size));
}
@ -1541,7 +1541,7 @@ impl EdgeModelData {
bg.corner.angle.set(corner1_angle);
bg.corner.radius.set(corner1_radius);
bg.corner.pos.set(corner1);
bg.corner.set_position_xy(corner1);
bg.corner.set_xy(corner1);
if !fully_attached {
bg.corner.dim.set(Vector2(node_half_width, source_node_half_height));
fg.corner.size.set(corner1_size);
@ -1550,7 +1550,7 @@ impl EdgeModelData {
fg.corner.radius.set(corner1_radius);
fg.corner.pos.set(corner1);
fg.corner.dim.set(Vector2(node_half_width, source_node_half_height));
fg.corner.set_position_xy(corner1);
fg.corner.set_xy(corner1);
} else {
fg.corner.size.set(zero());
bg.corner.dim.set(Vector2(INFINITE, INFINITE));
@ -1687,7 +1687,7 @@ impl EdgeModelData {
bg.corner3.radius.set(corner3_radius);
bg.corner3.pos.set(corner3);
bg.corner3.dim.set(Vector2(INFINITE, INFINITE));
bg.corner3.set_position_xy(corner3);
bg.corner3.set_xy(corner3);
} else {
bg.corner3.size.set(zero());
fg.corner3.size.set(corner3_size);
@ -1696,7 +1696,7 @@ impl EdgeModelData {
fg.corner3.radius.set(corner3_radius);
fg.corner3.pos.set(corner3);
fg.corner3.dim.set(zero());
fg.corner3.set_position_xy(corner3);
fg.corner3.set_xy(corner3);
}
let corner2_x = corner1_target.x + corner_2_3_side * corner2_radius;
@ -1711,7 +1711,7 @@ impl EdgeModelData {
bg.corner2.radius.set(corner2_radius);
bg.corner2.pos.set(corner2);
bg.corner2.dim.set(Vector2(INFINITE, INFINITE));
bg.corner2.set_position_xy(corner2);
bg.corner2.set_xy(corner2);
} else {
bg.corner2.size.set(zero());
fg.corner2.size.set(corner1_size);
@ -1720,7 +1720,7 @@ impl EdgeModelData {
fg.corner2.radius.set(corner2_radius);
fg.corner2.pos.set(corner2);
fg.corner2.dim.set(zero());
fg.corner2.set_position_xy(corner2);
fg.corner2.set_xy(corner2);
}
@ -1751,11 +1751,11 @@ impl EdgeModelData {
if fully_attached {
fg.arrow.size.set(zero());
bg.arrow.size.set(arrow_size);
bg.arrow.set_position_xy(arrow_pos);
bg.arrow.set_xy(arrow_pos);
} else {
bg.arrow.size.set(zero());
fg.arrow.size.set(arrow_size);
fg.arrow.set_position_xy(arrow_pos);
fg.arrow.set_xy(arrow_pos);
}
} else {
bg.arrow.size.set(zero());

View File

@ -629,11 +629,11 @@ impl NodeModel {
self.error_indicator.size.set(padded_size);
self.vcs_indicator.set_size(padded_size);
let x_offset_to_node_center = x_offset_to_node_center(width);
self.backdrop.set_position_x(x_offset_to_node_center);
self.background.set_position_x(x_offset_to_node_center);
self.drag_area.set_position_x(x_offset_to_node_center);
self.error_indicator.set_position_x(x_offset_to_node_center);
self.vcs_indicator.set_position_x(x_offset_to_node_center);
self.backdrop.set_x(x_offset_to_node_center);
self.background.set_x(x_offset_to_node_center);
self.drag_area.set_x(x_offset_to_node_center);
self.error_indicator.set_x(x_offset_to_node_center);
self.vcs_indicator.set_x(x_offset_to_node_center);
let action_bar_width = ACTION_BAR_WIDTH;
self.action_bar.mod_position(|t| {
@ -642,8 +642,8 @@ impl NodeModel {
self.action_bar.frp.set_size(Vector2::new(action_bar_width, ACTION_BAR_HEIGHT));
let visualization_offset = visualization_offset(width);
self.error_visualization.set_position_xy(visualization_offset);
self.visualization.set_position_xy(visualization_offset);
self.error_visualization.set_xy(visualization_offset);
self.visualization.set_xy(visualization_offset);
size
}
@ -688,6 +688,7 @@ impl Node {
let input = &frp.private.input;
let model = Rc::new(NodeModel::new(app, registry));
let selection = Animation::<f32>::new(network);
let display_object = &model.display_object;
// TODO[ao] The comment color should be animated, but this is currently slow. Will be fixed
// in https://github.com/enso-org/ide/issues/1031
@ -696,12 +697,13 @@ impl Node {
let style = StyleWatch::new(&app.display.default_scene.style_sheet);
let style_frp = &model.style;
let action_bar = &model.action_bar.frp;
// Hook up the display object position updates to the node's FRP. Required to calculate the
// bounding box.
model.display_object.set_on_updated(f!((p) out.position.emit(p.position().xy())));
frp::extend! { network
// Hook up the display object position updates to the node's FRP. Required to calculate
// the bounding box.
out.position <+ display_object.on_updated.map(f_!(display_object.position().xy()));
// === Hover ===
// The hover discovery of a node is an interesting process. First, we discover whether
// ths user hovers the drag area. The input port manager merges this information with
@ -758,9 +760,9 @@ impl Node {
eval comment_color ((value) model.comment.set_property(.., color::Rgba::from(value)));
eval model.comment.width ([model](width)
model.comment.set_position_x(-*width - COMMENT_MARGIN));
model.comment.set_x(-*width - COMMENT_MARGIN));
eval model.comment.height ([model](height)
model.comment.set_position_y(*height / 2.0));
model.comment.set_y(*height / 2.0));
model.comment.set_content <+ input.set_comment;
out.comment <+ model.comment.content.map(|text| text.to_im_string());

View File

@ -192,12 +192,12 @@ impl Model {
self.hover_area.size.set(hover_ara_size);
let center_offset = -size.x / 2.0 + hover_ara_size.x / 2.0;
let padding_offset = -0.5 * hover_padding * button_width - HOVER_EXTENSION_X / 2.0;
self.hover_area.set_position_x(center_offset + padding_offset);
self.hover_area.set_x(center_offset + padding_offset);
}
fn set_size(&self, size: Vector2) {
self.size.set(size);
self.icons.set_position_x(-size.x / 2.0);
self.icons.set_x(-size.x / 2.0);
// Note: Disabled for https://github.com/enso-org/ide/issues/1397
// Should be re-enabled when https://github.com/enso-org/ide/issues/862 as been implemented.

View File

@ -230,8 +230,8 @@ impl Model {
self.label.remove_all_cursors();
let origin = Vector2(TEXT_OFFSET, 0.0);
self.ports.set_position_xy(origin);
self.label.set_position_xy(origin);
self.ports.set_xy(origin);
self.label.set_xy(origin);
self.label.mod_position(|t| t.y += TEXT_SIZE / 2.0);
self

View File

@ -239,7 +239,7 @@ impl Model {
fn set_label(&self, content: impl Into<String>) {
let str = if ARGS.node_labels.unwrap_or(true) { content.into() } else { default() };
self.label.set_content(str);
self.label.set_position_x(-self.label.width.value() - input::area::TEXT_OFFSET);
self.label.set_x(-self.label.width.value() - input::area::TEXT_OFFSET);
}
/// Update expression type for the particular `ast::Id`.
@ -329,7 +329,7 @@ impl Model {
#[profile(Debug)]
fn set_size(&self, size: Vector2) {
self.ports.set_position_x(size.x / 2.0);
self.ports.set_x(size.x / 2.0);
self.traverse_borrowed_expression_mut(|is_a_port, node, _| {
if is_a_port {
node.payload_mut().set_size(size)

View File

@ -485,7 +485,7 @@ impl Model {
let type_label = app.new_view::<text::Text>();
let offset_y =
styles.get_number(ensogl_hardcoded_theme::graph_editor::node::type_label::offset_y);
type_label.set_position_y(offset_y);
type_label.set_y(offset_y);
self.type_label = Some(type_label.clone());
let display_object = display::object::Instance::new();
@ -549,7 +549,7 @@ impl Model {
let label_center_x = port_center_x;
label_center_x - type_label_width / 2.0
}));
eval set_type_label_x ((&t) type_label.set_position_x(t));
eval set_type_label_x ((&t) type_label.set_x(t));
eval frp.set_size_multiplier ((t) shape.set_size_multiplier(*t));

View File

@ -201,7 +201,7 @@ impl ProfilingLabel {
let label = text::Text::new(app);
root.add_child(&label);
label.set_position_y(crate::component::node::input::area::TEXT_SIZE / 2.0);
label.set_y(crate::component::node::input::area::TEXT_SIZE / 2.0);
scene.layers.main.remove(&label);
label.add_to_scene_layer(&scene.layers.label);
@ -236,7 +236,7 @@ impl ProfilingLabel {
// === Position ===
let x_offset = crate::component::node::input::area::TEXT_OFFSET;
eval label.width((&width) label.set_position_x(-width-x_offset));
eval label.width((&width) label.set_x(-width-x_offset));
// === Content ===

View File

@ -167,8 +167,8 @@ impl Button {
eval scene.frp.camera_changed([button,scene](_) {
let screen = scene.camera().screen();
button.set_position_x(screen.width/2.0 - 16.0);
button.set_position_y(screen.height/2.0 - 16.0);
button.set_x(screen.width/2.0 - 16.0);
button.set_y(screen.height/2.0 - 16.0);
});

View File

@ -414,7 +414,7 @@ impl ContainerModel {
self.action_bar.frp.set_size.emit(action_bar_size);
}
self.action_bar.set_position_y((size.y - ACTION_BAR_HEIGHT) / 2.0);
self.action_bar.set_y((size.y - ACTION_BAR_HEIGHT) / 2.0);
if let Some(viz) = &*self.visualization.borrow() {
viz.set_size.emit(size);
@ -649,9 +649,9 @@ impl Container {
// === Action bar actions ===
frp::extend! { network
eval_ action_bar.on_container_reset_position(model.drag_root.set_position_xy(Vector2::zero()));
eval_ action_bar.on_container_reset_position(model.drag_root.set_xy(Vector2::zero()));
drag_action <- app.cursor.frp.scene_position_delta.gate(&action_bar.container_drag_state);
eval drag_action ((mouse) model.drag_root.mod_position_xy(|pos| pos - mouse.xy()));
eval drag_action ((mouse) model.drag_root.mod_xy(|pos| pos - mouse.xy()));
}
// FIXME[mm]: If we set the size right here, we will see spurious shapes in some

View File

@ -198,7 +198,7 @@ impl Icons {
fn set_size(&self, size: Vector2) {
self.size.set(size);
self.icon_root.set_position_x(-size.x / 2.0);
self.icon_root.set_x(-size.x / 2.0);
self.place_shape_in_slot(&self.drag_icon, 0);
self.place_shape_in_slot(&self.reset_position_icon, 1);
}
@ -298,7 +298,7 @@ impl Model {
let right_padding = height / 2.0;
self.visualization_chooser.frp.set_icon_size(Vector2::new(height, height));
self.visualization_chooser.frp.set_icon_padding(Vector2::new(height / 3.0, height / 3.0));
self.visualization_chooser.set_position_x((width / 2.0) - right_padding);
self.visualization_chooser.set_x((width / 2.0) - right_padding);
self.visualization_chooser.frp.set_menu_offset_y(MENU_GAP);
}

View File

@ -1468,7 +1468,7 @@ impl GraphEditorModelWithNetwork {
) -> (NodeId, Option<NodeSource>, bool) {
let position = new_node_position::new_node_position(self, way, mouse_position);
let node = self.new_node(ctx);
node.set_position_xy(position);
node.set_xy(position);
let should_edit = !matches!(way, WayOfCreatingNode::AddNodeEvent);
if should_edit {
node.view.set_expression(node::Expression::default());
@ -1741,8 +1741,8 @@ impl GraphEditorModel {
self.add_child(&self.breadcrumbs);
let x_offset = MACOS_TRAFFIC_LIGHTS_SIDE_OFFSET;
let y_offset = MACOS_TRAFFIC_LIGHTS_VERTICAL_CENTER + component::breadcrumbs::HEIGHT / 2.0;
self.breadcrumbs.set_position_x(x_offset);
self.breadcrumbs.set_position_y(y_offset);
self.breadcrumbs.set_x(x_offset);
self.breadcrumbs.set_y(y_offset);
self.breadcrumbs.gap_width(traffic_lights_gap_width());
self.scene().add_child(&self.tooltip);
self.add_child(&self.profiling_button);
@ -3877,7 +3877,7 @@ mod tests {
camera_pos: Vector2,
) {
let camera = &scene.camera();
camera.set_position_xy(camera_pos);
camera.set_xy(camera_pos);
camera.update(scene);
click_add_node_button(editor);
}
@ -3941,12 +3941,12 @@ mod tests {
// Create 2nd node below the 1st one and move it slightly to the right.
graph_editor.nodes().select(node_1_id);
let (node_2_id, node_2) = graph_editor.add_node_by(&press_add_node_shortcut);
node_2.mod_position_x(|x| x + 16.0);
node_2.mod_x(|x| x + 16.0);
// Create 3rd node below the 2nd one and move it slightly down and far to the right.
graph_editor.nodes().select(node_2_id);
let (_, node_3) = graph_editor.add_node_by(&press_add_node_shortcut);
node_2.mod_position_xy(|pos| pos + Vector2(800.0, -7.0));
node_2.mod_xy(|pos| pos + Vector2(800.0, -7.0));
// Create 4th node by clicking (+) button when camera is roughly centered at the 1st node.
let small_displacement = Vector2(8.0, 9.0);
@ -3987,7 +3987,7 @@ mod tests {
fn add_node_by_api_at_pos(&self, position: Vector2) -> (NodeId, Node) {
let (node_id, node) = self.add_node_by_api();
self.stop_editing();
node.set_position_xy(position);
node.set_xy(position);
(node_id, node)
}

View File

@ -74,7 +74,7 @@ impl View {
let model = app.new_view::<text::Text>();
let height_fraction = DEPRECATED_Animation::<f32>::new(network);
model.set_position_x(PADDING_LEFT);
model.set_x(PADDING_LEFT);
scene.layers.main.remove(&model);
model.add_to_scene_layer(&scene.layers.panel_text);
// TODO[ao]: To have code editor usable we treat it as constantly mouse-hovered, but this
@ -108,7 +108,7 @@ impl View {
let y = -scene_size.height / 2.0 + height;
Vector2(x,y)
});
eval position ((pos) model.set_position_xy(*pos));
eval position ((pos) model.set_xy(*pos));
let color = styles.get_color(ensogl_hardcoded_theme::code::syntax::base);
eval color ((color) model.set_property_default(color));

View File

@ -125,8 +125,8 @@ impl component::Frp<Model> for Frp {
list_position_x <-
all_with3(&size, &list_panel.size, &snap, |sz, list_sz, snap| list_sz.x / 2.0 - sz.x / 2.0 + snap.x);
doc_position_x <- all_with3(&size, &doc_size, &snap, |sz, doc_sz, snap| sz.x / 2.0 - doc_sz.x / 2.0 + snap.x);
eval list_position_x ((x) model.list.set_position_x(*x));
eval doc_position_x ((x) model.documentation.set_position_x(*x));
eval list_position_x ((x) model.list.set_x(*x));
eval doc_position_x ((x) model.documentation.set_x(*x));
model.list.input.show <+ input.show;
model.list.input.hide <+ input.hide;

View File

@ -8,7 +8,6 @@ use enso_frp as frp;
use ensogl::animation::delayed::DelayedAnimation;
use ensogl::application::Application;
use ensogl::display;
use ensogl::display::scene::Scene;
use ensogl::Animation;
use ensogl_component::label::Label;
@ -50,7 +49,7 @@ pub struct PopupLabel {
}
impl display::Object for PopupLabel {
fn display_object(&self) -> &display::object::Instance<Scene> {
fn display_object(&self) -> &display::object::Instance {
self.label.display_object()
}
}
@ -180,7 +179,7 @@ impl View {
let half_height = scene_size.height / 2.0;
let label_height = model.label_height();
let pos_y = half_height - LABEL_PADDING_TOP - label_height / 2.0;
model.display_object.set_position_y(pos_y);
model.display_object.set_y(pos_y);
}));
eval_ frp.enabled(model.show_enabled_label());
@ -198,7 +197,7 @@ impl View {
}
impl display::Object for View {
fn display_object(&self) -> &display::object::Instance<Scene> {
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object
}
}

View File

@ -67,8 +67,8 @@ impl OpenDialog {
project_list_x <- all_with(&width,&project_list_width,|w,pw| - *w / 2.0 + *pw / 2.0);
file_browser_x <- all_with(&width,&file_browser_width, |w,fw| w / 2.0 - *fw / 2.0);
eval project_list_x ((x) project_list.set_position_x(*x));
eval file_browser_x ((x) file_browser.set_position_x(*x));
eval project_list_x ((x) project_list.set_x(*x));
eval file_browser_x ((x) file_browser.set_x(*x));
}
init.emit(());
Self { logger, network, project_list, file_browser, display_object, style_watch }

View File

@ -130,8 +130,8 @@ impl ProjectList {
eval size ((size) background.size.set(*size));
eval list_size ((size) list.resize(*size));
eval list_y ((y) list.set_position_y(*y));
eval caption_xy ((xy) caption.set_position_xy(*xy));
eval list_y ((y) list.set_y(*y));
eval caption_xy ((xy) caption.set_xy(*xy));
eval color ((color) caption.set_property_default(color));
eval label_size ((size) caption.set_property_default(text::Size(*size)));
};

View File

@ -25,7 +25,6 @@ use ensogl::application::shortcut;
use ensogl::application::Application;
use ensogl::display;
use ensogl::display::navigation::navigator::Navigator;
use ensogl::display::Scene;
use ensogl::system::web;
use ensogl::system::web::dom;
use ensogl::Animation;
@ -223,7 +222,7 @@ impl SearcherVariant {
SearcherVariant::ComponentBrowser(view) => {
frp::extend! {network
cb_position <- all_with(anchor, &view.expression_input_position, |anchor, pos| anchor - pos);
eval cb_position ((pos) view.set_position_xy(*pos));
eval cb_position ((pos) view.set_xy(*pos));
}
}
SearcherVariant::OldNodeSearcher(view) => {
@ -233,7 +232,7 @@ impl SearcherVariant {
let y = anchor.y - node::HEIGHT / 2.0 - size.y / 2.0;
Vector2(x, y)
});
eval searcher_pos ((pos) view.set_position_xy(*pos));
eval searcher_pos ((pos) view.set_xy(*pos));
}
}
}
@ -241,7 +240,7 @@ impl SearcherVariant {
}
impl display::Object for SearcherVariant {
fn display_object(&self) -> &display::object::Instance<Scene> {
fn display_object(&self) -> &display::object::Instance {
match self {
SearcherVariant::ComponentBrowser(view) => view.display_object(),
SearcherVariant::OldNodeSearcher(view) => view.display_object(),
@ -391,7 +390,7 @@ impl Model {
// Top buttons must always stay in top-left corner.
if let Some(window_control_buttons) = &*self.window_control_buttons {
let pos = Vector2(-shape.width, shape.height) / 2.0;
window_control_buttons.set_position_xy(pos);
window_control_buttons.set_xy(pos);
}
}
@ -552,7 +551,7 @@ impl View {
let move_to_edited_node = searcher_pos * (1.0 - zoom);
preserve_zoom + move_to_edited_node
});
eval searcher_cam_pos ((pos) searcher_cam.set_position_xy(*pos));
eval searcher_cam_pos ((pos) searcher_cam.set_xy(*pos));
eval searcher.is_visible ([model](is_visible) {
let is_attached = model.searcher.has_parent();
@ -737,7 +736,7 @@ impl View {
);
_eval <- all_with3(&model.prompt.width,&prompt_size,&prompt_bg_padding,
f!([model](width,size,padding) {
model.prompt.set_position_x(- *width / 2.0);
model.prompt.set_x(- *width / 2.0);
model.prompt_background.size.set(Vector2(*width + padding, *size + padding));
})
);

View File

@ -135,10 +135,10 @@ impl Model {
let action_list_gap_path = ensogl_hardcoded_theme::application::searcher::action_list_gap;
let action_list_gap = style.get_number_or(action_list_gap_path, 0.0);
list.set_label_layer(&scene.layers.node_searcher_text);
list.set_position_y(-action_list_gap);
list.set_position_x(ACTION_LIST_X);
documentation.set_position_x(DOCUMENTATION_X);
documentation.set_position_y(-action_list_gap);
list.set_y(-action_list_gap);
list.set_x(ACTION_LIST_X);
documentation.set_x(DOCUMENTATION_X);
documentation.set_y(-action_list_gap);
Self { app, logger, display_object, list, documentation, doc_provider }
}

View File

@ -16,7 +16,6 @@ use ensogl::application::Application;
use ensogl::display;
use ensogl::display::camera::Camera2d;
use ensogl::display::style;
use ensogl::display::Scene;
use ensogl_component::shadow;
use ensogl_hardcoded_theme as theme;
use ensogl_text as text;
@ -209,13 +208,13 @@ impl Model {
fn camera_changed(&self) {
let screen = self.camera.screen();
let y = screen.height / 2.0 - MARGIN;
self.root.set_position_y(y.round());
self.root.set_y(y.round());
}
fn update_layout(&self) {
let label_width = self.label.width.value();
self.label.set_position_x(-label_width / 2.0);
self.label.set_position_y(-HEIGHT / 2.0 + TEXT_SIZE / 2.0);
self.label.set_x(-label_width / 2.0);
self.label.set_y(-HEIGHT / 2.0 + TEXT_SIZE / 2.0);
let bg_width = if label_width > 0.0 {
label_width + 2.0 * PADDING + 2.0 * MAGIC_SHADOW_MARGIN
@ -224,7 +223,7 @@ impl Model {
};
let bg_height = HEIGHT + 2.0 * MAGIC_SHADOW_MARGIN;
self.background.size.set(Vector2(bg_width, bg_height));
self.background.set_position_y(-HEIGHT / 2.0);
self.background.set_y(-HEIGHT / 2.0);
}
fn add_event(&self, label: &event::Label) -> event::Id {
@ -350,7 +349,7 @@ impl View {
}
impl display::Object for View {
fn display_object(&self) -> &display::object::Instance<Scene> {
fn display_object(&self) -> &display::object::Instance {
&self.model.display_object
}
}

View File

@ -176,16 +176,16 @@ impl Model {
let padding_offset = Vector2(padding_left, -padding_top);
let origin_offset = |size: Vector2| Vector2(size.x / 2.0, -size.y / 2.0);
self.close.set_position_xy(padding_offset + origin_offset(close_size));
self.close.set_xy(padding_offset + origin_offset(close_size));
let fullscreen_x = padding_left + close_size.x + spacing;
self.fullscreen
.set_position_xy(Vector2(fullscreen_x, -padding_top) + origin_offset(fullscreen_size));
.set_xy(Vector2(fullscreen_x, -padding_top) + origin_offset(fullscreen_size));
let width = fullscreen_x + fullscreen_size.x + padding_right;
let height = padding_top + max(close_size.y, fullscreen_size.y) + padding_bottom;
let size = Vector2(width, height);
self.shape.set_position_xy(Vector2(size.x, -size.y) / 2.0);
self.shape.set_xy(Vector2(size.x, -size.y) / 2.0);
self.shape.size.set(size);
size
}

View File

@ -147,7 +147,7 @@ async fn adding_node_with_add_node_button() {
// If there is a free space, the new node is created in the center of screen.
let camera = scene.layers.main.camera();
camera.mod_position_xy(|pos| pos + Vector2(1000.0, 1000.0));
camera.mod_xy(|pos| pos + Vector2(1000.0, 1000.0));
wait_a_frame().await;
graph_editor.nodes().deselect_all();
let (node_id, node_source, _) = add_node_with_add_node_button(&graph_editor, "1").await;

View File

@ -265,24 +265,24 @@ impl DropDownMenu {
resize_menu <- all(model.selection_menu.size,frp.input.set_icon_size,frp.input.set_menu_offset_y);
eval resize_menu (((menu_size,icon_size,menu_offset_y)) {
// Align the top of the menu to the bottom of the icon.
model.selection_menu.set_position_y(-menu_size.y/2.0-icon_size.y/2.0-menu_offset_y);
model.selection_menu.set_y(-menu_size.y/2.0-icon_size.y/2.0-menu_offset_y);
// Align the right of the menu to the right of the icon.
let offfset_y = -menu_size.x/2.0+icon_size.x/2.0-list_view::SHADOW_PX/2.0;
model.selection_menu.set_position_x(offfset_y);
model.selection_menu.set_x(offfset_y);
});
label_position <- all(model.label.frp.width,frp.input.set_icon_size);
eval label_position (((text_width,icon_size)) {
model.label.set_position_x(-text_width-icon_size.x/2.0);
model.label.set_x(-text_width-icon_size.x/2.0);
// Adjust for text offset, so this appears more centered.
model.label.set_position_y(0.25 * icon_size.y);
model.label.set_y(0.25 * icon_size.y);
});
overlay_size <- all(model.label.frp.width,frp.input.set_icon_size);
eval overlay_size ([model]((text_width,icon_size)) {
let size = Vector2::new(text_width + icon_size.x,icon_size.y);
model.icon_overlay.size.set(size);
model.icon_overlay.set_position_x(-text_width/2.0);
model.icon_overlay.set_x(-text_width/2.0);
});

View File

@ -38,7 +38,6 @@ use crate::prelude::*;
use crate::model::AnyFolderContent;
use ensogl_core::display;
use ensogl_core::display::Scene;
use std::path::PathBuf;
@ -108,7 +107,7 @@ impl Default for FileBrowser {
}
impl display::Object for FileBrowser {
fn display_object(&self) -> &display::object::Instance<Scene> {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}

View File

@ -136,7 +136,7 @@ pub fn shape_from_block<BlockType: IntoThemePath>(
component.set_content.emit(block.label);
component.set_size.emit(size);
component.set_position_xy(pos);
component.set_xy(pos);
component
}
@ -151,7 +151,7 @@ fn shape_from_mark(mark: profiler_flame_graph::Mark, app: &Application) -> Mark
let label = format!("{} ({:.1}ms)", mark.label, mark.position);
component.set_content.emit(label);
component.set_position_xy(pos);
component.set_xy(pos);
component
}
@ -267,8 +267,8 @@ impl FlameGraph {
/// position as the root display object).
pub fn set_origin(&mut self, new_origin: f64) {
let delta = (self.origin_x - new_origin) as f32;
self.marks.iter().for_each(|mark| mark.mod_position_x(|pos| pos - delta));
self.blocks.iter().for_each(|block| block.mod_position_x(|pos| pos - delta));
self.marks.iter().for_each(|mark| mark.mod_x(|pos| pos - delta));
self.blocks.iter().for_each(|block| block.mod_x(|pos| pos - delta));
self.origin_x = new_origin
}
}

View File

@ -101,7 +101,7 @@ where EntryParams: frp::node::Data
contour <- all(init, entry_frp.contour)._1();
eval contour ((c) overlay.set_contour(*c));
contour_offset <- all(init, entry_frp.contour_offset)._1();
eval contour_offset ((off) overlay.set_position_xy(*off));
eval contour_offset ((off) overlay.set_xy(*off));
let events = &overlay.events;
let disabled = &entry_frp.disabled;
@ -173,7 +173,7 @@ pub fn set_position<E: Entry>(
column_widths: &ColumnWidths,
) {
let pos = position(row, col, entry_size, column_widths);
entry.set_position_xy(pos);
entry.set_xy(pos);
entry.frp().position_set(pos);
}

View File

@ -231,7 +231,7 @@ impl<InnerGrid, HeaderEntry: Entry> Model<InnerGrid, HeaderEntry, HeaderEntry::P
let updated_positions = visible_headers.iter().filter_map(|(col, header)| {
let new_position = header.header_position(*col, entries_size, viewport, widths);
(header.entry.position().xy() != new_position.position).as_some_from(|| {
header.entry.set_position_xy(new_position.position);
header.entry.set_xy(new_position.position);
header.entry.entry.frp().moved_as_header(&new_position);
(header.section_rows.start, *col, new_position.position)
})
@ -295,7 +295,7 @@ impl<InnerGrid, HeaderEntry: Entry> Model<InnerGrid, HeaderEntry, HeaderEntry::P
let width_offset = self.column_widths.width_diff(col);
entry_frp.set_size(entry_size + Vector2(width_offset, 0.0));
let position = entry.header_position(col, entry_size, viewport, widths);
entry.entry.set_position_xy(position.position);
entry.entry.set_xy(position.position);
entry_frp.moved_as_header(&position);
(entry.section_rows.start, col, position.position)
}

View File

@ -287,7 +287,6 @@ mod tests {
use ensogl_core::application::frp::API;
use ensogl_core::data::color;
use ensogl_core::display::scene::Layer;
use ensogl_core::display::Scene;
use ensogl_scroll_area::Viewport;
use itertools::iproduct;
@ -355,7 +354,7 @@ mod tests {
}
impl display::Object for TestEntry {
fn display_object(&self) -> &display::object::Instance<Scene> {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
}
}

View File

@ -79,7 +79,7 @@ ensogl_core::shape! {
/// [module's docs](mod@self) for more info.
pub fn set_viewport(shape: &View, viewport: Viewport) {
shape.size.set(viewport.size());
shape.set_position_xy(viewport.center_point());
shape.set_xy(viewport.center_point());
}

View File

@ -114,7 +114,7 @@ impl EntryData {
fn update_layout(&self, contour: entry::Contour, text_size: text::Size, text_offset: f32) {
self.background.set_contour(contour);
let size = contour.size;
self.label.set_position_xy(Vector2(text_offset - size.x / 2.0, text_size.value / 2.0));
self.label.set_xy(Vector2(text_offset - size.x / 2.0, text_size.value / 2.0));
}
}

View File

@ -135,7 +135,7 @@ impl Model {
let padded_size = size + padding * 2.0;
self.background.size.set(padded_size);
let text_origin = Vector2(text_offset - size.x / 2.0, text_size / 2.0);
self.label.set_position_xy(text_origin);
self.label.set_xy(text_origin);
padded_size
}

View File

@ -125,7 +125,7 @@ impl Label {
label.set_property_default <+ color.ref_into_some();
label.set_font <+ font;
label.set_property_default <+ size.map(|v| text::Size(*v)).ref_into_some();
eval size ((size) label.set_position_y(size/2.0));
eval size ((size) label.set_y(size/2.0));
label.set_content <+ text;
label.set_view_width <+ max_width_px.some();

View File

@ -288,7 +288,7 @@ impl<E: Entry> ListData<E, E::Params> {
entry.entry.update(&default());
}
};
entry.entry.set_position_y(Self::position_y_of_entry(id));
entry.entry.set_y(Self::position_y_of_entry(id));
}
}

View File

@ -235,10 +235,10 @@ impl<E: Entry> Model<E> {
let margin = Vector2(2.0 * SHAPE_MARGIN, 2.0 * SHAPE_MARGIN);
let shadow = Vector2(2.0 * SHADOW_PX, 2.0 * SHADOW_PX);
let entry_width = view.size.x - 2.0 * entry_padding;
self.entries.set_position_x(-view.size.x / 2.0 + entry_padding);
self.entries.set_x(-view.size.x / 2.0 + entry_padding);
self.background.size.set(view.size + padding + shadow + margin);
self.overlay.size.set(view.size + padding + shadow + margin);
self.scrolled_area.set_position_y(view.size.y / 2.0 - view.position_y);
self.scrolled_area.set_y(view.size.y / 2.0 - view.position_y);
self.entries.update_entries(visible_entries, entry_width, style_prefix);
}
@ -594,7 +594,7 @@ where E::Model: Default
selection_sprite_y <- all_with3(&selection_y.value, &selection_height.value, &style.selection_height,
|y, h, max_h| y + (max_h - h) / 2.0
);
eval selection_sprite_y ((y) model.selection.set_position_y(*y));
eval selection_sprite_y ((y) model.selection.set_y(*y));
frp.source.selection_size <+ all_with3(&frp.size, &style.padding, &selection_height.value, f!([](size, padding, height) {
let width = size.x - 2.0 * padding;
Vector2(width,*height)

View File

@ -199,14 +199,14 @@ struct Model {
impl Model {
fn resize(&self, size: Vector2) {
self.h_scrollbar.set_position_y(-size.y + scrollbar::WIDTH / 2.0);
self.h_scrollbar.set_y(-size.y + scrollbar::WIDTH / 2.0);
let scrollbar_y = size.x - scrollbar::WIDTH / 2.0 + scrollbar::PADDING / 2.0 + 1.0;
self.v_scrollbar.set_position_x(scrollbar_y);
self.h_scrollbar.set_position_x(size.x / 2.0);
self.v_scrollbar.set_position_y(-size.y / 2.0);
self.v_scrollbar.set_x(scrollbar_y);
self.h_scrollbar.set_x(size.x / 2.0);
self.v_scrollbar.set_y(-size.y / 2.0);
self.mask.size.set(size);
self.mask.set_position_x(size.x / 2.0);
self.mask.set_position_y(-size.y / 2.0);
self.mask.set_x(size.x / 2.0);
self.mask.set_y(-size.y / 2.0);
}
}
@ -335,8 +335,8 @@ impl ScrollArea {
frp.source.scroll_position_target_x <+ model.h_scrollbar.thumb_position_target.map(|x| -x);
frp.source.scroll_position_target_y <+ model.v_scrollbar.thumb_position_target;
eval frp.scroll_position_x((&pos) model.content.set_position_x(pos));
eval frp.scroll_position_y((&pos) model.content.set_position_y(pos));
eval frp.scroll_position_x((&pos) model.content.set_x(pos));
eval frp.scroll_position_y((&pos) model.content.set_y(pos));
scroll_position <- all(&frp.scroll_position_x, &frp.scroll_position_y);
scroll_position <- scroll_position.map(|(x,y)| Vector2::new(*x,*y));

View File

@ -83,7 +83,7 @@ impl Frp {
model.label_full.set_content <+ formatted;
eval model.label_left.width((offset)
model.label_full.set_position_x(-offset-LABEL_OFFSET));
model.label_full.set_x(-offset-LABEL_OFFSET));
}
}
}

View File

@ -91,11 +91,11 @@ impl Frp {
let track_click = relative_shape_down_position(net, scene, &model.track);
// Initialisation of components. Required for correct layout on startup.
model.label_right.set_position_y(text_size.value() / 2.0);
model.label_left.set_position_y(text_size.value() / 2.0);
model.label.set_position_y(text_size.value() / 2.0);
model.caption_left.set_position_y(text_size.value() / 2.0);
model.caption_center.set_position_y(text_size.value() / 2.0);
model.label_right.set_y(text_size.value() / 2.0);
model.label_left.set_y(text_size.value() / 2.0);
model.label.set_y(text_size.value() / 2.0);
model.caption_left.set_y(text_size.value() / 2.0);
model.caption_center.set_y(text_size.value() / 2.0);
let bg_color = style.get_color(theme::component::slider::background);
model.set_background_color(bg_color.value());
@ -106,9 +106,9 @@ impl Frp {
init_shadow_padding <- source::<()>();
shadow_padding <- all_with(&shadow.size,&init_shadow_padding,|&v,_| Vector2(v,v));
eval text_size ((size) {
model.label.set_position_y(size / 2.0);
model.label_right.set_position_y(size / 2.0);
model.label_left.set_position_y(size / 2.0);
model.label.set_y(size / 2.0);
model.label_right.set_y(size / 2.0);
model.label_left.set_y(size / 2.0);
});
eval bg_color ((color) model.set_background_color(*color) );
@ -116,7 +116,7 @@ impl Frp {
update_caption_position <- all(&size,&text_size);
eval update_caption_position((args) model.update_caption_position(args));
eval model.caption_center.frp.width((width)
model.caption_center.set_position_x(-width/2.0)
model.caption_center.set_x(-width/2.0)
);
// Size updates

View File

@ -152,12 +152,12 @@ impl Model {
let overflow_icon_size = size.y;
let label_offset = size.x / 2.0 - overflow_icon_size + left_padding;
self.label_left.set_position_x(-label_offset);
self.label_right.set_position_x(label_offset - self.label_right.width.value());
self.label_left.set_x(-label_offset);
self.label_right.set_x(label_offset - self.label_right.width.value());
let overflow_icon_offset = size.x / 2.0 - overflow_icon_size / 2.0;
self.left_overflow.set_position_x(-overflow_icon_offset);
self.right_overflow.set_position_x(overflow_icon_offset);
self.left_overflow.set_x(-overflow_icon_offset);
self.right_overflow.set_x(overflow_icon_offset);
let track_handle_size = Vector2::new(size.y / 2.0, size.y);
self.track_handle_left.size.set(track_handle_size);
@ -171,9 +171,9 @@ impl Model {
let left_padding = LABEL_OFFSET;
let overflow_icon_size = size.y / 2.0;
let caption_offset = size.x / 2.0 - overflow_icon_size - left_padding;
self.caption_left.set_position_x(-caption_offset);
self.caption_left.set_position_y(text_size / 2.0);
self.caption_center.set_position_y(text_size / 2.0);
self.caption_left.set_x(-caption_offset);
self.caption_left.set_y(text_size / 2.0);
self.caption_center.set_y(text_size / 2.0);
}
/// Set whether to allow interactions with the edges of the track shape. If this is set to
@ -208,8 +208,8 @@ impl Model {
self.track.left.set(value.start);
self.track.right.set(value.end);
self.track_handle_left.set_position_x(value.start * size.x - size.x / 2.0);
self.track_handle_right.set_position_x(value.end * size.x - size.x / 2.0);
self.track_handle_left.set_x(value.start * size.x - size.x / 2.0);
self.track_handle_right.set_x(value.end * size.x - size.x / 2.0);
}
/// Set the label in the center of the background to show the given numeric value.

View File

@ -126,7 +126,7 @@ impl Model {
self.display_object.add_child(&line);
line.set_content(process.to_string());
line.set_size(Vector2::new(LINE_WIDTH, INFINITE));
line.set_position_y(ROW_HEIGHT * ix as f32);
line.set_y(ROW_HEIGHT * ix as f32);
line.set_rotation_z(90.0_f32.to_radians());
line
})
@ -156,8 +156,8 @@ impl Model {
let start = message.recipient.id.min(message.sender.id) as u32;
line.set_size(Vector2::new(LINE_WIDTH, height_px));
line.set_position_x(message.time as f32);
line.set_position_y(ROW_HEIGHT * start as f32 + height_px / 2.0);
line.set_x(message.time as f32);
line.set_y(ROW_HEIGHT * start as f32 + height_px / 2.0);
line
})
.collect();
@ -195,7 +195,7 @@ impl Model {
.borrow()
.deref()
.iter()
.for_each(|line| line.mod_position_x(|x| x + delta))
.for_each(|line| line.mod_x(|x| x + delta))
}
}

View File

@ -320,16 +320,16 @@ impl Slider {
&model.value_text_dot.width,
);
value_text_left_pos_x <- value_text_left_pos_x.map(|(left, dot)| -*left - *dot / 2.0);
eval value_text_left_pos_x((x) model.value_text_left.set_position_x(*x));
eval model.value_text_left.height((h) model.value_text_left.set_position_y(*h / 2.0));
eval model.value_text_dot.width((w) model.value_text_dot.set_position_x(-*w / 2.0));
eval model.value_text_dot.height((h) model.value_text_dot.set_position_y(*h / 2.0));
eval model.value_text_dot.width((w) model.value_text_right.set_position_x(*w / 2.0));
eval model.value_text_right.height((h) model.value_text_right.set_position_y(*h / 2.0));
eval value_text_left_pos_x((x) model.value_text_left.set_x(*x));
eval model.value_text_left.height((h) model.value_text_left.set_y(*h / 2.0));
eval model.value_text_dot.width((w) model.value_text_dot.set_x(-*w / 2.0));
eval model.value_text_dot.height((h) model.value_text_dot.set_y(*h / 2.0));
eval model.value_text_dot.width((w) model.value_text_right.set_x(*w / 2.0));
eval model.value_text_right.height((h) model.value_text_right.set_y(*h / 2.0));
model.label.set_content <+ input.set_label;
eval input.set_label_hidden((v) model.set_label_hidden(*v));
eval model.label.height((h) model.label.set_position_y(*h / 2.0));
eval model.label.height((h) model.label.set_y(*h / 2.0));
label_pos_x <- all4(
&input.set_width,
&input.set_height,
@ -341,7 +341,7 @@ impl Slider {
LabelPosition::Outside => -comp_width / 2.0 - comp_height / 2.0 - lab_width,
}
);
eval label_pos_x((x) model.label.set_position_x(*x));
eval label_pos_x((x) model.label.set_x(*x));
};
}

View File

@ -270,7 +270,7 @@ impl View {
baseline_anim.target <+ frp.set_baseline;
baseline_anim.skip <+ frp.skip_baseline_animation;
eval baseline_anim.value ((y) display_object.set_position_y(*y));
eval baseline_anim.value ((y) display_object.set_y(*y));
new_baseline <- baseline_anim.value.on_change();
frp.private.output.baseline <+ new_baseline;
@ -307,7 +307,7 @@ impl View {
let truncation = TruncationData::new(size, ellipsis);
let x = self.glyphs.last().map(|g| g.position().x + g.x_advance.get()).unwrap_or(0.0);
let x = x + truncation.x_after_last_glyph();
truncation.ellipsis.set_position_xy(Vector2(x, truncation.y()));
truncation.ellipsis.set_xy(Vector2(x, truncation.y()));
truncation.ellipsis.scale.set(truncation.scale);
truncation.ellipsis.size.set(truncation.dim());
let was_truncated = self.truncation.borrow().is_some();

View File

@ -182,7 +182,7 @@ impl Selection {
_eval <- all_with(&ascender.value, &descender.value,
f!([model](ascender,descender) {
let height = ascender - descender;
model.view.set_position_y(height / 2.0 + descender);
model.view.set_y(height / 2.0 + descender);
model.view.size.modify(|t| Vector2(t.x, CURSOR_PADDING * 2.0 + height));
})
);
@ -217,10 +217,10 @@ impl Selection {
let width = max(CURSOR_WIDTH, abs_width - CURSORS_SPACING);
let view_width = CURSOR_PADDING * 2.0 + width;
let view_x = (abs_width/2.0) * side;
model.display_object.set_position_xy(*p);
model.right_side.set_position_x(abs_width);
model.display_object.set_xy(*p);
model.right_side.set_x(abs_width);
model.view.size.modify(|t| Vector2(view_width,t.y));
model.view.set_position_x(view_x);
model.view.set_x(view_x);
})
);
eval frp.set_color((color) model.view.color_rgb.set(color.into()));

View File

@ -807,7 +807,7 @@ impl TextModel {
let camera = self.layer.get().camera();
let origin_world_space = Vector4(0.0, 0.0, 0.0, 1.0);
let origin_clip_space = camera.view_projection_matrix() * origin_world_space;
let inv_object_matrix = self.transform_matrix().try_inverse().unwrap();
let inv_object_matrix = self.transformation_matrix().try_inverse().unwrap();
let shape = self.app.display.default_scene.frp.shape.value();
let clip_space_z = origin_clip_space.z;
@ -1369,8 +1369,8 @@ impl TextModel {
glyph.set_properties(shaped_glyph_set.non_variable_variations);
glyph.set_glyph_id(shaped_glyph.id());
glyph.x_advance.set(x_advance);
glyph.view.set_position_xy(glyph_render_offset * magic_scale);
glyph.set_position_xy(Vector2(glyph_offset_x, 0.0));
glyph.view.set_xy(glyph_render_offset * magic_scale);
glyph.set_xy(Vector2(glyph_offset_x, 0.0));
glyph_offset_x += x_advance;
divs.push(glyph_offset_x);
@ -1469,7 +1469,7 @@ impl TextModel {
if let Some(cursor) = &last_cursor {
cursor.right_side().add_child(glyph);
glyph.attached_to_cursor.set(true);
glyph.mod_position_x(|p| p - last_cursor_target_x);
glyph.mod_x(|p| p - last_cursor_target_x);
attached_glyphs.push(glyph.downgrade());
}
column += Column(1);
@ -1491,7 +1491,7 @@ impl TextModel {
if let Some(glyph) = glyph.upgrade() {
self.lines.borrow_mut()[line].add_child(&glyph);
let pos_x = selection.position_target.value().x;
glyph.mod_position_xy(|pos| Vector2(pos.x + pos_x, 0.0));
glyph.mod_xy(|pos| Vector2(pos.x + pos_x, 0.0));
glyph.attached_to_cursor.set(false);
}
}

View File

@ -75,7 +75,7 @@ impl Model {
};
let base_positions = position.xy();
self.tooltip.set_position_xy(base_positions + layout_offset)
self.tooltip.set_xy(base_positions + layout_offset)
}
fn set_style(&self, update: &Style) {

View File

@ -46,7 +46,7 @@ impl BoundingBox {
}
/// Return a bounding box given by the position and size. The position interpreted as the
/// top-right corner and size as the extend along the positive x and y-axis. Negative sizes
/// top-right corner and size as the extension along the positive x and y-axis. Negative sizes
/// are valid.
pub fn from_position_and_size(position: Vector2, size: Vector2) -> Self {
Self::from_corners(position, position + size)

View File

@ -4,9 +4,6 @@
//! a set of changed indexes and bulk-update the GPU-buffers every animation frame. You can think
//! of dirty flags like about a way to introduce laziness to the program evaluation mechanisms.
// === Non-Standard Linter Configuration ===
#![allow(missing_docs)]
use crate::data::function::traits::*;
use crate::prelude::*;
@ -20,75 +17,140 @@ use std::mem;
// === Operations ===
// ==================
/// Common traits for dirty flags.
pub mod traits {
use super::*;
// === Arg ===
/// Abstraction for dirty flags which accept an argument.
#[allow(missing_docs)]
pub trait HasArg {
type Arg;
}
/// The argument type-level getter.
pub type Arg<T> = <T as HasArg>::Arg;
// === Global Operations ===
/// Abstraction for dirty flags which can be checked for being dirty.
#[allow(missing_docs)]
pub trait HasCheckAll {
fn check_all(&self) -> bool;
}
/// Abstraction for dirty flags which can be unset (set to clean).
#[allow(missing_docs)]
pub trait HasUnsetAll {
fn unset_all(&mut self);
}
// === Arity-0 Operations ===
/// Abstraction for dirty flags which can perform a dirty check without requiring an argument.
#[allow(missing_docs)]
pub trait HasCheck0 {
fn check(&self) -> bool;
}
/// Abstraction for dirty flags which can be set without requiring an argument.
#[allow(missing_docs)]
pub trait HasSet0 {
fn set(&mut self);
}
/// Abstraction for dirty flags which can be unset without requiring an argument.
#[allow(missing_docs)]
pub trait HasUnset0 {
fn unset(&mut self);
}
// === Arity-1 Operations ===
/// Abstraction for dirty flags which can perform a dirty check by providing a single argument.
#[allow(missing_docs)]
pub trait HasCheck1: HasArg {
fn check(&self, arg: &Self::Arg) -> bool;
}
/// Abstraction for dirty flags which can be set by providing a single argument.
#[allow(missing_docs)]
pub trait HasSet1: HasArg {
fn set(&mut self, arg: Self::Arg);
}
/// Abstraction for dirty flags which can be unset by providing a single argument.
#[allow(missing_docs)]
pub trait HasUnset1: HasArg {
fn unset(&mut self, arg: &Self::Arg);
}
// === Shared Operations ===
// === Shared Global Operations ===
/// Abstraction for dirty flags which can be unset (set to clean) without requiring mutable
/// access to self.
#[allow(missing_docs)]
pub trait SharedHasUnsetAll {
fn unset_all(&self);
}
// === Shared Arity-0 Operations ===
/// Abstraction for dirty flags which can be set without requiring an argument and without
/// requiring mutable access to self.
#[allow(missing_docs)]
pub trait SharedHasSet0 {
fn set(&self);
}
/// Abstraction for dirty flags which can be unset without requiring an argument and without
/// requiring mutable access to self.
#[allow(missing_docs)]
pub trait SharedHasUnset0 {
fn unset(&self);
}
// === Shared Arity-1 Operations ===
/// Abstraction for dirty flags which can be set by providing a single argument without
/// requiring mutable access to self.
#[allow(missing_docs)]
pub trait SharedHasSet1: HasArg {
fn set(&self, arg: Self::Arg);
}
/// Abstraction for dirty flags which can be unset by providing a single argument without
/// requiring mutable access to self.
#[allow(missing_docs)]
pub trait SharedHasUnset1: HasArg {
fn unset(&self, arg: &Self::Arg);
}
// === Type Aliases ===
pub trait DirtyFlagOps = Debug + HasCheckAll + HasUnsetAll;
pub trait DirtyFlagOps0 = DirtyFlagOps + HasCheck0 + HasSet0;
pub trait DirtyFlagOps1 = DirtyFlagOps + HasCheck1 + HasSet1 where Arg<Self>: Debug;
/// Trait alias for bounds required by all dirty flags.
pub trait FlagOps = Debug + HasCheckAll + HasUnsetAll;
/// Trait alias for bounds required by all dirty flags which does not accept an argument.
pub trait FlagOps0 = FlagOps + HasCheck0 + HasSet0;
/// Trait alias for bounds required by all dirty flags which accept an argument.
pub trait FlagOps1 = FlagOps + HasCheck1 + HasSet1 where Arg<Self>: Debug;
}
pub use traits::*;
// =================
// === DirtyFlag ===
// =================
// ============
// === Flag ===
// ============
// === Definition ===
@ -97,7 +159,8 @@ pub use traits::*;
/// implements public API for working with dirty flags.
#[derive(Derivative)]
#[derivative(Debug(bound = "T:Debug"))]
pub struct DirtyFlag<T, OnMut> {
#[allow(missing_docs)]
pub struct Flag<T, OnMut> {
pub data: T,
#[derivative(Debug = "ignore")]
on_set: OnMut,
@ -106,12 +169,14 @@ pub struct DirtyFlag<T, OnMut> {
// === Basics ===
impl<OnMut, T: Default> DirtyFlag<T, OnMut> {
impl<OnMut, T: Default> Flag<T, OnMut> {
/// Constructor.
pub fn new(on_set: OnMut) -> Self {
let data = default();
Self { data, on_set }
}
/// Unsets the flag and returns its dirty value.
pub fn take(&mut self) -> T {
mem::take(&mut self.data)
}
@ -120,20 +185,20 @@ impl<OnMut, T: Default> DirtyFlag<T, OnMut> {
// === Arguments ===
impl<T: HasArg, OnMut> HasArg for DirtyFlag<T, OnMut> {
impl<T: HasArg, OnMut> HasArg for Flag<T, OnMut> {
type Arg = Arg<T>;
}
// === Global Operations ===
impl<T: HasCheckAll, OnMut> HasCheckAll for DirtyFlag<T, OnMut> {
impl<T: HasCheckAll, OnMut> HasCheckAll for Flag<T, OnMut> {
fn check_all(&self) -> bool {
self.data.check_all()
}
}
impl<T: HasUnsetAll, OnMut> HasUnsetAll for DirtyFlag<T, OnMut> {
impl<T: HasUnsetAll, OnMut> HasUnsetAll for Flag<T, OnMut> {
fn unset_all(&mut self) {
self.data.unset_all()
}
@ -142,13 +207,13 @@ impl<T: HasUnsetAll, OnMut> HasUnsetAll for DirtyFlag<T, OnMut> {
// === Check ===
impl<T: DirtyFlagOps0, OnMut> HasCheck0 for DirtyFlag<T, OnMut> {
impl<T: FlagOps0, OnMut> HasCheck0 for Flag<T, OnMut> {
fn check(&self) -> bool {
self.data.check()
}
}
impl<T: DirtyFlagOps1, OnMut> HasCheck1 for DirtyFlag<T, OnMut> {
impl<T: FlagOps1, OnMut> HasCheck1 for Flag<T, OnMut> {
fn check(&self, arg: &Self::Arg) -> bool {
self.data.check(arg)
}
@ -157,7 +222,7 @@ impl<T: DirtyFlagOps1, OnMut> HasCheck1 for DirtyFlag<T, OnMut> {
// === Set ===
impl<T: DirtyFlagOps0, OnMut: FnMut0> HasSet0 for DirtyFlag<T, OnMut> {
impl<T: FlagOps0, OnMut: FnMut0> HasSet0 for Flag<T, OnMut> {
fn set(&mut self) {
let is_set = self.data.check_all();
if !is_set {
@ -169,7 +234,7 @@ impl<T: DirtyFlagOps0, OnMut: FnMut0> HasSet0 for DirtyFlag<T, OnMut> {
}
}
impl<T: DirtyFlagOps1, OnMut: FnMut0> HasSet1 for DirtyFlag<T, OnMut> {
impl<T: FlagOps1, OnMut: FnMut0> HasSet1 for Flag<T, OnMut> {
fn set(&mut self, arg: Self::Arg) {
let first_set = !self.check_all();
let is_set = self.data.check(&arg);
@ -187,14 +252,14 @@ impl<T: DirtyFlagOps1, OnMut: FnMut0> HasSet1 for DirtyFlag<T, OnMut> {
// === Unset ===
impl<T: HasUnset0, OnMut> HasUnset0 for DirtyFlag<T, OnMut> {
impl<T: HasUnset0, OnMut> HasUnset0 for Flag<T, OnMut> {
fn unset(&mut self) {
trace!("Unsetting.");
self.data.unset()
}
}
impl<T: HasUnset1, OnMut> HasUnset1 for DirtyFlag<T, OnMut>
impl<T: HasUnset1, OnMut> HasUnset1 for Flag<T, OnMut>
where Arg<T>: Display
{
fn unset(&mut self, arg: &Self::Arg) {
@ -205,181 +270,307 @@ where Arg<T>: Display
// =======================
// === SharedDirtyFlag ===
// =======================
// ==================
// === RefCellFlag ===
// ==================
// === Definition ===
/// A version of `DirtyFlag` which uses internal mutability pattern. It is meant to expose the same
/// API but without requiring `self` reference to be mutable.
#[derive(Derivative)]
/// A version of `Flag` which uses internal mutability pattern. It is meant to expose the same
/// API but without requiring `self` reference to be mutable. This version does not allow for
/// cloning the flag. If you want to clone it you either need to put it in something like [`Rc`] or
/// use the [`SharedFlag`] instead.
#[derive(Derivative, From)]
#[derivative(Debug(bound = "T:Debug"))]
#[derivative(Clone(bound = ""))]
pub struct SharedDirtyFlag<T, OnMut> {
rc: Rc<RefCell<DirtyFlag<T, OnMut>>>,
#[repr(transparent)]
pub struct RefCellFlag<T, OnMut> {
data: RefCell<Flag<T, OnMut>>,
}
// === API ===
impl<T: Default, OnMut> SharedDirtyFlag<T, OnMut> {
impl<T: Default, OnMut> RefCellFlag<T, OnMut> {
/// Constructor.
pub fn new(on_set: OnMut) -> Self {
Self { rc: Rc::new(RefCell::new(DirtyFlag::new(on_set))) }
Self { data: RefCell::new(Flag::new(on_set)) }
}
/// Unsets the flag and returns its dirty value.
pub fn take(&self) -> T {
self.rc.borrow_mut().take()
self.data.borrow_mut().take()
}
}
impl<T, OnMut> SharedDirtyFlag<T, OnMut> {
pub fn clone_ref(&self) -> Self {
self.clone()
}
}
impl<T, OnMut> SharedDirtyFlag<T, OnMut> {
impl<T, OnMut> RefCellFlag<T, OnMut> {
/// Replace the callback of the flag.
pub fn set_callback(&self, on_set: OnMut) {
self.rc.borrow_mut().on_set = on_set;
}
}
impl<T, OnMut> From<Rc<RefCell<DirtyFlag<T, OnMut>>>> for SharedDirtyFlag<T, OnMut> {
fn from(rc: Rc<RefCell<DirtyFlag<T, OnMut>>>) -> Self {
Self { rc }
self.data.borrow_mut().on_set = on_set;
}
}
// === Arg ===
impl<T: HasArg, OnMut> HasArg for SharedDirtyFlag<T, OnMut> {
impl<T: HasArg, OnMut> HasArg for RefCellFlag<T, OnMut> {
type Arg = Arg<T>;
}
// === Global Operations ===
impl<T: HasUnsetAll, OnMut> SharedHasUnsetAll for SharedDirtyFlag<T, OnMut> {
impl<T: HasUnsetAll, OnMut> SharedHasUnsetAll for RefCellFlag<T, OnMut> {
fn unset_all(&self) {
self.rc.borrow_mut().unset_all()
self.data.borrow_mut().unset_all()
}
}
impl<T: HasCheckAll, OnMut> HasCheckAll for SharedDirtyFlag<T, OnMut> {
impl<T: HasCheckAll, OnMut> HasCheckAll for RefCellFlag<T, OnMut> {
fn check_all(&self) -> bool {
self.rc.borrow().check_all()
self.data.borrow().check_all()
}
}
// === Check ===
impl<T: DirtyFlagOps0, OnMut> HasCheck0 for SharedDirtyFlag<T, OnMut> {
impl<T: FlagOps0, OnMut> HasCheck0 for RefCellFlag<T, OnMut> {
fn check(&self) -> bool {
self.rc.borrow().check()
self.data.borrow().check()
}
}
impl<T: DirtyFlagOps1, OnMut> HasCheck1 for SharedDirtyFlag<T, OnMut> {
impl<T: FlagOps1, OnMut> HasCheck1 for RefCellFlag<T, OnMut> {
fn check(&self, arg: &Arg<T>) -> bool {
self.rc.borrow().check(arg)
self.data.borrow().check(arg)
}
}
// === Set ===
impl<T: DirtyFlagOps0, OnMut: FnMut0> SharedHasSet0 for SharedDirtyFlag<T, OnMut> {
impl<T: FlagOps0, OnMut: FnMut0> SharedHasSet0 for RefCellFlag<T, OnMut> {
fn set(&self) {
self.rc.borrow_mut().set()
self.data.borrow_mut().set()
}
}
impl<T: DirtyFlagOps1, OnMut: FnMut0> SharedHasSet1 for SharedDirtyFlag<T, OnMut> {
impl<T: FlagOps1, OnMut: FnMut0> SharedHasSet1 for RefCellFlag<T, OnMut> {
fn set(&self, arg: Arg<T>) {
self.rc.borrow_mut().set(arg)
self.data.borrow_mut().set(arg)
}
}
// === Unset ===
impl<T: HasUnset0, OnMut> SharedHasUnset0 for SharedDirtyFlag<T, OnMut> {
impl<T: HasUnset0, OnMut> SharedHasUnset0 for RefCellFlag<T, OnMut> {
fn unset(&self) {
self.rc.borrow_mut().unset()
self.data.borrow_mut().unset()
}
}
impl<T: HasUnset1, OnMut> SharedHasUnset1 for SharedDirtyFlag<T, OnMut>
impl<T: HasUnset1, OnMut> SharedHasUnset1 for RefCellFlag<T, OnMut>
where Arg<T>: Display
{
fn unset(&self, arg: &Self::Arg) {
self.rc.borrow_mut().unset(arg)
self.data.borrow_mut().unset(arg)
}
}
// === Weak References ===
// ==================
// === SharedFlag ===
// ==================
// === Definition ===
/// A version of `Flag` which uses internal mutability pattern. It is meant to expose the same
/// API but without requiring `self` reference to be mutable. This version implements cloning. If
/// you don't need it, or you want to store a bunch of flags enclosed in a single [`Rc`], use the
/// [`RefCellFlag`] instead.
#[derive(Derivative, CloneRef, From, Deref)]
#[derivative(Debug(bound = "T:Debug"))]
#[derivative(Clone(bound = ""))]
#[repr(transparent)]
pub struct SharedFlag<T, OnMut> {
rc: Rc<RefCellFlag<T, OnMut>>,
}
// === API ===
impl<T: Default, OnMut> SharedFlag<T, OnMut> {
/// Constructor.
pub fn new(on_set: OnMut) -> Self {
Self { rc: Rc::new(RefCellFlag::new(on_set)) }
}
}
// === Arg ===
impl<T: HasArg, OnMut> HasArg for SharedFlag<T, OnMut> {
type Arg = Arg<T>;
}
// === Global Operations ===
impl<T: HasUnsetAll, OnMut> SharedHasUnsetAll for SharedFlag<T, OnMut> {
fn unset_all(&self) {
self.rc.unset_all()
}
}
impl<T: HasCheckAll, OnMut> HasCheckAll for SharedFlag<T, OnMut> {
fn check_all(&self) -> bool {
self.rc.check_all()
}
}
// === Check ===
impl<T: FlagOps0, OnMut> HasCheck0 for SharedFlag<T, OnMut> {
fn check(&self) -> bool {
self.rc.check()
}
}
impl<T: FlagOps1, OnMut> HasCheck1 for SharedFlag<T, OnMut> {
fn check(&self, arg: &Arg<T>) -> bool {
self.rc.check(arg)
}
}
// === Set ===
impl<T: FlagOps0, OnMut: FnMut0> SharedHasSet0 for SharedFlag<T, OnMut> {
fn set(&self) {
self.rc.set()
}
}
impl<T: FlagOps1, OnMut: FnMut0> SharedHasSet1 for SharedFlag<T, OnMut> {
fn set(&self, arg: Arg<T>) {
self.rc.set(arg)
}
}
// === Unset ===
impl<T: HasUnset0, OnMut> SharedHasUnset0 for SharedFlag<T, OnMut> {
fn unset(&self) {
self.rc.unset()
}
}
impl<T: HasUnset1, OnMut> SharedHasUnset1 for SharedFlag<T, OnMut>
where Arg<T>: Display
{
fn unset(&self, arg: &Self::Arg) {
self.rc.unset(arg)
}
}
// ======================
// === WeakSharedFlag ===
// ======================
/// A weak version of [`SharedFlag`].
#[derive(Derivative)]
#[derivative(Debug(bound = "T:Debug"))]
#[derivative(Clone(bound = ""))]
pub struct WeakSharedDirtyFlag<T, OnMut> {
weak: Weak<RefCell<DirtyFlag<T, OnMut>>>,
#[repr(transparent)]
pub struct WeakSharedFlag<T, OnMut> {
weak: Weak<RefCellFlag<T, OnMut>>,
}
impl<T, OnMut> SharedDirtyFlag<T, OnMut> {
pub fn downgrade(&self) -> WeakSharedDirtyFlag<T, OnMut> {
impl<T, OnMut> SharedFlag<T, OnMut> {
/// Downgrade the flag to its weak version.
pub fn downgrade(&self) -> WeakSharedFlag<T, OnMut> {
let weak = self.rc.downgrade();
WeakSharedDirtyFlag { weak }
WeakSharedFlag { weak }
}
}
impl<T, OnMut> WeakSharedDirtyFlag<T, OnMut> {
pub fn upgrade(&self) -> Option<SharedDirtyFlag<T, OnMut>> {
self.weak.upgrade().map(|rc| SharedDirtyFlag { rc })
impl<T, OnMut> WeakSharedFlag<T, OnMut> {
/// Upgrade the flag to its strong version.
pub fn upgrade(&self) -> Option<SharedFlag<T, OnMut>> {
self.weak.upgrade().map(|rc| SharedFlag { rc })
}
}
// =============================================================================
// === Flags ===================================================================
// =============================================================================
// =================================================================================================
// === Flag Definitions ============================================================================
// =================================================================================================
macro_rules! define_flag {
($(#$meta:tt)* $name:ident $(< $($param:tt),* $(,)? >)?) => { paste! {
$(#$meta)*
pub type $name< $($($param,)*)? OnMut = ()> =
Flag<[<$name Data>] $(<$($param,)*>)?, OnMut>;
/// A version with an internal mutability pattern.
$(#$meta)*
pub type [<RefCell $name>]< $($($param,)*)? OnMut = ()> =
RefCellFlag<[<$name Data>] $(<$($param,)*>)?, OnMut>;
/// A version with an internal mutability pattern and a reference counting mechanism.
/// Can be cloned and downgraded to a weak reference.
$(#$meta)*
pub type [<Shared $name>]< $($($param,)*)? OnMut = ()> =
SharedFlag<[<$name Data>] $(<$($param,)*>)?, OnMut>;
/// A weak version of the shared flag.
$(#$meta)*
pub type [<WeakShared $name>]< $($($param,)*)? OnMut = ()> =
WeakSharedFlag<[<$name Data>] $(<$($param,)*>)?, OnMut>;
}};
}
// ============
// === Bool ===
// ============
/// The on / off dirty flag. If you need a simple dirty / clean switch, this one
/// is the right choice.
pub type Bool<OnMut = ()> = DirtyFlag<BoolData, OnMut>;
pub type SharedBool<OnMut = ()> = SharedDirtyFlag<BoolData, OnMut>;
pub type WeakSharedBool<OnMut = ()> = WeakSharedDirtyFlag<BoolData, OnMut>;
pub trait BoolCtx<OnMut> = where OnMut: FnMut0;
define_flag! {
/// The on / off dirty flag. If you need a simple dirty / clean switch, this one
/// is the right choice.
Bool
}
/// Internal representation of the [`Bool`] flag.
#[derive(Clone, Copy, Debug, Display, Default)]
pub struct BoolData {
is_dirty: bool,
}
impl HasCheckAll for BoolData {
fn check_all(&self) -> bool {
self.is_dirty
}
}
impl HasUnsetAll for BoolData {
fn unset_all(&mut self) {
self.is_dirty = false
}
}
impl HasCheck0 for BoolData {
fn check(&self) -> bool {
self.is_dirty
}
}
impl HasSet0 for BoolData {
fn set(&mut self) {
self.is_dirty = true
}
}
impl HasUnset0 for BoolData {
fn unset(&mut self) {
self.is_dirty = false
@ -392,15 +583,17 @@ impl HasUnset0 for BoolData {
// === Range ===
// =============
/// Dirty flag which keeps information about a range of dirty items. It does not track items
/// separately, nor you are allowed to keep multiple ranges in it. Just a single value range.
define_flag! {
/// Dirty flag which keeps information about a range of dirty items. It does not track items
/// separately, nor you are allowed to keep multiple ranges in it. Just a single value range.
Range<Ix>
}
pub type Range<Ix, OnMut> = DirtyFlag<RangeData<Ix>, OnMut>;
pub type SharedRange<Ix, OnMut> = SharedDirtyFlag<RangeData<Ix>, OnMut>;
pub trait RangeCtx<OnMut> = where OnMut: FnMut0;
pub trait RangeIx = PartialOrd + Copy + Debug;
/// Internal representation of the [`Range`] flag.
#[derive(Debug, Default)]
#[allow(missing_docs)]
pub struct RangeData<Ix = usize> {
pub range: Option<RangeInclusive<Ix>>,
}
@ -408,11 +601,13 @@ pub struct RangeData<Ix = usize> {
impl<Ix> HasArg for RangeData<Ix> {
type Arg = Ix;
}
impl<Ix> HasCheckAll for RangeData<Ix> {
fn check_all(&self) -> bool {
self.range.is_some()
}
}
impl<Ix> HasUnsetAll for RangeData<Ix> {
fn unset_all(&mut self) {
self.range = None
@ -464,18 +659,20 @@ impl<Ix: RangeIx> Display for RangeData<Ix> {
// === Set ===
// ===========
/// Dirty flag which keeps a set of dirty values. The `HashSet` dirty flag
/// counterpart. Please note that it uses `FxHashSet` under the hood, so there
/// are no guarantees regarding attack-proof hashing algorithm here.
define_flag! {
/// Dirty flag which keeps a set of dirty values. The `HashSet` dirty flag counterpart. Please
/// note that it uses `FxHashSet` under the hood, so there are no guarantees regarding
/// attack-proof hashing algorithm here.
Set<Ix>
}
pub type Set<Ix, OnMut = ()> = DirtyFlag<SetData<Ix>, OnMut>;
pub type SharedSet<Ix, OnMut = ()> = SharedDirtyFlag<SetData<Ix>, OnMut>;
pub trait SetCtx<OnMut> = where OnMut: FnMut0;
pub trait SetItem = Eq + Hash + Debug;
/// Internal representation of the [`Set`] flag.
#[derive(Derivative, Shrinkwrap)]
#[derivative(Debug(bound = "Item:SetItem"))]
#[derivative(Default(bound = "Item:SetItem"))]
#[allow(missing_docs)]
pub struct SetData<Item> {
pub set: FxHashSet<Item>,
}
@ -534,13 +731,17 @@ impl<'t, Item: SetItem> IntoIterator for &'t SetData<Item> {
// === Vector ===
// ==============
/// Dirty flag which keeps a vector of dirty values.
pub type Vector<Item, OnMut = ()> = DirtyFlag<VectorData<Item>, OnMut>;
pub type SharedVector<Item, OnMut = ()> = SharedDirtyFlag<VectorData<Item>, OnMut>;
define_flag! {
/// Dirty flag which keeps a vector of dirty values.
Vector<Item>
}
pub trait VectorItem = Debug + PartialEq;
/// Internal representation of the [`Vector`] flag.
#[derive(Derivative, Debug, Shrinkwrap)]
#[derivative(Default(bound = ""))]
#[allow(missing_docs)]
pub struct VectorData<Item> {
pub vec: Vec<Item>,
}
@ -548,11 +749,13 @@ pub struct VectorData<Item> {
impl<Item> HasArg for VectorData<Item> {
type Arg = Item;
}
impl<Item> HasCheckAll for VectorData<Item> {
fn check_all(&self) -> bool {
!self.vec.is_empty()
}
}
impl<Item> HasUnsetAll for VectorData<Item> {
fn unset_all(&mut self) {
self.vec.clear();
@ -599,24 +802,27 @@ impl<'t, Item> IntoIterator for &'t VectorData<Item> {
use bit_field::BitField as BF;
/// Dirty flag which keeps information about a set of enumerator values. The
/// items must be a plain enumerator implementing `Into<usize>`. The data is
/// stored as an efficient `BitField` under the hood.
define_flag! {
/// Dirty flag which keeps information about a set of enumerator values. The items must be a
/// plain enumerators implementing `Into<usize>`. The data is stored as an efficient `BitField`
/// under the hood.
Enum<Prim, T>
}
pub type Enum<Prim, T, OnMut> = DirtyFlag<EnumData<Prim, T>, OnMut>;
pub type SharedEnum<Prim, T, OnMut> = SharedDirtyFlag<EnumData<Prim, T>, OnMut>;
pub trait EnumCtx<OnMut> = where OnMut: FnMut0;
pub trait EnumBase = Default + PartialEq + Copy + BF;
pub trait EnumElem = Copy + Into<usize>;
/// Dirty flag which keeps dirty indexes in a `BitField` under the hood.
pub type BitField<Prim, OnMut> = Enum<Prim, usize, OnMut>;
/// Shared version of the [`BitField`] flag.
pub type SharedBitField<Prim, OnMut> = SharedEnum<Prim, usize, OnMut>;
/// Internal representation of the [`Enum`] flag.
#[derive(Derivative)]
#[derivative(Debug(bound = "Prim:Debug"))]
#[derivative(Default(bound = "Prim:Default"))]
#[allow(missing_docs)]
pub struct EnumData<Prim = u32, T = usize> {
pub bits: Prim,
phantom: PhantomData<T>,

View File

@ -197,7 +197,7 @@ type ProjectionDirty = dirty::SharedBool<()>;
type TransformDirty = dirty::SharedBool<()>;
impl Camera2dData {
fn new(display_object: &display::object::Instance) -> Self {
fn new() -> Self {
let screen = Screen::new();
let projection = default();
let clipping = default();
@ -205,10 +205,9 @@ impl Camera2dData {
let z_zoom_1 = 1.0;
let matrix = default();
let dirty = Dirty::new();
let display_object = display_object.clone_ref();
let display_object = display::object::Instance::new();
let zoom_update_registry = default();
let screen_update_registry = default();
display_object.set_on_updated(f_!(dirty.transform.set()));
display_object.mod_position(|p| p.z = 1.0);
dirty.projection.set();
let network = frp::Network::new("Camera2d");
@ -216,6 +215,7 @@ impl Camera2dData {
frp_position <- source();
frp_zoom <- source();
frp_screen <- source();
eval_ display_object.on_updated (dirty.transform.set());
}
let frp = Frp { network, position: frp_position, zoom: frp_zoom, screen: frp_screen };
Self {
@ -248,7 +248,7 @@ impl Camera2dData {
}
fn recompute_view_matrix(&mut self) {
let transform = self.display_object.matrix();
let transform = self.display_object.transformation_matrix();
self.matrix.view_inversed = transform;
self.matrix.view = transform.try_inverse().unwrap()
}
@ -402,8 +402,8 @@ impl Camera2d {
/// Creates new [`Camera2d`] instance. Please note that the camera will be of zero-size and in
/// order for it to work properly, you have to initialize it by using the `set_screen` method.
pub fn new() -> Self {
let display_object = display::object::Instance::new();
let data = Camera2dData::new(&display_object);
let data = Camera2dData::new();
let display_object = data.display_object.clone_ref();
let data = Rc::new(RefCell::new(data));
Self { display_object, data }
}

View File

@ -9,12 +9,12 @@ use crate::display::scene::layer::Layer;
// === Export ===
// ==============
pub mod class;
pub mod event;
pub mod transform;
pub mod instance;
pub mod transformation;
pub use class::Any;
pub use class::*;
pub use instance::Any;
pub use instance::*;
@ -64,14 +64,17 @@ impl<L: CloneRef + AsRef<Layer> + 'static> InstanceWithLayer<L> {
/// callback ensures that the `layer` will always be attached to the same layer the
/// `instance` is attached to.
pub fn new(instance: Instance, layer: L) -> Self {
instance.set_on_scene_layer_changed(f!([layer](_, source, destination) {
if let Some(src_layer) = source {
src_layer.remove_sublayer(layer.as_ref());
}
if let Some(dst_layer) = destination {
dst_layer.add_sublayer(layer.as_ref());
}
}));
let network = &instance.network;
frp::extend! { network
eval instance.on_layer_change ([layer] ((_, source, destination)) {
if let Some(src_layer) = source {
src_layer.remove_sublayer(layer.as_ref());
}
if let Some(dst_layer) = destination {
dst_layer.add_sublayer(layer.as_ref());
}
});
}
Self { instance, layer }
}
}

View File

@ -5,8 +5,8 @@
use crate::prelude::*;
use crate::display::object::class::Instance;
use crate::display::object::class::WeakInstance;
use crate::display::object::instance::Instance;
use crate::display::object::instance::WeakInstance;
@ -47,8 +47,8 @@ pub struct SomeEvent {
impl SomeEvent {
/// Constructor.
pub fn new<Host: 'static, T: 'static>(target: Option<&Instance<Host>>, payload: T) -> Self {
let event = Event::new(target.map(|t| t.downgrade()), payload);
pub fn new<T: 'static>(target: Option<WeakInstance>, payload: T) -> Self {
let event = Event::new(target, payload);
let state = event.state.clone_ref();
let captures = Rc::new(Cell::new(true));
let bubbles = Rc::new(Cell::new(true));
@ -68,7 +68,7 @@ impl SomeEvent {
impl Default for SomeEvent {
fn default() -> Self {
Self::new::<(), ()>(None, ())
Self::new::<()>(None, ())
}
}
@ -93,23 +93,23 @@ impl Default for SomeEvent {
#[derivative(Clone(bound = ""))]
#[derivative(Debug(bound = "T: Debug"))]
#[derivative(Default(bound = "T: Default"))]
pub struct Event<Host: 'static, T> {
data: Rc<EventData<Host, T>>,
pub struct Event<T> {
data: Rc<EventData<T>>,
}
/// Internal representation of [`Event`].
#[derive(Deref, Derivative)]
#[derivative(Debug(bound = "T: Debug"))]
#[derivative(Default(bound = "T: Default"))]
pub struct EventData<Host: 'static, T> {
pub struct EventData<T> {
#[deref]
payload: T,
target: Option<WeakInstance<Host>>,
target: Option<WeakInstance>,
state: Rc<Cell<State>>,
}
impl<Host, T> Event<Host, T> {
fn new(target: Option<WeakInstance<Host>>, payload: T) -> Self {
impl<T> Event<T> {
fn new(target: Option<WeakInstance>, payload: T) -> Self {
let state = default();
let data = Rc::new(EventData { payload, target, state });
Self { data }
@ -130,7 +130,7 @@ impl<Host, T> Event<Host, T> {
/// A reference to the object onto which the event was dispatched.
///
/// See: https://developer.mozilla.org/en-US/docs/Web/API/Event/target.
pub fn target(&self) -> Option<Instance<Host>> {
pub fn target(&self) -> Option<Instance> {
self.data.target.as_ref().and_then(|t| t.upgrade())
}
}

View File

@ -11,8 +11,9 @@ use crate::prelude::*;
/// Defines the order in which particular axis coordinates are processed. Used for example to define
/// the rotation order in `DisplayObject`.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, Default)]
pub enum AxisOrder {
#[default]
XYZ,
XZY,
YXZ,
@ -21,22 +22,17 @@ pub enum AxisOrder {
ZYX,
}
impl Default for AxisOrder {
fn default() -> Self {
Self::XYZ
}
}
// ======================
// === TransformOrder ===
// ======================
// ===========================
// === TransformationOrder ===
// ===========================
/// Defines the order in which transformations (scale, rotate, translate) are applied to a
/// particular object.
#[derive(Clone, Copy, Debug)]
pub enum TransformOrder {
#[derive(Clone, Copy, Debug, Default)]
pub enum TransformationOrder {
#[default]
ScaleRotateTranslate,
ScaleTranslateRotate,
RotateScaleTranslate,
@ -45,32 +41,26 @@ pub enum TransformOrder {
TranslateScaleRotate,
}
impl Default for TransformOrder {
fn default() -> Self {
Self::ScaleRotateTranslate
}
}
// =================
// === Transform ===
// =================
// ======================
// === Transformation ===
// ======================
/// Structure describing transform of an object, in particular its position, scale, and rotation.
/// You can use methods like `matrix` to get a combined transformation matrix. Bear in mind that
/// the matrix will always be recomputed from scratch. This structure does not contain any caching
/// mechanisms.
#[derive(Clone, Copy, Debug)]
pub struct Transform {
pub struct Transformation {
pub position: Vector3<f32>,
pub scale: Vector3<f32>,
pub rotation: Vector3<f32>,
pub transform_order: TransformOrder,
pub transform_order: TransformationOrder,
pub rotation_order: AxisOrder,
}
impl Default for Transform {
impl Default for Transformation {
fn default() -> Self {
let position = Vector3::new(0.0, 0.0, 0.0);
let scale = Vector3::new(1.0, 1.0, 1.0);
@ -81,7 +71,7 @@ impl Default for Transform {
}
}
impl Transform {
impl Transformation {
/// Creates a new transformation object.
pub fn new() -> Self {
default()
@ -93,32 +83,32 @@ impl Transform {
let mut matrix = Matrix4::identity();
let matrix_ref = &mut matrix;
match self.transform_order {
TransformOrder::ScaleRotateTranslate => {
TransformationOrder::ScaleRotateTranslate => {
self.append_scale(matrix_ref);
self.append_rotation(matrix_ref);
self.append_translation(matrix_ref);
}
TransformOrder::ScaleTranslateRotate => {
TransformationOrder::ScaleTranslateRotate => {
self.append_scale(matrix_ref);
self.append_translation(matrix_ref);
self.append_rotation(matrix_ref);
}
TransformOrder::RotateScaleTranslate => {
TransformationOrder::RotateScaleTranslate => {
self.append_rotation(matrix_ref);
self.append_scale(matrix_ref);
self.append_translation(matrix_ref);
}
TransformOrder::RotateTranslateScale => {
TransformationOrder::RotateTranslateScale => {
self.append_rotation(matrix_ref);
self.append_translation(matrix_ref);
self.append_scale(matrix_ref);
}
TransformOrder::TranslateRotateScale => {
TransformationOrder::TranslateRotateScale => {
self.append_translation(matrix_ref);
self.append_rotation(matrix_ref);
self.append_scale(matrix_ref);
}
TransformOrder::TranslateScaleRotate => {
TransformationOrder::TranslateScaleRotate => {
self.append_translation(matrix_ref);
self.append_scale(matrix_ref);
self.append_rotation(matrix_ref);
@ -158,24 +148,24 @@ impl Transform {
// =======================
// === CachedTransform ===
// =======================
// ============================
// === CachedTransformation ===
// ============================
/// The same as `Transform` but with caching. It contains cached transformation matrix and dirty
/// flags which are set after fields are modified. You can use the `update` function to recompute
/// the matrix.
/// The same as `Transformation` but with caching. It contains cached transformation matrix and
/// dirty flags which are set after fields are modified. You can use the `update` function to
/// recompute the matrix.
#[derive(Clone, Debug)]
#[allow(missing_copy_implementations)]
pub struct CachedTransform {
transform: Transform,
pub struct CachedTransformation {
transform: Transformation,
transform_matrix: Matrix4<f32>,
origin: Matrix4<f32>,
pub matrix: Matrix4<f32>,
pub dirty: bool,
}
impl Default for CachedTransform {
impl Default for CachedTransformation {
fn default() -> Self {
let transform = default();
let transform_matrix = Matrix4::identity();
@ -186,16 +176,16 @@ impl Default for CachedTransform {
}
}
impl CachedTransform {
impl CachedTransformation {
/// Constructor.
pub fn new() -> Self {
default()
}
/// Update the transformation matrix and return information if the data was really updated.
/// Update the transformation matrix if it was out of date. Returns [`true`] if the update was
/// needed.
pub fn update(&mut self, new_origin: Option<Matrix4<f32>>) -> bool {
let origin_changed = new_origin.is_some();
let changed = self.dirty || origin_changed;
let changed = self.dirty || new_origin.is_some();
if changed {
if self.dirty {
self.transform_matrix = self.transform.matrix();
@ -211,7 +201,7 @@ impl CachedTransform {
// === Getters ===
impl CachedTransform {
impl CachedTransformation {
pub fn position(&self) -> Vector3<f32> {
self.transform.position
}
@ -236,7 +226,7 @@ impl CachedTransform {
// === Setters ===
impl CachedTransform {
impl CachedTransformation {
pub fn position_mut(&mut self) -> &mut Vector3<f32> {
self.dirty = true;
&mut self.transform.position

View File

@ -15,6 +15,7 @@ use crate::display;
use crate::display::camera::Camera2d;
use crate::display::render;
use crate::display::scene::dom::DomScene;
use crate::display::shape::primitive::glsl;
use crate::display::style;
use crate::display::style::data::DataMatch;
use crate::display::symbol::registry::SymbolRegistry;
@ -122,6 +123,7 @@ pub struct Mouse {
pub mouse_manager: MouseManager,
pub last_position: Rc<Cell<Vector2<i32>>>,
pub position: Uniform<Vector2<i32>>,
pub click_count: Uniform<i32>,
pub hover_rgba: Uniform<Vector4<u32>>,
pub target: Rc<Cell<PointerTargetId>>,
pub handles: Rc<[callback::Handle; 4]>,
@ -135,47 +137,71 @@ impl Mouse {
root: &web::dom::WithKnownShape<web::HtmlDivElement>,
variables: &UniformScope,
current_js_event: &CurrentJsEvent,
display_mode: &Rc<Cell<glsl::codes::DisplayModes>>,
) -> Self {
let scene_frp = scene_frp.clone_ref();
let target = PointerTargetId::default();
let last_position = Rc::new(Cell::new(Vector2::new(0, 0)));
let position = variables.add_or_panic("mouse_position", Vector2(0, 0));
let click_count = variables.add_or_panic("mouse_click_count", 0);
let hover_rgba = variables.add_or_panic("mouse_hover_ids", Vector4(0, 0, 0, 0));
let target = Rc::new(Cell::new(target));
let mouse_manager = MouseManager::new_separated(&root.clone_ref().into(), &web::window);
let frp = frp::io::Mouse::new();
let on_move = mouse_manager.on_move.add(current_js_event.make_event_handler(
f!([frp,scene_frp,position,last_position] (event:&mouse::OnMove) {
let shape = scene_frp.shape.value();
let pixel_ratio = shape.pixel_ratio;
let screen_x = event.client_x();
let screen_y = event.client_y();
f!([frp, scene_frp, position, last_position, display_mode] (event: &mouse::OnMove) {
let shape = scene_frp.shape.value();
let pixel_ratio = shape.pixel_ratio;
let screen_x = event.client_x();
let screen_y = event.client_y();
let new_pos = Vector2::new(screen_x,screen_y);
let pos_changed = new_pos != last_position.get();
if pos_changed {
last_position.set(new_pos);
let new_canvas_position = new_pos.map(|v| (v as f32 * pixel_ratio) as i32);
position.set(new_canvas_position);
let position = Vector2(new_pos.x as f32,new_pos.y as f32) - shape.center();
let new_pos = Vector2::new(screen_x,screen_y);
let pos_changed = new_pos != last_position.get();
if pos_changed {
last_position.set(new_pos);
let new_canvas_position = new_pos.map(|v| (v as f32 * pixel_ratio) as i32);
position.set(new_canvas_position);
let position = Vector2(new_pos.x as f32,new_pos.y as f32) - shape.center();
if display_mode.get().allow_mouse_events() {
frp.position.emit(position);
}
}
),
}),
));
let on_down = mouse_manager.on_down.add(current_js_event.make_event_handler(
f!([frp, click_count, display_mode] (event:&mouse::OnDown) {
click_count.modify(|v| *v += 1);
if display_mode.get().allow_mouse_events() {
frp.down.emit(event.button());
}
}),
));
let on_up = mouse_manager.on_up.add(current_js_event.make_event_handler(
f!([frp, display_mode] (event:&mouse::OnUp) {
if display_mode.get().allow_mouse_events() {
frp.up.emit(event.button())
}
}),
));
let on_wheel = mouse_manager.on_wheel.add(current_js_event.make_event_handler(
f_!([frp, display_mode] {
if display_mode.get().allow_mouse_events() {
frp.wheel.emit(())
}
}),
));
let on_down = mouse_manager.on_down.add(
current_js_event
.make_event_handler(f!((event:&mouse::OnDown) frp.down.emit(event.button()))),
);
let on_up = mouse_manager.on_up.add(
current_js_event
.make_event_handler(f!((event:&mouse::OnUp) frp.up.emit(event.button()))),
);
let on_wheel = mouse_manager
.on_wheel
.add(current_js_event.make_event_handler(f_!(frp.wheel.emit(()))));
let handles = Rc::new([on_move, on_down, on_up, on_wheel]);
Self { mouse_manager, last_position, position, hover_rgba, target, handles, frp, scene_frp }
Self {
mouse_manager,
last_position,
position,
click_count,
hover_rgba,
target,
handles,
frp,
scene_frp,
}
}
/// Re-emits FRP mouse changed position event with the last mouse position value.
@ -688,7 +714,7 @@ pub struct UpdateStatus {
#[derive(Clone, CloneRef, Debug)]
pub struct SceneData {
pub display_object: display::object::Instance,
pub display_object: display::object::Root,
pub dom: Dom,
pub context: Rc<RefCell<Option<Context>>>,
pub context_lost_handler: Rc<RefCell<Option<ContextLostHandler>>>,
@ -710,17 +736,22 @@ pub struct SceneData {
pub frp: Frp,
pub pointer_position_changed: Rc<Cell<bool>>,
pub shader_compiler: shader::compiler::Controller,
display_mode: Rc<Cell<glsl::codes::DisplayModes>>,
extensions: Extensions,
disable_context_menu: Rc<EventListenerHandle>,
}
impl SceneData {
/// Create new instance with the provided on-dirty callback.
pub fn new<OnMut: Fn() + Clone + 'static>(stats: &Stats, on_mut: OnMut) -> Self {
pub fn new<OnMut: Fn() + Clone + 'static>(
stats: &Stats,
on_mut: OnMut,
display_mode: &Rc<Cell<glsl::codes::DisplayModes>>,
) -> Self {
debug!("Initializing.");
let display_mode = display_mode.clone_ref();
let dom = Dom::new();
let display_object = display::object::Instance::new();
display_object.force_set_visibility(true);
let display_object = display::object::Root::new();
let variables = UniformScope::new();
let dirty = Dirty::new(on_mut);
let symbols_dirty = &dirty.symbols;
@ -734,7 +765,7 @@ impl SceneData {
let style_sheet = style::Sheet::new();
let current_js_event = CurrentJsEvent::new();
let frp = Frp::new(&dom.root.shape);
let mouse = Mouse::new(&frp, &dom.root, &variables, &current_js_event);
let mouse = Mouse::new(&frp, &dom.root, &variables, &current_js_event, &display_mode);
let disable_context_menu = Rc::new(web::ignore_context_menu(&dom.root));
let keyboard = Keyboard::new(&current_js_event);
let network = &frp.network;
@ -759,6 +790,7 @@ impl SceneData {
let shader_compiler = default();
Self {
display_object,
display_mode,
dom,
context,
context_lost_handler,
@ -927,10 +959,10 @@ impl SceneData {
screen_pos: Vector2,
) -> Vector2 {
let origin_world_space = Vector4(0.0, 0.0, 0.0, 1.0);
let layer = object.display_layer().and_then(|t| t.upgrade());
let layer = object.display_layer();
let camera = layer.map_or(self.camera(), |l| l.camera());
let origin_clip_space = camera.view_projection_matrix() * origin_world_space;
let inv_object_matrix = object.transform_matrix().try_inverse().unwrap();
let inv_object_matrix = object.transformation_matrix().try_inverse().unwrap();
let shape = camera.screen();
let clip_space_z = origin_clip_space.z;
@ -1017,8 +1049,12 @@ pub struct Scene {
}
impl Scene {
pub fn new<OnMut: Fn() + Clone + 'static>(stats: &Stats, on_mut: OnMut) -> Self {
let no_mut_access = SceneData::new(stats, on_mut);
pub fn new<OnMut: Fn() + Clone + 'static>(
stats: &Stats,
on_mut: OnMut,
display_mode: &Rc<Cell<glsl::codes::DisplayModes>>,
) -> Self {
let no_mut_access = SceneData::new(stats, on_mut, display_mode);
let this = Self { no_mut_access };
this
}

View File

@ -210,14 +210,7 @@ impl DomScene {
/// Creates a new instance of DomSymbol and adds it to parent.
pub fn manage(&self, object: &DomSymbol) {
let dom = object.dom();
let data = &self.data;
if object.is_visible() {
self.view_projection_dom.append_or_warn(dom);
}
object.display_object().set_on_hide(f_!(dom.remove()));
object.display_object().set_on_show(f__!([data,dom] {
data.view_projection_dom.append_or_warn(&dom)
}));
self.view_projection_dom.append_or_warn(dom);
}
/// Update the objects to match the new camera's point of view. This function should be called
@ -227,7 +220,7 @@ impl DomScene {
return;
}
let trans_cam = camera.transform_matrix().try_inverse();
let trans_cam = camera.transformation_matrix().try_inverse();
let trans_cam = trans_cam.expect("Camera's matrix is not invertible.");
let trans_cam = trans_cam.map(eps);
let trans_cam = inverse_y_translation(trans_cam);

View File

@ -154,30 +154,11 @@ use std::any::TypeId;
/// Please note that the current implementation does not allow for hierarchical masks (masks applied
/// to already masked area or masks applied to masks). If you try using masks in hierarchical way,
/// the nested masks will be skipped and a warning will be emitted to the console.
#[derive(Clone, CloneRef)]
#[derive(Clone, CloneRef, Deref)]
pub struct Layer {
model: Rc<LayerModel>,
}
impl Deref for Layer {
type Target = LayerModel;
fn deref(&self) -> &Self::Target {
&self.model
}
}
impl AsRef<Layer> for Layer {
fn as_ref(&self) -> &Layer {
self
}
}
impl Debug for Layer {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Debug::fmt(&*self.model, f)
}
}
impl Layer {
/// Constructor.
pub fn new(name: impl Into<String>) -> Self {
@ -207,7 +188,7 @@ impl Layer {
/// Remove the display object from a layer it was assigned to, if any.
pub fn remove(&self, object: impl display::Object) {
object.display_object().remove_from_scene_layer(self);
object.display_object().remove_from_display_layer(self);
}
/// Instantiate the provided [`ShapeProxy`].
@ -258,12 +239,31 @@ impl Layer {
}
}
impl AsRef<Layer> for Layer {
fn as_ref(&self) -> &Layer {
self
}
}
impl Debug for Layer {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Debug::fmt(&*self.model, f)
}
}
impl From<&Layer> for LayerId {
fn from(t: &Layer) -> Self {
t.id()
}
}
impl Eq for Layer {}
impl PartialEq for Layer {
fn eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.model, &other.model)
}
}
// =================
@ -315,6 +315,7 @@ impl PartialEq for WeakLayer {
}
// ==================
// === LayerModel ===
// ==================

View File

@ -3,21 +3,13 @@
use crate::prelude::*;
use crate::control::io::mouse;
use crate::display::shape::primitive::glsl;
use crate::display::symbol;
use enso_frp as frp;
// =================
// === Constants ===
// =================
const ID_ENCODING_OVERFLOW_ERR: u32 =
include!("../shape/primitive/glsl/error_codes/id_encoding_overflow.txt");
// =====================
// === PointerTarget ===
// =====================
@ -175,7 +167,7 @@ impl PointerTargetId {
Ok(Self::Symbol { id })
}
_ => {
let err = if alpha == ID_ENCODING_OVERFLOW_ERR {
let err = if alpha == glsl::codes::ID_ENCODING_OVERFLOW_ERROR {
DecodeError::Overflow
} else {
DecodeError::WrongAlpha(alpha)

View File

@ -6,6 +6,7 @@
// ==============
pub mod def;
pub mod glsl;
pub mod shader;
pub mod style_watch;
pub mod system;

View File

@ -206,7 +206,7 @@ define_sdf_shapes! {
}
Line (width:f32) {
return bound_sdf(abs(position.y)-width, bounding_box(0.0,width));
return bound_sdf(abs(position.y) - width/2.0, bounding_box(0.0,width));
}

View File

@ -8,6 +8,7 @@ use crate::data::color;
use crate::display::shape::primitive::def::unit::PixelDistance;
use crate::system::gpu::shader::glsl::Glsl;
use enso_types;
use nalgebra::Scalar;
@ -192,123 +193,6 @@ where T: Max + Into<Glsl>
}
}
macro_rules! dim_impl {
($trait:ident for $tp:ty {
type $dim_ty_name:ident = $dim_ty:ty;
args = [$($single_arg:ident),* $(,)?];
$(swizzling = $multi_ty:ident [$($multi_arg:ident),* $(,)?];)*
}) => {
impl<T: Scalar + Copy> $trait for $tp {
type $dim_ty_name = $dim_ty;
$(
fn $single_arg(&self) -> Self::Dim1Type {
match self {
Self::Static(t) => Var::Static(t.$single_arg.clone()),
Self::Dynamic(t) => {
let code = format!("{}.{}", t, stringify!($single_arg));
Var::Dynamic(code.into())
}
}
}
)*
$($(
fn $multi_arg(&self) -> Self::$multi_ty {
match self {
Self::Static(t) => Var::Static(t.$multi_arg()),
Self::Dynamic(t) => {
let code = format!("{}.{}", t, stringify!($multi_arg));
Var::Dynamic(code.into())
}
}
}
)*)*
}
};
}
dim_impl! ( Dim1 for Var<Vector2<T>> {
type Dim1Type = Var<T>;
args = [x];
});
dim_impl! ( Dim2 for Var<Vector2<T>> {
type Dim2Type = Var<Vector2<T>>;
args = [y];
swizzling = Dim2Type [xx, xy, yx, yy];
});
dim_impl! ( Dim1 for Var<Vector3<T>> {
type Dim1Type = Var<T>;
args = [x];
});
dim_impl! ( Dim2 for Var<Vector3<T>> {
type Dim2Type = Var<Vector2<T>>;
args = [y];
swizzling = Dim2Type [xx, xy, yx, yy];
});
dim_impl! ( Dim3 for Var<Vector3<T>> {
type Dim3Type = Var<Vector3<T>>;
args = [z];
swizzling = Dim2Type [zz, xz, zx, yz, zy];
swizzling = Dim3Type [
xxx, xxy, xxz, xyx, xyy, xyz, xzx, xzy, xzz, yxx, yxy, yxz, yyx, yyy, yyz, yzx, yzy, yzz,
zxx, zxy, zxz, zyx, zyy, zyz, zzx, zzy, zzz
];
});
dim_impl! ( Dim1 for Var<Vector4<T>> {
type Dim1Type = Var<T>;
args = [x];
});
dim_impl! ( Dim2 for Var<Vector4<T>> {
type Dim2Type = Var<Vector2<T>>;
args = [y];
swizzling = Dim2Type [xx, xy, yx, yy];
});
dim_impl! ( Dim3 for Var<Vector4<T>> {
type Dim3Type = Var<Vector3<T>>;
args = [z];
swizzling = Dim2Type [zz, xz, zx, yz, zy];
swizzling = Dim3Type [
xxx, xxy, xxz, xyx, xyy, xyz, xzx, xzy, xzz, yxx, yxy, yxz, yyx, yyy, yyz, yzx, yzy, yzz,
zxx, zxy, zxz, zyx, zyy, zyz, zzx, zzy, zzz
];
});
dim_impl! ( Dim4 for Var<Vector4<T>> {
type Dim4Type = Var<Vector4<T>>;
args = [w];
swizzling = Dim2Type [ww, xw, wx, yw, wy, zw, wz];
swizzling = Dim3Type [
xxw, xyw, xzw, yxw, yyw, yzw, zxw, zyw, zzw, xwx, xwy, xwz, ywx, ywy, ywz, zwx, zwy, zwz,
wxx, wxy, wxz, wyx, wyy, wyz, wzx, wzy, wzz
];
swizzling = Dim4Type [
xxxx, xxxy, xxxz, xxxw, xxyx, xxyy, xxyz, xxyw, xxzx, xxzy, xxzz, xxzw, xxwx, xxwy, xxwz,
xxww, xyxx, xyxy, xyxz, xyxw, xyyx, xyyy, xyyz, xyyw, xyzx, xyzy, xyzz, xyzw, xywx, xywy,
xywz, xyww, xzxx, xzxy, xzxz, xzxw, xzyx, xzyy, xzyz, xzyw, xzzx, xzzy, xzzz, xzzw, xzwx,
xzwy, xzwz, xzww, xwxx, xwxy, xwxz, xwxw, xwyx, xwyy, xwyz, xwyw, xwzx, xwzy, xwzz, xwzw,
xwwx, xwwy, xwwz, xwww, yxxx, yxxy, yxxz, yxxw, yxyx, yxyy, yxyz, yxyw, yxzx, yxzy, yxzz,
yxzw, yxwx, yxwy, yxwz, yxww, yyxx, yyxy, yyxz, yyxw, yyyx, yyyy, yyyz, yyyw, yyzx, yyzy,
yyzz, yyzw, yywx, yywy, yywz, yyww, yzxx, yzxy, yzxz, yzxw, yzyx, yzyy, yzyz, yzyw, yzzx,
yzzy, yzzz, yzzw, yzwx, yzwy, yzwz, yzww, ywxx, ywxy, ywxz, ywxw, ywyx, ywyy, ywyz, ywyw,
ywzx, ywzy, ywzz, ywzw, ywwx, ywwy, ywwz, ywww, zxxx, zxxy, zxxz, zxxw, zxyx, zxyy, zxyz,
zxyw, zxzx, zxzy, zxzz, zxzw, zxwx, zxwy, zxwz, zxww, zyxx, zyxy, zyxz, zyxw, zyyx, zyyy,
zyyz, zyyw, zyzx, zyzy, zyzz, zyzw, zywx, zywy, zywz, zyww, zzxx, zzxy, zzxz, zzxw, zzyx,
zzyy, zzyz, zzyw, zzzx, zzzy, zzzz, zzzw, zzwx, zzwy, zzwz, zzww, zwxx, zwxy, zwxz, zwxw,
zwyx, zwyy, zwyz, zwyw, zwzx, zwzy, zwzz, zwzw, zwwx, zwwy, zwwz, zwww, wxxx, wxxy, wxxz,
wxxw, wxyx, wxyy, wxyz, wxyw, wxzx, wxzy, wxzz, wxzw, wxwx, wxwy, wxwz, wxww, wyxx, wyxy,
wyxz, wyxw, wyyx, wyyy, wyyz, wyyw, wyzx, wyzy, wyzz, wyzw, wywx, wywy, wywz, wyww, wzxx,
wzxy, wzxz, wzxw, wzyx, wzyy, wzyz, wzyw, wzzx, wzzy, wzzz, wzzw, wzwx, wzwy, wzwz, wzww,
wwxx, wwxy, wwxz, wwxw, wwyx, wwyy, wwyz, wwyw, wwzx, wwzy, wwzz, wwzw, wwwx, wwwy, wwwz,
wwww
];
});
impl PixelDistance for Var<Vector2<f32>> {
type Output = Var<Vector2<Pixels>>;
fn px(&self) -> Self::Output {
@ -571,6 +455,46 @@ define_shape_data_string_operator! { Mul mul (*) }
define_shape_data_string_operator! { Div div (/) }
// ============
// === Dim* ===
// ============
macro_rules! gen_dim_impl_for_vector {
([$vec:tt] $dim:tt $( $name:ident $swizzling_dim:tt [$($dim_ix:tt)*] [$($dim_ord:tt)*] )*) => {
paste! {
impl<T: Scalar + Copy> [<Dim $dim>] for Var<$vec<T>> {
type [<Dim $dim Type>] = Var<[<Vector $dim>]<T>>;
$(
fn $name(&self) -> Self::[<Dim $swizzling_dim Type>] {
match self {
Self::Static(t) => Var::Static(t.$name()),
Self::Dynamic(t) => {
let code = format!("{}.{}", t, stringify!($name));
Var::Dynamic(code.into())
}
}
}
)*
}
}
};
}
enso_types::with_swizzling_for_dim!(1, gen_dim_impl_for_vector, Vector2);
enso_types::with_swizzling_for_dim!(2, gen_dim_impl_for_vector, Vector2);
enso_types::with_swizzling_for_dim!(1, gen_dim_impl_for_vector, Vector3);
enso_types::with_swizzling_for_dim!(2, gen_dim_impl_for_vector, Vector3);
enso_types::with_swizzling_for_dim!(3, gen_dim_impl_for_vector, Vector3);
enso_types::with_swizzling_for_dim!(1, gen_dim_impl_for_vector, Vector4);
enso_types::with_swizzling_for_dim!(2, gen_dim_impl_for_vector, Vector4);
enso_types::with_swizzling_for_dim!(3, gen_dim_impl_for_vector, Vector4);
enso_types::with_swizzling_for_dim!(4, gen_dim_impl_for_vector, Vector4);
// =========================
// === Utility Functions ===
// =========================

View File

@ -0,0 +1,8 @@
//! GLSL constants and utilities.
// ==============
// === Export ===
// ==============
pub mod codes;

View File

@ -0,0 +1,81 @@
//! GLSL codes, numbers which are used to identify errors and display modes. These are shared
//! between Rust and GLSL code.
use crate::prelude::*;
use inflector::Inflector;
// =============
// === Codes ===
// =============
/// The error code used for ID encoding errors.
pub const ID_ENCODING_OVERFLOW_ERROR: u32 = 100;
/// Enum describing possible GLSL display modes.
#[derive(Clone, Copy, Debug, num_enum::IntoPrimitive, num_enum::TryFromPrimitive)]
#[repr(u32)]
#[allow(missing_docs)]
pub enum DisplayModes {
Normal,
DebugSpriteUv,
DebugSpriteOverview,
DebugSpriteGrid,
DebugSdf,
DebugShapeAaSpan,
DebugInstanceId,
}
// This is not derived, as then [`num_enum::TryFromPrimitive`] will return the default value for
// not matched numbers.
impl Default for DisplayModes {
fn default() -> Self {
Self::Normal
}
}
impl DisplayModes {
/// The numeric representation of the code.
pub const fn value(self) -> u32 {
self as u32
}
/// Conversion from the numeric representation of the code to the code variant.
pub fn from_value(number: u32) -> Option<Self> {
Self::try_from(number).ok()
}
/// Name of the code.
pub fn name(self) -> String {
format!("display_mode_{:?}", self).to_snake_case()
}
/// Check if the display mode allows mouse interactions in GUI. The display modes that do not
/// allow it use mouse for debug purposes (like changing object hue on click).
pub fn allow_mouse_events(self) -> bool {
match self {
DisplayModes::Normal => true,
DisplayModes::DebugSpriteUv => true,
DisplayModes::DebugSpriteOverview => false,
DisplayModes::DebugSpriteGrid => false,
DisplayModes::DebugSdf => true,
DisplayModes::DebugShapeAaSpan => true,
DisplayModes::DebugInstanceId => false,
}
}
/// All registered codes.
pub fn all() -> Vec<Self> {
let mut codes = vec![];
for i in 0.. {
if let Some(code) = Self::from_value(i) {
codes.push(code);
} else {
break;
}
}
codes
}
}

View File

@ -1,5 +1,5 @@
// =================================================================================================
// === Colorspaces Definition ======================================================================
// === Color spaces definition =====================================================================
// =================================================================================================
/// Helper for colors definition.
@ -12,100 +12,100 @@
/// All component values are in range 0.0..1.0.
#define DEF_COLOR(type_name3,type_name4,name3,name4,t1,t2,t3) \
\
/* ============================= */ \
/* === Non Transparent Color === */ \
/* ============================= */ \
\
/* === Definition === */ \
\
struct type_name3 { \
vec3 raw; \
}; \
\
\
/* === Getters === */ \
\
float t1 (type_name3 color) { return color.raw.x; } \
float t2 (type_name3 color) { return color.raw.y; } \
float t3 (type_name3 color) { return color.raw.z; } \
\
\
/* === Constructors === */ \
\
type_name3 name3(type_name3 identity) { \
return identity; \
} \
\
type_name3 name3(vec3 raw) { \
return type_name3(raw); \
} \
\
type_name3 name3(float t1, float t2, float t3) { \
return name3(vec3(t1,t2,t3)); \
} \
\
\
\
/* ========================= */ \
/* === Transparent Color === */ \
/* ========================= */ \
\
/* === Definition === */ \
\
struct type_name4 { \
vec4 raw; \
}; \
\
\
/* === Getters === */ \
\
float t1 (type_name4 name4) { return name4.raw.x; } \
float t2 (type_name4 name4) { return name4.raw.y; } \
float t3 (type_name4 name4) { return name4.raw.z; } \
float a (type_name4 name4) { return name4.raw.a; } \
\
\
/* === Constructors === */ \
\
type_name4 name4 (type_name4 identity) { \
return identity; \
} \
\
type_name4 name4 (vec4 raw) { \
return type_name4(raw); \
} \
\
type_name4 name4 (vec3 raw) { \
return name4(vec4(raw,1.0)); \
} \
\
type_name4 name4 (vec3 raw, float a) { \
return name4(vec4(raw,a)); \
} \
\
type_name4 name4 (type_name3 name3) { \
return name4(name3.raw); \
} \
\
type_name4 name4 (type_name3 name3, float a) { \
return name4(name3.raw,a); \
} \
\
type_name4 name4 (float t1, float t2, float t3) { \
return name4(vec3(t1,t2,t3)); \
} \
\
type_name4 name4 (float t1, float t2, float t3, float a) { \
return name4(vec4(t1,t2,t3,a)); \
} \
\
\
/* === Conversions === */ \
\
type_name3 name3 (type_name4 a) { \
return name3(a.raw.xyz); \
#define DEF_COLOR(TYPE_NAME_3, TYPE_NAME_4, NAME_3, NAME_4, T_1, T_2, T_3) \
\
/* ============================= */ \
/* === Non Transparent Color === */ \
/* ============================= */ \
\
/* === Definition === */ \
\
struct TYPE_NAME_3 { \
vec3 raw; \
}; \
\
\
/* === Getters === */ \
\
float T_1 (TYPE_NAME_3 color) { return color.raw.x; } \
float T_2 (TYPE_NAME_3 color) { return color.raw.y; } \
float T_3 (TYPE_NAME_3 color) { return color.raw.z; } \
\
\
/* === Constructors === */ \
\
TYPE_NAME_3 NAME_3(TYPE_NAME_3 identity) { \
return identity; \
} \
\
TYPE_NAME_3 NAME_3(vec3 raw) { \
return TYPE_NAME_3(raw); \
} \
\
TYPE_NAME_3 NAME_3(float T_1, float T_2, float T_3) { \
return NAME_3(vec3(T_1, T_2, T_3)); \
} \
\
\
\
/* ========================= */ \
/* === Transparent Color === */ \
/* ========================= */ \
\
/* === Definition === */ \
\
struct TYPE_NAME_4 { \
vec4 raw; \
}; \
\
\
/* === Getters === */ \
\
float T_1 (TYPE_NAME_4 NAME_4) { return NAME_4.raw.x; } \
float T_2 (TYPE_NAME_4 NAME_4) { return NAME_4.raw.y; } \
float T_3 (TYPE_NAME_4 NAME_4) { return NAME_4.raw.z; } \
float a (TYPE_NAME_4 NAME_4) { return NAME_4.raw.a; } \
\
\
/* === Constructors === */ \
\
TYPE_NAME_4 NAME_4 (TYPE_NAME_4 identity) { \
return identity; \
} \
\
TYPE_NAME_4 NAME_4 (vec4 raw) { \
return TYPE_NAME_4(raw); \
} \
\
TYPE_NAME_4 NAME_4 (vec3 raw) { \
return NAME_4(vec4(raw,1.0)); \
} \
\
TYPE_NAME_4 NAME_4 (vec3 raw, float a) { \
return NAME_4(vec4(raw,a)); \
} \
\
TYPE_NAME_4 NAME_4 (TYPE_NAME_3 NAME_3) { \
return NAME_4(NAME_3.raw); \
} \
\
TYPE_NAME_4 NAME_4 (TYPE_NAME_3 NAME_3, float a) { \
return NAME_4(NAME_3.raw, a); \
} \
\
TYPE_NAME_4 NAME_4 (float T_1, float T_2, float T_3) { \
return NAME_4(vec3(T_1, T_2, T_3)); \
} \
\
TYPE_NAME_4 NAME_4 (float T_1, float T_2, float T_3, float a) { \
return NAME_4(vec4(T_1, T_2, T_3, a)); \
} \
\
\
/* === Conversions === */ \
\
TYPE_NAME_3 NAME_3 (TYPE_NAME_4 a) { \
return NAME_3(a.raw.xyz); \
}
@ -117,30 +117,34 @@ DEF_COLOR(Lch , Lcha , lch , lcha , l , c ,h)
// =================================================================================================
// === Colorpsace Conversion =======================================================================
// === Color space conversion ======================================================================
// =================================================================================================
#define DEF_TRANSITIVE_CONVERSIONS_1_WAY( \
a_type_name3,a_type_name4,a_name3,a_name4,b_type_name3,b_type_name4,b_name3,b_name4) \
\
a_type_name3 a_name3(b_type_name4 b_name4) { \
return a_name3(b_name3(b_name4)); \
} \
\
a_type_name4 a_name4(b_type_name4 b_name4) { \
return a_name4(a_name3(b_name3(b_name4)),a(b_name4)); \
} \
\
a_type_name4 a_name4(b_type_name3 b_name3) { \
return a_name4(a_name3(b_name3)); \
#define DEF_TRANSITIVE_CONVERSIONS_1_WAY( \
A_TYPE_NAME_3, A_TYPE_NAME_4, A_NAME_3, A_NAME_4, B_TYPE_NAME_3, B_TYPE_NAME_4, B_NAME_3, B_NAME_4)\
\
A_TYPE_NAME_3 A_NAME_3(B_TYPE_NAME_4 B_NAME_4) { \
return A_NAME_3(B_NAME_3(B_NAME_4)); \
} \
\
A_TYPE_NAME_4 A_NAME_4(B_TYPE_NAME_4 B_NAME_4) { \
return A_NAME_4(A_NAME_3(B_NAME_3(B_NAME_4)), a(B_NAME_4)); \
} \
\
A_TYPE_NAME_4 A_NAME_4(B_TYPE_NAME_3 B_NAME_3) { \
return A_NAME_4(A_NAME_3(B_NAME_3)); \
} \
\
A_TYPE_NAME_4 A_NAME_4(B_TYPE_NAME_3 B_NAME_3, float alpha) { \
return A_NAME_4(A_NAME_3(B_NAME_3), alpha); \
}
#define DEF_TRANSITIVE_CONVERSIONS( \
a_type_name3,a_type_name4,a_name3,a_name4,b_type_name3,b_type_name4,b_name3,b_name4) \
DEF_TRANSITIVE_CONVERSIONS_1_WAY( \
a_type_name3,a_type_name4,a_name3,a_name4,b_type_name3,b_type_name4,b_name3,b_name4) \
DEF_TRANSITIVE_CONVERSIONS_1_WAY( \
b_type_name3,b_type_name4,b_name3,b_name4,a_type_name3,a_type_name4,a_name3,a_name4)
#define DEF_TRANSITIVE_CONVERSIONS( \
A_TYPE_NAME_3, A_TYPE_NAME_4, A_NAME_3, A_NAME_4, B_TYPE_NAME_3, B_TYPE_NAME_4, B_NAME_3, B_NAME_4)\
DEF_TRANSITIVE_CONVERSIONS_1_WAY( \
A_TYPE_NAME_3, A_TYPE_NAME_4, A_NAME_3, A_NAME_4, B_TYPE_NAME_3, B_TYPE_NAME_4, B_NAME_3, B_NAME_4)\
DEF_TRANSITIVE_CONVERSIONS_1_WAY( \
B_TYPE_NAME_3, B_TYPE_NAME_4, B_NAME_3, B_NAME_4, A_TYPE_NAME_3, A_TYPE_NAME_4, A_NAME_3, A_NAME_4)
@ -178,7 +182,7 @@ Rgb rgb(Srgb srgb) {
return rgb(r,g,b);
}
DEF_TRANSITIVE_CONVERSIONS(Srgb,Srgba,srgb,srgba,Rgb,Rgba,rgb,rgba)
DEF_TRANSITIVE_CONVERSIONS(Srgb, Srgba, srgb, srgba, Rgb, Rgba, rgb, rgba)
@ -195,17 +199,17 @@ Lch lch(Srgb rgb) {
( 0.4124, 0.3576, 0.1805
, 0.2126, 0.7152, 0.0722
, 0.0193, 0.1192, 0.9505 );
c.x = xyzF(c.x/lch_rgb_weights.x);
c.y = xyzF(c.y/lch_rgb_weights.y);
c.z = xyzF(c.z/lch_rgb_weights.z);
c.x = xyzF(c.x / lch_rgb_weights.x);
c.y = xyzF(c.y / lch_rgb_weights.y);
c.z = xyzF(c.z / lch_rgb_weights.z);
vec3 lab = vec3(max(0.,116.0*c.y - 16.0), 500.0*(c.x - c.y), 200.0*(c.y - c.z));
return lch(lab.x, length(vec2(lab.y,lab.z)), atan(lab.z, lab.y));
return lch(lab.x, length(vec2(lab.y, lab.z)), atan(lab.z, lab.y));
}
Srgb srgb (Lch lch) {
vec3 c = lch.raw;
c = vec3(c.x, cos(c.z) * c.y, sin(c.z) * c.y);
float lg = 1./116.*(c.x + 16.);
float lg = 1. / 116. * (c.x + 16.);
float x = lch_rgb_weights.x*xyzR(lg + 0.002*c.y);
float y = lch_rgb_weights.y*xyzR(lg);
float z = lch_rgb_weights.z*xyzR(lg - 0.005*c.z);
@ -217,7 +221,7 @@ Srgb srgb (Lch lch) {
return srgb(raw);
}
DEF_TRANSITIVE_CONVERSIONS(Srgb,Srgba,srgb,srgba,Lch,Lcha,lch,lcha)
DEF_TRANSITIVE_CONVERSIONS(Srgb, Srgba, srgb, srgba, Lch, Lcha, lch, lcha)
@ -245,7 +249,7 @@ Srgb srgb(HSV hsv) {
return srgb(c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y));
}
DEF_TRANSITIVE_CONVERSIONS(Srgb,Srgba,srgb,srgba,HSV,HSVA,hsv,hsva)
DEF_TRANSITIVE_CONVERSIONS(Srgb, Srgba, srgb, srgba, HSV, HSVA, hsv, hsva)
@ -269,7 +273,8 @@ Rgba mix(Rgba color1, Rgba color2, float t) {
// ================
#define DEF_GRADIENT(COLOR,COLOR_CONS,CONTROL_POINT,GRADIENT1,GRADIENT2,GRADIENT3,GRADIENT4,GRADIENT5) \
#define DEF_GRADIENT( \
COLOR, COLOR_CONS, CONTROL_POINT, GRADIENT_1, GRADIENT_2, GRADIENT_3, GRADIENT_4, GRADIENT_5) \
struct CONTROL_POINT { \
float offset; \
COLOR color; \
@ -279,29 +284,29 @@ CONTROL_POINT gradient_control_point(float offset, COLOR color) {
return CONTROL_POINT(offset,color); \
} \
\
struct GRADIENT1 { \
struct GRADIENT_1 { \
CONTROL_POINT control_point1; \
}; \
\
struct GRADIENT2 { \
struct GRADIENT_2 { \
CONTROL_POINT control_point1; \
CONTROL_POINT control_point2; \
}; \
\
struct GRADIENT3 { \
struct GRADIENT_3 { \
CONTROL_POINT control_point1; \
CONTROL_POINT control_point2; \
CONTROL_POINT control_point3; \
}; \
\
struct GRADIENT4 { \
struct GRADIENT_4 { \
CONTROL_POINT control_point1; \
CONTROL_POINT control_point2; \
CONTROL_POINT control_point3; \
CONTROL_POINT control_point4; \
}; \
\
struct GRADIENT5 { \
struct GRADIENT_5 { \
CONTROL_POINT control_point1; \
CONTROL_POINT control_point2; \
CONTROL_POINT control_point3; \
@ -309,93 +314,88 @@ struct GRADIENT5 {
CONTROL_POINT control_point5; \
}; \
\
GRADIENT2 gradient \
GRADIENT_2 gradient \
( CONTROL_POINT control_point1 \
, CONTROL_POINT control_point2 ) { \
return GRADIENT2(control_point1,control_point2); \
return GRADIENT_2(control_point1, control_point2); \
} \
\
GRADIENT3 gradient \
GRADIENT_3 gradient \
( CONTROL_POINT control_point1 \
, CONTROL_POINT control_point2 \
, CONTROL_POINT control_point3 ) { \
return GRADIENT3(control_point1,control_point2,control_point3); \
return GRADIENT_3(control_point1, control_point2, control_point3); \
} \
\
GRADIENT4 gradient \
GRADIENT_4 gradient \
( CONTROL_POINT control_point1 \
, CONTROL_POINT control_point2 \
, CONTROL_POINT control_point3 \
, CONTROL_POINT control_point4 ) { \
return GRADIENT4(control_point1,control_point2,control_point3,control_point4); \
return GRADIENT_4(control_point1, control_point2, control_point3, control_point4); \
} \
\
GRADIENT5 gradient \
GRADIENT_5 gradient \
( CONTROL_POINT control_point1 \
, CONTROL_POINT control_point2 \
, CONTROL_POINT control_point3 \
, CONTROL_POINT control_point4 \
, CONTROL_POINT control_point5 ) { \
return GRADIENT5(control_point1,control_point2,control_point3,control_point4,control_point5); \
return GRADIENT_5 \
(control_point1, control_point2, control_point3, control_point4, control_point5); \
} \
\
COLOR sample(GRADIENT2 gradient, float offset) { \
COLOR sample(GRADIENT_2 gradient, float offset) { \
float span = gradient.control_point2.offset - gradient.control_point1.offset; \
float t = clamp((offset - gradient.control_point1.offset)/span); \
return COLOR_CONS(mix(gradient.control_point1.color.raw,gradient.control_point2.color.raw,t)); \
float t = clamp((offset - gradient.control_point1.offset)/span); \
return COLOR_CONS(mix \
(gradient.control_point1.color.raw, gradient.control_point2.color.raw, t)); \
} \
\
COLOR sample(GRADIENT3 gradient, float offset) { \
COLOR sample(GRADIENT_3 gradient, float offset) { \
if (offset < gradient.control_point1.offset) { \
return gradient.control_point1.color; \
} else if (offset < gradient.control_point2.offset) { \
return sample(GRADIENT2(gradient.control_point1,gradient.control_point2),offset); \
return sample(GRADIENT_2(gradient.control_point1, gradient.control_point2), offset); \
} else if (offset < gradient.control_point3.offset) { \
return sample(GRADIENT2(gradient.control_point2,gradient.control_point3),offset); \
return sample(GRADIENT_2(gradient.control_point2, gradient.control_point3), offset); \
} else { \
return gradient.control_point3.color; \
} \
} \
\
COLOR sample(GRADIENT4 gradient, float offset) { \
COLOR sample(GRADIENT_4 gradient, float offset) { \
if (offset < gradient.control_point1.offset) { \
return gradient.control_point1.color; \
} else if (offset < gradient.control_point2.offset) { \
return sample(GRADIENT2(gradient.control_point1,gradient.control_point2),offset); \
return sample(GRADIENT_2(gradient.control_point1, gradient.control_point2), offset); \
} else if (offset < gradient.control_point3.offset) { \
return sample(GRADIENT2(gradient.control_point2,gradient.control_point3),offset); \
return sample(GRADIENT_2(gradient.control_point2, gradient.control_point3), offset); \
} else if (offset < gradient.control_point4.offset) { \
return sample(GRADIENT2(gradient.control_point3,gradient.control_point4),offset); \
return sample(GRADIENT_2(gradient.control_point3, gradient.control_point4), offset); \
} else { \
return gradient.control_point4.color; \
} \
} \
\
COLOR sample(GRADIENT5 gradient, float offset) { \
COLOR sample(GRADIENT_5 gradient, float offset) { \
if (offset < gradient.control_point1.offset) { \
return gradient.control_point1.color; \
} else if (offset < gradient.control_point2.offset) { \
return sample(GRADIENT2(gradient.control_point1,gradient.control_point2),offset); \
return sample(GRADIENT_2(gradient.control_point1, gradient.control_point2), offset); \
} else if (offset < gradient.control_point3.offset) { \
return sample(GRADIENT2(gradient.control_point2,gradient.control_point3),offset); \
return sample(GRADIENT_2(gradient.control_point2, gradient.control_point3), offset); \
} else if (offset < gradient.control_point4.offset) { \
return sample(GRADIENT2(gradient.control_point3,gradient.control_point4),offset); \
return sample(GRADIENT_2(gradient.control_point3, gradient.control_point4), offset); \
} else if (offset < gradient.control_point5.offset) { \
return sample(GRADIENT2(gradient.control_point4,gradient.control_point5),offset); \
return sample(GRADIENT_2(gradient.control_point4, gradient.control_point5), offset); \
} else { \
return gradient.control_point5.color; \
} \
} \
DEF_GRADIENT(Rgb,rgb,RgbGradientControlPoint,RgbGradient1,RgbGradient2,RgbGradient3,RgbGradient4,RgbGradient5)
DEF_GRADIENT(Rgba,rgba,RgbaGradientControlPoint,RgbaGradient1,RgbaGradient2,RgbaGradient3,RgbaGradient4,RgbaGradient5)
//Rgba blend(Rgba bottom, Rgba top, float t) {
// float weight = t * a(top);
// float rgb = mix(bottom.raw.rgb, top.raw.rgb, weight);
// float alpha = a(bottom) + a(top);
//}
DEF_GRADIENT(Rgb, rgb, RgbGradientControlPoint, RgbGradient1, RgbGradient2, RgbGradient3, \
RgbGradient4, RgbGradient5)
DEF_GRADIENT(Rgba, rgba, RgbaGradientControlPoint, RgbaGradient1, RgbaGradient2, RgbaGradient3, \
RgbaGradient4, RgbaGradient5)

View File

@ -1,23 +1,21 @@
/// This code is the body of the fragment shader main function of a GLSL shape.
// =================
// === Constants ===
// =================
const int DISPLAY_MODE_NORMAL = 0;
const int DISPLAY_MODE_DEBUG_SDF = 1;
const int DISPLAY_MODE_DEBUG_ID = 2;
//! This code is the body of the fragment shader main function of a GLSL shape.
// ============
// === Init ===
// ============
// =======================
// === Shape Rendering ===
// =======================
// The shape is first rendered by sampling the SDF equation generated by EnsoGL shape system and
// then it is clipped by a rectangle of the canvas size. The clipping is performed because the
// sprite size is slightly bigger than the canvas size in order to display anti-aliased border
// pixels when the sprite coordinates are not integers or if the scene is zoomed. See the docs
// attached to the shape system's geometry material to learn more.
Env env = Env(1);
vec2 position = input_local.xy ;
Shape shape = run(env,position);
float alpha = shape.color.color.raw.a;
vec2 position = input_local.xy ;
Shape view_box = debug_shape(rect(position, input_size));
Shape shape = run(position);
shape = intersection_no_blend(shape, view_box);
float alpha = shape.color.repr.raw.a;
@ -26,33 +24,69 @@ float alpha = shape.color.color.raw.a;
// ===========================
float alpha_no_aa = alpha > ID_ALPHA_THRESHOLD ? 1.0 : 0.0;
if (pointer_events_enabled) {
output_id = encode(input_global_instance_id,alpha_no_aa);
}
// =======================
// === Color Rendering ===
// =======================
// =====================
// === Display Modes ===
// =====================
if (input_display_mode == DISPLAY_MODE_NORMAL) {
output_color = srgba(unpremultiply(shape.color)).raw;
output_color = srgba(shape.color).raw;
output_color.rgb *= alpha;
} else if (input_display_mode == DISPLAY_MODE_DEBUG_SHAPE_AA_SPAN) {
output_color = srgba(shape.color).raw;
output_color.rgb *= alpha;
output_color = outside_of_uv() ? vec4(1.0,0.0,0.0,1.0) : output_color;
} else if (input_display_mode == DISPLAY_MODE_DEBUG_SDF) {
float zoom = zoom();
float factor = 200.0/zoom * input_pixel_ratio;
Rgb col = distance_meter(shape.sdf.distance,factor,factor);
output_color = rgba(col).raw;
output_color.a = alpha_no_aa;
float zoom = zoom();
float factor = 200.0/zoom * input_pixel_ratio;
Rgb col = distance_meter(shape.sdf.distance, factor, factor);
output_color = rgba(col).raw;
output_color.a = alpha_no_aa;
output_color.rgb *= alpha_no_aa;
} else if (input_display_mode == DISPLAY_MODE_DEBUG_ID) {
float object_hue = float((input_global_instance_id * 7) % 100) / 100.0;
Srgb object_color = srgb(hsv(object_hue, 1.0, 0.5));
output_color.rgb = object_color.raw.rgb;
output_color.a = alpha_no_aa;
} else if (input_display_mode == DISPLAY_MODE_DEBUG_INSTANCE_ID) {
float hue = float((input_global_instance_id + input_mouse_click_count % 10) * 7 % 100) / 100.0;
Srgb color = srgb(hsv(hue, 1.0, 0.5));
output_color.rgb = color.raw.rgb;
output_color.a = alpha_no_aa;
output_color.rgb *= alpha_no_aa;
} else if (input_display_mode == DISPLAY_MODE_DEBUG_SPRITE_OVERVIEW) {
float hue_seed = float(input_global_instance_id + input_mouse_click_count % 10) * 17.0;
float hue = mod(hue_seed, 100.0) / 100.0;
output_color = srgba(hsva(hue, 1.0, 1.0, alpha_no_aa)).raw;
output_color = outside_of_uv() ? vec4(output_color.rgb, 1.0) : output_color;
output_color.a *= clamp(float(input_mouse_position.x)/1000.0, 0.1, 1.0);
output_color.rgb *= output_color.a;
} else if (input_display_mode == DISPLAY_MODE_DEBUG_SPRITE_GRID) {
float hue = float((input_global_instance_id + input_mouse_click_count % 10) * 7 % 100) / 100.0;
Srgba color = srgba(hsv(hue, 1.0, 0.8), 1.0);
Srgba grid_color = srgba(hsv(hue, 1.0, 0.6), 1.0);
output_color = vec4(color.raw.rgb, clamp(float(input_mouse_position.x)/100.0, 0.1, 1.0));
output_color *= alpha_no_aa;
output_color = draw_grid(position, 1, grid_color.raw, output_color);
output_color = draw_grid(position, 2, grid_color.raw, output_color);
output_color = draw_grid(position, 3, grid_color.raw, output_color);
} else if (input_display_mode == DISPLAY_MODE_DEBUG_SPRITE_UV) {
bool overflow = input_uv.x >= 1.0 || input_uv.y >= 1.0;
float blue = overflow? .5 : .0;
output_color = vec4(input_uv, blue, 1.0);
} else {
// Unknown code, display a debug checkerboard.
float stripe_width = input_size.x / 4.0;
float stripe_height = input_size.y / 4.0;
bool vertical = mod(position.x, stripe_width * 2.0) < stripe_width;
bool horizontal = mod(position.y, stripe_height * 2.0) < stripe_height;
bool filled = (vertical || horizontal) && !(vertical && horizontal);
output_color = filled ? vec4(1.0,0.0,0.0,1.0) : vec4(0.0,0.0,0.0,1.0);
}

View File

@ -257,7 +257,7 @@ vec4 encode(int value, float alpha) {
rgb *= alpha;
#ifdef ID_ENCODING_OVERFLOW_CHECK
bool is_overflow = value > MAX_ENCODE_ID;
alpha = is_overflow ? (ID_ENCODING_OVERFLOW_ERROR_CODE/255.0) : alpha;
alpha = is_overflow ? (float(ID_ENCODING_OVERFLOW_ERROR)/255.0) : alpha;
#endif
return vec4(as_float_u8(chunks)*alpha,alpha);
}

View File

@ -0,0 +1,20 @@
/// A zoom level. Zoom of 1.0 means that all figures on the screen will be displayed with their
/// native size. Zoom of 2.0 means that all figures are scaled down twice.
float zoom() {
return input_z_zoom_1 / input_local.z;
}
/// We are adding a side padding to all sprites when drawing shapes on the in order to make
/// anti-aliasing working properly. Consider a situation when a box moves 0.5 pixels to the right.
/// Then the pixel with the x-coordinate 0 should be half-transparent. The pixel on the left from it
/// should be half-transparent as well. However, it will not exist without the padding.
///
/// Also, the padding depends on the zoom level. When shapes are zoomed out 2 times, the screen
/// pixel will display 2 pixels of the sprite canvas.
float aa_side_padding() {
return max(1.0, ceil(1.0 / zoom()));
}
bool outside_of_uv() {
return input_uv.x < 0.0 || input_uv.x > 1.0 || input_uv.y < 0.0 || input_uv.y > 1.0;
}

View File

@ -1,3 +1,64 @@
//! GLSL shape definition boilerplate.
// =============
// === Color ===
// =============
/// The default color used for [`Shape`]s. The LCHA representation was chosen because it gives good
/// results for color blending (better than RGB and way better than sRGB).
struct Color {
Lcha repr;
};
Color color (Lcha color) {
return Color(color);
}
Color color(vec3 lch, float a) {
return Color(lcha(lch, a));
}
Srgba srgba(Color color) {
return srgba(color.repr);
}
// ==========================
// === PremultipliedColor ===
// ==========================
/// The premultiplied version of [`Color`] (the `xyz` components are multiplied by its alpha).
struct PremultipliedColor {
Lcha repr;
};
PremultipliedColor premultiply(Color t) {
float alpha = a(t.repr);
vec3 rgb = t.repr.raw.rgb * alpha;
return PremultipliedColor(lcha(rgb, alpha));
}
Color unpremultiply(PremultipliedColor c) {
float alpha = c.repr.raw.a;
vec3 rgb = alpha > 0.0 ? c.repr.raw.rgb / alpha : c.repr.raw.rgb;
return color(rgb, alpha);
}
/// Implements glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA)
/// in the [`Color`]'s color space. See docs of [`Color`] to learn more.
PremultipliedColor blend(PremultipliedColor bg, PremultipliedColor fg) {
vec4 raw = fg.repr.raw + (1.0 - fg.repr.raw.a) * bg.repr.raw;
return PremultipliedColor(lcha(raw));
}
Srgba srgba(PremultipliedColor color) {
return srgba(unpremultiply(color));
}
// ===================
// === BoundingBox ===
// ===================
@ -11,43 +72,43 @@ struct BoundingBox {
};
BoundingBox bounding_box (float min_x, float max_x, float min_y, float max_y) {
return BoundingBox(min_x,max_x,min_y,max_y);
return BoundingBox(min_x, max_x, min_y, max_y);
}
BoundingBox bounding_box (float w, float h) {
return BoundingBox(-w,w,-h,h);
return BoundingBox(-w, w, -h, h);
}
BoundingBox bounding_box (vec2 size) {
float w2 = size.x / 2.0;
float h2 = size.y / 2.0;
return BoundingBox(-w2,w2,-h2,h2);
return BoundingBox(-w2, w2, -h2, h2);
}
BoundingBox infinite () {
return BoundingBox(0.0, 0.0, 0.0, 0.0);
}
/// Inverses the bounding box. Please note that the inversed bounding box is infinite and thus
/// it does not have a proper representation. We represent infinite bounding boxes as 0-sized ones.
BoundingBox inverse (BoundingBox a) {
return BoundingBox(0.0,0.0,0.0,0.0);
}
BoundingBox infinite () {
return BoundingBox(0.0,0.0,0.0,0.0);
return infinite();
}
BoundingBox unify (BoundingBox a, BoundingBox b) {
float min_x = min(a.min_x,b.min_x);
float max_x = max(a.max_x,b.max_x);
float min_y = min(a.min_y,b.min_y);
float max_y = max(a.max_y,b.max_y);
return BoundingBox(min_x,max_x,min_y,max_y);
float min_x = min(a.min_x, b.min_x);
float max_x = max(a.max_x, b.max_x);
float min_y = min(a.min_y, b.min_y);
float max_y = max(a.max_y, b.max_y);
return BoundingBox(min_x, max_x, min_y, max_y);
}
BoundingBox intersection (BoundingBox a, BoundingBox b) {
float min_x = max(a.min_x,b.min_x);
float max_x = min(a.max_x,b.max_x);
float min_y = max(a.min_y,b.min_y);
float max_y = min(a.max_y,b.max_y);
return BoundingBox(min_x,max_x,min_y,max_y);
float min_x = max(a.min_x, b.min_x);
float max_x = min(a.max_x, b.max_x);
float min_y = max(a.min_y, b.min_y);
float max_y = min(a.max_y, b.max_y);
return BoundingBox(min_x, max_x, min_y, max_y);
}
/// Please note that we cannot compute the exact bounding box for a difference of `a - b`. Thus, we
@ -57,20 +118,21 @@ BoundingBox difference (BoundingBox a, BoundingBox b) {
}
BoundingBox grow (BoundingBox a, float value) {
float min_x = a.min_x-value;
float max_x = a.max_x+value;
float min_y = a.min_y-value;
float max_y = a.max_y+value;
return BoundingBox(min_x,max_x,min_y,max_y);
float min_x = a.min_x - value;
float max_x = a.max_x + value;
float min_y = a.min_y - value;
float max_y = a.max_y + value;
return BoundingBox(min_x, max_x, min_y, max_y);
}
// ===========
// === Sdf ===
// ===========
/// Signed distance field. Describes the distance to the nearest point of a shape.
/// Follow the link to learn more: https://en.wikipedia.org/wiki/Signed_distance_function .
/// Signed distance field. Describes the distance to the nearest point of a shape. Follow the link
/// to learn more: https://en.wikipedia.org/wiki/Signed_distance_function.
struct Sdf {
float distance;
};
@ -84,15 +146,15 @@ Sdf inverse (Sdf a) {
}
Sdf unify (Sdf a, Sdf b) {
return Sdf(min(a.distance,b.distance));
return Sdf(min(a.distance, b.distance));
}
Sdf intersection (Sdf a, Sdf b) {
return Sdf(max(a.distance,b.distance));
return Sdf(max(a.distance, b.distance));
}
Sdf difference (Sdf a, Sdf b) {
return intersection(a,inverse(b));
return intersection(a, inverse(b));
}
Sdf grow (Sdf a, float size) {
@ -105,13 +167,19 @@ Sdf grow (Sdf a, float size) {
// === BoundSdf ===
// ================
/// Bound SDF. Signed distance field with associated bounds. See documentation of `sdf` and `bbox`
/// to learn more.
/// Bound SDF. Signed distance field with associated bounds. See documentation of [`sdf`] and
/// [`bbox`] to learn more.
struct BoundSdf {
float distance;
BoundingBox bounds;
};
float render(BoundSdf sdf) {
float zoom = zoom();
float growth = 0.5 / zoom;
return clamp((-sdf.distance * input_pixel_ratio + growth) * zoom);
}
// === Getters ===
@ -119,10 +187,6 @@ float distance (BoundSdf a) {
return a.distance;
}
//BoundingBox bounds (BoundSdf a) {
// return a.bounds;
//}
Sdf sdf (BoundSdf a) {
return sdf(a.distance);
}
@ -131,11 +195,11 @@ Sdf sdf (BoundSdf a) {
// === Smart Constructors ===
BoundSdf bound_sdf (float distance, BoundingBox bounds) {
return BoundSdf(distance,bounds);
return BoundSdf(distance, bounds);
}
BoundSdf bound_sdf (Sdf sdf, BoundingBox bounds) {
return bound_sdf(sdf.distance,bounds);
return bound_sdf(sdf.distance, bounds);
}
@ -153,24 +217,24 @@ BoundSdf pixel_snap (BoundSdf a) {
BoundSdf grow (BoundSdf a, float size) {
a.distance = a.distance - size;
a.bounds = grow(a.bounds,size);
a.bounds = grow(a.bounds,size);
return a;
}
BoundSdf inverse (BoundSdf a) {
return bound_sdf(inverse(sdf(a)),inverse(a.bounds));
return bound_sdf(inverse(sdf(a)), inverse(a.bounds));
}
BoundSdf unify (BoundSdf a, BoundSdf b) {
return bound_sdf(unify(sdf(a),sdf(b)),unify(a.bounds,b.bounds));
return bound_sdf(unify(sdf(a), sdf(b)), unify(a.bounds, b.bounds));
}
BoundSdf difference (BoundSdf a, BoundSdf b) {
return bound_sdf(difference(sdf(a),sdf(b)),difference(a.bounds,b.bounds));
return bound_sdf(difference(sdf(a), sdf(b)), difference(a.bounds, b.bounds));
}
BoundSdf intersection (BoundSdf a, BoundSdf b) {
return bound_sdf(intersection(sdf(a),sdf(b)),intersection(a.bounds,b.bounds));
return bound_sdf(intersection(sdf(a), sdf(b)), intersection(a.bounds, b.bounds));
}
@ -179,6 +243,8 @@ BoundSdf intersection (BoundSdf a, BoundSdf b) {
// === Id ===
// ==========
/// The ID of a shape. It is used to identify shapes after rendering to an non-antialiased ID
/// texture.
struct Id {
int value;
};
@ -192,133 +258,118 @@ Id new_id_layer (BoundSdf sdf, int i) {
}
// Premultiplied
struct Color {
Srgba color;
};
Color premultiply(Srgba t) {
float alpha = a(t);
vec3 rgb = t.raw.rgb * alpha;
return Color(srgba(rgb,alpha));
}
Srgba unpremultiply(Color t) {
float alpha = t.color.raw.a;
vec3 rgb = t.color.raw.rgb / alpha;
return srgba(rgb,alpha);
}
// Implements glBlendFuncSeparate(GL_ONE,GL_ONE_MINUS_SRC_ALPHA,GL_ONE,GL_ONE_MINUS_SRC_ALPHA);
Color blend(Color bg, Color fg) {
vec4 raw = fg.color.raw + (1.0 - fg.color.raw.a) * bg.color.raw;
return Color(srgba(raw));
}
// =============
// === Shape ===
// =============
float zoom() {
return input_z_zoom_1 / input_local.z;
}
float render(BoundSdf sdf) {
return clamp((-sdf.distance * input_pixel_ratio + 0.5) * zoom());
}
// Note: the color is premultiplied.
/// A visual shape that can be displayed on the screen or combined with other shapes.
struct Shape {
Id id;
/// The ID of the shape. It is used to identify shapes after rendering to an non-antialiased ID
/// texture.
Id id;
/// The Signed Distance Field, describing the shape boundaries.
BoundSdf sdf;
Color color;
float alpha;
/// The color of the shape. Please note that we are storing the premultiplied version of the
/// color, as blending requires premultiplied values. We could store the non-premultiplied,
/// however, then we would need to unpremultiply the color after blending, which leads to
/// a serious issue. If the alpha is 0, then either unpremultiplication needs to be more costly
/// and check for this condition, or it will produce infinite/invalid values for the `xyz`
/// components. If we blend such a color with another one, then we will get artifacts, as
/// multiplying an infinite/invalid value by 0 is an undefined behavior.
PremultipliedColor color;
/// The opacity of the shape. It is the result of rendering of the [`sdf`].
float alpha;
};
Shape shape (Id id, BoundSdf bound_sdf, Srgba rgba) {
Shape shape (Id id, BoundSdf bound_sdf, PremultipliedColor color) {
float alpha = render(bound_sdf);
rgba.raw.a *= alpha;
Color color = premultiply(rgba);
return Shape(id,bound_sdf,color,alpha);
color.repr.raw *= alpha;
return Shape(id, bound_sdf, color, alpha);
}
Shape shape (Id id, BoundSdf bound_sdf, Color color) {
float alpha = render(bound_sdf);
return Shape(id,bound_sdf,color,alpha);
return shape(id, bound_sdf, premultiply(color));
}
Shape shape (Id id, BoundSdf bound_sdf, Srgba rgba) {
return shape(id, bound_sdf, Color(lcha(rgba)));
}
Shape shape (Id id, BoundSdf bound_sdf) {
return shape(id, bound_sdf, srgba(1.0, 0.0, 0.0, 1.0));
}
Shape shape (Id id, BoundSdf bound_sdf, Lcha lcha) {
return shape(id, bound_sdf, Color(lcha));
}
/// A debug [`Shape`] constructor. Should not be used to create shapes that are rendered to the
/// screen as it's ID is always 0. It can be used to create temporary shapes. For example, it can
/// be used to create a clipping rectangle, that will be intersected with another shape.
Shape debug_shape (BoundSdf bound_sdf) {
Id id = new_id_layer(bound_sdf, 10);
return shape(id, bound_sdf);
}
Shape resample (Shape s, float multiplier) {
Id id = s.id;
BoundSdf sdf = resample(s.sdf,multiplier);
Srgba color = unpremultiply(s.color);
color.raw.a /= s.alpha;
return shape(id,sdf,color);
Id id = s.id;
BoundSdf sdf = resample(s.sdf, multiplier);
s.color.repr.raw.a /= s.alpha;
return shape(id, sdf, s.color);
}
Shape pixel_snap (Shape s) {
Id id = s.id;
BoundSdf sdf = pixel_snap(s.sdf);
Srgba color = unpremultiply(s.color);
color.raw.a /= s.alpha;
return shape(id,sdf,color);
Id id = s.id;
BoundSdf sdf = pixel_snap(s.sdf);
s.color.repr.raw.a /= s.alpha;
return shape(id, sdf, s.color);
}
Shape grow (Shape s, float value) {
Id id = s.id;
BoundSdf sdf = grow(s.sdf,value);
Srgba color = unpremultiply(s.color);
color.raw.a /= s.alpha;
return shape(id,sdf,color);
Id id = s.id;
BoundSdf sdf = grow(s.sdf,value);
s.color.repr.raw.a /= s.alpha;
return shape(id, sdf, s.color);
}
Shape inverse (Shape s1) {
return shape(s1.id,inverse(s1.sdf),s1.color);
return shape(s1.id, inverse(s1.sdf), s1.color);
}
Shape unify (Shape s1, Shape s2) {
return shape(s1.id,unify(s1.sdf,s2.sdf),blend(s1.color,s2.color));
return shape(s1.id, unify(s1.sdf, s2.sdf), blend(s1.color, s2.color));
}
Shape difference (Shape s1, Shape s2) {
return shape(s1.id,difference(s1.sdf,s2.sdf),s1.color);
return shape(s1.id, difference(s1.sdf, s2.sdf), s1.color);
}
Shape intersection (Shape s1, Shape s2) {
return shape(s1.id,intersection(s1.sdf,s2.sdf),blend(s1.color,s2.color));
return shape(s1.id, intersection(s1.sdf, s2.sdf), blend(s1.color, s2.color));
}
Shape intersection_no_blend (Shape s1, Shape s2) {
return shape(s1.id, intersection(s1.sdf, s2.sdf), s1.color);
}
Shape set_color(Shape shape, Srgba t) {
t.raw.a *= shape.alpha;
Color color = premultiply(t);
shape.color = color;
shape.color = premultiply(Color(lcha(t)));
return shape;
}
Shape withInfiniteBounds (Shape s) {
Id id = s.id;
Color color = s.color;
BoundSdf sdf = s.sdf;
sdf.bounds = infinite();
return shape(id, sdf, color);
Shape with_infinite_bounds (Shape s) {
BoundSdf sdf = s.sdf;
sdf.bounds = infinite();
return shape(s.id, sdf, s.color);
}
// ===========
// === Env ===
// ===========
struct Env {
int test;
};
///////////////////////
////// Transform //////
///////////////////////
// =================
// === Transform ===
// =================
vec2 translate (vec2 position, vec2 t) {
return position - t;
@ -326,7 +377,7 @@ vec2 translate (vec2 position, vec2 t) {
vec2 rotate (vec2 position, Radians angle) {
float v_angle = value(angle);
return position*cos(-v_angle) + vec2(position.y,-position.x)*sin(-v_angle);
return position * cos(-v_angle) + vec2(position.y, -position.x) * sin(-v_angle);
}
vec2 scale (vec2 position, float value) {
@ -340,3 +391,23 @@ vec2 cartesian2polar (vec2 position) {
vec2 repeat (vec2 position, vec2 tile_size) {
return mod(position+tile_size/2.0, tile_size) - tile_size/2.0;
}
// =============
// === Debug ===
// =============
vec4 draw_grid(vec2 position, int level, vec4 color, vec4 output_color) {
float sampling = pow(2.0, float(level - 1));
float width = min(sampling, zoom()) / input_pixel_ratio + 0.1;
float sampling2 = sampling / 2.0;
bool v = abs(mod(position.x + sampling2, sampling) - sampling2) <= width/2.0/zoom();
bool h = abs(mod(position.y + sampling2, sampling) - sampling2) <= width/2.0/zoom();
if ((v || h) && !outside_of_uv()) {
float alpha = clamp((zoom() - (4.0 - sampling))/(5.0 - sampling), 0.0, 1.0);
color *= alpha;
output_color = color + (1.0 - color.a) * output_color;
}
return output_color;
}

View File

@ -4,6 +4,7 @@
use crate::prelude::*;
use crate::display::shape::primitive::def::primitive;
use crate::display::shape::primitive::glsl::codes;
use crate::display::shape::primitive::shader::overload;
use crate::display::symbol::shader::builder::CodeTemplate;
@ -18,15 +19,13 @@ use super::canvas::Canvas;
// === GLSL Sources ===
/// Common GLSL functions for all sprite types.
pub const GLSL_PRELUDE: &str = include_str!("../glsl/prelude.glsl");
const MATH: &str = include_str!("../glsl/math.glsl");
const COLOR: &str = include_str!("../glsl/color.glsl");
const DEBUG: &str = include_str!("../glsl/debug.glsl");
const SHAPE: &str = include_str!("../glsl/shape.glsl");
const FRAGMENT_RUNNER: &str = include_str!("../glsl/fragment_runner.glsl");
const ERROR_CODES: &[(&str, &str)] = &[(
"ID_ENCODING_OVERFLOW_ERROR_CODE",
include_str!("../glsl/error_codes/id_encoding_overflow.txt"),
)];
// === Definition ===
@ -47,7 +46,7 @@ impl Builder {
canvas.add_current_function_code_line(iformat!("return {shape_ref.getter()};"));
canvas.submit_shape_constructor("run");
let shape_def = overload::allow_overloading(&canvas.to_glsl());
let code = [GLSL_PRELUDE.as_str(), "", &shape_header, &shape_def].join("\n\n");
let code = [GLSL_BOILERPLATE.as_str(), "", &shape_header, &shape_def].join("\n\n");
let main = format!(
"bool pointer_events_enabled = {};\n{}",
pointer_events_enabled, FRAGMENT_RUNNER
@ -68,26 +67,49 @@ fn header(label: &str) -> String {
}
// == GLSL_PRELUDE ==
// == GLSL Boilerplate ==
lazy_static! {
/// A common preamble used to start every shader program.
static ref GLSL_PRELUDE: String = make_glsl_prelude();
static ref GLSL_BOILERPLATE: String = gen_glsl_boilerplate();
}
fn make_error_codes() -> String {
let codes = ERROR_CODES.iter();
codes.map(|(name, code)| format!("const float {} = {}.0;", name, code.trim())).join("\n")
fn glsl_codes() -> String {
let codes = codes::DisplayModes::all();
let header = header("Codes");
let display_modes = codes
.iter()
.map(|code| format!("const int {} = {};", code.name().to_uppercase(), code.value()))
.join("\n");
let error_codes =
format!("const int ID_ENCODING_OVERFLOW_ERROR = {};", codes::ID_ENCODING_OVERFLOW_ERROR);
format!("{}\n\n{}\n{}", header, display_modes, error_codes)
}
fn make_glsl_prelude() -> String {
/// The GLSL common code and debug codes.
pub fn glsl_prelude_and_codes() -> String {
let codes = glsl_codes();
format!("{}\n\n{}", GLSL_PRELUDE, codes)
}
fn gen_glsl_boilerplate() -> String {
let redirections = overload::builtin_redirections();
let math = overload::allow_overloading(MATH);
let color = overload::allow_overloading(COLOR);
let debug = overload::allow_overloading(DEBUG);
let shape = overload::allow_overloading(SHAPE);
let err_codes = make_error_codes();
let codes_and_prelude = glsl_prelude_and_codes();
let defs_header = header("SDF Primitives");
let sdf_defs = overload::allow_overloading(&primitive::all_shapes_glsl_definitions());
[redirections, err_codes, math, color, debug, shape, defs_header, sdf_defs].join("\n\n")
[
redirections.as_str(),
codes_and_prelude.as_str(),
math.as_str(),
color.as_str(),
debug.as_str(),
shape.as_str(),
defs_header.as_str(),
sdf_defs.as_str(),
]
.join("\n\n")
}

View File

@ -62,7 +62,7 @@ impl ShapeData {
/// Getter of the shape as GLSL expression.
pub fn getter(&self) -> String {
iformat!("{self.name}(env,position)")
iformat!("{self.name}(position)")
}
}
@ -76,8 +76,8 @@ impl ShapeData {
/// Canvas for drawing vector graphics.
///
/// The API is stateful, similar to the API of HTML5 canvas element.
/// It uses GLSL and signed distance fields under the hood.
/// The API is stateful, similar to the API of HTML5 canvas element. It uses GLSL and signed
/// distance fields under the hood.
#[derive(Debug, Default)]
pub struct Canvas {
@ -123,17 +123,13 @@ impl Canvas {
/// Defines a new variable in the GLSL code.
pub fn define<E: Str>(&mut self, ty: &str, name: &str, expr: E) {
let max_type_length = 8;
let max_name_length = 6;
let ty = format!("{:1$}", ty, max_type_length);
let name = format!("{:1$}", name, max_name_length);
self.add_current_function_code_line(iformat!("{ty} {name} = {expr.as_ref()};"));
}
/// Submits the `current_function_lines` as a new shape construction function in the GLSL code.
pub fn submit_shape_constructor(&mut self, name: &str) {
let body = self.current_function_lines.join("\n ");
let func = iformat!("Shape {name} (Env env, vec2 position) {{\n {body}\n}}");
let func = iformat!("Shape {name} (vec2 position) {{\n {body}\n}}");
self.current_function_lines = default();
self.functions.push(func);
}
@ -155,13 +151,11 @@ impl Canvas {
/// Defines a new shape with a new id and associated parameters, like color.
pub fn define_shape(&mut self, num: usize, sdf: &str) -> Shape {
self.if_not_defined(num, |this| {
let color = "srgba(1.0,0.0,0.0)";
let mut shape = ShapeData::new(num);
let id = this.get_new_id();
this.define("Srgba", "color", iformat!("{color}"));
this.define("BoundSdf", "sdf", iformat!("{sdf}"));
this.define("Id", "id", iformat!("new_id_layer(sdf,{id})"));
this.add_current_function_code_line("return shape(id,sdf,color);");
this.add_current_function_code_line("return shape(id, sdf);");
this.submit_shape_constructor(&shape.name);
shape.add_id(id);
shape

View File

@ -349,6 +349,7 @@ pub struct ShapeSystemModel {
pub sprite_system: SpriteSystem,
pub shape: Rc<RefCell<def::AnyShape>>,
pub material: Rc<RefCell<Material>>,
pub geometry_material: Rc<RefCell<Material>>,
/// Enables or disables pointer events on this shape system. All shapes of a shape system which
/// have pointer events disabled will be completely transparent for the mouse (they will pass
/// through all mouse events to shapes behind them).
@ -366,10 +367,18 @@ impl ShapeSystemModel {
pub fn new(shape: def::AnyShape, pointer_events: bool) -> Self {
let sprite_system = SpriteSystem::new();
let material = Rc::new(RefCell::new(Self::default_material()));
let geometry_material = Rc::new(RefCell::new(Self::default_geometry_material()));
let pointer_events = Immutable(pointer_events);
let shape = Rc::new(RefCell::new(shape));
let do_not_use_shape_definition = default();
Self { sprite_system, shape, material, pointer_events, do_not_use_shape_definition }
Self {
sprite_system,
shape,
material,
geometry_material,
pointer_events,
do_not_use_shape_definition,
}
}
fn init(&self) {
@ -384,11 +393,63 @@ impl ShapeSystemModel {
material.add_input("pixel_ratio", 1.0);
material.add_input("z_zoom_1", 1.0);
material.add_input("time", 0.0);
material.add_input_def::<Vector2<i32>>("mouse_position");
material.add_input_def::<i32>("mouse_click_count");
material.add_input("display_mode", 0);
material.add_output("id", Vector4::<f32>::zero());
material
}
fn default_geometry_material() -> Material {
let mut material = SpriteSystem::default_geometry_material();
material.set_before_main(shader::builder::glsl_prelude_and_codes());
// The GLSL vertex shader implementing automatic shape padding for anti-aliasing. See the
// docs of [`aa_side_padding`] to learn more about the concept of shape padding.
//
// First, we are computing the vertex position without shape padding. This is required to
// make the function [`aa_side_padding`] work, as it uses [`zoom`], which uses the
// [`input_local.z`] value. The depth of the vertex can be computed only after the
// [`model_view_projection`] matrix is applied.
//
// Please note that this method is not guaranteed to always provide correct results. If
// there is a big angle between the camera and the shape normal axes (e.g. when the shape is
// significantly rotated around its Y-axis), the padding might be too small. To correct it,
// we might take normal axes into account, but it will require more computations, and we do
// not need it currently.
//
// Also, please note that we are first using the [`input_uv`] variable, and then we are
// changing it. It's because the unchanged value is the incoming UV in range 0..1, and then
// we are scaling it to a bigger range, so the padded area UV is not contained within 0..1.
material.set_main(
"
mat4 model_view_projection = input_view_projection * input_transform;
// Computing the vertex position without shape padding.
vec3 input_local_no_padding = vec3((input_uv - input_alignment) * input_size, 0.0);
vec4 position_no_padding = model_view_projection * vec4(input_local_no_padding, 1.0);
input_local.z = position_no_padding.z;
// We are now able to compute the padding and grow the canvas by its value.
vec2 padding = vec2(aa_side_padding());
if (input_display_mode == DISPLAY_MODE_DEBUG_SPRITE_OVERVIEW) {
padding = vec2(float(input_mouse_position.y) / 10.0);
}
vec2 padding2 = 2.0 * padding;
vec2 padded_size = input_size + padding2;
vec2 uv_scale = padded_size / input_size;
vec2 uv_offset = padding / input_size;
input_uv = vertex_uv * uv_scale - uv_offset;
// We need to recompute the vertex position with the padding.
input_local = vec3((input_uv - input_alignment) * input_size, 0.0);
gl_Position = model_view_projection * vec4(input_local,1.0);
input_local.z = gl_Position.z;
",
);
material
}
/// Replaces the shape definition.
#[profile(Detail)]
pub fn set_shape(&self, shape: def::AnyShape) {
@ -419,6 +480,7 @@ impl ShapeSystemModel {
#[profile(Detail)]
fn reload_material(&self) {
self.sprite_system.set_material(&*self.material.borrow());
self.sprite_system.set_geometry_material(&*self.geometry_material.borrow());
}
}

View File

@ -116,15 +116,23 @@ impl DomSymbol {
dom.set_style_or_warn("position", "absolute");
dom.set_style_or_warn("width", "0px");
dom.set_style_or_warn("height", "0px");
dom.set_style_or_warn("display", "none");
dom.append_or_warn(content);
let display_object = display::object::Instance::new();
let weak_display_object = display_object.downgrade();
let network = &display_object.network;
frp::extend! { network
eval_ display_object.on_show (dom.set_style_or_warn("display", ""));
eval_ display_object.on_hide (dom.set_style_or_warn("display", "none"));
eval_ display_object.on_updated ([dom] {
if let Some(display_object) = weak_display_object.upgrade() {
let mut transform = inverse_y_translation(display_object.transformation_matrix());
transform.iter_mut().for_each(|a| *a = eps(*a));
set_object_transform(&dom, &transform);
}
});
}
let guard = Rc::new(Guard::new(&display_object, &dom));
display_object.set_on_updated(enclose!((dom) move |t| {
let mut transform = inverse_y_translation(t.matrix());
transform.iter_mut().for_each(|a| *a = eps(*a));
set_object_transform(&dom,&transform);
}));
Self { dom, display_object, size, guard }
}

View File

@ -591,16 +591,19 @@ impl SymbolData {
fn init(self) -> Self {
let is_hidden = &self.is_hidden;
let id = self.id;
self.display_object.set_on_hide(f_!(is_hidden.set(true)));
self.display_object.set_on_show(f__!(is_hidden.set(false)));
self.display_object.set_on_scene_layer_changed(move |_, old_layers, new_layers| {
for layer in old_layers.iter().filter_map(|t| t.upgrade()) {
layer.remove_symbol(id)
}
for layer in new_layers.iter().filter_map(|t| t.upgrade()) {
layer.add_symbol(id)
}
});
let network = &self.display_object.network;
frp::extend! { network
eval_ self.display_object.on_hide(is_hidden.set(true));
eval_ self.display_object.on_show(is_hidden.set(false));
eval self.display_object.on_layer_change([] ((_, old_layers, new_layers)) {
for layer in old_layers.iter().filter_map(|t| t.upgrade()) {
layer.remove_symbol(id)
}
for layer in new_layers.iter().filter_map(|t| t.upgrade()) {
layer.add_symbol(id)
}
});
}
self
}

View File

@ -111,6 +111,71 @@ impl Size {
// ===================
// === SizedObject ===
// ===================
/// A display object bound with [`Size`].
#[derive(Debug)]
pub struct SizedObject {
size: Size,
display_object: display::object::Instance,
}
impl SizedObject {
fn new(attr: Attribute<Vector2<f32>>, transform: &Attribute<Matrix4<f32>>) -> Self {
let size = Size::new(attr);
let display_object = display::object::Instance::new();
let weak_display_object = display_object.downgrade();
let network = &display_object.network;
frp::extend! { network
eval_ display_object.on_updated ([transform] {
if let Some(display_object) = weak_display_object.upgrade() {
transform.set(display_object.transformation_matrix())
}
});
}
Self { size, display_object }.init()
}
/// Init display object bindings. In particular defines the behavior of the show and hide
/// callbacks.
fn init(self) -> Self {
let size = &self.size;
let display_object = &self.display_object;
let network = &display_object.network;
frp::extend! { network
eval_ display_object.on_show(size.show());
eval_ display_object.on_hide(size.hide());
}
self
}
/// Clone ref the underlying [`Size`].
pub fn clone_ref(&self) -> Size {
self.size.clone_ref()
}
}
impl HasItem for SizedObject {
type Item = Vector2;
}
impl CellGetter for SizedObject {
fn get(&self) -> Vector2 {
self.size.get()
}
}
impl CellSetter for SizedObject {
fn set(&self, v: Vector2) {
self.size.set(v);
self.display_object.set_bounding_box(v);
}
}
// ==============
// === Sprite ===
// ==============
@ -119,17 +184,44 @@ impl Size {
/// freely rotated only by their local z-axis. This implementation, however, implements sprites as
/// full 3D objects. We may want to fork this implementation in the future to create a specialized
/// 2d representation as well.
#[derive(Debug, Clone, CloneRef)]
#[derive(Debug, Clone, CloneRef, Deref)]
#[allow(missing_docs)]
pub struct Sprite {
pub symbol: Symbol,
model: Rc<SpriteModel>,
}
/// Internal representation of [`Sprite`].
#[derive(Debug, Deref)]
#[allow(missing_docs)]
pub struct SpriteModel {
#[deref]
pub instance: SymbolInstance,
pub size: Size,
display_object: display::object::Instance,
pub symbol: Symbol,
pub size: SizedObject,
transform: Attribute<Matrix4<f32>>,
stats: Rc<SpriteStats>,
erase_on_drop: Rc<EraseOnDrop<Attribute<Vector2<f32>>>>,
unset_parent_on_drop: Rc<display::object::UnsetParentOnDrop>,
stats: SpriteStats,
erase_on_drop: EraseOnDrop<Attribute<Vector2<f32>>>,
unset_parent_on_drop: display::object::UnsetParentOnDrop,
}
impl SpriteModel {
/// Constructor.
pub fn new(
symbol: &Symbol,
instance: SymbolInstance,
transform: Attribute<Matrix4<f32>>,
size: Attribute<Vector2<f32>>,
stats: &Stats,
) -> Self {
let symbol = symbol.clone_ref();
let stats = SpriteStats::new(stats);
let erase_on_drop = EraseOnDrop::new(size.clone_ref());
let size = SizedObject::new(size, &transform);
let unset_parent_on_drop = display::object::UnsetParentOnDrop::new(&size.display_object);
let default_size = Vector2(DEFAULT_SPRITE_SIZE.0, DEFAULT_SPRITE_SIZE.1);
size.set(default_size);
Self { symbol, instance, size, transform, stats, erase_on_drop, unset_parent_on_drop }
}
}
impl Sprite {
@ -141,37 +233,8 @@ impl Sprite {
size: Attribute<Vector2<f32>>,
stats: &Stats,
) -> Self {
let symbol = symbol.clone_ref();
let display_object = display::object::Instance::new();
let stats = Rc::new(SpriteStats::new(stats));
let erase_on_drop = Rc::new(EraseOnDrop::new(size.clone_ref()));
let size = Size::new(size);
let unset_parent_on_drop =
Rc::new(display::object::UnsetParentOnDrop::new(&display_object));
let default_size = Vector2(DEFAULT_SPRITE_SIZE.0, DEFAULT_SPRITE_SIZE.1);
size.set(default_size);
Self {
symbol,
instance,
size,
display_object,
transform,
stats,
erase_on_drop,
unset_parent_on_drop,
}
.init()
}
/// Init display object bindings. In particular defines the behavior of the show and hide
/// callbacks.
fn init(self) -> Self {
let size = &self.size;
let transform = &self.transform;
self.display_object.set_on_updated(f!((t) transform.set(t.matrix())));
self.display_object.set_on_hide(f_!(size.hide()));
self.display_object.set_on_show(f__!(size.show()));
self
let model = SpriteModel::new(symbol, instance, transform, size, stats);
Self { model: Rc::new(model) }
}
/// Get the symbol id.
@ -188,16 +251,15 @@ impl Sprite {
}
}
impl display::Object for Sprite {
impl display::Object for SpriteModel {
fn display_object(&self) -> &display::object::Instance {
&self.display_object
&self.size.display_object
}
}
impl Deref for Sprite {
type Target = SymbolInstance;
fn deref(&self) -> &Self::Target {
&self.instance
impl display::Object for Sprite {
fn display_object(&self) -> &display::object::Instance {
self.model.display_object()
}
}
@ -310,13 +372,14 @@ impl SpriteSystem {
fn init_shader(&self) {
let shader = self.symbol.shader();
let surface_material = Self::surface_material();
let geometry_material = Self::geometry_material();
let surface_material = Self::default_surface_material();
let geometry_material = Self::default_geometry_material();
shader.set_geometry_material(&geometry_material);
shader.set_material(&surface_material);
}
fn geometry_material() -> Material {
/// The default geometry material for all sprites.
pub fn default_geometry_material() -> Material {
let mut material = Material::new();
material.add_input_def::<Vector2<f32>>("size");
material.add_input_def::<Vector2<f32>>("uv");
@ -328,10 +391,10 @@ impl SpriteSystem {
material.set_main(
"
mat4 model_view_projection = input_view_projection * input_transform;
input_local = vec3((input_uv - input_alignment) * input_size, 0.0);
gl_Position = model_view_projection * vec4(input_local,1.0);
input_local.z = gl_Position.z;
",
input_local = vec3((input_uv - input_alignment) * input_size, 0.0);
gl_Position = model_view_projection * vec4(input_local,1.0);
input_local.z = gl_Position.z;
",
// This is left here in case it will be needed. The `instance_id` is the same as the
// built-in `gl_InstanceID` and can be implemented very efficiently:
// input_instance_id = gl_InstanceID;
@ -339,7 +402,8 @@ impl SpriteSystem {
material
}
fn surface_material() -> Material {
/// The default surface material for all sprites.
pub fn default_surface_material() -> Material {
let mut material = Material::new();
// FIXME We need to use this output, as we need to declare the same amount of shader
// FIXME outputs as the number of attachments to framebuffer. We should manage this more

View File

@ -159,7 +159,7 @@ impl {
let vertex_code = self.geometry_material.code().clone();
let fragment_code = self.surface_material.code().clone();
shader_builder.compute(&shader_cfg,vertex_code,fragment_code);
shader_builder.compute(&shader_cfg, vertex_code, fragment_code);
let code = shader_builder.build();
*self.program.borrow_mut() = None;

View File

@ -20,6 +20,7 @@ use crate::display::render;
use crate::display::render::passes::SymbolsRenderPass;
use crate::display::scene::DomPath;
use crate::display::scene::Scene;
use crate::display::shape::primitive::glsl;
use crate::system::web;
use enso_types::unit2::Duration;
@ -229,6 +230,7 @@ pub struct WorldData {
pub default_scene: Scene,
scene_dirty: dirty::SharedBool,
uniforms: Uniforms,
display_mode: Rc<Cell<glsl::codes::DisplayModes>>,
stats: Stats,
stats_monitor: debug::monitor::Monitor,
stats_draw_handle: callback::Handle,
@ -246,7 +248,8 @@ impl WorldData {
let on = Callbacks::default();
let scene_dirty = dirty::SharedBool::new(());
let on_change = enclose!((scene_dirty) move || scene_dirty.set());
let default_scene = Scene::new(&stats, on_change);
let display_mode = Rc::<Cell<glsl::codes::DisplayModes>>::default();
let default_scene = Scene::new(&stats, on_change, &display_mode);
let uniforms = Uniforms::new(&default_scene.variables);
let debug_hotkeys_handle = default();
let garbage_collector = default();
@ -262,6 +265,7 @@ impl WorldData {
default_scene,
scene_dirty,
uniforms,
display_mode,
stats,
on,
debug_hotkeys_handle,
@ -285,24 +289,29 @@ impl WorldData {
fn init_debug_hotkeys(&self) {
let stats_monitor = self.stats_monitor.clone_ref();
let display_mode = self.uniforms.display_mode.clone_ref();
let display_mode = self.display_mode.clone_ref();
let display_mode_uniform = self.uniforms.display_mode.clone_ref();
let closure: Closure<dyn Fn(JsValue)> = Closure::new(move |val: JsValue| {
let event = val.unchecked_into::<web::KeyboardEvent>();
let digit_prefix = "Digit";
if event.alt_key() && event.ctrl_key() {
let key = event.code();
if key == "Backquote" {
stats_monitor.toggle()
} else if key == "Digit0" {
display_mode.set(0)
} else if key == "Digit1" {
display_mode.set(1)
} else if key == "Digit2" {
display_mode.set(2)
} else if key == "KeyP" {
enso_debug_api::save_profile(&profiler::internal::take_log());
} else if key == "KeyQ" {
enso_debug_api::save_profile(&profiler::internal::take_log());
enso_debug_api::LifecycleController::new().map(|api| api.quit());
} else if key.starts_with(digit_prefix) {
let code_value = key.trim_start_matches(digit_prefix).parse().unwrap_or(0);
if let Some(mode) = glsl::codes::DisplayModes::from_value(code_value) {
warn!("Setting display mode to {:?}.", mode.name());
display_mode.set(mode);
} else {
warn!("Invalid display mode code: {code_value}.");
}
display_mode_uniform.set(code_value as i32);
}
}
});

View File

@ -59,11 +59,16 @@ impl<S: Shape> ShapeView<S> {
fn init_on_scene_layer_changed(&self) {
let weak_model = Rc::downgrade(&self.model);
self.display_object().set_on_scene_layer_changed(move |scene, old_layer, new_layer| {
if let Some(model) = weak_model.upgrade() {
model.on_scene_layer_changed(scene, old_layer, new_layer)
}
});
let display_object = self.display_object();
let network = &display_object.network;
frp::extend! { network
eval display_object.on_layer_change([] ((scene, old_layer, new_layer)) {
let scene = scene.as_ref().unwrap();
if let Some(model) = weak_model.upgrade() {
model.on_scene_layer_changed(scene, old_layer.as_ref(), new_layer.as_ref());
}
});
}
}
}
@ -298,7 +303,7 @@ impl<Model: 'static, Frp: 'static> Widget<Model, Frp> {
}
impl<Model: 'static, Frp: 'static> display::Object for Widget<Model, Frp> {
fn display_object(&self) -> &display::object::Instance<Scene> {
fn display_object(&self) -> &display::object::Instance {
&self.data.display_object
}
}

View File

@ -191,6 +191,11 @@ impl<Value> {
self.value = value;
}
/// Modifies the value of this uniform.
pub fn modify(&mut self, f: impl FnOnce(&mut Value)) {
f(&mut self.value);
}
// /// Checks whether the uniform was changed and not yet updated.
// pub fn check_dirty(&self) -> bool {
// self.dirty

View File

@ -121,7 +121,7 @@ pub fn main() {
.on
.before_frame
.add(move |_time| {
mask.set_position_x(((frame as f32) / 30.0).sin() * 100.0);
mask.set_x(((frame as f32) / 30.0).sin() * 100.0);
let _keep_alive = &navigator;
let _keep_alive = &style_watch;
let _keep_alive = &theme_manager;

View File

@ -30,9 +30,49 @@ use ensogl_core::display::symbol::geometry::SpriteSystem;
use ensogl_core::display::symbol::DomSymbol;
use ensogl_core::system::web;
use nalgebra::Vector2;
use nalgebra::Vector3;
// ==============
// === Export ===
// ==============
pub use ensogl_core::system::web::dom::Shape;
const ELEM_COUNT: i32 = 10;
const HTML_PADDING: f32 = 10.0;
const VERTICAL_MARGIN: f32 = 10.0;
const HEIGHT_FRACTION: f32 = 0.8;
fn update_shape(screen: Shape, sprites: &[Sprite], dom_symbols: &[DomSymbol]) {
let side_offset = 10.0;
let display_objects = sprites
.iter()
.map(|s| s.display_object())
.interleave(dom_symbols.iter().map(|s| s.display_object()));
let width = (screen.width - 3.0 * side_offset) / ELEM_COUNT as f32 + 2.0 * side_offset;
let height = screen.height;
for (i, object) in display_objects.enumerate() {
let fi = i as f32;
let x = -screen.width / 2.0 + width / 2.0 + (width - 2.0 * side_offset) * fi;
object.set_position(Vector3(x, 0.0, 0.0));
}
for symbol in sprites {
let size = Vector2::new(width, height * HEIGHT_FRACTION);
symbol.size.set(size);
symbol.mod_y(|y| y - screen.height / 2.0 + size.y / 2.0 + VERTICAL_MARGIN);
}
for symbol in dom_symbols {
let size = Vector2::new(width, height * HEIGHT_FRACTION - HTML_PADDING * 2.0);
symbol.set_size(size);
symbol.mod_x(|y| y - HTML_PADDING);
symbol.mod_y(|y| y + HTML_PADDING);
symbol.mod_y(|y| {
y + screen.height / 2.0 - (size.y + HTML_PADDING * 2.0) / 2.0 - VERTICAL_MARGIN
});
}
}
#[entry_point]
#[allow(dead_code)]
@ -41,7 +81,6 @@ pub fn main() {
let world = World::new().displayed_in("root");
let scene = &world.default_scene;
let camera = scene.camera();
let screen = camera.screen();
let navigator = Navigator::new(scene, &camera);
let sprite_system = SpriteSystem::new();
world.add_child(&sprite_system);
@ -50,44 +89,49 @@ pub fn main() {
let dom_back_layer = &scene.dom.layers.back;
let mut sprites: Vec<Sprite> = default();
let mut css3d_objects: Vec<DomSymbol> = default();
let count = 10;
for i in 0..count {
let x = i as f32;
let width = screen.width * 1.5 / count as f32;
let height = screen.height;
let y = height / 2.0;
let mut dom_symbols: Vec<DomSymbol> = default();
for i in 0..ELEM_COUNT {
let fi = i as f32;
if i % 2 == 0 {
let height = height * 0.75;
let size = Vector2::new(width, height);
let position = Vector3::new(width / 1.5 * x + width / 2.0, y, 0.0);
let sprite = sprite_system.new_instance();
sprite.size.set(size);
sprite.mod_position(|t| *t = position);
sprites.push(sprite);
} else {
let div = web::document.create_div_or_panic();
div.set_style_or_warn("width", "100%");
div.set_style_or_warn("height", "100%");
div.set_inner_html("top-left");
div.set_style_or_warn("padding", format!("{HTML_PADDING}px"));
div.set_style_or_warn(
"font-family",
"SF Pro Display,SF Pro Icons,Helvetica Neue,Helvetica,Arial,sans-serif",
);
div.set_inner_html(
"This is a dom element.<br/>\
Black boxes are WebGL sprites.<br/><br/>\
Try zooming and moving the scene!",
);
let size = Vector2::new(width, height);
let position = Vector3::new(width / 1.5 * x + width / 2.0, y, 0.0);
let object = DomSymbol::new(&div);
dom_front_layer.manage(&object);
world.add_child(&object);
let r = ((x + 0.0) * 16.0) as u8;
let g = ((x + 2.0) * 32.0) as u8;
let b = ((x + 4.0) * 64.0) as u8;
let r = ((fi + 2.0) * 64.0 / (ELEM_COUNT as f32)) as u8;
let g = ((fi + 4.0) * 128.0 / (ELEM_COUNT as f32)) as u8;
let b = ((fi + 8.0) * 255.0 / (ELEM_COUNT as f32)) as u8;
let color = iformat!("rgb({r},{g},{b})");
div.set_style_or_warn("background-color", color);
object.dom().append_or_warn(&div);
object.set_size(size);
object.mod_position(|t| *t = position);
css3d_objects.push(object);
dom_symbols.push(object);
}
}
let network = ensogl_core::frp::Network::new("network");
let sprites2 = sprites.clone();
let dom_symbols2 = dom_symbols.clone();
ensogl_core::frp::extend! { network
eval scene.frp.shape ([] (screen) update_shape(*screen, &sprites2, &dom_symbols2));
}
let layers = vec![dom_front_layer.clone_ref(), dom_back_layer.clone_ref()];
let mut iter_to_change = 0;
@ -97,14 +141,14 @@ pub fn main() {
.on
.before_frame
.add(move |_| {
let _keep_alive = &network;
let _keep_alive = &navigator;
let _keep_alive = &sprites;
let _keep_alive = &sprite_system;
if iter_to_change == 0 {
iter_to_change = 50;
i = (i + 1) % 2;
for (j, object) in css3d_objects.iter_mut().enumerate() {
for (j, object) in dom_symbols.iter_mut().enumerate() {
layers[(i + j) % 2].manage(object);
}
}

View File

@ -37,7 +37,22 @@ mod rectangle {
let rect = Rect((&width, &height)).corners_radius(10.0.px());
let inside = rect.shrink(BORDER_SIZE.px());
let border = &inside.grow((border_size - 1.0).px()) - &inside;
let shape = inside.fill(color) + border.fill(border_color);
let shape = border.fill(border_color) + inside.fill(color::Rgba(0.0,0.0,0.0,0.2));
// let line = Line(4.0.px()).fill(color::Rgba(1.0,0.0,0.0,1.0));
// let shape = inside.fill(color::Rgba(0.0,0.0,0.0,0.2));
// let shape = shape + line;
shape.into()
}
}
}
mod rectangle2 {
use super::*;
ensogl_core::shape! {
(style: Style) {
let rect = Rect((10.px(), 10.px()));
let shape = rect.fill(color::Rgba::new(0.0, 1.0, 0.0, 1.0));
shape.into()
}
}
@ -108,8 +123,13 @@ pub fn main() {
let container = define_rect(container_size * 2.0, container_size, network);
let left_stack = define_stack(network);
let right_stack = define_stack(network);
left_stack.mod_position_x(|x| x - (container_size) / 2.0);
right_stack.mod_position_x(|x| x + (container_size) / 2.0);
left_stack.mod_x(|x| x - (container_size) / 2.0);
right_stack.mod_x(|x| x + (container_size) / 2.0);
let rect = rectangle2::View::new();
rect.size.set(Vector2::new(2.0, 2.0));
world.add_child(&rect);
mem::forget(rect);
world.add_child(&container);
container.add_child(&left_stack);

View File

@ -189,10 +189,10 @@ fn init(app: &Application) {
let mut positions = itertools::iproduct!([-450.0, 50.0], [350.0, -50.0]).map(pair_to_vec2);
grids_layer.add(&plain_grid_view);
plain_grid_view.set_position_xy(positions.next().unwrap());
plain_grid_view.set_xy(positions.next().unwrap());
for (view, position) in grid_views_with_headers.iter().zip(positions) {
grids_layer.add(view);
view.set_position_xy(position);
view.set_xy(position);
}
let view = &grid_views_with_headers[0];

View File

@ -88,7 +88,7 @@ pub async fn main() {
let graph_height: f32 = flame_graph.height();
let sequence_diagram_offset = graph_height + sequence_diagram.height.value();
sequence_diagram.set_position_y(-sequence_diagram_offset);
sequence_diagram.set_y(-sequence_diagram_offset);
scene.add_child(&sequence_diagram);
scene.layers.main.add(&sequence_diagram);

View File

@ -101,7 +101,7 @@ fn init(app: &Application) {
theme::builtin::light::enable(app);
let scene = &app.display.default_scene;
scene.camera().set_position_xy(Vector2(100.0, -100.0));
scene.camera().set_xy(Vector2(100.0, -100.0));
let navigator = Navigator::new(scene, &scene.camera());
navigator.disable_wheel_panning();
@ -125,8 +125,8 @@ fn init(app: &Application) {
scroll_area.add_child(&background);
scene.layers.below_main.add(&background);
background.size.set(Vector2::new(200.0, 200.0));
background.set_position_x(100.0);
background.set_position_y(-100.0);
background.set_x(100.0);
background.set_y(-100.0);
std::mem::forget(background);
@ -135,8 +135,8 @@ fn init(app: &Application) {
let content = content::View::new();
scroll_area.content().add_child(&content);
content.size.set(Vector2::new(300.0, 1000.0));
content.set_position_x(150.0);
content.set_position_y(-500.0);
content.set_x(150.0);
content.set_y(-500.0);
std::mem::forget(content);

View File

@ -80,7 +80,7 @@ fn init(app: &Application) {
let slider2 = make_slider(app);
slider2.inner().frp.set_width(400.0);
slider2.inner().frp.set_height(50.0);
slider2.inner().set_position_y(60.0);
slider2.inner().set_y(60.0);
slider2.inner().frp.set_slider_track_color(color::Lcha(0.4, 0.7, 0.2, 1.0));
slider2.inner().frp.set_value_text_color(color::Lcha(0.2, 0.7, 0.7, 1.0));
slider2.inner().frp.set_slider_disabled(true);
@ -89,7 +89,7 @@ fn init(app: &Application) {
let slider3 = make_slider(app);
slider3.inner().frp.set_width(400.0);
slider3.inner().frp.set_height(50.0);
slider3.inner().set_position_y(120.0);
slider3.inner().set_y(120.0);
slider3.inner().frp.set_slider_track_color(color::Lcha(0.4, 0.7, 0.7, 1.0));
slider3.inner().frp.set_value_text_color(color::Lcha(0.2, 0.7, 0.2, 1.0));
slider3.inner().frp.set_label("Inner label");
@ -98,7 +98,7 @@ fn init(app: &Application) {
let slider4 = make_slider(app);
slider4.inner().frp.set_width(400.0);
slider4.inner().frp.set_height(50.0);
slider4.inner().set_position_y(180.0);
slider4.inner().set_y(180.0);
slider4.inner().frp.set_slider_track_color(color::Lcha(0.4, 0.7, 0.2, 1.0));
slider4.inner().frp.set_value_text_color(color::Lcha(0.2, 0.7, 0.7, 1.0));
slider4.inner().frp.set_label("Disabled label");

View File

@ -128,22 +128,22 @@ impl Borders {
eval area.height ([borders](h) {
borders.right.size.set(Vector2(BORDER_WIDTH + BORDER_PADDING * 2.0, *h));
borders.left.size.set(Vector2(BORDER_WIDTH + BORDER_PADDING * 2.0, *h));
borders.right.set_position_y(-h/2.0);
borders.left.set_position_y(-h/2.0);
borders.right.set_y(-h/2.0);
borders.left.set_y(-h/2.0);
borders.bottom_changed_frame_hold.set(DEBUG_FRAME_HOLD);
borders.bottom.color_rgba.set(RED);
borders.bottom.set_position_y(-*h);
borders.bottom.set_y(-*h);
});
eval area.width ([borders](w) {
borders.top.size.set(Vector2(*w, BORDER_WIDTH + BORDER_PADDING * 2.0));
borders.bottom.size.set(Vector2(*w, BORDER_WIDTH + BORDER_PADDING * 2.0));
borders.top.set_position_x(w/2.0);
borders.bottom.set_position_x(w/2.0);
borders.top.set_x(w/2.0);
borders.bottom.set_x(w/2.0);
borders.right_changed_frame_hold.set(DEBUG_FRAME_HOLD);
borders.right.color_rgba.set(RED);
borders.right.set_position_x(*w);
borders.right.set_x(*w);
});
}
mem::forget(frp);

View File

@ -12,3 +12,7 @@ nalgebra = { version = "0.26.1" }
num-traits = { version = "0.2" }
paste = "1.0.7"
serde = { version = "1.0", features = ["derive"], optional = true }
enso-prelude = { path = "../prelude" }
[build-dependencies]
enso-prelude = { path = "../prelude" }

177
lib/rust/types/build.rs Normal file
View File

@ -0,0 +1,177 @@
//! Generation of Dim* macros, macros allowing generation of swizzling getters and setters.
// === Non-Standard Linter Configuration ===
#![allow(clippy::bool_to_int_with_if)]
#![allow(clippy::let_and_return)]
#![allow(clippy::option_map_unit_fn)]
#![allow(clippy::precedence)]
#![allow(dead_code)]
#![deny(non_ascii_idents)]
#![deny(unconditional_recursion)]
#![warn(unsafe_code)]
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
use enso_prelude::*;
use std::fmt::Write;
use std::fs::File;
use std::io::Write as IoWrite;
// =================
// === Constants ===
// =================
const FILE: &str = "src/dim_macros.rs";
const AXES: &[&str] = &["x", "y", "z", "w"];
const INDENT_SIZE: usize = 4;
// ========================
// === Formatting Utils ===
// ========================
fn indent(level: usize) -> String {
" ".repeat(level * INDENT_SIZE)
}
// ======================
// === Implementation ===
// ======================
/// Generates swizzling data. The [`base_dim`] describes what dimension the data should be generated
/// in. For example, if it is set to 3, all of "x", "y", and "z" axes will be combined to generate
/// the result. The [`dim`] describes the dimension of the swizzling. For example, if it is set to
/// 2, the result will contain 2-dimensional coordinates, like "xy", or "yz". If the [`unique`] flag
/// is set, the generated swizzling will not have repeated axes (e.g. `xx` is not allowed).
///
/// The output is a vector of four elements:
/// - The swizzling name, like "xy", "xyz", "xz", etc.
/// - The swizzling dimension.
/// - The swizzling component indexes. For example [0, 2] for "xz".
/// - The enumeration of components. For example [0, 1] for "xz".
///
/// For example, for the base dimension of 3 and the dimension of 2, the following swizzles will be
/// generated:
///
/// ```text
/// xz 2 [0, 2] [0, 1]
/// yz 2 [1, 2] [0, 1]
/// zx 2 [2, 0] [0, 1]
/// zy 2 [2, 1] [0, 1]
/// zz 2 [2, 2] [0, 1]
/// ```
///
/// See the generated [`FILE`] to see the result of this script.
fn gen_swizzling(
base_dim: usize,
dim: usize,
unique: bool,
) -> Vec<(Vec<String>, usize, Vec<usize>, Vec<usize>)> {
let mut vec: Vec<(Vec<String>, Vec<usize>, Vec<usize>)> = vec![(vec![], vec![], vec![])];
for _ in 0..dim {
vec = vec
.clone()
.into_iter()
.cartesian_product(AXES[0..base_dim].iter().enumerate())
.filter_map(|((mut prod, mut ixs, mut ord), (ix, axis))| {
if unique && ixs.contains(&ix) {
return None;
}
prod.push(axis.to_string());
ixs.push(ix);
ord.push(ord.len());
Some((prod, ixs, ord))
})
.collect_vec();
}
vec.into_iter().map(|(prod, ixs, ord)| (prod, dim, ixs, ord)).collect_vec()
}
/// Just like [`gen_swizzling`], but the output always contains the dimension component. For
/// example, if the dimension was set to 2, the output will contain all swizzling combinations that
/// contain the "z" component.
fn gen_swizzling_force_dim_component(
input_dim: usize,
dim: usize,
unique: bool,
) -> Vec<(Vec<String>, usize, Vec<usize>, Vec<usize>)> {
let axe = AXES[input_dim - 1];
gen_swizzling(input_dim, dim, unique)
.into_iter()
.filter(|(axes, _, _, _)| axes.contains(&axe.to_string()))
.collect()
}
fn gen_swizzling_macro_branch(input_dim: usize, unique: bool) -> String {
let mut out = String::new();
out.write_str(&format!(
"{}({}, $f: ident $(,$($args:tt)*)?) => {{ $f! {{ $([$($args)*])? {}\n",
indent(1),
input_dim,
input_dim,
))
.unwrap();
for dim in 1..input_dim {
for (axes, dim, ixs, ord) in gen_swizzling_force_dim_component(input_dim, dim, unique) {
out.write_str(&format!("{}{} {} {:?} {:?}\n", indent(2), axes.join(""), dim, ixs, ord))
.unwrap();
}
}
for (axes, dim, ixs, ord) in gen_swizzling(input_dim, input_dim, unique) {
out.write_str(&format!("{}{} {} {:?} {:?}\n", indent(2), axes.join(""), dim, ixs, ord))
.unwrap();
}
out.write_str(&format!("{}}}}};\n", indent(1))).unwrap();
out
}
/// The generated macro accepts two arguments, the dimension of the swizzling and another macro name
/// that should be called with the swizzling data. The provided macro will be called with the chosen
/// dimension and the data generated by the [`gen_swizzling_macro_branch`] function.
///
/// See the generated [`FILE`] to see the result of this script.
fn gen_swizzling_macro(unique: bool) -> String {
let mut out = String::new();
let sfx = if unique { "_unique" } else { "" };
out.write_str("/// Swizzling data for the given dimension.\n").unwrap();
out.write_str("/// See the [`build.rs`] file to learn more.\n").unwrap();
out.write_str("#[macro_export]\n").unwrap();
out.write_str(&format!("macro_rules! with_swizzling_for_dim{} {{\n", sfx)).unwrap();
out.write_str(&gen_swizzling_macro_branch(1, unique)).unwrap();
out.write_str(&gen_swizzling_macro_branch(2, unique)).unwrap();
out.write_str(&gen_swizzling_macro_branch(3, unique)).unwrap();
out.write_str(&gen_swizzling_macro_branch(4, unique)).unwrap();
out.write_str("}").unwrap();
out
}
fn main() {
println!("cargo:rerun-if-changed=build.rs");
let mut file = File::create(FILE).unwrap();
let warning = "THIS IS AN AUTO-GENERATED FILE. DO NOT EDIT IT DIRECTLY!";
let border = "!".repeat(warning.len());
let mut out = String::new();
out.write_str("//! Macros allowing generation of swizzling getters and setters.\n").unwrap();
out.write_str("//! See the docs of [`build.rs`] and usage places to learn more.\n").unwrap();
out.write_str(&format!("\n// {}\n", border)).unwrap();
out.write_str("// THIS IS AN AUTO-GENERATED FILE. DO NOT EDIT IT DIRECTLY!\n").unwrap();
out.write_str(&format!("// {}\n\n\n", border)).unwrap();
out.write_str(&gen_swizzling_macro(false)).unwrap();
out.write_str("\n\n").unwrap();
out.write_str(&gen_swizzling_macro(true)).unwrap();
out.write_str("\n").unwrap();
file.write_all(out.as_bytes()).unwrap();
}

File diff suppressed because it is too large Load Diff

157
lib/rust/types/src/dim.rs Normal file
View File

@ -0,0 +1,157 @@
//! Definition of Dim* traits. These traits define common operations on types that represent
//! dimensional transformations. For example, they define getters, such as `xy()`, or setters, such
//! as `set_xy(...)` on 2-dimensional types. Moreover, this module implements these traits for
//! suitable nalgebra's Vector types.
use enso_prelude::*;
use nalgebra;
use nalgebra::Scalar;
use nalgebra::Vector2;
use nalgebra::Vector3;
use nalgebra::Vector4;
// ===================
// === Dim* Traits ===
// ===================
macro_rules! gen_dim_trait {
([$prev_dim:tt] $dim:tt
$( $name:ident $swizzling_dim:tt [$($dim_ix:tt)*] [$($dim_ord:tt)*] )*
) => { paste! {
#[doc = "Component swizzling getters for "]
#[doc = stringify!($dim)]
#[doc = "`-dimensional types."]
#[allow(missing_docs)]
pub trait [<Dim $dim>] : [<Dim $prev_dim>] {
type [<Dim $dim Type>];
$(
fn $name(&self) -> Self::[<Dim $swizzling_dim Type>];
)*
}
}};
}
/// An abstract, 0-dimensional type. It is defined to simplify macro definition.
pub trait Dim0 {}
impl<T> Dim0 for T {}
crate::with_swizzling_for_dim!(1, gen_dim_trait, 0);
crate::with_swizzling_for_dim!(2, gen_dim_trait, 1);
crate::with_swizzling_for_dim!(3, gen_dim_trait, 2);
crate::with_swizzling_for_dim!(4, gen_dim_trait, 3);
// =========================
// === DimSetter* Traits ===
// =========================
macro_rules! gen_dim_setter_trait {
($dim:tt
$( $name:ident $swizzling_dim:tt [$($dim_ix:tt)*] [$($dim_ord:tt)*] )*
) => { paste! {
#[doc = "Component swizzling setters for "]
#[doc = stringify!($dim)]
#[doc = "`-dimensional types."]
#[allow(missing_docs)]
pub trait [<Dim Setter $dim>] : [<Dim $dim>] {
$(
fn [<set_$name>](&mut self, value: Self::[<Dim $swizzling_dim Type>]);
)*
}
}};
}
crate::with_swizzling_for_dim_unique!(1, gen_dim_setter_trait);
crate::with_swizzling_for_dim_unique!(2, gen_dim_setter_trait);
crate::with_swizzling_for_dim_unique!(3, gen_dim_setter_trait);
crate::with_swizzling_for_dim_unique!(4, gen_dim_setter_trait);
// =====================================
// === Getters for nalgebra::Vector* ===
// =====================================
macro_rules! gen_dim_impl_for_vector {
([$vec:tt] $dim:tt $( $name:ident $swizzling_dim:tt [$($dim_ix:tt)*] [$($dim_ord:tt)*] )*) => {
paste! {
impl<T: Scalar + Copy> [<Dim $dim>] for $vec<T> {
type [<Dim $dim Type>] = [<Vector $dim>]<T>;
$(
fn $name(&self) -> Self::[<Dim $swizzling_dim Type>] {
gen_dim_impl_for_vector_body!{self, $swizzling_dim, [$($dim_ix)*]}
}
)*
}
}
};
}
macro_rules! gen_dim_impl_for_vector_body {
($this:tt, $swizzling_dim:tt, [$dim_ix:tt]) => {
$this[$dim_ix]
};
($this:tt, $swizzling_dim:tt, [$($dim_ix:tt),*]) => { paste! {
Self::[<Dim $swizzling_dim Type>]::new( $( $this[$dim_ix] ),* )
}};
}
/// A one dimensional vector, being just a value. It is used mostly to simplify macro definitions.
pub type Vector1<T> = T;
crate::with_swizzling_for_dim!(1, gen_dim_impl_for_vector, Vector2);
crate::with_swizzling_for_dim!(2, gen_dim_impl_for_vector, Vector2);
crate::with_swizzling_for_dim!(1, gen_dim_impl_for_vector, Vector3);
crate::with_swizzling_for_dim!(2, gen_dim_impl_for_vector, Vector3);
crate::with_swizzling_for_dim!(3, gen_dim_impl_for_vector, Vector3);
crate::with_swizzling_for_dim!(1, gen_dim_impl_for_vector, Vector4);
crate::with_swizzling_for_dim!(2, gen_dim_impl_for_vector, Vector4);
crate::with_swizzling_for_dim!(3, gen_dim_impl_for_vector, Vector4);
crate::with_swizzling_for_dim!(4, gen_dim_impl_for_vector, Vector4);
// =====================================
// === Setters for nalgebra::Vector* ===
// =====================================
macro_rules! gen_dim_setter_impl_for_vector {
([$vec:tt] $dim:tt $( $name:ident $swizzling_dim:tt [$($dim_ix:tt)*] [$($dim_ord:tt)*] )*) => {
paste! {
impl<T: Scalar + Copy> [<Dim Setter $dim>] for $vec<T> {
$(
fn [<set_ $name>](&mut self, value: Self::[<Dim $swizzling_dim Type>]) {
gen_dim_setter_impl_for_vector_body!{self, value, $swizzling_dim, [$($dim_ix)*], [$($dim_ord)*]}
}
)*
}
}
};
}
macro_rules! gen_dim_setter_impl_for_vector_body {
($this:tt, $value:tt, $swizzling_dim:tt, [$dim_ix:tt], [$($dim_ord:tt),*]) => {
$this[$dim_ix] = $value;
};
($this:tt, $value:tt, $swizzling_dim:tt, [$($dim_ix:tt),*], [$($dim_ord:tt),*]) => { paste! {
$( $this[$dim_ix] = $value[$dim_ord]; )*
}};
}
crate::with_swizzling_for_dim_unique!(1, gen_dim_setter_impl_for_vector, Vector2);
crate::with_swizzling_for_dim_unique!(2, gen_dim_setter_impl_for_vector, Vector2);
crate::with_swizzling_for_dim_unique!(1, gen_dim_setter_impl_for_vector, Vector3);
crate::with_swizzling_for_dim_unique!(2, gen_dim_setter_impl_for_vector, Vector3);
crate::with_swizzling_for_dim_unique!(3, gen_dim_setter_impl_for_vector, Vector3);
crate::with_swizzling_for_dim_unique!(1, gen_dim_setter_impl_for_vector, Vector4);
crate::with_swizzling_for_dim_unique!(2, gen_dim_setter_impl_for_vector, Vector4);
crate::with_swizzling_for_dim_unique!(3, gen_dim_setter_impl_for_vector, Vector4);
crate::with_swizzling_for_dim_unique!(4, gen_dim_setter_impl_for_vector, Vector4);

View File

@ -0,0 +1,441 @@
//! Macros allowing generation of swizzling getters and setters.
//! See the docs of [`build.rs`] and usage places to learn more.
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// THIS IS AN AUTO-GENERATED FILE. DO NOT EDIT IT DIRECTLY!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
/// Swizzling data for the given dimension.
/// See the [`build.rs`] file to learn more.
#[macro_export]
macro_rules! with_swizzling_for_dim {
(1, $f: ident $(,$($args:tt)*)?) => { $f! { $([$($args)*])? 1
x 1 [0] [0]
}};
(2, $f: ident $(,$($args:tt)*)?) => { $f! { $([$($args)*])? 2
y 1 [1] [0]
xx 2 [0, 0] [0, 1]
xy 2 [0, 1] [0, 1]
yx 2 [1, 0] [0, 1]
yy 2 [1, 1] [0, 1]
}};
(3, $f: ident $(,$($args:tt)*)?) => { $f! { $([$($args)*])? 3
z 1 [2] [0]
xz 2 [0, 2] [0, 1]
yz 2 [1, 2] [0, 1]
zx 2 [2, 0] [0, 1]
zy 2 [2, 1] [0, 1]
zz 2 [2, 2] [0, 1]
xxx 3 [0, 0, 0] [0, 1, 2]
xxy 3 [0, 0, 1] [0, 1, 2]
xxz 3 [0, 0, 2] [0, 1, 2]
xyx 3 [0, 1, 0] [0, 1, 2]
xyy 3 [0, 1, 1] [0, 1, 2]
xyz 3 [0, 1, 2] [0, 1, 2]
xzx 3 [0, 2, 0] [0, 1, 2]
xzy 3 [0, 2, 1] [0, 1, 2]
xzz 3 [0, 2, 2] [0, 1, 2]
yxx 3 [1, 0, 0] [0, 1, 2]
yxy 3 [1, 0, 1] [0, 1, 2]
yxz 3 [1, 0, 2] [0, 1, 2]
yyx 3 [1, 1, 0] [0, 1, 2]
yyy 3 [1, 1, 1] [0, 1, 2]
yyz 3 [1, 1, 2] [0, 1, 2]
yzx 3 [1, 2, 0] [0, 1, 2]
yzy 3 [1, 2, 1] [0, 1, 2]
yzz 3 [1, 2, 2] [0, 1, 2]
zxx 3 [2, 0, 0] [0, 1, 2]
zxy 3 [2, 0, 1] [0, 1, 2]
zxz 3 [2, 0, 2] [0, 1, 2]
zyx 3 [2, 1, 0] [0, 1, 2]
zyy 3 [2, 1, 1] [0, 1, 2]
zyz 3 [2, 1, 2] [0, 1, 2]
zzx 3 [2, 2, 0] [0, 1, 2]
zzy 3 [2, 2, 1] [0, 1, 2]
zzz 3 [2, 2, 2] [0, 1, 2]
}};
(4, $f: ident $(,$($args:tt)*)?) => { $f! { $([$($args)*])? 4
w 1 [3] [0]
xw 2 [0, 3] [0, 1]
yw 2 [1, 3] [0, 1]
zw 2 [2, 3] [0, 1]
wx 2 [3, 0] [0, 1]
wy 2 [3, 1] [0, 1]
wz 2 [3, 2] [0, 1]
ww 2 [3, 3] [0, 1]
xxw 3 [0, 0, 3] [0, 1, 2]
xyw 3 [0, 1, 3] [0, 1, 2]
xzw 3 [0, 2, 3] [0, 1, 2]
xwx 3 [0, 3, 0] [0, 1, 2]
xwy 3 [0, 3, 1] [0, 1, 2]
xwz 3 [0, 3, 2] [0, 1, 2]
xww 3 [0, 3, 3] [0, 1, 2]
yxw 3 [1, 0, 3] [0, 1, 2]
yyw 3 [1, 1, 3] [0, 1, 2]
yzw 3 [1, 2, 3] [0, 1, 2]
ywx 3 [1, 3, 0] [0, 1, 2]
ywy 3 [1, 3, 1] [0, 1, 2]
ywz 3 [1, 3, 2] [0, 1, 2]
yww 3 [1, 3, 3] [0, 1, 2]
zxw 3 [2, 0, 3] [0, 1, 2]
zyw 3 [2, 1, 3] [0, 1, 2]
zzw 3 [2, 2, 3] [0, 1, 2]
zwx 3 [2, 3, 0] [0, 1, 2]
zwy 3 [2, 3, 1] [0, 1, 2]
zwz 3 [2, 3, 2] [0, 1, 2]
zww 3 [2, 3, 3] [0, 1, 2]
wxx 3 [3, 0, 0] [0, 1, 2]
wxy 3 [3, 0, 1] [0, 1, 2]
wxz 3 [3, 0, 2] [0, 1, 2]
wxw 3 [3, 0, 3] [0, 1, 2]
wyx 3 [3, 1, 0] [0, 1, 2]
wyy 3 [3, 1, 1] [0, 1, 2]
wyz 3 [3, 1, 2] [0, 1, 2]
wyw 3 [3, 1, 3] [0, 1, 2]
wzx 3 [3, 2, 0] [0, 1, 2]
wzy 3 [3, 2, 1] [0, 1, 2]
wzz 3 [3, 2, 2] [0, 1, 2]
wzw 3 [3, 2, 3] [0, 1, 2]
wwx 3 [3, 3, 0] [0, 1, 2]
wwy 3 [3, 3, 1] [0, 1, 2]
wwz 3 [3, 3, 2] [0, 1, 2]
www 3 [3, 3, 3] [0, 1, 2]
xxxx 4 [0, 0, 0, 0] [0, 1, 2, 3]
xxxy 4 [0, 0, 0, 1] [0, 1, 2, 3]
xxxz 4 [0, 0, 0, 2] [0, 1, 2, 3]
xxxw 4 [0, 0, 0, 3] [0, 1, 2, 3]
xxyx 4 [0, 0, 1, 0] [0, 1, 2, 3]
xxyy 4 [0, 0, 1, 1] [0, 1, 2, 3]
xxyz 4 [0, 0, 1, 2] [0, 1, 2, 3]
xxyw 4 [0, 0, 1, 3] [0, 1, 2, 3]
xxzx 4 [0, 0, 2, 0] [0, 1, 2, 3]
xxzy 4 [0, 0, 2, 1] [0, 1, 2, 3]
xxzz 4 [0, 0, 2, 2] [0, 1, 2, 3]
xxzw 4 [0, 0, 2, 3] [0, 1, 2, 3]
xxwx 4 [0, 0, 3, 0] [0, 1, 2, 3]
xxwy 4 [0, 0, 3, 1] [0, 1, 2, 3]
xxwz 4 [0, 0, 3, 2] [0, 1, 2, 3]
xxww 4 [0, 0, 3, 3] [0, 1, 2, 3]
xyxx 4 [0, 1, 0, 0] [0, 1, 2, 3]
xyxy 4 [0, 1, 0, 1] [0, 1, 2, 3]
xyxz 4 [0, 1, 0, 2] [0, 1, 2, 3]
xyxw 4 [0, 1, 0, 3] [0, 1, 2, 3]
xyyx 4 [0, 1, 1, 0] [0, 1, 2, 3]
xyyy 4 [0, 1, 1, 1] [0, 1, 2, 3]
xyyz 4 [0, 1, 1, 2] [0, 1, 2, 3]
xyyw 4 [0, 1, 1, 3] [0, 1, 2, 3]
xyzx 4 [0, 1, 2, 0] [0, 1, 2, 3]
xyzy 4 [0, 1, 2, 1] [0, 1, 2, 3]
xyzz 4 [0, 1, 2, 2] [0, 1, 2, 3]
xyzw 4 [0, 1, 2, 3] [0, 1, 2, 3]
xywx 4 [0, 1, 3, 0] [0, 1, 2, 3]
xywy 4 [0, 1, 3, 1] [0, 1, 2, 3]
xywz 4 [0, 1, 3, 2] [0, 1, 2, 3]
xyww 4 [0, 1, 3, 3] [0, 1, 2, 3]
xzxx 4 [0, 2, 0, 0] [0, 1, 2, 3]
xzxy 4 [0, 2, 0, 1] [0, 1, 2, 3]
xzxz 4 [0, 2, 0, 2] [0, 1, 2, 3]
xzxw 4 [0, 2, 0, 3] [0, 1, 2, 3]
xzyx 4 [0, 2, 1, 0] [0, 1, 2, 3]
xzyy 4 [0, 2, 1, 1] [0, 1, 2, 3]
xzyz 4 [0, 2, 1, 2] [0, 1, 2, 3]
xzyw 4 [0, 2, 1, 3] [0, 1, 2, 3]
xzzx 4 [0, 2, 2, 0] [0, 1, 2, 3]
xzzy 4 [0, 2, 2, 1] [0, 1, 2, 3]
xzzz 4 [0, 2, 2, 2] [0, 1, 2, 3]
xzzw 4 [0, 2, 2, 3] [0, 1, 2, 3]
xzwx 4 [0, 2, 3, 0] [0, 1, 2, 3]
xzwy 4 [0, 2, 3, 1] [0, 1, 2, 3]
xzwz 4 [0, 2, 3, 2] [0, 1, 2, 3]
xzww 4 [0, 2, 3, 3] [0, 1, 2, 3]
xwxx 4 [0, 3, 0, 0] [0, 1, 2, 3]
xwxy 4 [0, 3, 0, 1] [0, 1, 2, 3]
xwxz 4 [0, 3, 0, 2] [0, 1, 2, 3]
xwxw 4 [0, 3, 0, 3] [0, 1, 2, 3]
xwyx 4 [0, 3, 1, 0] [0, 1, 2, 3]
xwyy 4 [0, 3, 1, 1] [0, 1, 2, 3]
xwyz 4 [0, 3, 1, 2] [0, 1, 2, 3]
xwyw 4 [0, 3, 1, 3] [0, 1, 2, 3]
xwzx 4 [0, 3, 2, 0] [0, 1, 2, 3]
xwzy 4 [0, 3, 2, 1] [0, 1, 2, 3]
xwzz 4 [0, 3, 2, 2] [0, 1, 2, 3]
xwzw 4 [0, 3, 2, 3] [0, 1, 2, 3]
xwwx 4 [0, 3, 3, 0] [0, 1, 2, 3]
xwwy 4 [0, 3, 3, 1] [0, 1, 2, 3]
xwwz 4 [0, 3, 3, 2] [0, 1, 2, 3]
xwww 4 [0, 3, 3, 3] [0, 1, 2, 3]
yxxx 4 [1, 0, 0, 0] [0, 1, 2, 3]
yxxy 4 [1, 0, 0, 1] [0, 1, 2, 3]
yxxz 4 [1, 0, 0, 2] [0, 1, 2, 3]
yxxw 4 [1, 0, 0, 3] [0, 1, 2, 3]
yxyx 4 [1, 0, 1, 0] [0, 1, 2, 3]
yxyy 4 [1, 0, 1, 1] [0, 1, 2, 3]
yxyz 4 [1, 0, 1, 2] [0, 1, 2, 3]
yxyw 4 [1, 0, 1, 3] [0, 1, 2, 3]
yxzx 4 [1, 0, 2, 0] [0, 1, 2, 3]
yxzy 4 [1, 0, 2, 1] [0, 1, 2, 3]
yxzz 4 [1, 0, 2, 2] [0, 1, 2, 3]
yxzw 4 [1, 0, 2, 3] [0, 1, 2, 3]
yxwx 4 [1, 0, 3, 0] [0, 1, 2, 3]
yxwy 4 [1, 0, 3, 1] [0, 1, 2, 3]
yxwz 4 [1, 0, 3, 2] [0, 1, 2, 3]
yxww 4 [1, 0, 3, 3] [0, 1, 2, 3]
yyxx 4 [1, 1, 0, 0] [0, 1, 2, 3]
yyxy 4 [1, 1, 0, 1] [0, 1, 2, 3]
yyxz 4 [1, 1, 0, 2] [0, 1, 2, 3]
yyxw 4 [1, 1, 0, 3] [0, 1, 2, 3]
yyyx 4 [1, 1, 1, 0] [0, 1, 2, 3]
yyyy 4 [1, 1, 1, 1] [0, 1, 2, 3]
yyyz 4 [1, 1, 1, 2] [0, 1, 2, 3]
yyyw 4 [1, 1, 1, 3] [0, 1, 2, 3]
yyzx 4 [1, 1, 2, 0] [0, 1, 2, 3]
yyzy 4 [1, 1, 2, 1] [0, 1, 2, 3]
yyzz 4 [1, 1, 2, 2] [0, 1, 2, 3]
yyzw 4 [1, 1, 2, 3] [0, 1, 2, 3]
yywx 4 [1, 1, 3, 0] [0, 1, 2, 3]
yywy 4 [1, 1, 3, 1] [0, 1, 2, 3]
yywz 4 [1, 1, 3, 2] [0, 1, 2, 3]
yyww 4 [1, 1, 3, 3] [0, 1, 2, 3]
yzxx 4 [1, 2, 0, 0] [0, 1, 2, 3]
yzxy 4 [1, 2, 0, 1] [0, 1, 2, 3]
yzxz 4 [1, 2, 0, 2] [0, 1, 2, 3]
yzxw 4 [1, 2, 0, 3] [0, 1, 2, 3]
yzyx 4 [1, 2, 1, 0] [0, 1, 2, 3]
yzyy 4 [1, 2, 1, 1] [0, 1, 2, 3]
yzyz 4 [1, 2, 1, 2] [0, 1, 2, 3]
yzyw 4 [1, 2, 1, 3] [0, 1, 2, 3]
yzzx 4 [1, 2, 2, 0] [0, 1, 2, 3]
yzzy 4 [1, 2, 2, 1] [0, 1, 2, 3]
yzzz 4 [1, 2, 2, 2] [0, 1, 2, 3]
yzzw 4 [1, 2, 2, 3] [0, 1, 2, 3]
yzwx 4 [1, 2, 3, 0] [0, 1, 2, 3]
yzwy 4 [1, 2, 3, 1] [0, 1, 2, 3]
yzwz 4 [1, 2, 3, 2] [0, 1, 2, 3]
yzww 4 [1, 2, 3, 3] [0, 1, 2, 3]
ywxx 4 [1, 3, 0, 0] [0, 1, 2, 3]
ywxy 4 [1, 3, 0, 1] [0, 1, 2, 3]
ywxz 4 [1, 3, 0, 2] [0, 1, 2, 3]
ywxw 4 [1, 3, 0, 3] [0, 1, 2, 3]
ywyx 4 [1, 3, 1, 0] [0, 1, 2, 3]
ywyy 4 [1, 3, 1, 1] [0, 1, 2, 3]
ywyz 4 [1, 3, 1, 2] [0, 1, 2, 3]
ywyw 4 [1, 3, 1, 3] [0, 1, 2, 3]
ywzx 4 [1, 3, 2, 0] [0, 1, 2, 3]
ywzy 4 [1, 3, 2, 1] [0, 1, 2, 3]
ywzz 4 [1, 3, 2, 2] [0, 1, 2, 3]
ywzw 4 [1, 3, 2, 3] [0, 1, 2, 3]
ywwx 4 [1, 3, 3, 0] [0, 1, 2, 3]
ywwy 4 [1, 3, 3, 1] [0, 1, 2, 3]
ywwz 4 [1, 3, 3, 2] [0, 1, 2, 3]
ywww 4 [1, 3, 3, 3] [0, 1, 2, 3]
zxxx 4 [2, 0, 0, 0] [0, 1, 2, 3]
zxxy 4 [2, 0, 0, 1] [0, 1, 2, 3]
zxxz 4 [2, 0, 0, 2] [0, 1, 2, 3]
zxxw 4 [2, 0, 0, 3] [0, 1, 2, 3]
zxyx 4 [2, 0, 1, 0] [0, 1, 2, 3]
zxyy 4 [2, 0, 1, 1] [0, 1, 2, 3]
zxyz 4 [2, 0, 1, 2] [0, 1, 2, 3]
zxyw 4 [2, 0, 1, 3] [0, 1, 2, 3]
zxzx 4 [2, 0, 2, 0] [0, 1, 2, 3]
zxzy 4 [2, 0, 2, 1] [0, 1, 2, 3]
zxzz 4 [2, 0, 2, 2] [0, 1, 2, 3]
zxzw 4 [2, 0, 2, 3] [0, 1, 2, 3]
zxwx 4 [2, 0, 3, 0] [0, 1, 2, 3]
zxwy 4 [2, 0, 3, 1] [0, 1, 2, 3]
zxwz 4 [2, 0, 3, 2] [0, 1, 2, 3]
zxww 4 [2, 0, 3, 3] [0, 1, 2, 3]
zyxx 4 [2, 1, 0, 0] [0, 1, 2, 3]
zyxy 4 [2, 1, 0, 1] [0, 1, 2, 3]
zyxz 4 [2, 1, 0, 2] [0, 1, 2, 3]
zyxw 4 [2, 1, 0, 3] [0, 1, 2, 3]
zyyx 4 [2, 1, 1, 0] [0, 1, 2, 3]
zyyy 4 [2, 1, 1, 1] [0, 1, 2, 3]
zyyz 4 [2, 1, 1, 2] [0, 1, 2, 3]
zyyw 4 [2, 1, 1, 3] [0, 1, 2, 3]
zyzx 4 [2, 1, 2, 0] [0, 1, 2, 3]
zyzy 4 [2, 1, 2, 1] [0, 1, 2, 3]
zyzz 4 [2, 1, 2, 2] [0, 1, 2, 3]
zyzw 4 [2, 1, 2, 3] [0, 1, 2, 3]
zywx 4 [2, 1, 3, 0] [0, 1, 2, 3]
zywy 4 [2, 1, 3, 1] [0, 1, 2, 3]
zywz 4 [2, 1, 3, 2] [0, 1, 2, 3]
zyww 4 [2, 1, 3, 3] [0, 1, 2, 3]
zzxx 4 [2, 2, 0, 0] [0, 1, 2, 3]
zzxy 4 [2, 2, 0, 1] [0, 1, 2, 3]
zzxz 4 [2, 2, 0, 2] [0, 1, 2, 3]
zzxw 4 [2, 2, 0, 3] [0, 1, 2, 3]
zzyx 4 [2, 2, 1, 0] [0, 1, 2, 3]
zzyy 4 [2, 2, 1, 1] [0, 1, 2, 3]
zzyz 4 [2, 2, 1, 2] [0, 1, 2, 3]
zzyw 4 [2, 2, 1, 3] [0, 1, 2, 3]
zzzx 4 [2, 2, 2, 0] [0, 1, 2, 3]
zzzy 4 [2, 2, 2, 1] [0, 1, 2, 3]
zzzz 4 [2, 2, 2, 2] [0, 1, 2, 3]
zzzw 4 [2, 2, 2, 3] [0, 1, 2, 3]
zzwx 4 [2, 2, 3, 0] [0, 1, 2, 3]
zzwy 4 [2, 2, 3, 1] [0, 1, 2, 3]
zzwz 4 [2, 2, 3, 2] [0, 1, 2, 3]
zzww 4 [2, 2, 3, 3] [0, 1, 2, 3]
zwxx 4 [2, 3, 0, 0] [0, 1, 2, 3]
zwxy 4 [2, 3, 0, 1] [0, 1, 2, 3]
zwxz 4 [2, 3, 0, 2] [0, 1, 2, 3]
zwxw 4 [2, 3, 0, 3] [0, 1, 2, 3]
zwyx 4 [2, 3, 1, 0] [0, 1, 2, 3]
zwyy 4 [2, 3, 1, 1] [0, 1, 2, 3]
zwyz 4 [2, 3, 1, 2] [0, 1, 2, 3]
zwyw 4 [2, 3, 1, 3] [0, 1, 2, 3]
zwzx 4 [2, 3, 2, 0] [0, 1, 2, 3]
zwzy 4 [2, 3, 2, 1] [0, 1, 2, 3]
zwzz 4 [2, 3, 2, 2] [0, 1, 2, 3]
zwzw 4 [2, 3, 2, 3] [0, 1, 2, 3]
zwwx 4 [2, 3, 3, 0] [0, 1, 2, 3]
zwwy 4 [2, 3, 3, 1] [0, 1, 2, 3]
zwwz 4 [2, 3, 3, 2] [0, 1, 2, 3]
zwww 4 [2, 3, 3, 3] [0, 1, 2, 3]
wxxx 4 [3, 0, 0, 0] [0, 1, 2, 3]
wxxy 4 [3, 0, 0, 1] [0, 1, 2, 3]
wxxz 4 [3, 0, 0, 2] [0, 1, 2, 3]
wxxw 4 [3, 0, 0, 3] [0, 1, 2, 3]
wxyx 4 [3, 0, 1, 0] [0, 1, 2, 3]
wxyy 4 [3, 0, 1, 1] [0, 1, 2, 3]
wxyz 4 [3, 0, 1, 2] [0, 1, 2, 3]
wxyw 4 [3, 0, 1, 3] [0, 1, 2, 3]
wxzx 4 [3, 0, 2, 0] [0, 1, 2, 3]
wxzy 4 [3, 0, 2, 1] [0, 1, 2, 3]
wxzz 4 [3, 0, 2, 2] [0, 1, 2, 3]
wxzw 4 [3, 0, 2, 3] [0, 1, 2, 3]
wxwx 4 [3, 0, 3, 0] [0, 1, 2, 3]
wxwy 4 [3, 0, 3, 1] [0, 1, 2, 3]
wxwz 4 [3, 0, 3, 2] [0, 1, 2, 3]
wxww 4 [3, 0, 3, 3] [0, 1, 2, 3]
wyxx 4 [3, 1, 0, 0] [0, 1, 2, 3]
wyxy 4 [3, 1, 0, 1] [0, 1, 2, 3]
wyxz 4 [3, 1, 0, 2] [0, 1, 2, 3]
wyxw 4 [3, 1, 0, 3] [0, 1, 2, 3]
wyyx 4 [3, 1, 1, 0] [0, 1, 2, 3]
wyyy 4 [3, 1, 1, 1] [0, 1, 2, 3]
wyyz 4 [3, 1, 1, 2] [0, 1, 2, 3]
wyyw 4 [3, 1, 1, 3] [0, 1, 2, 3]
wyzx 4 [3, 1, 2, 0] [0, 1, 2, 3]
wyzy 4 [3, 1, 2, 1] [0, 1, 2, 3]
wyzz 4 [3, 1, 2, 2] [0, 1, 2, 3]
wyzw 4 [3, 1, 2, 3] [0, 1, 2, 3]
wywx 4 [3, 1, 3, 0] [0, 1, 2, 3]
wywy 4 [3, 1, 3, 1] [0, 1, 2, 3]
wywz 4 [3, 1, 3, 2] [0, 1, 2, 3]
wyww 4 [3, 1, 3, 3] [0, 1, 2, 3]
wzxx 4 [3, 2, 0, 0] [0, 1, 2, 3]
wzxy 4 [3, 2, 0, 1] [0, 1, 2, 3]
wzxz 4 [3, 2, 0, 2] [0, 1, 2, 3]
wzxw 4 [3, 2, 0, 3] [0, 1, 2, 3]
wzyx 4 [3, 2, 1, 0] [0, 1, 2, 3]
wzyy 4 [3, 2, 1, 1] [0, 1, 2, 3]
wzyz 4 [3, 2, 1, 2] [0, 1, 2, 3]
wzyw 4 [3, 2, 1, 3] [0, 1, 2, 3]
wzzx 4 [3, 2, 2, 0] [0, 1, 2, 3]
wzzy 4 [3, 2, 2, 1] [0, 1, 2, 3]
wzzz 4 [3, 2, 2, 2] [0, 1, 2, 3]
wzzw 4 [3, 2, 2, 3] [0, 1, 2, 3]
wzwx 4 [3, 2, 3, 0] [0, 1, 2, 3]
wzwy 4 [3, 2, 3, 1] [0, 1, 2, 3]
wzwz 4 [3, 2, 3, 2] [0, 1, 2, 3]
wzww 4 [3, 2, 3, 3] [0, 1, 2, 3]
wwxx 4 [3, 3, 0, 0] [0, 1, 2, 3]
wwxy 4 [3, 3, 0, 1] [0, 1, 2, 3]
wwxz 4 [3, 3, 0, 2] [0, 1, 2, 3]
wwxw 4 [3, 3, 0, 3] [0, 1, 2, 3]
wwyx 4 [3, 3, 1, 0] [0, 1, 2, 3]
wwyy 4 [3, 3, 1, 1] [0, 1, 2, 3]
wwyz 4 [3, 3, 1, 2] [0, 1, 2, 3]
wwyw 4 [3, 3, 1, 3] [0, 1, 2, 3]
wwzx 4 [3, 3, 2, 0] [0, 1, 2, 3]
wwzy 4 [3, 3, 2, 1] [0, 1, 2, 3]
wwzz 4 [3, 3, 2, 2] [0, 1, 2, 3]
wwzw 4 [3, 3, 2, 3] [0, 1, 2, 3]
wwwx 4 [3, 3, 3, 0] [0, 1, 2, 3]
wwwy 4 [3, 3, 3, 1] [0, 1, 2, 3]
wwwz 4 [3, 3, 3, 2] [0, 1, 2, 3]
wwww 4 [3, 3, 3, 3] [0, 1, 2, 3]
}};
}
/// Swizzling data for the given dimension.
/// See the [`build.rs`] file to learn more.
#[macro_export]
macro_rules! with_swizzling_for_dim_unique {
(1, $f: ident $(,$($args:tt)*)?) => { $f! { $([$($args)*])? 1
x 1 [0] [0]
}};
(2, $f: ident $(,$($args:tt)*)?) => { $f! { $([$($args)*])? 2
y 1 [1] [0]
xy 2 [0, 1] [0, 1]
yx 2 [1, 0] [0, 1]
}};
(3, $f: ident $(,$($args:tt)*)?) => { $f! { $([$($args)*])? 3
z 1 [2] [0]
xz 2 [0, 2] [0, 1]
yz 2 [1, 2] [0, 1]
zx 2 [2, 0] [0, 1]
zy 2 [2, 1] [0, 1]
xyz 3 [0, 1, 2] [0, 1, 2]
xzy 3 [0, 2, 1] [0, 1, 2]
yxz 3 [1, 0, 2] [0, 1, 2]
yzx 3 [1, 2, 0] [0, 1, 2]
zxy 3 [2, 0, 1] [0, 1, 2]
zyx 3 [2, 1, 0] [0, 1, 2]
}};
(4, $f: ident $(,$($args:tt)*)?) => { $f! { $([$($args)*])? 4
w 1 [3] [0]
xw 2 [0, 3] [0, 1]
yw 2 [1, 3] [0, 1]
zw 2 [2, 3] [0, 1]
wx 2 [3, 0] [0, 1]
wy 2 [3, 1] [0, 1]
wz 2 [3, 2] [0, 1]
xyw 3 [0, 1, 3] [0, 1, 2]
xzw 3 [0, 2, 3] [0, 1, 2]
xwy 3 [0, 3, 1] [0, 1, 2]
xwz 3 [0, 3, 2] [0, 1, 2]
yxw 3 [1, 0, 3] [0, 1, 2]
yzw 3 [1, 2, 3] [0, 1, 2]
ywx 3 [1, 3, 0] [0, 1, 2]
ywz 3 [1, 3, 2] [0, 1, 2]
zxw 3 [2, 0, 3] [0, 1, 2]
zyw 3 [2, 1, 3] [0, 1, 2]
zwx 3 [2, 3, 0] [0, 1, 2]
zwy 3 [2, 3, 1] [0, 1, 2]
wxy 3 [3, 0, 1] [0, 1, 2]
wxz 3 [3, 0, 2] [0, 1, 2]
wyx 3 [3, 1, 0] [0, 1, 2]
wyz 3 [3, 1, 2] [0, 1, 2]
wzx 3 [3, 2, 0] [0, 1, 2]
wzy 3 [3, 2, 1] [0, 1, 2]
xyzw 4 [0, 1, 2, 3] [0, 1, 2, 3]
xywz 4 [0, 1, 3, 2] [0, 1, 2, 3]
xzyw 4 [0, 2, 1, 3] [0, 1, 2, 3]
xzwy 4 [0, 2, 3, 1] [0, 1, 2, 3]
xwyz 4 [0, 3, 1, 2] [0, 1, 2, 3]
xwzy 4 [0, 3, 2, 1] [0, 1, 2, 3]
yxzw 4 [1, 0, 2, 3] [0, 1, 2, 3]
yxwz 4 [1, 0, 3, 2] [0, 1, 2, 3]
yzxw 4 [1, 2, 0, 3] [0, 1, 2, 3]
yzwx 4 [1, 2, 3, 0] [0, 1, 2, 3]
ywxz 4 [1, 3, 0, 2] [0, 1, 2, 3]
ywzx 4 [1, 3, 2, 0] [0, 1, 2, 3]
zxyw 4 [2, 0, 1, 3] [0, 1, 2, 3]
zxwy 4 [2, 0, 3, 1] [0, 1, 2, 3]
zyxw 4 [2, 1, 0, 3] [0, 1, 2, 3]
zywx 4 [2, 1, 3, 0] [0, 1, 2, 3]
zwxy 4 [2, 3, 0, 1] [0, 1, 2, 3]
zwyx 4 [2, 3, 1, 0] [0, 1, 2, 3]
wxyz 4 [3, 0, 1, 2] [0, 1, 2, 3]
wxzy 4 [3, 0, 2, 1] [0, 1, 2, 3]
wyxz 4 [3, 1, 0, 2] [0, 1, 2, 3]
wyzx 4 [3, 1, 2, 0] [0, 1, 2, 3]
wzxy 4 [3, 2, 0, 1] [0, 1, 2, 3]
wzyx 4 [3, 2, 1, 0] [0, 1, 2, 3]
}};
}

Some files were not shown because too many files have changed in this diff Show More