Compare commits
44 commits
floating-p
...
master
Author | SHA1 | Date | |
---|---|---|---|
3ce70531db | |||
e71821fb79 | |||
f4dc18852a | |||
28d85930db | |||
fd36b2aec2 | |||
6efa4a0075 | |||
66a4e60e0d | |||
d1603f4296 | |||
6a4f173604 | |||
ac6920c288 | |||
fdbbd5c51a | |||
ac5aa57d80 | |||
ef22869e48 | |||
2100a9c221 | |||
0a2e37a04d | |||
|
82398896ce | ||
e2a692a912 | |||
cdf01052da | |||
d327791de9 | |||
d5962f10e3 | |||
0b637f7ac3 | |||
ce9d7942cf | |||
0212326d0a | |||
d1eab0d16f | |||
f6e0d12287 | |||
0c56cc6b8e | |||
d91aae4944 | |||
9484e91166 | |||
62a1e102cd | |||
d7eb032095 | |||
08f9ee167a | |||
75d4e6266f | |||
79b8faa00f | |||
e8a5758103 | |||
4e550893bb | |||
66ccaecd8f | |||
7bf1c91a99 | |||
73bbd64cc0 | |||
d1d7b59081 | |||
da58ee9824 | |||
dd83ff2c9e | |||
c3589bdc1b | |||
46dad30da9 | |||
a84ee1724d |
1
.gitattributes
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
assignment-2*/ext/* linguist-vendored
|
3
.gitignore
vendored
|
@ -1 +1,4 @@
|
||||||
.direnv
|
.direnv
|
||||||
|
.pijul
|
||||||
|
|
||||||
|
/target
|
||||||
|
|
2
.ignore
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
.git
|
||||||
|
.DS_Store
|
1288
Cargo.lock
generated
Normal file
20
Cargo.toml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
[workspace]
|
||||||
|
members = [
|
||||||
|
"assignment-0",
|
||||||
|
"assignment-1a",
|
||||||
|
"assignment-1b",
|
||||||
|
"assignment-1c",
|
||||||
|
"assignment-1d",
|
||||||
|
"assignment-2a-rust",
|
||||||
|
]
|
||||||
|
|
||||||
|
# For profiling with flamegraphs
|
||||||
|
[profile.release]
|
||||||
|
debug = true
|
||||||
|
|
||||||
|
# Optimize for size when creating handin
|
||||||
|
[profile.release-handin]
|
||||||
|
inherits = "release"
|
||||||
|
strip = true
|
||||||
|
lto = true
|
||||||
|
|
|
@ -4,16 +4,6 @@ authors = ["Michael Zhang <zhan4854@umn.edu>"]
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# For profiling with flamegraphs
|
|
||||||
[profile.release]
|
|
||||||
debug = true
|
|
||||||
|
|
||||||
# Optimize for size when creating handin
|
|
||||||
[profile.release-handin]
|
|
||||||
inherits = "release"
|
|
||||||
strip = true
|
|
||||||
lto = true
|
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "raytracer1b"
|
name = "raytracer1b"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
|
@ -4,16 +4,6 @@ authors = ["Michael Zhang <zhan4854@umn.edu>"]
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# For profiling with flamegraphs
|
|
||||||
[profile.release]
|
|
||||||
debug = true
|
|
||||||
|
|
||||||
# Optimize for size when creating handin
|
|
||||||
[profile.release-handin]
|
|
||||||
inherits = "release"
|
|
||||||
strip = true
|
|
||||||
lto = true
|
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "raytracer1c"
|
name = "raytracer1c"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
BIN
assignment-1c/examples/hw1c_grading_files/Test1.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
14
assignment-1c/examples/hw1c_grading_files/Test1.txt
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
eye 0 0 0
|
||||||
|
viewdir 0 0 -1
|
||||||
|
updir 0 1 0
|
||||||
|
hfov 60
|
||||||
|
imsize 512 256
|
||||||
|
bkgcolor 0.1 0.1 0.1
|
||||||
|
light -2 1 0 1 1 1 1
|
||||||
|
mtlcolor 0 1 0 1 1 1 0.2 0.6 0.2 20
|
||||||
|
v 0 1 -4
|
||||||
|
v -1 -1 -4
|
||||||
|
v 1 -1 -4
|
||||||
|
v 2 1 -6
|
||||||
|
f 1 2 3
|
||||||
|
f 1 3 4
|
BIN
assignment-1c/examples/hw1c_grading_files/Test2.png
Normal file
After Width: | Height: | Size: 12 KiB |
18
assignment-1c/examples/hw1c_grading_files/Test2.txt
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
eye 0 0 0
|
||||||
|
viewdir 0 0 -1
|
||||||
|
updir 0 1 0
|
||||||
|
hfov 60
|
||||||
|
imsize 512 256
|
||||||
|
bkgcolor 0.1 0.1 0.1
|
||||||
|
light -2 1 0 1 1 1 1
|
||||||
|
mtlcolor 0 0 1 1 1 1 0.2 0.6 0.2 20
|
||||||
|
v -1 1 -4
|
||||||
|
v -1 -1 -4
|
||||||
|
v 1 -1 -4
|
||||||
|
v 1 1 -4
|
||||||
|
vn -1 1 1
|
||||||
|
vn -1 -1 1
|
||||||
|
vn 1 -1 1
|
||||||
|
vn 1 1 1
|
||||||
|
f 1//1 2//2 3//3
|
||||||
|
f 1//1 3//3 4//4
|
BIN
assignment-1c/examples/hw1c_grading_files/Test3.png
Normal file
After Width: | Height: | Size: 105 KiB |
10
assignment-1c/examples/hw1c_grading_files/Test3.txt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
eye 2 -6 1
|
||||||
|
viewdir -1 3 -0.5
|
||||||
|
updir 0 0 1
|
||||||
|
hfov 50
|
||||||
|
imsize 512 512
|
||||||
|
bkgcolor 0.5 0.7 0.9
|
||||||
|
light 0 1 -1 0 1 1 1
|
||||||
|
mtlcolor 0 1 0 1 1 1 0.2 0.8 0.1 20
|
||||||
|
texture earthtexture.ppm
|
||||||
|
sphere 0 0 0 2
|
BIN
assignment-1c/examples/hw1c_grading_files/Test4.png
Normal file
After Width: | Height: | Size: 28 KiB |
19
assignment-1c/examples/hw1c_grading_files/Test4.txt
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
eye 0 0 0
|
||||||
|
viewdir 0 0 -1
|
||||||
|
updir 0 1 0
|
||||||
|
hfov 60
|
||||||
|
imsize 512 256
|
||||||
|
bkgcolor 0.1 0.1 0.1
|
||||||
|
light -2 1 0 1 1 1 1
|
||||||
|
mtlcolor 0 0 1 1 1 1 0.2 0.6 0.2 20
|
||||||
|
texture umn.ppm
|
||||||
|
v -1 1 -4
|
||||||
|
v -1 -1 -4
|
||||||
|
v 1 -1 -4
|
||||||
|
v 1 1 -4
|
||||||
|
vt 0 0
|
||||||
|
vt 0 1
|
||||||
|
vt 1 1
|
||||||
|
vt 1 0
|
||||||
|
f 1/1 2/2 3/3
|
||||||
|
f 1/1 3/3 4/4
|
BIN
assignment-1c/examples/hw1c_grading_files/Test5.png
Normal file
After Width: | Height: | Size: 25 KiB |
25
assignment-1c/examples/hw1c_grading_files/Test5.txt
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
eye 0 0 0
|
||||||
|
viewdir 0 0 -1
|
||||||
|
updir 0 1 0
|
||||||
|
hfov 60
|
||||||
|
imsize 512 256
|
||||||
|
bkgcolor 0.1 0.1 0.1
|
||||||
|
light -2 1 0 1 1 1 1
|
||||||
|
mtlcolor 0 0 1 1 1 1 0.2 0.6 0.2 20
|
||||||
|
texture umn.ppm
|
||||||
|
v -1 1 -4
|
||||||
|
v -1 -1 -4
|
||||||
|
v 1 -1 -4
|
||||||
|
v 1 1 -4
|
||||||
|
vn -1 1 1
|
||||||
|
vn -1 -1 1
|
||||||
|
vn 1 -1 1
|
||||||
|
vn 1 1 1
|
||||||
|
vt 0 0
|
||||||
|
vt 0 1
|
||||||
|
vt 1 1
|
||||||
|
vt 1 0
|
||||||
|
f 1/1/1 2/2/2 3/3/3
|
||||||
|
f 1/1/1 3/3/3 4/4/4
|
||||||
|
|
||||||
|
|
BIN
assignment-1c/examples/hw1c_grading_files/Test6.png
Normal file
After Width: | Height: | Size: 640 KiB |
56
assignment-1c/examples/hw1c_grading_files/Test6.txt
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
eye 12.5 5 2.5
|
||||||
|
viewdir -2 -0.5 2
|
||||||
|
updir 0 1 0
|
||||||
|
hfov 60
|
||||||
|
imsize 900 600
|
||||||
|
bkgcolor 0.5 0.7 0.9
|
||||||
|
light 1 -1 1 0 1 1 1
|
||||||
|
mtlcolor 0 1 0 1 1 1 0.2 0.8 0 20
|
||||||
|
v 10 0 5
|
||||||
|
v -10 0 5
|
||||||
|
v -10 0 25
|
||||||
|
v 10 0 25
|
||||||
|
v 5 0 12.5
|
||||||
|
v -5 0 12.5
|
||||||
|
v -5 5 12.5
|
||||||
|
v 5 5 12.5
|
||||||
|
v 5 0 17.5
|
||||||
|
v -5 0 17.5
|
||||||
|
v -5 5 17.5
|
||||||
|
v 5 5 17.5
|
||||||
|
v 5 7.5 15
|
||||||
|
v -5 7.5 15
|
||||||
|
v 5 4.5 12
|
||||||
|
v -5 4.5 12
|
||||||
|
v 5 4.5 18
|
||||||
|
v -5 4.5 18
|
||||||
|
vt 0 0
|
||||||
|
vt 0 1
|
||||||
|
vt 1 1
|
||||||
|
vt 1 0
|
||||||
|
vt 2 0
|
||||||
|
vt 2 1
|
||||||
|
vt 0.5 0
|
||||||
|
vt 4 0
|
||||||
|
vt 4 1
|
||||||
|
texture grass.ppm
|
||||||
|
f 1/2 2/3 3/4
|
||||||
|
f 1/2 3/4 4/1
|
||||||
|
texture wood.ppm
|
||||||
|
f 5/2 6/6 7/5
|
||||||
|
f 5/2 7/5 8/1
|
||||||
|
f 9/2 11/5 10/6
|
||||||
|
f 9/2 12/1 11/5
|
||||||
|
f 6/2 10/3 11/4
|
||||||
|
f 6/2 11/4 7/1
|
||||||
|
f 5/3 12/1 9/2
|
||||||
|
f 5/3 8/4 12/1
|
||||||
|
f 7/2 11/3 14/7
|
||||||
|
f 8/3 13/7 12/2
|
||||||
|
texture redwood.ppm
|
||||||
|
f 13/1 15/2 16/9
|
||||||
|
f 13/1 16/9 14/8
|
||||||
|
f 13/8 14/1 18/2
|
||||||
|
f 13/8 18/2 17/9
|
||||||
|
texture soccerball.ppm
|
||||||
|
sphere -2.5 0.5 9 0.5
|
BIN
assignment-1c/examples/hw1c_grading_files/TestE.png
Normal file
After Width: | Height: | Size: 46 KiB |
20
assignment-1c/examples/hw1c_grading_files/TestE.txt
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
eye 0 0 0
|
||||||
|
viewdir 0 0 -1
|
||||||
|
updir 0 1 0
|
||||||
|
hfov 60
|
||||||
|
imsize 512 256
|
||||||
|
bkgcolor 0.1 0.1 0.1
|
||||||
|
light -2 1 0 1 1 1 1
|
||||||
|
mtlcolor 1 1 1 1 1 1 0.2 0.6 0.2 20 1 0
|
||||||
|
bump normalmap.ppm
|
||||||
|
sphere -1.6 0 -4 0.5
|
||||||
|
v -1 1 -4
|
||||||
|
v -1 -1 -4
|
||||||
|
v 1 -1 -4
|
||||||
|
v 1 1 -4
|
||||||
|
vt 0 0
|
||||||
|
vt 0 1
|
||||||
|
vt 1 1
|
||||||
|
vt 1 0
|
||||||
|
f 1/1 2/2 3/3
|
||||||
|
f 1/1 3/3 4/4
|
2
assignment-1c/examples/hw1c_grading_files/grading.sh
Executable file
|
@ -0,0 +1,2 @@
|
||||||
|
#! /bin/sh
|
||||||
|
PROGRAM_NAME="raytracer1c"; echo "-------- Running Test1.txt --------"; ./$PROGRAM_NAME Test1.txt; echo "-------- Running Test2.txt --------";./$PROGRAM_NAME Test2.txt; echo "-------- Running Test3.txt --------";./$PROGRAM_NAME Test3.txt; echo "-------- Running Test4.txt --------";./$PROGRAM_NAME Test4.txt; echo "-------- Running Test5.txt --------";./$PROGRAM_NAME Test5.txt; echo "-------- Running Test6.txt --------";./$PROGRAM_NAME Test6.txt; echo "-------- Running TestE.txt --------";./$PROGRAM_NAME TestE.txt;
|
|
@ -4,7 +4,7 @@ extern crate tracing;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{Context, Result};
|
||||||
use assignment_1c::image::Image;
|
use assignment_1c::image::Image;
|
||||||
use assignment_1c::ray::Ray;
|
use assignment_1c::ray::Ray;
|
||||||
use assignment_1c::scene::Scene;
|
use assignment_1c::scene::Scene;
|
||||||
|
@ -112,9 +112,9 @@ fn main() -> Result<()> {
|
||||||
|
|
||||||
Ok(match earliest_intersection {
|
Ok(match earliest_intersection {
|
||||||
// Take the object's material color
|
// Take the object's material color
|
||||||
Some((obj_idx, intersection_context, object)) => {
|
Some((obj_idx, intersection_context, object)) => scene
|
||||||
scene.compute_pixel_color(obj_idx, object, intersection_context)?
|
.compute_pixel_color(obj_idx, object, intersection_context)
|
||||||
}
|
.context("Could not compute pixel color.")?,
|
||||||
|
|
||||||
// There was no intersection, so this should default to the scene's
|
// There was no intersection, so this should default to the scene's
|
||||||
// background color
|
// background color
|
||||||
|
|
|
@ -43,7 +43,7 @@ impl Scene {
|
||||||
|
|
||||||
let texture = match self.textures.get(texture_idx) {
|
let texture = match self.textures.get(texture_idx) {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => bail!("Texture index not found."),
|
None => bail!("Texture index {texture_idx} not found."),
|
||||||
};
|
};
|
||||||
|
|
||||||
texture.pixel_at(u, v)
|
texture.pixel_at(u, v)
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::path::Path;
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use nalgebra::Vector3;
|
use nalgebra::{Vector2, Vector3};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
image::{Color, Image},
|
image::{Color, Image},
|
||||||
|
@ -13,7 +13,7 @@ use crate::{
|
||||||
data::{Attenuation, Light, LightKind, Material},
|
data::{Attenuation, Light, LightKind, Material},
|
||||||
object::{Object, ObjectKind},
|
object::{Object, ObjectKind},
|
||||||
sphere::Sphere,
|
sphere::Sphere,
|
||||||
texture::{Texture, NormalMap},
|
texture::Texture,
|
||||||
triangle::Triangle,
|
triangle::Triangle,
|
||||||
Scene,
|
Scene,
|
||||||
},
|
},
|
||||||
|
@ -209,6 +209,9 @@ impl Scene {
|
||||||
// vn nx ny nz
|
// vn nx ny nz
|
||||||
"vn" => scene.vertex_normals.push(r!(Vector)),
|
"vn" => scene.vertex_normals.push(r!(Vector)),
|
||||||
|
|
||||||
|
// vt u v
|
||||||
|
"vt" => scene.texture_vertices.push(r!(Vector2<f64>)),
|
||||||
|
|
||||||
// f v1 v2 v3
|
// f v1 v2 v3
|
||||||
// f v1//n1 v2//n2 v3//n3
|
// f v1//n1 v2//n2 v3//n3
|
||||||
"f" => {
|
"f" => {
|
||||||
|
@ -230,7 +233,7 @@ impl Scene {
|
||||||
let textures = match textures.iter().filter(|o| o.is_some()).count() {
|
let textures = match textures.iter().filter(|o| o.is_some()).count() {
|
||||||
0 => None,
|
0 => None,
|
||||||
n if n == vs.len() => Some(textures.map(|o| o.unwrap())),
|
n if n == vs.len() => Some(textures.map(|o| o.unwrap())),
|
||||||
_ => bail!("Cannot mix and match having a normal index"),
|
_ => bail!("Cannot mix and match having a texture index"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let triangle = Triangle {
|
let triangle = Triangle {
|
||||||
|
@ -256,7 +259,7 @@ impl Scene {
|
||||||
texture_idx = Some(idx);
|
texture_idx = Some(idx);
|
||||||
|
|
||||||
let image = Image::from_file(path)?;
|
let image = Image::from_file(path)?;
|
||||||
let texture = Texture::new(image);
|
let texture = Texture::new(image, false);
|
||||||
scene.textures.push(texture);
|
scene.textures.push(texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,8 +274,8 @@ impl Scene {
|
||||||
texture_idx = Some(idx);
|
texture_idx = Some(idx);
|
||||||
|
|
||||||
let image = Image::from_file(path)?;
|
let image = Image::from_file(path)?;
|
||||||
let normal_map = NormalMap::new(image);
|
let normal_map = Texture::new(image, true);
|
||||||
scene.normal_maps.push(normal_map);
|
scene.textures.push(normal_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => bail!("Unknown keyword {keyword}"),
|
_ => bail!("Unknown keyword {keyword}"),
|
||||||
|
@ -332,6 +335,25 @@ macro_rules! impl_construct {
|
||||||
impl_construct!(f64);
|
impl_construct!(f64);
|
||||||
impl_construct!(usize);
|
impl_construct!(usize);
|
||||||
|
|
||||||
|
impl Construct for Vector2<f64> {
|
||||||
|
type Args = ();
|
||||||
|
|
||||||
|
fn construct<'a, I>(it: &mut I, _: Self::Args) -> Result<Self>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = &'a str>,
|
||||||
|
{
|
||||||
|
let (x, y) = match it.next_tuple() {
|
||||||
|
Some(v) => v,
|
||||||
|
None => bail!("Expected 2 values"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let x: f64 = x.parse()?;
|
||||||
|
let y: f64 = y.parse()?;
|
||||||
|
|
||||||
|
Ok(Vector2::new(x, y))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Construct for Vector3<f64> {
|
impl Construct for Vector3<f64> {
|
||||||
type Args = ();
|
type Args = ();
|
||||||
|
|
||||||
|
|
|
@ -7,12 +7,14 @@ pub mod sphere;
|
||||||
pub mod texture;
|
pub mod texture;
|
||||||
pub mod triangle;
|
pub mod triangle;
|
||||||
|
|
||||||
|
use nalgebra::Vector2;
|
||||||
|
|
||||||
use crate::image::Color;
|
use crate::image::Color;
|
||||||
use crate::{Point, Point2, Vector};
|
use crate::{Point, Point2, Vector};
|
||||||
|
|
||||||
use self::data::{Attenuation, DepthCueing, Light, Material};
|
use self::data::{Attenuation, DepthCueing, Light, Material};
|
||||||
use self::object::Object;
|
use self::object::Object;
|
||||||
use self::texture::{Texture, NormalMap};
|
use self::texture::{Texture};
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Scene {
|
pub struct Scene {
|
||||||
|
@ -40,7 +42,7 @@ pub struct Scene {
|
||||||
pub textures: Vec<Texture>,
|
pub textures: Vec<Texture>,
|
||||||
|
|
||||||
/// List of normal maps (Extra credit)
|
/// List of normal maps (Extra credit)
|
||||||
pub normal_maps: Vec<NormalMap>,
|
pub normal_maps: Vec<Texture>,
|
||||||
|
|
||||||
/// Coordinates into a texture image
|
/// Coordinates into a texture image
|
||||||
pub texture_vertices: Vec<Point2>,
|
pub texture_vertices: Vec<Point2>,
|
||||||
|
|
|
@ -4,17 +4,33 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Texture(Image);
|
pub struct Texture {
|
||||||
|
image: Image,
|
||||||
|
is_normal_map: bool,
|
||||||
|
}
|
||||||
|
|
||||||
impl Texture {
|
impl Texture {
|
||||||
pub fn new(image: Image) -> Self {
|
pub fn new(image: Image, is_normal_map: bool) -> Self {
|
||||||
Self(image)
|
Self {
|
||||||
|
image,
|
||||||
|
is_normal_map,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pixel_at_exact(&self, x: usize, y: usize) -> Color {
|
pub fn pixel_at_exact(&self, x: usize, y: usize) -> Color {
|
||||||
// TODO: Debug asserts?
|
// TODO: Debug asserts?
|
||||||
|
|
||||||
self.0.data[y * self.0.width + x]
|
let x = match x {
|
||||||
|
n if n < self.image.width => n,
|
||||||
|
_ => self.image.width - 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let y = match y {
|
||||||
|
n if n < self.image.height => n,
|
||||||
|
_ => self.image.height - 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.image.data[y * self.image.width + x]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a pixel at the given coordinate. For non-lattice coordinates,
|
/// Returns a pixel at the given coordinate. For non-lattice coordinates,
|
||||||
|
@ -24,8 +40,8 @@ impl Texture {
|
||||||
debug_assert!(0.0 <= v && v <= 1.0, "u must be between 0 and 1");
|
debug_assert!(0.0 <= v && v <= 1.0, "u must be between 0 and 1");
|
||||||
|
|
||||||
// Slide 121
|
// Slide 121
|
||||||
let x = u * (self.0.width - 1) as f64;
|
let x = u * (self.image.width - 1) as f64;
|
||||||
let y = v * (self.0.height - 1) as f64;
|
let y = v * (self.image.height - 1) as f64;
|
||||||
|
|
||||||
let i = x.floor();
|
let i = x.floor();
|
||||||
let j = y.floor();
|
let j = y.floor();
|
||||||
|
@ -42,23 +58,3 @@ impl Texture {
|
||||||
+ (alpha) * (beta) * self.pixel_at_exact(i + 1, j + 1)
|
+ (alpha) * (beta) * self.pixel_at_exact(i + 1, j + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct NormalMap(Image);
|
|
||||||
|
|
||||||
impl NormalMap {
|
|
||||||
pub fn new(image: Image) -> Self {
|
|
||||||
Self(image)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn normal_vector_at_exact(&self, x: usize, y: usize) -> Vector {
|
|
||||||
let vec = self.0.data[y * self.0.width + x];
|
|
||||||
|
|
||||||
// So, according to the instructions, this should actually be a value
|
|
||||||
// between -1 and 1. However, we're reading this in through an image.
|
|
||||||
// I'm just going to do the lazy thing here (which theoretically
|
|
||||||
// actually saves cycles) by only doing the transformation when loading
|
|
||||||
// out of the image
|
|
||||||
vec.map(|value| 2.0 * value / 255.0 - 1.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
2
assignment-1d/.cargo/config.toml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[registries.crates-io]
|
||||||
|
protocol = "sparse"
|
11
assignment-1d/.gitignore
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
/target
|
||||||
|
/assignment-1*
|
||||||
|
/raytracer1*
|
||||||
|
/examples/*.png
|
||||||
|
*.ppm
|
||||||
|
*.zip
|
||||||
|
*.pdf
|
||||||
|
perf.data*
|
||||||
|
flamegraph.svg
|
||||||
|
showcase.png
|
||||||
|
/out.log
|
0
assignment-1d/ASSIGNMENT.md
Normal file
1068
assignment-1d/Cargo.lock
generated
Normal file
30
assignment-1d/Cargo.toml
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
[package]
|
||||||
|
name = "assignment-1d"
|
||||||
|
authors = ["Michael Zhang <zhan4854@umn.edu>"]
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
release-handin = ["tracing/release_max_level_info"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "raytracer1d"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = { version = "1.0.68", features = ["backtrace"] }
|
||||||
|
base64 = "0.21.0"
|
||||||
|
clap = { version = "4.1.4", features = ["cargo", "derive"] }
|
||||||
|
contracts = "0.6.3"
|
||||||
|
derivative = "2.2.0"
|
||||||
|
either = "1.8.1"
|
||||||
|
generator = "0.7.2"
|
||||||
|
itertools = "0.10.5"
|
||||||
|
nalgebra = "0.32.1"
|
||||||
|
num = { version = "0.4.0", features = ["serde"] }
|
||||||
|
ordered-float = "3.4.0"
|
||||||
|
rand = "0.8.5"
|
||||||
|
rayon = "1.6.1"
|
||||||
|
tracing = "0.1.37"
|
||||||
|
tracing-appender = "0.2.2"
|
||||||
|
tracing-subscriber = { version = "0.3.16", features = ["json"] }
|
53
assignment-1d/Makefile
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
|
.PRECIOUS: $(EXAMPLES_PPM)
|
||||||
|
|
||||||
|
DEBUG :=
|
||||||
|
CARGO_FLAGS := --release
|
||||||
|
RAYTRACER_FLAGS :=
|
||||||
|
DOCKER := docker
|
||||||
|
ZIP := zip
|
||||||
|
PANDOC := pandoc
|
||||||
|
CONVERT := convert
|
||||||
|
|
||||||
|
ifeq ($(DEBUG),1)
|
||||||
|
RAYTRACER_FLAGS += -vvvv
|
||||||
|
else
|
||||||
|
endif
|
||||||
|
|
||||||
|
HANDIN := ./hw1d.michael.zhang.zip
|
||||||
|
BINARY := ./raytracer1d
|
||||||
|
SOURCES := Cargo.toml $(shell find -name "*.rs")
|
||||||
|
|
||||||
|
EXAMPLES := $(shell find examples -name "*.txt")
|
||||||
|
EXAMPLES_PPM := $(patsubst %.txt,%.ppm,$(EXAMPLES))
|
||||||
|
EXAMPLES_PNG := $(patsubst %.txt,%.png,$(EXAMPLES))
|
||||||
|
|
||||||
|
all: $(HANDIN)
|
||||||
|
|
||||||
|
$(BINARY): $(SOURCES)
|
||||||
|
mkdir -p target/docker
|
||||||
|
$(DOCKER) run \
|
||||||
|
--rm \
|
||||||
|
-v "$(shell pwd)":/usr/src/myapp \
|
||||||
|
-v cargo-registry:/usr/local/cargo \
|
||||||
|
--user "$(shell id -u)":"$(shell id -g)" \
|
||||||
|
-w /usr/src/myapp \
|
||||||
|
-e CARGO_TARGET_DIR=/usr/src/myapp/target/docker \
|
||||||
|
rust \
|
||||||
|
cargo build --profile release-handin --features release-handin
|
||||||
|
mv target/docker/release-handin/raytracer1d $@
|
||||||
|
|
||||||
|
$(HANDIN): $(BINARY) Makefile Cargo.toml Cargo.lock README.md $(EXAMPLES_PNG) $(EXAMPLES_PPM)
|
||||||
|
$(ZIP) -r $@ src examples $^
|
||||||
|
|
||||||
|
examples/%.ppm: examples/%.txt $(SOURCES)
|
||||||
|
cargo run $(CARGO_FLAGS) -- -o $@ $(RAYTRACER_FLAGS) $<
|
||||||
|
|
||||||
|
examples/%.png: examples/%.ppm
|
||||||
|
convert $< $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf target/docker \
|
||||||
|
$(HANDIN) $(BINARY) \
|
||||||
|
$(EXAMPLES_PPM) $(EXAMPLES_PNG)
|
29
assignment-1d/README.md
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
# Raycaster
|
||||||
|
|
||||||
|
## Bundle contents
|
||||||
|
|
||||||
|
Writeup is located at `/writeup.pdf`.
|
||||||
|
|
||||||
|
The binary can be found at `/raytracer1b`. Run `./raytracer1b --help` to see
|
||||||
|
how to use it. The binary has been built using the Rust Docker image, which
|
||||||
|
should have an environment similar to CSELabs. If there is trouble running the
|
||||||
|
binary, try building from source, as documented below.
|
||||||
|
|
||||||
|
Examples are found in the `examples` directory. The text files are the input
|
||||||
|
sources, and the ppm files are the corresponding outputs. They have been
|
||||||
|
generated by running this program. For convenience, pngs have also been provided
|
||||||
|
using imagemagick.
|
||||||
|
|
||||||
|
## Showcase image
|
||||||
|
|
||||||
|
The showcase image can be found at `/showcase.png`.
|
||||||
|
|
||||||
|
## Building from source
|
||||||
|
|
||||||
|
The Makefile currently uses Docker to produce a more consistent build. If you
|
||||||
|
have a Rust+Cargo toolchain installed locally, it's also possible to build the
|
||||||
|
source using just:
|
||||||
|
|
||||||
|
cargo build --release
|
||||||
|
|
||||||
|
The binary will be found in `target/release`.
|
2
assignment-1d/examples/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# Necessary files
|
||||||
|
!/earthtexture.ppm
|
22
assignment-1d/examples/Hw1dSample1.txt
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
eye 0 5 0
|
||||||
|
viewdir 0 0 1
|
||||||
|
updir 0 1 0
|
||||||
|
hfov 45
|
||||||
|
imsize 1080 1080
|
||||||
|
bkgcolor 0.5 0.7 0.9 1
|
||||||
|
light 0 -1 0 0 1 1 1
|
||||||
|
mtlcolor 1 1 1 1 1 1 0.2 0.4 0.6 60 0.2 1.5
|
||||||
|
sphere 1.25 8 15 1
|
||||||
|
sphere 0 6 15 1
|
||||||
|
sphere 1.5 4 15 1
|
||||||
|
mtlcolor 1 1 1 1 1 1 0.2 0.4 0.6 60 1 0
|
||||||
|
sphere -1.5 4 15 1
|
||||||
|
|
||||||
|
mtlcolor 1 1 1 1 1 1 0.2 0.8 0 20 1 0
|
||||||
|
v 10 0 5
|
||||||
|
v -10 0 5
|
||||||
|
v -10 0 25
|
||||||
|
v 10 0 25
|
||||||
|
|
||||||
|
f 1 2 3
|
||||||
|
f 1 3 4
|
12
assignment-1d/examples/Hw1dSample2.txt
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
eye 0 0 0
|
||||||
|
viewdir 1 0 0
|
||||||
|
updir 0 0 1
|
||||||
|
hfov 60
|
||||||
|
imsize 1080 1080
|
||||||
|
bkgcolor 0.5 0.7 0.9 1
|
||||||
|
light 0 94820000 -28450000 1 0 0 0
|
||||||
|
mtlcolor 1 1 1 1 1 1 0 0.05 0.1 80 1 30
|
||||||
|
sphere 3 0 0 1
|
||||||
|
mtlcolor 0 1 0 1 1 1 1 0 0 1 1 0
|
||||||
|
texture harbor.ppm
|
||||||
|
sphere 0 0 0 100000000
|
18
assignment-1d/examples/sample-1-but-only-1-sphere.txt
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
eye 0 5 0
|
||||||
|
viewdir 0 0 1
|
||||||
|
updir 0 1 0
|
||||||
|
hfov 45
|
||||||
|
imsize 1080 1080
|
||||||
|
bkgcolor 0.5 0.7 0.9 1
|
||||||
|
light 0 -1 0 0 1 1 1
|
||||||
|
mtlcolor 1 1 1 1 1 1 0.2 0.4 0.6 60 1 0
|
||||||
|
sphere -1.5 4 15 1
|
||||||
|
|
||||||
|
mtlcolor 1 1 1 1 1 1 0.2 0.8 0 20 1 0
|
||||||
|
v 10 0 5
|
||||||
|
v -10 0 5
|
||||||
|
v -10 0 25
|
||||||
|
v 10 0 25
|
||||||
|
|
||||||
|
f 1 2 3
|
||||||
|
f 1 3 4
|
18
assignment-1d/examples/sample-1-but-only-transparent.txt
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
eye 0 5 0
|
||||||
|
viewdir 0 0 1
|
||||||
|
updir 0 1 0
|
||||||
|
hfov 45
|
||||||
|
imsize 128 128
|
||||||
|
bkgcolor 0.5 0.7 0.9 1
|
||||||
|
light 0 -1 0 0 1 1 1
|
||||||
|
mtlcolor 1 1 1 1 1 1 0.2 0.4 0.6 60 0.2 1.5
|
||||||
|
sphere 0 6 15 3
|
||||||
|
|
||||||
|
mtlcolor 1 1 1 1 1 1 0.2 0.8 0 20 1 0
|
||||||
|
v 10 0 5
|
||||||
|
v -10 0 5
|
||||||
|
v -10 0 25
|
||||||
|
v 10 0 25
|
||||||
|
|
||||||
|
f 1 2 3
|
||||||
|
f 1 3 4
|
45
assignment-1d/examples/soft-shadow-demo.txt
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
imsize 640 480
|
||||||
|
eye 0 0 15
|
||||||
|
viewdir 0 0 -1
|
||||||
|
hfov 60
|
||||||
|
updir 0 1 0
|
||||||
|
bkgcolor 0.5 0.5 0.5
|
||||||
|
|
||||||
|
depthcueing 0.5 0.5 0.5 1 0.4 60 0
|
||||||
|
|
||||||
|
light 10 10 -10 1 1 1 1
|
||||||
|
|
||||||
|
mtlcolor 0.5 1 0.5 1 1 1 0.2 1 0.1 5 0.5 1
|
||||||
|
sphere 4.5 4.5 -20 4.5
|
||||||
|
sphere -4.5 -4.5 -20 4.5
|
||||||
|
|
||||||
|
mtlcolor 1 0.5 0.5 1 1 1 0.2 0.8 0 5 0.8 1
|
||||||
|
sphere -10 0 -30 4
|
||||||
|
sphere -20 0 -30 4
|
||||||
|
sphere -30 0 -30 4
|
||||||
|
sphere -40 0 -30 4
|
||||||
|
sphere 0 0 -30 4
|
||||||
|
sphere 10 0 -30 4
|
||||||
|
sphere 20 0 -30 4
|
||||||
|
sphere 30 0 -30 4
|
||||||
|
sphere 40 0 -30 4
|
||||||
|
|
||||||
|
sphere -10 -10 -30 4
|
||||||
|
sphere -20 -10 -30 4
|
||||||
|
sphere -30 -10 -30 4
|
||||||
|
sphere -40 -10 -30 4
|
||||||
|
sphere 0 -10 -30 4
|
||||||
|
sphere 10 -10 -30 4
|
||||||
|
sphere 20 -10 -30 4
|
||||||
|
sphere 30 -10 -30 4
|
||||||
|
sphere 40 -10 -30 4
|
||||||
|
|
||||||
|
sphere -10 10 -30 4
|
||||||
|
sphere -20 10 -30 4
|
||||||
|
sphere -30 10 -30 4
|
||||||
|
sphere -40 10 -30 4
|
||||||
|
sphere 0 10 -30 4
|
||||||
|
sphere 10 10 -30 4
|
||||||
|
sphere 20 10 -30 4
|
||||||
|
sphere 30 10 -30 4
|
||||||
|
sphere 40 10 -30 4
|
29
assignment-1d/examples/surface-reflect.txt
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
imsize 1366 768
|
||||||
|
eye 0 5 -2
|
||||||
|
viewdir 0 -0.2 1
|
||||||
|
hfov 60
|
||||||
|
updir 0 1 0
|
||||||
|
bkgcolor 0.4 0.5 0.6
|
||||||
|
depthcueing 0.5 0.5 0.5 1 0.4 60 0
|
||||||
|
light 0 -1 0 0 1 1 1
|
||||||
|
|
||||||
|
mtlcolor 1 0.6 0.6 1 1 1 0.2 0.4 0.6 60 0.9 2
|
||||||
|
sphere -1.5 4 15 1
|
||||||
|
|
||||||
|
mtlcolor 0.6 0.6 1 1 1 1 0.2 0.4 0.6 60 0.9 2
|
||||||
|
sphere 0 -1 12 2
|
||||||
|
|
||||||
|
mtlcolor 0.6 1 0.6 1 1 1 0.2 0.4 0.6 60 1 2
|
||||||
|
sphere 6 8 20 3
|
||||||
|
|
||||||
|
mtlcolor 1 1 0.6 1 1 1 0.2 0.4 0.6 60 0.9 2
|
||||||
|
sphere -6 -8 20 4
|
||||||
|
|
||||||
|
mtlcolor 0.7 0.6 0.8 0.5 0.5 0.5 0.2 0.8 0.1 20 0.5 1.5
|
||||||
|
v 10 0 5
|
||||||
|
v -10 0 5
|
||||||
|
v -10 0 25
|
||||||
|
v 10 0 25
|
||||||
|
|
||||||
|
f 1 2 3
|
||||||
|
f 1 3 4
|
11
assignment-1d/examples/transparency-distance.txt
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
eye 0 0 10
|
||||||
|
viewdir 0 0 -1
|
||||||
|
updir 0 1 0
|
||||||
|
hfov 60
|
||||||
|
imsize 512 512
|
||||||
|
bkgcolor 0.5 0.7 0.9 1
|
||||||
|
light 0 -1 0 0 1 1 1
|
||||||
|
|
||||||
|
mtlcolor 0.7 0.2 0.7 1 1 1 0 0.05 0.1 80 0.5 1.5
|
||||||
|
sphere 1 1 -6 3
|
||||||
|
sphere -1 -1 1 3
|
127
assignment-1d/src/image.rs
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
use std::{
|
||||||
|
fs::File,
|
||||||
|
io::{BufRead, BufReader, Read, Write},
|
||||||
|
path::Path,
|
||||||
|
};
|
||||||
|
|
||||||
|
use anyhow::{Context, Result};
|
||||||
|
use generator::{done, Gn};
|
||||||
|
use itertools::Itertools;
|
||||||
|
use nalgebra::Vector3;
|
||||||
|
|
||||||
|
/// A pixel color represented by a red, green, and blue value in the range 0-1.
|
||||||
|
pub type Color = Vector3<f64>;
|
||||||
|
|
||||||
|
/// A representation of an image
|
||||||
|
#[derive(Derivative)]
|
||||||
|
#[derivative(Debug)]
|
||||||
|
pub struct Image {
|
||||||
|
/// Width in pixels
|
||||||
|
pub width: usize,
|
||||||
|
|
||||||
|
/// Height in pixels
|
||||||
|
pub height: usize,
|
||||||
|
|
||||||
|
/// Pixel data in row-major form.
|
||||||
|
#[derivative(Debug = "ignore")]
|
||||||
|
pub data: Vec<Color>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Image {
|
||||||
|
pub fn from_file(path: impl AsRef<Path>) -> Result<Self> {
|
||||||
|
let path = path.as_ref();
|
||||||
|
let file = File::open(path)
|
||||||
|
.with_context(|| format!("Could not open file at {path:?}"))?;
|
||||||
|
Self::read(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse image from a Read
|
||||||
|
pub fn read(r: impl Read + Send) -> Result<Self> {
|
||||||
|
let mut line_reader = BufReader::new(r);
|
||||||
|
|
||||||
|
let mut header = String::new();
|
||||||
|
line_reader
|
||||||
|
.read_line(&mut header)
|
||||||
|
.context("Could not read line")?;
|
||||||
|
let parts = header.trim().split(" ").collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let width = parts[1].parse::<usize>().context("Could not read width")?;
|
||||||
|
let height = parts[2].parse::<usize>().context("Could not read height")?;
|
||||||
|
let max_value = parts[3]
|
||||||
|
.parse::<usize>()
|
||||||
|
.context("Could not read max value")?;
|
||||||
|
|
||||||
|
// Generator for reading numbers
|
||||||
|
let numbers = Gn::<()>::new_scoped(move |mut s| {
|
||||||
|
macro_rules! gen_try {
|
||||||
|
($expr:expr, $str:expr $(, $($arg:expr),* $(,)?)?) => {
|
||||||
|
match $expr {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => {
|
||||||
|
s.yield_(
|
||||||
|
Err(anyhow::Error::from(e))
|
||||||
|
.with_context(|| format!($str $(, $($arg,)*)?)),
|
||||||
|
);
|
||||||
|
done!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
for line in line_reader.lines() {
|
||||||
|
let line = gen_try!(line, "Could not read line");
|
||||||
|
let parts = line.trim().split_whitespace();
|
||||||
|
|
||||||
|
for part in parts {
|
||||||
|
let int =
|
||||||
|
gen_try!(part.parse::<u64>(), "Could not read int from: {}", part);
|
||||||
|
s.yield_(Ok(int));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done!()
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut data = Vec::with_capacity(width * height);
|
||||||
|
for mut chunk in &(numbers).chunks(3) {
|
||||||
|
let (r, g, b) = match chunk.next_tuple() {
|
||||||
|
Some(v) => v,
|
||||||
|
None => bail!("Not enough elements"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let r = r? as f64 / max_value as f64;
|
||||||
|
let g = g? as f64 / max_value as f64;
|
||||||
|
let b = b? as f64 / max_value as f64;
|
||||||
|
|
||||||
|
let color = Color::new(r, g, b);
|
||||||
|
data.push(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Image {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write the image in PPM format to a file.
|
||||||
|
pub fn write(&self, mut w: impl Write) -> Result<()> {
|
||||||
|
// Header
|
||||||
|
let header = format!("P3 {} {} 255\n", self.width, self.height);
|
||||||
|
w.write_all(header.as_bytes())?;
|
||||||
|
|
||||||
|
// Pixel data
|
||||||
|
assert_eq!(self.data.len(), self.width * self.height);
|
||||||
|
|
||||||
|
for pixel in self.data.iter() {
|
||||||
|
let pixel = pixel * 256.0;
|
||||||
|
let red = pixel.x as u8;
|
||||||
|
let green = pixel.y as u8;
|
||||||
|
let blue = pixel.z as u8;
|
||||||
|
let pixel = format!("{red} {green} {blue}\n");
|
||||||
|
w.write_all(pixel.as_bytes())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
22
assignment-1d/src/lib.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
use nalgebra::{Vector2, Vector3};
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate anyhow;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate contracts;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate derivative;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate tracing;
|
||||||
|
|
||||||
|
pub mod image;
|
||||||
|
pub mod ray;
|
||||||
|
pub mod scene;
|
||||||
|
pub mod utils;
|
||||||
|
|
||||||
|
// Creating a bunch of aliases here to make it more obvious which one I'm
|
||||||
|
// expecting a variable to be
|
||||||
|
|
||||||
|
pub type Point2 = Vector2<f64>;
|
||||||
|
pub type Point = Vector3<f64>;
|
||||||
|
pub type Vector = Vector3<f64>;
|
204
assignment-1d/src/main.rs
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
#[macro_use]
|
||||||
|
extern crate anyhow;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate tracing;
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::{fs::File, str::FromStr};
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use assignment_1d::{image::Image, ray::Ray, scene::Scene};
|
||||||
|
|
||||||
|
use clap::{ArgAction, Parser};
|
||||||
|
|
||||||
|
use rayon::prelude::{IntoParallelIterator, ParallelIterator};
|
||||||
|
use tracing::metadata::LevelFilter;
|
||||||
|
use tracing_appender::non_blocking::WorkerGuard;
|
||||||
|
use tracing_subscriber::{
|
||||||
|
fmt::Layer, prelude::__tracing_subscriber_SubscriberExt,
|
||||||
|
util::SubscriberInitExt,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Simple raytracer with Blinn-Phong illumination and shadowing.
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[clap(author, version, about, long_about = None)]
|
||||||
|
struct Opt {
|
||||||
|
/// Path to the input file to use.
|
||||||
|
#[clap()]
|
||||||
|
input_path: PathBuf,
|
||||||
|
|
||||||
|
/// Path to the output (defaults to the same file name as the input except
|
||||||
|
/// with an extension of .ppm)
|
||||||
|
#[clap(short = 'o', long = "output")]
|
||||||
|
output_path: Option<PathBuf>,
|
||||||
|
|
||||||
|
/// Log output in json
|
||||||
|
#[clap(long = "json")]
|
||||||
|
use_json: bool,
|
||||||
|
|
||||||
|
/// Which file to send logs to (stderr by default)
|
||||||
|
#[clap(long = "log-output")]
|
||||||
|
log_output: Option<PathBuf>,
|
||||||
|
|
||||||
|
/// Force parallel projection to be used
|
||||||
|
#[clap(long = "parallel")]
|
||||||
|
force_parallel: bool,
|
||||||
|
|
||||||
|
/// Override distance from eye
|
||||||
|
#[clap(long = "distance", default_value = "1.0")]
|
||||||
|
distance: f64,
|
||||||
|
|
||||||
|
/// Verbosity
|
||||||
|
#[clap(short, long, action = ArgAction::Count)]
|
||||||
|
verbosity: u8,
|
||||||
|
|
||||||
|
/// Evaluate at a single pixel
|
||||||
|
#[clap(short, long = "render-pixel")]
|
||||||
|
render_pixel: Option<RenderPixel>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
let opt = Opt::parse();
|
||||||
|
|
||||||
|
let _guard = setup_logging(&opt);
|
||||||
|
|
||||||
|
// Rename the output file if it's not provided
|
||||||
|
let out_file = opt
|
||||||
|
.output_path
|
||||||
|
.unwrap_or_else(|| opt.input_path.with_extension("ppm"));
|
||||||
|
|
||||||
|
let mut scene = Scene::from_input_file(&opt.input_path)?;
|
||||||
|
let distance = opt.distance;
|
||||||
|
|
||||||
|
// Force-override parallel projection
|
||||||
|
if opt.force_parallel {
|
||||||
|
scene.parallel_projection = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Translate image pixels to real-world 3d coords
|
||||||
|
let translate_pixel = scene.pixel_translation_function(distance);
|
||||||
|
|
||||||
|
let evaluate_at_pixel = |px, py| {
|
||||||
|
let span = trace_span!("main_loop", px = px, py = py);
|
||||||
|
let _enter = span.enter();
|
||||||
|
|
||||||
|
let pixel_in_space = translate_pixel(px, py);
|
||||||
|
|
||||||
|
let ray_start = if scene.parallel_projection {
|
||||||
|
// For a parallel projection, we'll just take the view direction and
|
||||||
|
// subtract it from the target point. This means every single
|
||||||
|
// ray will be viewed from a point at infinity, rather than a single eye
|
||||||
|
// position.
|
||||||
|
let n = scene.view_dir.normalize();
|
||||||
|
let view_dir = n * distance;
|
||||||
|
pixel_in_space - view_dir
|
||||||
|
} else {
|
||||||
|
scene.eye_pos
|
||||||
|
};
|
||||||
|
|
||||||
|
let ray = Ray::from_endpoints(ray_start, pixel_in_space);
|
||||||
|
|
||||||
|
// let res= rayon::spawn(|| scene.trace_single_ray(ray, 0));
|
||||||
|
scene.trace_single_ray(scene.eye_pos, ray, 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
// For debugging purposes!
|
||||||
|
if let Some(RenderPixel(px, py)) = opt.render_pixel {
|
||||||
|
let pixel_color = evaluate_at_pixel(px, py)?;
|
||||||
|
println!("Pixel color: {pixel_color}");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a parallel iterator for pixels
|
||||||
|
// The iterator preserves order and uses row-major order
|
||||||
|
let pixels_iter = (0..scene.image_height)
|
||||||
|
.into_par_iter()
|
||||||
|
.flat_map(|y| (0..scene.image_width).into_par_iter().map(move |x| (x, y)));
|
||||||
|
|
||||||
|
// Loop through every single pixel of the output file
|
||||||
|
let pixels = pixels_iter
|
||||||
|
.map(|(px, py)| evaluate_at_pixel(px, py))
|
||||||
|
.collect::<Result<Vec<_>>>()?;
|
||||||
|
|
||||||
|
// Construct and emit image
|
||||||
|
let image = Image {
|
||||||
|
width: scene.image_width,
|
||||||
|
height: scene.image_height,
|
||||||
|
data: pixels,
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
let file = File::create(out_file)?;
|
||||||
|
image.write(file)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct RenderPixel(usize, usize);
|
||||||
|
|
||||||
|
impl FromStr for RenderPixel {
|
||||||
|
type Err = anyhow::Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let parts = s.split(",").collect::<Vec<_>>();
|
||||||
|
ensure!(parts.len() == 2, "must be a pair");
|
||||||
|
|
||||||
|
let x = parts[0].parse::<usize>()?;
|
||||||
|
let y = parts[1].parse::<usize>()?;
|
||||||
|
|
||||||
|
Ok(RenderPixel(x, y))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A little bit of engineering to make it easy to write conditional builders
|
||||||
|
/// for logging setup because the tracing-subscriber crate for some reason
|
||||||
|
/// decided it would be a good idea to have all of its builders be polymorphic?
|
||||||
|
macro_rules! logsetup_if {
|
||||||
|
($ident:ident , $cond:expr , $iftrue:expr , $iffalse:expr => { $($body:tt)* }) => {
|
||||||
|
if ($cond) {
|
||||||
|
let $ident = $iftrue;
|
||||||
|
$($body)*
|
||||||
|
} else {
|
||||||
|
let $ident = $iffalse;
|
||||||
|
$($body)*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_logging(opt: &Opt) -> Option<WorkerGuard> {
|
||||||
|
let mut result = None;
|
||||||
|
|
||||||
|
let level_filter = match opt.verbosity {
|
||||||
|
0 => LevelFilter::ERROR,
|
||||||
|
1 => LevelFilter::WARN,
|
||||||
|
2 => LevelFilter::INFO,
|
||||||
|
3 => LevelFilter::DEBUG,
|
||||||
|
_ => LevelFilter::TRACE,
|
||||||
|
};
|
||||||
|
|
||||||
|
let layer = Layer::default();
|
||||||
|
|
||||||
|
logsetup_if! (layer, opt.use_json, layer.json(), layer => {
|
||||||
|
let layer = layer
|
||||||
|
.with_target(false)
|
||||||
|
.with_timer(tracing_subscriber::fmt::time::uptime())
|
||||||
|
.with_level(true);
|
||||||
|
|
||||||
|
logsetup_if! (layer, opt.log_output.is_some(), {
|
||||||
|
let log_output = opt.log_output.clone().unwrap();
|
||||||
|
let file_appender = tracing_appender::rolling::never(".", log_output);
|
||||||
|
let (non_blocking, guard) = tracing_appender::non_blocking(file_appender);
|
||||||
|
result = Some(guard);
|
||||||
|
layer.with_writer(non_blocking)
|
||||||
|
}, layer => {
|
||||||
|
tracing_subscriber::registry()
|
||||||
|
.with(layer)
|
||||||
|
.with(level_filter)
|
||||||
|
.init();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
60
assignment-1d/src/ray.rs
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use crate::{Point, Vector};
|
||||||
|
|
||||||
|
/// A normalized parametric Ray of the form (origin + direction * time)
|
||||||
|
///
|
||||||
|
/// That means at any time t: f64, the point represented by origin + direction *
|
||||||
|
/// time occurs on the ray. This is pretty much a (time -> point) function.
|
||||||
|
pub struct Ray {
|
||||||
|
/// The point in space where the ray started
|
||||||
|
pub origin: Point,
|
||||||
|
|
||||||
|
/// The direction the ray is headed
|
||||||
|
pub direction: Vector,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Ray {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"({:.2}, {:.2}, {:.2}) + t * ({:.2}, {:.2}, {:.2})",
|
||||||
|
self.origin.x,
|
||||||
|
self.origin.y,
|
||||||
|
self.origin.z,
|
||||||
|
self.direction.x,
|
||||||
|
self.direction.y,
|
||||||
|
self.direction.z,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ray {
|
||||||
|
pub fn new(origin: Point, direction: Vector) -> Self {
|
||||||
|
Ray { origin, direction }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct a ray from endpoints
|
||||||
|
pub fn from_endpoints(start: Point, end: Point) -> Self {
|
||||||
|
let delta = (end - start).normalize();
|
||||||
|
Ray {
|
||||||
|
origin: start,
|
||||||
|
direction: delta,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Evaluate the ray at a certain point in time, yielding a point
|
||||||
|
pub fn eval(&self, time: f64) -> Point {
|
||||||
|
self.origin + self.direction * time
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if any of the components is NaN
|
||||||
|
pub fn has_nan(&self) -> bool {
|
||||||
|
self.origin.x.is_nan()
|
||||||
|
|| self.origin.y.is_nan()
|
||||||
|
|| self.origin.z.is_nan()
|
||||||
|
|| self.direction.x.is_nan()
|
||||||
|
|| self.direction.y.is_nan()
|
||||||
|
|| self.direction.z.is_nan()
|
||||||
|
}
|
||||||
|
}
|
208
assignment-1d/src/scene/cylinder.rs
Normal file
|
@ -0,0 +1,208 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
use ordered_float::NotNan;
|
||||||
|
|
||||||
|
use crate::utils::compute_rotation_matrix;
|
||||||
|
use crate::Vector;
|
||||||
|
use crate::{ray::Ray, Point};
|
||||||
|
|
||||||
|
use super::illumination::IntersectionContext;
|
||||||
|
use super::Scene;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Cylinder {
|
||||||
|
pub center: Point,
|
||||||
|
pub direction: Vector,
|
||||||
|
pub radius: f64,
|
||||||
|
pub length: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cylinder {
|
||||||
|
/// Given a cylinder, returns the first time at which this ray intersects the
|
||||||
|
/// cylinder.
|
||||||
|
///
|
||||||
|
/// If there is no intersection point, returns None.
|
||||||
|
pub fn intersects_ray_at(
|
||||||
|
&self,
|
||||||
|
_: &Scene,
|
||||||
|
ray: &Ray,
|
||||||
|
) -> Result<Option<IntersectionContext>> {
|
||||||
|
// Determine rotation matrix for turning the cylinder upright along the
|
||||||
|
// Z-axis
|
||||||
|
let target_direction = Vector::new(0.0, 0.0, 1.0);
|
||||||
|
let rotation_matrix =
|
||||||
|
compute_rotation_matrix(self.direction, target_direction)?;
|
||||||
|
let inverse_rotation_matrix =
|
||||||
|
rotation_matrix.try_inverse().ok_or_else(|| {
|
||||||
|
anyhow!("Rotation matrix for some reason does not have an inverse?")
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Transform all parameters according to this rotation matrix
|
||||||
|
let rotated_cylinder_center = rotation_matrix * self.center;
|
||||||
|
let rotated_ray_origin = rotation_matrix * ray.origin;
|
||||||
|
let rotated_ray_direction = rotation_matrix * ray.direction;
|
||||||
|
|
||||||
|
// Now that we know the cylinder is upright, we can start checking against
|
||||||
|
// the formula:
|
||||||
|
//
|
||||||
|
// (ox + t*rx - cx)^2 + (oy + t*ry - cy)^2 = r^2
|
||||||
|
//
|
||||||
|
// where o{xy} is the ray origin, r{xy} is the ray direction, and c{xy} is
|
||||||
|
// the cylinder center. The z will be taken care of after the fact. To
|
||||||
|
// solve, we must put it into the form At^2 + Bt + c = 0. The variables
|
||||||
|
// are:
|
||||||
|
//
|
||||||
|
// A: rx^2 + ry^2
|
||||||
|
// B: 2(rx(ox - cx) + ry(oy - cy))
|
||||||
|
// C: (cx - ox)^2 + (cy - oy)^2 - r^2
|
||||||
|
let (a, b, c) = {
|
||||||
|
let o = rotated_ray_origin;
|
||||||
|
let r = rotated_ray_direction;
|
||||||
|
let c = rotated_cylinder_center;
|
||||||
|
|
||||||
|
(
|
||||||
|
r.x.powi(2) + r.y.powi(2),
|
||||||
|
2.0 * (r.x * (o.x - c.x) + r.y * (o.y - c.y)),
|
||||||
|
(c.x - o.x).powi(2) + (c.y - o.y).powi(2) - self.radius.powi(2),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let discriminant = b * b - 4.0 * a * c;
|
||||||
|
|
||||||
|
let possible_side_solutions = match discriminant {
|
||||||
|
// Discriminant < 0, means the equation has no solutions.
|
||||||
|
d if d < 0.0 => vec![],
|
||||||
|
|
||||||
|
// Discriminant == 0
|
||||||
|
d if d == 0.0 => vec![-b / 2.0 * a],
|
||||||
|
|
||||||
|
// Discriminant > 0, 2 solutions available.
|
||||||
|
d if d > 0.0 => {
|
||||||
|
vec![
|
||||||
|
(-b + discriminant.sqrt()) / (2.0 * a),
|
||||||
|
(-b - discriminant.sqrt()) / (2.0 * a),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Probably hit some NaN or Infinity value due to faulty inputs...
|
||||||
|
_ => bail!("Invalid determinant value: {discriminant}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Filter out solutions that don't have a valid Z position.
|
||||||
|
let side_solutions = possible_side_solutions.into_iter().filter_map(|t| {
|
||||||
|
let ray_point = ray.eval(t);
|
||||||
|
let rotated_ray_point = rotation_matrix * ray_point;
|
||||||
|
let z = rotated_ray_point.z - rotated_cylinder_center.z;
|
||||||
|
|
||||||
|
// Check to see if z is between -len/2 and len/2
|
||||||
|
if z.abs() > self.length / 2.0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let time = NotNan::new(t).ok()?;
|
||||||
|
|
||||||
|
// The point on the center of the cylinder that corresponds to the z-axis
|
||||||
|
// point of the intersection
|
||||||
|
let center_at_z = {
|
||||||
|
let mut center_point = rotation_matrix * ray_point;
|
||||||
|
center_point.x = rotated_cylinder_center.x;
|
||||||
|
center_point.y = rotated_cylinder_center.y;
|
||||||
|
|
||||||
|
inverse_rotation_matrix * center_point
|
||||||
|
};
|
||||||
|
let normal = (ray_point - center_at_z).normalize();
|
||||||
|
|
||||||
|
Some(IntersectionContext {
|
||||||
|
time,
|
||||||
|
point: ray_point,
|
||||||
|
normal,
|
||||||
|
exiting: todo!(),
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
// We also need to add solutions for the two ends of the cylinder, which
|
||||||
|
// uses a similar method except backwards: check intersection points
|
||||||
|
// with the correct z-plane and then see if the points are within the
|
||||||
|
// circle.
|
||||||
|
//
|
||||||
|
// Luckily, this means we only need to care about one dimension at first,
|
||||||
|
// and don't need to perform the quadratic equation method above.
|
||||||
|
//
|
||||||
|
// oz + t * rz = cz +- (len / 2)
|
||||||
|
// t = (-oz + cz +- (len / 2)) / rz
|
||||||
|
let possible_z_intersections = {
|
||||||
|
let o = rotated_ray_origin;
|
||||||
|
let r = rotated_ray_direction;
|
||||||
|
let c = rotated_cylinder_center;
|
||||||
|
|
||||||
|
if r.z == 0.0 {
|
||||||
|
Vec::new() // No solutions here
|
||||||
|
} else {
|
||||||
|
vec![
|
||||||
|
(-o.z + c.z + self.length / 2.0) / r.z,
|
||||||
|
(-o.z + c.z - self.length / 2.0) / r.z,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let end_solutions = possible_z_intersections.into_iter().filter_map(|t| {
|
||||||
|
let ray_point = ray.eval(t);
|
||||||
|
let rotated_point = rotation_matrix * ray_point;
|
||||||
|
|
||||||
|
// Filter out all the solutions where the intersection point does not lie
|
||||||
|
// in the circle
|
||||||
|
if rotated_point.x.powi(2) + rotated_point.y.powi(2) > self.radius.powi(2)
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let normal_rotated =
|
||||||
|
Vector::new(0.0, 0.0, rotated_point.z - rotated_cylinder_center.z)
|
||||||
|
.normalize();
|
||||||
|
let normal = inverse_rotation_matrix * normal_rotated;
|
||||||
|
|
||||||
|
let time = NotNan::new(t).ok()?;
|
||||||
|
Some(IntersectionContext {
|
||||||
|
time,
|
||||||
|
point: ray_point,
|
||||||
|
normal,
|
||||||
|
exiting: todo!(),
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let solutions = side_solutions
|
||||||
|
.into_iter()
|
||||||
|
.chain(end_solutions.into_iter())
|
||||||
|
// Remove any t < 0, since that means it's behind the viewer and we
|
||||||
|
// can't see it.
|
||||||
|
.filter(|ctx| *ctx.time >= 0.0);
|
||||||
|
|
||||||
|
// Return the minimum solution
|
||||||
|
Ok(solutions.min_by_key(|ctx| ctx.time))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::{ray::Ray, scene::Scene, Point, Vector};
|
||||||
|
|
||||||
|
use super::Cylinder;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cylinder() {
|
||||||
|
let cylinder = Cylinder {
|
||||||
|
center: Point::new(0.0, 0.0, 0.0),
|
||||||
|
direction: Vector::new(0.0, 1.0, 0.0),
|
||||||
|
radius: 3.0,
|
||||||
|
length: 4.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let eye = Point::new(0.0, 3.0, 3.0);
|
||||||
|
let end = Point::new(0.0, 2.0, 2.0);
|
||||||
|
let ray = Ray::from_endpoints(eye, end);
|
||||||
|
|
||||||
|
let scene = Scene::default();
|
||||||
|
let _res = cylinder.intersects_ray_at(&scene, &ray);
|
||||||
|
// panic!("Result: {res:?}");
|
||||||
|
}
|
||||||
|
}
|
193
assignment-1d/src/scene/data.rs
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use crate::image::Color;
|
||||||
|
use crate::utils::cross;
|
||||||
|
use crate::Point;
|
||||||
|
|
||||||
|
use super::Scene;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Rect {
|
||||||
|
pub upper_left: Point,
|
||||||
|
pub upper_right: Point,
|
||||||
|
pub lower_left: Point,
|
||||||
|
pub lower_right: Point,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Material {
|
||||||
|
pub diffuse_color: Point,
|
||||||
|
pub specular_color: Point,
|
||||||
|
|
||||||
|
pub k_a: f64,
|
||||||
|
pub k_d: f64,
|
||||||
|
pub k_s: f64,
|
||||||
|
pub exponent: f64,
|
||||||
|
|
||||||
|
/// Opacity
|
||||||
|
pub alpha: f64,
|
||||||
|
|
||||||
|
/// Index of refraction
|
||||||
|
pub eta: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum LightKind {
|
||||||
|
/// A point light source exists at a point and emits light in all directions
|
||||||
|
Point {
|
||||||
|
location: Point,
|
||||||
|
|
||||||
|
/// Whether light attenuation is enabled for this light
|
||||||
|
attenuation: Option<Attenuation>,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// A directional light source exists at an infinitely far location but emits
|
||||||
|
/// light in a specific direction
|
||||||
|
Directional { direction: Point },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Light {
|
||||||
|
/// The kind of light source, as well as its associated information
|
||||||
|
pub kind: LightKind,
|
||||||
|
|
||||||
|
/// The color, or intensity, of the light source
|
||||||
|
pub color: Point,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Light {
|
||||||
|
/// Get the unit directional vector pointing from the given point to this
|
||||||
|
/// light source
|
||||||
|
pub fn direction_from(&self, point: Point) -> Point {
|
||||||
|
match self.kind {
|
||||||
|
LightKind::Point { location, .. } => location - point,
|
||||||
|
LightKind::Directional { direction } => -direction,
|
||||||
|
}
|
||||||
|
.normalize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DepthCueing {
|
||||||
|
/// The color to tint (should be the same as the background color, to avoid
|
||||||
|
/// bizarre visual effects)
|
||||||
|
pub color: Color,
|
||||||
|
|
||||||
|
/// Proportion of the color influenced by the depth tint when the distance is
|
||||||
|
/// maxed (caps at 1.0)
|
||||||
|
pub a_max: f64,
|
||||||
|
|
||||||
|
/// Proportion of the color influenced by the depth tint when the distance is
|
||||||
|
/// at the minimum (caps at 1.0)
|
||||||
|
pub a_min: f64,
|
||||||
|
|
||||||
|
/// The max distance that should be affected by the depth tint
|
||||||
|
pub dist_max: f64,
|
||||||
|
|
||||||
|
/// The min distance that should be affected by the depth tint
|
||||||
|
pub dist_min: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A default implementation here needs to simulate what would happen if there
|
||||||
|
/// was no depth cueing. In this case, if we have both a_max and a_min be 1.0,
|
||||||
|
/// then the original color will always apply and there will be no need for
|
||||||
|
/// depth color
|
||||||
|
impl Default for DepthCueing {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
color: Default::default(),
|
||||||
|
a_max: 1.0,
|
||||||
|
a_min: 1.0,
|
||||||
|
dist_max: 0.0,
|
||||||
|
dist_min: 0.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Light attenuation dropoff coefficients
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Attenuation {
|
||||||
|
pub c1: f64,
|
||||||
|
pub c2: f64,
|
||||||
|
pub c3: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A default implementation here needs to simulate what would happen if there
|
||||||
|
/// was no light attenuation specified. In this case, c1 would just be a
|
||||||
|
/// constant of 1 and all the coefficients for anything involving distance would
|
||||||
|
/// be zeroed out
|
||||||
|
impl Default for Attenuation {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
c1: 1.0,
|
||||||
|
c2: 0.0,
|
||||||
|
c3: 0.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scene {
|
||||||
|
/// Determine the boundaries of the viewing window in world coordinates
|
||||||
|
pub fn compute_viewing_window(&self, distance: f64) -> Rect {
|
||||||
|
// Compute viewing directions
|
||||||
|
let u = cross(self.view_dir, self.up_dir).normalize();
|
||||||
|
let v = cross(u, self.view_dir).normalize();
|
||||||
|
|
||||||
|
// Compute dimensions of viewing window based on field of view
|
||||||
|
let viewing_width = {
|
||||||
|
// Divide the angle in 2 since we are trying to use trig rules so we must
|
||||||
|
// get it from a right triangle
|
||||||
|
let half_hfov = self.hfov.to_radians() / 2.0;
|
||||||
|
|
||||||
|
// tan(hfov / 2) = w / 2d
|
||||||
|
let w_over_2d = half_hfov.tan();
|
||||||
|
|
||||||
|
// To find the viewing width we must multiply by 2d now
|
||||||
|
w_over_2d * 2.0 * distance
|
||||||
|
};
|
||||||
|
|
||||||
|
let aspect_ratio = self.image_width as f64 / self.image_height as f64;
|
||||||
|
let viewing_height = viewing_width / aspect_ratio;
|
||||||
|
|
||||||
|
// Compute viewing window corners
|
||||||
|
let n = self.view_dir.normalize();
|
||||||
|
|
||||||
|
#[rustfmt::skip] // Don't format, or else this line wraps over
|
||||||
|
let view_window = Rect {
|
||||||
|
upper_left: self.eye_pos + n * distance - u * (viewing_width / 2.0) + v * (viewing_height / 2.0),
|
||||||
|
upper_right: self.eye_pos + n * distance + u * (viewing_width / 2.0) + v * (viewing_height / 2.0),
|
||||||
|
lower_left: self.eye_pos + n * distance - u * (viewing_width / 2.0) - v * (viewing_height / 2.0),
|
||||||
|
lower_right: self.eye_pos + n * distance + u * (viewing_width / 2.0) - v * (viewing_height / 2.0),
|
||||||
|
};
|
||||||
|
|
||||||
|
view_window
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a pixel translation function based on the viewing window of the
|
||||||
|
/// current scene
|
||||||
|
pub fn pixel_translation_function(
|
||||||
|
&self,
|
||||||
|
distance: f64,
|
||||||
|
) -> impl Fn(usize, usize) -> Point {
|
||||||
|
let view_window = self.compute_viewing_window(distance);
|
||||||
|
|
||||||
|
let dx = view_window.upper_right - view_window.upper_left;
|
||||||
|
let pixel_base_x = dx / self.image_width as f64;
|
||||||
|
|
||||||
|
let dy = view_window.lower_left - view_window.upper_left;
|
||||||
|
let pixel_base_y = dy / self.image_height as f64;
|
||||||
|
|
||||||
|
// The final function to be returned
|
||||||
|
move |px: usize, py: usize| {
|
||||||
|
let x_component = pixel_base_x * px as f64;
|
||||||
|
let y_component = pixel_base_y * py as f64;
|
||||||
|
|
||||||
|
// Without adding this, we would be getting the top-left of the pixel's
|
||||||
|
// rectangle. We want the center, so add half of the pixel size as
|
||||||
|
// well.
|
||||||
|
let center_offset = (pixel_base_x + pixel_base_y) / 2.0;
|
||||||
|
|
||||||
|
view_window.upper_left + x_component + y_component + center_offset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
519
assignment-1d/src/scene/illumination.rs
Normal file
|
@ -0,0 +1,519 @@
|
||||||
|
use std::iter;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use ordered_float::NotNan;
|
||||||
|
use rand::Rng;
|
||||||
|
use rayon::prelude::{
|
||||||
|
IndexedParallelIterator, IntoParallelIterator, IntoParallelRefIterator,
|
||||||
|
ParallelIterator,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
image::Color,
|
||||||
|
ray::Ray,
|
||||||
|
utils::{
|
||||||
|
compute_reflection_ray, compute_refraction_lengths, dot, RefractionResult,
|
||||||
|
},
|
||||||
|
Point, Vector,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
data::{DepthCueing, Light, LightKind, Material},
|
||||||
|
object::Object,
|
||||||
|
Scene,
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Is this a good constant?
|
||||||
|
const JITTER_CONST: f64 = 0.05;
|
||||||
|
const ZERO_COLOR: Color = Color::new(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
// Soft shadows: jitter some rays here to somewhere close to the
|
||||||
|
// actual location as well, and measure the proportion
|
||||||
|
// of them that intersect any objects
|
||||||
|
const SOFT_SHADOW_JITTER_RADIUS: f64 = 1.0;
|
||||||
|
const JITTER_RAYS: usize = 75;
|
||||||
|
|
||||||
|
impl Scene {
|
||||||
|
/// Determine the color that should be used to fill this pixel.
|
||||||
|
///
|
||||||
|
/// - material_idx is the index into the materials list.
|
||||||
|
/// - intersection_context contains information on vectors where the
|
||||||
|
/// intersection occurred
|
||||||
|
///
|
||||||
|
/// Also known as Shade_Ray in the slides.
|
||||||
|
pub fn compute_pixel_color(
|
||||||
|
&self,
|
||||||
|
obj_idx: usize,
|
||||||
|
object: &Object,
|
||||||
|
origin: Point,
|
||||||
|
incident_ray: Ray,
|
||||||
|
intersection_context: IntersectionContext,
|
||||||
|
depth: usize,
|
||||||
|
) -> Result<Color> {
|
||||||
|
let span = trace_span!("compute_pixel_color", intersection = ?intersection_context, incident_ray=?incident_ray);
|
||||||
|
let _enter = span.enter();
|
||||||
|
|
||||||
|
let material = match self.materials.get(object.material_idx) {
|
||||||
|
Some(v) => v,
|
||||||
|
None => bail!("Material index not found."),
|
||||||
|
};
|
||||||
|
|
||||||
|
let diffuse_color = match object.texture_idx {
|
||||||
|
Some(texture_idx) => {
|
||||||
|
let (u, v) = object
|
||||||
|
.kind
|
||||||
|
.get_texture_coord(&self, &intersection_context)?;
|
||||||
|
|
||||||
|
let texture = match self.textures.get(texture_idx) {
|
||||||
|
Some(v) => v,
|
||||||
|
None => bail!("Texture index not found."),
|
||||||
|
};
|
||||||
|
|
||||||
|
texture.pixel_at(u, v)
|
||||||
|
}
|
||||||
|
None => material.diffuse_color,
|
||||||
|
};
|
||||||
|
|
||||||
|
let ambient_component = material.k_a * diffuse_color;
|
||||||
|
|
||||||
|
// Diffuse and specular lighting for each separate light
|
||||||
|
let diffuse_and_specular: Color = self
|
||||||
|
.lights
|
||||||
|
.par_iter()
|
||||||
|
.map(|light| {
|
||||||
|
// The vector pointing in the direction of the light
|
||||||
|
let light_direction = light.direction_from(intersection_context.point);
|
||||||
|
|
||||||
|
let normal = intersection_context.normal.normalize(); // reflection_normal();
|
||||||
|
|
||||||
|
// Viewer direction is no longer towards the eye, but to the last origin point, so that
|
||||||
|
// transmitted rays reflect properly
|
||||||
|
// let viewer_direction = self.eye_pos - intersection_context.point;
|
||||||
|
let incoming_ray_direction = (intersection_context.point - origin).normalize();
|
||||||
|
|
||||||
|
let halfway_direction =
|
||||||
|
((light_direction + incoming_ray_direction) / 2.0).normalize();
|
||||||
|
|
||||||
|
let diffuse_component = material.k_d
|
||||||
|
* diffuse_color
|
||||||
|
* dot(normal, light_direction).max(0.0);
|
||||||
|
|
||||||
|
let specular_component = material.k_s
|
||||||
|
* material.specular_color
|
||||||
|
* dot(normal, halfway_direction)
|
||||||
|
.max(0.0)
|
||||||
|
.powf(material.exponent);
|
||||||
|
|
||||||
|
// Shadow coefficient between 0 and 1 to control how bright this pixel
|
||||||
|
// should be from being in the shadow of another object (could be
|
||||||
|
// between 0 and 1 when applying soft shadows)
|
||||||
|
let shadow_coefficient = self.compute_shadow_coefficient(
|
||||||
|
obj_idx,
|
||||||
|
intersection_context.point,
|
||||||
|
light,
|
||||||
|
);
|
||||||
|
|
||||||
|
let attenuation_coefficient = match &light.kind {
|
||||||
|
LightKind::Point {
|
||||||
|
location,
|
||||||
|
attenuation: Some(att),
|
||||||
|
} => {
|
||||||
|
let dist = (location - intersection_context.point).norm();
|
||||||
|
let denom = att.c1 + att.c2 * dist + att.c3 * dist.powi(2);
|
||||||
|
if denom == 0.0 {
|
||||||
|
warn!("Light attenuation coefficients produced a denominator of 0. Check your inputs...");
|
||||||
|
1.0 // Some kind of graceful fallback here
|
||||||
|
} else {
|
||||||
|
1.0 / denom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => 1.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let diffuse_and_specular = diffuse_component + specular_component;
|
||||||
|
|
||||||
|
attenuation_coefficient
|
||||||
|
* shadow_coefficient
|
||||||
|
* light.color.component_mul(&diffuse_and_specular)
|
||||||
|
})
|
||||||
|
.sum();
|
||||||
|
|
||||||
|
let (eta_i, eta_t) = match intersection_context.exiting {
|
||||||
|
// true => (material.eta, 1.0),
|
||||||
|
_ => (1.0, material.eta),
|
||||||
|
};
|
||||||
|
|
||||||
|
let specular_reflection_component = if material.k_s == 0.0 {
|
||||||
|
ZERO_COLOR
|
||||||
|
} else {
|
||||||
|
self.compute_specular_reflection(
|
||||||
|
&intersection_context,
|
||||||
|
&incident_ray,
|
||||||
|
depth,
|
||||||
|
)?
|
||||||
|
};
|
||||||
|
|
||||||
|
let transparency_component = if eta_t < 1.0 || material.alpha == 1.0 {
|
||||||
|
ZERO_COLOR
|
||||||
|
} else {
|
||||||
|
self.compute_transparency(
|
||||||
|
&intersection_context,
|
||||||
|
&incident_ray,
|
||||||
|
eta_i,
|
||||||
|
eta_t,
|
||||||
|
depth,
|
||||||
|
)?
|
||||||
|
};
|
||||||
|
|
||||||
|
let fresnel_coefficient = self.compute_fresnel_coefficient(
|
||||||
|
material,
|
||||||
|
&incident_ray.direction,
|
||||||
|
intersection_context.normal,
|
||||||
|
);
|
||||||
|
|
||||||
|
// This is the result of the Phong illumination equation.
|
||||||
|
let color = (ambient_component + diffuse_and_specular) + {
|
||||||
|
// This part is all the transparency + reflection stuff
|
||||||
|
fresnel_coefficient * specular_reflection_component
|
||||||
|
+ (1.0 - fresnel_coefficient)
|
||||||
|
* (1.0 - material.alpha)
|
||||||
|
* transparency_component
|
||||||
|
};
|
||||||
|
debug!(
|
||||||
|
last_time_component = ?(ambient_component + diffuse_and_specular),
|
||||||
|
?specular_reflection_component,
|
||||||
|
?transparency_component,
|
||||||
|
?fresnel_coefficient,
|
||||||
|
?color,
|
||||||
|
"color result"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Apply depth cueing to the result
|
||||||
|
let a_dc = {
|
||||||
|
// Distance from the viewer
|
||||||
|
let d_obj = (intersection_context.point - self.eye_pos).norm();
|
||||||
|
let DepthCueing {
|
||||||
|
dist_max,
|
||||||
|
dist_min,
|
||||||
|
a_max,
|
||||||
|
a_min,
|
||||||
|
..
|
||||||
|
} = self.depth_cueing;
|
||||||
|
|
||||||
|
if d_obj < dist_min {
|
||||||
|
a_max
|
||||||
|
} else if d_obj < dist_max {
|
||||||
|
a_min + (a_max - a_min) * (dist_max - d_obj) / (dist_max - dist_min)
|
||||||
|
} else {
|
||||||
|
a_min
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let color = a_dc * color + (1.0 - a_dc) * self.depth_cueing.color;
|
||||||
|
|
||||||
|
// Need to clamp the result so none of the components goes over 1
|
||||||
|
let clamped_result = color.map(|v| v.min(1.0));
|
||||||
|
|
||||||
|
Ok(clamped_result)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Perform another ray casting to see if there are any objects obstructing
|
||||||
|
/// the light source to this particular point
|
||||||
|
pub fn compute_shadow_coefficient(
|
||||||
|
&self,
|
||||||
|
obj_idx: usize,
|
||||||
|
point: Point,
|
||||||
|
light: &Light,
|
||||||
|
) -> f64 {
|
||||||
|
let light_direction = light.direction_from(point);
|
||||||
|
let ray = Ray {
|
||||||
|
origin: point,
|
||||||
|
direction: light_direction.normalize(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Small helper for iterating over all of the objects in the scene except
|
||||||
|
// for the current one
|
||||||
|
let other_objects = self
|
||||||
|
.objects
|
||||||
|
.par_iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(i, _)| *i != obj_idx);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct ShadowResult {
|
||||||
|
transparent_coefficient: f64,
|
||||||
|
shadow_opacity: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the list of intersections with all the other objects in the scene
|
||||||
|
// This list will be a set of opacities
|
||||||
|
let intersections = other_objects
|
||||||
|
.filter_map(|(_, object)| {
|
||||||
|
let intersection_context =
|
||||||
|
match object.kind.intersects_ray_at(&self, &ray) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(err) => {
|
||||||
|
error!("Error while performing shadow casting: {err}");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}?;
|
||||||
|
|
||||||
|
let intersection_time = *intersection_context.time;
|
||||||
|
let material = &self.materials[object.material_idx];
|
||||||
|
|
||||||
|
match light.kind {
|
||||||
|
// In the case of point lights, we must check to see if both t > 0 and
|
||||||
|
// t is less than the time it took to even get to the light.
|
||||||
|
LightKind::Point { location, .. } => {
|
||||||
|
let light_time = (location - ray.origin).norm();
|
||||||
|
|
||||||
|
if intersection_time <= 0.0 || intersection_time >= light_time {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(ShadowResult {
|
||||||
|
transparent_coefficient: material.alpha,
|
||||||
|
shadow_opacity: self
|
||||||
|
.compute_soft_shadow_coefficient(location, point, object),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the case of directional lights, only t > 0 needs to be checked
|
||||||
|
LightKind::Directional { .. } => {
|
||||||
|
if intersection_time <= 0.0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
// The object obstructed the directional light, which means (1 -
|
||||||
|
// alpha) amount of light passes through
|
||||||
|
Some(ShadowResult {
|
||||||
|
transparent_coefficient: material.alpha,
|
||||||
|
|
||||||
|
// Opacity is 0 because there's no jitter from an infinitely far
|
||||||
|
// away light source
|
||||||
|
shadow_opacity: 0.0,
|
||||||
|
}) // complete obstruction
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
match intersections.is_empty() {
|
||||||
|
true => 1.0,
|
||||||
|
false => {
|
||||||
|
// let average =
|
||||||
|
// intersections.iter().map(|s| s.shadow_opacity).sum::<f64>()
|
||||||
|
// / intersections.len() as f64;
|
||||||
|
|
||||||
|
// (1 - a_0) * (1 - a_1) * (...)
|
||||||
|
let transparency = intersections
|
||||||
|
.iter()
|
||||||
|
.map(|s| 1.0 - s.transparent_coefficient)
|
||||||
|
.product::<f64>();
|
||||||
|
|
||||||
|
// debug!(
|
||||||
|
// "average {average}, transparency {transparency} = {}",
|
||||||
|
// average * transparency
|
||||||
|
// );
|
||||||
|
transparency
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_soft_shadow_coefficient(
|
||||||
|
&self,
|
||||||
|
light_location: Point,
|
||||||
|
original_intersection_point: Point,
|
||||||
|
object: &Object,
|
||||||
|
) -> f64 {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let locations = iter::repeat_with(|| {
|
||||||
|
let x = rng.gen_range(0.0..SOFT_SHADOW_JITTER_RADIUS);
|
||||||
|
let y = rng.gen_range(0.0..SOFT_SHADOW_JITTER_RADIUS);
|
||||||
|
let z = rng.gen_range(0.0..SOFT_SHADOW_JITTER_RADIUS);
|
||||||
|
let delta = Vector::new(x, y, z);
|
||||||
|
light_location + delta
|
||||||
|
})
|
||||||
|
.take(JITTER_RAYS)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let num_obstructed_rays = locations
|
||||||
|
.into_par_iter()
|
||||||
|
.filter(|location| {
|
||||||
|
let direction = (location - original_intersection_point).normalize();
|
||||||
|
let ray = Ray {
|
||||||
|
origin: original_intersection_point,
|
||||||
|
direction,
|
||||||
|
};
|
||||||
|
|
||||||
|
let intersection_context =
|
||||||
|
match object.kind.intersects_ray_at(&self, &ray) {
|
||||||
|
Ok(Some(v)) => v,
|
||||||
|
Ok(None) => return false,
|
||||||
|
Err(err) => {
|
||||||
|
error!("Error while performing shadow casting: {err}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let light_time = (location - ray.origin).norm();
|
||||||
|
let intersection_time = *intersection_context.time;
|
||||||
|
|
||||||
|
0.0 < intersection_time && intersection_time < light_time
|
||||||
|
})
|
||||||
|
.count();
|
||||||
|
|
||||||
|
(JITTER_RAYS - num_obstructed_rays) as f64 / JITTER_RAYS as f64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_fresnel_coefficient(
|
||||||
|
&self,
|
||||||
|
material: &Material,
|
||||||
|
incident_ray: &Vector,
|
||||||
|
normal: Vector,
|
||||||
|
) -> f64 {
|
||||||
|
let mut cos_theta_i = dot(*incident_ray, normal);
|
||||||
|
|
||||||
|
if cos_theta_i < 0.0 {
|
||||||
|
cos_theta_i = dot(*incident_ray, -normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
let f0 = ((material.eta - 1.0) / (material.eta + 1.0)).powi(2);
|
||||||
|
let fr = f0 * 1.0 + (1.0 - f0) * (1.0 - cos_theta_i).powi(5);
|
||||||
|
|
||||||
|
if fr < 0.0 || fr > 1.0 {
|
||||||
|
warn!(
|
||||||
|
eta = material.eta,
|
||||||
|
cos_theta_i, f0, fr, "fresnel coefficient outside of 0 - 1"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fr
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_specular_reflection(
|
||||||
|
&self,
|
||||||
|
intersection_context: &IntersectionContext,
|
||||||
|
incident_ray: &Ray,
|
||||||
|
depth: usize,
|
||||||
|
) -> Result<Color> {
|
||||||
|
let reflection_ray = compute_reflection_ray(
|
||||||
|
incident_ray.direction.clone(),
|
||||||
|
intersection_context.reflection_normal().normalize(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let origin = intersection_context.point;
|
||||||
|
let origin = origin + JITTER_CONST * reflection_ray;
|
||||||
|
let ray = Ray::new(origin, reflection_ray);
|
||||||
|
|
||||||
|
self.trace_single_ray(origin, ray, depth + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_transparency(
|
||||||
|
&self,
|
||||||
|
intersection_context: &IntersectionContext,
|
||||||
|
incident_ray: &Ray,
|
||||||
|
eta_i: f64,
|
||||||
|
eta_t: f64,
|
||||||
|
depth: usize,
|
||||||
|
) -> Result<Color> {
|
||||||
|
let span =
|
||||||
|
trace_span!("compute_transparency", eta_i = eta_i, eta_t = eta_t);
|
||||||
|
let _enter = span.enter();
|
||||||
|
|
||||||
|
// Fix the normal direction to account for exiting a material
|
||||||
|
let normal = intersection_context.reflection_normal().normalize();
|
||||||
|
|
||||||
|
let i = incident_ray.direction.normalize();
|
||||||
|
|
||||||
|
assert!(eta_t != 0.0, "wtf eta_t is 0");
|
||||||
|
|
||||||
|
// This comes in two parts: one is reflection and one is refraction. The
|
||||||
|
// refraction component will only occur if the angle remains below the
|
||||||
|
// critical angle. The reflection amount is added in proportion to the
|
||||||
|
// Fresnel coefficient.
|
||||||
|
|
||||||
|
// First, calculate whether or not refraction is happening. If total
|
||||||
|
// internal reflection occurs, then there's no refraction since there's
|
||||||
|
// no ray escaping the medium.
|
||||||
|
|
||||||
|
let value =
|
||||||
|
match compute_refraction_lengths(normal, &incident_ray, eta_i, eta_t) {
|
||||||
|
Some(RefractionResult {
|
||||||
|
cos_theta_i,
|
||||||
|
sin_theta_i: _,
|
||||||
|
sin_theta_t,
|
||||||
|
cos_theta_t,
|
||||||
|
}) => {
|
||||||
|
// Now that we identified that there is refraction happening, transmit
|
||||||
|
// a ray through the material at the scene behind it in the
|
||||||
|
// new direction.
|
||||||
|
|
||||||
|
// Calculate refraction direction
|
||||||
|
let a = normal * cos_theta_t;
|
||||||
|
let s_direction = cos_theta_i * normal - i;
|
||||||
|
let m_unit = s_direction.normalize();
|
||||||
|
let b = m_unit * sin_theta_t;
|
||||||
|
let t = a + b;
|
||||||
|
|
||||||
|
// Jitter a bit to reduce acne
|
||||||
|
// TODO: Is this a good constant?
|
||||||
|
let origin = intersection_context.point;
|
||||||
|
let origin = origin + JITTER_CONST * t;
|
||||||
|
let ray = Ray::new(origin, t);
|
||||||
|
|
||||||
|
self.trace_single_ray(origin, ray, depth + 1)?
|
||||||
|
}
|
||||||
|
|
||||||
|
// No extra color from the transmitted ray, since it's completely
|
||||||
|
// reflected
|
||||||
|
None => ZERO_COLOR,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Calculate reflection
|
||||||
|
// let sin_theta_t = (eta_i / eta_t) * sin_theta_i;
|
||||||
|
// let cos_theta_t = (1.0 - sin_theta_t.powi(2)).sqrt();
|
||||||
|
// let fresnel_coefficient = self.compute_fresnel_coefficient(&material, i,
|
||||||
|
// n);
|
||||||
|
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Information about an intersection
|
||||||
|
#[derive(Derivative)]
|
||||||
|
#[derivative(Debug, PartialEq, PartialOrd, Ord)]
|
||||||
|
pub struct IntersectionContext {
|
||||||
|
/// The time of the intersection in the parametric ray
|
||||||
|
///
|
||||||
|
/// Unfortunately, IEEE floats in Rust don't have total ordering, because
|
||||||
|
/// NaNs violate ordering properties. The way to remedy this is to ensure we
|
||||||
|
/// don't have NaNs by wrapping it into this type, which then implements
|
||||||
|
/// total ordering.
|
||||||
|
pub time: NotNan<f64>,
|
||||||
|
|
||||||
|
/// The intersection point.
|
||||||
|
#[derivative(PartialEq = "ignore", Ord = "ignore")]
|
||||||
|
pub point: Point,
|
||||||
|
|
||||||
|
/// The normal vector protruding from the surface of the object at the
|
||||||
|
/// intersection point
|
||||||
|
#[derivative(PartialEq = "ignore", Ord = "ignore")]
|
||||||
|
pub normal: Vector,
|
||||||
|
|
||||||
|
/// Is this ray exiting the material at the intersection point?
|
||||||
|
pub exiting: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for IntersectionContext {}
|
||||||
|
|
||||||
|
impl IntersectionContext {
|
||||||
|
// If we're exiting the material, the normal should face the other direction
|
||||||
|
// since that's how the reflection works
|
||||||
|
pub fn reflection_normal(&self) -> Vector {
|
||||||
|
match self.exiting {
|
||||||
|
true => -self.normal,
|
||||||
|
false => self.normal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
371
assignment-1d/src/scene/input_file/mod.rs
Normal file
|
@ -0,0 +1,371 @@
|
||||||
|
pub mod triangle_vertex;
|
||||||
|
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use anyhow::{Context, Result};
|
||||||
|
use itertools::Itertools;
|
||||||
|
use nalgebra::Vector3;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
image::{Color, Image},
|
||||||
|
scene::{
|
||||||
|
cylinder::Cylinder,
|
||||||
|
data::{Attenuation, Light, LightKind, Material},
|
||||||
|
input_file::triangle_vertex::TriangleVertex,
|
||||||
|
object::{Object, ObjectKind},
|
||||||
|
sphere::Sphere,
|
||||||
|
texture::{NormalMap, Texture},
|
||||||
|
triangle::Triangle,
|
||||||
|
Scene,
|
||||||
|
},
|
||||||
|
Point, Vector,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::data::DepthCueing;
|
||||||
|
|
||||||
|
impl Scene {
|
||||||
|
/// Parse the input file into a scene
|
||||||
|
pub fn from_input_file(path: impl AsRef<Path>) -> Result<Self> {
|
||||||
|
let path = path.as_ref();
|
||||||
|
|
||||||
|
// Scope the read so the file is dropped and closed immediately after the
|
||||||
|
// contents have been read to memory
|
||||||
|
let contents = {
|
||||||
|
let mut contents = String::new();
|
||||||
|
let mut file = File::open(path)?;
|
||||||
|
file.read_to_string(&mut contents)?;
|
||||||
|
contents
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut scene = Scene::default();
|
||||||
|
let mut material_idx = None;
|
||||||
|
let mut texture_idx = None;
|
||||||
|
|
||||||
|
for line in contents.lines() {
|
||||||
|
// Comments :)
|
||||||
|
let line = line.trim();
|
||||||
|
if line.starts_with("#") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split lines into words. `parts' is an iterator, which is consumed upon
|
||||||
|
// iterating, rather than collected into a Vec
|
||||||
|
let mut parts = line.split_whitespace();
|
||||||
|
|
||||||
|
// The keyword is the very first space-separated substring, and tells us
|
||||||
|
// how to interpret the rest
|
||||||
|
let keyword = match parts.next() {
|
||||||
|
Some(v) => v,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Short for "read", macro for reading something from the iterator and
|
||||||
|
/// converting it into the appropriate format given by $ty. For this to
|
||||||
|
/// work, $ty must implement Construct
|
||||||
|
macro_rules! r {
|
||||||
|
($ty:ty) => {
|
||||||
|
<$ty>::construct(&mut parts, ())
|
||||||
|
.with_context(|| format!("Could not parse {} ({}:{})", stringify!($ty), file!(), line!()))?
|
||||||
|
};
|
||||||
|
|
||||||
|
($ty:ty, $($ex:expr),* $(,)?) => {
|
||||||
|
<$ty>::construct(&mut parts, $($ex,)*)
|
||||||
|
.with_context(|| format!("Could not parse {} ({}:{})", stringify!($ty), file!(), line!()))?
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shortcut for unwrapping one of the state `Option's
|
||||||
|
macro_rules! u {
|
||||||
|
($expr:expr) => {
|
||||||
|
match $expr {
|
||||||
|
Some(v) => v,
|
||||||
|
None => {
|
||||||
|
bail!(
|
||||||
|
"Each object must be preceded by a `{}` line",
|
||||||
|
stringify!($expr)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
match keyword {
|
||||||
|
"imsize" => {
|
||||||
|
scene.image_width = r!(usize);
|
||||||
|
scene.image_height = r!(usize);
|
||||||
|
}
|
||||||
|
"projection" => {
|
||||||
|
if let Some("parallel") = parts.next() {
|
||||||
|
scene.parallel_projection = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"eye" => scene.eye_pos = r!(Vector3<f64>),
|
||||||
|
"viewdir" => scene.view_dir = r!(Vector3<f64>),
|
||||||
|
"updir" => scene.up_dir = r!(Vector3<f64>),
|
||||||
|
|
||||||
|
"hfov" => scene.hfov = r!(f64),
|
||||||
|
"bkgcolor" => scene.bkg_color = r!(Color),
|
||||||
|
|
||||||
|
// light x y z w r g b
|
||||||
|
// attlight x y z w r g b c1 c2 c3
|
||||||
|
"light" | "attlight" => {
|
||||||
|
let vec3 = r!(Vector3<f64>);
|
||||||
|
let w = r!(usize);
|
||||||
|
let color = r!(Color);
|
||||||
|
|
||||||
|
let attenuation = match keyword == "attlight" {
|
||||||
|
true => {
|
||||||
|
let c = r!(Vector3<f64>);
|
||||||
|
Some(Attenuation {
|
||||||
|
c1: c.x,
|
||||||
|
c2: c.y,
|
||||||
|
c3: c.z,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
false => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let kind = match w as usize {
|
||||||
|
0 => LightKind::Directional { direction: vec3 },
|
||||||
|
1 => LightKind::Point {
|
||||||
|
location: vec3,
|
||||||
|
attenuation,
|
||||||
|
},
|
||||||
|
_ => bail!("Invalid w; must be either 0 or 1"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let light = Light { kind, color };
|
||||||
|
scene.lights.push(light);
|
||||||
|
}
|
||||||
|
|
||||||
|
// depthcueing dcr dcg dcb amax amin distmax distmin
|
||||||
|
"depthcueing" => {
|
||||||
|
let color = r!(Color);
|
||||||
|
let a_max = r!(f64);
|
||||||
|
let a_min = r!(f64);
|
||||||
|
let dist_max = r!(f64);
|
||||||
|
let dist_min = r!(f64);
|
||||||
|
|
||||||
|
scene.depth_cueing = DepthCueing {
|
||||||
|
color,
|
||||||
|
a_max,
|
||||||
|
a_min,
|
||||||
|
dist_max,
|
||||||
|
dist_min,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// mtlcolor Odr Odg Odb Osr Osg Osb ka kd ks n alpha eta
|
||||||
|
"mtlcolor" => {
|
||||||
|
let diffuse_color = r!(Color);
|
||||||
|
let specular_color = r!(Color);
|
||||||
|
let k_a = r!(f64);
|
||||||
|
let k_d = r!(f64);
|
||||||
|
let k_s = r!(f64);
|
||||||
|
let exponent = r!(f64);
|
||||||
|
let alpha = r!(f64);
|
||||||
|
let eta = r!(f64);
|
||||||
|
|
||||||
|
let material = Material {
|
||||||
|
diffuse_color,
|
||||||
|
specular_color,
|
||||||
|
k_a,
|
||||||
|
k_d,
|
||||||
|
k_s,
|
||||||
|
exponent,
|
||||||
|
alpha,
|
||||||
|
eta,
|
||||||
|
};
|
||||||
|
|
||||||
|
let idx = scene.materials.len();
|
||||||
|
material_idx = Some(idx);
|
||||||
|
scene.materials.push(material);
|
||||||
|
}
|
||||||
|
|
||||||
|
"sphere" => {
|
||||||
|
let center = r!(Point);
|
||||||
|
let radius = r!(f64);
|
||||||
|
|
||||||
|
scene.objects.push(Object {
|
||||||
|
kind: ObjectKind::Sphere(Sphere { center, radius }),
|
||||||
|
material_idx: u!(material_idx),
|
||||||
|
texture_idx,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
"cylinder" => {
|
||||||
|
let center = r!(Point);
|
||||||
|
let direction = r!(Vector);
|
||||||
|
let radius = r!(f64);
|
||||||
|
let length = r!(f64);
|
||||||
|
|
||||||
|
scene.objects.push(Object {
|
||||||
|
kind: ObjectKind::Cylinder(Cylinder {
|
||||||
|
center,
|
||||||
|
direction,
|
||||||
|
radius,
|
||||||
|
length,
|
||||||
|
}),
|
||||||
|
material_idx: u!(material_idx),
|
||||||
|
texture_idx,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assignment 1C: Triangles and textures
|
||||||
|
|
||||||
|
// v x y z
|
||||||
|
"v" => scene.triangle_vertices.push(r!(Vector)),
|
||||||
|
|
||||||
|
// vn nx ny nz
|
||||||
|
"vn" => scene.vertex_normals.push(r!(Vector)),
|
||||||
|
|
||||||
|
// f v1 v2 v3
|
||||||
|
// f v1//n1 v2//n2 v3//n3
|
||||||
|
"f" => {
|
||||||
|
let v1 = r!(TriangleVertex);
|
||||||
|
let v2 = r!(TriangleVertex);
|
||||||
|
let v3 = r!(TriangleVertex);
|
||||||
|
let vs = Vector3::new(v1, v2, v3);
|
||||||
|
|
||||||
|
let vertices = vs.map(|v| v.vertex_idx);
|
||||||
|
|
||||||
|
let normals = vs.map(|v| v.normal_idx);
|
||||||
|
let normals = match normals.iter().filter(|o| o.is_some()).count() {
|
||||||
|
0 => None,
|
||||||
|
n if n == vs.len() => Some(normals.map(|o| o.unwrap())),
|
||||||
|
_ => bail!("Cannot mix and match having a normal index"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let textures = vs.map(|v| v.texture_idx);
|
||||||
|
let textures = match textures.iter().filter(|o| o.is_some()).count() {
|
||||||
|
0 => None,
|
||||||
|
n if n == vs.len() => Some(textures.map(|o| o.unwrap())),
|
||||||
|
_ => bail!("Cannot mix and match having a normal index"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let triangle = Triangle {
|
||||||
|
vertices,
|
||||||
|
normals,
|
||||||
|
textures,
|
||||||
|
};
|
||||||
|
scene.objects.push(Object {
|
||||||
|
kind: ObjectKind::Triangle(triangle),
|
||||||
|
material_idx: u!(material_idx),
|
||||||
|
texture_idx,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
"texture" => {
|
||||||
|
let input_parent = path.parent().unwrap().to_path_buf();
|
||||||
|
let path = match parts.next() {
|
||||||
|
Some(s) => input_parent.join(s),
|
||||||
|
None => bail!("Did not provide path."),
|
||||||
|
};
|
||||||
|
|
||||||
|
let idx = scene.textures.len();
|
||||||
|
texture_idx = Some(idx);
|
||||||
|
|
||||||
|
let image = Image::from_file(path)?;
|
||||||
|
let texture = Texture::new(image);
|
||||||
|
scene.textures.push(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
"bump" => {
|
||||||
|
let input_parent = path.parent().unwrap().to_path_buf();
|
||||||
|
let path = match parts.next() {
|
||||||
|
Some(s) => input_parent.join(s),
|
||||||
|
None => bail!("Did not provide path."),
|
||||||
|
};
|
||||||
|
|
||||||
|
let idx = scene.textures.len();
|
||||||
|
texture_idx = Some(idx);
|
||||||
|
|
||||||
|
let image = Image::from_file(path)?;
|
||||||
|
let normal_map = NormalMap::new(image);
|
||||||
|
scene.normal_maps.push(normal_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => bail!("Unknown keyword {keyword}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(scene)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Construct: Sized {
|
||||||
|
type Args;
|
||||||
|
|
||||||
|
/// Construct an element of this type from an iterator over strings.
|
||||||
|
fn construct<'a, I>(it: &mut I, args: Self::Args) -> Result<Self>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = &'a str>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Construct> Construct for Option<T> {
|
||||||
|
type Args = T::Args;
|
||||||
|
|
||||||
|
fn construct<'a, I>(it: &mut I, args: Self::Args) -> Result<Self>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = &'a str>,
|
||||||
|
{
|
||||||
|
let mut peeker = it.peekable();
|
||||||
|
|
||||||
|
if peeker.peek().is_none() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
T::construct(&mut peeker, args).map(Some)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_construct {
|
||||||
|
($ty:ty) => {
|
||||||
|
impl Construct for $ty {
|
||||||
|
type Args = ();
|
||||||
|
|
||||||
|
fn construct<'a, I>(it: &mut I, _: Self::Args) -> Result<Self>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = &'a str>,
|
||||||
|
{
|
||||||
|
let item = match it.next() {
|
||||||
|
Some(v) => v,
|
||||||
|
None => bail!(
|
||||||
|
"Ran out of items for {} ({}:{})",
|
||||||
|
stringify!($ty),
|
||||||
|
file!(),
|
||||||
|
line!()
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(item.parse()?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_construct!(f64);
|
||||||
|
impl_construct!(usize);
|
||||||
|
|
||||||
|
impl Construct for Vector3<f64> {
|
||||||
|
type Args = ();
|
||||||
|
|
||||||
|
fn construct<'a, I>(it: &mut I, _: Self::Args) -> Result<Self>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = &'a str>,
|
||||||
|
{
|
||||||
|
let (x, y, z) = match it.next_tuple() {
|
||||||
|
Some(v) => v,
|
||||||
|
None => bail!("Expected 3 values"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let x: f64 = x.parse()?;
|
||||||
|
let y: f64 = y.parse()?;
|
||||||
|
let z: f64 = z.parse()?;
|
||||||
|
|
||||||
|
Ok(Vector3::new(x, y, z))
|
||||||
|
}
|
||||||
|
}
|
49
assignment-1d/src/scene/input_file/triangle_vertex.rs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
use super::Construct;
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
|
pub struct TriangleVertex {
|
||||||
|
pub vertex_idx: usize,
|
||||||
|
pub normal_idx: Option<usize>,
|
||||||
|
pub texture_idx: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Construct for TriangleVertex {
|
||||||
|
type Args = ();
|
||||||
|
|
||||||
|
fn construct<'a, I>(it: &mut I, _: Self::Args) -> Result<Self>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = &'a str>,
|
||||||
|
{
|
||||||
|
let s = match it.next() {
|
||||||
|
Some(v) => v,
|
||||||
|
None => bail!("Waiting on another"),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Note: indexed by 1 not 0, so we will just do the subtraction
|
||||||
|
// here to avoid having to deal with it later
|
||||||
|
let parts = s.split("/").collect_vec();
|
||||||
|
ensure!(parts.len() >= 1 && parts.len() <= 3);
|
||||||
|
let vertex_idx: usize = parts[0].parse::<usize>()? - 1;
|
||||||
|
|
||||||
|
let texture_idx =
|
||||||
|
match parts.get(1).and_then(|s| (!s.is_empty()).then(|| *s)) {
|
||||||
|
Some(s) => Some(s.parse::<usize>()? - 1),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let normal_idx =
|
||||||
|
match parts.get(2).and_then(|s| (!s.is_empty()).then(|| *s)) {
|
||||||
|
Some(s) => Some(s.parse::<usize>()? - 1),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(TriangleVertex {
|
||||||
|
vertex_idx,
|
||||||
|
texture_idx,
|
||||||
|
normal_idx,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
52
assignment-1d/src/scene/mod.rs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
pub mod cylinder;
|
||||||
|
pub mod data;
|
||||||
|
pub mod illumination;
|
||||||
|
pub mod input_file;
|
||||||
|
pub mod object;
|
||||||
|
pub mod sphere;
|
||||||
|
pub mod texture;
|
||||||
|
pub mod tracing;
|
||||||
|
pub mod triangle;
|
||||||
|
|
||||||
|
use crate::image::Color;
|
||||||
|
use crate::{Point, Point2, Vector};
|
||||||
|
|
||||||
|
use self::data::{Attenuation, DepthCueing, Light, Material};
|
||||||
|
use self::object::Object;
|
||||||
|
use self::texture::{NormalMap, Texture};
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct Scene {
|
||||||
|
pub eye_pos: Point,
|
||||||
|
pub view_dir: Vector,
|
||||||
|
pub up_dir: Vector,
|
||||||
|
|
||||||
|
/// Horizontal field of view (in degrees)
|
||||||
|
pub hfov: f64,
|
||||||
|
pub parallel_projection: bool,
|
||||||
|
|
||||||
|
pub image_width: usize,
|
||||||
|
pub image_height: usize,
|
||||||
|
|
||||||
|
/// Background color
|
||||||
|
pub bkg_color: Color,
|
||||||
|
pub depth_cueing: DepthCueing,
|
||||||
|
pub attenuation: Attenuation,
|
||||||
|
|
||||||
|
pub materials: Vec<Material>,
|
||||||
|
pub lights: Vec<Light>,
|
||||||
|
pub objects: Vec<Object>,
|
||||||
|
|
||||||
|
/// List of textures
|
||||||
|
pub textures: Vec<Texture>,
|
||||||
|
|
||||||
|
/// List of normal maps (Extra credit)
|
||||||
|
pub normal_maps: Vec<NormalMap>,
|
||||||
|
|
||||||
|
/// Coordinates into a texture image
|
||||||
|
pub texture_vertices: Vec<Point2>,
|
||||||
|
|
||||||
|
/// Triangle vertices
|
||||||
|
pub triangle_vertices: Vec<Point>,
|
||||||
|
pub vertex_normals: Vec<Vector>,
|
||||||
|
}
|
61
assignment-1d/src/scene/object.rs
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
use crate::ray::Ray;
|
||||||
|
|
||||||
|
use super::cylinder::Cylinder;
|
||||||
|
use super::illumination::IntersectionContext;
|
||||||
|
use super::sphere::Sphere;
|
||||||
|
use super::triangle::Triangle;
|
||||||
|
use super::Scene;
|
||||||
|
|
||||||
|
/// An object in the scene
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Object {
|
||||||
|
pub kind: ObjectKind,
|
||||||
|
|
||||||
|
/// Index into the scene's material color list
|
||||||
|
pub material_idx: usize,
|
||||||
|
|
||||||
|
/// If this object has a texture, this is the index into the texture list
|
||||||
|
pub texture_idx: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ObjectKind {
|
||||||
|
Sphere(Sphere),
|
||||||
|
Cylinder(Cylinder),
|
||||||
|
Triangle(Triangle),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectKind {
|
||||||
|
/// Determine where the ray intersects this object, returning the earliest
|
||||||
|
/// time this happens. Returns None if no intersection occurs.
|
||||||
|
///
|
||||||
|
/// Also known as Trace_Ray in the slides, except not the part where it calls
|
||||||
|
/// Shade_Ray.
|
||||||
|
pub fn intersects_ray_at(
|
||||||
|
&self,
|
||||||
|
scene: &Scene,
|
||||||
|
ray: &Ray,
|
||||||
|
) -> Result<Option<IntersectionContext>> {
|
||||||
|
match self {
|
||||||
|
ObjectKind::Sphere(sphere) => sphere.intersects_ray_at(scene, ray),
|
||||||
|
ObjectKind::Cylinder(cylinder) => cylinder.intersects_ray_at(scene, ray),
|
||||||
|
ObjectKind::Triangle(triangle) => triangle.intersects_ray_at(scene, ray),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the (u, v) coordinates in the texture (between 0 and 1) that
|
||||||
|
/// corresponds to the intersection point
|
||||||
|
pub fn get_texture_coord(
|
||||||
|
&self,
|
||||||
|
scene: &Scene,
|
||||||
|
ctx: &IntersectionContext,
|
||||||
|
) -> Result<(f64, f64)> {
|
||||||
|
match self {
|
||||||
|
ObjectKind::Sphere(sphere) => sphere.get_texture_coord(ctx),
|
||||||
|
ObjectKind::Cylinder(cylinder) => todo!(),
|
||||||
|
ObjectKind::Triangle(triangle) => triangle.get_texture_coord(scene, ctx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
116
assignment-1d/src/scene/sphere.rs
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
use std::f64::consts::PI;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use ordered_float::NotNan;
|
||||||
|
|
||||||
|
use crate::{ray::Ray, utils::min_f64, Point};
|
||||||
|
|
||||||
|
use super::illumination::IntersectionContext;
|
||||||
|
use super::Scene;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Sphere {
|
||||||
|
pub center: Point,
|
||||||
|
pub radius: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sphere {
|
||||||
|
/// Given a sphere, returns the first time at which this ray intersects the
|
||||||
|
/// sphere.
|
||||||
|
///
|
||||||
|
/// If there is no intersection point, returns None.
|
||||||
|
pub fn intersects_ray_at(
|
||||||
|
&self,
|
||||||
|
_: &Scene,
|
||||||
|
ray: &Ray,
|
||||||
|
) -> Result<Option<IntersectionContext>> {
|
||||||
|
let a = ray.direction.norm();
|
||||||
|
let b = 2.0
|
||||||
|
* (ray.direction.x * (ray.origin.x - self.center.x)
|
||||||
|
+ ray.direction.y * (ray.origin.y - self.center.y)
|
||||||
|
+ ray.direction.z * (ray.origin.z - self.center.z));
|
||||||
|
let c = (ray.origin.x - self.center.x).powi(2)
|
||||||
|
+ (ray.origin.y - self.center.y).powi(2)
|
||||||
|
+ (ray.origin.z - self.center.z).powi(2)
|
||||||
|
- self.radius.powi(2);
|
||||||
|
|
||||||
|
let discriminant = b * b - 4.0 * a * c;
|
||||||
|
|
||||||
|
if discriminant.is_nan() {
|
||||||
|
warn!("WTF NAN");
|
||||||
|
}
|
||||||
|
|
||||||
|
let time = match discriminant {
|
||||||
|
// Discriminant < 0, means the equation has no solutions.
|
||||||
|
d if d < 0.0 => None,
|
||||||
|
|
||||||
|
// Discriminant == 0
|
||||||
|
d if d == 0.0 => Some(-b / (2.0 * a)),
|
||||||
|
|
||||||
|
d if d > 0.0 => {
|
||||||
|
let solution_1 = (-b + discriminant.sqrt()) / (2.0 * a);
|
||||||
|
let solution_2 = (-b - discriminant.sqrt()) / (2.0 * a);
|
||||||
|
|
||||||
|
let solutions = [solution_1, solution_2]
|
||||||
|
.into_iter()
|
||||||
|
// Remove any t < 0, since that means it's behind the viewer and we
|
||||||
|
// can't see it.
|
||||||
|
.filter(|t| *t >= 0.0);
|
||||||
|
|
||||||
|
// Return the minimum solution
|
||||||
|
min_f64(solutions)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Probably hit some NaN or Infinity value due to faulty inputs...
|
||||||
|
_ => unreachable!("Invalid determinant value: {discriminant}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let time = match time.and_then(|t| NotNan::new(t).ok()) {
|
||||||
|
Some(v) => v,
|
||||||
|
None => return Ok(None),
|
||||||
|
};
|
||||||
|
|
||||||
|
let point = ray.eval(*time);
|
||||||
|
let normal = (point - self.center).normalize();
|
||||||
|
|
||||||
|
let exiting = {
|
||||||
|
// To figure out if we're exiting, just test if the origin is inside the
|
||||||
|
// sphere
|
||||||
|
|
||||||
|
let dx = ray.origin.x - self.center.x;
|
||||||
|
let dy = ray.origin.y - self.center.y;
|
||||||
|
let dz = ray.origin.z - self.center.z;
|
||||||
|
|
||||||
|
dx.powi(2) + dy.powi(2) + dz.powi(2) <= self.radius.powi(2)
|
||||||
|
};
|
||||||
|
|
||||||
|
/* let normal = match exiting {
|
||||||
|
true => -normal,
|
||||||
|
false => normal,
|
||||||
|
}; */
|
||||||
|
|
||||||
|
Ok(Some(IntersectionContext {
|
||||||
|
time,
|
||||||
|
point,
|
||||||
|
normal,
|
||||||
|
exiting,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_texture_coord(
|
||||||
|
&self,
|
||||||
|
ctx: &IntersectionContext,
|
||||||
|
) -> Result<(f64, f64)> {
|
||||||
|
// Reverse engineer the angles from the coordinate of the intersection
|
||||||
|
let cosp = (ctx.point.z - self.center.z) / self.radius;
|
||||||
|
let phi = cosp.acos();
|
||||||
|
let theta =
|
||||||
|
(ctx.point.y - self.center.y).atan2(ctx.point.x - self.center.x);
|
||||||
|
|
||||||
|
// Map theta and phi into 0 - 1 range
|
||||||
|
let v = phi / PI;
|
||||||
|
let u = 0.5 + theta / (2.0 * PI);
|
||||||
|
|
||||||
|
Ok((u, v))
|
||||||
|
}
|
||||||
|
}
|
64
assignment-1d/src/scene/texture.rs
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
use crate::{
|
||||||
|
image::{Color, Image},
|
||||||
|
Vector,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Texture(Image);
|
||||||
|
|
||||||
|
impl Texture {
|
||||||
|
pub fn new(image: Image) -> Self {
|
||||||
|
Self(image)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pixel_at_exact(&self, x: usize, y: usize) -> Color {
|
||||||
|
// TODO: Debug asserts?
|
||||||
|
|
||||||
|
self.0.data[y * self.0.width + x]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a pixel at the given coordinate. For non-lattice coordinates,
|
||||||
|
/// bi-linear interpolation of the image is done.
|
||||||
|
pub fn pixel_at(&self, u: f64, v: f64) -> Color {
|
||||||
|
debug_assert!(0.0 <= u && u <= 1.0, "u must be between 0 and 1");
|
||||||
|
debug_assert!(0.0 <= v && v <= 1.0, "u must be between 0 and 1");
|
||||||
|
|
||||||
|
// Slide 121
|
||||||
|
let x = u * (self.0.width - 1) as f64;
|
||||||
|
let y = v * (self.0.height - 1) as f64;
|
||||||
|
|
||||||
|
let i = x.floor();
|
||||||
|
let j = y.floor();
|
||||||
|
|
||||||
|
let alpha = x - i;
|
||||||
|
let beta = y - j;
|
||||||
|
|
||||||
|
let i = i as usize;
|
||||||
|
let j = j as usize;
|
||||||
|
|
||||||
|
(1.0 - alpha) * (1.0 - beta) * self.pixel_at_exact(i, j)
|
||||||
|
+ (alpha) * (1.0 - beta) * self.pixel_at_exact(i + 1, j)
|
||||||
|
+ (1.0 - alpha) * (beta) * self.pixel_at_exact(i, j + 1)
|
||||||
|
+ (alpha) * (beta) * self.pixel_at_exact(i + 1, j + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct NormalMap(Image);
|
||||||
|
|
||||||
|
impl NormalMap {
|
||||||
|
pub fn new(image: Image) -> Self {
|
||||||
|
Self(image)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn normal_vector_at_exact(&self, x: usize, y: usize) -> Vector {
|
||||||
|
let vec = self.0.data[y * self.0.width + x];
|
||||||
|
|
||||||
|
// So, according to the instructions, this should actually be a value
|
||||||
|
// between -1 and 1. However, we're reading this in through an image.
|
||||||
|
// I'm just going to do the lazy thing here (which theoretically
|
||||||
|
// actually saves cycles) by only doing the transformation when loading
|
||||||
|
// out of the image
|
||||||
|
vec.map(|value| 2.0 * value / 255.0 - 1.0)
|
||||||
|
}
|
||||||
|
}
|
66
assignment-1d/src/scene/tracing.rs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
use crate::{image::Color, ray::Ray, Point};
|
||||||
|
|
||||||
|
use super::Scene;
|
||||||
|
|
||||||
|
const MAX_RECURSION_DEPTH: usize = 10_usize;
|
||||||
|
|
||||||
|
impl Scene {
|
||||||
|
pub fn trace_single_ray(
|
||||||
|
&self,
|
||||||
|
origin: Point,
|
||||||
|
ray: Ray,
|
||||||
|
depth: usize,
|
||||||
|
) -> Result<Color> {
|
||||||
|
if depth > MAX_RECURSION_DEPTH {
|
||||||
|
return Ok(Color::new(0.0, 0.0, 0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
let span = trace_span!("trace_ray", ray = ?ray, depth = depth);
|
||||||
|
let _enter = span.enter();
|
||||||
|
|
||||||
|
let intersections = self
|
||||||
|
.objects
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(i, object)| {
|
||||||
|
match object.kind.intersects_ray_at(&self, &ray) {
|
||||||
|
Ok(Some(t)) => {
|
||||||
|
// Return both the t and the sphere, because we want to sort on
|
||||||
|
// the t but later retrieve attributes from the sphere
|
||||||
|
Some(Ok((i, t, object)))
|
||||||
|
}
|
||||||
|
Ok(None) => None,
|
||||||
|
Err(err) => {
|
||||||
|
error!("Error: {err}");
|
||||||
|
Some(Err(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>>>()?;
|
||||||
|
|
||||||
|
// Sort the list of intersection times by the lowest one.
|
||||||
|
let earliest_intersection =
|
||||||
|
intersections.into_iter().min_by_key(|(_, t, _)| t.time);
|
||||||
|
|
||||||
|
info!("Ray {ray:?} intersected at: {earliest_intersection:?}");
|
||||||
|
|
||||||
|
Ok(match earliest_intersection {
|
||||||
|
// Take the object's material color
|
||||||
|
Some((obj_idx, intersection_context, object)) => self
|
||||||
|
.compute_pixel_color(
|
||||||
|
obj_idx,
|
||||||
|
object,
|
||||||
|
origin,
|
||||||
|
ray,
|
||||||
|
intersection_context,
|
||||||
|
depth,
|
||||||
|
)?,
|
||||||
|
|
||||||
|
// There was no intersection, so this should default to the scene's
|
||||||
|
// background color
|
||||||
|
None => self.bkg_color,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
190
assignment-1d/src/scene/triangle.rs
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
use std::f64::EPSILON;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use nalgebra::{Matrix2, Vector2, Vector3};
|
||||||
|
use ordered_float::NotNan;
|
||||||
|
|
||||||
|
use crate::ray::Ray;
|
||||||
|
use crate::utils::{cross, dot};
|
||||||
|
use crate::{Point, Vector};
|
||||||
|
|
||||||
|
use super::illumination::IntersectionContext;
|
||||||
|
use super::Scene;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Triangle {
|
||||||
|
/// Indexes into the scene's vertex list
|
||||||
|
pub vertices: Vector3<usize>,
|
||||||
|
|
||||||
|
/// Indexes into the scene's normal coordinates list
|
||||||
|
pub normals: Option<Vector3<usize>>,
|
||||||
|
|
||||||
|
/// Indexes into the scene's texture coordinates list
|
||||||
|
pub textures: Option<Vector3<usize>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Triangle {
|
||||||
|
pub fn intersects_ray_at(
|
||||||
|
&self,
|
||||||
|
scene: &Scene,
|
||||||
|
ray: &Ray,
|
||||||
|
) -> Result<Option<IntersectionContext>> {
|
||||||
|
let (p0, e1, e2) = self.basis_vectors(scene);
|
||||||
|
|
||||||
|
// Solve for the plane equation coefficients A, B, C, D such that:
|
||||||
|
//
|
||||||
|
// $$
|
||||||
|
// Ax + By + Cz + D = 0
|
||||||
|
// $$
|
||||||
|
let n = cross(e1, e2);
|
||||||
|
let a = n.x;
|
||||||
|
let b = n.y;
|
||||||
|
let c = n.z;
|
||||||
|
|
||||||
|
// Sub in p0 to solve for D
|
||||||
|
let d = -(a * p0.x + b * p0.y + c * p0.z);
|
||||||
|
|
||||||
|
// Find the intersection point
|
||||||
|
let time = {
|
||||||
|
let (x0, y0, z0, xd, yd, zd) =
|
||||||
|
match (ray.origin.as_slice(), ray.direction.as_slice()) {
|
||||||
|
([x0, y0, z0], [xd, yd, zd]) => (x0, y0, z0, xd, yd, zd),
|
||||||
|
_ => unreachable!("lol rip no tuple interface"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let denom = a * xd + b * yd + c * zd;
|
||||||
|
if denom == 0.0 {
|
||||||
|
// The ray is parallel to the plane, so there is no intersection point.
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
|
-(a * x0 + b * y0 + c * z0 + d) / denom
|
||||||
|
};
|
||||||
|
|
||||||
|
// Intersected the plane behind where the ray started
|
||||||
|
if time < 0.0 {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let time = NotNan::new(time)?;
|
||||||
|
let point = ray.eval(*time);
|
||||||
|
|
||||||
|
// Use barycentric coordinates to determine if the point is inside of the
|
||||||
|
// triangle
|
||||||
|
// p = p0 + beta * e1 + gamma * e2
|
||||||
|
// Using the whack linear algebra approach derived on slide 57
|
||||||
|
let ep = point - p0;
|
||||||
|
let p = Vector2::new(dot(e1, ep), dot(e2, ep));
|
||||||
|
|
||||||
|
let (alpha, beta, gamma) =
|
||||||
|
self.compute_barycentric_coordinates(scene, p)?;
|
||||||
|
|
||||||
|
// Each of alpha, beta, and gamma must be between 0 and 1
|
||||||
|
if ![alpha, beta, gamma]
|
||||||
|
.into_iter()
|
||||||
|
.all(|v| 0.0 - EPSILON <= v && v <= 1.0 + EPSILON)
|
||||||
|
{
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let normal = match self.normals {
|
||||||
|
// If surface normals are provided, then interpolate the normals to do
|
||||||
|
// smooth shading
|
||||||
|
Some(normals) => {
|
||||||
|
let n0 = scene.vertex_normals[normals.x];
|
||||||
|
let n1 = scene.vertex_normals[normals.y];
|
||||||
|
let n2 = scene.vertex_normals[normals.z];
|
||||||
|
|
||||||
|
(alpha * n0 + beta * n1 + gamma * n2).normalize()
|
||||||
|
}
|
||||||
|
|
||||||
|
None => n.normalize(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Some(IntersectionContext {
|
||||||
|
time,
|
||||||
|
point,
|
||||||
|
normal,
|
||||||
|
exiting: false,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the (u, v) texture coordinates corresponding to the point provided in
|
||||||
|
/// the intersection context
|
||||||
|
pub fn get_texture_coord(
|
||||||
|
&self,
|
||||||
|
scene: &Scene,
|
||||||
|
ctx: &IntersectionContext,
|
||||||
|
) -> Result<(f64, f64)> {
|
||||||
|
let texture_coordinates = match self.textures {
|
||||||
|
Some(v) => v,
|
||||||
|
None => {
|
||||||
|
bail!("Textured triangle requested without providing coordinates")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let p0 = scene.texture_vertices[texture_coordinates.x];
|
||||||
|
let p1 = scene.texture_vertices[texture_coordinates.y];
|
||||||
|
let p2 = scene.texture_vertices[texture_coordinates.z];
|
||||||
|
|
||||||
|
let p = self.convert_point(scene, ctx.point);
|
||||||
|
let (alpha, beta, gamma) =
|
||||||
|
self.compute_barycentric_coordinates(scene, p)?;
|
||||||
|
|
||||||
|
let u = alpha * p0.x + beta * p1.x + gamma * p2.x;
|
||||||
|
let v = alpha * p0.y + beta * p1.y + gamma * p2.y;
|
||||||
|
|
||||||
|
Ok((u, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert_point(&self, scene: &Scene, point: Point) -> Vector2<f64> {
|
||||||
|
let (p0, e1, e2) = self.basis_vectors(scene);
|
||||||
|
|
||||||
|
let ep = point - p0;
|
||||||
|
Vector2::new(dot(e1, ep), dot(e2, ep))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fetch the corners of the triangles from the scene
|
||||||
|
#[inline]
|
||||||
|
fn corner_coordinates(&self, scene: &Scene) -> (Point, Point, Point) {
|
||||||
|
let p0 = scene.triangle_vertices[self.vertices.x];
|
||||||
|
let p1 = scene.triangle_vertices[self.vertices.y];
|
||||||
|
let p2 = scene.triangle_vertices[self.vertices.z];
|
||||||
|
|
||||||
|
(p0, p1, p2)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the new basis vectors using p0 as the origin. Returns (p0, e1, e2)
|
||||||
|
#[inline]
|
||||||
|
fn basis_vectors(&self, scene: &Scene) -> (Vector, Vector, Vector) {
|
||||||
|
let (p0, p1, p2) = self.corner_coordinates(scene);
|
||||||
|
let e1 = p1 - p0;
|
||||||
|
let e2 = p2 - p0;
|
||||||
|
(p0, e1, e2)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute barycentric coordinates
|
||||||
|
fn compute_barycentric_coordinates(
|
||||||
|
&self,
|
||||||
|
scene: &Scene,
|
||||||
|
p: Vector2<f64>,
|
||||||
|
) -> Result<(f64, f64, f64)> {
|
||||||
|
let (_, e1, e2) = self.basis_vectors(scene);
|
||||||
|
let d = Matrix2::new(dot(e1, e1), dot(e1, e2), dot(e2, e1), dot(e2, e2));
|
||||||
|
|
||||||
|
let d_inv = match d.try_inverse() {
|
||||||
|
Some(v) => v,
|
||||||
|
// TODO: Whack
|
||||||
|
None => bail!("No inverse..."),
|
||||||
|
};
|
||||||
|
|
||||||
|
let sol = d_inv * p;
|
||||||
|
let beta = sol.x;
|
||||||
|
let gamma = sol.y;
|
||||||
|
|
||||||
|
// Slide 46
|
||||||
|
let alpha = 1.0 - beta - gamma;
|
||||||
|
|
||||||
|
Ok((alpha, beta, gamma))
|
||||||
|
}
|
||||||
|
}
|
160
assignment-1d/src/utils.rs
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use nalgebra::{Matrix3, Vector3};
|
||||||
|
use ordered_float::NotNan;
|
||||||
|
|
||||||
|
use crate::{ray::Ray, Vector};
|
||||||
|
|
||||||
|
/// Finds the minimum of an iterator of f64s, ignoring any NaN values
|
||||||
|
#[inline]
|
||||||
|
pub fn min_f64<I>(i: I) -> Option<f64>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = f64>,
|
||||||
|
{
|
||||||
|
i.filter_map(|i| NotNan::new(i).ok())
|
||||||
|
.min()
|
||||||
|
.map(|i| i.into_inner())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finds the minimum of an iterator of f64s using the given predicate, ignoring
|
||||||
|
/// any NaN values
|
||||||
|
#[inline]
|
||||||
|
pub fn min_f64_by_key<I, F>(i: I, f: F) -> Option<f64>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = f64>,
|
||||||
|
F: FnMut(&NotNan<f64>),
|
||||||
|
{
|
||||||
|
i.filter_map(|i| NotNan::new(i).ok())
|
||||||
|
.min_by_key(f)
|
||||||
|
.map(|i| i.into_inner())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Dot-product between two 3D vectors.
|
||||||
|
#[inline]
|
||||||
|
pub fn dot(a: Vector, b: Vector) -> f64 {
|
||||||
|
a.x * b.x + a.y * b.y + a.z * b.z
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cross-product between two 3D vectors.
|
||||||
|
#[inline]
|
||||||
|
pub fn cross(a: Vector, b: Vector) -> Vector {
|
||||||
|
let x = a.y * b.z - a.z * b.y;
|
||||||
|
let y = a.z * b.x - a.x * b.z;
|
||||||
|
let z = a.x * b.y - a.y * b.x;
|
||||||
|
Vector::new(x, y, z)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculate the rotation matrix between the 2 given vectors
|
||||||
|
///
|
||||||
|
/// Based on the method given [here][1].
|
||||||
|
///
|
||||||
|
/// [1]: https://math.stackexchange.com/a/897677
|
||||||
|
pub fn compute_rotation_matrix(
|
||||||
|
a: Vector3<f64>,
|
||||||
|
b: Vector3<f64>,
|
||||||
|
) -> Result<Matrix3<f64>> {
|
||||||
|
// Special case: if a and b are in the same direction, just return the
|
||||||
|
// identity matrix.
|
||||||
|
if a.normalize() == b.normalize() {
|
||||||
|
return Ok(Matrix3::identity());
|
||||||
|
}
|
||||||
|
|
||||||
|
let cos_t = dot(a, b);
|
||||||
|
let sin_t = cross(a, b).norm();
|
||||||
|
|
||||||
|
let g = Matrix3::new(cos_t, -sin_t, 0.0, sin_t, cos_t, 0.0, 0.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
// New basis vectors
|
||||||
|
let u = a;
|
||||||
|
let v = (b - cos_t * a).normalize();
|
||||||
|
let w = cross(b, a);
|
||||||
|
|
||||||
|
// Not sure if this is required to be invertible?
|
||||||
|
let f_inverse = Matrix3::from_columns(&[u, v, w]);
|
||||||
|
let f = match f_inverse.try_inverse() {
|
||||||
|
Some(v) => v,
|
||||||
|
None => {
|
||||||
|
// So I ran into this case trying to compute the rotation matrix where one
|
||||||
|
// of the vector endpoints was (0, 0, 0). I'm pretty sure this case makes
|
||||||
|
// no sense in reality, which means if I ever encounter this case, I
|
||||||
|
// probably made a mistake somewhere before. So going to just error
|
||||||
|
// out here and screw recovering.
|
||||||
|
//
|
||||||
|
// println!("Failed to compute inverse matrix.");
|
||||||
|
// println!("- Initial: a = {a}, b = {b}");
|
||||||
|
// println!("- cos(t) = {cos_t}, sin(t) = {sin_t}");
|
||||||
|
// println!("- Basis: u = {u}, v = {v}, w = {w}");
|
||||||
|
bail!("Failed to compute inverse matrix of {f_inverse}\na = {a}\nb = {b}")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// if (f_inverse * g * f).norm() != 1.0 {
|
||||||
|
// bail!("WTF {}", (f_inverse * g * f).norm());
|
||||||
|
// }
|
||||||
|
|
||||||
|
Ok(f_inverse * g * f)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RefractionResult {
|
||||||
|
pub cos_theta_i: f64,
|
||||||
|
pub sin_theta_i: f64,
|
||||||
|
pub sin_theta_t: f64,
|
||||||
|
pub cos_theta_t: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This function computes the 4 values:
|
||||||
|
///
|
||||||
|
/// - cos_theta_i
|
||||||
|
/// - sin_theta_i
|
||||||
|
/// - sin_theta_t
|
||||||
|
/// - cos_theta_t
|
||||||
|
///
|
||||||
|
/// If total internal reflection occurs, return None instead.
|
||||||
|
pub fn compute_refraction_lengths(
|
||||||
|
normal: Vector,
|
||||||
|
incident_ray: &Ray,
|
||||||
|
eta_i: f64,
|
||||||
|
eta_t: f64,
|
||||||
|
) -> Option<RefractionResult> {
|
||||||
|
let i = incident_ray.direction.normalize();
|
||||||
|
let cos_theta_i = dot(i, normal);
|
||||||
|
let sin_theta_i = (1.0 - cos_theta_i.powi(2)).sqrt();
|
||||||
|
|
||||||
|
if sin_theta_i * eta_i > eta_t {
|
||||||
|
info!("Total internal reflection encountered.");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let sin_theta_t = (eta_i / eta_t) * sin_theta_i;
|
||||||
|
let cos_theta_t = (1.0 - sin_theta_t.powi(2)).sqrt();
|
||||||
|
|
||||||
|
Some(RefractionResult {
|
||||||
|
cos_theta_i,
|
||||||
|
sin_theta_i,
|
||||||
|
sin_theta_t,
|
||||||
|
cos_theta_t,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn compute_reflection_ray(incident_ray: Vector, normal: Vector) -> Vector {
|
||||||
|
let I = (-incident_ray).normalize();
|
||||||
|
let N = normal.normalize();
|
||||||
|
|
||||||
|
2.0 * dot(N, I) * N - I
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::{utils::compute_reflection_ray, Vector};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_reflection_ray() {
|
||||||
|
let incident_ray = Vector::new(2.0, -1.0, 2.0);
|
||||||
|
let normal = Vector::new(0.0, 1.0, 0.0);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
compute_reflection_ray(incident_ray, normal),
|
||||||
|
Vector::new(2.0, 1.0, 2.0).normalize()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
4
assignment-2a/.clang-format
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
|
||||||
|
AlignAfterOpenBracket: BlockIndent
|
5
assignment-2a/.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/build
|
||||||
|
/result*
|
||||||
|
.cache
|
||||||
|
|
||||||
|
hw2a.michael.zhang.zip
|
79
assignment-2a/CMakeLists.txt
Executable file
|
@ -0,0 +1,79 @@
|
||||||
|
# Set the minimum required version of cmake for this project
|
||||||
|
cmake_minimum_required (VERSION 3.1)
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
|
# Create a project called 'HW2a'
|
||||||
|
project(HW2a)
|
||||||
|
|
||||||
|
# Define in the C++ code what the variable "SRC_DIR" should be equal to the current_path/src
|
||||||
|
add_definitions( -DSRC_DIR="${CMAKE_CURRENT_SOURCE_DIR}/src" )
|
||||||
|
|
||||||
|
# Generate the `compile_commands.json` file.
|
||||||
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "")
|
||||||
|
|
||||||
|
if(CMAKE_EXPORT_COMPILE_COMMANDS)
|
||||||
|
set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES
|
||||||
|
${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Find OpenGL, and set link library names and include paths
|
||||||
|
find_package(OpenGL REQUIRED)
|
||||||
|
set(OPENGL_LIBRARIES ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY})
|
||||||
|
set(OPENGL_INCLUDE_DIRS ${OPENGL_INCLUDE_DIR})
|
||||||
|
include_directories(${OPENGL_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
# Also disable building some of the extra things GLFW has (examples, tests, docs)
|
||||||
|
set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL " " FORCE)
|
||||||
|
set(GLFW_BUILD_TESTS OFF CACHE BOOL " " FORCE)
|
||||||
|
set(GLFW_BUILD_DOCS OFF CACHE BOOL " " FORCE)
|
||||||
|
|
||||||
|
# Now actually run cmake on the CMakeLists.txt file found inside of the GLFW directory
|
||||||
|
add_subdirectory(ext/glfw)
|
||||||
|
|
||||||
|
# Make a list of all the source files
|
||||||
|
set(
|
||||||
|
SOURCES
|
||||||
|
src/HW2a.cpp
|
||||||
|
|
||||||
|
ext/glad/src/glad.c
|
||||||
|
)
|
||||||
|
|
||||||
|
# Make a list of all the header files (optional-- only necessary to make them appear in IDE)
|
||||||
|
set(
|
||||||
|
INCLUDES
|
||||||
|
src/ShaderStuff.hpp
|
||||||
|
)
|
||||||
|
|
||||||
|
# Make a list of all of the directories to look in when doing #include "whatever.h"
|
||||||
|
set(
|
||||||
|
INCLUDE_DIRS
|
||||||
|
ext/
|
||||||
|
ext/glfw/include
|
||||||
|
ext/glad/include
|
||||||
|
)
|
||||||
|
|
||||||
|
set(
|
||||||
|
LIBS
|
||||||
|
glfw
|
||||||
|
${OPENGL_LIBRARIES}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Define what we are trying to produce here (an executable), as
|
||||||
|
# well as what items are needed to create it (the header and source files)
|
||||||
|
add_executable(${PROJECT_NAME} ${SOURCES} ${INCLUDES})
|
||||||
|
|
||||||
|
# Tell cmake which directories to look in when you #include a file
|
||||||
|
# Equivalent to the "-I" option for g++
|
||||||
|
include_directories(${INCLUDE_DIRS})
|
||||||
|
|
||||||
|
# Tell cmake which libraries to link to
|
||||||
|
# Equivalent to the "-l" option for g++
|
||||||
|
target_link_libraries(${PROJECT_NAME} PRIVATE ${LIBS})
|
||||||
|
|
||||||
|
# For Visual Studio only
|
||||||
|
if (MSVC)
|
||||||
|
# Do a parallel compilation of this project
|
||||||
|
target_compile_options(${PROJECT_NAME} PRIVATE "/MP")
|
||||||
|
# Have this project be the default startup project (the one to build/run when hitting F5)
|
||||||
|
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME})
|
||||||
|
endif()
|
14
assignment-2a/Makefile
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
|
ZIP := zip
|
||||||
|
|
||||||
|
HANDIN := hw2a.michael.zhang.zip
|
||||||
|
SOURCES := $(shell find -name "*.cpp")
|
||||||
|
|
||||||
|
all: $(HANDIN)
|
||||||
|
|
||||||
|
$(HANDIN): src/HW2a.cpp examples README.md
|
||||||
|
$(ZIP) -r $@ $^
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(HANDIN)
|
13
assignment-2a/README.md
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# Assignment 2A
|
||||||
|
|
||||||
|
Compiles but does not run on CSE labs machines due to OpenGL 3.2 missing.
|
||||||
|
|
||||||
|
Try with `examples/test.obj`, run the program with
|
||||||
|
|
||||||
|
cmake -B build
|
||||||
|
make -C build
|
||||||
|
./build/HW2a examples/test.obj
|
||||||
|
|
||||||
|
This test has a few triangles in it. Other obj files _should_ work in theory
|
||||||
|
|
||||||
|
![](examples/test.png)
|
1
assignment-2a/compile_commands.json
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
build/compile_commands.json
|
26
assignment-2a/default.nix
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{ stdenv, cmake, ninja, libglvnd, libGLU, xorg, spdlog }:
|
||||||
|
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
name = "assignment-2a";
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
nativeBuildInputs = [ cmake ninja ];
|
||||||
|
buildInputs = [
|
||||||
|
libglvnd
|
||||||
|
libGLU
|
||||||
|
xorg.libX11
|
||||||
|
xorg.libXcursor
|
||||||
|
xorg.libXext
|
||||||
|
xorg.libXi
|
||||||
|
xorg.libXinerama
|
||||||
|
xorg.libXrandr
|
||||||
|
xorg.libXrender
|
||||||
|
spdlog
|
||||||
|
];
|
||||||
|
|
||||||
|
preBuild = ''
|
||||||
|
env
|
||||||
|
'';
|
||||||
|
|
||||||
|
cmakeFlags = [ "-DCMAKE_CURRENT_SOURCE_DIR=${./.}" ];
|
||||||
|
}
|
11
assignment-2a/examples/test.obj
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
v 2 3 0
|
||||||
|
v 1.5 4 0
|
||||||
|
v 3 2 0
|
||||||
|
|
||||||
|
v 1.5 4 0
|
||||||
|
v 3 2 0
|
||||||
|
v 5 3.4 0
|
||||||
|
|
||||||
|
v 3 2 0
|
||||||
|
v 5 3.4 0
|
||||||
|
v 6 5.9 0
|
BIN
assignment-2a/examples/test.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
assignment-2a/ext/.DS_Store
vendored
Normal file
BIN
assignment-2a/ext/glad/.DS_Store
vendored
Normal file
290
assignment-2a/ext/glad/include/KHR/khrplatform.h
Executable file
|
@ -0,0 +1,290 @@
|
||||||
|
#ifndef __khrplatform_h_
|
||||||
|
#define __khrplatform_h_
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copyright (c) 2008-2018 The Khronos Group Inc.
|
||||||
|
**
|
||||||
|
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
** copy of this software and/or associated documentation files (the
|
||||||
|
** "Materials"), to deal in the Materials without restriction, including
|
||||||
|
** without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||||
|
** permit persons to whom the Materials are furnished to do so, subject to
|
||||||
|
** the following conditions:
|
||||||
|
**
|
||||||
|
** The above copyright notice and this permission notice shall be included
|
||||||
|
** in all copies or substantial portions of the Materials.
|
||||||
|
**
|
||||||
|
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Khronos platform-specific types and definitions.
|
||||||
|
*
|
||||||
|
* The master copy of khrplatform.h is maintained in the Khronos EGL
|
||||||
|
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
|
||||||
|
* The last semantic modification to khrplatform.h was at commit ID:
|
||||||
|
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
|
||||||
|
*
|
||||||
|
* Adopters may modify this file to suit their platform. Adopters are
|
||||||
|
* encouraged to submit platform specific modifications to the Khronos
|
||||||
|
* group so that they can be included in future versions of this file.
|
||||||
|
* Please submit changes by filing pull requests or issues on
|
||||||
|
* the EGL Registry repository linked above.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* See the Implementer's Guidelines for information about where this file
|
||||||
|
* should be located on your system and for more details of its use:
|
||||||
|
* http://www.khronos.org/registry/implementers_guide.pdf
|
||||||
|
*
|
||||||
|
* This file should be included as
|
||||||
|
* #include <KHR/khrplatform.h>
|
||||||
|
* by Khronos client API header files that use its types and defines.
|
||||||
|
*
|
||||||
|
* The types in khrplatform.h should only be used to define API-specific types.
|
||||||
|
*
|
||||||
|
* Types defined in khrplatform.h:
|
||||||
|
* khronos_int8_t signed 8 bit
|
||||||
|
* khronos_uint8_t unsigned 8 bit
|
||||||
|
* khronos_int16_t signed 16 bit
|
||||||
|
* khronos_uint16_t unsigned 16 bit
|
||||||
|
* khronos_int32_t signed 32 bit
|
||||||
|
* khronos_uint32_t unsigned 32 bit
|
||||||
|
* khronos_int64_t signed 64 bit
|
||||||
|
* khronos_uint64_t unsigned 64 bit
|
||||||
|
* khronos_intptr_t signed same number of bits as a pointer
|
||||||
|
* khronos_uintptr_t unsigned same number of bits as a pointer
|
||||||
|
* khronos_ssize_t signed size
|
||||||
|
* khronos_usize_t unsigned size
|
||||||
|
* khronos_float_t signed 32 bit floating point
|
||||||
|
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
|
||||||
|
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
|
||||||
|
* nanoseconds
|
||||||
|
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
|
||||||
|
* khronos_boolean_enum_t enumerated boolean type. This should
|
||||||
|
* only be used as a base type when a client API's boolean type is
|
||||||
|
* an enum. Client APIs which use an integer or other type for
|
||||||
|
* booleans cannot use this as the base type for their boolean.
|
||||||
|
*
|
||||||
|
* Tokens defined in khrplatform.h:
|
||||||
|
*
|
||||||
|
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
|
||||||
|
*
|
||||||
|
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
|
||||||
|
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
|
||||||
|
*
|
||||||
|
* Calling convention macros defined in this file:
|
||||||
|
* KHRONOS_APICALL
|
||||||
|
* KHRONOS_APIENTRY
|
||||||
|
* KHRONOS_APIATTRIBUTES
|
||||||
|
*
|
||||||
|
* These may be used in function prototypes as:
|
||||||
|
*
|
||||||
|
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
|
||||||
|
* int arg1,
|
||||||
|
* int arg2) KHRONOS_APIATTRIBUTES;
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
|
||||||
|
# define KHRONOS_STATIC 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* Definition of KHRONOS_APICALL
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
* This precedes the return type of the function in the function prototype.
|
||||||
|
*/
|
||||||
|
#if defined(KHRONOS_STATIC)
|
||||||
|
/* If the preprocessor constant KHRONOS_STATIC is defined, make the
|
||||||
|
* header compatible with static linking. */
|
||||||
|
# define KHRONOS_APICALL
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
# define KHRONOS_APICALL __declspec(dllimport)
|
||||||
|
#elif defined (__SYMBIAN32__)
|
||||||
|
# define KHRONOS_APICALL IMPORT_C
|
||||||
|
#elif defined(__ANDROID__)
|
||||||
|
# define KHRONOS_APICALL __attribute__((visibility("default")))
|
||||||
|
#else
|
||||||
|
# define KHRONOS_APICALL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* Definition of KHRONOS_APIENTRY
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
* This follows the return type of the function and precedes the function
|
||||||
|
* name in the function prototype.
|
||||||
|
*/
|
||||||
|
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(KHRONOS_STATIC)
|
||||||
|
/* Win32 but not WinCE */
|
||||||
|
# define KHRONOS_APIENTRY __stdcall
|
||||||
|
#else
|
||||||
|
# define KHRONOS_APIENTRY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* Definition of KHRONOS_APIATTRIBUTES
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
* This follows the closing parenthesis of the function prototype arguments.
|
||||||
|
*/
|
||||||
|
#if defined (__ARMCC_2__)
|
||||||
|
#define KHRONOS_APIATTRIBUTES __softfp
|
||||||
|
#else
|
||||||
|
#define KHRONOS_APIATTRIBUTES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* basic type definitions
|
||||||
|
*-----------------------------------------------------------------------*/
|
||||||
|
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Using <stdint.h>
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
typedef int32_t khronos_int32_t;
|
||||||
|
typedef uint32_t khronos_uint32_t;
|
||||||
|
typedef int64_t khronos_int64_t;
|
||||||
|
typedef uint64_t khronos_uint64_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
|
||||||
|
#elif defined(__VMS ) || defined(__sgi)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Using <inttypes.h>
|
||||||
|
*/
|
||||||
|
#include <inttypes.h>
|
||||||
|
typedef int32_t khronos_int32_t;
|
||||||
|
typedef uint32_t khronos_uint32_t;
|
||||||
|
typedef int64_t khronos_int64_t;
|
||||||
|
typedef uint64_t khronos_uint64_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
|
||||||
|
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Win32
|
||||||
|
*/
|
||||||
|
typedef __int32 khronos_int32_t;
|
||||||
|
typedef unsigned __int32 khronos_uint32_t;
|
||||||
|
typedef __int64 khronos_int64_t;
|
||||||
|
typedef unsigned __int64 khronos_uint64_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
|
||||||
|
#elif defined(__sun__) || defined(__digital__)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sun or Digital
|
||||||
|
*/
|
||||||
|
typedef int khronos_int32_t;
|
||||||
|
typedef unsigned int khronos_uint32_t;
|
||||||
|
#if defined(__arch64__) || defined(_LP64)
|
||||||
|
typedef long int khronos_int64_t;
|
||||||
|
typedef unsigned long int khronos_uint64_t;
|
||||||
|
#else
|
||||||
|
typedef long long int khronos_int64_t;
|
||||||
|
typedef unsigned long long int khronos_uint64_t;
|
||||||
|
#endif /* __arch64__ */
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
|
||||||
|
#elif 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hypothetical platform with no float or int64 support
|
||||||
|
*/
|
||||||
|
typedef int khronos_int32_t;
|
||||||
|
typedef unsigned int khronos_uint32_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 0
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 0
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generic fallback
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
typedef int32_t khronos_int32_t;
|
||||||
|
typedef uint32_t khronos_uint32_t;
|
||||||
|
typedef int64_t khronos_int64_t;
|
||||||
|
typedef uint64_t khronos_uint64_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Types that are (so far) the same on all platforms
|
||||||
|
*/
|
||||||
|
typedef signed char khronos_int8_t;
|
||||||
|
typedef unsigned char khronos_uint8_t;
|
||||||
|
typedef signed short int khronos_int16_t;
|
||||||
|
typedef unsigned short int khronos_uint16_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Types that differ between LLP64 and LP64 architectures - in LLP64,
|
||||||
|
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
|
||||||
|
* to be the only LLP64 architecture in current use.
|
||||||
|
*/
|
||||||
|
#ifdef _WIN64
|
||||||
|
typedef signed long long int khronos_intptr_t;
|
||||||
|
typedef unsigned long long int khronos_uintptr_t;
|
||||||
|
typedef signed long long int khronos_ssize_t;
|
||||||
|
typedef unsigned long long int khronos_usize_t;
|
||||||
|
#else
|
||||||
|
typedef signed long int khronos_intptr_t;
|
||||||
|
typedef unsigned long int khronos_uintptr_t;
|
||||||
|
typedef signed long int khronos_ssize_t;
|
||||||
|
typedef unsigned long int khronos_usize_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if KHRONOS_SUPPORT_FLOAT
|
||||||
|
/*
|
||||||
|
* Float type
|
||||||
|
*/
|
||||||
|
typedef float khronos_float_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if KHRONOS_SUPPORT_INT64
|
||||||
|
/* Time types
|
||||||
|
*
|
||||||
|
* These types can be used to represent a time interval in nanoseconds or
|
||||||
|
* an absolute Unadjusted System Time. Unadjusted System Time is the number
|
||||||
|
* of nanoseconds since some arbitrary system event (e.g. since the last
|
||||||
|
* time the system booted). The Unadjusted System Time is an unsigned
|
||||||
|
* 64 bit value that wraps back to 0 every 584 years. Time intervals
|
||||||
|
* may be either signed or unsigned.
|
||||||
|
*/
|
||||||
|
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
|
||||||
|
typedef khronos_int64_t khronos_stime_nanoseconds_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dummy value used to pad enum types to 32 bits.
|
||||||
|
*/
|
||||||
|
#ifndef KHRONOS_MAX_ENUM
|
||||||
|
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enumerated boolean type
|
||||||
|
*
|
||||||
|
* Values other than zero should be considered to be true. Therefore
|
||||||
|
* comparisons should not be made against KHRONOS_TRUE.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
KHRONOS_FALSE = 0,
|
||||||
|
KHRONOS_TRUE = 1,
|
||||||
|
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
|
||||||
|
} khronos_boolean_enum_t;
|
||||||
|
|
||||||
|
#endif /* __khrplatform_h_ */
|
3292
assignment-2a/ext/glad/include/glad/glad.h
Executable file
1674
assignment-2a/ext/glad/src/glad.c
Executable file
65
assignment-2a/ext/glfw/.appveyor.yml
Executable file
|
@ -0,0 +1,65 @@
|
||||||
|
image:
|
||||||
|
- Visual Studio 2015
|
||||||
|
- Visual Studio 2019
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- ci
|
||||||
|
- master
|
||||||
|
- 3.3-stable
|
||||||
|
skip_tags: true
|
||||||
|
skip_commits:
|
||||||
|
files:
|
||||||
|
- README.md
|
||||||
|
- LICENSE.md
|
||||||
|
- docs/*
|
||||||
|
environment:
|
||||||
|
matrix:
|
||||||
|
- GENERATOR: MinGW Makefiles
|
||||||
|
BUILD_SHARED_LIBS: ON
|
||||||
|
CFLAGS: -Werror
|
||||||
|
- GENERATOR: MinGW Makefiles
|
||||||
|
BUILD_SHARED_LIBS: OFF
|
||||||
|
CFLAGS: -Werror
|
||||||
|
- GENERATOR: Visual Studio 10 2010
|
||||||
|
BUILD_SHARED_LIBS: ON
|
||||||
|
CFLAGS: /WX
|
||||||
|
- GENERATOR: Visual Studio 10 2010
|
||||||
|
BUILD_SHARED_LIBS: OFF
|
||||||
|
CFLAGS: /WX
|
||||||
|
- GENERATOR: Visual Studio 16 2019
|
||||||
|
BUILD_SHARED_LIBS: ON
|
||||||
|
CFLAGS: /WX
|
||||||
|
- GENERATOR: Visual Studio 16 2019
|
||||||
|
BUILD_SHARED_LIBS: OFF
|
||||||
|
CFLAGS: /WX
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
exclude:
|
||||||
|
- image: Visual Studio 2015
|
||||||
|
GENERATOR: Visual Studio 16 2019
|
||||||
|
- image: Visual Studio 2019
|
||||||
|
GENERATOR: Visual Studio 10 2010
|
||||||
|
- image: Visual Studio 2019
|
||||||
|
GENERATOR: MinGW Makefiles
|
||||||
|
for:
|
||||||
|
-
|
||||||
|
matrix:
|
||||||
|
except:
|
||||||
|
- GENERATOR: Visual Studio 10 2010
|
||||||
|
build_script:
|
||||||
|
- set PATH=%PATH:C:\Program Files\Git\usr\bin=C:\MinGW\bin%
|
||||||
|
- cmake -S . -B build -G "%GENERATOR%" -DBUILD_SHARED_LIBS=%BUILD_SHARED_LIBS%
|
||||||
|
- cmake --build build
|
||||||
|
-
|
||||||
|
matrix:
|
||||||
|
only:
|
||||||
|
- GENERATOR: Visual Studio 10 2010
|
||||||
|
build_script:
|
||||||
|
- cmake -S . -B build -G "%GENERATOR%" -DBUILD_SHARED_LIBS=%BUILD_SHARED_LIBS%
|
||||||
|
- cmake --build build --target glfw
|
||||||
|
notifications:
|
||||||
|
- provider: Email
|
||||||
|
to:
|
||||||
|
- ci@glfw.org
|
||||||
|
on_build_failure: true
|
||||||
|
on_build_success: false
|
5
assignment-2a/ext/glfw/.gitattributes
vendored
Executable file
|
@ -0,0 +1,5 @@
|
||||||
|
*.m linguist-language=Objective-C
|
||||||
|
.gitignore export-ignore
|
||||||
|
.gitattributes export-ignore
|
||||||
|
.travis.yml export-ignore
|
||||||
|
.appveyor.yml export-ignore
|
85
assignment-2a/ext/glfw/.gitignore
vendored
Executable file
|
@ -0,0 +1,85 @@
|
||||||
|
# External junk
|
||||||
|
.DS_Store
|
||||||
|
_ReSharper*
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.suo
|
||||||
|
*.dir
|
||||||
|
*.vcxproj*
|
||||||
|
*.sln
|
||||||
|
.vs/
|
||||||
|
Win32
|
||||||
|
x64
|
||||||
|
Debug
|
||||||
|
Release
|
||||||
|
MinSizeRel
|
||||||
|
RelWithDebInfo
|
||||||
|
*.xcodeproj
|
||||||
|
|
||||||
|
# CMake files
|
||||||
|
Makefile
|
||||||
|
CMakeCache.txt
|
||||||
|
CMakeFiles
|
||||||
|
CMakeScripts
|
||||||
|
cmake_install.cmake
|
||||||
|
cmake_uninstall.cmake
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
docs/Doxyfile
|
||||||
|
docs/html
|
||||||
|
docs/warnings.txt
|
||||||
|
docs/doxygen_sqlite3.db
|
||||||
|
src/glfw_config.h
|
||||||
|
src/glfw3.pc
|
||||||
|
src/glfw3Config.cmake
|
||||||
|
src/glfw3ConfigVersion.cmake
|
||||||
|
src/wayland-pointer-constraints-unstable-v1-client-protocol.h
|
||||||
|
src/wayland-pointer-constraints-unstable-v1-protocol.c
|
||||||
|
src/wayland-relative-pointer-unstable-v1-client-protocol.h
|
||||||
|
src/wayland-relative-pointer-unstable-v1-protocol.c
|
||||||
|
|
||||||
|
# Compiled binaries
|
||||||
|
src/libglfw.so
|
||||||
|
src/libglfw.so.3
|
||||||
|
src/libglfw.so.3.4
|
||||||
|
src/libglfw.dylib
|
||||||
|
src/libglfw.dylib
|
||||||
|
src/libglfw.3.dylib
|
||||||
|
src/libglfw.3.4.dylib
|
||||||
|
src/libglfw3.a
|
||||||
|
src/glfw3.lib
|
||||||
|
src/glfw3.dll
|
||||||
|
src/glfw3dll.lib
|
||||||
|
src/libglfw3dll.a
|
||||||
|
examples/*.app
|
||||||
|
examples/*.exe
|
||||||
|
examples/boing
|
||||||
|
examples/gears
|
||||||
|
examples/heightmap
|
||||||
|
examples/offscreen
|
||||||
|
examples/particles
|
||||||
|
examples/splitview
|
||||||
|
examples/sharing
|
||||||
|
examples/triangle-opengl
|
||||||
|
examples/wave
|
||||||
|
tests/*.app
|
||||||
|
tests/*.exe
|
||||||
|
tests/clipboard
|
||||||
|
tests/cursor
|
||||||
|
tests/empty
|
||||||
|
tests/events
|
||||||
|
tests/gamma
|
||||||
|
tests/glfwinfo
|
||||||
|
tests/icon
|
||||||
|
tests/iconify
|
||||||
|
tests/joysticks
|
||||||
|
tests/monitors
|
||||||
|
tests/msaa
|
||||||
|
tests/reopen
|
||||||
|
tests/tearing
|
||||||
|
tests/threads
|
||||||
|
tests/timeout
|
||||||
|
tests/title
|
||||||
|
tests/triangle-vulkan
|
||||||
|
tests/windows
|
||||||
|
|
104
assignment-2a/ext/glfw/.travis.yml
Executable file
|
@ -0,0 +1,104 @@
|
||||||
|
language: c
|
||||||
|
compiler: clang
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- ci
|
||||||
|
- master
|
||||||
|
- 3.3-stable
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: linux
|
||||||
|
dist: xenial
|
||||||
|
sudo: false
|
||||||
|
name: "X11 shared library"
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- libxrandr-dev
|
||||||
|
- libxinerama-dev
|
||||||
|
- libxcursor-dev
|
||||||
|
- libxi-dev
|
||||||
|
env:
|
||||||
|
- BUILD_SHARED_LIBS=ON
|
||||||
|
- CFLAGS=-Werror
|
||||||
|
- os: linux
|
||||||
|
dist: xenial
|
||||||
|
sudo: false
|
||||||
|
name: "X11 static library"
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- libxrandr-dev
|
||||||
|
- libxinerama-dev
|
||||||
|
- libxcursor-dev
|
||||||
|
- libxi-dev
|
||||||
|
env:
|
||||||
|
- BUILD_SHARED_LIBS=OFF
|
||||||
|
- CFLAGS=-Werror
|
||||||
|
- os: linux
|
||||||
|
dist: xenial
|
||||||
|
sudo: required
|
||||||
|
name: "Wayland shared library"
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- ppa:kubuntu-ppa/backports
|
||||||
|
packages:
|
||||||
|
- extra-cmake-modules
|
||||||
|
- libwayland-dev
|
||||||
|
- libxkbcommon-dev
|
||||||
|
- libegl1-mesa-dev
|
||||||
|
env:
|
||||||
|
- USE_WAYLAND=ON
|
||||||
|
- BUILD_SHARED_LIBS=ON
|
||||||
|
- CFLAGS=-Werror
|
||||||
|
- os: linux
|
||||||
|
dist: xenial
|
||||||
|
sudo: required
|
||||||
|
name: "Wayland static library"
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- ppa:kubuntu-ppa/backports
|
||||||
|
packages:
|
||||||
|
- extra-cmake-modules
|
||||||
|
- libwayland-dev
|
||||||
|
- libxkbcommon-dev
|
||||||
|
- libegl1-mesa-dev
|
||||||
|
env:
|
||||||
|
- USE_WAYLAND=ON
|
||||||
|
- BUILD_SHARED_LIBS=OFF
|
||||||
|
- CFLAGS=-Werror
|
||||||
|
- os: osx
|
||||||
|
sudo: false
|
||||||
|
name: "Cocoa shared library"
|
||||||
|
env:
|
||||||
|
- BUILD_SHARED_LIBS=ON
|
||||||
|
- CFLAGS=-Werror
|
||||||
|
- os: osx
|
||||||
|
sudo: false
|
||||||
|
name: "Cocoa static library"
|
||||||
|
env:
|
||||||
|
- BUILD_SHARED_LIBS=OFF
|
||||||
|
- CFLAGS=-Werror
|
||||||
|
script:
|
||||||
|
- if grep -Inr '\s$' src include docs tests examples CMake *.md .gitattributes .gitignore; then
|
||||||
|
echo Trailing whitespace found, aborting;
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- if test -n "${USE_WAYLAND}"; then
|
||||||
|
git clone git://anongit.freedesktop.org/wayland/wayland-protocols;
|
||||||
|
pushd wayland-protocols;
|
||||||
|
git checkout 1.15 && ./autogen.sh --prefix=/usr && make && sudo make install;
|
||||||
|
popd;
|
||||||
|
fi
|
||||||
|
- cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} -DGLFW_USE_WAYLAND=${USE_WAYLAND} ..
|
||||||
|
- cmake --build .
|
||||||
|
notifications:
|
||||||
|
email:
|
||||||
|
recipients:
|
||||||
|
- ci@glfw.org
|
||||||
|
on_success: never
|
||||||
|
on_failure: always
|
33
assignment-2a/ext/glfw/CMake/GenerateMappings.cmake
Executable file
|
@ -0,0 +1,33 @@
|
||||||
|
# Usage:
|
||||||
|
# cmake -P GenerateMappings.cmake <path/to/mappings.h.in> <path/to/mappings.h>
|
||||||
|
|
||||||
|
set(source_url "https://raw.githubusercontent.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb.txt")
|
||||||
|
set(source_path "${CMAKE_CURRENT_BINARY_DIR}/gamecontrollerdb.txt")
|
||||||
|
set(template_path "${CMAKE_ARGV3}")
|
||||||
|
set(target_path "${CMAKE_ARGV4}")
|
||||||
|
|
||||||
|
if (NOT EXISTS "${template_path}")
|
||||||
|
message(FATAL_ERROR "Failed to find template file ${template_path}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(DOWNLOAD "${source_url}" "${source_path}"
|
||||||
|
STATUS download_status
|
||||||
|
TLS_VERIFY on)
|
||||||
|
|
||||||
|
list(GET download_status 0 status_code)
|
||||||
|
list(GET download_status 1 status_message)
|
||||||
|
|
||||||
|
if (status_code)
|
||||||
|
message(FATAL_ERROR "Failed to download ${source_url}: ${status_message}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(STRINGS "${source_path}" lines)
|
||||||
|
foreach(line ${lines})
|
||||||
|
if ("${line}" MATCHES "^[0-9a-fA-F].*$")
|
||||||
|
set(GLFW_GAMEPAD_MAPPINGS "${GLFW_GAMEPAD_MAPPINGS}\"${line}\",\n")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
configure_file("${template_path}" "${target_path}" @ONLY NEWLINE_STYLE UNIX)
|
||||||
|
file(REMOVE "${source_path}")
|
||||||
|
|
38
assignment-2a/ext/glfw/CMake/MacOSXBundleInfo.plist.in
Executable file
|
@ -0,0 +1,38 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>English</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
|
||||||
|
<key>CFBundleGetInfoString</key>
|
||||||
|
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
|
||||||
|
<key>CFBundleIconFile</key>
|
||||||
|
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleLongVersionString</key>
|
||||||
|
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
|
||||||
|
<key>CSResourcesFileMapped</key>
|
||||||
|
<true/>
|
||||||
|
<key>LSRequiresCarbon</key>
|
||||||
|
<true/>
|
||||||
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
|
||||||
|
<key>NSHighResolutionCapable</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
13
assignment-2a/ext/glfw/CMake/i686-w64-mingw32-clang.cmake
Executable file
|
@ -0,0 +1,13 @@
|
||||||
|
# Define the environment for cross-compiling with 32-bit MinGW-w64 Clang
|
||||||
|
SET(CMAKE_SYSTEM_NAME Windows) # Target system name
|
||||||
|
SET(CMAKE_SYSTEM_VERSION 1)
|
||||||
|
SET(CMAKE_C_COMPILER "i686-w64-mingw32-clang")
|
||||||
|
SET(CMAKE_CXX_COMPILER "i686-w64-mingw32-clang++")
|
||||||
|
SET(CMAKE_RC_COMPILER "i686-w64-mingw32-windres")
|
||||||
|
SET(CMAKE_RANLIB "i686-w64-mingw32-ranlib")
|
||||||
|
|
||||||
|
# Configure the behaviour of the find commands
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH "/usr/i686-w64-mingw32")
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
13
assignment-2a/ext/glfw/CMake/i686-w64-mingw32.cmake
Executable file
|
@ -0,0 +1,13 @@
|
||||||
|
# Define the environment for cross-compiling with 32-bit MinGW-w64 GCC
|
||||||
|
SET(CMAKE_SYSTEM_NAME Windows) # Target system name
|
||||||
|
SET(CMAKE_SYSTEM_VERSION 1)
|
||||||
|
SET(CMAKE_C_COMPILER "i686-w64-mingw32-gcc")
|
||||||
|
SET(CMAKE_CXX_COMPILER "i686-w64-mingw32-g++")
|
||||||
|
SET(CMAKE_RC_COMPILER "i686-w64-mingw32-windres")
|
||||||
|
SET(CMAKE_RANLIB "i686-w64-mingw32-ranlib")
|
||||||
|
|
||||||
|
# Configure the behaviour of the find commands
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH "/usr/i686-w64-mingw32")
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
17
assignment-2a/ext/glfw/CMake/modules/FindEpollShim.cmake
Executable file
|
@ -0,0 +1,17 @@
|
||||||
|
# Find EpollShim
|
||||||
|
# Once done, this will define
|
||||||
|
#
|
||||||
|
# EPOLLSHIM_FOUND - System has EpollShim
|
||||||
|
# EPOLLSHIM_INCLUDE_DIRS - The EpollShim include directories
|
||||||
|
# EPOLLSHIM_LIBRARIES - The libraries needed to use EpollShim
|
||||||
|
|
||||||
|
find_path(EPOLLSHIM_INCLUDE_DIRS NAMES sys/epoll.h sys/timerfd.h HINTS /usr/local/include/libepoll-shim)
|
||||||
|
find_library(EPOLLSHIM_LIBRARIES NAMES epoll-shim libepoll-shim HINTS /usr/local/lib)
|
||||||
|
|
||||||
|
if (EPOLLSHIM_INCLUDE_DIRS AND EPOLLSHIM_LIBRARIES)
|
||||||
|
set(EPOLLSHIM_FOUND TRUE)
|
||||||
|
endif (EPOLLSHIM_INCLUDE_DIRS AND EPOLLSHIM_LIBRARIES)
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(EPOLLSHIM DEFAULT_MSG EPOLLSHIM_LIBRARIES EPOLLSHIM_INCLUDE_DIRS)
|
||||||
|
mark_as_advanced(EPOLLSHIM_INCLUDE_DIRS EPOLLSHIM_LIBRARIES)
|
18
assignment-2a/ext/glfw/CMake/modules/FindOSMesa.cmake
Executable file
|
@ -0,0 +1,18 @@
|
||||||
|
# Try to find OSMesa on a Unix system
|
||||||
|
#
|
||||||
|
# This will define:
|
||||||
|
#
|
||||||
|
# OSMESA_LIBRARIES - Link these to use OSMesa
|
||||||
|
# OSMESA_INCLUDE_DIR - Include directory for OSMesa
|
||||||
|
#
|
||||||
|
# Copyright (c) 2014 Brandon Schaefer <brandon.schaefer@canonical.com>
|
||||||
|
|
||||||
|
if (NOT WIN32)
|
||||||
|
|
||||||
|
find_package (PkgConfig)
|
||||||
|
pkg_check_modules (PKG_OSMESA QUIET osmesa)
|
||||||
|
|
||||||
|
set (OSMESA_INCLUDE_DIR ${PKG_OSMESA_INCLUDE_DIRS})
|
||||||
|
set (OSMESA_LIBRARIES ${PKG_OSMESA_LIBRARIES})
|
||||||
|
|
||||||
|
endif ()
|
26
assignment-2a/ext/glfw/CMake/modules/FindWaylandProtocols.cmake
Executable file
|
@ -0,0 +1,26 @@
|
||||||
|
find_package(PkgConfig)
|
||||||
|
|
||||||
|
pkg_check_modules(WaylandProtocols QUIET wayland-protocols>=${WaylandProtocols_FIND_VERSION})
|
||||||
|
|
||||||
|
execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=pkgdatadir wayland-protocols
|
||||||
|
OUTPUT_VARIABLE WaylandProtocols_PKGDATADIR
|
||||||
|
RESULT_VARIABLE _pkgconfig_failed)
|
||||||
|
if (_pkgconfig_failed)
|
||||||
|
message(FATAL_ERROR "Missing wayland-protocols pkgdatadir")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(REGEX REPLACE "[\r\n]" "" WaylandProtocols_PKGDATADIR "${WaylandProtocols_PKGDATADIR}")
|
||||||
|
|
||||||
|
find_package_handle_standard_args(WaylandProtocols
|
||||||
|
FOUND_VAR
|
||||||
|
WaylandProtocols_FOUND
|
||||||
|
REQUIRED_VARS
|
||||||
|
WaylandProtocols_PKGDATADIR
|
||||||
|
VERSION_VAR
|
||||||
|
WaylandProtocols_VERSION
|
||||||
|
HANDLE_COMPONENTS
|
||||||
|
)
|
||||||
|
|
||||||
|
set(WAYLAND_PROTOCOLS_FOUND ${WaylandProtocols_FOUND})
|
||||||
|
set(WAYLAND_PROTOCOLS_PKGDATADIR ${WaylandProtocols_PKGDATADIR})
|
||||||
|
set(WAYLAND_PROTOCOLS_VERSION ${WaylandProtocols_VERSION})
|
34
assignment-2a/ext/glfw/CMake/modules/FindXKBCommon.cmake
Executable file
|
@ -0,0 +1,34 @@
|
||||||
|
# - Try to find XKBCommon
|
||||||
|
# Once done, this will define
|
||||||
|
#
|
||||||
|
# XKBCOMMON_FOUND - System has XKBCommon
|
||||||
|
# XKBCOMMON_INCLUDE_DIRS - The XKBCommon include directories
|
||||||
|
# XKBCOMMON_LIBRARIES - The libraries needed to use XKBCommon
|
||||||
|
# XKBCOMMON_DEFINITIONS - Compiler switches required for using XKBCommon
|
||||||
|
|
||||||
|
find_package(PkgConfig)
|
||||||
|
pkg_check_modules(PC_XKBCOMMON QUIET xkbcommon)
|
||||||
|
set(XKBCOMMON_DEFINITIONS ${PC_XKBCOMMON_CFLAGS_OTHER})
|
||||||
|
|
||||||
|
find_path(XKBCOMMON_INCLUDE_DIR
|
||||||
|
NAMES xkbcommon/xkbcommon.h
|
||||||
|
HINTS ${PC_XKBCOMMON_INCLUDE_DIR} ${PC_XKBCOMMON_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
find_library(XKBCOMMON_LIBRARY
|
||||||
|
NAMES xkbcommon
|
||||||
|
HINTS ${PC_XKBCOMMON_LIBRARY} ${PC_XKBCOMMON_LIBRARY_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
set(XKBCOMMON_LIBRARIES ${XKBCOMMON_LIBRARY})
|
||||||
|
set(XKBCOMMON_LIBRARY_DIRS ${XKBCOMMON_LIBRARY_DIRS})
|
||||||
|
set(XKBCOMMON_INCLUDE_DIRS ${XKBCOMMON_INCLUDE_DIR})
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(XKBCommon DEFAULT_MSG
|
||||||
|
XKBCOMMON_LIBRARY
|
||||||
|
XKBCOMMON_INCLUDE_DIR
|
||||||
|
)
|
||||||
|
|
||||||
|
mark_as_advanced(XKBCOMMON_LIBRARY XKBCOMMON_INCLUDE_DIR)
|
||||||
|
|
13
assignment-2a/ext/glfw/CMake/x86_64-w64-mingw32-clang.cmake
Executable file
|
@ -0,0 +1,13 @@
|
||||||
|
# Define the environment for cross-compiling with 64-bit MinGW-w64 Clang
|
||||||
|
SET(CMAKE_SYSTEM_NAME Windows) # Target system name
|
||||||
|
SET(CMAKE_SYSTEM_VERSION 1)
|
||||||
|
SET(CMAKE_C_COMPILER "x86_64-w64-mingw32-clang")
|
||||||
|
SET(CMAKE_CXX_COMPILER "x86_64-w64-mingw32-clang++")
|
||||||
|
SET(CMAKE_RC_COMPILER "x86_64-w64-mingw32-windres")
|
||||||
|
SET(CMAKE_RANLIB "x86_64-w64-mingw32-ranlib")
|
||||||
|
|
||||||
|
# Configure the behaviour of the find commands
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH "/usr/x86_64-w64-mingw32")
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
13
assignment-2a/ext/glfw/CMake/x86_64-w64-mingw32.cmake
Executable file
|
@ -0,0 +1,13 @@
|
||||||
|
# Define the environment for cross-compiling with 64-bit MinGW-w64 GCC
|
||||||
|
SET(CMAKE_SYSTEM_NAME Windows) # Target system name
|
||||||
|
SET(CMAKE_SYSTEM_VERSION 1)
|
||||||
|
SET(CMAKE_C_COMPILER "x86_64-w64-mingw32-gcc")
|
||||||
|
SET(CMAKE_CXX_COMPILER "x86_64-w64-mingw32-g++")
|
||||||
|
SET(CMAKE_RC_COMPILER "x86_64-w64-mingw32-windres")
|
||||||
|
SET(CMAKE_RANLIB "x86_64-w64-mingw32-ranlib")
|
||||||
|
|
||||||
|
# Configure the behaviour of the find commands
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH "/usr/x86_64-w64-mingw32")
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
379
assignment-2a/ext/glfw/CMakeLists.txt
Executable file
|
@ -0,0 +1,379 @@
|
||||||
|
cmake_minimum_required(VERSION 3.0)
|
||||||
|
|
||||||
|
project(GLFW VERSION 3.4.0 LANGUAGES C)
|
||||||
|
|
||||||
|
set(CMAKE_LEGACY_CYGWIN_WIN32 OFF)
|
||||||
|
|
||||||
|
if (POLICY CMP0054)
|
||||||
|
cmake_policy(SET CMP0054 NEW)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (POLICY CMP0077)
|
||||||
|
cmake_policy(SET CMP0077 NEW)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||||
|
|
||||||
|
if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
|
set(GLFW_STANDALONE TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
|
||||||
|
option(GLFW_BUILD_EXAMPLES "Build the GLFW example programs" ${GLFW_STANDALONE})
|
||||||
|
option(GLFW_BUILD_TESTS "Build the GLFW test programs" ${GLFW_STANDALONE})
|
||||||
|
option(GLFW_BUILD_DOCS "Build the GLFW documentation" ON)
|
||||||
|
option(GLFW_INSTALL "Generate installation target" ON)
|
||||||
|
option(GLFW_VULKAN_STATIC "Assume the Vulkan loader is linked with the application" OFF)
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
include(CMakeDependentOption)
|
||||||
|
|
||||||
|
cmake_dependent_option(GLFW_USE_OSMESA "Use OSMesa for offscreen context creation" OFF
|
||||||
|
"UNIX" OFF)
|
||||||
|
cmake_dependent_option(GLFW_USE_HYBRID_HPG "Force use of high-performance GPU on hybrid systems" OFF
|
||||||
|
"WIN32" OFF)
|
||||||
|
cmake_dependent_option(GLFW_USE_WAYLAND "Use Wayland for window creation" OFF
|
||||||
|
"UNIX;NOT APPLE" OFF)
|
||||||
|
cmake_dependent_option(USE_MSVC_RUNTIME_LIBRARY_DLL "Use MSVC runtime library DLL" ON
|
||||||
|
"MSVC" OFF)
|
||||||
|
|
||||||
|
if (BUILD_SHARED_LIBS)
|
||||||
|
set(_GLFW_BUILD_DLL 1)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (BUILD_SHARED_LIBS AND UNIX)
|
||||||
|
# On Unix-like systems, shared libraries can use the soname system.
|
||||||
|
set(GLFW_LIB_NAME glfw)
|
||||||
|
else()
|
||||||
|
set(GLFW_LIB_NAME glfw3)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (GLFW_VULKAN_STATIC)
|
||||||
|
if (BUILD_SHARED_LIBS)
|
||||||
|
# If you absolutely must do this, remove this line and add the Vulkan
|
||||||
|
# loader static library via the CMAKE_SHARED_LINKER_FLAGS
|
||||||
|
message(FATAL_ERROR "You are trying to link the Vulkan loader static library into the GLFW shared library")
|
||||||
|
endif()
|
||||||
|
set(_GLFW_VULKAN_STATIC 1)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(APPEND CMAKE_MODULE_PATH "${GLFW_SOURCE_DIR}/CMake/modules")
|
||||||
|
|
||||||
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
|
if (GLFW_BUILD_DOCS)
|
||||||
|
set(DOXYGEN_SKIP_DOT TRUE)
|
||||||
|
find_package(Doxygen)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
# Set compiler specific flags
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
if (MSVC)
|
||||||
|
if (MSVC90)
|
||||||
|
# Workaround for VS 2008 not shipping with the DirectX 9 SDK
|
||||||
|
include(CheckIncludeFile)
|
||||||
|
check_include_file(dinput.h DINPUT_H_FOUND)
|
||||||
|
if (NOT DINPUT_H_FOUND)
|
||||||
|
message(FATAL_ERROR "DirectX 9 SDK not found")
|
||||||
|
endif()
|
||||||
|
# Workaround for VS 2008 not shipping with stdint.h
|
||||||
|
list(APPEND glfw_INCLUDE_DIRS "${GLFW_SOURCE_DIR}/deps/vs2008")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT USE_MSVC_RUNTIME_LIBRARY_DLL)
|
||||||
|
foreach (flag CMAKE_C_FLAGS
|
||||||
|
CMAKE_C_FLAGS_DEBUG
|
||||||
|
CMAKE_C_FLAGS_RELEASE
|
||||||
|
CMAKE_C_FLAGS_MINSIZEREL
|
||||||
|
CMAKE_C_FLAGS_RELWITHDEBINFO)
|
||||||
|
|
||||||
|
if (${flag} MATCHES "/MD")
|
||||||
|
string(REGEX REPLACE "/MD" "/MT" ${flag} "${${flag}}")
|
||||||
|
endif()
|
||||||
|
if (${flag} MATCHES "/MDd")
|
||||||
|
string(REGEX REPLACE "/MDd" "/MTd" ${flag} "${${flag}}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (MINGW)
|
||||||
|
# Workaround for legacy MinGW not providing XInput and DirectInput
|
||||||
|
include(CheckIncludeFile)
|
||||||
|
|
||||||
|
check_include_file(dinput.h DINPUT_H_FOUND)
|
||||||
|
check_include_file(xinput.h XINPUT_H_FOUND)
|
||||||
|
if (NOT DINPUT_H_FOUND OR NOT XINPUT_H_FOUND)
|
||||||
|
list(APPEND glfw_INCLUDE_DIRS "${GLFW_SOURCE_DIR}/deps/mingw")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Enable link-time exploit mitigation features enabled by default on MSVC
|
||||||
|
include(CheckCCompilerFlag)
|
||||||
|
|
||||||
|
# Compatibility with data execution prevention (DEP)
|
||||||
|
set(CMAKE_REQUIRED_FLAGS "-Wl,--nxcompat")
|
||||||
|
check_c_compiler_flag("" _GLFW_HAS_DEP)
|
||||||
|
if (_GLFW_HAS_DEP)
|
||||||
|
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--nxcompat ${CMAKE_SHARED_LINKER_FLAGS}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Compatibility with address space layout randomization (ASLR)
|
||||||
|
set(CMAKE_REQUIRED_FLAGS "-Wl,--dynamicbase")
|
||||||
|
check_c_compiler_flag("" _GLFW_HAS_ASLR)
|
||||||
|
if (_GLFW_HAS_ASLR)
|
||||||
|
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--dynamicbase ${CMAKE_SHARED_LINKER_FLAGS}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Compatibility with 64-bit address space layout randomization (ASLR)
|
||||||
|
set(CMAKE_REQUIRED_FLAGS "-Wl,--high-entropy-va")
|
||||||
|
check_c_compiler_flag("" _GLFW_HAS_64ASLR)
|
||||||
|
if (_GLFW_HAS_64ASLR)
|
||||||
|
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--high-entropy-va ${CMAKE_SHARED_LINKER_FLAGS}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
# Detect and select backend APIs
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
if (GLFW_USE_WAYLAND)
|
||||||
|
set(_GLFW_WAYLAND 1)
|
||||||
|
message(STATUS "Using Wayland for window creation")
|
||||||
|
elseif (GLFW_USE_OSMESA)
|
||||||
|
set(_GLFW_OSMESA 1)
|
||||||
|
message(STATUS "Using OSMesa for headless context creation")
|
||||||
|
elseif (WIN32)
|
||||||
|
set(_GLFW_WIN32 1)
|
||||||
|
message(STATUS "Using Win32 for window creation")
|
||||||
|
elseif (APPLE)
|
||||||
|
set(_GLFW_COCOA 1)
|
||||||
|
message(STATUS "Using Cocoa for window creation")
|
||||||
|
elseif (UNIX)
|
||||||
|
set(_GLFW_X11 1)
|
||||||
|
message(STATUS "Using X11 for window creation")
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "No supported platform was detected")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
# Find and add Unix math and time libraries
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
if (UNIX AND NOT APPLE)
|
||||||
|
find_library(RT_LIBRARY rt)
|
||||||
|
mark_as_advanced(RT_LIBRARY)
|
||||||
|
if (RT_LIBRARY)
|
||||||
|
list(APPEND glfw_LIBRARIES "${RT_LIBRARY}")
|
||||||
|
list(APPEND glfw_PKG_LIBS "-lrt")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_library(MATH_LIBRARY m)
|
||||||
|
mark_as_advanced(MATH_LIBRARY)
|
||||||
|
if (MATH_LIBRARY)
|
||||||
|
list(APPEND glfw_LIBRARIES "${MATH_LIBRARY}")
|
||||||
|
list(APPEND glfw_PKG_LIBS "-lm")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (CMAKE_DL_LIBS)
|
||||||
|
list(APPEND glfw_LIBRARIES "${CMAKE_DL_LIBS}")
|
||||||
|
list(APPEND glfw_PKG_LIBS "-l${CMAKE_DL_LIBS}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
# Use Win32 for window creation
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
if (_GLFW_WIN32)
|
||||||
|
|
||||||
|
list(APPEND glfw_PKG_LIBS "-lgdi32")
|
||||||
|
|
||||||
|
if (GLFW_USE_HYBRID_HPG)
|
||||||
|
set(_GLFW_USE_HYBRID_HPG 1)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
# Use X11 for window creation
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
if (_GLFW_X11)
|
||||||
|
|
||||||
|
find_package(X11 REQUIRED)
|
||||||
|
|
||||||
|
list(APPEND glfw_PKG_DEPS "x11")
|
||||||
|
|
||||||
|
# Set up library and include paths
|
||||||
|
list(APPEND glfw_INCLUDE_DIRS "${X11_X11_INCLUDE_PATH}")
|
||||||
|
list(APPEND glfw_LIBRARIES "${X11_X11_LIB}" "${CMAKE_THREAD_LIBS_INIT}")
|
||||||
|
|
||||||
|
# Check for XRandR (modern resolution switching and gamma control)
|
||||||
|
if (NOT X11_Xrandr_INCLUDE_PATH)
|
||||||
|
message(FATAL_ERROR "The RandR headers were not found")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Check for Xinerama (legacy multi-monitor support)
|
||||||
|
if (NOT X11_Xinerama_INCLUDE_PATH)
|
||||||
|
message(FATAL_ERROR "The Xinerama headers were not found")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Check for Xkb (X keyboard extension)
|
||||||
|
if (NOT X11_Xkb_INCLUDE_PATH)
|
||||||
|
message(FATAL_ERROR "The X keyboard extension headers were not found")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Check for Xcursor (cursor creation from RGBA images)
|
||||||
|
if (NOT X11_Xcursor_INCLUDE_PATH)
|
||||||
|
message(FATAL_ERROR "The Xcursor headers were not found")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Check for XInput (modern HID input)
|
||||||
|
if (NOT X11_Xi_INCLUDE_PATH)
|
||||||
|
message(FATAL_ERROR "The XInput headers were not found")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(APPEND glfw_INCLUDE_DIRS "${X11_Xrandr_INCLUDE_PATH}"
|
||||||
|
"${X11_Xinerama_INCLUDE_PATH}"
|
||||||
|
"${X11_Xkb_INCLUDE_PATH}"
|
||||||
|
"${X11_Xcursor_INCLUDE_PATH}"
|
||||||
|
"${X11_Xi_INCLUDE_PATH}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
# Use Wayland for window creation
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
if (_GLFW_WAYLAND)
|
||||||
|
find_package(ECM REQUIRED NO_MODULE)
|
||||||
|
list(APPEND CMAKE_MODULE_PATH "${ECM_MODULE_PATH}")
|
||||||
|
|
||||||
|
find_package(Wayland REQUIRED Client Cursor Egl)
|
||||||
|
find_package(WaylandScanner REQUIRED)
|
||||||
|
find_package(WaylandProtocols 1.15 REQUIRED)
|
||||||
|
|
||||||
|
list(APPEND glfw_PKG_DEPS "wayland-egl")
|
||||||
|
|
||||||
|
list(APPEND glfw_INCLUDE_DIRS "${Wayland_INCLUDE_DIRS}")
|
||||||
|
list(APPEND glfw_LIBRARIES "${Wayland_LIBRARIES}" "${CMAKE_THREAD_LIBS_INIT}")
|
||||||
|
|
||||||
|
find_package(XKBCommon REQUIRED)
|
||||||
|
list(APPEND glfw_INCLUDE_DIRS "${XKBCOMMON_INCLUDE_DIRS}")
|
||||||
|
|
||||||
|
include(CheckIncludeFiles)
|
||||||
|
include(CheckFunctionExists)
|
||||||
|
check_include_files(xkbcommon/xkbcommon-compose.h HAVE_XKBCOMMON_COMPOSE_H)
|
||||||
|
check_function_exists(memfd_create HAVE_MEMFD_CREATE)
|
||||||
|
|
||||||
|
if (NOT ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux"))
|
||||||
|
find_package(EpollShim)
|
||||||
|
if (EPOLLSHIM_FOUND)
|
||||||
|
list(APPEND glfw_INCLUDE_DIRS "${EPOLLSHIM_INCLUDE_DIRS}")
|
||||||
|
list(APPEND glfw_LIBRARIES "${EPOLLSHIM_LIBRARIES}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
# Use OSMesa for offscreen context creation
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
if (_GLFW_OSMESA)
|
||||||
|
find_package(OSMesa REQUIRED)
|
||||||
|
list(APPEND glfw_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
# Use Cocoa for window creation and NSOpenGL for context creation
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
if (_GLFW_COCOA)
|
||||||
|
|
||||||
|
list(APPEND glfw_LIBRARIES
|
||||||
|
"-framework Cocoa"
|
||||||
|
"-framework IOKit"
|
||||||
|
"-framework CoreFoundation"
|
||||||
|
"-framework CoreVideo")
|
||||||
|
|
||||||
|
set(glfw_PKG_DEPS "")
|
||||||
|
set(glfw_PKG_LIBS "-framework Cocoa -framework IOKit -framework CoreFoundation -framework CoreVideo")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
# Add the Vulkan loader as a dependency if necessary
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
if (GLFW_VULKAN_STATIC)
|
||||||
|
list(APPEND glfw_PKG_DEPS "vulkan")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
# Export GLFW library dependencies
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
foreach(arg ${glfw_PKG_DEPS})
|
||||||
|
set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} ${arg}")
|
||||||
|
endforeach()
|
||||||
|
foreach(arg ${glfw_PKG_LIBS})
|
||||||
|
set(GLFW_PKG_LIBS "${GLFW_PKG_LIBS} ${arg}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
# Create generated files
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
include(CMakePackageConfigHelpers)
|
||||||
|
|
||||||
|
set(GLFW_CONFIG_PATH "${CMAKE_INSTALL_LIBDIR}/cmake/glfw3")
|
||||||
|
|
||||||
|
configure_package_config_file(src/glfw3Config.cmake.in
|
||||||
|
src/glfw3Config.cmake
|
||||||
|
INSTALL_DESTINATION "${GLFW_CONFIG_PATH}"
|
||||||
|
NO_CHECK_REQUIRED_COMPONENTS_MACRO)
|
||||||
|
|
||||||
|
write_basic_package_version_file(src/glfw3ConfigVersion.cmake
|
||||||
|
VERSION ${GLFW_VERSION}
|
||||||
|
COMPATIBILITY SameMajorVersion)
|
||||||
|
|
||||||
|
configure_file(src/glfw_config.h.in src/glfw_config.h @ONLY)
|
||||||
|
|
||||||
|
configure_file(src/glfw3.pc.in src/glfw3.pc @ONLY)
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
# Add subdirectories
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
add_subdirectory(src)
|
||||||
|
|
||||||
|
if (GLFW_BUILD_EXAMPLES)
|
||||||
|
add_subdirectory(examples)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (GLFW_BUILD_TESTS)
|
||||||
|
add_subdirectory(tests)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (DOXYGEN_FOUND AND GLFW_BUILD_DOCS)
|
||||||
|
add_subdirectory(docs)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
# Install files other than the library
|
||||||
|
# The library is installed by src/CMakeLists.txt
|
||||||
|
#--------------------------------------------------------------------
|
||||||
|
if (GLFW_INSTALL)
|
||||||
|
install(DIRECTORY include/GLFW DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||||
|
FILES_MATCHING PATTERN glfw3.h PATTERN glfw3native.h)
|
||||||
|
|
||||||
|
install(FILES "${GLFW_BINARY_DIR}/src/glfw3Config.cmake"
|
||||||
|
"${GLFW_BINARY_DIR}/src/glfw3ConfigVersion.cmake"
|
||||||
|
DESTINATION "${GLFW_CONFIG_PATH}")
|
||||||
|
|
||||||
|
install(EXPORT glfwTargets FILE glfw3Targets.cmake
|
||||||
|
EXPORT_LINK_INTERFACE_LIBRARIES
|
||||||
|
DESTINATION "${GLFW_CONFIG_PATH}")
|
||||||
|
install(FILES "${GLFW_BINARY_DIR}/src/glfw3.pc"
|
||||||
|
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||||
|
|
||||||
|
# Only generate this target if no higher-level project already has
|
||||||
|
if (NOT TARGET uninstall)
|
||||||
|
configure_file(cmake_uninstall.cmake.in
|
||||||
|
cmake_uninstall.cmake IMMEDIATE @ONLY)
|
||||||
|
|
||||||
|
add_custom_target(uninstall
|
||||||
|
"${CMAKE_COMMAND}" -P
|
||||||
|
"${GLFW_BINARY_DIR}/cmake_uninstall.cmake")
|
||||||
|
set_target_properties(uninstall PROPERTIES FOLDER "GLFW3")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
23
assignment-2a/ext/glfw/LICENSE.md
Executable file
|
@ -0,0 +1,23 @@
|
||||||
|
Copyright (c) 2002-2006 Marcus Geelnard
|
||||||
|
|
||||||
|
Copyright (c) 2006-2019 Camilla Löwy
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would
|
||||||
|
be appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not
|
||||||
|
be misrepresented as being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source
|
||||||
|
distribution.
|
||||||
|
|
347
assignment-2a/ext/glfw/README.md
Executable file
|
@ -0,0 +1,347 @@
|
||||||
|
# GLFW
|
||||||
|
|
||||||
|
[![Build status](https://travis-ci.org/glfw/glfw.svg?branch=master)](https://travis-ci.org/glfw/glfw)
|
||||||
|
[![Build status](https://ci.appveyor.com/api/projects/status/0kf0ct9831i5l6sp/branch/master?svg=true)](https://ci.appveyor.com/project/elmindreda/glfw)
|
||||||
|
[![Coverity Scan](https://scan.coverity.com/projects/4884/badge.svg)](https://scan.coverity.com/projects/glfw-glfw)
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
GLFW is an Open Source, multi-platform library for OpenGL, OpenGL ES and Vulkan
|
||||||
|
application development. It provides a simple, platform-independent API for
|
||||||
|
creating windows, contexts and surfaces, reading input, handling events, etc.
|
||||||
|
|
||||||
|
GLFW natively supports Windows, macOS and Linux and other Unix-like systems. On
|
||||||
|
Linux both X11 and Wayland is supported.
|
||||||
|
|
||||||
|
GLFW is licensed under the [zlib/libpng
|
||||||
|
license](http://www.glfw.org/license.html).
|
||||||
|
|
||||||
|
You can [download](http://www.glfw.org/download.html) the latest stable release
|
||||||
|
as source or Windows binaries, or fetch the `latest` branch from GitHub. Each
|
||||||
|
release starting with 3.0 also has a corresponding [annotated
|
||||||
|
tag](https://github.com/glfw/glfw/releases) with source and binary archives.
|
||||||
|
|
||||||
|
The [documentation](http://www.glfw.org/docs/latest/) is available online and is
|
||||||
|
included in all source and binary archives. See the [release
|
||||||
|
notes](https://www.glfw.org/docs/latest/news.html) for new features, caveats and
|
||||||
|
deprecations in the latest release. For more details see the [version
|
||||||
|
history](http://www.glfw.org/changelog.html).
|
||||||
|
|
||||||
|
The `master` branch is the stable integration branch and _should_ always compile
|
||||||
|
and run on all supported platforms, although details of newly added features may
|
||||||
|
change until they have been included in a release. New features and many bug
|
||||||
|
fixes live in [other branches](https://github.com/glfw/glfw/branches/all) until
|
||||||
|
they are stable enough to merge.
|
||||||
|
|
||||||
|
If you are new to GLFW, you may find the
|
||||||
|
[tutorial](http://www.glfw.org/docs/latest/quick.html) for GLFW 3 useful. If
|
||||||
|
you have used GLFW 2 in the past, there is a [transition
|
||||||
|
guide](http://www.glfw.org/docs/latest/moving.html) for moving to the GLFW
|
||||||
|
3 API.
|
||||||
|
|
||||||
|
|
||||||
|
## Compiling GLFW
|
||||||
|
|
||||||
|
GLFW itself requires only the headers and libraries for your OS and window
|
||||||
|
system. It does not need the headers for any context creation API (WGL, GLX,
|
||||||
|
EGL, NSGL, OSMesa) or rendering API (OpenGL, OpenGL ES, Vulkan) to enable
|
||||||
|
support for them.
|
||||||
|
|
||||||
|
GLFW supports compilation on Windows with Visual C++ 2010 and later, MinGW and
|
||||||
|
MinGW-w64, on macOS with Clang and on Linux and other Unix-like systems with GCC
|
||||||
|
and Clang. It will likely compile in other environments as well, but this is
|
||||||
|
not regularly tested.
|
||||||
|
|
||||||
|
There are [pre-compiled Windows binaries](http://www.glfw.org/download.html)
|
||||||
|
available for all supported compilers.
|
||||||
|
|
||||||
|
See the [compilation guide](http://www.glfw.org/docs/latest/compile.html) for
|
||||||
|
more information about how to compile GLFW yourself.
|
||||||
|
|
||||||
|
|
||||||
|
## Using GLFW
|
||||||
|
|
||||||
|
See the [documentation](http://www.glfw.org/docs/latest/) for tutorials, guides
|
||||||
|
and the API reference.
|
||||||
|
|
||||||
|
|
||||||
|
## Contributing to GLFW
|
||||||
|
|
||||||
|
See the [contribution
|
||||||
|
guide](https://github.com/glfw/glfw/blob/master/docs/CONTRIBUTING.md) for
|
||||||
|
more information.
|
||||||
|
|
||||||
|
|
||||||
|
## System requirements
|
||||||
|
|
||||||
|
GLFW supports Windows XP and later and macOS 10.8 and later. Linux and other
|
||||||
|
Unix-like systems running the X Window System are supported even without
|
||||||
|
a desktop environment or modern extensions, although some features require
|
||||||
|
a running window or clipboard manager. The OSMesa backend requires Mesa 6.3.
|
||||||
|
|
||||||
|
See the [compatibility guide](http://www.glfw.org/docs/latest/compat.html)
|
||||||
|
in the documentation for more information.
|
||||||
|
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
GLFW itself depends only on the headers and libraries for your window system.
|
||||||
|
|
||||||
|
The (experimental) Wayland backend also depends on the `extra-cmake-modules`
|
||||||
|
package, which is used to generated Wayland protocol headers.
|
||||||
|
|
||||||
|
The examples and test programs depend on a number of tiny libraries. These are
|
||||||
|
located in the `deps/` directory.
|
||||||
|
|
||||||
|
- [getopt\_port](https://github.com/kimgr/getopt_port/) for examples
|
||||||
|
with command-line options
|
||||||
|
- [TinyCThread](https://github.com/tinycthread/tinycthread) for threaded
|
||||||
|
examples
|
||||||
|
- [glad2](https://github.com/Dav1dde/glad) for loading OpenGL and Vulkan
|
||||||
|
functions
|
||||||
|
- [linmath.h](https://github.com/datenwolf/linmath.h) for linear algebra in
|
||||||
|
examples
|
||||||
|
- [Nuklear](https://github.com/vurtun/nuklear) for test and example UI
|
||||||
|
- [stb\_image\_write](https://github.com/nothings/stb) for writing images to disk
|
||||||
|
|
||||||
|
The documentation is generated with [Doxygen](http://doxygen.org/) if CMake can
|
||||||
|
find that tool.
|
||||||
|
|
||||||
|
|
||||||
|
## Reporting bugs
|
||||||
|
|
||||||
|
Bugs are reported to our [issue tracker](https://github.com/glfw/glfw/issues).
|
||||||
|
Please check the [contribution
|
||||||
|
guide](https://github.com/glfw/glfw/blob/master/docs/CONTRIBUTING.md) for
|
||||||
|
information on what to include when reporting a bug.
|
||||||
|
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
- Disabled tests and examples by default when built as a CMake subdirectory
|
||||||
|
- Bugfix: The CMake config-file package used an absolute path and was not
|
||||||
|
relocatable (#1470)
|
||||||
|
- Bugfix: Video modes with a duplicate screen area were discarded (#1555,#1556)
|
||||||
|
- Bugfix: Compiling with -Wextra-semi caused warnings (#1440)
|
||||||
|
- [Win32] Bugfix: `GLFW_INCLUDE_VULKAN` plus `VK_USE_PLATFORM_WIN32_KHR` caused
|
||||||
|
symbol redefinition (#1524)
|
||||||
|
- [Win32] Bugfix: The cursor position event was emitted before its cursor enter
|
||||||
|
event (#1490)
|
||||||
|
- [Win32] Bugfix: The window hint `GLFW_MAXIMIZED` did not move or resize the
|
||||||
|
window (#1499)
|
||||||
|
- [Cocoa] Bugfix: `glfwSetWindowSize` used a bottom-left anchor point (#1553)
|
||||||
|
- [X11] Bugfix: The CMake files did not check for the XInput headers (#1480)
|
||||||
|
- [X11] Bugfix: Key names were not updated when the keyboard layout changed
|
||||||
|
(#1462,#1528)
|
||||||
|
- [X11] Bugfix: Decorations could not be enabled after window creation (#1566)
|
||||||
|
- [X11] Bugfix: Content scale fallback value could be inconsistent (#1578)
|
||||||
|
- [NSGL] Removed enforcement of forward-compatible flag for core contexts
|
||||||
|
|
||||||
|
|
||||||
|
## Contact
|
||||||
|
|
||||||
|
On [glfw.org](http://www.glfw.org/) you can find the latest version of GLFW, as
|
||||||
|
well as news, documentation and other information about the project.
|
||||||
|
|
||||||
|
If you have questions related to the use of GLFW, we have a
|
||||||
|
[forum](https://discourse.glfw.org/), and the `#glfw` IRC channel on
|
||||||
|
[Freenode](http://freenode.net/).
|
||||||
|
|
||||||
|
If you have a bug to report, a patch to submit or a feature you'd like to
|
||||||
|
request, please file it in the
|
||||||
|
[issue tracker](https://github.com/glfw/glfw/issues) on GitHub.
|
||||||
|
|
||||||
|
Finally, if you're interested in helping out with the development of GLFW or
|
||||||
|
porting it to your favorite platform, join us on the forum, GitHub or IRC.
|
||||||
|
|
||||||
|
|
||||||
|
## Acknowledgements
|
||||||
|
|
||||||
|
GLFW exists because people around the world donated their time and lent their
|
||||||
|
skills.
|
||||||
|
|
||||||
|
- Bobyshev Alexander
|
||||||
|
- Matt Arsenault
|
||||||
|
- David Avedissian
|
||||||
|
- Keith Bauer
|
||||||
|
- John Bartholomew
|
||||||
|
- Coşku Baş
|
||||||
|
- Niklas Behrens
|
||||||
|
- Andrew Belt
|
||||||
|
- Niklas Bergström
|
||||||
|
- Denis Bernard
|
||||||
|
- Doug Binks
|
||||||
|
- blanco
|
||||||
|
- Kyle Brenneman
|
||||||
|
- Rok Breulj
|
||||||
|
- Kai Burjack
|
||||||
|
- Martin Capitanio
|
||||||
|
- David Carlier
|
||||||
|
- Arturo Castro
|
||||||
|
- Chi-kwan Chan
|
||||||
|
- Ian Clarkson
|
||||||
|
- Michał Cichoń
|
||||||
|
- Lambert Clara
|
||||||
|
- Anna Clarke
|
||||||
|
- Yaron Cohen-Tal
|
||||||
|
- Omar Cornut
|
||||||
|
- Andrew Corrigan
|
||||||
|
- Bailey Cosier
|
||||||
|
- Noel Cower
|
||||||
|
- Jason Daly
|
||||||
|
- Jarrod Davis
|
||||||
|
- Olivier Delannoy
|
||||||
|
- Paul R. Deppe
|
||||||
|
- Michael Dickens
|
||||||
|
- Роман Донченко
|
||||||
|
- Mario Dorn
|
||||||
|
- Wolfgang Draxinger
|
||||||
|
- Jonathan Dummer
|
||||||
|
- Ralph Eastwood
|
||||||
|
- Fredrik Ehnbom
|
||||||
|
- Robin Eklind
|
||||||
|
- Siavash Eliasi
|
||||||
|
- Felipe Ferreira
|
||||||
|
- Michael Fogleman
|
||||||
|
- Gerald Franz
|
||||||
|
- Mário Freitas
|
||||||
|
- GeO4d
|
||||||
|
- Marcus Geelnard
|
||||||
|
- Charles Giessen
|
||||||
|
- Stephen Gowen
|
||||||
|
- Kovid Goyal
|
||||||
|
- Eloi Marín Gratacós
|
||||||
|
- Stefan Gustavson
|
||||||
|
- Jonathan Hale
|
||||||
|
- Sylvain Hellegouarch
|
||||||
|
- Matthew Henry
|
||||||
|
- heromyth
|
||||||
|
- Lucas Hinderberger
|
||||||
|
- Paul Holden
|
||||||
|
- Warren Hu
|
||||||
|
- Charles Huber
|
||||||
|
- IntellectualKitty
|
||||||
|
- Aaron Jacobs
|
||||||
|
- Erik S. V. Jansson
|
||||||
|
- Toni Jovanoski
|
||||||
|
- Arseny Kapoulkine
|
||||||
|
- Cem Karan
|
||||||
|
- Osman Keskin
|
||||||
|
- Josh Kilmer
|
||||||
|
- Cameron King
|
||||||
|
- Peter Knut
|
||||||
|
- Christoph Kubisch
|
||||||
|
- Yuri Kunde Schlesner
|
||||||
|
- Rokas Kupstys
|
||||||
|
- Konstantin Käfer
|
||||||
|
- Eric Larson
|
||||||
|
- Robin Leffmann
|
||||||
|
- Glenn Lewis
|
||||||
|
- Shane Liesegang
|
||||||
|
- Anders Lindqvist
|
||||||
|
- Leon Linhart
|
||||||
|
- Eyal Lotem
|
||||||
|
- Aaron Loucks
|
||||||
|
- Luflosi
|
||||||
|
- Tristam MacDonald
|
||||||
|
- Hans Mackowiak
|
||||||
|
- Дмитри Малышев
|
||||||
|
- Zbigniew Mandziejewicz
|
||||||
|
- Adam Marcus
|
||||||
|
- Célestin Marot
|
||||||
|
- Kyle McDonald
|
||||||
|
- David Medlock
|
||||||
|
- Bryce Mehring
|
||||||
|
- Jonathan Mercier
|
||||||
|
- Marcel Metz
|
||||||
|
- Liam Middlebrook
|
||||||
|
- Ave Milia
|
||||||
|
- Jonathan Miller
|
||||||
|
- Kenneth Miller
|
||||||
|
- Bruce Mitchener
|
||||||
|
- Jack Moffitt
|
||||||
|
- Jeff Molofee
|
||||||
|
- Alexander Monakov
|
||||||
|
- Pierre Morel
|
||||||
|
- Jon Morton
|
||||||
|
- Pierre Moulon
|
||||||
|
- Martins Mozeiko
|
||||||
|
- Julian Møller
|
||||||
|
- ndogxj
|
||||||
|
- Kristian Nielsen
|
||||||
|
- Kamil Nowakowski
|
||||||
|
- Denis Ovod
|
||||||
|
- Ozzy
|
||||||
|
- Andri Pálsson
|
||||||
|
- Peoro
|
||||||
|
- Braden Pellett
|
||||||
|
- Christopher Pelloux
|
||||||
|
- Arturo J. Pérez
|
||||||
|
- Anthony Pesch
|
||||||
|
- Orson Peters
|
||||||
|
- Emmanuel Gil Peyrot
|
||||||
|
- Cyril Pichard
|
||||||
|
- Keith Pitt
|
||||||
|
- Stanislav Podgorskiy
|
||||||
|
- Konstantin Podsvirov
|
||||||
|
- Nathan Poirier
|
||||||
|
- Alexandre Pretyman
|
||||||
|
- Pablo Prietz
|
||||||
|
- przemekmirek
|
||||||
|
- Guillaume Racicot
|
||||||
|
- Philip Rideout
|
||||||
|
- Eddie Ringle
|
||||||
|
- Max Risuhin
|
||||||
|
- Jorge Rodriguez
|
||||||
|
- Ed Ropple
|
||||||
|
- Aleksey Rybalkin
|
||||||
|
- Riku Salminen
|
||||||
|
- Brandon Schaefer
|
||||||
|
- Sebastian Schuberth
|
||||||
|
- Christian Sdunek
|
||||||
|
- Matt Sealey
|
||||||
|
- Steve Sexton
|
||||||
|
- Arkady Shapkin
|
||||||
|
- Yoshiki Shibukawa
|
||||||
|
- Dmitri Shuralyov
|
||||||
|
- Daniel Skorupski
|
||||||
|
- Bradley Smith
|
||||||
|
- Cliff Smolinsky
|
||||||
|
- Patrick Snape
|
||||||
|
- Erlend Sogge Heggen
|
||||||
|
- Julian Squires
|
||||||
|
- Johannes Stein
|
||||||
|
- Pontus Stenetorp
|
||||||
|
- Michael Stocker
|
||||||
|
- Justin Stoecker
|
||||||
|
- Elviss Strazdins
|
||||||
|
- Paul Sultana
|
||||||
|
- Nathan Sweet
|
||||||
|
- TTK-Bandit
|
||||||
|
- Sergey Tikhomirov
|
||||||
|
- Arthur Tombs
|
||||||
|
- Ioannis Tsakpinis
|
||||||
|
- Samuli Tuomola
|
||||||
|
- Matthew Turner
|
||||||
|
- urraka
|
||||||
|
- Elias Vanderstuyft
|
||||||
|
- Stef Velzel
|
||||||
|
- Jari Vetoniemi
|
||||||
|
- Ricardo Vieira
|
||||||
|
- Nicholas Vitovitch
|
||||||
|
- Simon Voordouw
|
||||||
|
- Corentin Wallez
|
||||||
|
- Torsten Walluhn
|
||||||
|
- Patrick Walton
|
||||||
|
- Xo Wang
|
||||||
|
- Jay Weisskopf
|
||||||
|
- Frank Wille
|
||||||
|
- Ryogo Yoshimura
|
||||||
|
- Lukas Zanner
|
||||||
|
- Andrey Zholos
|
||||||
|
- Santi Zupancic
|
||||||
|
- Jonas Ådahl
|
||||||
|
- Lasse Öörni
|
||||||
|
- All the unmentioned and anonymous contributors in the GLFW community, for bug
|
||||||
|
reports, patches, feedback, testing and encouragement
|
||||||
|
|
29
assignment-2a/ext/glfw/cmake_uninstall.cmake.in
Executable file
|
@ -0,0 +1,29 @@
|
||||||
|
|
||||||
|
if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
|
||||||
|
message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
|
||||||
|
string(REGEX REPLACE "\n" ";" files "${files}")
|
||||||
|
|
||||||
|
foreach (file ${files})
|
||||||
|
message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
|
||||||
|
if (EXISTS "$ENV{DESTDIR}${file}")
|
||||||
|
exec_program("@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
|
||||||
|
OUTPUT_VARIABLE rm_out
|
||||||
|
RETURN_VALUE rm_retval)
|
||||||
|
if (NOT "${rm_retval}" STREQUAL 0)
|
||||||
|
MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
|
||||||
|
endif()
|
||||||
|
elseif (IS_SYMLINK "$ENV{DESTDIR}${file}")
|
||||||
|
EXEC_PROGRAM("@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
|
||||||
|
OUTPUT_VARIABLE rm_out
|
||||||
|
RETURN_VALUE rm_retval)
|
||||||
|
if (NOT "${rm_retval}" STREQUAL 0)
|
||||||
|
message(FATAL_ERROR "Problem when removing symlink \"$ENV{DESTDIR}${file}\"")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
230
assignment-2a/ext/glfw/deps/getopt.c
Executable file
|
@ -0,0 +1,230 @@
|
||||||
|
/* Copyright (c) 2012, Kim Gräsman
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Kim Gräsman nor the names of contributors may be used
|
||||||
|
* to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL KIM GRÄSMAN BE LIABLE FOR ANY DIRECT,
|
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "getopt.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
const int no_argument = 0;
|
||||||
|
const int required_argument = 1;
|
||||||
|
const int optional_argument = 2;
|
||||||
|
|
||||||
|
char* optarg;
|
||||||
|
int optopt;
|
||||||
|
/* The variable optind [...] shall be initialized to 1 by the system. */
|
||||||
|
int optind = 1;
|
||||||
|
int opterr;
|
||||||
|
|
||||||
|
static char* optcursor = NULL;
|
||||||
|
|
||||||
|
/* Implemented based on [1] and [2] for optional arguments.
|
||||||
|
optopt is handled FreeBSD-style, per [3].
|
||||||
|
Other GNU and FreeBSD extensions are purely accidental.
|
||||||
|
|
||||||
|
[1] http://pubs.opengroup.org/onlinepubs/000095399/functions/getopt.html
|
||||||
|
[2] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html
|
||||||
|
[3] http://www.freebsd.org/cgi/man.cgi?query=getopt&sektion=3&manpath=FreeBSD+9.0-RELEASE
|
||||||
|
*/
|
||||||
|
int getopt(int argc, char* const argv[], const char* optstring) {
|
||||||
|
int optchar = -1;
|
||||||
|
const char* optdecl = NULL;
|
||||||
|
|
||||||
|
optarg = NULL;
|
||||||
|
opterr = 0;
|
||||||
|
optopt = 0;
|
||||||
|
|
||||||
|
/* Unspecified, but we need it to avoid overrunning the argv bounds. */
|
||||||
|
if (optind >= argc)
|
||||||
|
goto no_more_optchars;
|
||||||
|
|
||||||
|
/* If, when getopt() is called argv[optind] is a null pointer, getopt()
|
||||||
|
shall return -1 without changing optind. */
|
||||||
|
if (argv[optind] == NULL)
|
||||||
|
goto no_more_optchars;
|
||||||
|
|
||||||
|
/* If, when getopt() is called *argv[optind] is not the character '-',
|
||||||
|
getopt() shall return -1 without changing optind. */
|
||||||
|
if (*argv[optind] != '-')
|
||||||
|
goto no_more_optchars;
|
||||||
|
|
||||||
|
/* If, when getopt() is called argv[optind] points to the string "-",
|
||||||
|
getopt() shall return -1 without changing optind. */
|
||||||
|
if (strcmp(argv[optind], "-") == 0)
|
||||||
|
goto no_more_optchars;
|
||||||
|
|
||||||
|
/* If, when getopt() is called argv[optind] points to the string "--",
|
||||||
|
getopt() shall return -1 after incrementing optind. */
|
||||||
|
if (strcmp(argv[optind], "--") == 0) {
|
||||||
|
++optind;
|
||||||
|
goto no_more_optchars;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optcursor == NULL || *optcursor == '\0')
|
||||||
|
optcursor = argv[optind] + 1;
|
||||||
|
|
||||||
|
optchar = *optcursor;
|
||||||
|
|
||||||
|
/* FreeBSD: The variable optopt saves the last known option character
|
||||||
|
returned by getopt(). */
|
||||||
|
optopt = optchar;
|
||||||
|
|
||||||
|
/* The getopt() function shall return the next option character (if one is
|
||||||
|
found) from argv that matches a character in optstring, if there is
|
||||||
|
one that matches. */
|
||||||
|
optdecl = strchr(optstring, optchar);
|
||||||
|
if (optdecl) {
|
||||||
|
/* [I]f a character is followed by a colon, the option takes an
|
||||||
|
argument. */
|
||||||
|
if (optdecl[1] == ':') {
|
||||||
|
optarg = ++optcursor;
|
||||||
|
if (*optarg == '\0') {
|
||||||
|
/* GNU extension: Two colons mean an option takes an
|
||||||
|
optional arg; if there is text in the current argv-element
|
||||||
|
(i.e., in the same word as the option name itself, for example,
|
||||||
|
"-oarg"), then it is returned in optarg, otherwise optarg is set
|
||||||
|
to zero. */
|
||||||
|
if (optdecl[2] != ':') {
|
||||||
|
/* If the option was the last character in the string pointed to by
|
||||||
|
an element of argv, then optarg shall contain the next element
|
||||||
|
of argv, and optind shall be incremented by 2. If the resulting
|
||||||
|
value of optind is greater than argc, this indicates a missing
|
||||||
|
option-argument, and getopt() shall return an error indication.
|
||||||
|
|
||||||
|
Otherwise, optarg shall point to the string following the
|
||||||
|
option character in that element of argv, and optind shall be
|
||||||
|
incremented by 1.
|
||||||
|
*/
|
||||||
|
if (++optind < argc) {
|
||||||
|
optarg = argv[optind];
|
||||||
|
} else {
|
||||||
|
/* If it detects a missing option-argument, it shall return the
|
||||||
|
colon character ( ':' ) if the first character of optstring
|
||||||
|
was a colon, or a question-mark character ( '?' ) otherwise.
|
||||||
|
*/
|
||||||
|
optarg = NULL;
|
||||||
|
optchar = (optstring[0] == ':') ? ':' : '?';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
optarg = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
optcursor = NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* If getopt() encounters an option character that is not contained in
|
||||||
|
optstring, it shall return the question-mark ( '?' ) character. */
|
||||||
|
optchar = '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optcursor == NULL || *++optcursor == '\0')
|
||||||
|
++optind;
|
||||||
|
|
||||||
|
return optchar;
|
||||||
|
|
||||||
|
no_more_optchars:
|
||||||
|
optcursor = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Implementation based on [1].
|
||||||
|
|
||||||
|
[1] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html
|
||||||
|
*/
|
||||||
|
int getopt_long(int argc, char* const argv[], const char* optstring,
|
||||||
|
const struct option* longopts, int* longindex) {
|
||||||
|
const struct option* o = longopts;
|
||||||
|
const struct option* match = NULL;
|
||||||
|
int num_matches = 0;
|
||||||
|
size_t argument_name_length = 0;
|
||||||
|
const char* current_argument = NULL;
|
||||||
|
int retval = -1;
|
||||||
|
|
||||||
|
optarg = NULL;
|
||||||
|
optopt = 0;
|
||||||
|
|
||||||
|
if (optind >= argc)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (strlen(argv[optind]) < 3 || strncmp(argv[optind], "--", 2) != 0)
|
||||||
|
return getopt(argc, argv, optstring);
|
||||||
|
|
||||||
|
/* It's an option; starts with -- and is longer than two chars. */
|
||||||
|
current_argument = argv[optind] + 2;
|
||||||
|
argument_name_length = strcspn(current_argument, "=");
|
||||||
|
for (; o->name; ++o) {
|
||||||
|
if (strncmp(o->name, current_argument, argument_name_length) == 0) {
|
||||||
|
match = o;
|
||||||
|
++num_matches;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_matches == 1) {
|
||||||
|
/* If longindex is not NULL, it points to a variable which is set to the
|
||||||
|
index of the long option relative to longopts. */
|
||||||
|
if (longindex)
|
||||||
|
*longindex = (int) (match - longopts);
|
||||||
|
|
||||||
|
/* If flag is NULL, then getopt_long() shall return val.
|
||||||
|
Otherwise, getopt_long() returns 0, and flag shall point to a variable
|
||||||
|
which shall be set to val if the option is found, but left unchanged if
|
||||||
|
the option is not found. */
|
||||||
|
if (match->flag)
|
||||||
|
*(match->flag) = match->val;
|
||||||
|
|
||||||
|
retval = match->flag ? 0 : match->val;
|
||||||
|
|
||||||
|
if (match->has_arg != no_argument) {
|
||||||
|
optarg = strchr(argv[optind], '=');
|
||||||
|
if (optarg != NULL)
|
||||||
|
++optarg;
|
||||||
|
|
||||||
|
if (match->has_arg == required_argument) {
|
||||||
|
/* Only scan the next argv for required arguments. Behavior is not
|
||||||
|
specified, but has been observed with Ubuntu and Mac OSX. */
|
||||||
|
if (optarg == NULL && ++optind < argc) {
|
||||||
|
optarg = argv[optind];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optarg == NULL)
|
||||||
|
retval = ':';
|
||||||
|
}
|
||||||
|
} else if (strchr(argv[optind], '=')) {
|
||||||
|
/* An argument was provided to a non-argument option.
|
||||||
|
I haven't seen this specified explicitly, but both GNU and BSD-based
|
||||||
|
implementations show this behavior.
|
||||||
|
*/
|
||||||
|
retval = '?';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Unknown option or ambiguous match. */
|
||||||
|
retval = '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
++optind;
|
||||||
|
return retval;
|
||||||
|
}
|
57
assignment-2a/ext/glfw/deps/getopt.h
Executable file
|
@ -0,0 +1,57 @@
|
||||||
|
/* Copyright (c) 2012, Kim Gräsman
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Kim Gräsman nor the names of contributors may be used
|
||||||
|
* to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL KIM GRÄSMAN BE LIABLE FOR ANY DIRECT,
|
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INCLUDED_GETOPT_PORT_H
|
||||||
|
#define INCLUDED_GETOPT_PORT_H
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern const int no_argument;
|
||||||
|
extern const int required_argument;
|
||||||
|
extern const int optional_argument;
|
||||||
|
|
||||||
|
extern char* optarg;
|
||||||
|
extern int optind, opterr, optopt;
|
||||||
|
|
||||||
|
struct option {
|
||||||
|
const char* name;
|
||||||
|
int has_arg;
|
||||||
|
int* flag;
|
||||||
|
int val;
|
||||||
|
};
|
||||||
|
|
||||||
|
int getopt(int argc, char* const argv[], const char* optstring);
|
||||||
|
|
||||||
|
int getopt_long(int argc, char* const argv[],
|
||||||
|
const char* optstring, const struct option* longopts, int* longindex);
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // INCLUDED_GETOPT_PORT_H
|
3840
assignment-2a/ext/glfw/deps/glad/gl.h
Executable file
282
assignment-2a/ext/glfw/deps/glad/khrplatform.h
Executable file
|
@ -0,0 +1,282 @@
|
||||||
|
#ifndef __khrplatform_h_
|
||||||
|
#define __khrplatform_h_
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copyright (c) 2008-2018 The Khronos Group Inc.
|
||||||
|
**
|
||||||
|
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
** copy of this software and/or associated documentation files (the
|
||||||
|
** "Materials"), to deal in the Materials without restriction, including
|
||||||
|
** without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||||
|
** permit persons to whom the Materials are furnished to do so, subject to
|
||||||
|
** the following conditions:
|
||||||
|
**
|
||||||
|
** The above copyright notice and this permission notice shall be included
|
||||||
|
** in all copies or substantial portions of the Materials.
|
||||||
|
**
|
||||||
|
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Khronos platform-specific types and definitions.
|
||||||
|
*
|
||||||
|
* The master copy of khrplatform.h is maintained in the Khronos EGL
|
||||||
|
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
|
||||||
|
* The last semantic modification to khrplatform.h was at commit ID:
|
||||||
|
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
|
||||||
|
*
|
||||||
|
* Adopters may modify this file to suit their platform. Adopters are
|
||||||
|
* encouraged to submit platform specific modifications to the Khronos
|
||||||
|
* group so that they can be included in future versions of this file.
|
||||||
|
* Please submit changes by filing pull requests or issues on
|
||||||
|
* the EGL Registry repository linked above.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* See the Implementer's Guidelines for information about where this file
|
||||||
|
* should be located on your system and for more details of its use:
|
||||||
|
* http://www.khronos.org/registry/implementers_guide.pdf
|
||||||
|
*
|
||||||
|
* This file should be included as
|
||||||
|
* #include <KHR/khrplatform.h>
|
||||||
|
* by Khronos client API header files that use its types and defines.
|
||||||
|
*
|
||||||
|
* The types in khrplatform.h should only be used to define API-specific types.
|
||||||
|
*
|
||||||
|
* Types defined in khrplatform.h:
|
||||||
|
* khronos_int8_t signed 8 bit
|
||||||
|
* khronos_uint8_t unsigned 8 bit
|
||||||
|
* khronos_int16_t signed 16 bit
|
||||||
|
* khronos_uint16_t unsigned 16 bit
|
||||||
|
* khronos_int32_t signed 32 bit
|
||||||
|
* khronos_uint32_t unsigned 32 bit
|
||||||
|
* khronos_int64_t signed 64 bit
|
||||||
|
* khronos_uint64_t unsigned 64 bit
|
||||||
|
* khronos_intptr_t signed same number of bits as a pointer
|
||||||
|
* khronos_uintptr_t unsigned same number of bits as a pointer
|
||||||
|
* khronos_ssize_t signed size
|
||||||
|
* khronos_usize_t unsigned size
|
||||||
|
* khronos_float_t signed 32 bit floating point
|
||||||
|
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
|
||||||
|
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
|
||||||
|
* nanoseconds
|
||||||
|
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
|
||||||
|
* khronos_boolean_enum_t enumerated boolean type. This should
|
||||||
|
* only be used as a base type when a client API's boolean type is
|
||||||
|
* an enum. Client APIs which use an integer or other type for
|
||||||
|
* booleans cannot use this as the base type for their boolean.
|
||||||
|
*
|
||||||
|
* Tokens defined in khrplatform.h:
|
||||||
|
*
|
||||||
|
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
|
||||||
|
*
|
||||||
|
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
|
||||||
|
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
|
||||||
|
*
|
||||||
|
* Calling convention macros defined in this file:
|
||||||
|
* KHRONOS_APICALL
|
||||||
|
* KHRONOS_APIENTRY
|
||||||
|
* KHRONOS_APIATTRIBUTES
|
||||||
|
*
|
||||||
|
* These may be used in function prototypes as:
|
||||||
|
*
|
||||||
|
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
|
||||||
|
* int arg1,
|
||||||
|
* int arg2) KHRONOS_APIATTRIBUTES;
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* Definition of KHRONOS_APICALL
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
* This precedes the return type of the function in the function prototype.
|
||||||
|
*/
|
||||||
|
#if defined(_WIN32) && !defined(__SCITECH_SNAP__)
|
||||||
|
# define KHRONOS_APICALL __declspec(dllimport)
|
||||||
|
#elif defined (__SYMBIAN32__)
|
||||||
|
# define KHRONOS_APICALL IMPORT_C
|
||||||
|
#elif defined(__ANDROID__)
|
||||||
|
# define KHRONOS_APICALL __attribute__((visibility("default")))
|
||||||
|
#else
|
||||||
|
# define KHRONOS_APICALL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* Definition of KHRONOS_APIENTRY
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
* This follows the return type of the function and precedes the function
|
||||||
|
* name in the function prototype.
|
||||||
|
*/
|
||||||
|
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
|
||||||
|
/* Win32 but not WinCE */
|
||||||
|
# define KHRONOS_APIENTRY __stdcall
|
||||||
|
#else
|
||||||
|
# define KHRONOS_APIENTRY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* Definition of KHRONOS_APIATTRIBUTES
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
* This follows the closing parenthesis of the function prototype arguments.
|
||||||
|
*/
|
||||||
|
#if defined (__ARMCC_2__)
|
||||||
|
#define KHRONOS_APIATTRIBUTES __softfp
|
||||||
|
#else
|
||||||
|
#define KHRONOS_APIATTRIBUTES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* basic type definitions
|
||||||
|
*-----------------------------------------------------------------------*/
|
||||||
|
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Using <stdint.h>
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
typedef int32_t khronos_int32_t;
|
||||||
|
typedef uint32_t khronos_uint32_t;
|
||||||
|
typedef int64_t khronos_int64_t;
|
||||||
|
typedef uint64_t khronos_uint64_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
|
||||||
|
#elif defined(__VMS ) || defined(__sgi)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Using <inttypes.h>
|
||||||
|
*/
|
||||||
|
#include <inttypes.h>
|
||||||
|
typedef int32_t khronos_int32_t;
|
||||||
|
typedef uint32_t khronos_uint32_t;
|
||||||
|
typedef int64_t khronos_int64_t;
|
||||||
|
typedef uint64_t khronos_uint64_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
|
||||||
|
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Win32
|
||||||
|
*/
|
||||||
|
typedef __int32 khronos_int32_t;
|
||||||
|
typedef unsigned __int32 khronos_uint32_t;
|
||||||
|
typedef __int64 khronos_int64_t;
|
||||||
|
typedef unsigned __int64 khronos_uint64_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
|
||||||
|
#elif defined(__sun__) || defined(__digital__)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sun or Digital
|
||||||
|
*/
|
||||||
|
typedef int khronos_int32_t;
|
||||||
|
typedef unsigned int khronos_uint32_t;
|
||||||
|
#if defined(__arch64__) || defined(_LP64)
|
||||||
|
typedef long int khronos_int64_t;
|
||||||
|
typedef unsigned long int khronos_uint64_t;
|
||||||
|
#else
|
||||||
|
typedef long long int khronos_int64_t;
|
||||||
|
typedef unsigned long long int khronos_uint64_t;
|
||||||
|
#endif /* __arch64__ */
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
|
||||||
|
#elif 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hypothetical platform with no float or int64 support
|
||||||
|
*/
|
||||||
|
typedef int khronos_int32_t;
|
||||||
|
typedef unsigned int khronos_uint32_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 0
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 0
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generic fallback
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
typedef int32_t khronos_int32_t;
|
||||||
|
typedef uint32_t khronos_uint32_t;
|
||||||
|
typedef int64_t khronos_int64_t;
|
||||||
|
typedef uint64_t khronos_uint64_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Types that are (so far) the same on all platforms
|
||||||
|
*/
|
||||||
|
typedef signed char khronos_int8_t;
|
||||||
|
typedef unsigned char khronos_uint8_t;
|
||||||
|
typedef signed short int khronos_int16_t;
|
||||||
|
typedef unsigned short int khronos_uint16_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Types that differ between LLP64 and LP64 architectures - in LLP64,
|
||||||
|
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
|
||||||
|
* to be the only LLP64 architecture in current use.
|
||||||
|
*/
|
||||||
|
#ifdef _WIN64
|
||||||
|
typedef signed long long int khronos_intptr_t;
|
||||||
|
typedef unsigned long long int khronos_uintptr_t;
|
||||||
|
typedef signed long long int khronos_ssize_t;
|
||||||
|
typedef unsigned long long int khronos_usize_t;
|
||||||
|
#else
|
||||||
|
typedef signed long int khronos_intptr_t;
|
||||||
|
typedef unsigned long int khronos_uintptr_t;
|
||||||
|
typedef signed long int khronos_ssize_t;
|
||||||
|
typedef unsigned long int khronos_usize_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if KHRONOS_SUPPORT_FLOAT
|
||||||
|
/*
|
||||||
|
* Float type
|
||||||
|
*/
|
||||||
|
typedef float khronos_float_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if KHRONOS_SUPPORT_INT64
|
||||||
|
/* Time types
|
||||||
|
*
|
||||||
|
* These types can be used to represent a time interval in nanoseconds or
|
||||||
|
* an absolute Unadjusted System Time. Unadjusted System Time is the number
|
||||||
|
* of nanoseconds since some arbitrary system event (e.g. since the last
|
||||||
|
* time the system booted). The Unadjusted System Time is an unsigned
|
||||||
|
* 64 bit value that wraps back to 0 every 584 years. Time intervals
|
||||||
|
* may be either signed or unsigned.
|
||||||
|
*/
|
||||||
|
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
|
||||||
|
typedef khronos_int64_t khronos_stime_nanoseconds_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dummy value used to pad enum types to 32 bits.
|
||||||
|
*/
|
||||||
|
#ifndef KHRONOS_MAX_ENUM
|
||||||
|
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enumerated boolean type
|
||||||
|
*
|
||||||
|
* Values other than zero should be considered to be true. Therefore
|
||||||
|
* comparisons should not be made against KHRONOS_TRUE.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
KHRONOS_FALSE = 0,
|
||||||
|
KHRONOS_TRUE = 1,
|
||||||
|
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
|
||||||
|
} khronos_boolean_enum_t;
|
||||||
|
|
||||||
|
#endif /* __khrplatform_h_ */
|
92
assignment-2a/ext/glfw/deps/glad/vk_platform.h
Executable file
|
@ -0,0 +1,92 @@
|
||||||
|
/* */
|
||||||
|
/* File: vk_platform.h */
|
||||||
|
/* */
|
||||||
|
/*
|
||||||
|
** Copyright (c) 2014-2017 The Khronos Group Inc.
|
||||||
|
**
|
||||||
|
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
** you may not use this file except in compliance with the License.
|
||||||
|
** You may obtain a copy of the License at
|
||||||
|
**
|
||||||
|
** http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
**
|
||||||
|
** Unless required by applicable law or agreed to in writing, software
|
||||||
|
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
** See the License for the specific language governing permissions and
|
||||||
|
** limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef VK_PLATFORM_H_
|
||||||
|
#define VK_PLATFORM_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
/*
|
||||||
|
***************************************************************************************************
|
||||||
|
* Platform-specific directives and type declarations
|
||||||
|
***************************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Platform-specific calling convention macros.
|
||||||
|
*
|
||||||
|
* Platforms should define these so that Vulkan clients call Vulkan commands
|
||||||
|
* with the same calling conventions that the Vulkan implementation expects.
|
||||||
|
*
|
||||||
|
* VKAPI_ATTR - Placed before the return type in function declarations.
|
||||||
|
* Useful for C++11 and GCC/Clang-style function attribute syntax.
|
||||||
|
* VKAPI_CALL - Placed after the return type in function declarations.
|
||||||
|
* Useful for MSVC-style calling convention syntax.
|
||||||
|
* VKAPI_PTR - Placed between the '(' and '*' in function pointer types.
|
||||||
|
*
|
||||||
|
* Function declaration: VKAPI_ATTR void VKAPI_CALL vkCommand(void);
|
||||||
|
* Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void);
|
||||||
|
*/
|
||||||
|
#if defined(_WIN32)
|
||||||
|
/* On Windows, Vulkan commands use the stdcall convention */
|
||||||
|
#define VKAPI_ATTR
|
||||||
|
#define VKAPI_CALL __stdcall
|
||||||
|
#define VKAPI_PTR VKAPI_CALL
|
||||||
|
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7
|
||||||
|
#error "Vulkan isn't supported for the 'armeabi' NDK ABI"
|
||||||
|
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE)
|
||||||
|
/* On Android 32-bit ARM targets, Vulkan functions use the "hardfloat" */
|
||||||
|
/* calling convention, i.e. float parameters are passed in registers. This */
|
||||||
|
/* is true even if the rest of the application passes floats on the stack, */
|
||||||
|
/* as it does by default when compiling for the armeabi-v7a NDK ABI. */
|
||||||
|
#define VKAPI_ATTR __attribute__((pcs("aapcs-vfp")))
|
||||||
|
#define VKAPI_CALL
|
||||||
|
#define VKAPI_PTR VKAPI_ATTR
|
||||||
|
#else
|
||||||
|
/* On other platforms, use the default calling convention */
|
||||||
|
#define VKAPI_ATTR
|
||||||
|
#define VKAPI_CALL
|
||||||
|
#define VKAPI_PTR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#if !defined(VK_NO_STDINT_H)
|
||||||
|
#if defined(_MSC_VER) && (_MSC_VER < 1600)
|
||||||
|
typedef signed __int8 int8_t;
|
||||||
|
typedef unsigned __int8 uint8_t;
|
||||||
|
typedef signed __int16 int16_t;
|
||||||
|
typedef unsigned __int16 uint16_t;
|
||||||
|
typedef signed __int32 int32_t;
|
||||||
|
typedef unsigned __int32 uint32_t;
|
||||||
|
typedef signed __int64 int64_t;
|
||||||
|
typedef unsigned __int64 uint64_t;
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
#endif /* !defined(VK_NO_STDINT_H) */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#endif
|
3480
assignment-2a/ext/glfw/deps/glad/vulkan.h
Executable file
1791
assignment-2a/ext/glfw/deps/glad_gl.c
Executable file
593
assignment-2a/ext/glfw/deps/glad_vulkan.c
Executable file
|
@ -0,0 +1,593 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <glad/vulkan.h>
|
||||||
|
|
||||||
|
#ifndef GLAD_IMPL_UTIL_C_
|
||||||
|
#define GLAD_IMPL_UTIL_C_
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define GLAD_IMPL_UTIL_SSCANF sscanf_s
|
||||||
|
#else
|
||||||
|
#define GLAD_IMPL_UTIL_SSCANF sscanf
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* GLAD_IMPL_UTIL_C_ */
|
||||||
|
|
||||||
|
|
||||||
|
int GLAD_VK_VERSION_1_0 = 0;
|
||||||
|
int GLAD_VK_VERSION_1_1 = 0;
|
||||||
|
int GLAD_VK_EXT_debug_report = 0;
|
||||||
|
int GLAD_VK_KHR_surface = 0;
|
||||||
|
int GLAD_VK_KHR_swapchain = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PFN_vkAcquireNextImage2KHR glad_vkAcquireNextImage2KHR = NULL;
|
||||||
|
PFN_vkAcquireNextImageKHR glad_vkAcquireNextImageKHR = NULL;
|
||||||
|
PFN_vkAllocateCommandBuffers glad_vkAllocateCommandBuffers = NULL;
|
||||||
|
PFN_vkAllocateDescriptorSets glad_vkAllocateDescriptorSets = NULL;
|
||||||
|
PFN_vkAllocateMemory glad_vkAllocateMemory = NULL;
|
||||||
|
PFN_vkBeginCommandBuffer glad_vkBeginCommandBuffer = NULL;
|
||||||
|
PFN_vkBindBufferMemory glad_vkBindBufferMemory = NULL;
|
||||||
|
PFN_vkBindBufferMemory2 glad_vkBindBufferMemory2 = NULL;
|
||||||
|
PFN_vkBindImageMemory glad_vkBindImageMemory = NULL;
|
||||||
|
PFN_vkBindImageMemory2 glad_vkBindImageMemory2 = NULL;
|
||||||
|
PFN_vkCmdBeginQuery glad_vkCmdBeginQuery = NULL;
|
||||||
|
PFN_vkCmdBeginRenderPass glad_vkCmdBeginRenderPass = NULL;
|
||||||
|
PFN_vkCmdBindDescriptorSets glad_vkCmdBindDescriptorSets = NULL;
|
||||||
|
PFN_vkCmdBindIndexBuffer glad_vkCmdBindIndexBuffer = NULL;
|
||||||
|
PFN_vkCmdBindPipeline glad_vkCmdBindPipeline = NULL;
|
||||||
|
PFN_vkCmdBindVertexBuffers glad_vkCmdBindVertexBuffers = NULL;
|
||||||
|
PFN_vkCmdBlitImage glad_vkCmdBlitImage = NULL;
|
||||||
|
PFN_vkCmdClearAttachments glad_vkCmdClearAttachments = NULL;
|
||||||
|
PFN_vkCmdClearColorImage glad_vkCmdClearColorImage = NULL;
|
||||||
|
PFN_vkCmdClearDepthStencilImage glad_vkCmdClearDepthStencilImage = NULL;
|
||||||
|
PFN_vkCmdCopyBuffer glad_vkCmdCopyBuffer = NULL;
|
||||||
|
PFN_vkCmdCopyBufferToImage glad_vkCmdCopyBufferToImage = NULL;
|
||||||
|
PFN_vkCmdCopyImage glad_vkCmdCopyImage = NULL;
|
||||||
|
PFN_vkCmdCopyImageToBuffer glad_vkCmdCopyImageToBuffer = NULL;
|
||||||
|
PFN_vkCmdCopyQueryPoolResults glad_vkCmdCopyQueryPoolResults = NULL;
|
||||||
|
PFN_vkCmdDispatch glad_vkCmdDispatch = NULL;
|
||||||
|
PFN_vkCmdDispatchBase glad_vkCmdDispatchBase = NULL;
|
||||||
|
PFN_vkCmdDispatchIndirect glad_vkCmdDispatchIndirect = NULL;
|
||||||
|
PFN_vkCmdDraw glad_vkCmdDraw = NULL;
|
||||||
|
PFN_vkCmdDrawIndexed glad_vkCmdDrawIndexed = NULL;
|
||||||
|
PFN_vkCmdDrawIndexedIndirect glad_vkCmdDrawIndexedIndirect = NULL;
|
||||||
|
PFN_vkCmdDrawIndirect glad_vkCmdDrawIndirect = NULL;
|
||||||
|
PFN_vkCmdEndQuery glad_vkCmdEndQuery = NULL;
|
||||||
|
PFN_vkCmdEndRenderPass glad_vkCmdEndRenderPass = NULL;
|
||||||
|
PFN_vkCmdExecuteCommands glad_vkCmdExecuteCommands = NULL;
|
||||||
|
PFN_vkCmdFillBuffer glad_vkCmdFillBuffer = NULL;
|
||||||
|
PFN_vkCmdNextSubpass glad_vkCmdNextSubpass = NULL;
|
||||||
|
PFN_vkCmdPipelineBarrier glad_vkCmdPipelineBarrier = NULL;
|
||||||
|
PFN_vkCmdPushConstants glad_vkCmdPushConstants = NULL;
|
||||||
|
PFN_vkCmdResetEvent glad_vkCmdResetEvent = NULL;
|
||||||
|
PFN_vkCmdResetQueryPool glad_vkCmdResetQueryPool = NULL;
|
||||||
|
PFN_vkCmdResolveImage glad_vkCmdResolveImage = NULL;
|
||||||
|
PFN_vkCmdSetBlendConstants glad_vkCmdSetBlendConstants = NULL;
|
||||||
|
PFN_vkCmdSetDepthBias glad_vkCmdSetDepthBias = NULL;
|
||||||
|
PFN_vkCmdSetDepthBounds glad_vkCmdSetDepthBounds = NULL;
|
||||||
|
PFN_vkCmdSetDeviceMask glad_vkCmdSetDeviceMask = NULL;
|
||||||
|
PFN_vkCmdSetEvent glad_vkCmdSetEvent = NULL;
|
||||||
|
PFN_vkCmdSetLineWidth glad_vkCmdSetLineWidth = NULL;
|
||||||
|
PFN_vkCmdSetScissor glad_vkCmdSetScissor = NULL;
|
||||||
|
PFN_vkCmdSetStencilCompareMask glad_vkCmdSetStencilCompareMask = NULL;
|
||||||
|
PFN_vkCmdSetStencilReference glad_vkCmdSetStencilReference = NULL;
|
||||||
|
PFN_vkCmdSetStencilWriteMask glad_vkCmdSetStencilWriteMask = NULL;
|
||||||
|
PFN_vkCmdSetViewport glad_vkCmdSetViewport = NULL;
|
||||||
|
PFN_vkCmdUpdateBuffer glad_vkCmdUpdateBuffer = NULL;
|
||||||
|
PFN_vkCmdWaitEvents glad_vkCmdWaitEvents = NULL;
|
||||||
|
PFN_vkCmdWriteTimestamp glad_vkCmdWriteTimestamp = NULL;
|
||||||
|
PFN_vkCreateBuffer glad_vkCreateBuffer = NULL;
|
||||||
|
PFN_vkCreateBufferView glad_vkCreateBufferView = NULL;
|
||||||
|
PFN_vkCreateCommandPool glad_vkCreateCommandPool = NULL;
|
||||||
|
PFN_vkCreateComputePipelines glad_vkCreateComputePipelines = NULL;
|
||||||
|
PFN_vkCreateDebugReportCallbackEXT glad_vkCreateDebugReportCallbackEXT = NULL;
|
||||||
|
PFN_vkCreateDescriptorPool glad_vkCreateDescriptorPool = NULL;
|
||||||
|
PFN_vkCreateDescriptorSetLayout glad_vkCreateDescriptorSetLayout = NULL;
|
||||||
|
PFN_vkCreateDescriptorUpdateTemplate glad_vkCreateDescriptorUpdateTemplate = NULL;
|
||||||
|
PFN_vkCreateDevice glad_vkCreateDevice = NULL;
|
||||||
|
PFN_vkCreateEvent glad_vkCreateEvent = NULL;
|
||||||
|
PFN_vkCreateFence glad_vkCreateFence = NULL;
|
||||||
|
PFN_vkCreateFramebuffer glad_vkCreateFramebuffer = NULL;
|
||||||
|
PFN_vkCreateGraphicsPipelines glad_vkCreateGraphicsPipelines = NULL;
|
||||||
|
PFN_vkCreateImage glad_vkCreateImage = NULL;
|
||||||
|
PFN_vkCreateImageView glad_vkCreateImageView = NULL;
|
||||||
|
PFN_vkCreateInstance glad_vkCreateInstance = NULL;
|
||||||
|
PFN_vkCreatePipelineCache glad_vkCreatePipelineCache = NULL;
|
||||||
|
PFN_vkCreatePipelineLayout glad_vkCreatePipelineLayout = NULL;
|
||||||
|
PFN_vkCreateQueryPool glad_vkCreateQueryPool = NULL;
|
||||||
|
PFN_vkCreateRenderPass glad_vkCreateRenderPass = NULL;
|
||||||
|
PFN_vkCreateSampler glad_vkCreateSampler = NULL;
|
||||||
|
PFN_vkCreateSamplerYcbcrConversion glad_vkCreateSamplerYcbcrConversion = NULL;
|
||||||
|
PFN_vkCreateSemaphore glad_vkCreateSemaphore = NULL;
|
||||||
|
PFN_vkCreateShaderModule glad_vkCreateShaderModule = NULL;
|
||||||
|
PFN_vkCreateSwapchainKHR glad_vkCreateSwapchainKHR = NULL;
|
||||||
|
PFN_vkDebugReportMessageEXT glad_vkDebugReportMessageEXT = NULL;
|
||||||
|
PFN_vkDestroyBuffer glad_vkDestroyBuffer = NULL;
|
||||||
|
PFN_vkDestroyBufferView glad_vkDestroyBufferView = NULL;
|
||||||
|
PFN_vkDestroyCommandPool glad_vkDestroyCommandPool = NULL;
|
||||||
|
PFN_vkDestroyDebugReportCallbackEXT glad_vkDestroyDebugReportCallbackEXT = NULL;
|
||||||
|
PFN_vkDestroyDescriptorPool glad_vkDestroyDescriptorPool = NULL;
|
||||||
|
PFN_vkDestroyDescriptorSetLayout glad_vkDestroyDescriptorSetLayout = NULL;
|
||||||
|
PFN_vkDestroyDescriptorUpdateTemplate glad_vkDestroyDescriptorUpdateTemplate = NULL;
|
||||||
|
PFN_vkDestroyDevice glad_vkDestroyDevice = NULL;
|
||||||
|
PFN_vkDestroyEvent glad_vkDestroyEvent = NULL;
|
||||||
|
PFN_vkDestroyFence glad_vkDestroyFence = NULL;
|
||||||
|
PFN_vkDestroyFramebuffer glad_vkDestroyFramebuffer = NULL;
|
||||||
|
PFN_vkDestroyImage glad_vkDestroyImage = NULL;
|
||||||
|
PFN_vkDestroyImageView glad_vkDestroyImageView = NULL;
|
||||||
|
PFN_vkDestroyInstance glad_vkDestroyInstance = NULL;
|
||||||
|
PFN_vkDestroyPipeline glad_vkDestroyPipeline = NULL;
|
||||||
|
PFN_vkDestroyPipelineCache glad_vkDestroyPipelineCache = NULL;
|
||||||
|
PFN_vkDestroyPipelineLayout glad_vkDestroyPipelineLayout = NULL;
|
||||||
|
PFN_vkDestroyQueryPool glad_vkDestroyQueryPool = NULL;
|
||||||
|
PFN_vkDestroyRenderPass glad_vkDestroyRenderPass = NULL;
|
||||||
|
PFN_vkDestroySampler glad_vkDestroySampler = NULL;
|
||||||
|
PFN_vkDestroySamplerYcbcrConversion glad_vkDestroySamplerYcbcrConversion = NULL;
|
||||||
|
PFN_vkDestroySemaphore glad_vkDestroySemaphore = NULL;
|
||||||
|
PFN_vkDestroyShaderModule glad_vkDestroyShaderModule = NULL;
|
||||||
|
PFN_vkDestroySurfaceKHR glad_vkDestroySurfaceKHR = NULL;
|
||||||
|
PFN_vkDestroySwapchainKHR glad_vkDestroySwapchainKHR = NULL;
|
||||||
|
PFN_vkDeviceWaitIdle glad_vkDeviceWaitIdle = NULL;
|
||||||
|
PFN_vkEndCommandBuffer glad_vkEndCommandBuffer = NULL;
|
||||||
|
PFN_vkEnumerateDeviceExtensionProperties glad_vkEnumerateDeviceExtensionProperties = NULL;
|
||||||
|
PFN_vkEnumerateDeviceLayerProperties glad_vkEnumerateDeviceLayerProperties = NULL;
|
||||||
|
PFN_vkEnumerateInstanceExtensionProperties glad_vkEnumerateInstanceExtensionProperties = NULL;
|
||||||
|
PFN_vkEnumerateInstanceLayerProperties glad_vkEnumerateInstanceLayerProperties = NULL;
|
||||||
|
PFN_vkEnumerateInstanceVersion glad_vkEnumerateInstanceVersion = NULL;
|
||||||
|
PFN_vkEnumeratePhysicalDeviceGroups glad_vkEnumeratePhysicalDeviceGroups = NULL;
|
||||||
|
PFN_vkEnumeratePhysicalDevices glad_vkEnumeratePhysicalDevices = NULL;
|
||||||
|
PFN_vkFlushMappedMemoryRanges glad_vkFlushMappedMemoryRanges = NULL;
|
||||||
|
PFN_vkFreeCommandBuffers glad_vkFreeCommandBuffers = NULL;
|
||||||
|
PFN_vkFreeDescriptorSets glad_vkFreeDescriptorSets = NULL;
|
||||||
|
PFN_vkFreeMemory glad_vkFreeMemory = NULL;
|
||||||
|
PFN_vkGetBufferMemoryRequirements glad_vkGetBufferMemoryRequirements = NULL;
|
||||||
|
PFN_vkGetBufferMemoryRequirements2 glad_vkGetBufferMemoryRequirements2 = NULL;
|
||||||
|
PFN_vkGetDescriptorSetLayoutSupport glad_vkGetDescriptorSetLayoutSupport = NULL;
|
||||||
|
PFN_vkGetDeviceGroupPeerMemoryFeatures glad_vkGetDeviceGroupPeerMemoryFeatures = NULL;
|
||||||
|
PFN_vkGetDeviceGroupPresentCapabilitiesKHR glad_vkGetDeviceGroupPresentCapabilitiesKHR = NULL;
|
||||||
|
PFN_vkGetDeviceGroupSurfacePresentModesKHR glad_vkGetDeviceGroupSurfacePresentModesKHR = NULL;
|
||||||
|
PFN_vkGetDeviceMemoryCommitment glad_vkGetDeviceMemoryCommitment = NULL;
|
||||||
|
PFN_vkGetDeviceProcAddr glad_vkGetDeviceProcAddr = NULL;
|
||||||
|
PFN_vkGetDeviceQueue glad_vkGetDeviceQueue = NULL;
|
||||||
|
PFN_vkGetDeviceQueue2 glad_vkGetDeviceQueue2 = NULL;
|
||||||
|
PFN_vkGetEventStatus glad_vkGetEventStatus = NULL;
|
||||||
|
PFN_vkGetFenceStatus glad_vkGetFenceStatus = NULL;
|
||||||
|
PFN_vkGetImageMemoryRequirements glad_vkGetImageMemoryRequirements = NULL;
|
||||||
|
PFN_vkGetImageMemoryRequirements2 glad_vkGetImageMemoryRequirements2 = NULL;
|
||||||
|
PFN_vkGetImageSparseMemoryRequirements glad_vkGetImageSparseMemoryRequirements = NULL;
|
||||||
|
PFN_vkGetImageSparseMemoryRequirements2 glad_vkGetImageSparseMemoryRequirements2 = NULL;
|
||||||
|
PFN_vkGetImageSubresourceLayout glad_vkGetImageSubresourceLayout = NULL;
|
||||||
|
PFN_vkGetInstanceProcAddr glad_vkGetInstanceProcAddr = NULL;
|
||||||
|
PFN_vkGetPhysicalDeviceExternalBufferProperties glad_vkGetPhysicalDeviceExternalBufferProperties = NULL;
|
||||||
|
PFN_vkGetPhysicalDeviceExternalFenceProperties glad_vkGetPhysicalDeviceExternalFenceProperties = NULL;
|
||||||
|
PFN_vkGetPhysicalDeviceExternalSemaphoreProperties glad_vkGetPhysicalDeviceExternalSemaphoreProperties = NULL;
|
||||||
|
PFN_vkGetPhysicalDeviceFeatures glad_vkGetPhysicalDeviceFeatures = NULL;
|
||||||
|
PFN_vkGetPhysicalDeviceFeatures2 glad_vkGetPhysicalDeviceFeatures2 = NULL;
|
||||||
|
PFN_vkGetPhysicalDeviceFormatProperties glad_vkGetPhysicalDeviceFormatProperties = NULL;
|
||||||
|
PFN_vkGetPhysicalDeviceFormatProperties2 glad_vkGetPhysicalDeviceFormatProperties2 = NULL;
|
||||||
|
PFN_vkGetPhysicalDeviceImageFormatProperties glad_vkGetPhysicalDeviceImageFormatProperties = NULL;
|
||||||
|
PFN_vkGetPhysicalDeviceImageFormatProperties2 glad_vkGetPhysicalDeviceImageFormatProperties2 = NULL;
|
||||||
|
PFN_vkGetPhysicalDeviceMemoryProperties glad_vkGetPhysicalDeviceMemoryProperties = NULL;
|
||||||
|
PFN_vkGetPhysicalDeviceMemoryProperties2 glad_vkGetPhysicalDeviceMemoryProperties2 = NULL;
|
||||||
|
PFN_vkGetPhysicalDevicePresentRectanglesKHR glad_vkGetPhysicalDevicePresentRectanglesKHR = NULL;
|
||||||
|
PFN_vkGetPhysicalDeviceProperties glad_vkGetPhysicalDeviceProperties = NULL;
|
||||||
|
PFN_vkGetPhysicalDeviceProperties2 glad_vkGetPhysicalDeviceProperties2 = NULL;
|
||||||
|
PFN_vkGetPhysicalDeviceQueueFamilyProperties glad_vkGetPhysicalDeviceQueueFamilyProperties = NULL;
|
||||||
|
PFN_vkGetPhysicalDeviceQueueFamilyProperties2 glad_vkGetPhysicalDeviceQueueFamilyProperties2 = NULL;
|
||||||
|
PFN_vkGetPhysicalDeviceSparseImageFormatProperties glad_vkGetPhysicalDeviceSparseImageFormatProperties = NULL;
|
||||||
|
PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 glad_vkGetPhysicalDeviceSparseImageFormatProperties2 = NULL;
|
||||||
|
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR glad_vkGetPhysicalDeviceSurfaceCapabilitiesKHR = NULL;
|
||||||
|
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR glad_vkGetPhysicalDeviceSurfaceFormatsKHR = NULL;
|
||||||
|
PFN_vkGetPhysicalDeviceSurfacePresentModesKHR glad_vkGetPhysicalDeviceSurfacePresentModesKHR = NULL;
|
||||||
|
PFN_vkGetPhysicalDeviceSurfaceSupportKHR glad_vkGetPhysicalDeviceSurfaceSupportKHR = NULL;
|
||||||
|
PFN_vkGetPipelineCacheData glad_vkGetPipelineCacheData = NULL;
|
||||||
|
PFN_vkGetQueryPoolResults glad_vkGetQueryPoolResults = NULL;
|
||||||
|
PFN_vkGetRenderAreaGranularity glad_vkGetRenderAreaGranularity = NULL;
|
||||||
|
PFN_vkGetSwapchainImagesKHR glad_vkGetSwapchainImagesKHR = NULL;
|
||||||
|
PFN_vkInvalidateMappedMemoryRanges glad_vkInvalidateMappedMemoryRanges = NULL;
|
||||||
|
PFN_vkMapMemory glad_vkMapMemory = NULL;
|
||||||
|
PFN_vkMergePipelineCaches glad_vkMergePipelineCaches = NULL;
|
||||||
|
PFN_vkQueueBindSparse glad_vkQueueBindSparse = NULL;
|
||||||
|
PFN_vkQueuePresentKHR glad_vkQueuePresentKHR = NULL;
|
||||||
|
PFN_vkQueueSubmit glad_vkQueueSubmit = NULL;
|
||||||
|
PFN_vkQueueWaitIdle glad_vkQueueWaitIdle = NULL;
|
||||||
|
PFN_vkResetCommandBuffer glad_vkResetCommandBuffer = NULL;
|
||||||
|
PFN_vkResetCommandPool glad_vkResetCommandPool = NULL;
|
||||||
|
PFN_vkResetDescriptorPool glad_vkResetDescriptorPool = NULL;
|
||||||
|
PFN_vkResetEvent glad_vkResetEvent = NULL;
|
||||||
|
PFN_vkResetFences glad_vkResetFences = NULL;
|
||||||
|
PFN_vkSetEvent glad_vkSetEvent = NULL;
|
||||||
|
PFN_vkTrimCommandPool glad_vkTrimCommandPool = NULL;
|
||||||
|
PFN_vkUnmapMemory glad_vkUnmapMemory = NULL;
|
||||||
|
PFN_vkUpdateDescriptorSetWithTemplate glad_vkUpdateDescriptorSetWithTemplate = NULL;
|
||||||
|
PFN_vkUpdateDescriptorSets glad_vkUpdateDescriptorSets = NULL;
|
||||||
|
PFN_vkWaitForFences glad_vkWaitForFences = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
static void glad_vk_load_VK_VERSION_1_0( GLADuserptrloadfunc load, void* userptr) {
|
||||||
|
if(!GLAD_VK_VERSION_1_0) return;
|
||||||
|
vkAllocateCommandBuffers = (PFN_vkAllocateCommandBuffers) load("vkAllocateCommandBuffers", userptr);
|
||||||
|
vkAllocateDescriptorSets = (PFN_vkAllocateDescriptorSets) load("vkAllocateDescriptorSets", userptr);
|
||||||
|
vkAllocateMemory = (PFN_vkAllocateMemory) load("vkAllocateMemory", userptr);
|
||||||
|
vkBeginCommandBuffer = (PFN_vkBeginCommandBuffer) load("vkBeginCommandBuffer", userptr);
|
||||||
|
vkBindBufferMemory = (PFN_vkBindBufferMemory) load("vkBindBufferMemory", userptr);
|
||||||
|
vkBindImageMemory = (PFN_vkBindImageMemory) load("vkBindImageMemory", userptr);
|
||||||
|
vkCmdBeginQuery = (PFN_vkCmdBeginQuery) load("vkCmdBeginQuery", userptr);
|
||||||
|
vkCmdBeginRenderPass = (PFN_vkCmdBeginRenderPass) load("vkCmdBeginRenderPass", userptr);
|
||||||
|
vkCmdBindDescriptorSets = (PFN_vkCmdBindDescriptorSets) load("vkCmdBindDescriptorSets", userptr);
|
||||||
|
vkCmdBindIndexBuffer = (PFN_vkCmdBindIndexBuffer) load("vkCmdBindIndexBuffer", userptr);
|
||||||
|
vkCmdBindPipeline = (PFN_vkCmdBindPipeline) load("vkCmdBindPipeline", userptr);
|
||||||
|
vkCmdBindVertexBuffers = (PFN_vkCmdBindVertexBuffers) load("vkCmdBindVertexBuffers", userptr);
|
||||||
|
vkCmdBlitImage = (PFN_vkCmdBlitImage) load("vkCmdBlitImage", userptr);
|
||||||
|
vkCmdClearAttachments = (PFN_vkCmdClearAttachments) load("vkCmdClearAttachments", userptr);
|
||||||
|
vkCmdClearColorImage = (PFN_vkCmdClearColorImage) load("vkCmdClearColorImage", userptr);
|
||||||
|
vkCmdClearDepthStencilImage = (PFN_vkCmdClearDepthStencilImage) load("vkCmdClearDepthStencilImage", userptr);
|
||||||
|
vkCmdCopyBuffer = (PFN_vkCmdCopyBuffer) load("vkCmdCopyBuffer", userptr);
|
||||||
|
vkCmdCopyBufferToImage = (PFN_vkCmdCopyBufferToImage) load("vkCmdCopyBufferToImage", userptr);
|
||||||
|
vkCmdCopyImage = (PFN_vkCmdCopyImage) load("vkCmdCopyImage", userptr);
|
||||||
|
vkCmdCopyImageToBuffer = (PFN_vkCmdCopyImageToBuffer) load("vkCmdCopyImageToBuffer", userptr);
|
||||||
|
vkCmdCopyQueryPoolResults = (PFN_vkCmdCopyQueryPoolResults) load("vkCmdCopyQueryPoolResults", userptr);
|
||||||
|
vkCmdDispatch = (PFN_vkCmdDispatch) load("vkCmdDispatch", userptr);
|
||||||
|
vkCmdDispatchIndirect = (PFN_vkCmdDispatchIndirect) load("vkCmdDispatchIndirect", userptr);
|
||||||
|
vkCmdDraw = (PFN_vkCmdDraw) load("vkCmdDraw", userptr);
|
||||||
|
vkCmdDrawIndexed = (PFN_vkCmdDrawIndexed) load("vkCmdDrawIndexed", userptr);
|
||||||
|
vkCmdDrawIndexedIndirect = (PFN_vkCmdDrawIndexedIndirect) load("vkCmdDrawIndexedIndirect", userptr);
|
||||||
|
vkCmdDrawIndirect = (PFN_vkCmdDrawIndirect) load("vkCmdDrawIndirect", userptr);
|
||||||
|
vkCmdEndQuery = (PFN_vkCmdEndQuery) load("vkCmdEndQuery", userptr);
|
||||||
|
vkCmdEndRenderPass = (PFN_vkCmdEndRenderPass) load("vkCmdEndRenderPass", userptr);
|
||||||
|
vkCmdExecuteCommands = (PFN_vkCmdExecuteCommands) load("vkCmdExecuteCommands", userptr);
|
||||||
|
vkCmdFillBuffer = (PFN_vkCmdFillBuffer) load("vkCmdFillBuffer", userptr);
|
||||||
|
vkCmdNextSubpass = (PFN_vkCmdNextSubpass) load("vkCmdNextSubpass", userptr);
|
||||||
|
vkCmdPipelineBarrier = (PFN_vkCmdPipelineBarrier) load("vkCmdPipelineBarrier", userptr);
|
||||||
|
vkCmdPushConstants = (PFN_vkCmdPushConstants) load("vkCmdPushConstants", userptr);
|
||||||
|
vkCmdResetEvent = (PFN_vkCmdResetEvent) load("vkCmdResetEvent", userptr);
|
||||||
|
vkCmdResetQueryPool = (PFN_vkCmdResetQueryPool) load("vkCmdResetQueryPool", userptr);
|
||||||
|
vkCmdResolveImage = (PFN_vkCmdResolveImage) load("vkCmdResolveImage", userptr);
|
||||||
|
vkCmdSetBlendConstants = (PFN_vkCmdSetBlendConstants) load("vkCmdSetBlendConstants", userptr);
|
||||||
|
vkCmdSetDepthBias = (PFN_vkCmdSetDepthBias) load("vkCmdSetDepthBias", userptr);
|
||||||
|
vkCmdSetDepthBounds = (PFN_vkCmdSetDepthBounds) load("vkCmdSetDepthBounds", userptr);
|
||||||
|
vkCmdSetEvent = (PFN_vkCmdSetEvent) load("vkCmdSetEvent", userptr);
|
||||||
|
vkCmdSetLineWidth = (PFN_vkCmdSetLineWidth) load("vkCmdSetLineWidth", userptr);
|
||||||
|
vkCmdSetScissor = (PFN_vkCmdSetScissor) load("vkCmdSetScissor", userptr);
|
||||||
|
vkCmdSetStencilCompareMask = (PFN_vkCmdSetStencilCompareMask) load("vkCmdSetStencilCompareMask", userptr);
|
||||||
|
vkCmdSetStencilReference = (PFN_vkCmdSetStencilReference) load("vkCmdSetStencilReference", userptr);
|
||||||
|
vkCmdSetStencilWriteMask = (PFN_vkCmdSetStencilWriteMask) load("vkCmdSetStencilWriteMask", userptr);
|
||||||
|
vkCmdSetViewport = (PFN_vkCmdSetViewport) load("vkCmdSetViewport", userptr);
|
||||||
|
vkCmdUpdateBuffer = (PFN_vkCmdUpdateBuffer) load("vkCmdUpdateBuffer", userptr);
|
||||||
|
vkCmdWaitEvents = (PFN_vkCmdWaitEvents) load("vkCmdWaitEvents", userptr);
|
||||||
|
vkCmdWriteTimestamp = (PFN_vkCmdWriteTimestamp) load("vkCmdWriteTimestamp", userptr);
|
||||||
|
vkCreateBuffer = (PFN_vkCreateBuffer) load("vkCreateBuffer", userptr);
|
||||||
|
vkCreateBufferView = (PFN_vkCreateBufferView) load("vkCreateBufferView", userptr);
|
||||||
|
vkCreateCommandPool = (PFN_vkCreateCommandPool) load("vkCreateCommandPool", userptr);
|
||||||
|
vkCreateComputePipelines = (PFN_vkCreateComputePipelines) load("vkCreateComputePipelines", userptr);
|
||||||
|
vkCreateDescriptorPool = (PFN_vkCreateDescriptorPool) load("vkCreateDescriptorPool", userptr);
|
||||||
|
vkCreateDescriptorSetLayout = (PFN_vkCreateDescriptorSetLayout) load("vkCreateDescriptorSetLayout", userptr);
|
||||||
|
vkCreateDevice = (PFN_vkCreateDevice) load("vkCreateDevice", userptr);
|
||||||
|
vkCreateEvent = (PFN_vkCreateEvent) load("vkCreateEvent", userptr);
|
||||||
|
vkCreateFence = (PFN_vkCreateFence) load("vkCreateFence", userptr);
|
||||||
|
vkCreateFramebuffer = (PFN_vkCreateFramebuffer) load("vkCreateFramebuffer", userptr);
|
||||||
|
vkCreateGraphicsPipelines = (PFN_vkCreateGraphicsPipelines) load("vkCreateGraphicsPipelines", userptr);
|
||||||
|
vkCreateImage = (PFN_vkCreateImage) load("vkCreateImage", userptr);
|
||||||
|
vkCreateImageView = (PFN_vkCreateImageView) load("vkCreateImageView", userptr);
|
||||||
|
vkCreateInstance = (PFN_vkCreateInstance) load("vkCreateInstance", userptr);
|
||||||
|
vkCreatePipelineCache = (PFN_vkCreatePipelineCache) load("vkCreatePipelineCache", userptr);
|
||||||
|
vkCreatePipelineLayout = (PFN_vkCreatePipelineLayout) load("vkCreatePipelineLayout", userptr);
|
||||||
|
vkCreateQueryPool = (PFN_vkCreateQueryPool) load("vkCreateQueryPool", userptr);
|
||||||
|
vkCreateRenderPass = (PFN_vkCreateRenderPass) load("vkCreateRenderPass", userptr);
|
||||||
|
vkCreateSampler = (PFN_vkCreateSampler) load("vkCreateSampler", userptr);
|
||||||
|
vkCreateSemaphore = (PFN_vkCreateSemaphore) load("vkCreateSemaphore", userptr);
|
||||||
|
vkCreateShaderModule = (PFN_vkCreateShaderModule) load("vkCreateShaderModule", userptr);
|
||||||
|
vkDestroyBuffer = (PFN_vkDestroyBuffer) load("vkDestroyBuffer", userptr);
|
||||||
|
vkDestroyBufferView = (PFN_vkDestroyBufferView) load("vkDestroyBufferView", userptr);
|
||||||
|
vkDestroyCommandPool = (PFN_vkDestroyCommandPool) load("vkDestroyCommandPool", userptr);
|
||||||
|
vkDestroyDescriptorPool = (PFN_vkDestroyDescriptorPool) load("vkDestroyDescriptorPool", userptr);
|
||||||
|
vkDestroyDescriptorSetLayout = (PFN_vkDestroyDescriptorSetLayout) load("vkDestroyDescriptorSetLayout", userptr);
|
||||||
|
vkDestroyDevice = (PFN_vkDestroyDevice) load("vkDestroyDevice", userptr);
|
||||||
|
vkDestroyEvent = (PFN_vkDestroyEvent) load("vkDestroyEvent", userptr);
|
||||||
|
vkDestroyFence = (PFN_vkDestroyFence) load("vkDestroyFence", userptr);
|
||||||
|
vkDestroyFramebuffer = (PFN_vkDestroyFramebuffer) load("vkDestroyFramebuffer", userptr);
|
||||||
|
vkDestroyImage = (PFN_vkDestroyImage) load("vkDestroyImage", userptr);
|
||||||
|
vkDestroyImageView = (PFN_vkDestroyImageView) load("vkDestroyImageView", userptr);
|
||||||
|
vkDestroyInstance = (PFN_vkDestroyInstance) load("vkDestroyInstance", userptr);
|
||||||
|
vkDestroyPipeline = (PFN_vkDestroyPipeline) load("vkDestroyPipeline", userptr);
|
||||||
|
vkDestroyPipelineCache = (PFN_vkDestroyPipelineCache) load("vkDestroyPipelineCache", userptr);
|
||||||
|
vkDestroyPipelineLayout = (PFN_vkDestroyPipelineLayout) load("vkDestroyPipelineLayout", userptr);
|
||||||
|
vkDestroyQueryPool = (PFN_vkDestroyQueryPool) load("vkDestroyQueryPool", userptr);
|
||||||
|
vkDestroyRenderPass = (PFN_vkDestroyRenderPass) load("vkDestroyRenderPass", userptr);
|
||||||
|
vkDestroySampler = (PFN_vkDestroySampler) load("vkDestroySampler", userptr);
|
||||||
|
vkDestroySemaphore = (PFN_vkDestroySemaphore) load("vkDestroySemaphore", userptr);
|
||||||
|
vkDestroyShaderModule = (PFN_vkDestroyShaderModule) load("vkDestroyShaderModule", userptr);
|
||||||
|
vkDeviceWaitIdle = (PFN_vkDeviceWaitIdle) load("vkDeviceWaitIdle", userptr);
|
||||||
|
vkEndCommandBuffer = (PFN_vkEndCommandBuffer) load("vkEndCommandBuffer", userptr);
|
||||||
|
vkEnumerateDeviceExtensionProperties = (PFN_vkEnumerateDeviceExtensionProperties) load("vkEnumerateDeviceExtensionProperties", userptr);
|
||||||
|
vkEnumerateDeviceLayerProperties = (PFN_vkEnumerateDeviceLayerProperties) load("vkEnumerateDeviceLayerProperties", userptr);
|
||||||
|
vkEnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties) load("vkEnumerateInstanceExtensionProperties", userptr);
|
||||||
|
vkEnumerateInstanceLayerProperties = (PFN_vkEnumerateInstanceLayerProperties) load("vkEnumerateInstanceLayerProperties", userptr);
|
||||||
|
vkEnumeratePhysicalDevices = (PFN_vkEnumeratePhysicalDevices) load("vkEnumeratePhysicalDevices", userptr);
|
||||||
|
vkFlushMappedMemoryRanges = (PFN_vkFlushMappedMemoryRanges) load("vkFlushMappedMemoryRanges", userptr);
|
||||||
|
vkFreeCommandBuffers = (PFN_vkFreeCommandBuffers) load("vkFreeCommandBuffers", userptr);
|
||||||
|
vkFreeDescriptorSets = (PFN_vkFreeDescriptorSets) load("vkFreeDescriptorSets", userptr);
|
||||||
|
vkFreeMemory = (PFN_vkFreeMemory) load("vkFreeMemory", userptr);
|
||||||
|
vkGetBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements) load("vkGetBufferMemoryRequirements", userptr);
|
||||||
|
vkGetDeviceMemoryCommitment = (PFN_vkGetDeviceMemoryCommitment) load("vkGetDeviceMemoryCommitment", userptr);
|
||||||
|
vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr) load("vkGetDeviceProcAddr", userptr);
|
||||||
|
vkGetDeviceQueue = (PFN_vkGetDeviceQueue) load("vkGetDeviceQueue", userptr);
|
||||||
|
vkGetEventStatus = (PFN_vkGetEventStatus) load("vkGetEventStatus", userptr);
|
||||||
|
vkGetFenceStatus = (PFN_vkGetFenceStatus) load("vkGetFenceStatus", userptr);
|
||||||
|
vkGetImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements) load("vkGetImageMemoryRequirements", userptr);
|
||||||
|
vkGetImageSparseMemoryRequirements = (PFN_vkGetImageSparseMemoryRequirements) load("vkGetImageSparseMemoryRequirements", userptr);
|
||||||
|
vkGetImageSubresourceLayout = (PFN_vkGetImageSubresourceLayout) load("vkGetImageSubresourceLayout", userptr);
|
||||||
|
vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) load("vkGetInstanceProcAddr", userptr);
|
||||||
|
vkGetPhysicalDeviceFeatures = (PFN_vkGetPhysicalDeviceFeatures) load("vkGetPhysicalDeviceFeatures", userptr);
|
||||||
|
vkGetPhysicalDeviceFormatProperties = (PFN_vkGetPhysicalDeviceFormatProperties) load("vkGetPhysicalDeviceFormatProperties", userptr);
|
||||||
|
vkGetPhysicalDeviceImageFormatProperties = (PFN_vkGetPhysicalDeviceImageFormatProperties) load("vkGetPhysicalDeviceImageFormatProperties", userptr);
|
||||||
|
vkGetPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties) load("vkGetPhysicalDeviceMemoryProperties", userptr);
|
||||||
|
vkGetPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties) load("vkGetPhysicalDeviceProperties", userptr);
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties = (PFN_vkGetPhysicalDeviceQueueFamilyProperties) load("vkGetPhysicalDeviceQueueFamilyProperties", userptr);
|
||||||
|
vkGetPhysicalDeviceSparseImageFormatProperties = (PFN_vkGetPhysicalDeviceSparseImageFormatProperties) load("vkGetPhysicalDeviceSparseImageFormatProperties", userptr);
|
||||||
|
vkGetPipelineCacheData = (PFN_vkGetPipelineCacheData) load("vkGetPipelineCacheData", userptr);
|
||||||
|
vkGetQueryPoolResults = (PFN_vkGetQueryPoolResults) load("vkGetQueryPoolResults", userptr);
|
||||||
|
vkGetRenderAreaGranularity = (PFN_vkGetRenderAreaGranularity) load("vkGetRenderAreaGranularity", userptr);
|
||||||
|
vkInvalidateMappedMemoryRanges = (PFN_vkInvalidateMappedMemoryRanges) load("vkInvalidateMappedMemoryRanges", userptr);
|
||||||
|
vkMapMemory = (PFN_vkMapMemory) load("vkMapMemory", userptr);
|
||||||
|
vkMergePipelineCaches = (PFN_vkMergePipelineCaches) load("vkMergePipelineCaches", userptr);
|
||||||
|
vkQueueBindSparse = (PFN_vkQueueBindSparse) load("vkQueueBindSparse", userptr);
|
||||||
|
vkQueueSubmit = (PFN_vkQueueSubmit) load("vkQueueSubmit", userptr);
|
||||||
|
vkQueueWaitIdle = (PFN_vkQueueWaitIdle) load("vkQueueWaitIdle", userptr);
|
||||||
|
vkResetCommandBuffer = (PFN_vkResetCommandBuffer) load("vkResetCommandBuffer", userptr);
|
||||||
|
vkResetCommandPool = (PFN_vkResetCommandPool) load("vkResetCommandPool", userptr);
|
||||||
|
vkResetDescriptorPool = (PFN_vkResetDescriptorPool) load("vkResetDescriptorPool", userptr);
|
||||||
|
vkResetEvent = (PFN_vkResetEvent) load("vkResetEvent", userptr);
|
||||||
|
vkResetFences = (PFN_vkResetFences) load("vkResetFences", userptr);
|
||||||
|
vkSetEvent = (PFN_vkSetEvent) load("vkSetEvent", userptr);
|
||||||
|
vkUnmapMemory = (PFN_vkUnmapMemory) load("vkUnmapMemory", userptr);
|
||||||
|
vkUpdateDescriptorSets = (PFN_vkUpdateDescriptorSets) load("vkUpdateDescriptorSets", userptr);
|
||||||
|
vkWaitForFences = (PFN_vkWaitForFences) load("vkWaitForFences", userptr);
|
||||||
|
}
|
||||||
|
static void glad_vk_load_VK_VERSION_1_1( GLADuserptrloadfunc load, void* userptr) {
|
||||||
|
if(!GLAD_VK_VERSION_1_1) return;
|
||||||
|
vkBindBufferMemory2 = (PFN_vkBindBufferMemory2) load("vkBindBufferMemory2", userptr);
|
||||||
|
vkBindImageMemory2 = (PFN_vkBindImageMemory2) load("vkBindImageMemory2", userptr);
|
||||||
|
vkCmdDispatchBase = (PFN_vkCmdDispatchBase) load("vkCmdDispatchBase", userptr);
|
||||||
|
vkCmdSetDeviceMask = (PFN_vkCmdSetDeviceMask) load("vkCmdSetDeviceMask", userptr);
|
||||||
|
vkCreateDescriptorUpdateTemplate = (PFN_vkCreateDescriptorUpdateTemplate) load("vkCreateDescriptorUpdateTemplate", userptr);
|
||||||
|
vkCreateSamplerYcbcrConversion = (PFN_vkCreateSamplerYcbcrConversion) load("vkCreateSamplerYcbcrConversion", userptr);
|
||||||
|
vkDestroyDescriptorUpdateTemplate = (PFN_vkDestroyDescriptorUpdateTemplate) load("vkDestroyDescriptorUpdateTemplate", userptr);
|
||||||
|
vkDestroySamplerYcbcrConversion = (PFN_vkDestroySamplerYcbcrConversion) load("vkDestroySamplerYcbcrConversion", userptr);
|
||||||
|
vkEnumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion) load("vkEnumerateInstanceVersion", userptr);
|
||||||
|
vkEnumeratePhysicalDeviceGroups = (PFN_vkEnumeratePhysicalDeviceGroups) load("vkEnumeratePhysicalDeviceGroups", userptr);
|
||||||
|
vkGetBufferMemoryRequirements2 = (PFN_vkGetBufferMemoryRequirements2) load("vkGetBufferMemoryRequirements2", userptr);
|
||||||
|
vkGetDescriptorSetLayoutSupport = (PFN_vkGetDescriptorSetLayoutSupport) load("vkGetDescriptorSetLayoutSupport", userptr);
|
||||||
|
vkGetDeviceGroupPeerMemoryFeatures = (PFN_vkGetDeviceGroupPeerMemoryFeatures) load("vkGetDeviceGroupPeerMemoryFeatures", userptr);
|
||||||
|
vkGetDeviceQueue2 = (PFN_vkGetDeviceQueue2) load("vkGetDeviceQueue2", userptr);
|
||||||
|
vkGetImageMemoryRequirements2 = (PFN_vkGetImageMemoryRequirements2) load("vkGetImageMemoryRequirements2", userptr);
|
||||||
|
vkGetImageSparseMemoryRequirements2 = (PFN_vkGetImageSparseMemoryRequirements2) load("vkGetImageSparseMemoryRequirements2", userptr);
|
||||||
|
vkGetPhysicalDeviceExternalBufferProperties = (PFN_vkGetPhysicalDeviceExternalBufferProperties) load("vkGetPhysicalDeviceExternalBufferProperties", userptr);
|
||||||
|
vkGetPhysicalDeviceExternalFenceProperties = (PFN_vkGetPhysicalDeviceExternalFenceProperties) load("vkGetPhysicalDeviceExternalFenceProperties", userptr);
|
||||||
|
vkGetPhysicalDeviceExternalSemaphoreProperties = (PFN_vkGetPhysicalDeviceExternalSemaphoreProperties) load("vkGetPhysicalDeviceExternalSemaphoreProperties", userptr);
|
||||||
|
vkGetPhysicalDeviceFeatures2 = (PFN_vkGetPhysicalDeviceFeatures2) load("vkGetPhysicalDeviceFeatures2", userptr);
|
||||||
|
vkGetPhysicalDeviceFormatProperties2 = (PFN_vkGetPhysicalDeviceFormatProperties2) load("vkGetPhysicalDeviceFormatProperties2", userptr);
|
||||||
|
vkGetPhysicalDeviceImageFormatProperties2 = (PFN_vkGetPhysicalDeviceImageFormatProperties2) load("vkGetPhysicalDeviceImageFormatProperties2", userptr);
|
||||||
|
vkGetPhysicalDeviceMemoryProperties2 = (PFN_vkGetPhysicalDeviceMemoryProperties2) load("vkGetPhysicalDeviceMemoryProperties2", userptr);
|
||||||
|
vkGetPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2) load("vkGetPhysicalDeviceProperties2", userptr);
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties2 = (PFN_vkGetPhysicalDeviceQueueFamilyProperties2) load("vkGetPhysicalDeviceQueueFamilyProperties2", userptr);
|
||||||
|
vkGetPhysicalDeviceSparseImageFormatProperties2 = (PFN_vkGetPhysicalDeviceSparseImageFormatProperties2) load("vkGetPhysicalDeviceSparseImageFormatProperties2", userptr);
|
||||||
|
vkTrimCommandPool = (PFN_vkTrimCommandPool) load("vkTrimCommandPool", userptr);
|
||||||
|
vkUpdateDescriptorSetWithTemplate = (PFN_vkUpdateDescriptorSetWithTemplate) load("vkUpdateDescriptorSetWithTemplate", userptr);
|
||||||
|
}
|
||||||
|
static void glad_vk_load_VK_EXT_debug_report( GLADuserptrloadfunc load, void* userptr) {
|
||||||
|
if(!GLAD_VK_EXT_debug_report) return;
|
||||||
|
vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT) load("vkCreateDebugReportCallbackEXT", userptr);
|
||||||
|
vkDebugReportMessageEXT = (PFN_vkDebugReportMessageEXT) load("vkDebugReportMessageEXT", userptr);
|
||||||
|
vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT) load("vkDestroyDebugReportCallbackEXT", userptr);
|
||||||
|
}
|
||||||
|
static void glad_vk_load_VK_KHR_surface( GLADuserptrloadfunc load, void* userptr) {
|
||||||
|
if(!GLAD_VK_KHR_surface) return;
|
||||||
|
vkDestroySurfaceKHR = (PFN_vkDestroySurfaceKHR) load("vkDestroySurfaceKHR", userptr);
|
||||||
|
vkGetPhysicalDeviceSurfaceCapabilitiesKHR = (PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR) load("vkGetPhysicalDeviceSurfaceCapabilitiesKHR", userptr);
|
||||||
|
vkGetPhysicalDeviceSurfaceFormatsKHR = (PFN_vkGetPhysicalDeviceSurfaceFormatsKHR) load("vkGetPhysicalDeviceSurfaceFormatsKHR", userptr);
|
||||||
|
vkGetPhysicalDeviceSurfacePresentModesKHR = (PFN_vkGetPhysicalDeviceSurfacePresentModesKHR) load("vkGetPhysicalDeviceSurfacePresentModesKHR", userptr);
|
||||||
|
vkGetPhysicalDeviceSurfaceSupportKHR = (PFN_vkGetPhysicalDeviceSurfaceSupportKHR) load("vkGetPhysicalDeviceSurfaceSupportKHR", userptr);
|
||||||
|
}
|
||||||
|
static void glad_vk_load_VK_KHR_swapchain( GLADuserptrloadfunc load, void* userptr) {
|
||||||
|
if(!GLAD_VK_KHR_swapchain) return;
|
||||||
|
vkAcquireNextImage2KHR = (PFN_vkAcquireNextImage2KHR) load("vkAcquireNextImage2KHR", userptr);
|
||||||
|
vkAcquireNextImageKHR = (PFN_vkAcquireNextImageKHR) load("vkAcquireNextImageKHR", userptr);
|
||||||
|
vkCreateSwapchainKHR = (PFN_vkCreateSwapchainKHR) load("vkCreateSwapchainKHR", userptr);
|
||||||
|
vkDestroySwapchainKHR = (PFN_vkDestroySwapchainKHR) load("vkDestroySwapchainKHR", userptr);
|
||||||
|
vkGetDeviceGroupPresentCapabilitiesKHR = (PFN_vkGetDeviceGroupPresentCapabilitiesKHR) load("vkGetDeviceGroupPresentCapabilitiesKHR", userptr);
|
||||||
|
vkGetDeviceGroupSurfacePresentModesKHR = (PFN_vkGetDeviceGroupSurfacePresentModesKHR) load("vkGetDeviceGroupSurfacePresentModesKHR", userptr);
|
||||||
|
vkGetPhysicalDevicePresentRectanglesKHR = (PFN_vkGetPhysicalDevicePresentRectanglesKHR) load("vkGetPhysicalDevicePresentRectanglesKHR", userptr);
|
||||||
|
vkGetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR) load("vkGetSwapchainImagesKHR", userptr);
|
||||||
|
vkQueuePresentKHR = (PFN_vkQueuePresentKHR) load("vkQueuePresentKHR", userptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int glad_vk_get_extensions( VkPhysicalDevice physical_device, uint32_t *out_extension_count, char ***out_extensions) {
|
||||||
|
uint32_t i;
|
||||||
|
uint32_t instance_extension_count = 0;
|
||||||
|
uint32_t device_extension_count = 0;
|
||||||
|
uint32_t max_extension_count;
|
||||||
|
uint32_t total_extension_count;
|
||||||
|
char **extensions;
|
||||||
|
VkExtensionProperties *ext_properties;
|
||||||
|
VkResult result;
|
||||||
|
|
||||||
|
if (vkEnumerateInstanceExtensionProperties == NULL || (physical_device != NULL && vkEnumerateDeviceExtensionProperties == NULL)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = vkEnumerateInstanceExtensionProperties(NULL, &instance_extension_count, NULL);
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (physical_device != NULL) {
|
||||||
|
result = vkEnumerateDeviceExtensionProperties(physical_device, NULL, &device_extension_count, NULL);
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
total_extension_count = instance_extension_count + device_extension_count;
|
||||||
|
max_extension_count = instance_extension_count > device_extension_count
|
||||||
|
? instance_extension_count : device_extension_count;
|
||||||
|
|
||||||
|
ext_properties = (VkExtensionProperties*) malloc(max_extension_count * sizeof(VkExtensionProperties));
|
||||||
|
if (ext_properties == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = vkEnumerateInstanceExtensionProperties(NULL, &instance_extension_count, ext_properties);
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
free((void*) ext_properties);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extensions = (char**) calloc(total_extension_count, sizeof(char*));
|
||||||
|
if (extensions == NULL) {
|
||||||
|
free((void*) ext_properties);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < instance_extension_count; ++i) {
|
||||||
|
VkExtensionProperties ext = ext_properties[i];
|
||||||
|
|
||||||
|
size_t extension_name_length = strlen(ext.extensionName) + 1;
|
||||||
|
extensions[i] = (char*) malloc(extension_name_length * sizeof(char));
|
||||||
|
memcpy(extensions[i], ext.extensionName, extension_name_length * sizeof(char));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (physical_device != NULL) {
|
||||||
|
result = vkEnumerateDeviceExtensionProperties(physical_device, NULL, &device_extension_count, ext_properties);
|
||||||
|
if (result != VK_SUCCESS) {
|
||||||
|
for (i = 0; i < instance_extension_count; ++i) {
|
||||||
|
free((void*) extensions[i]);
|
||||||
|
}
|
||||||
|
free(extensions);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < device_extension_count; ++i) {
|
||||||
|
VkExtensionProperties ext = ext_properties[i];
|
||||||
|
|
||||||
|
size_t extension_name_length = strlen(ext.extensionName) + 1;
|
||||||
|
extensions[instance_extension_count + i] = (char*) malloc(extension_name_length * sizeof(char));
|
||||||
|
memcpy(extensions[instance_extension_count + i], ext.extensionName, extension_name_length * sizeof(char));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free((void*) ext_properties);
|
||||||
|
|
||||||
|
*out_extension_count = total_extension_count;
|
||||||
|
*out_extensions = extensions;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void glad_vk_free_extensions(uint32_t extension_count, char **extensions) {
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
for(i = 0; i < extension_count ; ++i) {
|
||||||
|
free((void*) (extensions[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
free((void*) extensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int glad_vk_has_extension(const char *name, uint32_t extension_count, char **extensions) {
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < extension_count; ++i) {
|
||||||
|
if(strcmp(name, extensions[i]) == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GLADapiproc glad_vk_get_proc_from_userptr(const char* name, void *userptr) {
|
||||||
|
return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int glad_vk_find_extensions_vulkan( VkPhysicalDevice physical_device) {
|
||||||
|
uint32_t extension_count = 0;
|
||||||
|
char **extensions = NULL;
|
||||||
|
if (!glad_vk_get_extensions(physical_device, &extension_count, &extensions)) return 0;
|
||||||
|
|
||||||
|
GLAD_VK_EXT_debug_report = glad_vk_has_extension("VK_EXT_debug_report", extension_count, extensions);
|
||||||
|
GLAD_VK_KHR_surface = glad_vk_has_extension("VK_KHR_surface", extension_count, extensions);
|
||||||
|
GLAD_VK_KHR_swapchain = glad_vk_has_extension("VK_KHR_swapchain", extension_count, extensions);
|
||||||
|
|
||||||
|
glad_vk_free_extensions(extension_count, extensions);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int glad_vk_find_core_vulkan( VkPhysicalDevice physical_device) {
|
||||||
|
int major = 1;
|
||||||
|
int minor = 0;
|
||||||
|
|
||||||
|
#ifdef VK_VERSION_1_1
|
||||||
|
if (vkEnumerateInstanceVersion != NULL) {
|
||||||
|
uint32_t version;
|
||||||
|
VkResult result;
|
||||||
|
|
||||||
|
result = vkEnumerateInstanceVersion(&version);
|
||||||
|
if (result == VK_SUCCESS) {
|
||||||
|
major = (int) VK_VERSION_MAJOR(version);
|
||||||
|
minor = (int) VK_VERSION_MINOR(version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (physical_device != NULL && vkGetPhysicalDeviceProperties != NULL) {
|
||||||
|
VkPhysicalDeviceProperties properties;
|
||||||
|
vkGetPhysicalDeviceProperties(physical_device, &properties);
|
||||||
|
|
||||||
|
major = (int) VK_VERSION_MAJOR(properties.apiVersion);
|
||||||
|
minor = (int) VK_VERSION_MINOR(properties.apiVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLAD_VK_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1;
|
||||||
|
GLAD_VK_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1;
|
||||||
|
|
||||||
|
return GLAD_MAKE_VERSION(major, minor);
|
||||||
|
}
|
||||||
|
|
||||||
|
int gladLoadVulkanUserPtr( VkPhysicalDevice physical_device, GLADuserptrloadfunc load, void *userptr) {
|
||||||
|
int version;
|
||||||
|
|
||||||
|
#ifdef VK_VERSION_1_1
|
||||||
|
vkEnumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion) load("vkEnumerateInstanceVersion", userptr);
|
||||||
|
#endif
|
||||||
|
version = glad_vk_find_core_vulkan( physical_device);
|
||||||
|
if (!version) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
glad_vk_load_VK_VERSION_1_0(load, userptr);
|
||||||
|
glad_vk_load_VK_VERSION_1_1(load, userptr);
|
||||||
|
|
||||||
|
if (!glad_vk_find_extensions_vulkan( physical_device)) return 0;
|
||||||
|
glad_vk_load_VK_EXT_debug_report(load, userptr);
|
||||||
|
glad_vk_load_VK_KHR_surface(load, userptr);
|
||||||
|
glad_vk_load_VK_KHR_swapchain(load, userptr);
|
||||||
|
|
||||||
|
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int gladLoadVulkan( VkPhysicalDevice physical_device, GLADloadfunc load) {
|
||||||
|
return gladLoadVulkanUserPtr( physical_device, glad_vk_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
574
assignment-2a/ext/glfw/deps/linmath.h
Executable file
|
@ -0,0 +1,574 @@
|
||||||
|
#ifndef LINMATH_H
|
||||||
|
#define LINMATH_H
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define inline __inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define LINMATH_H_DEFINE_VEC(n) \
|
||||||
|
typedef float vec##n[n]; \
|
||||||
|
static inline void vec##n##_add(vec##n r, vec##n const a, vec##n const b) \
|
||||||
|
{ \
|
||||||
|
int i; \
|
||||||
|
for(i=0; i<n; ++i) \
|
||||||
|
r[i] = a[i] + b[i]; \
|
||||||
|
} \
|
||||||
|
static inline void vec##n##_sub(vec##n r, vec##n const a, vec##n const b) \
|
||||||
|
{ \
|
||||||
|
int i; \
|
||||||
|
for(i=0; i<n; ++i) \
|
||||||
|
r[i] = a[i] - b[i]; \
|
||||||
|
} \
|
||||||
|
static inline void vec##n##_scale(vec##n r, vec##n const v, float const s) \
|
||||||
|
{ \
|
||||||
|
int i; \
|
||||||
|
for(i=0; i<n; ++i) \
|
||||||
|
r[i] = v[i] * s; \
|
||||||
|
} \
|
||||||
|
static inline float vec##n##_mul_inner(vec##n const a, vec##n const b) \
|
||||||
|
{ \
|
||||||
|
float p = 0.; \
|
||||||
|
int i; \
|
||||||
|
for(i=0; i<n; ++i) \
|
||||||
|
p += b[i]*a[i]; \
|
||||||
|
return p; \
|
||||||
|
} \
|
||||||
|
static inline float vec##n##_len(vec##n const v) \
|
||||||
|
{ \
|
||||||
|
return (float) sqrt(vec##n##_mul_inner(v,v)); \
|
||||||
|
} \
|
||||||
|
static inline void vec##n##_norm(vec##n r, vec##n const v) \
|
||||||
|
{ \
|
||||||
|
float k = 1.f / vec##n##_len(v); \
|
||||||
|
vec##n##_scale(r, v, k); \
|
||||||
|
}
|
||||||
|
|
||||||
|
LINMATH_H_DEFINE_VEC(2)
|
||||||
|
LINMATH_H_DEFINE_VEC(3)
|
||||||
|
LINMATH_H_DEFINE_VEC(4)
|
||||||
|
|
||||||
|
static inline void vec3_mul_cross(vec3 r, vec3 const a, vec3 const b)
|
||||||
|
{
|
||||||
|
r[0] = a[1]*b[2] - a[2]*b[1];
|
||||||
|
r[1] = a[2]*b[0] - a[0]*b[2];
|
||||||
|
r[2] = a[0]*b[1] - a[1]*b[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void vec3_reflect(vec3 r, vec3 const v, vec3 const n)
|
||||||
|
{
|
||||||
|
float p = 2.f*vec3_mul_inner(v, n);
|
||||||
|
int i;
|
||||||
|
for(i=0;i<3;++i)
|
||||||
|
r[i] = v[i] - p*n[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void vec4_mul_cross(vec4 r, vec4 a, vec4 b)
|
||||||
|
{
|
||||||
|
r[0] = a[1]*b[2] - a[2]*b[1];
|
||||||
|
r[1] = a[2]*b[0] - a[0]*b[2];
|
||||||
|
r[2] = a[0]*b[1] - a[1]*b[0];
|
||||||
|
r[3] = 1.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void vec4_reflect(vec4 r, vec4 v, vec4 n)
|
||||||
|
{
|
||||||
|
float p = 2.f*vec4_mul_inner(v, n);
|
||||||
|
int i;
|
||||||
|
for(i=0;i<4;++i)
|
||||||
|
r[i] = v[i] - p*n[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef vec4 mat4x4[4];
|
||||||
|
static inline void mat4x4_identity(mat4x4 M)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
for(i=0; i<4; ++i)
|
||||||
|
for(j=0; j<4; ++j)
|
||||||
|
M[i][j] = i==j ? 1.f : 0.f;
|
||||||
|
}
|
||||||
|
static inline void mat4x4_dup(mat4x4 M, mat4x4 N)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
for(i=0; i<4; ++i)
|
||||||
|
for(j=0; j<4; ++j)
|
||||||
|
M[i][j] = N[i][j];
|
||||||
|
}
|
||||||
|
static inline void mat4x4_row(vec4 r, mat4x4 M, int i)
|
||||||
|
{
|
||||||
|
int k;
|
||||||
|
for(k=0; k<4; ++k)
|
||||||
|
r[k] = M[k][i];
|
||||||
|
}
|
||||||
|
static inline void mat4x4_col(vec4 r, mat4x4 M, int i)
|
||||||
|
{
|
||||||
|
int k;
|
||||||
|
for(k=0; k<4; ++k)
|
||||||
|
r[k] = M[i][k];
|
||||||
|
}
|
||||||
|
static inline void mat4x4_transpose(mat4x4 M, mat4x4 N)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
for(j=0; j<4; ++j)
|
||||||
|
for(i=0; i<4; ++i)
|
||||||
|
M[i][j] = N[j][i];
|
||||||
|
}
|
||||||
|
static inline void mat4x4_add(mat4x4 M, mat4x4 a, mat4x4 b)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i=0; i<4; ++i)
|
||||||
|
vec4_add(M[i], a[i], b[i]);
|
||||||
|
}
|
||||||
|
static inline void mat4x4_sub(mat4x4 M, mat4x4 a, mat4x4 b)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i=0; i<4; ++i)
|
||||||
|
vec4_sub(M[i], a[i], b[i]);
|
||||||
|
}
|
||||||
|
static inline void mat4x4_scale(mat4x4 M, mat4x4 a, float k)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i=0; i<4; ++i)
|
||||||
|
vec4_scale(M[i], a[i], k);
|
||||||
|
}
|
||||||
|
static inline void mat4x4_scale_aniso(mat4x4 M, mat4x4 a, float x, float y, float z)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
vec4_scale(M[0], a[0], x);
|
||||||
|
vec4_scale(M[1], a[1], y);
|
||||||
|
vec4_scale(M[2], a[2], z);
|
||||||
|
for(i = 0; i < 4; ++i) {
|
||||||
|
M[3][i] = a[3][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static inline void mat4x4_mul(mat4x4 M, mat4x4 a, mat4x4 b)
|
||||||
|
{
|
||||||
|
mat4x4 temp;
|
||||||
|
int k, r, c;
|
||||||
|
for(c=0; c<4; ++c) for(r=0; r<4; ++r) {
|
||||||
|
temp[c][r] = 0.f;
|
||||||
|
for(k=0; k<4; ++k)
|
||||||
|
temp[c][r] += a[k][r] * b[c][k];
|
||||||
|
}
|
||||||
|
mat4x4_dup(M, temp);
|
||||||
|
}
|
||||||
|
static inline void mat4x4_mul_vec4(vec4 r, mat4x4 M, vec4 v)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
for(j=0; j<4; ++j) {
|
||||||
|
r[j] = 0.f;
|
||||||
|
for(i=0; i<4; ++i)
|
||||||
|
r[j] += M[i][j] * v[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static inline void mat4x4_translate(mat4x4 T, float x, float y, float z)
|
||||||
|
{
|
||||||
|
mat4x4_identity(T);
|
||||||
|
T[3][0] = x;
|
||||||
|
T[3][1] = y;
|
||||||
|
T[3][2] = z;
|
||||||
|
}
|
||||||
|
static inline void mat4x4_translate_in_place(mat4x4 M, float x, float y, float z)
|
||||||
|
{
|
||||||
|
vec4 t = {x, y, z, 0};
|
||||||
|
vec4 r;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 4; ++i) {
|
||||||
|
mat4x4_row(r, M, i);
|
||||||
|
M[3][i] += vec4_mul_inner(r, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static inline void mat4x4_from_vec3_mul_outer(mat4x4 M, vec3 a, vec3 b)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
for(i=0; i<4; ++i) for(j=0; j<4; ++j)
|
||||||
|
M[i][j] = i<3 && j<3 ? a[i] * b[j] : 0.f;
|
||||||
|
}
|
||||||
|
static inline void mat4x4_rotate(mat4x4 R, mat4x4 M, float x, float y, float z, float angle)
|
||||||
|
{
|
||||||
|
float s = sinf(angle);
|
||||||
|
float c = cosf(angle);
|
||||||
|
vec3 u = {x, y, z};
|
||||||
|
|
||||||
|
if(vec3_len(u) > 1e-4) {
|
||||||
|
mat4x4 T, C, S = {{0}};
|
||||||
|
|
||||||
|
vec3_norm(u, u);
|
||||||
|
mat4x4_from_vec3_mul_outer(T, u, u);
|
||||||
|
|
||||||
|
S[1][2] = u[0];
|
||||||
|
S[2][1] = -u[0];
|
||||||
|
S[2][0] = u[1];
|
||||||
|
S[0][2] = -u[1];
|
||||||
|
S[0][1] = u[2];
|
||||||
|
S[1][0] = -u[2];
|
||||||
|
|
||||||
|
mat4x4_scale(S, S, s);
|
||||||
|
|
||||||
|
mat4x4_identity(C);
|
||||||
|
mat4x4_sub(C, C, T);
|
||||||
|
|
||||||
|
mat4x4_scale(C, C, c);
|
||||||
|
|
||||||
|
mat4x4_add(T, T, C);
|
||||||
|
mat4x4_add(T, T, S);
|
||||||
|
|
||||||
|
T[3][3] = 1.;
|
||||||
|
mat4x4_mul(R, M, T);
|
||||||
|
} else {
|
||||||
|
mat4x4_dup(R, M);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static inline void mat4x4_rotate_X(mat4x4 Q, mat4x4 M, float angle)
|
||||||
|
{
|
||||||
|
float s = sinf(angle);
|
||||||
|
float c = cosf(angle);
|
||||||
|
mat4x4 R = {
|
||||||
|
{1.f, 0.f, 0.f, 0.f},
|
||||||
|
{0.f, c, s, 0.f},
|
||||||
|
{0.f, -s, c, 0.f},
|
||||||
|
{0.f, 0.f, 0.f, 1.f}
|
||||||
|
};
|
||||||
|
mat4x4_mul(Q, M, R);
|
||||||
|
}
|
||||||
|
static inline void mat4x4_rotate_Y(mat4x4 Q, mat4x4 M, float angle)
|
||||||
|
{
|
||||||
|
float s = sinf(angle);
|
||||||
|
float c = cosf(angle);
|
||||||
|
mat4x4 R = {
|
||||||
|
{ c, 0.f, s, 0.f},
|
||||||
|
{ 0.f, 1.f, 0.f, 0.f},
|
||||||
|
{ -s, 0.f, c, 0.f},
|
||||||
|
{ 0.f, 0.f, 0.f, 1.f}
|
||||||
|
};
|
||||||
|
mat4x4_mul(Q, M, R);
|
||||||
|
}
|
||||||
|
static inline void mat4x4_rotate_Z(mat4x4 Q, mat4x4 M, float angle)
|
||||||
|
{
|
||||||
|
float s = sinf(angle);
|
||||||
|
float c = cosf(angle);
|
||||||
|
mat4x4 R = {
|
||||||
|
{ c, s, 0.f, 0.f},
|
||||||
|
{ -s, c, 0.f, 0.f},
|
||||||
|
{ 0.f, 0.f, 1.f, 0.f},
|
||||||
|
{ 0.f, 0.f, 0.f, 1.f}
|
||||||
|
};
|
||||||
|
mat4x4_mul(Q, M, R);
|
||||||
|
}
|
||||||
|
static inline void mat4x4_invert(mat4x4 T, mat4x4 M)
|
||||||
|
{
|
||||||
|
float idet;
|
||||||
|
float s[6];
|
||||||
|
float c[6];
|
||||||
|
s[0] = M[0][0]*M[1][1] - M[1][0]*M[0][1];
|
||||||
|
s[1] = M[0][0]*M[1][2] - M[1][0]*M[0][2];
|
||||||
|
s[2] = M[0][0]*M[1][3] - M[1][0]*M[0][3];
|
||||||
|
s[3] = M[0][1]*M[1][2] - M[1][1]*M[0][2];
|
||||||
|
s[4] = M[0][1]*M[1][3] - M[1][1]*M[0][3];
|
||||||
|
s[5] = M[0][2]*M[1][3] - M[1][2]*M[0][3];
|
||||||
|
|
||||||
|
c[0] = M[2][0]*M[3][1] - M[3][0]*M[2][1];
|
||||||
|
c[1] = M[2][0]*M[3][2] - M[3][0]*M[2][2];
|
||||||
|
c[2] = M[2][0]*M[3][3] - M[3][0]*M[2][3];
|
||||||
|
c[3] = M[2][1]*M[3][2] - M[3][1]*M[2][2];
|
||||||
|
c[4] = M[2][1]*M[3][3] - M[3][1]*M[2][3];
|
||||||
|
c[5] = M[2][2]*M[3][3] - M[3][2]*M[2][3];
|
||||||
|
|
||||||
|
/* Assumes it is invertible */
|
||||||
|
idet = 1.0f/( s[0]*c[5]-s[1]*c[4]+s[2]*c[3]+s[3]*c[2]-s[4]*c[1]+s[5]*c[0] );
|
||||||
|
|
||||||
|
T[0][0] = ( M[1][1] * c[5] - M[1][2] * c[4] + M[1][3] * c[3]) * idet;
|
||||||
|
T[0][1] = (-M[0][1] * c[5] + M[0][2] * c[4] - M[0][3] * c[3]) * idet;
|
||||||
|
T[0][2] = ( M[3][1] * s[5] - M[3][2] * s[4] + M[3][3] * s[3]) * idet;
|
||||||
|
T[0][3] = (-M[2][1] * s[5] + M[2][2] * s[4] - M[2][3] * s[3]) * idet;
|
||||||
|
|
||||||
|
T[1][0] = (-M[1][0] * c[5] + M[1][2] * c[2] - M[1][3] * c[1]) * idet;
|
||||||
|
T[1][1] = ( M[0][0] * c[5] - M[0][2] * c[2] + M[0][3] * c[1]) * idet;
|
||||||
|
T[1][2] = (-M[3][0] * s[5] + M[3][2] * s[2] - M[3][3] * s[1]) * idet;
|
||||||
|
T[1][3] = ( M[2][0] * s[5] - M[2][2] * s[2] + M[2][3] * s[1]) * idet;
|
||||||
|
|
||||||
|
T[2][0] = ( M[1][0] * c[4] - M[1][1] * c[2] + M[1][3] * c[0]) * idet;
|
||||||
|
T[2][1] = (-M[0][0] * c[4] + M[0][1] * c[2] - M[0][3] * c[0]) * idet;
|
||||||
|
T[2][2] = ( M[3][0] * s[4] - M[3][1] * s[2] + M[3][3] * s[0]) * idet;
|
||||||
|
T[2][3] = (-M[2][0] * s[4] + M[2][1] * s[2] - M[2][3] * s[0]) * idet;
|
||||||
|
|
||||||
|
T[3][0] = (-M[1][0] * c[3] + M[1][1] * c[1] - M[1][2] * c[0]) * idet;
|
||||||
|
T[3][1] = ( M[0][0] * c[3] - M[0][1] * c[1] + M[0][2] * c[0]) * idet;
|
||||||
|
T[3][2] = (-M[3][0] * s[3] + M[3][1] * s[1] - M[3][2] * s[0]) * idet;
|
||||||
|
T[3][3] = ( M[2][0] * s[3] - M[2][1] * s[1] + M[2][2] * s[0]) * idet;
|
||||||
|
}
|
||||||
|
static inline void mat4x4_orthonormalize(mat4x4 R, mat4x4 M)
|
||||||
|
{
|
||||||
|
float s = 1.;
|
||||||
|
vec3 h;
|
||||||
|
|
||||||
|
mat4x4_dup(R, M);
|
||||||
|
vec3_norm(R[2], R[2]);
|
||||||
|
|
||||||
|
s = vec3_mul_inner(R[1], R[2]);
|
||||||
|
vec3_scale(h, R[2], s);
|
||||||
|
vec3_sub(R[1], R[1], h);
|
||||||
|
vec3_norm(R[2], R[2]);
|
||||||
|
|
||||||
|
s = vec3_mul_inner(R[1], R[2]);
|
||||||
|
vec3_scale(h, R[2], s);
|
||||||
|
vec3_sub(R[1], R[1], h);
|
||||||
|
vec3_norm(R[1], R[1]);
|
||||||
|
|
||||||
|
s = vec3_mul_inner(R[0], R[1]);
|
||||||
|
vec3_scale(h, R[1], s);
|
||||||
|
vec3_sub(R[0], R[0], h);
|
||||||
|
vec3_norm(R[0], R[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void mat4x4_frustum(mat4x4 M, float l, float r, float b, float t, float n, float f)
|
||||||
|
{
|
||||||
|
M[0][0] = 2.f*n/(r-l);
|
||||||
|
M[0][1] = M[0][2] = M[0][3] = 0.f;
|
||||||
|
|
||||||
|
M[1][1] = 2.f*n/(t-b);
|
||||||
|
M[1][0] = M[1][2] = M[1][3] = 0.f;
|
||||||
|
|
||||||
|
M[2][0] = (r+l)/(r-l);
|
||||||
|
M[2][1] = (t+b)/(t-b);
|
||||||
|
M[2][2] = -(f+n)/(f-n);
|
||||||
|
M[2][3] = -1.f;
|
||||||
|
|
||||||
|
M[3][2] = -2.f*(f*n)/(f-n);
|
||||||
|
M[3][0] = M[3][1] = M[3][3] = 0.f;
|
||||||
|
}
|
||||||
|
static inline void mat4x4_ortho(mat4x4 M, float l, float r, float b, float t, float n, float f)
|
||||||
|
{
|
||||||
|
M[0][0] = 2.f/(r-l);
|
||||||
|
M[0][1] = M[0][2] = M[0][3] = 0.f;
|
||||||
|
|
||||||
|
M[1][1] = 2.f/(t-b);
|
||||||
|
M[1][0] = M[1][2] = M[1][3] = 0.f;
|
||||||
|
|
||||||
|
M[2][2] = -2.f/(f-n);
|
||||||
|
M[2][0] = M[2][1] = M[2][3] = 0.f;
|
||||||
|
|
||||||
|
M[3][0] = -(r+l)/(r-l);
|
||||||
|
M[3][1] = -(t+b)/(t-b);
|
||||||
|
M[3][2] = -(f+n)/(f-n);
|
||||||
|
M[3][3] = 1.f;
|
||||||
|
}
|
||||||
|
static inline void mat4x4_perspective(mat4x4 m, float y_fov, float aspect, float n, float f)
|
||||||
|
{
|
||||||
|
/* NOTE: Degrees are an unhandy unit to work with.
|
||||||
|
* linmath.h uses radians for everything! */
|
||||||
|
float const a = 1.f / (float) tan(y_fov / 2.f);
|
||||||
|
|
||||||
|
m[0][0] = a / aspect;
|
||||||
|
m[0][1] = 0.f;
|
||||||
|
m[0][2] = 0.f;
|
||||||
|
m[0][3] = 0.f;
|
||||||
|
|
||||||
|
m[1][0] = 0.f;
|
||||||
|
m[1][1] = a;
|
||||||
|
m[1][2] = 0.f;
|
||||||
|
m[1][3] = 0.f;
|
||||||
|
|
||||||
|
m[2][0] = 0.f;
|
||||||
|
m[2][1] = 0.f;
|
||||||
|
m[2][2] = -((f + n) / (f - n));
|
||||||
|
m[2][3] = -1.f;
|
||||||
|
|
||||||
|
m[3][0] = 0.f;
|
||||||
|
m[3][1] = 0.f;
|
||||||
|
m[3][2] = -((2.f * f * n) / (f - n));
|
||||||
|
m[3][3] = 0.f;
|
||||||
|
}
|
||||||
|
static inline void mat4x4_look_at(mat4x4 m, vec3 eye, vec3 center, vec3 up)
|
||||||
|
{
|
||||||
|
/* Adapted from Android's OpenGL Matrix.java. */
|
||||||
|
/* See the OpenGL GLUT documentation for gluLookAt for a description */
|
||||||
|
/* of the algorithm. We implement it in a straightforward way: */
|
||||||
|
|
||||||
|
/* TODO: The negation of of can be spared by swapping the order of
|
||||||
|
* operands in the following cross products in the right way. */
|
||||||
|
vec3 f;
|
||||||
|
vec3 s;
|
||||||
|
vec3 t;
|
||||||
|
|
||||||
|
vec3_sub(f, center, eye);
|
||||||
|
vec3_norm(f, f);
|
||||||
|
|
||||||
|
vec3_mul_cross(s, f, up);
|
||||||
|
vec3_norm(s, s);
|
||||||
|
|
||||||
|
vec3_mul_cross(t, s, f);
|
||||||
|
|
||||||
|
m[0][0] = s[0];
|
||||||
|
m[0][1] = t[0];
|
||||||
|
m[0][2] = -f[0];
|
||||||
|
m[0][3] = 0.f;
|
||||||
|
|
||||||
|
m[1][0] = s[1];
|
||||||
|
m[1][1] = t[1];
|
||||||
|
m[1][2] = -f[1];
|
||||||
|
m[1][3] = 0.f;
|
||||||
|
|
||||||
|
m[2][0] = s[2];
|
||||||
|
m[2][1] = t[2];
|
||||||
|
m[2][2] = -f[2];
|
||||||
|
m[2][3] = 0.f;
|
||||||
|
|
||||||
|
m[3][0] = 0.f;
|
||||||
|
m[3][1] = 0.f;
|
||||||
|
m[3][2] = 0.f;
|
||||||
|
m[3][3] = 1.f;
|
||||||
|
|
||||||
|
mat4x4_translate_in_place(m, -eye[0], -eye[1], -eye[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef float quat[4];
|
||||||
|
static inline void quat_identity(quat q)
|
||||||
|
{
|
||||||
|
q[0] = q[1] = q[2] = 0.f;
|
||||||
|
q[3] = 1.f;
|
||||||
|
}
|
||||||
|
static inline void quat_add(quat r, quat a, quat b)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i=0; i<4; ++i)
|
||||||
|
r[i] = a[i] + b[i];
|
||||||
|
}
|
||||||
|
static inline void quat_sub(quat r, quat a, quat b)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i=0; i<4; ++i)
|
||||||
|
r[i] = a[i] - b[i];
|
||||||
|
}
|
||||||
|
static inline void quat_mul(quat r, quat p, quat q)
|
||||||
|
{
|
||||||
|
vec3 w;
|
||||||
|
vec3_mul_cross(r, p, q);
|
||||||
|
vec3_scale(w, p, q[3]);
|
||||||
|
vec3_add(r, r, w);
|
||||||
|
vec3_scale(w, q, p[3]);
|
||||||
|
vec3_add(r, r, w);
|
||||||
|
r[3] = p[3]*q[3] - vec3_mul_inner(p, q);
|
||||||
|
}
|
||||||
|
static inline void quat_scale(quat r, quat v, float s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i=0; i<4; ++i)
|
||||||
|
r[i] = v[i] * s;
|
||||||
|
}
|
||||||
|
static inline float quat_inner_product(quat a, quat b)
|
||||||
|
{
|
||||||
|
float p = 0.f;
|
||||||
|
int i;
|
||||||
|
for(i=0; i<4; ++i)
|
||||||
|
p += b[i]*a[i];
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
static inline void quat_conj(quat r, quat q)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i=0; i<3; ++i)
|
||||||
|
r[i] = -q[i];
|
||||||
|
r[3] = q[3];
|
||||||
|
}
|
||||||
|
static inline void quat_rotate(quat r, float angle, vec3 axis) {
|
||||||
|
int i;
|
||||||
|
vec3 v;
|
||||||
|
vec3_scale(v, axis, sinf(angle / 2));
|
||||||
|
for(i=0; i<3; ++i)
|
||||||
|
r[i] = v[i];
|
||||||
|
r[3] = cosf(angle / 2);
|
||||||
|
}
|
||||||
|
#define quat_norm vec4_norm
|
||||||
|
static inline void quat_mul_vec3(vec3 r, quat q, vec3 v)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Method by Fabian 'ryg' Giessen (of Farbrausch)
|
||||||
|
t = 2 * cross(q.xyz, v)
|
||||||
|
v' = v + q.w * t + cross(q.xyz, t)
|
||||||
|
*/
|
||||||
|
vec3 t = {q[0], q[1], q[2]};
|
||||||
|
vec3 u = {q[0], q[1], q[2]};
|
||||||
|
|
||||||
|
vec3_mul_cross(t, t, v);
|
||||||
|
vec3_scale(t, t, 2);
|
||||||
|
|
||||||
|
vec3_mul_cross(u, u, t);
|
||||||
|
vec3_scale(t, t, q[3]);
|
||||||
|
|
||||||
|
vec3_add(r, v, t);
|
||||||
|
vec3_add(r, r, u);
|
||||||
|
}
|
||||||
|
static inline void mat4x4_from_quat(mat4x4 M, quat q)
|
||||||
|
{
|
||||||
|
float a = q[3];
|
||||||
|
float b = q[0];
|
||||||
|
float c = q[1];
|
||||||
|
float d = q[2];
|
||||||
|
float a2 = a*a;
|
||||||
|
float b2 = b*b;
|
||||||
|
float c2 = c*c;
|
||||||
|
float d2 = d*d;
|
||||||
|
|
||||||
|
M[0][0] = a2 + b2 - c2 - d2;
|
||||||
|
M[0][1] = 2.f*(b*c + a*d);
|
||||||
|
M[0][2] = 2.f*(b*d - a*c);
|
||||||
|
M[0][3] = 0.f;
|
||||||
|
|
||||||
|
M[1][0] = 2*(b*c - a*d);
|
||||||
|
M[1][1] = a2 - b2 + c2 - d2;
|
||||||
|
M[1][2] = 2.f*(c*d + a*b);
|
||||||
|
M[1][3] = 0.f;
|
||||||
|
|
||||||
|
M[2][0] = 2.f*(b*d + a*c);
|
||||||
|
M[2][1] = 2.f*(c*d - a*b);
|
||||||
|
M[2][2] = a2 - b2 - c2 + d2;
|
||||||
|
M[2][3] = 0.f;
|
||||||
|
|
||||||
|
M[3][0] = M[3][1] = M[3][2] = 0.f;
|
||||||
|
M[3][3] = 1.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void mat4x4o_mul_quat(mat4x4 R, mat4x4 M, quat q)
|
||||||
|
{
|
||||||
|
/* XXX: The way this is written only works for othogonal matrices. */
|
||||||
|
/* TODO: Take care of non-orthogonal case. */
|
||||||
|
quat_mul_vec3(R[0], q, M[0]);
|
||||||
|
quat_mul_vec3(R[1], q, M[1]);
|
||||||
|
quat_mul_vec3(R[2], q, M[2]);
|
||||||
|
|
||||||
|
R[3][0] = R[3][1] = R[3][2] = 0.f;
|
||||||
|
R[3][3] = 1.f;
|
||||||
|
}
|
||||||
|
static inline void quat_from_mat4x4(quat q, mat4x4 M)
|
||||||
|
{
|
||||||
|
float r=0.f;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
int perm[] = { 0, 1, 2, 0, 1 };
|
||||||
|
int *p = perm;
|
||||||
|
|
||||||
|
for(i = 0; i<3; i++) {
|
||||||
|
float m = M[i][i];
|
||||||
|
if( m < r )
|
||||||
|
continue;
|
||||||
|
m = r;
|
||||||
|
p = &perm[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
r = (float) sqrt(1.f + M[p[0]][p[0]] - M[p[1]][p[1]] - M[p[2]][p[2]] );
|
||||||
|
|
||||||
|
if(r < 1e-6) {
|
||||||
|
q[0] = 1.f;
|
||||||
|
q[1] = q[2] = q[3] = 0.f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
q[0] = r/2.f;
|
||||||
|
q[1] = (M[p[0]][p[1]] - M[p[1]][p[0]])/(2.f*r);
|
||||||
|
q[2] = (M[p[2]][p[0]] - M[p[0]][p[2]])/(2.f*r);
|
||||||
|
q[3] = (M[p[2]][p[1]] - M[p[1]][p[2]])/(2.f*r);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
117
assignment-2a/ext/glfw/deps/mingw/_mingw_dxhelper.h
Executable file
|
@ -0,0 +1,117 @@
|
||||||
|
/**
|
||||||
|
* This file has no copyright assigned and is placed in the Public Domain.
|
||||||
|
* This file is part of the mingw-w64 runtime package.
|
||||||
|
* No warranty is given; refer to the file DISCLAIMER within this package.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && !defined(_MSC_EXTENSIONS)
|
||||||
|
#define NONAMELESSUNION 1
|
||||||
|
#endif
|
||||||
|
#if defined(NONAMELESSSTRUCT) && \
|
||||||
|
!defined(NONAMELESSUNION)
|
||||||
|
#define NONAMELESSUNION 1
|
||||||
|
#endif
|
||||||
|
#if defined(NONAMELESSUNION) && \
|
||||||
|
!defined(NONAMELESSSTRUCT)
|
||||||
|
#define NONAMELESSSTRUCT 1
|
||||||
|
#endif
|
||||||
|
#if !defined(__GNU_EXTENSION)
|
||||||
|
#if defined(__GNUC__) || defined(__GNUG__)
|
||||||
|
#define __GNU_EXTENSION __extension__
|
||||||
|
#else
|
||||||
|
#define __GNU_EXTENSION
|
||||||
|
#endif
|
||||||
|
#endif /* __extension__ */
|
||||||
|
|
||||||
|
#ifndef __ANONYMOUS_DEFINED
|
||||||
|
#define __ANONYMOUS_DEFINED
|
||||||
|
#if defined(__GNUC__) || defined(__GNUG__)
|
||||||
|
#define _ANONYMOUS_UNION __extension__
|
||||||
|
#define _ANONYMOUS_STRUCT __extension__
|
||||||
|
#else
|
||||||
|
#define _ANONYMOUS_UNION
|
||||||
|
#define _ANONYMOUS_STRUCT
|
||||||
|
#endif
|
||||||
|
#ifndef NONAMELESSUNION
|
||||||
|
#define _UNION_NAME(x)
|
||||||
|
#define _STRUCT_NAME(x)
|
||||||
|
#else /* NONAMELESSUNION */
|
||||||
|
#define _UNION_NAME(x) x
|
||||||
|
#define _STRUCT_NAME(x) x
|
||||||
|
#endif
|
||||||
|
#endif /* __ANONYMOUS_DEFINED */
|
||||||
|
|
||||||
|
#ifndef DUMMYUNIONNAME
|
||||||
|
# ifdef NONAMELESSUNION
|
||||||
|
# define DUMMYUNIONNAME u
|
||||||
|
# define DUMMYUNIONNAME1 u1 /* Wine uses this variant */
|
||||||
|
# define DUMMYUNIONNAME2 u2
|
||||||
|
# define DUMMYUNIONNAME3 u3
|
||||||
|
# define DUMMYUNIONNAME4 u4
|
||||||
|
# define DUMMYUNIONNAME5 u5
|
||||||
|
# define DUMMYUNIONNAME6 u6
|
||||||
|
# define DUMMYUNIONNAME7 u7
|
||||||
|
# define DUMMYUNIONNAME8 u8
|
||||||
|
# define DUMMYUNIONNAME9 u9
|
||||||
|
# else /* NONAMELESSUNION */
|
||||||
|
# define DUMMYUNIONNAME
|
||||||
|
# define DUMMYUNIONNAME1 /* Wine uses this variant */
|
||||||
|
# define DUMMYUNIONNAME2
|
||||||
|
# define DUMMYUNIONNAME3
|
||||||
|
# define DUMMYUNIONNAME4
|
||||||
|
# define DUMMYUNIONNAME5
|
||||||
|
# define DUMMYUNIONNAME6
|
||||||
|
# define DUMMYUNIONNAME7
|
||||||
|
# define DUMMYUNIONNAME8
|
||||||
|
# define DUMMYUNIONNAME9
|
||||||
|
# endif
|
||||||
|
#endif /* DUMMYUNIONNAME */
|
||||||
|
|
||||||
|
#if !defined(DUMMYUNIONNAME1) /* MinGW does not define this one */
|
||||||
|
# ifdef NONAMELESSUNION
|
||||||
|
# define DUMMYUNIONNAME1 u1 /* Wine uses this variant */
|
||||||
|
# else
|
||||||
|
# define DUMMYUNIONNAME1 /* Wine uses this variant */
|
||||||
|
# endif
|
||||||
|
#endif /* DUMMYUNIONNAME1 */
|
||||||
|
|
||||||
|
#ifndef DUMMYSTRUCTNAME
|
||||||
|
# ifdef NONAMELESSUNION
|
||||||
|
# define DUMMYSTRUCTNAME s
|
||||||
|
# define DUMMYSTRUCTNAME1 s1 /* Wine uses this variant */
|
||||||
|
# define DUMMYSTRUCTNAME2 s2
|
||||||
|
# define DUMMYSTRUCTNAME3 s3
|
||||||
|
# define DUMMYSTRUCTNAME4 s4
|
||||||
|
# define DUMMYSTRUCTNAME5 s5
|
||||||
|
# else
|
||||||
|
# define DUMMYSTRUCTNAME
|
||||||
|
# define DUMMYSTRUCTNAME1 /* Wine uses this variant */
|
||||||
|
# define DUMMYSTRUCTNAME2
|
||||||
|
# define DUMMYSTRUCTNAME3
|
||||||
|
# define DUMMYSTRUCTNAME4
|
||||||
|
# define DUMMYSTRUCTNAME5
|
||||||
|
# endif
|
||||||
|
#endif /* DUMMYSTRUCTNAME */
|
||||||
|
|
||||||
|
/* These are for compatibility with the Wine source tree */
|
||||||
|
|
||||||
|
#ifndef WINELIB_NAME_AW
|
||||||
|
# ifdef __MINGW_NAME_AW
|
||||||
|
# define WINELIB_NAME_AW __MINGW_NAME_AW
|
||||||
|
# else
|
||||||
|
# ifdef UNICODE
|
||||||
|
# define WINELIB_NAME_AW(func) func##W
|
||||||
|
# else
|
||||||
|
# define WINELIB_NAME_AW(func) func##A
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif /* WINELIB_NAME_AW */
|
||||||
|
|
||||||
|
#ifndef DECL_WINELIB_TYPE_AW
|
||||||
|
# ifdef __MINGW_TYPEDEF_AW
|
||||||
|
# define DECL_WINELIB_TYPE_AW __MINGW_TYPEDEF_AW
|
||||||
|
# else
|
||||||
|
# define DECL_WINELIB_TYPE_AW(type) typedef WINELIB_NAME_AW(type) type;
|
||||||
|
# endif
|
||||||
|
#endif /* DECL_WINELIB_TYPE_AW */
|
||||||
|
|