Skip to content

Commit

Permalink
Texture coordinates are now integers
Browse files Browse the repository at this point in the history
There is a lot of random cleanup in this commit, but the only real
change in functionality is switching from inputting precomputed f32
fractional coordinates to unsigned pixels for the texture coordinates.

This has a couple of major benefits: resizing textures no longer breaks
texture coordinates, and fractionally extracting from a texture is no
longer possible.

Subpixel rendering may be desired, however. I'm currently debating
whether to always pixel align or offer some sort of integer-based
subpixel subdivisions. With the modern movement being to move to higher
DPI screens, in general, the importance of subpixel rendering dimenishes
and the sharpness of pixel aligned graphics shines.

Ultimately, I'm sure this will be tweaked once text rendering is
supported, as that's the situation where subpixel rendering seems like
it should be important.
  • Loading branch information
ecton committed Jul 3, 2023
1 parent 781d235 commit 7e1ba79
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 73 deletions.
2 changes: 1 addition & 1 deletion examples/shapes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use std::time::Duration;
use appit::RunningWindow;
use kludgine::app::WindowBehavior;
use kludgine::math::{Dips, Pixels, Point, Rect, Size};
use kludgine::shapes::{PathBuilder, PreparedGraphic};
use kludgine::Color;
use kludgine::{PathBuilder, PreparedGraphic};

