diff --git a/examples/color.rs b/examples/color.rs index dbf8950..bf1640d 100644 --- a/examples/color.rs +++ b/examples/color.rs @@ -64,6 +64,7 @@ impl Game for Colors { height: 1.0, }, position: Point::new(0.0, 0.0), + rotation: 0.0, size: (500.0, 500.0), }, target, diff --git a/examples/image.rs b/examples/image.rs index 704eaaf..ea92215 100644 --- a/examples/image.rs +++ b/examples/image.rs @@ -4,7 +4,8 @@ use coffee::graphics::{ }; use coffee::load::Task; use coffee::ui::{ - Align, Column, Element, Image, Justify, Renderer, Text, UserInterface, + Align, Column, Element, Image, Justify, Panel, Renderer, Text, + UserInterface, }; use coffee::{Game, Result, Timer}; @@ -54,13 +55,13 @@ impl UserInterface for ImageScreen { .align_items(Align::Center) .justify_content(Justify::Center) .spacing(20) - .push( + .push(Panel::new( Text::new("This is an image") .size(50) .height(60) .horizontal_alignment(HorizontalAlignment::Center) .vertical_alignment(VerticalAlignment::Center), - ) + )) .push(Image::new(&self.image).height(250)) .into() } diff --git a/examples/input.rs b/examples/input.rs index 75615b9..8c86744 100644 --- a/examples/input.rs +++ b/examples/input.rs @@ -2,8 +2,7 @@ use std::collections::HashSet; use coffee::graphics::{ - Color, Frame, Image, Point, Rectangle, Sprite, Vector, Window, - WindowSettings, + Color, Frame, Image, Point, Rectangle, Sprite, Window, WindowSettings, }; use coffee::input::{self, keyboard, mouse, Input}; use coffee::load::Task; @@ -154,6 +153,7 @@ impl Game for InputExample { height: 1, }, position: self.cursor_position - Vector::new(3.0, 3.0), + rotation: 0.0, scale: (6.0, 6.0), }, &mut frame.as_target(), diff --git a/examples/particles.rs b/examples/particles.rs index 073d656..536bcab 100644 --- a/examples/particles.rs +++ b/examples/particles.rs @@ -149,6 +149,7 @@ impl Game for Particles { height: 1, }, position: particle.position + velocity * delta_factor, + rotation: 0.0, scale: (1.0, 1.0), } }); diff --git a/src/graphics/backend_gfx/quad.rs b/src/graphics/backend_gfx/quad.rs index 11abd41..76b98af 100644 --- a/src/graphics/backend_gfx/quad.rs +++ b/src/graphics/backend_gfx/quad.rs @@ -33,6 +33,7 @@ gfx_defines! { src: [f32; 4] = "a_Src", translation: [f32; 2] = "a_Translation", scale: [f32; 2] = "a_Scale", + rotation: f32 = "a_Rotation", layer: u32 = "t_Layer", } @@ -213,11 +214,13 @@ impl From for Quad { let source = quad.source; let position = quad.position; let (width, height) = quad.size; + let rotation = quad.rotation; Quad { src: [source.x, source.y, source.width, source.height], translation: [position.x, position.y], scale: [width, height], + rotation: rotation, layer: 0, } } diff --git a/src/graphics/backend_gfx/shader/quad.vert b/src/graphics/backend_gfx/shader/quad.vert index 919d8e9..bd4e4d2 100644 --- a/src/graphics/backend_gfx/shader/quad.vert +++ b/src/graphics/backend_gfx/shader/quad.vert @@ -6,26 +6,44 @@ in vec4 a_Src; in vec2 a_Scale; in vec2 a_Translation; in uint t_Layer; +in float a_Rotation; -layout (std140) uniform Globals { +layout(std140)uniform Globals{ mat4 u_MVP; }; out vec2 v_Uv; flat out uint v_Layer; -void main() { - v_Uv = a_Pos * a_Src.zw + a_Src.xy; - v_Layer = t_Layer; - - mat4 instance_transform = mat4( - vec4(a_Scale.x, 0.0, 0.0, 0.0), - vec4(0.0, a_Scale.y, 0.0, 0.0), - vec4(0.0, 0.0, 1.0, 0.0), - vec4(a_Translation, 0.0, 1.0) +void main(){ + v_Uv=a_Pos*a_Src.zw+a_Src.xy; + v_Layer=t_Layer; + + mat4 Scale=mat4( + vec4(a_Scale.x,0.,0.,0.), + vec4(0.,a_Scale.y,0.,0.), + vec4(0.,0.,1.,0.), + vec4(0,0,0.,1.) ); - - vec4 position = u_MVP * instance_transform * vec4(a_Pos, 0.0, 1.0); - - gl_Position = position; + + mat4 Rotate=mat4( + vec4(cos(a_Rotation),-sin(a_Rotation),0.,0.), + vec4(sin(a_Rotation),cos(a_Rotation),0.,0.), + vec4(0.,0.,1.,0.), + vec4(0.,0.,0.,1.) + ); + + mat4 Translate=mat4( + vec4(1.,0.,0.,0.), + vec4(0.,1.,0.,0.), + vec4(0.,0.,1.,0.), + vec4(a_Translation,0.,1.) + ); + + vec4 temp = (Rotate*vec4(a_Pos-vec2(.5,.5),0.,1.)) + vec4(.5,.5,0,0); + mat4 instance_transform=Translate*Scale; + + vec4 position=u_MVP*instance_transform*temp; + + gl_Position=position; } diff --git a/src/graphics/backend_wgpu/quad.rs b/src/graphics/backend_wgpu/quad.rs index ae9939b..947574e 100644 --- a/src/graphics/backend_wgpu/quad.rs +++ b/src/graphics/backend_wgpu/quad.rs @@ -168,9 +168,14 @@ impl Pipeline { }, wgpu::VertexAttributeDescriptor { shader_location: 4, - format: wgpu::VertexFormat::Uint, + format: wgpu::VertexFormat::Float, offset: 4 * (4 + 2 + 2), }, + wgpu::VertexAttributeDescriptor { + shader_location: 5, + format: wgpu::VertexFormat::Uint, + offset: 4 * (4 + 2 + 2 + 1), + }, ], }, ], @@ -336,6 +341,7 @@ pub struct Quad { source: [f32; 4], scale: [f32; 2], translation: [f32; 2], + rotation: f32, pub layer: u32, } @@ -347,11 +353,13 @@ impl From for Quad { fn from(quad: graphics::Quad) -> Quad { let source = quad.source; let position = quad.position; + let rotation = quad.rotation; let (width, height) = quad.size; Quad { source: [source.x, source.y, source.width, source.height], translation: [position.x, position.y], + rotation: rotation, scale: [width, height], layer: 0, } diff --git a/src/graphics/backend_wgpu/shader/quad.frag.spv b/src/graphics/backend_wgpu/shader/quad.frag.spv index 40e5536..b4356c0 100644 Binary files a/src/graphics/backend_wgpu/shader/quad.frag.spv and b/src/graphics/backend_wgpu/shader/quad.frag.spv differ diff --git a/src/graphics/backend_wgpu/shader/quad.vert b/src/graphics/backend_wgpu/shader/quad.vert index 0358b1d..fe97e2d 100644 --- a/src/graphics/backend_wgpu/shader/quad.vert +++ b/src/graphics/backend_wgpu/shader/quad.vert @@ -1,28 +1,46 @@ #version 450 -layout(location = 0) in vec2 a_Pos; -layout(location = 1) in vec4 a_Src; -layout(location = 2) in vec2 a_Scale; -layout(location = 3) in vec2 a_Translation; -layout(location = 4) in uint t_Layer; +layout(location=0)in vec2 a_Pos; +layout(location=1)in vec4 a_Src; +layout(location=2)in vec2 a_Scale; +layout(location=3)in vec2 a_Translation; +layout(location=4)in float a_Rotation; +layout(location=5)in uint t_Layer; -layout (set = 0, binding = 0) uniform Globals { +layout(set=0,binding=0)uniform Globals{ mat4 u_Transform; }; -layout(location = 0) out vec2 v_Uv; -layout(location = 1) flat out uint v_Layer; +layout(location=0)out vec2 v_Uv; +layout(location=1)flat out uint v_Layer; -void main() { - v_Uv = a_Pos * a_Src.zw + a_Src.xy; - v_Layer = t_Layer; - - mat4 a_Transform = mat4( - vec4(a_Scale.x, 0.0, 0.0, 0.0), - vec4(0.0, a_Scale.y, 0.0, 0.0), - vec4(0.0, 0.0, 1.0, 0.0), - vec4(a_Translation, 0.0, 1.0) +void main(){ + v_Uv=a_Pos*a_Src.zw+a_Src.xy; + v_Layer=t_Layer; + + mat4 Scale=mat4( + vec4(a_Scale.x,0.,0.,0.), + vec4(0.,a_Scale.y,0.,0.), + vec4(0.,0.,1.,0.), + vec4(0,0,0.,1.) ); - - gl_Position = u_Transform * a_Transform * vec4(a_Pos, 0.0, 1.0); + + mat4 Rotate=mat4( + vec4(cos(a_Rotation),-sin(a_Rotation),0.,0.), + vec4(sin(a_Rotation),cos(a_Rotation),0.,0.), + vec4(0.,0.,1.,0.), + vec4(0.,0.,0.,1.) + ); + + mat4 Translate=mat4( + vec4(1.,0.,0.,0.), + vec4(0.,1.,0.,0.), + vec4(0.,0.,1.,0.), + vec4(a_Translation,0.,1.) + ); + + vec4 temp = (Rotate*vec4(a_Pos-vec2(.5,.5),0.,1.)) + vec4(.5,.5,0,0); + mat4 a_Transform=Translate*Scale; + + gl_Position=u_Transform*a_Transform*temp; } diff --git a/src/graphics/backend_wgpu/shader/quad.vert.spv b/src/graphics/backend_wgpu/shader/quad.vert.spv index 2e806ad..ba3c82a 100644 Binary files a/src/graphics/backend_wgpu/shader/quad.vert.spv and b/src/graphics/backend_wgpu/shader/quad.vert.spv differ diff --git a/src/graphics/quad.rs b/src/graphics/quad.rs index 1a631c6..6d1c8b1 100644 --- a/src/graphics/quad.rs +++ b/src/graphics/quad.rs @@ -8,9 +8,12 @@ pub struct Quad { /// coordinates: [0.0, 1.0]. pub source: Rectangle, - /// The position where the quad should be drawn. + /// The position where the quad should be drawn, anchored at the top left of the quad. pub position: Point, + /// The clockwise rotation to apply to the quad when drawing, specified in radians. + pub rotation: f32, + /// The size of the quad. pub size: (f32, f32), } @@ -25,6 +28,7 @@ impl Default for Quad { height: 1.0, }, position: Point::new(0.0, 0.0), + rotation: 0.0, size: (1.0, 1.0), } } diff --git a/src/graphics/sprite.rs b/src/graphics/sprite.rs index 623efe6..fe9ca62 100644 --- a/src/graphics/sprite.rs +++ b/src/graphics/sprite.rs @@ -13,9 +13,12 @@ pub struct Sprite { /// coordinates. pub source: Rectangle, - /// The position where the sprite should be drawn. + /// The position where the sprite should be drawn, anchored at the top left of the sprite. pub position: Point, + /// The clockwise rotation to apply to the sprite when drawing, specified in radians. + pub rotation: f32, + /// The scale to apply to the sprite. pub scale: (f32, f32), } @@ -31,6 +34,7 @@ impl Default for Sprite { height: 1, }, position: Point::new(0.0, 0.0), + rotation: 0.0, scale: (1.0, 1.0), } } @@ -46,6 +50,7 @@ impl IntoQuad for Sprite { height: self.source.height as f32 * y_unit, }, position: self.position, + rotation: self.rotation, size: ( self.source.width as f32 * self.scale.0, self.source.height as f32 * self.scale.1, diff --git a/src/ui/renderer/button.rs b/src/ui/renderer/button.rs index 4feed4c..9011ecb 100644 --- a/src/ui/renderer/button.rs +++ b/src/ui/renderer/button.rs @@ -61,6 +61,7 @@ impl button::Renderer for Renderer { ..LEFT }, position: Point::new(bounds.x, bounds.y), + rotation: 0.0, scale: (1.0, 1.0), }); @@ -71,6 +72,7 @@ impl button::Renderer for Renderer { ..BACKGROUND }, position: Point::new(bounds.x + LEFT.width as f32, bounds.y), + rotation: 0.0, scale: (bounds.width - (LEFT.width + RIGHT.width) as f32, 1.0), }); @@ -84,6 +86,7 @@ impl button::Renderer for Renderer { bounds.x + bounds.width - RIGHT.width as f32, bounds.y, ), + rotation: 0.0, scale: (1.0, 1.0), }); diff --git a/src/ui/renderer/checkbox.rs b/src/ui/renderer/checkbox.rs index 0b99a57..c8482de 100644 --- a/src/ui/renderer/checkbox.rs +++ b/src/ui/renderer/checkbox.rs @@ -27,6 +27,7 @@ impl checkbox::Renderer for Renderer { ..SPRITE }, position: Point::new(bounds.x, bounds.y), + rotation: 0.0, scale: (1.0, 1.0), }); @@ -37,6 +38,7 @@ impl checkbox::Renderer for Renderer { ..SPRITE }, position: Point::new(bounds.x, bounds.y), + rotation: 0.0, scale: (1.0, 1.0), }); } diff --git a/src/ui/renderer/image.rs b/src/ui/renderer/image.rs index 64f1fff..ca5b890 100644 --- a/src/ui/renderer/image.rs +++ b/src/ui/renderer/image.rs @@ -1,5 +1,5 @@ -use crate::graphics::{Rectangle, Sprite, Point, Image, Batch}; -use crate::ui::{Renderer, image}; +use crate::graphics::{Batch, Image, Point, Rectangle, Sprite}; +use crate::ui::{image, Renderer}; impl image::Renderer for Renderer { fn draw( @@ -22,14 +22,16 @@ impl image::Renderer for Renderer { ((ratio_x, ratio_x), Point::new(position_x, position_y)) }; - let mut batch = Batch::new(image); + let rotation = 0.0; + + let mut batch = Batch::new(image); batch.add(Sprite { source, position, + rotation, scale, }); self.images.push(batch); } } - diff --git a/src/ui/renderer/panel.rs b/src/ui/renderer/panel.rs index 11da6c2..99fe9b0 100644 --- a/src/ui/renderer/panel.rs +++ b/src/ui/renderer/panel.rs @@ -67,7 +67,6 @@ const BOTTOM_RIGHT: Rectangle = Rectangle { width: TOP_RIGHT.width, height: TOP_RIGHT.height, }; - impl panel::Renderer for Renderer { fn draw(&mut self, bounds: Rectangle) { self.sprites.add(Sprite { @@ -83,6 +82,7 @@ impl panel::Renderer for Renderer { bounds.width - (TOP_LEFT.width + TOP_RIGHT.width) as f32, 1.0, ), + rotation: 0.0, }); self.sprites.add(Sprite { @@ -97,6 +97,7 @@ impl panel::Renderer for Renderer { self.sprites.add(Sprite { source: CONTENT_BACKGROUND, position: Point::new(bounds.x, bounds.y + TOP_BORDER.height as f32), + rotation: 0.0, scale: ( bounds.width, bounds.height @@ -107,6 +108,7 @@ impl panel::Renderer for Renderer { self.sprites.add(Sprite { source: LEFT_BORDER, position: Point::new(bounds.x, bounds.y + TOP_BORDER.height as f32), + rotation: 0.0, scale: ( 1.0, bounds.height - (TOP_BORDER.height + BOTTOM_LEFT.height) as f32, @@ -119,6 +121,7 @@ impl panel::Renderer for Renderer { bounds.x + bounds.width - RIGHT_BORDER.width as f32, bounds.y + TOP_BORDER.height as f32, ), + rotation: 0.0, scale: ( 1.0, bounds.height @@ -141,6 +144,7 @@ impl panel::Renderer for Renderer { bounds.x + BOTTOM_LEFT.width as f32, bounds.y + bounds.height - BOTTOM_BORDER.height as f32, ), + rotation: 0.0, scale: ( bounds.width - (BOTTOM_LEFT.width + BOTTOM_LEFT.width) as f32, 1.0, diff --git a/src/ui/renderer/progress_bar.rs b/src/ui/renderer/progress_bar.rs index 941799e..ada59ce 100644 --- a/src/ui/renderer/progress_bar.rs +++ b/src/ui/renderer/progress_bar.rs @@ -1,4 +1,4 @@ -use crate::graphics::{Rectangle, Sprite, Point}; +use crate::graphics::{Point, Rectangle, Sprite}; use crate::ui::{progress_bar, Renderer}; const LEFT: Rectangle = Rectangle { @@ -23,20 +23,19 @@ const RIGHT: Rectangle = Rectangle { }; impl progress_bar::Renderer for Renderer { - fn draw( - &mut self, - bounds: Rectangle, - progress: f32, - ) { + fn draw(&mut self, bounds: Rectangle, progress: f32) { let active_class = 0; let background_class = 1; let full = 1.0; - let left_width_f32 = LEFT.width as f32 / 100.0; + let left_width_f32 = LEFT.width as f32 / bounds.width; let background_width = 1.0 - 2.0 * left_width_f32; - self.sprites.add(left_sprite(bounds, background_class, full)); - self.sprites.add(background_sprite(bounds, background_class, full)); - self.sprites.add(right_sprite(bounds, background_class, full)); + self.sprites + .add(left_sprite(bounds, background_class, full)); + self.sprites + .add(background_sprite(bounds, background_class, full)); + self.sprites + .add(right_sprite(bounds, background_class, full)); if progress > 0.0 { let area = bound(progress / left_width_f32); @@ -45,11 +44,14 @@ impl progress_bar::Renderer for Renderer { if progress > left_width_f32 { let area = bound((progress - left_width_f32) / background_width); - self.sprites.add(background_sprite(bounds, active_class, area)); + self.sprites + .add(background_sprite(bounds, active_class, area)); } if progress > left_width_f32 + background_width { - let area = bound((progress - left_width_f32 - background_width) / left_width_f32); + let area = bound( + (progress - left_width_f32 - background_width) / left_width_f32, + ); self.sprites.add(right_sprite(bounds, active_class, area)); } } @@ -72,11 +74,16 @@ fn left_sprite(bounds: Rectangle, class_index: u16, area: f32) -> Sprite { height: LEFT.height, }, position: Point::new(bounds.x, bounds.y), + rotation: 0.0, scale: (1.0, 1.0), } } -fn background_sprite(bounds: Rectangle, class_index: u16, area: f32) -> Sprite { +fn background_sprite( + bounds: Rectangle, + class_index: u16, + area: f32, +) -> Sprite { Sprite { source: Rectangle { x: BACKGROUND.x, @@ -84,7 +91,11 @@ fn background_sprite(bounds: Rectangle, class_index: u16, area: f32) -> Spr ..BACKGROUND }, position: Point::new(bounds.x + LEFT.width as f32, bounds.y), - scale: ((bounds.width - (LEFT.width + RIGHT.width) as f32) * area, 1.0), + rotation: 0.0, + scale: ( + (bounds.width - (LEFT.width + RIGHT.width) as f32) * area, + 1.0, + ), } } @@ -100,6 +111,7 @@ fn right_sprite(bounds: Rectangle, class_index: u16, area: f32) -> Sprite { bounds.x + bounds.width - RIGHT.width as f32, bounds.y, ), + rotation: 0.0, scale: (1.0, 1.0), } } diff --git a/src/ui/renderer/radio.rs b/src/ui/renderer/radio.rs index 626a7b2..c6e5121 100644 --- a/src/ui/renderer/radio.rs +++ b/src/ui/renderer/radio.rs @@ -26,6 +26,7 @@ impl radio::Renderer for Renderer { ..SPRITE }, position: Point::new(bounds.x, bounds.y), + rotation: 0.0, scale: (1.0, 1.0), }); @@ -36,6 +37,7 @@ impl radio::Renderer for Renderer { ..SPRITE }, position: Point::new(bounds.x, bounds.y), + rotation: 0.0, scale: (1.0, 1.0), }); } diff --git a/src/ui/renderer/slider.rs b/src/ui/renderer/slider.rs index 9a7a00f..d5c68ed 100644 --- a/src/ui/renderer/slider.rs +++ b/src/ui/renderer/slider.rs @@ -27,18 +27,21 @@ impl slider::Renderer for Renderer { range: RangeInclusive, value: f32, ) -> MouseCursor { + let rail_length = bounds.width - MARKER.width as f32; + self.sprites.add(Sprite { source: RAIL, position: Point::new( bounds.x + MARKER.width as f32 / 2.0, bounds.y + 12.5, ), + rotation: 0.0, scale: (bounds.width - MARKER.width as f32, 1.0), }); let (range_start, range_end) = range.into_inner(); - let marker_offset = (bounds.width - MARKER.width as f32) + let marker_offset = rail_length * ((value - range_start) / (range_end - range_start).max(1.0)); let mouse_over = bounds.contains(cursor_position); @@ -53,6 +56,7 @@ impl slider::Renderer for Renderer { bounds.x + marker_offset.round(), bounds.y + (if state.is_dragging() { 2.0 } else { 0.0 }), ), + rotation: 0.0, scale: (1.0, 1.0), });