1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
//! Vertices and shapes, the core of the rendering process.
//! 
//! # Linear algebra libraries
//! A number of linear algebra libraries exist for rust. `polystrip` provides `Vector2`, `Vector3`, and `Matrix4` as wrappers
//! around definitions provided by the [`mint`](https://docs.rs/mint) library, which is compatible with most of these linear
//! algebra libraries
//! 
//! # Coordinates
//! ## Screen space
//! `(0.0, 0.0)` is the screen center. `(1.0, 1.0)` is the top-right corner.
//! `(-1.0, -1.0)` is the bottom-left corner.
//! 
//! ## Texture space
//! `(0.0, 0.0)` is the top-left corner
//! `(1.0, 1.0)` is the bottom-right corner

/// A vertex describing a position and a position on a texture.
/// 
/// Texture coordinates are interpolated linearly between vertices.
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct TextureVertex {
	pub position: Vector3,
	pub tex_coords: Vector2,
}

unsafe impl bytemuck::Pod for TextureVertex {}
unsafe impl bytemuck::Zeroable for TextureVertex {}

impl TextureVertex {
	pub(crate) fn desc<'a>() -> &'a [gfx_hal::pso::AttributeDesc] {
		use std::mem::size_of;
		
		&[
			gfx_hal::pso::AttributeDesc {
				location: 0,
				binding: 0,
				element: gfx_hal::pso::Element {
					format: gfx_hal::format::Format::Rgb32Sfloat,
					offset: 0,
				},
			},
			gfx_hal::pso::AttributeDesc {
				location: 1,
				binding: 0,
				element: gfx_hal::pso::Element {
					format: gfx_hal::format::Format::Rg32Sfloat,
					offset: size_of::<[f32; 3]>() as u32,
				},
			},
		]
	}
}

/// A color in the sRGB color space, with red, green, blue, and alpha components all represented with `u8`s
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd)]
pub struct Color {
	pub r: u8,
	pub g: u8,
	pub b: u8,
	pub a: u8,
}

impl Color {
	pub const RED: Color     = Color::new(255,  0 ,  0 , 255);
	pub const YELLOW: Color  = Color::new(255, 255,  0 , 255);
	pub const GREEN: Color   = Color::new( 0 , 255,  0 , 255);
	pub const CYAN: Color    = Color::new( 0 , 255, 255, 255);
	pub const BLUE: Color    = Color::new( 0 ,  0 , 255, 255);
	pub const MAGENTA: Color = Color::new(255,  0 , 255, 255);
	pub const WHITE: Color   = Color::new(255, 255, 255, 255);
	pub const BLACK: Color   = Color::new( 0 ,  0 ,  0 , 255);

	pub const fn new(r: u8, g: u8, b: u8, a: u8) -> Color {
		Color { r, g, b, a }
	}
}

/// A vertex describing a position and a color.
/// 
/// Colors are interpolated linearly between vertices.
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct ColorVertex {
	pub position: Vector3,
	pub color: Color,
}

unsafe impl bytemuck::Pod for ColorVertex {}
unsafe impl bytemuck::Zeroable for ColorVertex {}

impl ColorVertex {
	pub(crate) fn desc<'a>() -> &'a [gfx_hal::pso::AttributeDesc] {
		use std::mem::size_of;
		
		&[
			gfx_hal::pso::AttributeDesc {
				location: 0,
				binding: 0,
				element: gfx_hal::pso::Element {
					format: gfx_hal::format::Format::Rgb32Sfloat,
					offset: 0,
				},
			},
			gfx_hal::pso::AttributeDesc {
				location: 1,
				binding: 0,
				element: gfx_hal::pso::Element {
					format: gfx_hal::format::Format::Rgba8Unorm,
					offset: size_of::<[f32; 3]>() as u32,
				},
			},
		]
	}
}

/// A set of vertices and indices describing an outlined geometric shape as a set of lines.
///
/// The colors of the lines are determined by interpolating the colors at each
/// [`ColorVertex`](struct.ColorVertex).
#[derive(Clone, Copy, Debug)]
pub struct StrokedShape<'a> {
	pub vertices: &'a [ColorVertex],
	/// A list of pairs of vertices which specify which vertices should have lines drawn between them
	pub indices: &'a [[u16; 2]],
}

/// A set of vertices and indices describing a geometric shape as a set of triangles.
///
/// The color of the shape is determined by interpolating the colors at each
/// [`ColorVertex`](struct.ColorVertex).
#[derive(Clone, Copy, Debug)]
pub struct ColoredShape<'a> {
	pub vertices: &'a [ColorVertex],
	/// A list of sets of three vertices which specify how the vertices should be rendered as triangles.
	pub indices: &'a [[u16; 3]], //TODO: Work out if it should need to be CCW or not
}

