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
//! GPU POD data types.
use crate::{
    mtl,
    resources::Tint as TintComponent,
    sprite::{SpriteRender, SpriteSheet},
    types::Texture,
};
use amethyst_assets::{AssetStorage, Handle};
use amethyst_core::{
    math::{convert, Matrix4, Vector4},
    Transform,
};
use glsl_layout::*;
use rendy::{
    hal::format::Format,
    mesh::{AsAttribute, AsVertex, Model, VertexFormat},
};

/// TextureOffset
/// ```glsl,ignore
/// struct UvOffset {
///    vec2 u_offset;
///    vec2 v_offset;
/// };
/// ```
#[derive(Clone, Copy, Debug, AsStd140)]
#[repr(C, align(16))]
pub struct TextureOffset {
    /// U-axis offset
    pub u_offset: vec2,
    /// V-axis offset
    pub v_offset: vec2,
}

impl TextureOffset {
    /// Helper function from proper type to Pod type.
    pub fn from_offset(offset: &crate::mtl::TextureOffset) -> Self {
        TextureOffset {
            u_offset: [offset.u.0, offset.u.1].into(),
            v_offset: [offset.v.0, offset.v.1].into(),
        }
    }
}

/// ViewArgs
/// ```glsl,ignore
/// uniform ViewArgs {
///    uniform mat4 proj;
///    uniform mat4 view;
/// };
/// ```
#[derive(Clone, Copy, Debug, AsStd140)]
#[repr(C, align(16))]
pub struct ViewArgs {
    /// Projection matrix
    pub proj: mat4,
    /// View matrix
    pub view: mat4,
}

/// Tint
/// ```glsl,ignore
/// vec4 tint;
/// ```
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, AsStd140)]
#[repr(C, align(16))]
pub struct Tint {
    /// Tint color as `Rgba32Sfloat`
    pub tint: vec4,
}

impl AsAttribute for Tint {
    const NAME: &'static str = "tint";
    const FORMAT: Format = Format::Rgba32Sfloat;
}

/// Instance-rate vertex arguments
/// ```glsl,ignore
///  mat4 model;
///  vec4 tint;
/// ```
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[repr(C, align(16))]
pub struct VertexArgs {
    /// Instance-rate model matrix
    pub model: mat4,
    /// Instance-rate model `Tint`
    pub tint: vec4,
}

impl VertexArgs {
    /// Populates a `VertexArgs` instance-rate structure with the information from a `Transform`
    /// and `TintComponent` components.
    #[inline]
    pub fn from_object_data(transform: &Transform, tint: Option<&TintComponent>) -> Self {
        let model: [[f32; 4]; 4] = convert::<_, Matrix4<f32>>(*transform.global_matrix()).into();
        VertexArgs {
            model: model.into(),
            tint: tint.map_or([1.0; 4].into(), |t| {
                let (r, g, b, a) = t.0.into_components();
                [r, g, b, a].into()
            }),
        }
    }
}

impl AsVertex for VertexArgs {
    fn vertex() -> VertexFormat {
        VertexFormat::new((Model::vertex(), Tint::vertex()))
    }
}

/// Instance-rate joints offset
/// ```glsl,ignore
///  uint joints_offset;
/// ```
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, AsStd140)]
#[repr(C, align(4))]
pub struct JointsOffset {
    /// `u32` joints offset value
    pub joints_offset: u32,
}

impl AsAttribute for JointsOffset {
    const NAME: &'static str = "joints_offset";
    const FORMAT: Format = Format::R32Uint;
}

/// Skinned Instance-rate vertex arguments.
/// ```glsl,ignore
///  mat4 model;
///  vec4 tint;
///  uint joints_offset:
/// ```
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[repr(C, packed)]
pub struct SkinnedVertexArgs {
    /// Instance-rate model matrix
    pub model: mat4,
    /// Instance-rate `Tint`
    pub tint: vec4,
    /// Instance-rate joint offset as `u32`
    pub joints_offset: u32,
}

impl AsVertex for SkinnedVertexArgs {
    fn vertex() -> VertexFormat {
        VertexFormat::new((Model::vertex(), Tint::vertex(), JointsOffset::vertex()))
    }
}