fn main() {
Test::run();
Expand Down
2 changes: 1 addition & 1 deletion examples/texture-collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::time::Duration;
use appit::RunningWindow;
use kludgine::app::WindowBehavior;
use kludgine::math::{Dips, Pixels, Point, Rect, Size};
use kludgine::{shapes::PreparedGraphic, Color, TextureCollection};
use kludgine::{Color, PreparedGraphic, TextureCollection};

fn main() {
Test::run();
Expand Down
2 changes: 1 addition & 1 deletion examples/texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::time::Duration;
use appit::RunningWindow;
use kludgine::app::WindowBehavior;
use kludgine::math::{Dips, Point, Rect, Size};
use kludgine::shapes::PreparedGraphic;
use kludgine::PreparedGraphic;
use kludgine::Texture;

fn main() {
Expand Down
13 changes: 9 additions & 4 deletions src/atlas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use alot::{LotId, Lots};

use crate::math::{Rect, Size, ToFloat, UPixels};
use crate::pack::{TextureAllocation, TexturePacker};
use crate::sealed;
use crate::shapes::{PreparedGraphic, Vertex};
use crate::{Graphics, Texture, TextureSource, WgpuDeviceAndQueue};

Expand Down Expand Up @@ -164,13 +165,15 @@ impl TextureCollection {
}
}

impl TextureSource for TextureCollection {
impl TextureSource for TextureCollection {}

impl sealed::TextureSource for TextureCollection {
fn bind_group(&self, graphics: &Graphics<'_>) -> Arc<wgpu::BindGroup> {
let data = self.data.read().map_or_else(PoisonError::into_inner, |g| g);
data.texture.bind_group(graphics)
}

fn id(&self) -> crate::TextureId {
fn id(&self) -> sealed::TextureId {
let data = self.data.read().map_or_else(PoisonError::into_inner, |g| g);
data.texture.id()
}
Expand Down Expand Up @@ -207,12 +210,14 @@ impl Drop for CollectedTexture {
}
}

impl TextureSource for CollectedTexture {
impl TextureSource for CollectedTexture {}

impl sealed::TextureSource for CollectedTexture {
fn bind_group(&self, graphics: &Graphics<'_>) -> Arc<wgpu::BindGroup> {
self.collection.bind_group(graphics)
}

fn id(&self) -> crate::TextureId {
fn id(&self) -> sealed::TextureId {
self.collection.id()
}
}
53 changes: 18 additions & 35 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ use std::fmt::{self, Debug, Formatter};
use std::hash::Hash;
use std::mem::size_of;
use std::ops::{Add, Div, Neg, Range};
use std::sync::atomic::{self, AtomicUsize};
use std::sync::{Arc, OnceLock};
use std::sync::Arc;

use bytemuck::{Pod, Zeroable};
use wgpu::util::DeviceExt;
Expand All @@ -15,8 +14,7 @@ use crate::math::{
Dips, Pixels, Point, Ratio, Rect, ScreenTransformation, Size, ToFloat, UPixels, Zero,
};
use crate::shapes::{
PathBuilder, PreparedGraphic, PushConstants, ShaderScalable, Shape, Vertex, FLAG_ROTATE,
FLAG_SCALE, FLAG_TEXTURED, FLAG_TRANSLATE,
PushConstants, Vertex, FLAG_ROTATE, FLAG_SCALE, FLAG_TEXTURED, FLAG_TRANSLATE,
};

#[cfg(feature = "app")]
Expand All @@ -25,7 +23,10 @@ mod atlas;
mod buffer;
pub mod math;
mod pack;
pub mod shapes;
mod sealed;
mod shapes;

pub use shapes::{Path, PathBuilder, PreparedGraphic, ShaderScalable, Shape};

pub use atlas::{CollectedTexture, TextureCollection};

Expand Down Expand Up @@ -82,7 +83,7 @@ impl Kludgine {
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::FRAGMENT,
visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::D2,
Expand Down Expand Up @@ -170,7 +171,7 @@ impl Kludgine {
shader_location: 0,
},
wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x2,
format: wgpu::VertexFormat::Uint32x2,
offset: 8,
shader_location: 1,
},
Expand Down Expand Up @@ -793,23 +794,9 @@ struct Uniforms {
_padding: [u32; 3],
}

#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub struct TextureId(usize);

impl TextureId {
pub fn new_unique_id() -> Self {
static COUNTER: OnceLock<AtomicUsize> = OnceLock::new();
Self(
COUNTER
.get_or_init(AtomicUsize::default)
.fetch_add(1, atomic::Ordering::Relaxed),
)
}
}

#[derive(Debug)]
pub struct Texture {
id: TextureId,
id: sealed::TextureId,
wgpu: wgpu::Texture,
view: wgpu::TextureView,
bind_group: Arc<wgpu::BindGroup>,
Expand All @@ -835,7 +822,7 @@ impl Texture {
let view = wgpu.create_view(&wgpu::TextureViewDescriptor::default());
let bind_group = Arc::new(create_bind_group(graphics, &view));
Self {
id: TextureId::new_unique_id(),
id: sealed::TextureId::new_unique_id(),
wgpu,
view,
bind_group,
Expand Down Expand Up @@ -866,7 +853,7 @@ impl Texture {
let view = wgpu.create_view(&wgpu::TextureViewDescriptor::default());
let bind_group = Arc::new(create_bind_group(graphics, &view));
Self {
id: TextureId::new_unique_id(),
id: sealed::TextureId::new_unique_id(),
wgpu,
view,
bind_group,
Expand Down Expand Up @@ -961,9 +948,6 @@ impl Texture {
Vertex<Unit>: bytemuck::Pod,
{
let (source_top_left, source_bottom_right) = source.extents();
let size = self.size().into_float();
let source_top_left = source_top_left.into_float() / size;
let source_bottom_right = source_bottom_right.into_float() / size;
let (dest_top_left, dest_bottom_right) = dest.extents();
let path = PathBuilder::new_textured(dest_top_left, source_top_left)
.line_to(
Expand Down Expand Up @@ -1049,17 +1033,16 @@ fn create_bind_group(
// }
// }

pub trait TextureSource {
fn id(&self) -> TextureId;
fn bind_group(&self, graphics: &Graphics<'_>) -> Arc<wgpu::BindGroup>;
}
pub trait TextureSource: sealed::TextureSource {}

impl TextureSource for Texture {}

impl TextureSource for Texture {
impl sealed::TextureSource for Texture {
fn bind_group(&self, _graphics: &Graphics<'_>) -> Arc<wgpu::BindGroup> {
self.bind_group.clone()
}

fn id(&self) -> TextureId {
fn id(&self) -> sealed::TextureId {
self.id
}
}
Expand All @@ -1073,7 +1056,7 @@ pub struct Renderer<'render, 'gfx> {
struct Command {
indices: Range<u32>,
constants: PushConstants,
texture: Option<TextureId>,
texture: Option<sealed::TextureId>,
}

#[derive(Eq, PartialEq, Debug, Clone, Copy)]
Expand Down Expand Up @@ -1240,7 +1223,7 @@ pub struct Rendering {
vertices: Vec<Vertex<i32>>,
vertex_index_by_id: HashMap<VertexId, u16>,
indices: Vec<u16>,
textures: HashMap<TextureId, Arc<wgpu::BindGroup>>,
textures: HashMap<sealed::TextureId, Arc<wgpu::BindGroup>>,
commands: Vec<Command>,
}

Expand Down
26 changes: 26 additions & 0 deletions src/sealed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use std::sync::atomic::{self, AtomicUsize};
use std::sync::{Arc, OnceLock};

use crate::Graphics;

#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub struct TextureId(usize);

impl TextureId {
pub fn new_unique_id() -> Self {
static COUNTER: OnceLock<AtomicUsize> = OnceLock::new();
Self(
COUNTER
.get_or_init(AtomicUsize::default)
.fetch_add(1, atomic::Ordering::Relaxed),
)
}
}

pub trait ShaderScalableSealed {
fn flags() -> u32;
}
pub trait TextureSource {
fn id(&self) -> TextureId;
fn bind_group(&self, graphics: &Graphics<'_>) -> Arc<wgpu::BindGroup>;
}
43 changes: 19 additions & 24 deletions src/shapes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use wgpu::{BufferUsages, ShaderStages};

use crate::buffer::Buffer;
use crate::math::{Dips, Pixels, Point, Rect, ToFloat, UPixels, Zero};
use crate::{Color, Graphics, RenderingGraphics, TextureSource};
use crate::{sealed, Color, Graphics, RenderingGraphics, TextureSource};

#[derive(Debug, Clone, PartialEq)]
pub struct Shape<Unit, const TEXTURED: bool> {
Expand Down Expand Up @@ -167,12 +167,6 @@ where

pub trait ShaderScalable: sealed::ShaderScalableSealed {}

mod sealed {
pub trait ShaderScalableSealed {
fn flags() -> u32;
}
}

impl ShaderScalable for Pixels {}

impl ShaderScalable for Dips {}
Expand Down Expand Up @@ -217,7 +211,7 @@ where

Vertex {
location: Point::new(Unit::from_float(position.x), Unit::from_float(position.y)),
texture: Point::new(attributes[0], attributes[1]),
texture: Point::new(attributes[0].round(), attributes[1].round()),
color: self.default_color,
}
}
Expand Down Expand Up @@ -335,10 +329,7 @@ pub struct Vertex<Unit> {

#[test]
fn vertex_align() {
assert_eq!(
std::mem::size_of::<[Vertex<Dips>; 2]>(),
std::mem::size_of::<Vertex<Dips>>() * 2
);
assert_eq!(std::mem::size_of::<Vertex<Dips>>(), 20);
}

unsafe impl bytemuck::Pod for Vertex<Pixels> {}
Expand All @@ -360,21 +351,21 @@ pub enum PathEvent<Unit> {
Begin {
/// The location to begin at.
at: Endpoint<Unit>,
texture: Point<f32>,
texture: Point<UPixels>,
},
/// A straight line segment.
Line {
/// The end location of the line.
to: Endpoint<Unit>,
texture: Point<f32>,
texture: Point<UPixels>,
},
/// A quadratic curve (one control point).
Quadratic {
/// The control point for the curve.
ctrl: ControlPoint<Unit>,
/// The end location of the curve.
to: Endpoint<Unit>,
texture: Point<f32>,
texture: Point<UPixels>,
},
/// A cubic curve (two control points).
Cubic {
Expand All @@ -384,7 +375,7 @@ pub enum PathEvent<Unit> {
ctrl2: ControlPoint<Unit>,
/// The end location of the curve.
to: Endpoint<Unit>,
texture: Point<f32>,
texture: Point<UPixels>,
},
/// Ends the path. Must be the last entry.
End {
Expand Down Expand Up @@ -417,13 +408,17 @@ where
for &event in &self.events {
match event {
PathEvent::Begin { at, texture } => {
builder.begin(at.into(), &[texture.x, texture.y]);
builder.begin(at.into(), &[texture.x.into_float(), texture.y.into_float()]);
}
PathEvent::Line { to, texture } => {
builder.line_to(to.into(), &[texture.x, texture.y]);
builder.line_to(to.into(), &[texture.x.into_float(), texture.y.into_float()]);
}
PathEvent::Quadratic { ctrl, to, texture } => {
builder.quadratic_bezier_to(ctrl.into(), to.into(), &[texture.x, texture.y]);
builder.quadratic_bezier_to(
ctrl.into(),
to.into(),
&[texture.x.into_float(), texture.y.into_float()],
);
}
PathEvent::Cubic {
ctrl1,
Expand All @@ -435,7 +430,7 @@ where
ctrl1.into(),
ctrl2.into(),
to.into(),
&[texture.x, texture.y],
&[texture.x.into_float(), texture.y.into_float()],
);
}
PathEvent::End { close } => builder.end(close),
Expand Down Expand Up @@ -563,7 +558,7 @@ where
{
/// Creates a new path with the initial position `start_at`.
#[must_use]
pub fn new_textured(start_at: Endpoint<Unit>, texture: Point<f32>) -> Self {
pub fn new_textured(start_at: Endpoint<Unit>, texture: Point<UPixels>) -> Self {
Self {
path: Path::from_iter([(PathEvent::Begin {
at: start_at,
Expand All @@ -583,7 +578,7 @@ where

/// Create a straight line from the current location to `end_at`.
#[must_use]
pub fn line_to(mut self, end_at: Endpoint<Unit>, texture: Point<f32>) -> Self {
pub fn line_to(mut self, end_at: Endpoint<Unit>, texture: Point<UPixels>) -> Self {
self.path.events.push(PathEvent::Line {
to: end_at,
texture,
Expand All @@ -599,7 +594,7 @@ where
mut self,
control: ControlPoint<Unit>,
end_at: Endpoint<Unit>,
texture: Point<f32>,
texture: Point<UPixels>,
) -> Self {
self.path.events.push(PathEvent::Quadratic {
ctrl: control,
Expand All @@ -618,7 +613,7 @@ where
control1: ControlPoint<Unit>,
control2: ControlPoint<Unit>,
end_at: Endpoint<Unit>,
texture: Point<f32>,
texture: Point<UPixels>,
) -> Self {
self.path.events.push(PathEvent::Cubic {
ctrl1: control1,
Expand Down
Loading

0 comments on commit 7e1ba79

Please sign in to comment.