/// A set of vertices and indices describing a geometric shape as a set of triangles.
/// 
/// The color of the shape is determined by interpolating the texture coordinates at each
/// [`TextureVertex`](struct.TextureVertex).
/// 
/// A `TexturedShape` does not store the texture it is to draw. This must be specified in the
/// arguments to [`Frame::draw_textured`](../renderer/struct.Frame#method.draw_textured)
#[derive(Clone, Copy, Debug)]
pub struct TexturedShape<'a> {
	pub vertices: &'a [TextureVertex],
	/// A list of sets of three vertices which specify how the vertices should be rendered as triangles.
	pub indices: &'a [[u16; 3]], //TODO: As above
}

/// A rectangle in pixel coordinates. (x, y) is the top-left corner; (w, h) expanding rightward and downward.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd)]
pub struct Rect {
	pub x: i32,
	pub y: i32,
	pub w: i32,
	pub h: i32,
}

impl Rect {
	pub fn new(x: i32, y: i32, w: i32, h: i32) -> Rect {
		Rect { x, y, w, h }
	}
}

use std::ops::{Deref, DerefMut};

/// A 2D vector in screen space
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct Vector2(pub mint::Vector2<f32>);

unsafe impl bytemuck::Zeroable for Vector2 {}
unsafe impl bytemuck::Pod for Vector2 {}

impl Vector2 {
	pub fn new(x: f32, y: f32) -> Vector2 {
		Vector2(mint::Vector2 { x, y })
	}

	pub fn with_height(self, height: f32) -> Vector3 {
		Vector3(mint::Vector3 { x: self.x, y: self.y, z: height	})
	}
}

impl From<mint::Vector2<f32>> for Vector2 {
	fn from(v: mint::Vector2<f32>) -> Self {
		Self(v)
	}
}

impl From<Vector2> for mint::Vector2<f32> {
	fn from(v: Vector2) -> Self {
		v.0
	}
}

impl From<[f32; 2]> for Vector2 {
	fn from(v: [f32; 2]) -> Self {
		Self(mint::Vector2::from(v))
	}
}

impl From<Vector2> for [f32; 2] {
	fn from(v: Vector2) -> Self {
		v.0.into()
	}
}

impl Deref for Vector2 {
	type Target = mint::Vector2<f32>;

	fn deref(&self) -> &Self::Target {
		&self.0
	}
}

impl DerefMut for Vector2 {
	fn deref_mut(&mut self) -> &mut Self::Target {
		&mut self.0
	}
}

/// A 3D vector in screen space
///
/// # Height
/// The `z` coordinate of this vector, is uncapped linear height, used to affect the render output.
/// Out of a set of shapes drawn at the same height, the one drawn last appears on top.
/// Out of a set of shapes drawn at different heights, the one with the greatest height appears on top.
///
/// Additionally, height interpolates linearly between vertices.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct Vector3(pub mint::Vector3<f32>);

unsafe impl bytemuck::Zeroable for Vector3 {}
unsafe impl bytemuck::Pod for Vector3 {}

impl Vector3 {
	pub fn new(x: f32, y: f32, z: f32) -> Vector3 {
		Vector3(mint::Vector3 { x, y, z })
	}
}

impl From<mint::Vector3<f32>> for Vector3 {
	fn from(v: mint::Vector3<f32>) -> Self {
		Self(v)
	}
}

impl From<Vector3> for mint::Vector3<f32> {
	fn from(v: Vector3) -> Self {
		v.0
	}
}

impl From<[f32; 3]> for Vector3 {
	fn from(v: [f32; 3]) -> Self {
		Self(mint::Vector3::from(v))
	}
}

impl From<Vector3> for [f32; 3] {
	fn from(v: Vector3) -> Self {
		v.0.into()
	}
}

impl Deref for Vector3 {
	type Target = mint::Vector3<f32>;

	fn deref(&self) -> &Self::Target {
		&self.0
	}
}

impl DerefMut for Vector3 {
	fn deref_mut(&mut self) -> &mut Self::Target {
		&mut self.0
	}
}

/// A 4 x 4 column major matrix in screen space
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct Matrix4(pub mint::ColumnMatrix4<f32>);

unsafe impl bytemuck::Zeroable for Matrix4 {}
unsafe impl bytemuck::Pod for Matrix4 {}

impl Matrix4 {
	/// Returns the [identity matrix](https://en.wikipedia.org/wiki/Identity_matrix).
	pub fn identity() -> Matrix4 {
		Matrix4(mint::ColumnMatrix4::from([
			[1.0, 0.0, 0.0, 0.0],
			[0.0, 1.0, 0.0, 0.0],
			[0.0, 0.0, 1.0, 0.0],
			[0.0, 0.0, 0.0, 1.0],
		]))
	}

	/// Returns a matrix that translates by the given X and Y values, in screen space
	pub fn translate(v: Vector2) -> Matrix4 {
		Matrix4(mint::ColumnMatrix4::from([
			[1.0, 0.0, 0.0, 0.0],
			[0.0, 1.0, 0.0, 0.0],
			[0.0, 0.0, 1.0, 0.0],
			[v.x, v.y, 0.0, 1.0],
		]))
	}