impl SkinnedVertexArgs {
    /// Populate `SkinnedVertexArgs` from the supplied `Transform` and `TintComponent`
    #[inline]
    pub fn from_object_data(
        transform: &Transform,
        tint: Option<&TintComponent>,
        joints_offset: u32,
    ) -> Self {
        let model: [[f32; 4]; 4] = convert::<_, Matrix4<f32>>(*transform.global_matrix()).into();
        SkinnedVertexArgs {
            model: model.into(),
            tint: tint.map_or([1.0; 4].into(), |t| {
                let (r, g, b, a) = t.0.into_components();
                [r, g, b, a].into()
            }),
            joints_offset,
        }
    }
}

/// point light struct
/// ```glsl,ignore
/// struct PointLight {
///    vec3 position;
///    vec3 color;
///    float intensity;
/// };
/// ```
#[derive(Clone, Copy, Debug, AsStd140)]
pub struct PointLight {
    /// Light world position
    pub position: vec3,
    /// Light color
    pub color: vec3,
    /// Light intensity (0 - infinity)
    pub intensity: float,
}

/// directional light struct
/// ```glsl,ignore
/// struct DirectionalLight {
///    vec3 color;
///    float intensity;
///    vec3 direction;
/// };
/// ```
#[derive(Clone, Copy, Debug, AsStd140)]
pub struct DirectionalLight {
    /// Light Color
    pub color: vec3,
    /// Light intensity (0 - infinity)
    pub intensity: float,
    /// light cast direction vector
    pub direction: vec3,
}

/// spot light struct
/// ```glsl,ignore
/// struct SpotLight {
///    vec3 position;
///    vec3 color;
///    vec3 direction;
///    float angle;
///    float intensity;
///    float range;
///    float smoothness;
/// };
/// ```
#[derive(Clone, Copy, Debug, AsStd140)]
pub struct SpotLight {
    /// Light world position
    pub position: vec3,
    /// Light Color
    pub color: vec3,
    /// Light direction
    pub direction: vec3,
    /// Angle of the light in radians
    pub angle: float,
    /// Light intensity (0 - infinity)
    pub intensity: float,
    /// Spotlight range
    pub range: float,
    /// Spotlight smoothness
    pub smoothness: float,
}

/// Environment Uniform
/// ```glsl,ignore
/// uniform Environment {
///    vec3 ambient_color;
///    vec3 camera_position;
///    int point_light_count;
///    int directional_light_count;
///    int spot_light_count;
/// };
/// ```
#[derive(Clone, Copy, Debug, AsStd140)]
pub struct Environment {
    /// Ambient color for the entire image
    pub ambient_color: vec3,
    /// Camera world position
    pub camera_position: vec3,
    /// Number of point lights
    pub point_light_count: int,
    /// Number of directional lights
    pub directional_light_count: int,
    /// Number of spot lights
    pub spot_light_count: int,
}

/// Material Uniform
/// ```glsl,ignore
/// uniform Material {
///    UvOffset uv_offset;
///    float alpha_cutoff;
/// };
/// ```
#[derive(Clone, Copy, Debug, AsStd140)]
#[repr(C, align(16))]
pub struct Material {
    /// UV offset of material
    pub uv_offset: TextureOffset,
    /// Material alpha cutoff
    pub alpha_cutoff: float,
}

impl Material {
    /// Helper function from amethyst_rendy 'proper' type to POD type.
    pub fn from_material(mat: &mtl::Material) -> Self {
        Material {
            uv_offset: TextureOffset::from_offset(&mat.uv_offset),
            alpha_cutoff: mat.alpha_cutoff,
        }
    }
}

/// Sprite Vertex Data
/// ```glsl,ignore
/// vec2 dir_x;
/// vec2 dir_y;
/// vec2 pos;
/// vec2 u_offset;
/// vec2 v_offset;
/// float depth;
/// vec4 tint;
/// ```
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, AsStd140)]
#[repr(C, align(4))]
pub struct SpriteArgs {
    /// Rotation of the sprite, X-axis
    pub dir_x: vec2,
    /// Rotation of the sprite, Y-axis
    pub dir_y: vec2,
    /// Screen position of the sprite
    pub pos: vec2,
    /// Upper-left coordinate of the sprite in the spritesheet
    pub u_offset: vec2,
    /// Bottom-right coordinate of the sprite in the spritesheet
    pub v_offset: vec2,
    /// Depth value of this sprite
    pub depth: float,
    /// Tint for this this sprite
    pub tint: vec4,
}

