mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 08:21:49 +03:00
Display object refactoring (#3877)
This commit is contained in:
parent
4e30b3036d
commit
d60e3835f2
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2373,6 +2373,7 @@ dependencies = [
|
||||
name = "enso-types"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"enso-prelude",
|
||||
"enso-reflect",
|
||||
"nalgebra",
|
||||
"num-traits",
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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()));
|
||||
|
@ -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.
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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));
|
||||
|
||||
|
||||
|
@ -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 ===
|
||||
|
@ -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);
|
||||
});
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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 }
|
||||
|
@ -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)));
|
||||
};
|
||||
|
@ -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));
|
||||
})
|
||||
);
|
||||
|
@ -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 }
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
});
|
||||
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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));
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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()));
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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 ===
|
||||
// ============
|
||||
|
||||
define_flag! {
|
||||
/// The on / off dirty flag. If you need a simple dirty / clean switch, this one
|
||||
/// is the right choice.
|
||||
Bool
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/// 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 ===
|
||||
// =============
|
||||
|
||||
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 ===
|
||||
// ==============
|
||||
|
||||
define_flag! {
|
||||
/// 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>;
|
||||
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>,
|
||||
|
@ -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 }
|
||||
}
|
||||
|
@ -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) {
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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
|
@ -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,17 +137,19 @@ 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) {
|
||||
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();
|
||||
@ -158,24 +162,46 @@ impl Mouse {
|
||||
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, ¤t_js_event);
|
||||
let mouse = Mouse::new(&frp, &dom.root, &variables, ¤t_js_event, &display_mode);
|
||||
let disable_context_menu = Rc::new(web::ignore_context_menu(&dom.root));
|
||||
let keyboard = Keyboard::new(¤t_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
|
||||
}
|
||||
|
@ -210,15 +210,8 @@ 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)
|
||||
}));
|
||||
}
|
||||
|
||||
/// Update the objects to match the new camera's point of view. This function should be called
|
||||
/// only after camera position change.
|
||||
@ -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);
|
||||
|
@ -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 ===
|
||||
// ==================
|
||||
|
@ -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)
|
||||
|
@ -6,6 +6,7 @@
|
||||
// ==============
|
||||
|
||||
pub mod def;
|
||||
pub mod glsl;
|
||||
pub mod shader;
|
||||
pub mod style_watch;
|
||||
pub mod system;
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 ===
|
||||
// =========================
|
||||
|
8
lib/rust/ensogl/core/src/display/shape/primitive/glsl.rs
Normal file
8
lib/rust/ensogl/core/src/display/shape/primitive/glsl.rs
Normal file
@ -0,0 +1,8 @@
|
||||
//! GLSL constants and utilities.
|
||||
|
||||
|
||||
// ==============
|
||||
// === Export ===
|
||||
// ==============
|
||||
|
||||
pub mod codes;
|
@ -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
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
// =================================================================================================
|
||||
// === Colorspaces Definition ======================================================================
|
||||
// === Color spaces definition =====================================================================
|
||||
// =================================================================================================
|
||||
|
||||
/// Helper for colors definition.
|
||||
@ -12,7 +12,7 @@
|
||||
/// All component values are in range 0.0..1.0.
|
||||
|
||||
|
||||
#define DEF_COLOR(type_name3,type_name4,name3,name4,t1,t2,t3) \
|
||||
#define DEF_COLOR(TYPE_NAME_3, TYPE_NAME_4, NAME_3, NAME_4, T_1, T_2, T_3) \
|
||||
\
|
||||
/* ============================= */ \
|
||||
/* === Non Transparent Color === */ \
|
||||
@ -20,30 +20,30 @@
|
||||
\
|
||||
/* === Definition === */ \
|
||||
\
|
||||
struct type_name3 { \
|
||||
struct TYPE_NAME_3 { \
|
||||
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; } \
|
||||
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_name3 name3(type_name3 identity) { \
|
||||
TYPE_NAME_3 NAME_3(TYPE_NAME_3 identity) { \
|
||||
return identity; \
|
||||
} \
|
||||
\
|
||||
type_name3 name3(vec3 raw) { \
|
||||
return type_name3(raw); \
|
||||
TYPE_NAME_3 NAME_3(vec3 raw) { \
|
||||
return TYPE_NAME_3(raw); \
|
||||
} \
|
||||
\
|
||||
type_name3 name3(float t1, float t2, float t3) { \
|
||||
return name3(vec3(t1,t2,t3)); \
|
||||
TYPE_NAME_3 NAME_3(float T_1, float T_2, float T_3) { \
|
||||
return NAME_3(vec3(T_1, T_2, T_3)); \
|
||||
} \
|
||||
\
|
||||
\
|
||||
@ -54,58 +54,58 @@ type_name3 name3(float t1, float t2, float t3) { \
|
||||
\
|
||||
/* === Definition === */ \
|
||||
\
|
||||
struct type_name4 { \
|
||||
struct TYPE_NAME_4 { \
|
||||
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; } \
|
||||
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_name4 name4 (type_name4 identity) { \
|
||||
TYPE_NAME_4 NAME_4 (TYPE_NAME_4 identity) { \
|
||||
return identity; \
|
||||
} \
|
||||
\
|
||||
type_name4 name4 (vec4 raw) { \
|
||||
return type_name4(raw); \
|
||||
TYPE_NAME_4 NAME_4 (vec4 raw) { \
|
||||
return TYPE_NAME_4(raw); \
|
||||
} \
|
||||
\
|
||||
type_name4 name4 (vec3 raw) { \
|
||||
return name4(vec4(raw,1.0)); \
|
||||
TYPE_NAME_4 NAME_4 (vec3 raw) { \
|
||||
return NAME_4(vec4(raw,1.0)); \
|
||||
} \
|
||||
\
|
||||
type_name4 name4 (vec3 raw, float a) { \
|
||||
return name4(vec4(raw,a)); \
|
||||
TYPE_NAME_4 NAME_4 (vec3 raw, float a) { \
|
||||
return NAME_4(vec4(raw,a)); \
|
||||
} \
|
||||
\
|
||||
type_name4 name4 (type_name3 name3) { \
|
||||
return name4(name3.raw); \
|
||||
TYPE_NAME_4 NAME_4 (TYPE_NAME_3 NAME_3) { \
|
||||
return NAME_4(NAME_3.raw); \
|
||||
} \
|
||||
\
|
||||
type_name4 name4 (type_name3 name3, float a) { \
|
||||
return name4(name3.raw,a); \
|
||||
TYPE_NAME_4 NAME_4 (TYPE_NAME_3 NAME_3, float a) { \
|
||||
return NAME_4(NAME_3.raw, a); \
|
||||
} \
|
||||
\
|
||||
type_name4 name4 (float t1, float t2, float t3) { \
|
||||
return name4(vec3(t1,t2,t3)); \
|
||||
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_name4 name4 (float t1, float t2, float t3, float a) { \
|
||||
return name4(vec4(t1,t2,t3,a)); \
|
||||
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_name3 name3 (type_name4 a) { \
|
||||
return name3(a.raw.xyz); \
|
||||
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_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_name3 a_name3(b_type_name4 b_name4) { \
|
||||
return a_name3(b_name3(b_name4)); \
|
||||
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_name4 a_name4(b_type_name4 b_name4) { \
|
||||
return a_name4(a_name3(b_name3(b_name4)),a(b_name4)); \
|
||||
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_name4 a_name4(b_type_name3 b_name3) { \
|
||||
return a_name4(a_name3(b_name3)); \
|
||||
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) \
|
||||
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_name3,a_type_name4,a_name3,a_name4,b_type_name3,b_type_name4,b_name3,b_name4) \
|
||||
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_name3,b_type_name4,b_name3,b_name4,a_type_name3,a_type_name4,a_name3,a_name4)
|
||||
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)
|
||||
|
||||
|
||||
|
||||
@ -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)); \
|
||||
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)
|
||||
|
@ -1 +0,0 @@
|
||||
100
|
@ -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;
|
||||
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,21 +24,25 @@ 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;
|
||||
@ -49,10 +51,42 @@ if (input_display_mode == DISPLAY_MODE_NORMAL) {
|
||||
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;
|
||||
} 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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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 ===
|
||||
// ===================
|
||||
@ -24,14 +85,14 @@ BoundingBox bounding_box (vec2 size) {
|
||||
return BoundingBox(-w2, w2, -h2, h2);
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
BoundingBox infinite () {
|
||||
return BoundingBox(0.0, 0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
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 infinite();
|
||||
}
|
||||
|
||||
BoundingBox unify (BoundingBox a, BoundingBox b) {
|
||||
@ -65,12 +126,13 @@ BoundingBox grow (BoundingBox a, float value) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ===========
|
||||
// === 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;
|
||||
};
|
||||
@ -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);
|
||||
}
|
||||
@ -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,85 +258,79 @@ 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 {
|
||||
/// 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;
|
||||
/// 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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
s.color.repr.raw.a /= s.alpha;
|
||||
return shape(id, sdf, s.color);
|
||||
}
|
||||
|
||||
Shape inverse (Shape s1) {
|
||||
@ -289,36 +349,27 @@ Shape intersection (Shape s1, Shape s2) {
|
||||
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;
|
||||
Shape with_infinite_bounds (Shape s) {
|
||||
BoundSdf sdf = s.sdf;
|
||||
sdf.bounds = infinite();
|
||||
return shape(id, sdf, color);
|
||||
return shape(s.id, sdf, s.color);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ===========
|
||||
// === Env ===
|
||||
// ===========
|
||||
|
||||
struct Env {
|
||||
int test;
|
||||
};
|
||||
|
||||
|
||||
|
||||
///////////////////////
|
||||
////// Transform //////
|
||||
///////////////////////
|
||||
// =================
|
||||
// === Transform ===
|
||||
// =================
|
||||
|
||||
vec2 translate (vec2 position, vec2 t) {
|
||||
return position - t;
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 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());
|
||||
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));
|
||||
Self { dom, display_object, size, guard }
|
||||
}
|
||||
|
||||
|
@ -591,9 +591,11 @@ 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| {
|
||||
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)
|
||||
}
|
||||
@ -601,6 +603,7 @@ impl SymbolData {
|
||||
layer.add_symbol(id)
|
||||
}
|
||||
});
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -59,13 +59,18 @@ 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| {
|
||||
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, new_layer)
|
||||
model.on_scene_layer_changed(scene, old_layer.as_ref(), new_layer.as_ref());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Shape> HasContent for ShapeView<S> {
|
||||
type Content = S;
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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];
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
@ -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
177
lib/rust/types/build.rs
Normal 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
157
lib/rust/types/src/dim.rs
Normal 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);
|
441
lib/rust/types/src/dim_macros.rs
Normal file
441
lib/rust/types/src/dim_macros.rs
Normal 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]
|
||||
}};
|
||||
}
|
@ -29,6 +29,8 @@
|
||||
// ==============
|
||||
|
||||
pub mod algebra;
|
||||
pub mod dim;
|
||||
pub mod dim_macros;
|
||||
pub mod num;
|
||||
pub mod topology;
|
||||
pub mod unit;
|
||||
|
Loading…
Reference in New Issue
Block a user