	/// Returns a matrix that rotates the XY plane counterclockwise about the origin by the given angle.
	/// 
	/// Interprets the angle to be in radians.
	pub fn rotate(r: f32) -> Matrix4 {
		Matrix4(mint::ColumnMatrix4::from([
			[r.cos(),-r.sin(), 0.0, 0.0],
			[r.sin(), r.cos(), 0.0, 0.0],
			[  0.0  ,   0.0  , 1.0, 0.0],
			[  0.0  ,   0.0  , 0.0, 1.0],
		]))
	}

	/// Returns a matrix that scales the XY plane by the given factor
	pub fn scale(f: f32) -> Matrix4 {
		Matrix4(mint::ColumnMatrix4::from([
			[ f , 0.0, 0.0, 0.0],
			[0.0,  f , 0.0, 0.0],
			[0.0, 0.0, 1.0, 0.0],
			[0.0, 0.0, 0.0, 1.0],
		]))
	}

	/// Returns a matrix that scales the X coordinate by the given factor and the Y coordinate by the given factor.
	pub fn scale_nonuniform(x: f32, y: f32) -> Matrix4 {
		Matrix4(mint::ColumnMatrix4::from([
			[ x , 0.0, 0.0, 0.0],
			[0.0,  y , 0.0, 0.0],
			[0.0, 0.0, 1.0, 0.0],
			[0.0, 0.0, 0.0, 1.0],
		]))
	}

	/// Returns a simple perspective matrix from the four passed parameters. Equivalent to the 
	/// [`gluPerspective`](https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml) function in OpenGL.
	/// 
	/// See also [`RendererBuilder::real_3d`](crate::RendererBuilder::real_3d)
	/// 
	/// # Parameters
	/// * `fovy`: The angle of the field of view up and down, in radians. Must be nonzero and cannot be a multiple of tau (2π)
	/// * `aspect`: The ratio of screen width to screen height. Should be updated when the window is resized. Must be nonzero.
	/// * `near`: Distance from the camera to the near clipping plane, in screen-space coordinates.
	/// * `far`: Distance from the camera to the far clipping plane, in screen-space coordinates. Must not be equal to `near`.
	pub fn perspective(fovy: f32, aspect: f32, near: f32, far: f32) -> Matrix4 {
		let f = (fovy / 2.).cos() / (fovy / 2.).sin();
		Matrix4(mint::ColumnMatrix4::from([
			[f/aspect, 0.0, 0.0, 0.0],
			[0.0, f, 0.0, 0.0],
			[0.0, 0.0, (far + near) / (near - far), -1.0],
			[0.0, 0.0, (2. * far * near) / (near - far), 0.0],
		]))
	}

	pub fn row(&self, i: usize) -> [f32; 4] {
		[self.x.as_ref()[i], self.y.as_ref()[i], self.z.as_ref()[i], self.w.as_ref()[i]]
	}
}

fn dot(lhs: [f32; 4], rhs: [f32; 4]) -> f32 {
	lhs[0] * rhs[0] + lhs[1] * rhs[1] + lhs[2] * rhs[2] + lhs[3] * rhs[3]
}

impl std::ops::Mul<Matrix4> for Matrix4 {
	type Output = Matrix4;
	fn mul(self, rhs: Matrix4) -> Matrix4 {
		Matrix4(mint::ColumnMatrix4::from([
			[dot(self.row(0), rhs.x.into()), dot(self.row(1), rhs.x.into()), dot(self.row(2), rhs.x.into()), dot(self.row(3), rhs.x.into())],
			[dot(self.row(0), rhs.y.into()), dot(self.row(1), rhs.y.into()), dot(self.row(2), rhs.y.into()), dot(self.row(3), rhs.y.into())],
			[dot(self.row(0), rhs.z.into()), dot(self.row(1), rhs.z.into()), dot(self.row(2), rhs.z.into()), dot(self.row(3), rhs.z.into())],
			[dot(self.row(0), rhs.w.into()), dot(self.row(1), rhs.w.into()), dot(self.row(2), rhs.w.into()), dot(self.row(3), rhs.w.into())],
		]))
	}
}

impl From<mint::ColumnMatrix4<f32>> for Matrix4 {
	fn from(v: mint::ColumnMatrix4<f32>) -> Self {
		Self(v)
	}
}

impl From<Matrix4> for mint::ColumnMatrix4<f32> {
	fn from(v: Matrix4) -> Self {
		v.0
	}
}

impl From<[[f32; 4]; 4]> for Matrix4 {
	fn from(v: [[f32; 4]; 4]) -> Self {
		Self(mint::ColumnMatrix4::from(v))
	}
}

impl From<Matrix4> for [[f32; 4]; 4] {
	fn from(v: Matrix4) -> Self {
		v.0.into()
	}
}

impl Deref for Matrix4 {
	type Target = mint::ColumnMatrix4<f32>;

	fn deref(&self) -> &Self::Target {
		&self.0
	}
}

impl DerefMut for Matrix4 {
	fn deref_mut(&mut self) -> &mut Self::Target {
		&mut self.0
	}
}