impl AsVertex for SpriteArgs {
    fn vertex() -> VertexFormat {
        VertexFormat::new((
            (Format::Rg32Sfloat, "dir_x"),
            (Format::Rg32Sfloat, "dir_y"),
            (Format::Rg32Sfloat, "pos"),
            (Format::Rg32Sfloat, "u_offset"),
            (Format::Rg32Sfloat, "v_offset"),
            (Format::R32Sfloat, "depth"),
            (Format::Rgba32Sfloat, "tint"),
        ))
    }
}

impl SpriteArgs {
    /// Extracts POD vertex data from the provided storages for a sprite.
    ///
    /// # Arguments
    /// * `tex_storage` - `Texture` Storage
    /// * `sprite_storage` - `SpriteSheet` Storage
    /// * `sprite_render` - `SpriteRender` component reference
    /// * `transform` - 'Transform' component reference
    pub fn from_data<'a>(
        tex_storage: &AssetStorage<Texture>,
        sprite_storage: &'a AssetStorage<SpriteSheet>,
        sprite_render: &SpriteRender,
        transform: &Transform,
        tint: Option<&TintComponent>,
    ) -> Option<(Self, &'a Handle<Texture>)> {
        let sprite_sheet = sprite_storage.get(&sprite_render.sprite_sheet)?;
        if !tex_storage.contains(&sprite_sheet.texture) {
            return None;
        }

        let sprite = &sprite_sheet.sprites[sprite_render.sprite_number];

        let transform = convert::<_, Matrix4<f32>>(*transform.global_matrix());
        let dir_x = transform.column(0) * sprite.width;
        let dir_y = transform.column(1) * -sprite.height;
        let pos = transform * Vector4::new(-sprite.offsets[0], -sprite.offsets[1], 0.0, 1.0);

        Some((
            SpriteArgs {
                dir_x: dir_x.xy().into_pod(),
                dir_y: dir_y.xy().into_pod(),
                pos: pos.xy().into_pod(),
                u_offset: [sprite.tex_coords.left, sprite.tex_coords.right].into(),
                v_offset: [sprite.tex_coords.top, sprite.tex_coords.bottom].into(),
                depth: pos.z,
                tint: tint.map_or([1.0; 4].into(), |t| {
                    let (r, g, b, a) = t.0.into_components();
                    [r, g, b, a].into()
                }),
            },
            &sprite_sheet.texture,
        ))
    }
}

/// Trait for auto conversion into standard GLSL POD types.
pub trait IntoPod<T> {
    /// Converts `Self` to the supplied `T` GLSL type.
    fn into_pod(self) -> T;
}

impl IntoPod<vec2> for amethyst_core::math::Vector2<f32> {
    fn into_pod(self) -> vec2 {
        let arr: [f32; 2] = self.into();
        arr.into()
    }
}

impl IntoPod<vec3> for amethyst_core::math::Vector3<f32> {
    fn into_pod(self) -> vec3 {
        let arr: [f32; 3] = self.into();
        arr.into()
    }
}

impl IntoPod<vec3> for palette::Srgb {
    fn into_pod(self) -> vec3 {
        let (r, g, b) = self.into_components();
        [r, g, b].into()
    }
}

impl IntoPod<[f32; 3]> for palette::Srgb {
    fn into_pod(self) -> [f32; 3] {
        let (r, g, b) = self.into_components();
        [r, g, b]
    }
}

impl IntoPod<vec4> for palette::Srgba {
    fn into_pod(self) -> vec4 {
        let (r, g, b, a) = self.into_components();
        [r, g, b, a].into()
    }
}

impl IntoPod<[f32; 4]> for palette::Srgba {
    fn into_pod(self) -> [f32; 4] {
        let (r, g, b, a) = self.into_components();
        [r, g, b, a]
    }
}