use crate::{image_cache::*, makepad_draw::*, widget::*};
use crate::makepad_derive_widget::*;
live_design! {
link widgets
use link::shaders::*;
pub RotatedImageBase = {{RotatedImage}} {}
pub RotatedImage = <RotatedImageBase> {
width: Fit
height: Fit
draw_bg: {
texture image: texture2d
instance rotation: 0.0
instance opacity: 1.0
instance scale: 1.0
fn rotation_vertex_expansion(rotation: float, w: float, h: float) -> vec2 {
let horizontal_expansion = (abs(cos(rotation)) * w + abs(sin(rotation)) * h) / w - 1.0;
let vertical_expansion = (abs(sin(rotation)) * w + abs(cos(rotation)) * h) / h - 1.0;
return vec2(horizontal_expansion, vertical_expansion);
}
fn rotate_2d_from_center(coord: vec2, a: float, size: vec2) -> vec2 {
let cos_a = cos(-a);
let sin_a = sin(-a);
let centered_coord = coord - vec2(0.5, 0.5);
let denorm_coord = vec2(centered_coord.x, centered_coord.y * size.y / size.x);
let demorm_rotated = vec2(denorm_coord.x * cos_a - denorm_coord.y * sin_a, denorm_coord.x * sin_a + denorm_coord.y * cos_a);
let rotated = vec2(demorm_rotated.x, demorm_rotated.y * size.x / size.y);
return rotated + vec2(0.5, 0.5);
}
fn get_color(self) -> vec4 {
let rot_padding = rotation_vertex_expansion(self.rotation, self.rect_size.x, self.rect_size.y) / 2.0;
let current_pos = self.pos.xy - rot_padding;
let original_pos = rotate_2d_from_center(current_pos, self.rotation, self.rect_size);
let scaled_pos = original_pos / self.scale;
let color = sample2d(self.image, scaled_pos).xyzw;
let faded_color = color * vec4(1.0, 1.0, 1.0, self.opacity);
return faded_color;
}
fn pixel(self) -> vec4 {
let rot_expansion = rotation_vertex_expansion(self.rotation, self.rect_size.x, self.rect_size.y);
let sdf = Sdf2d::viewport(self.pos * self.rect_size);
let translation_offset = vec2(self.rect_size.x * rot_expansion.x / 2.0, self.rect_size.y * self.scale * rot_expansion.y / 2.0);
sdf.translate(translation_offset.x, translation_offset.y);
let center = self.rect_size * 0.5;
sdf.rotate(self.rotation, center.x, center.y);
let scaled_size = self.rect_size * self.scale;
sdf.box(0.0, 0.0, scaled_size.x, scaled_size.y, 1);
sdf.fill_premul(Pal::premul(self.get_color()));
return sdf.result
}
fn vertex(self) -> vec4 {
let rot_expansion = rotation_vertex_expansion(self.rotation, self.rect_size.x, self.rect_size.y);
let adjusted_pos = vec2(
self.rect_pos.x - self.rect_size.x * rot_expansion.x / 2.0,
self.rect_pos.y - self.rect_size.y * rot_expansion.y / 2.0
);
let expanded_size = vec2(self.rect_size.x * (self.scale + rot_expansion.x), self.rect_size.y * (self.scale + rot_expansion.y));
let clipped: vec2 = clamp(
self.geom_pos * expanded_size + adjusted_pos,
self.draw_clip.xy,
self.draw_clip.zw
);
self.pos = (clipped - adjusted_pos) / self.rect_size;
return self.camera_projection * (self.camera_view * (
self.view_transform * vec4(clipped.x, clipped.y, self.draw_depth + self.draw_zbias, 1.)
));
}
shape: Solid,
fill: Image
}
}
}
#[derive(Live, Widget)]
pub struct RotatedImage {
#[walk] walk: Walk,
#[layout] layout: Layout,
#[redraw] #[live] draw_bg: DrawColor,
#[live] source: LiveDependency,
#[rust(Texture::new(cx))] texture: Option<Texture>,
#[live] scale: f64,
}
impl ImageCacheImpl for RotatedImage {
fn get_texture(&self, _id:usize) -> &Option<Texture> {
&self.texture
}
fn set_texture(&mut self, texture: Option<Texture>, _id:usize) {
self.texture = texture;
}
}
impl LiveHook for RotatedImage {
fn after_apply(&mut self, cx: &mut Cx, _applyl: &mut Apply, _index: usize, _nodes: &[LiveNode]) {
self.lazy_create_image_cache(cx);
let source = self.source.clone();
if source.as_str().len()>0{
let _ = self.load_image_dep_by_path(cx, source.as_str(), 0);
}
}
}
impl Widget for RotatedImage {
fn draw_walk(&mut self, cx: &mut Cx2d, _scope:&mut Scope, walk: Walk) -> DrawStep {
self.draw_walk_rotated_image(cx, walk)
}
}
impl RotatedImage {
pub fn draw_walk_rotated_image(&mut self, cx: &mut Cx2d, walk: Walk) -> DrawStep {
if let Some(image_texture) = &self.texture {
self.draw_bg.draw_vars.set_texture(0, image_texture);
}
self.draw_bg.draw_walk(cx, walk);
DrawStep::done()
}
}