Compare commits
4 Commits
main
...
reworking_
| Author | SHA1 | Date | |
|---|---|---|---|
| 7f9a700f1c | |||
| 8b9e08f076 | |||
| 0f451c715c | |||
| 1775cf90bc |
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,2 +1,2 @@
|
|||||||
*/target
|
/target
|
||||||
*/out
|
assets/models/bugatti/*
|
||||||
|
|||||||
1856
Cargo.lock
generated
Normal file
1856
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
18
Cargo.toml
Normal file
18
Cargo.toml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
[package]
|
||||||
|
name = "proj"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
dotenvy = "0.15.7"
|
||||||
|
gl = "0.14.0"
|
||||||
|
glutin = "0.32.3"
|
||||||
|
glutin-winit = "0.5.0"
|
||||||
|
raw-window-handle = "0.6.2"
|
||||||
|
thiserror = "2.0.17"
|
||||||
|
winit = "0.30.12"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
dotenvy = "0.15.7"
|
||||||
|
gl_generator = "0.14"
|
||||||
|
cfg_aliases = "0.2.1"
|
||||||
9
assets/models/bugatti/README.txt
Normal file
9
assets/models/bugatti/README.txt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
Hi, thanks for downloadiing this model.It was created by Bob Kimani (Kimz Auto).
|
||||||
|
if you like the model please feel free to donate to my PayPal account at
|
||||||
|
bobiankimani@gmail.com
|
||||||
|
Or simply buy the model for a price of your choice here
|
||||||
|
|
||||||
|
https://sellfy.com/p/FrEB/
|
||||||
|
I would reaaly appreciate it even if its just one dollar.Thanks;)
|
||||||
|
Please include this credit when you use the file.
|
||||||
|
Regards Bob :)
|
||||||
400
assets/models/bugatti/bugatti.mtl
Normal file
400
assets/models/bugatti/bugatti.mtl
Normal file
@ -0,0 +1,400 @@
|
|||||||
|
# Blender MTL File: 'bugatti.blend'
|
||||||
|
# Material Count: 40
|
||||||
|
|
||||||
|
newmtl BLUE.002
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.000000 0.000000 0.800000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl ENGINE
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl GRILL.004
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.026482 0.026482 0.026482
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl Mirrors
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl NAVY
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.000000 0.017778 0.047407
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl None
|
||||||
|
Ns 0
|
||||||
|
Ka 0.000000 0.000000 0.000000
|
||||||
|
Kd 0.8 0.8 0.8
|
||||||
|
Ks 0.8 0.8 0.8
|
||||||
|
d 1
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl Nut.004
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl Studio_Lights.004
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl Studio_Lights.005
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl Trim.004
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl WHEEL_CURB.004
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl WHITE.002
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl aluminiumm
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl back_drop.004
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl black
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.102592 0.102592 0.102592
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl black_cable
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl black_fuel_tank.004
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl black_side_vent
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.001651 0.001651 0.001651
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl black_strip.004
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.009774 0.009774 0.009774
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl black_vent.004
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl brake_disk.004
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl breaks_
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl cALLIPERS.004
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.014633 0.586055 0.640002
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl exhaust
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.204648 0.451652 0.640001
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl front_window.004
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl glass_front.004
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.054000 0.640003 0.568643
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl glossy
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.000000 0.568960 0.640002
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl headlight_glass.004
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl headlight_square.004
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl red.002
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl red_glass
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640002 0.047774 0.026908
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl reflective_coat.004
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.026482 0.026482 0.026482
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl rim_blue.004
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.026033 0.152250 0.640001
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl rim_silver.004
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl silver_door_strip.004
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640000 0.601480 0.265530
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl silver_trim
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.043975 0.043975 0.043975
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl sun
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl tyre.004
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.011736 0.011736 0.011736
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl wheel_joint.004
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
|
||||||
|
newmtl white_holders
|
||||||
|
Ns 96.078431
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.640000 0.640000 0.640000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
41
build.rs
Normal file
41
build.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
use std::env;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use cfg_aliases::cfg_aliases;
|
||||||
|
use gl_generator::{Api, Fallbacks, Profile, Registry, StructGenerator};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// XXX this is taken from glutin/build.rs.
|
||||||
|
dotenvy::dotenv().ok();
|
||||||
|
|
||||||
|
// Setup alias to reduce `cfg` boilerplate.
|
||||||
|
cfg_aliases! {
|
||||||
|
// Systems.
|
||||||
|
android_platform: { target_os = "android" },
|
||||||
|
wasm_platform: { target_family = "wasm" },
|
||||||
|
macos_platform: { target_os = "macos" },
|
||||||
|
ios_platform: { target_os = "ios" },
|
||||||
|
apple: { any(ios_platform, macos_platform) },
|
||||||
|
free_unix: { all(unix, not(apple), not(android_platform)) },
|
||||||
|
|
||||||
|
// Native displays.
|
||||||
|
x11_platform: { all(feature = "x11", free_unix, not(wasm_platform)) },
|
||||||
|
wayland_platform: { all(feature = "wayland", free_unix, not(wasm_platform)) },
|
||||||
|
|
||||||
|
// Backends.
|
||||||
|
egl_backend: { all(feature = "egl", any(windows, unix), not(apple), not(wasm_platform)) },
|
||||||
|
glx_backend: { all(feature = "glx", x11_platform, not(wasm_platform)) },
|
||||||
|
wgl_backend: { all(feature = "wgl", windows, not(wasm_platform)) },
|
||||||
|
cgl_backend: { all(macos_platform, not(wasm_platform)) },
|
||||||
|
}
|
||||||
|
|
||||||
|
let dest = PathBuf::from(&env::var("OUT_DIR").unwrap());
|
||||||
|
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
|
||||||
|
let mut file = File::create(dest.join("gl_bindings.rs")).unwrap();
|
||||||
|
Registry::new(Api::Gles2, (3, 0), Profile::Core, Fallbacks::All, [])
|
||||||
|
.write_bindings(StructGenerator, &mut file)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
235
gl_rust/Cargo.lock
generated
235
gl_rust/Cargo.lock
generated
@ -1,235 +0,0 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
|
||||||
# It is not intended for manual editing.
|
|
||||||
version = 4
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aho-corasick"
|
|
||||||
version = "1.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bindgen"
|
|
||||||
version = "0.72.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"cexpr",
|
|
||||||
"clang-sys",
|
|
||||||
"itertools",
|
|
||||||
"log",
|
|
||||||
"prettyplease",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"regex",
|
|
||||||
"rustc-hash",
|
|
||||||
"shlex",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "2.11.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cexpr"
|
|
||||||
version = "0.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
|
||||||
dependencies = [
|
|
||||||
"nom",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clang-sys"
|
|
||||||
version = "1.8.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
|
|
||||||
dependencies = [
|
|
||||||
"glob",
|
|
||||||
"libc",
|
|
||||||
"libloading",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dotenvy"
|
|
||||||
version = "0.15.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "either"
|
|
||||||
version = "1.15.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "glob"
|
|
||||||
version = "0.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "itertools"
|
|
||||||
version = "0.13.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libc"
|
|
||||||
version = "0.2.182"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libloading"
|
|
||||||
version = "0.8.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"windows-link",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "log"
|
|
||||||
version = "0.4.29"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memchr"
|
|
||||||
version = "2.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "minimal-lexical"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nom"
|
|
||||||
version = "7.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
"minimal-lexical",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "prettyplease"
|
|
||||||
version = "0.2.37"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro2"
|
|
||||||
version = "1.0.106"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
|
||||||
dependencies = [
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proj"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"bindgen",
|
|
||||||
"dotenvy",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quote"
|
|
||||||
version = "1.0.44"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex"
|
|
||||||
version = "1.12.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
|
|
||||||
dependencies = [
|
|
||||||
"aho-corasick",
|
|
||||||
"memchr",
|
|
||||||
"regex-automata",
|
|
||||||
"regex-syntax",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-automata"
|
|
||||||
version = "0.4.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
|
|
||||||
dependencies = [
|
|
||||||
"aho-corasick",
|
|
||||||
"memchr",
|
|
||||||
"regex-syntax",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-syntax"
|
|
||||||
version = "0.8.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustc-hash"
|
|
||||||
version = "2.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "shlex"
|
|
||||||
version = "1.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "syn"
|
|
||||||
version = "2.0.117"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-ident"
|
|
||||||
version = "1.0.24"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-link"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "proj"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2024"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
dotenvy = "0.15.7"
|
|
||||||
|
|
||||||
[build-dependencies]
|
|
||||||
dotenvy = "0.15.7"
|
|
||||||
bindgen = "0.72.1"
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
use bindgen::Builder;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
// XXX this is taken from glutin/build.rs.
|
|
||||||
dotenvy::dotenv().ok();
|
|
||||||
|
|
||||||
let bindings_header = "../glc/src/glc_api.h";
|
|
||||||
|
|
||||||
let bindings = Builder::default().header(bindings_header).generate().unwrap();
|
|
||||||
|
|
||||||
bindings.write_to_file("./src/glc.rs").unwrap();
|
|
||||||
|
|
||||||
println!("cargo:rerun-if-changed=build.rs");
|
|
||||||
println!("cargo:rerun-if-changed={bindings_header}");
|
|
||||||
}
|
|
||||||
@ -1,85 +0,0 @@
|
|||||||
use crate::models::{self, Model, ModelData, RenderObject, Scene, ShaderSource};
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::ffi::{ CStr, CString };
|
|
||||||
use crate::glc;
|
|
||||||
|
|
||||||
pub struct Renderer {
|
|
||||||
shaders: HashMap<String, glc::GpuUint>,
|
|
||||||
scenes: HashMap<String, Scene>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Renderer {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
shaders: HashMap::new(),
|
|
||||||
scenes: HashMap::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compile_shader(shader_kind: glc::GpuShaderType, source: &[i8]) -> glc::GpuShaderHandle {
|
|
||||||
unsafe {
|
|
||||||
let shader = glc::gpu_shader_compile(source.as_ptr(), shader_kind);
|
|
||||||
shader
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_shader(&self, shader_src: &ShaderSource) -> glc::GpuProgram {
|
|
||||||
unsafe {
|
|
||||||
program
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_shader(&mut self, name: &str, shader: gl::types::GLuint) {
|
|
||||||
if let None = self.shaders.get(name) {
|
|
||||||
self.shaders.insert(name.to_string(), shader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_shader(&self, name: &str) -> Option<&gl::types::GLuint> {
|
|
||||||
self.shaders.get(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove_shader(&mut self, name: &str) {
|
|
||||||
self.shaders.remove(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resize(&self, width: i32, height: i32) {
|
|
||||||
unsafe {
|
|
||||||
self.gl.Viewport(0, 0, width, height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn draw_object(&self, obj: &RenderObject, shader: glc::GpuShaderHandle) {
|
|
||||||
unsafe {
|
|
||||||
|
|
||||||
self.UseProgram(shader);
|
|
||||||
|
|
||||||
self.BindBuffer(gl::ARRAY_BUFFER, obj.vbo);
|
|
||||||
self.BindVertexArray(obj.vao);
|
|
||||||
|
|
||||||
self.DrawArrays(gl::TRIANGLES, 0, obj.vertex_count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render(&self, current_scene: &String) {
|
|
||||||
unsafe {
|
|
||||||
glc::gpu_clear(1.0, 1.0, 1.0, 0.9);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(scene) = self.scenes.get(current_scene) {
|
|
||||||
for model in scene.models {
|
|
||||||
self.draw_object(obj, *shader);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
eprintln!("Unknown Scene Requested: {}", current_scene);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for Renderer {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
self.shaders.values().for_each(|shader| glc::gpu_program_destroy(shader));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
10271
gl_rust/src/gl_c.rs
10271
gl_rust/src/gl_c.rs
File diff suppressed because it is too large
Load Diff
8192
gl_rust/src/glc.rs
8192
gl_rust/src/glc.rs
File diff suppressed because it is too large
Load Diff
@ -1,28 +0,0 @@
|
|||||||
pub mod models {
|
|
||||||
pub mod mesh;
|
|
||||||
pub use mesh::*;
|
|
||||||
|
|
||||||
pub mod vertex;
|
|
||||||
pub use vertex::*;
|
|
||||||
|
|
||||||
pub mod model;
|
|
||||||
pub use model::*;
|
|
||||||
|
|
||||||
pub mod scene;
|
|
||||||
pub use scene::*;
|
|
||||||
|
|
||||||
pub mod material;
|
|
||||||
pub use material::*;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod app {
|
|
||||||
pub mod renderer;
|
|
||||||
pub mod app;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod shaders {
|
|
||||||
pub mod shaders;
|
|
||||||
pub use shaders::*;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod glc;
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
use proj::{app::app::App, models::{Mesh, ModelData, ShaderSource}, shaders::{FRAGMENT_SHADER_SOURCE, VERTEX_SHADER_SOURCE}};
|
|
||||||
use winit::event_loop::EventLoop;
|
|
||||||
|
|
||||||
const TRIANGLE_OBJ_PATH: &str = "assets/models/small_house/model.obj";
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
dotenvy::dotenv().ok();
|
|
||||||
let event_loop = EventLoop::new()
|
|
||||||
.expect("Should be able to have Event Loop");
|
|
||||||
|
|
||||||
let mut mesh = Mesh::new();
|
|
||||||
if let Err(e) = mesh.load_obj(TRIANGLE_OBJ_PATH) {
|
|
||||||
panic!("{}", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
let shader_src = ShaderSource {
|
|
||||||
vertex_src: VERTEX_SHADER_SOURCE,
|
|
||||||
fragment_src: FRAGMENT_SHADER_SOURCE
|
|
||||||
};
|
|
||||||
|
|
||||||
let scene_data = ModelData {
|
|
||||||
name: "home".to_string(),
|
|
||||||
meshes: vec![(mesh)]
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut app = App::new(scene_data);
|
|
||||||
|
|
||||||
app.set_current_scene("home");
|
|
||||||
|
|
||||||
let event_res = event_loop.run_app(&mut app);
|
|
||||||
|
|
||||||
println!("{:#?}", event_res);
|
|
||||||
}
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
#[derive(Debug)]
|
|
||||||
pub struct Material {
|
|
||||||
pub ambient: [f32; 3],
|
|
||||||
pub diffuse: [f32; 3],
|
|
||||||
pub specular: [f32; 3],
|
|
||||||
pub shader_name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Material {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
ambient: Default::default(),
|
|
||||||
diffuse: Default::default(),
|
|
||||||
specular: Default::default(),
|
|
||||||
shader_name: String::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,123 +0,0 @@
|
|||||||
use crate::models::Material;
|
|
||||||
|
|
||||||
use super::Vertex;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Mesh {
|
|
||||||
pub vertices: Vec<Vertex>,
|
|
||||||
pub material_name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
const NEW_MATERIAL_DELIMITER: &str = "newmtl ";
|
|
||||||
|
|
||||||
fn parse_rgb(values: &str) -> Result<[f32; 3], Box<dyn std::error::Error>> {
|
|
||||||
let mut rgb = [0.0; 3];
|
|
||||||
let mut i = 0;
|
|
||||||
|
|
||||||
let values = values.split_whitespace();
|
|
||||||
|
|
||||||
for v in values {
|
|
||||||
let parsed = v.parse::<f32>()?;
|
|
||||||
rgb[i] = parsed;
|
|
||||||
i += 1;
|
|
||||||
if i > 2 {
|
|
||||||
todo!("Implement custom error handling: too many values");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if i != 3 {
|
|
||||||
todo!("Implement custom error handling: too few values");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(rgb)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Mesh {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
vertices: vec![],
|
|
||||||
material_name: String::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_obj(&mut self, path: &str) -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
let content = std::fs::read_to_string(path)?;
|
|
||||||
|
|
||||||
for line in content.lines() {
|
|
||||||
if line.starts_with("v ") {
|
|
||||||
let coords: Result<Vec<f32>, _> = line
|
|
||||||
.split_whitespace()
|
|
||||||
.skip(1)
|
|
||||||
.take(3)
|
|
||||||
.map(|s| s.parse::<f32>())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
match coords {
|
|
||||||
Ok(v) if v.len() == 3 => {
|
|
||||||
self.vertices.push(Vertex { x: v[0], y: v[1], z: v[2] })
|
|
||||||
},
|
|
||||||
_ => eprintln!("Warning: Invalid vertex line: {}", line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("{:#?}", self.vertices);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_material(&mut self, path: &str) -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
let content = std::fs::read_to_string(path)?;
|
|
||||||
let mut lines = content.lines().peekable();
|
|
||||||
|
|
||||||
while let Some(line) = lines.next() {
|
|
||||||
let line = line.trim();
|
|
||||||
if line.is_empty() {
|
|
||||||
continue ;
|
|
||||||
}
|
|
||||||
|
|
||||||
if line.starts_with(NEW_MATERIAL_DELIMITER) {
|
|
||||||
let mat_name = line.strip_prefix(NEW_MATERIAL_DELIMITER).unwrap();
|
|
||||||
|
|
||||||
while let Some(&next_line) = lines.peek() {
|
|
||||||
let next = next_line.trim();
|
|
||||||
|
|
||||||
if next.starts_with(NEW_MATERIAL_DELIMITER) || next.is_empty() {
|
|
||||||
lines.next();
|
|
||||||
|
|
||||||
let mut material = Material::new();
|
|
||||||
if let Some((key, values)) = next.split_once(' ') {
|
|
||||||
match key {
|
|
||||||
"Ka" => {
|
|
||||||
match parse_rgb(values) {
|
|
||||||
Ok(v) => material.ka = v,
|
|
||||||
Err(e) => eprintln!("Error parsing Ka values: {}", e.to_string())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Kd" => {
|
|
||||||
match parse_rgb(values) {
|
|
||||||
Ok(v) => material.kd = v,
|
|
||||||
Err(e) => eprintln!("Error parsing Kd values: {}", e.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"Ks" => {
|
|
||||||
match parse_rgb(values) {
|
|
||||||
Ok(v) => material.ks = v,
|
|
||||||
Err(e) => eprintln!("Error parsing Ks values: {}", e.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => { eprintln!("Unknown key: {key}") }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.materials.insert(mat_name.to_string(), material);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("{:#?}", self.vertices);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
use crate::models::Mesh;
|
|
||||||
|
|
||||||
pub struct ShaderSource {
|
|
||||||
pub vertex_src: &'static [u8],
|
|
||||||
pub fragment_src: &'static [u8],
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Model {
|
|
||||||
pub objects: Vec<RenderObject>
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct RenderObject {
|
|
||||||
pub vao: gl::types::GLuint,
|
|
||||||
pub vbo: gl::types::GLuint,
|
|
||||||
pub _ebo: Option<gl::types::GLuint>,
|
|
||||||
pub vertex_count: i32,
|
|
||||||
pub _index_count: Option<i32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ModelData {
|
|
||||||
pub name: String,
|
|
||||||
pub meshes: Vec<Mesh>
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use crate::models::{Material, Model};
|
|
||||||
|
|
||||||
pub struct Scene {
|
|
||||||
pub models: Vec<Model>,
|
|
||||||
pub materials: HashMap<String, Material>,
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
#[derive(Debug)]
|
|
||||||
pub struct Vertex {
|
|
||||||
pub x: f32,
|
|
||||||
pub y: f32,
|
|
||||||
pub z: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
|
|
||||||
pub const VERTEX_SHADER_SOURCE: &[u8] = b"
|
|
||||||
#version 100
|
|
||||||
precision mediump float;
|
|
||||||
|
|
||||||
attribute vec3 position;
|
|
||||||
attribute vec3 color;
|
|
||||||
|
|
||||||
varying vec3 v_color;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
gl_Position = vec4(position, 1.0);
|
|
||||||
v_color = color;
|
|
||||||
}
|
|
||||||
\0";
|
|
||||||
|
|
||||||
pub const FRAGMENT_SHADER_SOURCE: &[u8] = b"
|
|
||||||
#version 100
|
|
||||||
precision mediump float;
|
|
||||||
|
|
||||||
varying vec3 v_color;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
gl_FragColor = vec4(v_color, 1.0);
|
|
||||||
}
|
|
||||||
\0";
|
|
||||||
@ -1,311 +0,0 @@
|
|||||||
#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(__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
|
|
||||||
/*
|
|
||||||
* To support platform where unsigned long cannot be used interchangeably with
|
|
||||||
* inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
|
|
||||||
* Ideally, we could just use (u)intptr_t everywhere, but this could result in
|
|
||||||
* ABI breakage if khronos_uintptr_t is changed from unsigned long to
|
|
||||||
* unsigned long long or similar (this results in different C++ name mangling).
|
|
||||||
* To avoid changes for existing platforms, we restrict usage of intptr_t to
|
|
||||||
* platforms where the size of a pointer is larger than the size of long.
|
|
||||||
*/
|
|
||||||
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
|
|
||||||
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
|
|
||||||
#define KHRONOS_USE_INTPTR_T
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#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 KHRONOS_USE_INTPTR_T
|
|
||||||
typedef intptr_t khronos_intptr_t;
|
|
||||||
typedef uintptr_t khronos_uintptr_t;
|
|
||||||
#elif defined(_WIN64)
|
|
||||||
typedef signed long long int khronos_intptr_t;
|
|
||||||
typedef unsigned long long int khronos_uintptr_t;
|
|
||||||
#else
|
|
||||||
typedef signed long int khronos_intptr_t;
|
|
||||||
typedef unsigned long int khronos_uintptr_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(_WIN64)
|
|
||||||
typedef signed long long int khronos_ssize_t;
|
|
||||||
typedef unsigned long long int khronos_usize_t;
|
|
||||||
#else
|
|
||||||
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_ */
|
|
||||||
File diff suppressed because it is too large
Load Diff
BIN
glc/lib/libglc.a
BIN
glc/lib/libglc.a
Binary file not shown.
79
glc/nob.c
79
glc/nob.c
@ -1,79 +0,0 @@
|
|||||||
#define NOB_IMPLEMENTATION
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "nob.h"
|
|
||||||
|
|
||||||
#define BUILD_DIR "./build/"
|
|
||||||
#define SRC_DIR "./src/"
|
|
||||||
#define OBJDIR BUILD_DIR"obj/"
|
|
||||||
#define LIB_DIR "./lib/"
|
|
||||||
#define LIB_OUT LIB_DIR"libglc.a"
|
|
||||||
|
|
||||||
Cmd ar_cmd = {0};
|
|
||||||
|
|
||||||
_Bool walk_dir_func(Nob_Walk_Entry e) {
|
|
||||||
printf("Path: %s\n", e.path);
|
|
||||||
if (e.type == NOB_FILE_REGULAR) {
|
|
||||||
size_t input_len = strlen(e.path);
|
|
||||||
if (input_len > 3) {
|
|
||||||
if (strcmp(&e.path[input_len - 2], ".h") != 0) {
|
|
||||||
Cmd cmd = {0};
|
|
||||||
String_Builder sb_out = {0};
|
|
||||||
String_View sv = {0};
|
|
||||||
|
|
||||||
char *path_cpy = strdup(e.path);
|
|
||||||
|
|
||||||
sv = sv_from_cstr(path_cpy);
|
|
||||||
|
|
||||||
size_t l = strlen(e.path);
|
|
||||||
while (--l) {
|
|
||||||
if (e.path[l] == '/') {
|
|
||||||
sv_chop_left(&sv, l + 1);
|
|
||||||
break ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("file_name: %s\n", sv.data);
|
|
||||||
|
|
||||||
cmd_append(&cmd, "cc", "-c", "-static");
|
|
||||||
nob_cc_flags(&cmd);
|
|
||||||
|
|
||||||
cmd_append(&cmd, "-o");
|
|
||||||
sb_append_cstr(&sb_out, OBJDIR);
|
|
||||||
sb_append_cstr(&sb_out, sv.data);
|
|
||||||
cmd_append(&cmd, sb_out.items);
|
|
||||||
cmd_append(&cmd, strdup(path_cpy));
|
|
||||||
cmd_run(&cmd);
|
|
||||||
cmd_append(&ar_cmd, strdup(sb_out.items));
|
|
||||||
memset(sb_out.items, 0, sb_out.count);
|
|
||||||
sb_free(sb_out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*e.action = NOB_WALK_CONT;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
NOB_GO_REBUILD_URSELF(argc, argv);
|
|
||||||
|
|
||||||
if (!nob_mkdir_if_not_exists(BUILD_DIR)) {
|
|
||||||
nob_log(ERROR, "Failed to create %s: %s\n", BUILD_DIR, strerror(errno));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!nob_mkdir_if_not_exists(OBJDIR)) {
|
|
||||||
nob_log(ERROR, "Failed to create %s: %s\n", OBJDIR, strerror(errno));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *bin_path = BUILD_DIR "main";
|
|
||||||
|
|
||||||
cmd_append(&ar_cmd, "ar", "rcs", LIB_OUT);
|
|
||||||
nob_walk_dir(SRC_DIR, walk_dir_func, .post_order = true);
|
|
||||||
|
|
||||||
cmd_run(&ar_cmd);
|
|
||||||
|
|
||||||
nob_log(INFO, "Starting build...\n");
|
|
||||||
}
|
|
||||||
BIN
glc/nob.old
BIN
glc/nob.old
Binary file not shown.
@ -1 +0,0 @@
|
|||||||
#include "glc_api.h"
|
|
||||||
@ -1,52 +0,0 @@
|
|||||||
#include "../glc.h" // IWYU pragma: keep
|
|
||||||
|
|
||||||
u32 gpu_buffer_create(GpuBuffer *buf, float *vertices, u32 vertex_count, u32 *indices, int idx_count) {
|
|
||||||
u32 vao = 0, vbo = 0, ebo = 0, vao_stride = 0;
|
|
||||||
|
|
||||||
glGenVertexArrays(1, &vao);
|
|
||||||
glBindVertexArray(vao);
|
|
||||||
|
|
||||||
if (!vertices) return 1;
|
|
||||||
if (!indices) return 2;
|
|
||||||
|
|
||||||
vao_stride = DEFAULT_VERTEX_STRIDE;
|
|
||||||
|
|
||||||
glGenBuffers(1, &vbo);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, vertex_count * vao_stride * sizeof(*vertices), vertices, GL_STATIC_DRAW);
|
|
||||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(*vertices) * vao_stride, (void*)0);
|
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
|
|
||||||
glGenBuffers(1, &ebo);
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx_count * vao_stride * sizeof(*indices), indices, GL_STATIC_DRAW);
|
|
||||||
|
|
||||||
glBindVertexArray(0);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
||||||
|
|
||||||
buf->vao = vao;
|
|
||||||
buf->vbo = vbo;
|
|
||||||
buf->ebo = ebo;
|
|
||||||
buf->stride = vao_stride;
|
|
||||||
buf->index_count = idx_count;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void gpu_buffer_destroy(GpuBuffer *buffer) {
|
|
||||||
if (buffer->vbo != 0) {
|
|
||||||
glDeleteBuffers(1, &buffer->vbo);
|
|
||||||
}
|
|
||||||
if (buffer->ebo != 0) {
|
|
||||||
glDeleteBuffers(1, &buffer->ebo);
|
|
||||||
}
|
|
||||||
if (buffer->vao != 0) {
|
|
||||||
glDeleteVertexArrays(1, &buffer->vao);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void gpu_buffer_draw(GpuBuffer *buf) {
|
|
||||||
glBindVertexArray(buf->vao);
|
|
||||||
glDrawElements(GL_TRIANGLES, buf->index_count, GL_UNSIGNED_INT, 0);
|
|
||||||
}
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
#include "../glc.h" // IWYU pragma: keep
|
|
||||||
|
|
||||||
void gpu_clear(float r, float g, float b, float a) {
|
|
||||||
glClearColor(r, g, b, a);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
}
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
#include "../glc.h" // IWYU pragma: keep
|
|
||||||
|
|
||||||
INTERN
|
|
||||||
void gpu_shader_error_get(uint32_t shader) {
|
|
||||||
int success;
|
|
||||||
char infoLog[512];
|
|
||||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
glGetShaderInfoLog(shader, 512, NULL, infoLog);
|
|
||||||
err("[SHADER_ERROR] Failed to compile shader: %s\n", infoLog);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
INTERN
|
|
||||||
void gpu_program_handle_error_get(GpuProgramHandle program) {
|
|
||||||
int success;
|
|
||||||
char info_log[512];
|
|
||||||
|
|
||||||
glGetProgramiv(program, GL_LINK_STATUS, &success);
|
|
||||||
if (!success) {
|
|
||||||
glGetProgramInfoLog(program, 512, NULL, info_log);
|
|
||||||
err("[PROGRAM_ERROR] Failed to link program: %s\n", info_log);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
#include "../glc.h" // IWYU pragma: keep
|
|
||||||
|
|
||||||
INTERN
|
|
||||||
GpuShaderHandle gpu_shader_compile(char const *src, GpuShaderType type) {
|
|
||||||
uint32_t shader = glCreateShader(type);
|
|
||||||
|
|
||||||
glShaderSource(shader, 1, &src, NULL);
|
|
||||||
glCompileShader(shader);
|
|
||||||
gpu_shader_error_get(shader);
|
|
||||||
|
|
||||||
return shader;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
INTERN
|
|
||||||
GpuProgramHandle gpu_program_handle_link(GpuProgramHandle handle, GpuShaderHandle vertex_shader, GpuShaderHandle fragment_shader) {
|
|
||||||
|
|
||||||
glAttachShader(handle, vertex_shader);
|
|
||||||
glAttachShader(handle, fragment_shader);
|
|
||||||
glLinkProgram(handle);
|
|
||||||
gpu_program_handle_error_get(handle);
|
|
||||||
|
|
||||||
glDeleteShader(vertex_shader);
|
|
||||||
glDeleteShader(fragment_shader);
|
|
||||||
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
INTERN
|
|
||||||
GpuProgramHandle gpu_program_handle_create(const char *vert_src, const char *frag_src) {
|
|
||||||
GpuShaderHandle vert_shader = gpu_shader_compile(vert_src, GL_VERTEX_SHADER);
|
|
||||||
GpuShaderHandle frag_shader = gpu_shader_compile(frag_src, GL_FRAGMENT_SHADER);
|
|
||||||
GpuProgramHandle handle = glCreateProgram();
|
|
||||||
gpu_program_handle_link(handle, vert_shader, frag_shader);
|
|
||||||
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
API
|
|
||||||
GpuProgram gpu_program_create(const char *vert_src, const char *frag_src) {
|
|
||||||
GpuProgram program = {0};
|
|
||||||
program.handle = gpu_program_handle_create(vert_src, frag_src);
|
|
||||||
|
|
||||||
return program;
|
|
||||||
}
|
|
||||||
|
|
||||||
API
|
|
||||||
void gpu_program_use(GpuProgram *program) {
|
|
||||||
gpu_program_handle_use(program->handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
INTERN
|
|
||||||
void gpu_program_handle_use(GpuProgramHandle handle) {
|
|
||||||
glUseProgram(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
INTERN
|
|
||||||
void gpu_program_handle_clear() {
|
|
||||||
gpu_program_handle_use(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
1833
glc/src/glad.c
1833
glc/src/glad.c
File diff suppressed because it is too large
Load Diff
@ -1,5 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
# include "glc_internal.h"
|
|
||||||
# include "glc_api.h"
|
|
||||||
# include "glc_types.h"
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "glc_types.h"
|
|
||||||
|
|
||||||
#define API
|
|
||||||
|
|
||||||
/* GPU */
|
|
||||||
|
|
||||||
API GpuProgram gpu_program_create(const char *vert_src, const char *frag_src);
|
|
||||||
API void gpu_program_destroy(GpuProgram *gpu_program);
|
|
||||||
API void gpu_program_use(GpuProgram *program);
|
|
||||||
API void gpu_program_clear();
|
|
||||||
API u32 gpu_buffer_create(GpuBuffer *buf, float *vertices, u32 vertex_count, u32 *indices, int idx_count);
|
|
||||||
API void gpu_buffer_destroy(GpuBuffer *buffer);
|
|
||||||
API void gpu_buffer_draw(GpuBuffer *buffer);
|
|
||||||
API void gpu_clear(float r, float g, float b, float a);
|
|
||||||
|
|
||||||
/* ### PLATFORM ### */
|
|
||||||
|
|
||||||
/* WINDOW */
|
|
||||||
API Window window_create(u32 width, u32 height, const char *title);
|
|
||||||
API void window_destroy(Window *win);
|
|
||||||
API void window_buffers_swap(Window *win);
|
|
||||||
API void window_poll_events(Window *win);
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "glc_types.h"
|
|
||||||
|
|
||||||
#include "../lib/include/glad/glad.h"
|
|
||||||
#include <GLFW/glfw3.h>
|
|
||||||
|
|
||||||
#define err(...) do { fprintf(stderr, __VA_ARGS__); exit(EXIT_FAILURE); } while (0)
|
|
||||||
|
|
||||||
#define DEFAULT_VERTEX_STRIDE 3
|
|
||||||
#define INTERN
|
|
||||||
|
|
||||||
extern char const *vertex_shader_src;
|
|
||||||
extern char const *fragment_shader_src;
|
|
||||||
|
|
||||||
/* GPU */
|
|
||||||
|
|
||||||
INTERN GpuShaderHandle gpu_shader_compile(char const *src, GpuShaderType type);
|
|
||||||
INTERN void gpu_shader_error_get(uint32_t shader);
|
|
||||||
|
|
||||||
INTERN GpuProgramHandle gpu_program_handle_create(const char *vert_src, const char *frag_src);
|
|
||||||
INTERN GpuProgramHandle gpu_program_handle_link(GpuProgramHandle handle, GpuShaderHandle vert_shader, GpuShaderHandle frag_shader);
|
|
||||||
INTERN void gpu_program_handle_error_get(GpuProgramHandle program);
|
|
||||||
INTERN void gpu_program_handle_use(GpuProgramHandle handle);
|
|
||||||
|
|
||||||
INTERN void window_framebuffer_size_callback(GLFWwindow *win, int width, int height);
|
|
||||||
|
|
||||||
@ -1,52 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "../lib/include/glad/glad.h"
|
|
||||||
#include <GLFW/glfw3.h>
|
|
||||||
|
|
||||||
typedef uint8_t u8;
|
|
||||||
typedef uint16_t u16;
|
|
||||||
typedef uint32_t u32;
|
|
||||||
typedef uint64_t u64;
|
|
||||||
|
|
||||||
typedef int8_t i8;
|
|
||||||
typedef int16_t i16;
|
|
||||||
typedef int32_t i32;
|
|
||||||
typedef int64_t i64;
|
|
||||||
|
|
||||||
typedef i32 GpuShaderHandle;
|
|
||||||
typedef i32 GpuProgramHandle;
|
|
||||||
|
|
||||||
typedef GLvoid GpuVoid;
|
|
||||||
typedef GLboolean GpuBool;
|
|
||||||
typedef GLbyte GpuByte;
|
|
||||||
typedef GLshort GpuShort;
|
|
||||||
typedef GLsizei GpuSizeI;
|
|
||||||
typedef GLsizeiptr GpuSizeIPtr;
|
|
||||||
typedef GLint GpuInt;
|
|
||||||
typedef GLuint GpuUint;
|
|
||||||
typedef GLfloat GpuFloat;
|
|
||||||
typedef GLdouble GpuDouble;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
FRAGMENT_SHADER = GL_FRAGMENT_SHADER,
|
|
||||||
VERTEX_SHADER = GL_VERTEX_SHADER,
|
|
||||||
} GpuShaderType;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
GpuShaderHandle handle;
|
|
||||||
} GpuProgram;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
GLFWwindow *win;
|
|
||||||
i32 width;
|
|
||||||
i32 height;
|
|
||||||
} Window;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
GLuint vao;
|
|
||||||
GLuint vbo;
|
|
||||||
GLuint ebo;
|
|
||||||
u32 stride;
|
|
||||||
u32 index_count;
|
|
||||||
} GpuBuffer;
|
|
||||||
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
#include "../../glc.h" // IWYU pragma: keep
|
|
||||||
|
|
||||||
void window_poll_events(Window *win) {
|
|
||||||
(void)win;
|
|
||||||
glfwPollEvents();
|
|
||||||
}
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
#include "../../glc.h" // IWYU pragma: keep
|
|
||||||
|
|
||||||
void window_framebuffer_size_callback(GLFWwindow *win, int width, int height) {
|
|
||||||
(void)win;
|
|
||||||
glViewport(0, 0, width, height);
|
|
||||||
}
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
#include "../../glc.h" // IWYU pragma: keep
|
|
||||||
|
|
||||||
void window_buffers_swap(Window *win) {
|
|
||||||
glfwSwapBuffers(win->win);
|
|
||||||
}
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
#include "../../glc.h" // IWYU pragma: keep
|
|
||||||
|
|
||||||
i32 window_width_get(Window *win) {
|
|
||||||
glfwGetWindowSize(win->win, &win->width, &win->height);
|
|
||||||
return win->width;
|
|
||||||
}
|
|
||||||
|
|
||||||
i32 window_height_get(Window *win) {
|
|
||||||
glfwGetWindowSize(win->win, &win->width, &win->height);
|
|
||||||
return win->height;
|
|
||||||
}
|
|
||||||
|
|
||||||
Window window_create(u32 width, u32 height, const char *title) {
|
|
||||||
glfwInit();
|
|
||||||
|
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
|
|
||||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
|
||||||
|
|
||||||
GLFWwindow *glfw_window = glfwCreateWindow(width, height, title, NULL, NULL);
|
|
||||||
if (glfw_window == NULL) {
|
|
||||||
err("Failed to create GL window\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
glfwMakeContextCurrent(glfw_window);
|
|
||||||
|
|
||||||
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
|
|
||||||
err("Failed to initialize glad\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
glViewport(0, 0, width, height);
|
|
||||||
glfwSetFramebufferSizeCallback(glfw_window, (GLFWframebuffersizefun)window_framebuffer_size_callback);
|
|
||||||
return (Window){ glfw_window, width, height };
|
|
||||||
}
|
|
||||||
|
|
||||||
void window_destroy(Window *win) {
|
|
||||||
glfwDestroyWindow(win->win);
|
|
||||||
}
|
|
||||||
245
glrs/Cargo.lock
generated
245
glrs/Cargo.lock
generated
@ -1,245 +0,0 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
|
||||||
# It is not intended for manual editing.
|
|
||||||
version = 4
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aho-corasick"
|
|
||||||
version = "1.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bindgen"
|
|
||||||
version = "0.72.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"cexpr",
|
|
||||||
"clang-sys",
|
|
||||||
"itertools",
|
|
||||||
"log",
|
|
||||||
"prettyplease",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"regex",
|
|
||||||
"rustc-hash",
|
|
||||||
"shlex",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "2.11.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cc"
|
|
||||||
version = "1.2.56"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2"
|
|
||||||
dependencies = [
|
|
||||||
"find-msvc-tools",
|
|
||||||
"shlex",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cexpr"
|
|
||||||
version = "0.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
|
||||||
dependencies = [
|
|
||||||
"nom",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clang-sys"
|
|
||||||
version = "1.8.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
|
|
||||||
dependencies = [
|
|
||||||
"glob",
|
|
||||||
"libc",
|
|
||||||
"libloading",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "either"
|
|
||||||
version = "1.15.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "find-msvc-tools"
|
|
||||||
version = "0.1.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "glob"
|
|
||||||
version = "0.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "glrs"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"bindgen",
|
|
||||||
"cc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "itertools"
|
|
||||||
version = "0.13.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libc"
|
|
||||||
version = "0.2.182"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libloading"
|
|
||||||
version = "0.8.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"windows-link",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "log"
|
|
||||||
version = "0.4.29"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memchr"
|
|
||||||
version = "2.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "minimal-lexical"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nom"
|
|
||||||
version = "7.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
"minimal-lexical",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "prettyplease"
|
|
||||||
version = "0.2.37"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro2"
|
|
||||||
version = "1.0.106"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
|
||||||
dependencies = [
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quote"
|
|
||||||
version = "1.0.44"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex"
|
|
||||||
version = "1.12.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
|
|
||||||
dependencies = [
|
|
||||||
"aho-corasick",
|
|
||||||
"memchr",
|
|
||||||
"regex-automata",
|
|
||||||
"regex-syntax",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-automata"
|
|
||||||
version = "0.4.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
|
|
||||||
dependencies = [
|
|
||||||
"aho-corasick",
|
|
||||||
"memchr",
|
|
||||||
"regex-syntax",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-syntax"
|
|
||||||
version = "0.8.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustc-hash"
|
|
||||||
version = "2.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "shlex"
|
|
||||||
version = "1.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "syn"
|
|
||||||
version = "2.0.117"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-ident"
|
|
||||||
version = "1.0.24"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-link"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "glrs"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2024"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
cc = "1.2.56"
|
|
||||||
|
|
||||||
[build-dependencies]
|
|
||||||
bindgen = "0.72.1"
|
|
||||||
cc = "1.2.56"
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
use cc;
|
|
||||||
|
|
||||||
fn collect_c_files(dir: &str) -> Vec<std::path::PathBuf> {
|
|
||||||
let mut files = vec![];
|
|
||||||
for entry in std::fs::read_dir(dir).unwrap() {
|
|
||||||
let path = entry.unwrap().path();
|
|
||||||
if path.is_dir() {
|
|
||||||
files.extend(collect_c_files(path.to_str().unwrap()));
|
|
||||||
} else if path.extension().map_or(false, |e| e == "c") {
|
|
||||||
files.push(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
files
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
|
|
||||||
let cfiles = collect_c_files("../glc/src");
|
|
||||||
|
|
||||||
cc::Build::new()
|
|
||||||
.files(&cfiles)
|
|
||||||
.compile("glc"); // produces libgl_layer.a
|
|
||||||
|
|
||||||
let bindings = bindgen::Builder::default()
|
|
||||||
.header("../glc/src/glc_api.h")
|
|
||||||
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
|
|
||||||
.generate()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
bindings
|
|
||||||
.write_to_file(std::path::PathBuf::from(std::env::var("OUT_DIR").unwrap()).join("bindings.rs"))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let bindings_header = "../glc/src/glc_api.h";
|
|
||||||
|
|
||||||
println!("cargo:rerun-if-changed=build.rs");
|
|
||||||
println!("cargo:rerun-if-changed={bindings_header}");
|
|
||||||
cfiles.iter().for_each(|c| {
|
|
||||||
println!("cargo::rerun-if-changed={}", c.parent().unwrap().to_str().unwrap());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
use crate::glc;
|
|
||||||
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
pub mod glc {
|
|
||||||
#![allow(non_snake_case, nonstandard_style)]
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod glrs;
|
|
||||||
147
src/app/app.rs
Normal file
147
src/app/app.rs
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
use winit::application::ApplicationHandler;
|
||||||
|
use winit::keyboard::{KeyCode, PhysicalKey};
|
||||||
|
use winit::window::WindowAttributes;
|
||||||
|
use winit::{event, window};
|
||||||
|
|
||||||
|
use crate::app::scene::Scene;
|
||||||
|
use crate::backend::{DrawCommand, RenderBackend};
|
||||||
|
use crate::geometry::Mesh;
|
||||||
|
use crate::handles::{MeshHandle, ShaderHandle};
|
||||||
|
use crate::models::{self, ModelData};
|
||||||
|
|
||||||
|
pub enum UploadData<B: RenderBackend> {
|
||||||
|
ModelData(ModelData),
|
||||||
|
Shader(B::ShaderSource),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct App<B: RenderBackend> {
|
||||||
|
pub backend: B,
|
||||||
|
pub scene: Scene,
|
||||||
|
pub meshes: Vec<Mesh>,
|
||||||
|
pub mesh_handles: Vec<MeshHandle>,
|
||||||
|
pub model_queue: Vec<ModelData>,
|
||||||
|
pub shader_queue: Vec<B::ShaderSource>,
|
||||||
|
pub shaders: Vec<ShaderHandle>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: RenderBackend> App<B> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
backend: B::new(),
|
||||||
|
scene: Default::default(),
|
||||||
|
meshes: Vec::new(),
|
||||||
|
mesh_handles: Vec::new(),
|
||||||
|
shaders: Vec::new(),
|
||||||
|
model_queue: Vec::new(),
|
||||||
|
shader_queue: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_shader(&mut self, shader_src: B::ShaderSource) {
|
||||||
|
self.shader_queue.push(shader_src);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_model(&mut self, model_data: ModelData) {
|
||||||
|
self.model_queue.push(model_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upload_data_queue(&mut self) {
|
||||||
|
for mesh in &self.meshes {
|
||||||
|
let handle = self.backend.create_mesh(mesh).expect("Should be able to create mesh");
|
||||||
|
self.mesh_handles.push(handle);
|
||||||
|
}
|
||||||
|
let mut model: models::Model = Default::default();
|
||||||
|
for shader_src in &self.shader_queue {
|
||||||
|
let shader = self.backend.create_shader(&shader_src).expect("Should be able to create shaders");
|
||||||
|
self.shaders.push(shader);
|
||||||
|
}
|
||||||
|
for model_data in &mut self.model_queue {
|
||||||
|
for mesh in &mut model_data.meshes {
|
||||||
|
let mat = model_data.materials.iter_mut().find(|mat| mat.name == *mesh.material_name.as_ref()
|
||||||
|
.expect("Mesh should have associated Material!")
|
||||||
|
).expect("Model should have Material requested by mesh");
|
||||||
|
mat.shader = *self.shaders.get(0).expect("Should have a shader");
|
||||||
|
let new_mesh = self.backend.create_mesh(mesh).unwrap();
|
||||||
|
let mat_handle = self.scene.add_material(mat);
|
||||||
|
model.parts.push((new_mesh, mat_handle))
|
||||||
|
}
|
||||||
|
model.set_transform(model_data.transform);
|
||||||
|
}
|
||||||
|
self.scene.models.push(model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn window_attributes() -> WindowAttributes {
|
||||||
|
window::Window::default_attributes()
|
||||||
|
.with_transparent(false)
|
||||||
|
.with_title("Test Window")
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: RenderBackend> ApplicationHandler for App<B> {
|
||||||
|
fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
|
||||||
|
self.backend.resume(event_loop);
|
||||||
|
self.upload_data_queue();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn suspended(&mut self, _event_loop: &winit::event_loop::ActiveEventLoop) {
|
||||||
|
println!("Android window removed");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn window_event(
|
||||||
|
&mut self,
|
||||||
|
event_loop: &winit::event_loop::ActiveEventLoop,
|
||||||
|
_window_id: window::WindowId,
|
||||||
|
event: event::WindowEvent,
|
||||||
|
) {
|
||||||
|
match event {
|
||||||
|
event::WindowEvent::Resized(size) if size.width != 0 && size.height != 0 => {
|
||||||
|
},
|
||||||
|
event::WindowEvent::CloseRequested => {
|
||||||
|
event_loop.exit();
|
||||||
|
}
|
||||||
|
event::WindowEvent::KeyboardInput { event, .. } => {
|
||||||
|
println!("Hit key: {:#?}", &event.physical_key);
|
||||||
|
match event.physical_key {
|
||||||
|
PhysicalKey::Code(KeyCode::KeyW) => {
|
||||||
|
self.scene.camera.position.z -= 0.1;
|
||||||
|
}
|
||||||
|
PhysicalKey::Code(KeyCode::KeyS) => {
|
||||||
|
self.scene.camera.position.z += 0.1;
|
||||||
|
}
|
||||||
|
PhysicalKey::Code(KeyCode::Escape) => {
|
||||||
|
event_loop.exit();
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exiting(&mut self, _event_loop: &winit::event_loop::ActiveEventLoop) {
|
||||||
|
// let _gl_display = self.gl_context.take().unwrap().display();
|
||||||
|
//
|
||||||
|
// #[cfg(egl_backend)]
|
||||||
|
// #[allow(irrefutable_let_patterns)]
|
||||||
|
// if let glutin::display::Display::Egl(display) = _gl_display {
|
||||||
|
// unsafe {
|
||||||
|
// display.terminate();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn about_to_wait(&mut self, _event_loop: &winit::event_loop::ActiveEventLoop) {
|
||||||
|
self.backend.begin_frame();
|
||||||
|
for mesh in &self.mesh_handles {
|
||||||
|
let cmd = DrawCommand {
|
||||||
|
mesh: mesh.clone(),
|
||||||
|
shader: ShaderHandle(0),
|
||||||
|
textures: &[],
|
||||||
|
uniforms: &[]
|
||||||
|
};
|
||||||
|
self.backend.draw(&cmd);
|
||||||
|
}
|
||||||
|
self.backend.end_frame();
|
||||||
|
}
|
||||||
|
}
|
||||||
35
src/app/camera.rs
Normal file
35
src/app/camera.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
use crate::math::{Mat4, Vec3};
|
||||||
|
|
||||||
|
pub struct Camera {
|
||||||
|
pub position: Vec3,
|
||||||
|
pub target: Vec3,
|
||||||
|
pub up: Vec3,
|
||||||
|
pub fov: f32,
|
||||||
|
pub aspect_ratio: f32,
|
||||||
|
pub near: f32,
|
||||||
|
pub far: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Camera {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
position: Vec3::new(0.0, 2.0, 5.0),
|
||||||
|
target: Vec3::new(0.0, 0.0, 0.0),
|
||||||
|
up: Vec3::new(0.0, 1.0, 0.0),
|
||||||
|
fov: 45.0_f32.to_radians(),
|
||||||
|
aspect_ratio: 16.0 / 9.0,
|
||||||
|
near: 0.1,
|
||||||
|
far: 100.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Camera {
|
||||||
|
pub fn view_matrix(&self) -> Mat4 {
|
||||||
|
Mat4::look_at(self.position, self.target, self.up)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn projection_matrix(&self) -> Mat4 {
|
||||||
|
Mat4::perspective(self.fov, self.aspect_ratio, self.near, self.far)
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/app/light.rs
Normal file
15
src/app/light.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
use crate::math::Vec3;
|
||||||
|
|
||||||
|
pub struct Light {
|
||||||
|
pub position: Vec3,
|
||||||
|
pub color: Vec3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Light {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
position: Vec3::new(3.0, 5.0, 3.0),
|
||||||
|
color: Vec3::new(1.0, 1.0, 1.0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
74
src/app/scene.rs
Normal file
74
src/app/scene.rs
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::{app::{camera::Camera, light::Light}, assets, backend::{Uniform, backend}, handles, math::Mat4, models::Model};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Scene {
|
||||||
|
pub light: Light,
|
||||||
|
pub camera: Camera,
|
||||||
|
pub models: Vec<Model>,
|
||||||
|
pub materials: HashMap<handles::MaterialHandle, assets::mtl::Material>,
|
||||||
|
next_mat_id: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scene {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
light: Light::default(),
|
||||||
|
camera: Camera::default(),
|
||||||
|
materials: HashMap::new(),
|
||||||
|
next_mat_id: 0,
|
||||||
|
models: vec![]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_material(&mut self, material: &assets::mtl::Material) -> handles::MaterialHandle {
|
||||||
|
let mat_handle = handles::MaterialHandle(self.next_mat_id);
|
||||||
|
self.materials.insert(mat_handle, material.clone());
|
||||||
|
self.next_mat_id += 1;
|
||||||
|
mat_handle
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&mut self, backend: &mut impl backend::RenderBackend) {
|
||||||
|
backend.begin_frame();
|
||||||
|
|
||||||
|
let view = self.camera.view_matrix();
|
||||||
|
let projection = self.camera.projection_matrix();
|
||||||
|
|
||||||
|
let scene_uniforms = [
|
||||||
|
Uniform::Mat4(c"u_view".into(), view),
|
||||||
|
Uniform::Mat4(c"u_projection".into(), projection),
|
||||||
|
Uniform::Vec3(c"u_view_pos".into(), self.camera.position),
|
||||||
|
Uniform::Vec3(c"u_light_pos".into(), self.light.position),
|
||||||
|
Uniform::Vec3(c"u_light_color".into(), self.light.color),
|
||||||
|
];
|
||||||
|
|
||||||
|
for model in &mut self.models {
|
||||||
|
let current_transform = model.transform;
|
||||||
|
let transform = current_transform
|
||||||
|
* Mat4::rotation_y(0.05);
|
||||||
|
|
||||||
|
model.set_transform(transform);
|
||||||
|
|
||||||
|
let model_uniform = Uniform::Mat4(c"u_model".into(), model.transform);
|
||||||
|
|
||||||
|
for (mesh, mtl) in &model.parts {
|
||||||
|
let mtl = &self.materials[&mtl];
|
||||||
|
|
||||||
|
let mut all_uniforms = vec![model_uniform.clone()];
|
||||||
|
all_uniforms.extend(scene_uniforms.iter().cloned());
|
||||||
|
all_uniforms.extend(mtl.uniforms().iter().cloned());
|
||||||
|
|
||||||
|
let draw_cmd = backend::DrawCommand {
|
||||||
|
mesh: *mesh,
|
||||||
|
shader: mtl.shader,
|
||||||
|
uniforms: &all_uniforms,
|
||||||
|
textures: &vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
backend.draw(&draw_cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
backend.end_frame();
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/assets/error.rs
Normal file
33
src/assets/error.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum ParseError {
|
||||||
|
#[error("\n expected {expected} values, got {got}")]
|
||||||
|
TooFewValues { expected: usize, got: usize },
|
||||||
|
|
||||||
|
#[error("\n expected {expected} values, got {got}")]
|
||||||
|
TooManyValues { expected: usize, got: usize },
|
||||||
|
|
||||||
|
#[error("\n invalid float: {0}")]
|
||||||
|
InvalidFloat(#[from] std::num::ParseFloatError),
|
||||||
|
|
||||||
|
#[error("\n invalid value: {0}")]
|
||||||
|
InvalidValue(#[from] Box<dyn std::error::Error + Send + Sync>),
|
||||||
|
|
||||||
|
#[error("\n unknown prefix: {0}")]
|
||||||
|
UnknownPrefix(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum AssetError {
|
||||||
|
#[error("\n Parse in {file} at line {line}: {source}")]
|
||||||
|
Parse {
|
||||||
|
file: String,
|
||||||
|
line: usize,
|
||||||
|
#[source]
|
||||||
|
source: ParseError
|
||||||
|
},
|
||||||
|
|
||||||
|
#[error("I/O: {0}")]
|
||||||
|
IO(#[from] std::io::Error),
|
||||||
|
}
|
||||||
255
src/assets/mtl.rs
Normal file
255
src/assets/mtl.rs
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
use core::ffi;
|
||||||
|
|
||||||
|
use crate::{assets::{error::AssetError, parser::parse_args}, backend::Uniform, handles::ShaderHandle, math::{Mat4, Vec3, Vec4, Vec2}};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct TextureId(pub u32);
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Material {
|
||||||
|
pub name: String,
|
||||||
|
pub shader: ShaderHandle,
|
||||||
|
|
||||||
|
ambient: Vec3,
|
||||||
|
diffuse: Vec3,
|
||||||
|
specular: Vec3,
|
||||||
|
emissive: Vec3,
|
||||||
|
_shininess: f32,
|
||||||
|
opacity: f32,
|
||||||
|
|
||||||
|
pub diffuse_texture: Option<TextureId>,
|
||||||
|
pub normal_texture: Option<TextureId>,
|
||||||
|
pub specular_texture: Option<TextureId>,
|
||||||
|
|
||||||
|
uniforms: Vec<Uniform>,
|
||||||
|
textures: Vec<TextureId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Material {
|
||||||
|
fn default() -> Self {
|
||||||
|
let mut mat = Self {
|
||||||
|
name: String::new(),
|
||||||
|
shader: ShaderHandle::default(),
|
||||||
|
ambient: Vec3::new(0.1, 0.1, 0.1),
|
||||||
|
diffuse: Vec3::new(0.8, 0.8, 0.8),
|
||||||
|
specular: Vec3::new(0.5, 0.5, 0.5),
|
||||||
|
emissive: Vec3::new(0.0, 0.0, 0.0),
|
||||||
|
_shininess: 32.0,
|
||||||
|
opacity: 1.0,
|
||||||
|
diffuse_texture: None,
|
||||||
|
normal_texture: None,
|
||||||
|
specular_texture: None,
|
||||||
|
uniforms: Vec::new(),
|
||||||
|
textures: Vec::new(),
|
||||||
|
};
|
||||||
|
// Set default uniforms
|
||||||
|
mat.set_uniform_v3(c"u_ambient", mat.ambient);
|
||||||
|
mat.set_uniform_v3(c"u_diffuse", mat.diffuse);
|
||||||
|
mat.set_uniform_v3(c"u_specular", mat.specular);
|
||||||
|
mat.set_uniform_f(c"u_shininess", mat._shininess);
|
||||||
|
mat
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Material {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_ambient(&mut self, v: Vec3) {
|
||||||
|
self.ambient = v;
|
||||||
|
self.set_uniform_v3(c"u_ambient", v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_diffuse(&mut self, v: Vec3) {
|
||||||
|
self.diffuse = v;
|
||||||
|
self.set_uniform_v3(c"u_diffuse", v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_specular(&mut self, v: Vec3) {
|
||||||
|
self.specular = v;
|
||||||
|
self.set_uniform_v3(c"u_specular", v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_emissive(&mut self, v: Vec3) {
|
||||||
|
self.emissive = v;
|
||||||
|
self.set_uniform_v3(c"u_emissive", v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_shininess(&mut self, v: f32) {
|
||||||
|
self._shininess = v;
|
||||||
|
self.set_uniform_f(c"u_shininess", v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_opacity(&mut self, v: f32) {
|
||||||
|
self.opacity = v;
|
||||||
|
self.set_uniform_f(c"u_opacity", v);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn set_uniform_f(&mut self, name: &ffi::CStr, val: f32) {
|
||||||
|
if let Some(Uniform::Float(_, v)) = self.uniforms
|
||||||
|
.iter_mut()
|
||||||
|
.find(|u| matches!(u, Uniform::Float(n, _) if n == name))
|
||||||
|
{
|
||||||
|
*v = val;
|
||||||
|
} else {
|
||||||
|
self.uniforms.push(Uniform::Float(name.into(), val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_uniform_v2(&mut self, name: &ffi::CStr, val: Vec2) {
|
||||||
|
if let Some(Uniform::Vec2(_, v)) = self.uniforms
|
||||||
|
.iter_mut()
|
||||||
|
.find(|u| matches!(u, Uniform::Vec2(n, _) if n == name))
|
||||||
|
{
|
||||||
|
*v = val;
|
||||||
|
} else {
|
||||||
|
self.uniforms.push(Uniform::Vec2(name.into(), val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_uniform_v3(&mut self, name: &ffi::CStr, val: Vec3) {
|
||||||
|
if let Some(Uniform::Vec3(_, v)) = self.uniforms
|
||||||
|
.iter_mut()
|
||||||
|
.find(|u| matches!(u, Uniform::Vec3(n, _) if n == name))
|
||||||
|
{
|
||||||
|
*v = val;
|
||||||
|
} else {
|
||||||
|
self.uniforms.push(Uniform::Vec3(name.into(), val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_uniform_v4(&mut self, name: &ffi::CStr, val: Vec4) {
|
||||||
|
if let Some(Uniform::Vec4(_, v)) = self.uniforms
|
||||||
|
.iter_mut()
|
||||||
|
.find(|u| matches!(u, Uniform::Vec4(n, _) if n == name))
|
||||||
|
{
|
||||||
|
*v = val;
|
||||||
|
} else {
|
||||||
|
self.uniforms.push(Uniform::Vec4(name.into(), val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_uniform_m4(&mut self, name: &ffi::CStr, val: Mat4) {
|
||||||
|
if let Some(Uniform::Mat4(_, v)) = self.uniforms
|
||||||
|
.iter_mut()
|
||||||
|
.find(|u| matches!(u, Uniform::Mat4(n, _) if n == name))
|
||||||
|
{
|
||||||
|
*v = val;
|
||||||
|
} else {
|
||||||
|
self.uniforms.push(Uniform::Mat4(name.into(), val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uniforms(&self) -> &[Uniform] {
|
||||||
|
&self.uniforms
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn textures(&self) -> &[TextureId] {
|
||||||
|
&self.textures
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const NEW_MATERIAL_DELIMITER: &str = "newmtl ";
|
||||||
|
|
||||||
|
pub fn load_materials(path: &str) -> Result<Vec<Material>, AssetError> {
|
||||||
|
let content = std::fs::read_to_string(path)?;
|
||||||
|
let mut materials = vec![];
|
||||||
|
let mut current_material: Option<Material> = None;
|
||||||
|
|
||||||
|
for (i, line) in content.lines().enumerate() {
|
||||||
|
let line = line.trim();
|
||||||
|
if line.is_empty() || line.starts_with('#') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if line.starts_with(NEW_MATERIAL_DELIMITER) {
|
||||||
|
if let Some(mat) = current_material.take() {
|
||||||
|
materials.push(mat);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mat_name = line.strip_prefix(NEW_MATERIAL_DELIMITER).unwrap().trim();
|
||||||
|
let mut material = Material::new();
|
||||||
|
|
||||||
|
material.name = mat_name.to_string();
|
||||||
|
current_material = Some(material);
|
||||||
|
|
||||||
|
} else if let Some(ref mut material) = current_material {
|
||||||
|
let delim = " ";
|
||||||
|
let i = i + 1;
|
||||||
|
|
||||||
|
if let Some((key, values)) = line.split_once(' ') {
|
||||||
|
match key.trim() {
|
||||||
|
"Ka" => {
|
||||||
|
match parse_args::<3, f32>(values, delim) {
|
||||||
|
Ok([x, y, z]) => material.set_ambient(Vec3::new(x, y, z)),
|
||||||
|
Err(e) => return Err(AssetError::Parse {
|
||||||
|
file: path.to_string(),
|
||||||
|
line: i,
|
||||||
|
source: e,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Kd" => {
|
||||||
|
match parse_args::<3, f32>(values, delim) {
|
||||||
|
Ok([x, y, z]) => material.set_diffuse(Vec3::new(x, y, z)),
|
||||||
|
Err(e) => return Err(AssetError::Parse {
|
||||||
|
file: path.to_string(),
|
||||||
|
line: i,
|
||||||
|
source: e,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Ks" => {
|
||||||
|
match parse_args::<3, f32>(values, delim) {
|
||||||
|
Ok([x, y, z]) => material.set_specular(Vec3::new(x, y, z)),
|
||||||
|
Err(e) => return Err(AssetError::Parse {
|
||||||
|
file: path.to_string(),
|
||||||
|
line: i,
|
||||||
|
source: e,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Ke" => {
|
||||||
|
match parse_args::<3, f32>(values, delim) {
|
||||||
|
Ok([x, y, z]) => material.set_emissive(Vec3::new(x, y, z)),
|
||||||
|
Err(e) => return Err(AssetError::Parse {
|
||||||
|
file: path.to_string(),
|
||||||
|
line: i,
|
||||||
|
source: e,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"Ns" => {
|
||||||
|
match parse_args::<1, f32>(values, delim) {
|
||||||
|
Ok(v) => material.set_shininess(v[0]),
|
||||||
|
Err(e) => return Err(AssetError::Parse {
|
||||||
|
file: path.to_string(),
|
||||||
|
line: i,
|
||||||
|
source: e,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"d" => {
|
||||||
|
match parse_args::<1, f32>(values, delim) {
|
||||||
|
Ok(v) => material.set_opacity(v[0]),
|
||||||
|
Err(e) => return Err(AssetError::Parse {
|
||||||
|
file: path.to_string(),
|
||||||
|
line: i,
|
||||||
|
source: e,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(mat) = current_material {
|
||||||
|
materials.push(mat);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(materials)
|
||||||
|
}
|
||||||
105
src/assets/obj.rs
Normal file
105
src/assets/obj.rs
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
use crate::{assets::parser::parse_args, math::{ Vec2, Vec3 }};
|
||||||
|
use super::types;
|
||||||
|
use super::error::AssetError;
|
||||||
|
|
||||||
|
pub fn load_obj(path: &str) -> Result<types::ObjData, AssetError> {
|
||||||
|
let mut obj_data = types::ObjData::new();
|
||||||
|
let content = std::fs::read_to_string(path)?;
|
||||||
|
let mut current_name = String::new();
|
||||||
|
|
||||||
|
let mut current_mash = types::ObjMesh {
|
||||||
|
name: String::new(),
|
||||||
|
material_name: None,
|
||||||
|
faces: vec![]
|
||||||
|
};
|
||||||
|
|
||||||
|
let delim = " ";
|
||||||
|
|
||||||
|
for (i, line) in content.lines().enumerate() {
|
||||||
|
let i = i + 1;
|
||||||
|
let line = line.trim();
|
||||||
|
if let Some((prefix, values)) = line.split_once(' ') {
|
||||||
|
match prefix.trim() {
|
||||||
|
"v" => {
|
||||||
|
match parse_args::<3, f32>(values, delim) {
|
||||||
|
Ok([x, y, z]) => obj_data.vertices.push(Vec3::new(x, y, z)),
|
||||||
|
Err(e) => return Err(AssetError::Parse {
|
||||||
|
file: path.to_string(),
|
||||||
|
line: i,
|
||||||
|
source: e,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"vt" => {
|
||||||
|
match parse_args::<2, f32>(values, delim) {
|
||||||
|
Ok([x, y]) => obj_data.tex_coords.push(Vec2::new(x, y)),
|
||||||
|
Err(e) => return Err(AssetError::Parse {
|
||||||
|
file: path.to_string(),
|
||||||
|
line: i,
|
||||||
|
source: e,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"vn" => {
|
||||||
|
match parse_args::<3, f32>(values, delim) {
|
||||||
|
Ok([x, y, z]) => obj_data.normals.push(Vec3::new(x, y, z)),
|
||||||
|
Err(e) => return Err(AssetError::Parse {
|
||||||
|
file: path.to_string(),
|
||||||
|
line: i,
|
||||||
|
source: e,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"o" | "g" => {
|
||||||
|
current_name = values.to_string();
|
||||||
|
current_mash.name = current_name.clone();
|
||||||
|
}
|
||||||
|
"usemtl" => {
|
||||||
|
if !current_mash.faces.is_empty() {
|
||||||
|
obj_data.meshes.push(current_mash);
|
||||||
|
}
|
||||||
|
|
||||||
|
let material_name = Some(values.to_string());
|
||||||
|
current_mash = types::ObjMesh {
|
||||||
|
name: current_name.clone(),
|
||||||
|
material_name,
|
||||||
|
faces: vec![]
|
||||||
|
};
|
||||||
|
},
|
||||||
|
"mtllib" => {
|
||||||
|
obj_data.material_lib = Some(values.to_string());
|
||||||
|
}
|
||||||
|
"f" => {
|
||||||
|
let mut current_face = types::ObjFace { indices: vec![] };
|
||||||
|
let mut line_split = values.split_whitespace();
|
||||||
|
|
||||||
|
while let Some(val) = line_split.next() {
|
||||||
|
let face_index: [u32; 3] = parse_args::<3, u32>(val, "/")
|
||||||
|
.map_err(|e| AssetError::Parse {
|
||||||
|
file: path.to_string(),
|
||||||
|
line: i,
|
||||||
|
source: e
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// OBJ indices are 1-based, convert to 0-based
|
||||||
|
let vertex_index = types::VertexIndex {
|
||||||
|
position: face_index[0] - 1,
|
||||||
|
tex_coord: if face_index[1] != 0 { Some(face_index[1] - 1) } else { None },
|
||||||
|
normal: if face_index[2] != 0 { Some(face_index[2] - 1) } else { None },
|
||||||
|
};
|
||||||
|
|
||||||
|
current_face.indices.push(vertex_index);
|
||||||
|
}
|
||||||
|
current_mash.faces.push(current_face);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !current_mash.faces.is_empty() {
|
||||||
|
obj_data.meshes.push(current_mash);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(obj_data)
|
||||||
|
}
|
||||||
62
src/assets/parser.rs
Normal file
62
src/assets/parser.rs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use crate::assets::error::ParseError;
|
||||||
|
|
||||||
|
pub fn parse_args<const N: usize, T>(
|
||||||
|
values: &str,
|
||||||
|
delim: &str
|
||||||
|
) -> Result<[T; N], ParseError>
|
||||||
|
where
|
||||||
|
T: FromStr + Copy + Default,
|
||||||
|
T::Err: std::error::Error + 'static + Send + Sync
|
||||||
|
{
|
||||||
|
let mut result = [T::default(); N];
|
||||||
|
let mut i = 0;
|
||||||
|
|
||||||
|
let values = values.split(delim);
|
||||||
|
|
||||||
|
for v in values {
|
||||||
|
if i < N {
|
||||||
|
let parsed = if !v.is_empty() {
|
||||||
|
v.parse::<T>().map_err(|e| {ParseError::InvalidValue(Box::new(e))})?
|
||||||
|
} else {
|
||||||
|
Default::default()
|
||||||
|
};
|
||||||
|
result[i] = parsed;
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if i > N {
|
||||||
|
Err(ParseError::TooManyValues{ expected: N, got: i })
|
||||||
|
} else if i < N {
|
||||||
|
Err(ParseError::TooFewValues{ expected: N, got: i })
|
||||||
|
} else {
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_all_args<T>(
|
||||||
|
values: &str,
|
||||||
|
delim: &str
|
||||||
|
) -> Result<Vec<T>, ParseError>
|
||||||
|
where
|
||||||
|
T: FromStr + Copy + Default,
|
||||||
|
T::Err: std::error::Error + 'static + Send + Sync
|
||||||
|
{
|
||||||
|
let mut result: Vec<T> = Vec::new();
|
||||||
|
let mut i = 0;
|
||||||
|
|
||||||
|
let values = values.split(delim);
|
||||||
|
|
||||||
|
for v in values {
|
||||||
|
let parsed = if !v.is_empty() {
|
||||||
|
v.parse::<T>().map_err(|e| {ParseError::InvalidValue(Box::new(e))})?
|
||||||
|
} else {
|
||||||
|
Default::default()
|
||||||
|
};
|
||||||
|
result[i] = parsed;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
41
src/assets/types.rs
Normal file
41
src/assets/types.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
use crate::math::{ Vec2, Vec3 };
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ObjData {
|
||||||
|
pub normals: Vec<Vec3>,
|
||||||
|
pub vertices: Vec<Vec3>,
|
||||||
|
pub tex_coords: Vec<Vec2>,
|
||||||
|
pub meshes: Vec<ObjMesh>,
|
||||||
|
pub material_lib: Option<String>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ObjMesh {
|
||||||
|
pub name: String,
|
||||||
|
pub material_name: Option<String>,
|
||||||
|
pub faces: Vec<ObjFace>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ObjFace {
|
||||||
|
pub indices: Vec<VertexIndex>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjData {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
normals: vec![],
|
||||||
|
vertices: vec![],
|
||||||
|
tex_coords: vec![],
|
||||||
|
meshes: vec![],
|
||||||
|
material_lib: None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct VertexIndex {
|
||||||
|
pub position: u32,
|
||||||
|
pub tex_coord: Option<u32>,
|
||||||
|
pub normal: Option<u32>
|
||||||
|
}
|
||||||
49
src/backend/backend.rs
Normal file
49
src/backend/backend.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
use crate::{geometry, handles::{self, MeshHandle}, math};
|
||||||
|
use std::ffi::CString;
|
||||||
|
|
||||||
|
|
||||||
|
pub struct DrawCommand<'a> {
|
||||||
|
pub mesh: handles::MeshHandle,
|
||||||
|
pub shader: handles::ShaderHandle,
|
||||||
|
pub uniforms: &'a [Uniform],
|
||||||
|
pub textures: &'a [(u32, u32)],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum Uniform {
|
||||||
|
Float(CString, f32),
|
||||||
|
Vec2(CString, math::Vec2),
|
||||||
|
Vec3(CString, math::Vec3),
|
||||||
|
Vec4(CString, math::Vec4),
|
||||||
|
Mat4(CString, math::Mat4),
|
||||||
|
Int(CString, i32)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait RenderBackend {
|
||||||
|
type ShaderSource: Default;
|
||||||
|
fn new() -> Self;
|
||||||
|
|
||||||
|
fn resume(&mut self, event_loop: &winit::event_loop::ActiveEventLoop);
|
||||||
|
fn resize(&mut self, width: u32, height: u32);
|
||||||
|
fn suspend(&mut self);
|
||||||
|
|
||||||
|
fn begin_frame(&mut self);
|
||||||
|
fn draw(&self, cmd: &DrawCommand);
|
||||||
|
fn end_frame(&self);
|
||||||
|
|
||||||
|
fn create_shader(&mut self, desc: &Self::ShaderSource) -> Result<handles::ShaderHandle, String>;
|
||||||
|
fn create_mesh(&mut self, mesh: &geometry::Mesh) -> Result<MeshHandle, String>;
|
||||||
|
// fn create_buffer(&mut self, data: &[u8], usage: BufferUsage) -> BufferHandle;
|
||||||
|
// fn create_texture(&mut self, desc: TextureDescriptor) -> TextureHandle;
|
||||||
|
|
||||||
|
fn set_target_fps(&mut self, fps: u32);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub struct FrameContext<'a> {
|
||||||
|
// backend: &'a mut dyn RenderBackend,
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// impl FrameContext<'_> {
|
||||||
|
// pub fn draw(&mut self, mesh: &Mesh, material: MaterialHandle, transform: Mat4);
|
||||||
|
// }
|
||||||
8
src/backend/gpu/mesh.rs
Normal file
8
src/backend/gpu/mesh.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GpuMesh {
|
||||||
|
pub vao: gl::types::GLuint,
|
||||||
|
pub vbo: gl::types::GLuint,
|
||||||
|
pub ebo: Option<gl::types::GLuint>,
|
||||||
|
pub vertex_count: i32,
|
||||||
|
pub index_count: Option<i32>,
|
||||||
|
}
|
||||||
53
src/backend/opengl/gl.rs
Normal file
53
src/backend/opengl/gl.rs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#![allow(clippy::all)]
|
||||||
|
#![allow(unsafe_op_in_unsafe_fn)]
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs"));
|
||||||
|
|
||||||
|
pub use Gles2 as Gl;
|
||||||
|
pub use crate::math;
|
||||||
|
|
||||||
|
use glutin::config::{Config, GlConfig};
|
||||||
|
use glutin::context::{ContextApi, ContextAttributesBuilder, NotCurrentContext, Version};
|
||||||
|
use glutin::display::GetGlDisplay;
|
||||||
|
use glutin::prelude::GlDisplay;
|
||||||
|
use raw_window_handle::HasWindowHandle;
|
||||||
|
use winit::window::Window;
|
||||||
|
|
||||||
|
pub fn gl_config_picker(configs: Box<dyn Iterator<Item = Config> + '_>) -> Config {
|
||||||
|
configs
|
||||||
|
.reduce(|accum, config| {
|
||||||
|
let transparency_check = config.supports_transparency().unwrap_or(false)
|
||||||
|
& !accum.supports_transparency().unwrap_or(false);
|
||||||
|
|
||||||
|
if transparency_check || config.num_samples() > accum.num_samples() {
|
||||||
|
config
|
||||||
|
} else {
|
||||||
|
accum
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gl_create_context(window: &Window, gl_config: &Config) -> NotCurrentContext {
|
||||||
|
let raw_window_handle = window.window_handle().ok().map(|wh| wh.as_raw());
|
||||||
|
let context_attributes = ContextAttributesBuilder::new().build(raw_window_handle);
|
||||||
|
|
||||||
|
let fallback_context_attributes = ContextAttributesBuilder::new()
|
||||||
|
.with_context_api(ContextApi::Gles(None))
|
||||||
|
.build(raw_window_handle);
|
||||||
|
|
||||||
|
let legacy_context_attributes = ContextAttributesBuilder::new()
|
||||||
|
.with_context_api(ContextApi::OpenGl(Some(Version::new(2, 1))))
|
||||||
|
.build(raw_window_handle);
|
||||||
|
|
||||||
|
let gl_display = gl_config.display();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
gl_display.create_context(gl_config, &context_attributes).unwrap_or_else(|_| {
|
||||||
|
gl_display.create_context(gl_config, &fallback_context_attributes).unwrap_or_else(|_| {
|
||||||
|
gl_display
|
||||||
|
.create_context(gl_config, &legacy_context_attributes)
|
||||||
|
.expect("Failed to create context")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
227
src/backend/opengl/gl_backend.rs
Normal file
227
src/backend/opengl/gl_backend.rs
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::num::NonZero;
|
||||||
|
use std::thread;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
use glutin::config::GetGlConfig;
|
||||||
|
use glutin::display::GetGlDisplay;
|
||||||
|
use glutin::prelude::{GlDisplay, NotCurrentGlContext, PossiblyCurrentGlContext};
|
||||||
|
use glutin::surface::{GlSurface, SwapInterval};
|
||||||
|
use glutin_winit::GlWindow;
|
||||||
|
use winit::window::Window;
|
||||||
|
use crate::backend::gpu;
|
||||||
|
|
||||||
|
use crate::{backend, geometry, handles, shaders};
|
||||||
|
use crate::app::app::window_attributes;
|
||||||
|
use crate::backend::opengl::{self, GlRenderer};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum GlDisplayCreationState {
|
||||||
|
Builder(glutin_winit::DisplayBuilder),
|
||||||
|
Init
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct AppState {
|
||||||
|
gl_surface: glutin::surface::Surface<glutin::surface::WindowSurface>,
|
||||||
|
window: Window,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GlBackend {
|
||||||
|
gl_display: GlDisplayCreationState,
|
||||||
|
gl_context: Option<glutin::context::PossiblyCurrentContext>,
|
||||||
|
gl: Option<GlRenderer>,
|
||||||
|
template: glutin::config::ConfigTemplateBuilder,
|
||||||
|
state: Option<AppState>,
|
||||||
|
meshes: HashMap<handles::MeshHandle, gpu::GpuMesh>,
|
||||||
|
shaders: HashMap<handles::ShaderHandle, shaders::Shader>,
|
||||||
|
|
||||||
|
// tmp
|
||||||
|
next_mesh_id: u32,
|
||||||
|
next_shader_id: u32,
|
||||||
|
|
||||||
|
frame_time: Duration,
|
||||||
|
start: Instant,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl backend::RenderBackend for GlBackend {
|
||||||
|
type ShaderSource = opengl::GlShaderSource;
|
||||||
|
|
||||||
|
fn new() -> Self where Self: Sized {
|
||||||
|
let template = glutin::config::ConfigTemplateBuilder::new()
|
||||||
|
.with_alpha_size(8)
|
||||||
|
.with_multisampling(4)
|
||||||
|
.with_transparency(cfg!(target_os = "macos"));
|
||||||
|
|
||||||
|
let display_builder = glutin_winit::DisplayBuilder::new().with_window_attributes(Some(window_attributes()));
|
||||||
|
|
||||||
|
Self {
|
||||||
|
gl_display: GlDisplayCreationState::Builder(display_builder),
|
||||||
|
gl_context: None,
|
||||||
|
state: None,
|
||||||
|
gl: None,
|
||||||
|
meshes: HashMap::new(),
|
||||||
|
shaders: HashMap::new(),
|
||||||
|
next_mesh_id: 0,
|
||||||
|
next_shader_id: 0,
|
||||||
|
frame_time: Duration::from_secs_f32(1.0 / 60.0),
|
||||||
|
start: Instant::now(),
|
||||||
|
template,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resume(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
|
||||||
|
let (window, gl_config) = match &self.gl_display {
|
||||||
|
GlDisplayCreationState::Builder(builder) => {
|
||||||
|
let (window, gl_config) = match builder.clone().build(
|
||||||
|
event_loop,
|
||||||
|
self.template.clone(),
|
||||||
|
opengl::gl_config_picker
|
||||||
|
) {
|
||||||
|
Ok((window, gl_config)) => (window.unwrap(), gl_config),
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Error: {:#?}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.gl_display = GlDisplayCreationState::Init;
|
||||||
|
self.gl_context = Some(opengl::gl_create_context(&window, &gl_config).treat_as_possibly_current());
|
||||||
|
|
||||||
|
(window, gl_config)
|
||||||
|
},
|
||||||
|
GlDisplayCreationState::Init => {
|
||||||
|
let gl_config = self.gl_context.as_ref().unwrap().config();
|
||||||
|
match glutin_winit::finalize_window(event_loop, window_attributes(), &gl_config) {
|
||||||
|
Ok(window) => (window, gl_config),
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Error: {:#?}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let attrs = window
|
||||||
|
.build_surface_attributes(Default::default())
|
||||||
|
.expect("Failed to build surface attributes");
|
||||||
|
|
||||||
|
let gl_surface = unsafe {
|
||||||
|
gl_config.display().create_window_surface(&gl_config, &attrs).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let gl_context = self.gl_context.as_ref().unwrap();
|
||||||
|
gl_context.make_current(&gl_surface).unwrap();
|
||||||
|
|
||||||
|
if self.gl.is_none() {
|
||||||
|
let renderer = opengl::GlRenderer::new(
|
||||||
|
&gl_context.display()
|
||||||
|
);
|
||||||
|
|
||||||
|
self.gl = Some(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(res) = gl_surface.set_swap_interval(
|
||||||
|
gl_context,
|
||||||
|
SwapInterval::Wait(NonZero::new(1).unwrap())
|
||||||
|
) {
|
||||||
|
eprintln!("Error setting vsync: {:?}", res)
|
||||||
|
}
|
||||||
|
|
||||||
|
window.request_redraw();
|
||||||
|
|
||||||
|
assert!(self.state.replace(AppState { gl_surface, window }).is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn suspend(&mut self) {
|
||||||
|
self.state = None;
|
||||||
|
self.gl_context = Some(
|
||||||
|
self.gl_context.take().unwrap().make_not_current().unwrap().treat_as_possibly_current()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resize(&mut self, width: u32, height: u32) {
|
||||||
|
if let Some(AppState { gl_surface, window: _ }) = &self.state && self.gl.is_some() {
|
||||||
|
let gl_context = self.gl_context.as_ref().unwrap();
|
||||||
|
|
||||||
|
gl_surface.resize(
|
||||||
|
gl_context,
|
||||||
|
NonZero::new(width).unwrap(),
|
||||||
|
NonZero::new(height).unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
self.gl
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.Viewport(0, 0, width as i32, height as i32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_shader(&mut self, desc: &Self::ShaderSource) -> Result<handles::ShaderHandle, String> {
|
||||||
|
if let Some(gl) = &self.gl {
|
||||||
|
let shader = gl.create_shader(&desc);
|
||||||
|
let shader_handle = handles::ShaderHandle(self.next_shader_id);
|
||||||
|
self.shaders.insert(shader_handle, shader);
|
||||||
|
self.next_shader_id += 1;
|
||||||
|
Ok(shader_handle)
|
||||||
|
} else {
|
||||||
|
todo!("implement error type for GlBackend")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_mesh(&mut self, mesh: &geometry::Mesh) -> Result<handles::MeshHandle, String> {
|
||||||
|
if let Some(gl) = &self.gl {
|
||||||
|
let gpu_mesh = gl.upload_mesh(mesh);
|
||||||
|
let mesh_handle = handles::MeshHandle(self.next_mesh_id);
|
||||||
|
self.meshes.insert(mesh_handle, gpu_mesh);
|
||||||
|
self.next_mesh_id += 1;
|
||||||
|
Ok(mesh_handle)
|
||||||
|
} else {
|
||||||
|
todo!("implement error type for GlBackend")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn begin_frame(&mut self) {
|
||||||
|
if let Some(gl) = &self.gl {
|
||||||
|
gl.clear(0.1, 0.1, 0.1, 1.0);
|
||||||
|
self.start = Instant::now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw(&self, cmd: &backend::DrawCommand) {
|
||||||
|
let mesh = self.meshes.get(&cmd.mesh);
|
||||||
|
let shader = self.shaders.get(&cmd.shader);
|
||||||
|
|
||||||
|
if let (Some(mesh), Some(shader), Some(gl)) = (mesh, shader, &self.gl) {
|
||||||
|
gl.use_shader(*shader);
|
||||||
|
|
||||||
|
for u in cmd.uniforms {
|
||||||
|
gl.apply_uniform(*shader, &u);
|
||||||
|
}
|
||||||
|
|
||||||
|
gl.draw_mesh(mesh);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
println!("{:#?}", mesh);
|
||||||
|
println!("{:#?}", shader);
|
||||||
|
println!("{:#?}", self.state);
|
||||||
|
println!("{:#?}", self.gl.is_some());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end_frame(&self) {
|
||||||
|
if let (Some(state), Some(gl_context)) = (&self.state, &self.gl_context) {
|
||||||
|
state.window.request_redraw();
|
||||||
|
state.gl_surface.swap_buffers(gl_context).unwrap();
|
||||||
|
let elapsed = self.start.elapsed();
|
||||||
|
if elapsed < self.frame_time {
|
||||||
|
thread::sleep(self.frame_time - elapsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_target_fps(&mut self, fps: u32) {
|
||||||
|
self.frame_time = Duration::from_secs_f32(1.0 / (fps as f32));
|
||||||
|
}
|
||||||
|
}
|
||||||
244
src/backend/opengl/gl_renderer.rs
Normal file
244
src/backend/opengl/gl_renderer.rs
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
use gl::types::GLfloat;
|
||||||
|
use glutin::prelude::GlDisplay;
|
||||||
|
use crate::backend::{opengl, Uniform};
|
||||||
|
use crate::math::{ Mat4, Vec3 };
|
||||||
|
use crate::{geometry, backend::gpu::GpuMesh};
|
||||||
|
use crate::shaders::Shader;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::ffi::{ CStr, CString, c_void };
|
||||||
|
use super::gl::Gl;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RenderState {
|
||||||
|
pub projection: Mat4,
|
||||||
|
pub view: Mat4,
|
||||||
|
pub model: Mat4,
|
||||||
|
pub camera_pos: Vec3,
|
||||||
|
pub light_pos: Vec3,
|
||||||
|
pub light_color: Vec3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderState {
|
||||||
|
pub fn new(aspect_ratio: f32) -> Self {
|
||||||
|
let camera_pos = Vec3::new(0.0, 2.0, 5.0);
|
||||||
|
Self {
|
||||||
|
projection: Mat4::perspective(45.0_f32.to_radians(), aspect_ratio, 0.1, 100.0),
|
||||||
|
view: Mat4::look_at(
|
||||||
|
camera_pos,
|
||||||
|
Vec3::new(0.0, 0.0, 0.0),
|
||||||
|
Vec3::new(0.0, 1.0, 0.0),
|
||||||
|
),
|
||||||
|
model: Mat4::identity(),
|
||||||
|
camera_pos,
|
||||||
|
light_pos: Vec3::new(3.0, 5.0, 3.0),
|
||||||
|
light_color: Vec3::new(1.0, 1.0, 1.0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_gl_string(gl: &opengl::Gl, variant: gl::types::GLenum) -> Option<&'static CStr>{
|
||||||
|
unsafe {
|
||||||
|
let s = gl.GetString(variant);
|
||||||
|
(!s.is_null()).then(|| CStr::from_ptr(s.cast()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GlRenderer {
|
||||||
|
gl: Gl,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GlRenderer {
|
||||||
|
pub fn new<D: GlDisplay>(gl_display: &D) -> Self {
|
||||||
|
let gl = opengl::Gl::load_with(|symbol| {
|
||||||
|
let symbol = CString::new(symbol).unwrap();
|
||||||
|
gl_display.get_proc_address(symbol.as_c_str()).cast()
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(renderer) = get_gl_string(&gl, gl::RENDERER) {
|
||||||
|
println!("Running on {}", renderer.to_string_lossy());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(version) = get_gl_string(&gl, gl::VERSION) {
|
||||||
|
println!("OpenGL version {}", version.to_string_lossy());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(shaders_version) = get_gl_string(&gl, gl::SHADING_LANGUAGE_VERSION) {
|
||||||
|
println!("Shaders version on {}", shaders_version.to_string_lossy());
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
gl.Enable(gl::DEPTH_TEST);
|
||||||
|
gl.DepthFunc(gl::LESS);
|
||||||
|
|
||||||
|
gl.Enable(gl::MULTISAMPLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
gl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn upload_mesh(&self, mesh: &geometry::Mesh) -> GpuMesh {
|
||||||
|
unsafe {
|
||||||
|
let gl = &self.gl;
|
||||||
|
|
||||||
|
let mut vao = std::mem::zeroed();
|
||||||
|
gl.GenVertexArrays(1, &mut vao);
|
||||||
|
gl.BindVertexArray(vao);
|
||||||
|
|
||||||
|
let mut vbo = std::mem::zeroed();
|
||||||
|
gl.GenBuffers(1, &mut vbo);
|
||||||
|
gl.BindBuffer(gl::ARRAY_BUFFER, vbo);
|
||||||
|
|
||||||
|
for attribute in &mesh.format.attributes {
|
||||||
|
let location = attribute.semantic.location();
|
||||||
|
gl.VertexAttribPointer(
|
||||||
|
attribute.semantic.location(),
|
||||||
|
attribute.comp_count as i32,
|
||||||
|
attribute.data_type.to_gpu(),
|
||||||
|
attribute.normalized as u8,
|
||||||
|
mesh.format.stride as i32,
|
||||||
|
attribute.offset as *const c_void,
|
||||||
|
);
|
||||||
|
gl.EnableVertexAttribArray(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
gl.BufferData(
|
||||||
|
gl::ARRAY_BUFFER,
|
||||||
|
mesh.vertex_data.len() as gl::types::GLsizeiptr,
|
||||||
|
mesh.vertex_data.as_ptr() as *const _,
|
||||||
|
gl::STATIC_DRAW,
|
||||||
|
);
|
||||||
|
|
||||||
|
let (ebo, index_count) = if !mesh.indices.is_empty() {
|
||||||
|
let mut ebo = std::mem::zeroed();
|
||||||
|
gl.GenBuffers(1, &mut ebo);
|
||||||
|
gl.BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ebo);
|
||||||
|
gl.BufferData(
|
||||||
|
gl::ELEMENT_ARRAY_BUFFER,
|
||||||
|
(mesh.indices.len() * std::mem::size_of::<u32>()) as gl::types::GLsizeiptr,
|
||||||
|
mesh.indices.as_ptr() as *const _,
|
||||||
|
gl::STATIC_DRAW,
|
||||||
|
);
|
||||||
|
(Some(ebo), Some(mesh.indices.len() as i32))
|
||||||
|
} else {
|
||||||
|
(None, None)
|
||||||
|
};
|
||||||
|
|
||||||
|
gl.BindVertexArray(0);
|
||||||
|
|
||||||
|
GpuMesh {
|
||||||
|
vao,
|
||||||
|
vbo,
|
||||||
|
ebo,
|
||||||
|
vertex_count: mesh.vertex_count as i32,
|
||||||
|
index_count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compile_shader(gl: &opengl::Gl, shader: gl::types::GLenum, source: &[u8]) -> gl::types::GLuint {
|
||||||
|
unsafe {
|
||||||
|
let shader = gl.CreateShader(shader);
|
||||||
|
gl.ShaderSource(shader, 1, [source.as_ptr().cast()].as_ptr(), std::ptr::null());
|
||||||
|
gl.CompileShader(shader);
|
||||||
|
shader
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_shader(&self, shader_src: &opengl::GlShaderSource) -> Shader {
|
||||||
|
unsafe {
|
||||||
|
let vertex_shader = Self::compile_shader(
|
||||||
|
&self.gl,
|
||||||
|
gl::VERTEX_SHADER,
|
||||||
|
shader_src.vertex_src.as_bytes()
|
||||||
|
);
|
||||||
|
let fragment_shader = Self::compile_shader(
|
||||||
|
&self.gl,
|
||||||
|
gl::FRAGMENT_SHADER,
|
||||||
|
shader_src.fragment_src.as_bytes()
|
||||||
|
);
|
||||||
|
|
||||||
|
let program = self.gl.CreateProgram();
|
||||||
|
|
||||||
|
self.gl.AttachShader(program, vertex_shader);
|
||||||
|
self.gl.AttachShader(program, fragment_shader);
|
||||||
|
|
||||||
|
self.gl.LinkProgram(program);
|
||||||
|
|
||||||
|
self.gl.DeleteShader(vertex_shader);
|
||||||
|
self.gl.DeleteShader(fragment_shader);
|
||||||
|
|
||||||
|
Shader(program)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn apply_uniform(&self, shader: Shader, uniform: &Uniform) {
|
||||||
|
unsafe {
|
||||||
|
match uniform {
|
||||||
|
Uniform::Float(name, value) => {
|
||||||
|
let location = self.GetUniformLocation(*shader, name.as_ptr());
|
||||||
|
self.Uniform1f(location, *value);
|
||||||
|
}
|
||||||
|
Uniform::Int(name, value) => {
|
||||||
|
let location = self.GetUniformLocation(*shader, name.as_ptr());
|
||||||
|
self.Uniform1i(location, *value);
|
||||||
|
}
|
||||||
|
Uniform::Vec2(name, value) => {
|
||||||
|
let location = self.GetUniformLocation(*shader, name.as_ptr());
|
||||||
|
self.Uniform2f(location, value[0], value[1]);
|
||||||
|
}
|
||||||
|
Uniform::Vec3(name, value) => {
|
||||||
|
let location = self.GetUniformLocation(*shader, name.as_ptr());
|
||||||
|
self.Uniform3f(location, value[0], value[1], value[2]);
|
||||||
|
}
|
||||||
|
Uniform::Vec4(name, value) => {
|
||||||
|
let location = self.GetUniformLocation(*shader, name.as_ptr());
|
||||||
|
self.Uniform4f(location, value[0], value[1], value[2], value[3]);
|
||||||
|
}
|
||||||
|
Uniform::Mat4(name, value) => {
|
||||||
|
let location = self.GetUniformLocation(*shader, name.as_ptr());
|
||||||
|
self.UniformMatrix4fv(location, 1, gl::FALSE, value.as_ptr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&self, red: GLfloat, green: GLfloat, blue: GLfloat, alpha: GLfloat) {
|
||||||
|
unsafe {
|
||||||
|
self.ClearColor(red, green, blue, alpha);
|
||||||
|
self.Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn use_shader(&self, shader: Shader) {
|
||||||
|
unsafe { self.UseProgram(*shader) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resize(&self, width: i32, height: i32) {
|
||||||
|
unsafe {
|
||||||
|
self.gl.Viewport(0, 0, width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw_mesh(&self, mesh: &GpuMesh) {
|
||||||
|
unsafe {
|
||||||
|
self.BindVertexArray(mesh.vao);
|
||||||
|
|
||||||
|
if let (Some(ebo), Some(count)) = (mesh.ebo, mesh.index_count) {
|
||||||
|
self.BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ebo);
|
||||||
|
self.DrawElements(gl::TRIANGLES, count, gl::UNSIGNED_INT, std::ptr::null());
|
||||||
|
} else {
|
||||||
|
self.DrawArrays(gl::TRIANGLES, 0, mesh.vertex_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for GlRenderer {
|
||||||
|
type Target = opengl::Gl;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.gl
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/backend/opengl/gl_shader.rs
Normal file
5
src/backend/opengl/gl_shader.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#[derive(Default)]
|
||||||
|
pub struct GlShaderSource {
|
||||||
|
pub vertex_src: String,
|
||||||
|
pub fragment_src: String,
|
||||||
|
}
|
||||||
96
src/geometry/mesh.rs
Normal file
96
src/geometry/mesh.rs
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use crate::{assets::types::{ObjData, ObjMesh, VertexIndex}, geometry::VertexFormat, math::{Vec2, Vec4}};
|
||||||
|
use super::Vertex;
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct Mesh {
|
||||||
|
pub name: String,
|
||||||
|
pub format: VertexFormat,
|
||||||
|
pub vertex_data: Vec<u8>,
|
||||||
|
pub vertex_count: usize,
|
||||||
|
pub vertices: Vec<Vertex>,
|
||||||
|
pub indices: Vec<u32>,
|
||||||
|
pub material_name: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct MeshBuilder {
|
||||||
|
mesh: Mesh,
|
||||||
|
current_vertex: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MeshBuilder {
|
||||||
|
pub fn build(self) -> Mesh {
|
||||||
|
self.mesh
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn begin_vertex(mut self) -> Self {
|
||||||
|
self.current_vertex.clear();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn end_vertex(mut self) -> Self {
|
||||||
|
if self.current_vertex.len() > 0 {
|
||||||
|
self.mesh.vertex_data.extend_from_slice(&self.current_vertex);
|
||||||
|
self.mesh.vertex_count += 1;
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn position2(mut self, pos: Vec2) -> Self {
|
||||||
|
self.current_vertex.extend_from_slice(&pos.to_bytes());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tex_coord(mut self, pos: Vec2) -> Self {
|
||||||
|
self.current_vertex.extend_from_slice(&pos.to_bytes());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn color(mut self, color: Vec4) -> Self {
|
||||||
|
self.current_vertex.extend_from_slice(&color.to_bytes());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mesh {
|
||||||
|
pub fn builder(name: impl AsRef<str>, format: VertexFormat) -> MeshBuilder {
|
||||||
|
let mesh: Self = Self { name: name.as_ref().to_string(), format, ..Default::default() };
|
||||||
|
MeshBuilder {
|
||||||
|
mesh,
|
||||||
|
current_vertex: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(obj: &ObjData, obj_mash: &ObjMesh) -> Self {
|
||||||
|
let mut vertices: Vec<Vertex> = Vec::new();
|
||||||
|
let mut indices: Vec<u32> = Vec::new();
|
||||||
|
let mut vertex_map: HashMap<VertexIndex, u32> = HashMap::new();
|
||||||
|
|
||||||
|
for face in &obj_mash.faces {
|
||||||
|
for i in 1..(face.indices.len() - 1) {
|
||||||
|
for &idx in &[face.indices[0], face.indices[i], face.indices[i +1]] {
|
||||||
|
let index = *vertex_map.entry(idx).or_insert_with(|| {
|
||||||
|
let v = Vertex {
|
||||||
|
position: obj.vertices[idx.position as usize],
|
||||||
|
normal: idx.normal.map(|n| obj.normals[n as usize]).unwrap_or_default(),
|
||||||
|
tex_coord: idx.tex_coord.map(|t| obj.tex_coords[t as usize]).unwrap_or_default(),
|
||||||
|
};
|
||||||
|
vertices.push(v);
|
||||||
|
(vertices.len() - 1) as u32
|
||||||
|
});
|
||||||
|
indices.push(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Mesh {
|
||||||
|
vertices,
|
||||||
|
format: Default::default(),
|
||||||
|
vertex_data: vec![],
|
||||||
|
vertex_count: 0,
|
||||||
|
indices,
|
||||||
|
name: obj_mash.name.clone(),
|
||||||
|
material_name: obj_mash.material_name.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
100
src/geometry/vertex.rs
Normal file
100
src/geometry/vertex.rs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use crate::math::{ Vec2, Vec3 };
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum VertexSemantic {
|
||||||
|
Position,
|
||||||
|
Normal,
|
||||||
|
TexCoord0,
|
||||||
|
TexCoord1,
|
||||||
|
Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VertexSemantic {
|
||||||
|
pub fn location(&self) -> u32 {
|
||||||
|
match self {
|
||||||
|
VertexSemantic::Position => 0,
|
||||||
|
VertexSemantic::Normal => 1,
|
||||||
|
VertexSemantic::Color => 2,
|
||||||
|
VertexSemantic::TexCoord0 => 3,
|
||||||
|
VertexSemantic::TexCoord1 => 4,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub enum AttributeType {
|
||||||
|
Float,
|
||||||
|
Int,
|
||||||
|
UnsignedInt,
|
||||||
|
Byte,
|
||||||
|
UnsignedByte,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AttributeType {
|
||||||
|
pub fn to_gpu(&self) -> gl::types::GLenum {
|
||||||
|
match self {
|
||||||
|
AttributeType::Float => gl::FLOAT,
|
||||||
|
AttributeType::Int => gl::INT,
|
||||||
|
AttributeType::UnsignedInt => gl::UNSIGNED_INT,
|
||||||
|
AttributeType::Byte => gl::BYTE,
|
||||||
|
AttributeType::UnsignedByte => gl::UNSIGNED_BYTE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct VertexAttribute {
|
||||||
|
pub semantic: VertexSemantic,
|
||||||
|
pub comp_count: usize,
|
||||||
|
pub data_type: AttributeType,
|
||||||
|
pub normalized: bool,
|
||||||
|
pub offset: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct VertexFormat {
|
||||||
|
pub attributes: Vec<VertexAttribute>,
|
||||||
|
pub stride: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VertexFormat {
|
||||||
|
pub fn ui_2d() -> Self {
|
||||||
|
Self {
|
||||||
|
attributes: vec![
|
||||||
|
VertexAttribute {
|
||||||
|
semantic: VertexSemantic::Position,
|
||||||
|
comp_count: 2,
|
||||||
|
data_type: AttributeType::Float,
|
||||||
|
normalized: false,
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
|
VertexAttribute {
|
||||||
|
semantic: VertexSemantic::Color,
|
||||||
|
comp_count: 4,
|
||||||
|
data_type: AttributeType::Float,
|
||||||
|
normalized: false,
|
||||||
|
offset: 2 * std::mem::size_of::<f32>()
|
||||||
|
}
|
||||||
|
],
|
||||||
|
stride: (2 + 4) * std::mem::size_of::<f32>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for VertexFormat {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
attributes: vec![],
|
||||||
|
stride: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Vertex {
|
||||||
|
pub position: Vec3,
|
||||||
|
pub normal: Vec3,
|
||||||
|
pub tex_coord: Vec2,
|
||||||
|
}
|
||||||
17
src/handles.rs
Normal file
17
src/handles.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)]
|
||||||
|
pub struct MeshHandle(pub u32);
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)]
|
||||||
|
pub struct MaterialHandle(pub u32);
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||||
|
pub struct ShaderHandle(pub u32);
|
||||||
|
|
||||||
|
impl Deref for ShaderHandle {
|
||||||
|
type Target = u32;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
79
src/lib.rs
Normal file
79
src/lib.rs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
pub mod models {
|
||||||
|
pub mod model;
|
||||||
|
pub use model::*;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod assets {
|
||||||
|
pub mod mtl;
|
||||||
|
pub mod obj;
|
||||||
|
pub mod types;
|
||||||
|
pub mod parser;
|
||||||
|
|
||||||
|
pub mod error;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod geometry {
|
||||||
|
pub mod vertex;
|
||||||
|
pub use vertex::*;
|
||||||
|
|
||||||
|
pub mod mesh;
|
||||||
|
pub use mesh::*;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod math {
|
||||||
|
pub use vector::*;
|
||||||
|
pub mod vector {
|
||||||
|
pub mod vec2;
|
||||||
|
pub mod vec3;
|
||||||
|
pub mod vec4;
|
||||||
|
|
||||||
|
pub use vec2::*;
|
||||||
|
pub use vec3::*;
|
||||||
|
pub use vec4::*;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use matrix::*;
|
||||||
|
pub mod matrix {
|
||||||
|
pub mod mat4;
|
||||||
|
pub use mat4::*;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod app {
|
||||||
|
pub mod app;
|
||||||
|
pub mod light;
|
||||||
|
pub mod camera;
|
||||||
|
pub mod scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod shaders {
|
||||||
|
pub mod types;
|
||||||
|
pub use types::*;
|
||||||
|
|
||||||
|
pub mod constants;
|
||||||
|
pub use constants::*;
|
||||||
|
|
||||||
|
pub mod inputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod backend {
|
||||||
|
pub mod opengl {
|
||||||
|
pub mod gl_renderer;
|
||||||
|
pub use gl_renderer::*;
|
||||||
|
pub mod gl_backend;
|
||||||
|
pub use gl_backend::*;
|
||||||
|
pub mod gl_shader;
|
||||||
|
pub use gl_shader::*;
|
||||||
|
pub mod gl;
|
||||||
|
pub use gl::*;
|
||||||
|
}
|
||||||
|
pub mod gpu {
|
||||||
|
pub mod mesh;
|
||||||
|
pub use mesh::*;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod backend;
|
||||||
|
pub use backend::*;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod handles;
|
||||||
47
src/main.rs
Normal file
47
src/main.rs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
use proj::{
|
||||||
|
app::app::App, assets, backend::opengl, geometry::{AttributeType, Mesh, MeshBuilder, VertexFormat, VertexSemantic}, math::{Mat4, Vec2, Vec4}, models::{self, Model}, shaders::{FRAGMENT_SHADER_2D, FRAGMENT_SHADER_SOURCE, VERTEX_SHADER_2D, VERTEX_SHADER_SOURCE, inputs::ShaderInputs}
|
||||||
|
};
|
||||||
|
use winit::event_loop::EventLoop;
|
||||||
|
|
||||||
|
const HOUSE_OBJ_PATH: &str = "assets/models/small_house/model.obj";
|
||||||
|
const HOUSE_MAT_PATH: &str = "assets/models/small_house/materials.mtl";
|
||||||
|
|
||||||
|
const BUGATTI_OBJ_PATH: &str = "assets/models/bugatti/bugatti.obj";
|
||||||
|
const BUGATTI_MTL_PATH: &str = "assets/models/bugatti/bugatti.mtl";
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
dotenvy::dotenv().ok();
|
||||||
|
|
||||||
|
let event_loop = EventLoop::new()
|
||||||
|
.expect("Should be able to have Event Loop");
|
||||||
|
|
||||||
|
let shader_src = opengl::GlShaderSource {
|
||||||
|
vertex_src: VERTEX_SHADER_2D.to_string(),
|
||||||
|
fragment_src: FRAGMENT_SHADER_2D.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
let mut app = App::<opengl::GlBackend>::new();
|
||||||
|
|
||||||
|
let mesh = Mesh::builder("triangle", VertexFormat::ui_2d())
|
||||||
|
.begin_vertex()
|
||||||
|
.position2(Vec2::new(0.0, 0.5))
|
||||||
|
.color(Vec4::new(1.0, 0.0, 0.0, 1.0))
|
||||||
|
.end_vertex()
|
||||||
|
.begin_vertex()
|
||||||
|
.position2(Vec2::new(-0.5, -0.5))
|
||||||
|
.color(Vec4::new(1.0, 1.0, 0.0, 1.0))
|
||||||
|
.end_vertex()
|
||||||
|
.begin_vertex()
|
||||||
|
.position2(Vec2::new(0.5, -0.5))
|
||||||
|
.color(Vec4::new(0.0, 0.0, 1.0, 1.0))
|
||||||
|
.end_vertex()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
app.meshes.push(mesh);
|
||||||
|
app.add_shader(shader_src);
|
||||||
|
|
||||||
|
let event_res = event_loop.run_app(&mut app);
|
||||||
|
|
||||||
|
println!("{:#?}", event_res);
|
||||||
|
}
|
||||||
127
src/math/matrix/mat4.rs
Normal file
127
src/math/matrix/mat4.rs
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
use crate::math::{ Vec3 };
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Mat4 {
|
||||||
|
pub data: [f32; 16],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mat4 {
|
||||||
|
pub fn identity() -> Self {
|
||||||
|
Self {
|
||||||
|
data: [
|
||||||
|
1.0, 0.0, 0.0, 0.0,
|
||||||
|
0.0, 1.0, 0.0, 0.0,
|
||||||
|
0.0, 0.0, 1.0, 0.0,
|
||||||
|
0.0, 0.0, 0.0, 1.0,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn translation(x: f32, y: f32, z: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
data: [
|
||||||
|
1.0, 0.0, 0.0, 0.0,
|
||||||
|
0.0, 1.0, 0.0, 0.0,
|
||||||
|
0.0, 0.0, 1.0, 0.0,
|
||||||
|
x, y, z, 1.0,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scale(x: f32, y: f32, z: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
data: [
|
||||||
|
x, 0.0, 0.0, 0.0,
|
||||||
|
0.0, y, 0.0, 0.0,
|
||||||
|
0.0, 0.0, z, 0.0,
|
||||||
|
0.0, 0.0, 0.0, 1.0,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rotation_x(angle: f32) -> Self {
|
||||||
|
let c = angle.cos();
|
||||||
|
let s = angle.sin();
|
||||||
|
Self {
|
||||||
|
data: [
|
||||||
|
1.0, 0.0, 0.0, 0.0,
|
||||||
|
0.0, c, s, 0.0,
|
||||||
|
0.0, -s, c, 0.0,
|
||||||
|
0.0, 0.0, 0.0, 1.0,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rotation_y(angle: f32) -> Self {
|
||||||
|
let c = angle.cos();
|
||||||
|
let s = angle.sin();
|
||||||
|
Self {
|
||||||
|
data: [
|
||||||
|
c, 0.0, -s, 0.0,
|
||||||
|
0.0, 1.0, 0.0, 0.0,
|
||||||
|
s, 0.0, c, 0.0,
|
||||||
|
0.0, 0.0, 0.0, 1.0,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rotation_z(angle: f32) -> Self {
|
||||||
|
let c = angle.cos();
|
||||||
|
let s = angle.sin();
|
||||||
|
Self {
|
||||||
|
data: [
|
||||||
|
c, s, 0.0, 0.0,
|
||||||
|
-s, c, 0.0, 0.0,
|
||||||
|
0.0, 0.0, 1.0, 0.0,
|
||||||
|
0.0, 0.0, 0.0, 1.0,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn perspective(fov: f32, aspect: f32, near: f32, far: f32) -> Self {
|
||||||
|
let f = 1.0 / (fov / 2.0).tan();
|
||||||
|
let nf = 1.0 / (near - far);
|
||||||
|
Self {
|
||||||
|
data: [
|
||||||
|
f / aspect, 0.0, 0.0, 0.0,
|
||||||
|
0.0, f, 0.0, 0.0,
|
||||||
|
0.0, 0.0, (far + near) * nf, -1.0,
|
||||||
|
0.0, 0.0, 2.0 * far * near * nf, 0.0,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn look_at(eye: Vec3, target: Vec3, up: Vec3) -> Self {
|
||||||
|
let f = (target - eye).normalize();
|
||||||
|
let r = f.cross(&up).normalize();
|
||||||
|
let u = r.cross(&f);
|
||||||
|
Self {
|
||||||
|
data: [
|
||||||
|
r.x, u.x, -f.x, 0.0,
|
||||||
|
r.y, u.y, -f.y, 0.0,
|
||||||
|
r.z, u.z, -f.z, 0.0,
|
||||||
|
-r.dot(&eye), -u.dot(&eye), f.dot(&eye), 1.0,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_ptr(&self) -> *const f32 {
|
||||||
|
self.data.as_ptr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Mul for Mat4 {
|
||||||
|
type Output = Self;
|
||||||
|
fn mul(self, rhs: Self) -> Self {
|
||||||
|
let mut result = [0.0f32; 16];
|
||||||
|
for row in 0..4 {
|
||||||
|
for col in 0..4 {
|
||||||
|
for k in 0..4 {
|
||||||
|
result[col * 4 + row] += self.data[k * 4 + row] * rhs.data[col * 4 + k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self { data: result }
|
||||||
|
}
|
||||||
|
}
|
||||||
181
src/math/vector/vec2.rs
Normal file
181
src/math/vector/vec2.rs
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
use std::ops::{Add, Sub, Mul, Div, Neg, Index, IndexMut};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Vec2 {
|
||||||
|
pub x: f32,
|
||||||
|
pub y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Vec2 {
|
||||||
|
pub const fn new(x: f32, y: f32) -> Self {
|
||||||
|
Self { x, y }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn zero() -> Self {
|
||||||
|
Self { x: 0.0, y: 0.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn one() -> Self {
|
||||||
|
Self { x: 1.0, y: 1.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn length_squared(&self) -> f32 {
|
||||||
|
self.x * self.x + self.y * self.y
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn length(&self) -> f32 {
|
||||||
|
self.length_squared().sqrt()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn normalize(&self) -> Self {
|
||||||
|
let len = self.length();
|
||||||
|
if len == 0.0 {
|
||||||
|
return *self;
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
x: self.x / len,
|
||||||
|
y: self.y / len,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dot(&self, other: &Self) -> f32 {
|
||||||
|
self.x * other.x + self.y * other.y
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_ptr(&self) -> *const f32 {
|
||||||
|
&self.x as *const f32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_mut_ptr(&mut self) -> *mut f32 {
|
||||||
|
&mut self.x as *mut f32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bytes(&self) -> [u8; 8] {
|
||||||
|
let mut bytes = [0u8; 8];
|
||||||
|
bytes[0..4].copy_from_slice(&self.x.to_ne_bytes());
|
||||||
|
bytes[4..8].copy_from_slice(&self.y.to_ne_bytes());
|
||||||
|
bytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for Vec2 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x + rhs.x,
|
||||||
|
y: self.y + rhs.y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<f32> for Vec2 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: f32) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x + rhs,
|
||||||
|
y: self.y + rhs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for Vec2 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x - rhs.x,
|
||||||
|
y: self.y - rhs.y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub<f32> for Vec2 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(self, rhs: f32) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x - rhs,
|
||||||
|
y: self.y - rhs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul for Vec2 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x * rhs.x,
|
||||||
|
y: self.y * rhs.y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<f32> for Vec2 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(self, rhs: f32) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x * rhs,
|
||||||
|
y: self.y * rhs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Div for Vec2 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn div(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x / rhs.x,
|
||||||
|
y: self.y / rhs.y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Div<f32> for Vec2 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn div(self, rhs: f32) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x / rhs,
|
||||||
|
y: self.y / rhs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Neg for Vec2 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn neg(self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: -self.x,
|
||||||
|
y: -self.y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<usize> for Vec2 {
|
||||||
|
type Output = f32;
|
||||||
|
|
||||||
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
|
match index {
|
||||||
|
0 => &self.x,
|
||||||
|
1 => &self.y,
|
||||||
|
_ => panic!("Vec2 index out of bounds: {}", index),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<usize> for Vec2 {
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||||
|
match index {
|
||||||
|
0 => &mut self.x,
|
||||||
|
1 => &mut self.y,
|
||||||
|
_ => panic!("Vec2 index out of bounds: {}", index),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
203
src/math/vector/vec3.rs
Normal file
203
src/math/vector/vec3.rs
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
use std::ops::{Add, Sub, Mul, Div, Neg, Index, IndexMut};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Vec3 {
|
||||||
|
pub x: f32,
|
||||||
|
pub y: f32,
|
||||||
|
pub z: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Vec3 {
|
||||||
|
pub const fn new(x: f32, y: f32, z: f32) -> Self {
|
||||||
|
Self { x, y, z }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn zero() -> Self {
|
||||||
|
Self { x: 0.0, y: 0.0, z: 0.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn one() -> Self {
|
||||||
|
Self { x: 1.0, y: 1.0, z: 1.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn length_squared(&self) -> f32 {
|
||||||
|
self.x * self.x + self.y * self.y + self.z * self.z
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn length(&self) -> f32 {
|
||||||
|
self.length_squared().sqrt()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn normalize(&self) -> Self {
|
||||||
|
let len = self.length();
|
||||||
|
if len == 0.0 {
|
||||||
|
return *self;
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
x: self.x / len,
|
||||||
|
y: self.y / len,
|
||||||
|
z: self.z / len,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dot(&self, other: &Self) -> f32 {
|
||||||
|
self.x * other.x + self.y * other.y + self.z * other.z
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cross(&self, other: &Self) -> Self {
|
||||||
|
Self {
|
||||||
|
x: self.y * other.z - self.z * other.y,
|
||||||
|
y: self.z * other.x - self.x * other.z,
|
||||||
|
z: self.x * other.y - self.y * other.x,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_ptr(&self) -> *const f32 {
|
||||||
|
&self.x as *const f32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_mut_ptr(&mut self) -> *mut f32 {
|
||||||
|
&mut self.x as *mut f32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bytes(&self) -> [u8; 12] {
|
||||||
|
let mut bytes = [0u8; 12];
|
||||||
|
bytes[0..4].copy_from_slice(&self.x.to_ne_bytes());
|
||||||
|
bytes[4..8].copy_from_slice(&self.y.to_ne_bytes());
|
||||||
|
bytes[8..12].copy_from_slice(&self.z.to_ne_bytes());
|
||||||
|
bytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for Vec3 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x + rhs.x,
|
||||||
|
y: self.y + rhs.y,
|
||||||
|
z: self.z + rhs.z,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<f32> for Vec3 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: f32) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x + rhs,
|
||||||
|
y: self.y + rhs,
|
||||||
|
z: self.z + rhs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for Vec3 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x - rhs.x,
|
||||||
|
y: self.y - rhs.y,
|
||||||
|
z: self.z - rhs.z,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub<f32> for Vec3 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(self, rhs: f32) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x - rhs,
|
||||||
|
y: self.y - rhs,
|
||||||
|
z: self.z - rhs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul for Vec3 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x * rhs.x,
|
||||||
|
y: self.y * rhs.y,
|
||||||
|
z: self.z * rhs.z,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<f32> for Vec3 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(self, rhs: f32) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x * rhs,
|
||||||
|
y: self.y * rhs,
|
||||||
|
z: self.z * rhs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Div for Vec3 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn div(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x / rhs.x,
|
||||||
|
y: self.y / rhs.y,
|
||||||
|
z: self.z / rhs.z,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Div<f32> for Vec3 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn div(self, rhs: f32) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x / rhs,
|
||||||
|
y: self.y / rhs,
|
||||||
|
z: self.z / rhs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Neg for Vec3 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn neg(self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: -self.x,
|
||||||
|
y: -self.y,
|
||||||
|
z: -self.z,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<usize> for Vec3 {
|
||||||
|
type Output = f32;
|
||||||
|
|
||||||
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
|
match index {
|
||||||
|
0 => &self.x,
|
||||||
|
1 => &self.y,
|
||||||
|
2 => &self.z,
|
||||||
|
_ => panic!("Vec3 index out of bounds: {}", index),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<usize> for Vec3 {
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||||
|
match index {
|
||||||
|
0 => &mut self.x,
|
||||||
|
1 => &mut self.y,
|
||||||
|
2 => &mut self.z,
|
||||||
|
_ => panic!("Vec3 index out of bounds: {}", index),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
209
src/math/vector/vec4.rs
Normal file
209
src/math/vector/vec4.rs
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
use std::ops::{Add, Sub, Mul, Div, Neg, Index, IndexMut};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Vec4 {
|
||||||
|
pub x: f32,
|
||||||
|
pub y: f32,
|
||||||
|
pub z: f32,
|
||||||
|
pub w: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Vec4 {
|
||||||
|
pub const fn new(x: f32, y: f32, z: f32, w: f32) -> Self {
|
||||||
|
Self { x, y, z, w }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn zero() -> Self {
|
||||||
|
Self { x: 0.0, y: 0.0, z: 0.0, w: 0.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn one() -> Self {
|
||||||
|
Self { x: 1.0, y: 1.0, z: 1.0, w: 1.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn length_squared(&self) -> f32 {
|
||||||
|
self.x * self.x + self.y * self.y + self.z * self.z + self.w * self.w
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn length(&self) -> f32 {
|
||||||
|
self.length_squared().sqrt()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn normalize(&self) -> Self {
|
||||||
|
let len = self.length();
|
||||||
|
if len == 0.0 {
|
||||||
|
return *self;
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
x: self.x / len,
|
||||||
|
y: self.y / len,
|
||||||
|
z: self.z / len,
|
||||||
|
w: self.w / len,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dot(&self, other: &Self) -> f32 {
|
||||||
|
self.x * other.x + self.y * other.y + self.z * other.z + self.w * other.w
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_ptr(&self) -> *const f32 {
|
||||||
|
&self.x as *const f32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_mut_ptr(&mut self) -> *mut f32 {
|
||||||
|
&mut self.x as *mut f32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bytes(&self) -> [u8; 16] {
|
||||||
|
let mut bytes = [0u8; 16];
|
||||||
|
bytes[0..4].copy_from_slice(&self.x.to_ne_bytes());
|
||||||
|
bytes[4..8].copy_from_slice(&self.y.to_ne_bytes());
|
||||||
|
bytes[8..12].copy_from_slice(&self.z.to_ne_bytes());
|
||||||
|
bytes[12..16].copy_from_slice(&self.w.to_ne_bytes());
|
||||||
|
bytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for Vec4 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x + rhs.x,
|
||||||
|
y: self.y + rhs.y,
|
||||||
|
z: self.z + rhs.z,
|
||||||
|
w: self.w + rhs.w,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<f32> for Vec4 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: f32) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x + rhs,
|
||||||
|
y: self.y + rhs,
|
||||||
|
z: self.z + rhs,
|
||||||
|
w: self.w + rhs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for Vec4 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x - rhs.x,
|
||||||
|
y: self.y - rhs.y,
|
||||||
|
z: self.z - rhs.z,
|
||||||
|
w: self.w - rhs.w,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub<f32> for Vec4 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(self, rhs: f32) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x - rhs,
|
||||||
|
y: self.y - rhs,
|
||||||
|
z: self.z - rhs,
|
||||||
|
w: self.w - rhs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul for Vec4 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x * rhs.x,
|
||||||
|
y: self.y * rhs.y,
|
||||||
|
z: self.z * rhs.z,
|
||||||
|
w: self.w * rhs.w,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<f32> for Vec4 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(self, rhs: f32) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x * rhs,
|
||||||
|
y: self.y * rhs,
|
||||||
|
z: self.z * rhs,
|
||||||
|
w: self.w * rhs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Div for Vec4 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn div(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x / rhs.x,
|
||||||
|
y: self.y / rhs.y,
|
||||||
|
z: self.z / rhs.z,
|
||||||
|
w: self.w / rhs.w,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Div<f32> for Vec4 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn div(self, rhs: f32) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x / rhs,
|
||||||
|
y: self.y / rhs,
|
||||||
|
z: self.z / rhs,
|
||||||
|
w: self.w / rhs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Neg for Vec4 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn neg(self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: -self.x,
|
||||||
|
y: -self.y,
|
||||||
|
z: -self.z,
|
||||||
|
w: -self.w,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<usize> for Vec4 {
|
||||||
|
type Output = f32;
|
||||||
|
|
||||||
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
|
match index {
|
||||||
|
0 => &self.x,
|
||||||
|
1 => &self.y,
|
||||||
|
2 => &self.z,
|
||||||
|
3 => &self.w,
|
||||||
|
_ => panic!("Vec4 index out of bounds: {}", index),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<usize> for Vec4 {
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||||
|
match index {
|
||||||
|
0 => &mut self.x,
|
||||||
|
1 => &mut self.y,
|
||||||
|
2 => &mut self.z,
|
||||||
|
3 => &mut self.w,
|
||||||
|
_ => panic!("Vec4 index out of bounds: {}", index),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
68
src/math/vector/vector.rs
Normal file
68
src/math/vector/vector.rs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
use std::ops::Sub;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Vec2 {
|
||||||
|
pub x: f32,
|
||||||
|
pub y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Vec3 {
|
||||||
|
pub x: f32,
|
||||||
|
pub y: f32,
|
||||||
|
pub z: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for Vec3 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x - rhs.x,
|
||||||
|
y: self.y - rhs.y,
|
||||||
|
z: self.z - rhs.z,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Vec3 {
|
||||||
|
pub fn length(&self) -> f32 {
|
||||||
|
(self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn normalize(&mut self) -> Self {
|
||||||
|
let len = self.length();
|
||||||
|
|
||||||
|
if len == 0.0 {
|
||||||
|
return *self;
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
x: self.x / len,
|
||||||
|
y: self.y / len,
|
||||||
|
z: self.z / len,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dot(&self, other: Vec3) -> f32 {
|
||||||
|
self.x * other.x + self.y * other.y + self.z * other.z
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cross(&self, other: Self) -> Self {
|
||||||
|
Self {
|
||||||
|
x: self.y * other.z - self.z * other.y,
|
||||||
|
y: self.z * other.x - self.x * other.z,
|
||||||
|
z: self.x * other.y - self.y * other.x,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Vec4 {
|
||||||
|
pub x: f32,
|
||||||
|
pub y: f32,
|
||||||
|
pub z: f32,
|
||||||
|
pub w: f32,
|
||||||
|
}
|
||||||
61
src/models/model.rs
Normal file
61
src/models/model.rs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
use crate::geometry::Mesh;
|
||||||
|
use crate::assets::mtl::Material;
|
||||||
|
use crate::handles::{ MeshHandle, MaterialHandle };
|
||||||
|
use crate::assets::types::ObjData;
|
||||||
|
use crate::math::Mat4;
|
||||||
|
|
||||||
|
pub struct ModelData {
|
||||||
|
pub name: String,
|
||||||
|
pub meshes: Vec<Mesh>,
|
||||||
|
pub materials: Vec<Material>,
|
||||||
|
pub transform: Mat4,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&ObjData> for ModelData {
|
||||||
|
fn from(obj: &ObjData) -> Self {
|
||||||
|
let meshes = obj.meshes.iter()
|
||||||
|
.map(|obj_mesh| Mesh::new(obj, obj_mesh))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
ModelData {
|
||||||
|
name: String::new(),
|
||||||
|
meshes,
|
||||||
|
materials: Vec::new(),
|
||||||
|
transform: Mat4::identity(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Model {
|
||||||
|
pub name: String,
|
||||||
|
pub parts: Vec<(MeshHandle, MaterialHandle)>,
|
||||||
|
pub transform: Mat4,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Model {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
name: String::new(),
|
||||||
|
parts: Vec::new(),
|
||||||
|
transform: Mat4::identity(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Model {
|
||||||
|
/// Set position (translation)
|
||||||
|
pub fn set_position(&mut self, x: f32, y: f32, z: f32) {
|
||||||
|
self.transform = Mat4::translation(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set scale
|
||||||
|
pub fn set_scale(&mut self, x: f32, y: f32, z: f32) {
|
||||||
|
self.transform = Mat4::scale(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set full transform (for combining translation * rotation * scale)
|
||||||
|
pub fn set_transform(&mut self, transform: Mat4) {
|
||||||
|
self.transform = transform;
|
||||||
|
}
|
||||||
|
}
|
||||||
87
src/shaders/constants.rs
Normal file
87
src/shaders/constants.rs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
pub const VERTEX_SHADER_SOURCE: &str = r#"
|
||||||
|
#version 330 core
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 a_position;
|
||||||
|
layout(location = 1) in vec3 a_normal;
|
||||||
|
layout(location = 2) in vec2 a_texcoord;
|
||||||
|
|
||||||
|
uniform mat4 u_model;
|
||||||
|
uniform mat4 u_view;
|
||||||
|
uniform mat4 u_projection;
|
||||||
|
|
||||||
|
out vec3 v_position;
|
||||||
|
out vec3 v_normal;
|
||||||
|
out vec2 v_texcoord;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 world_pos = u_model * vec4(a_position, 1.0);
|
||||||
|
v_position = world_pos.xyz;
|
||||||
|
v_normal = mat3(transpose(inverse(u_model))) * a_normal;
|
||||||
|
v_texcoord = a_texcoord;
|
||||||
|
gl_Position = u_projection * u_view * world_pos;
|
||||||
|
}"#;
|
||||||
|
|
||||||
|
pub const FRAGMENT_SHADER_SOURCE: &str = r#"
|
||||||
|
#version 330 core
|
||||||
|
|
||||||
|
in vec3 v_position;
|
||||||
|
in vec3 v_normal;
|
||||||
|
in vec2 v_texcoord;
|
||||||
|
|
||||||
|
uniform vec3 u_light_pos;
|
||||||
|
uniform vec3 u_light_color;
|
||||||
|
uniform vec3 u_view_pos;
|
||||||
|
|
||||||
|
uniform vec3 u_ambient;
|
||||||
|
uniform vec3 u_diffuse;
|
||||||
|
uniform vec3 u_specular;
|
||||||
|
uniform float u_shininess;
|
||||||
|
|
||||||
|
out vec4 frag_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec3 normal = normalize(v_normal);
|
||||||
|
vec3 light_dir = normalize(u_light_pos - v_position);
|
||||||
|
vec3 view_dir = normalize(u_view_pos - v_position);
|
||||||
|
vec3 halfway = normalize(light_dir + view_dir);
|
||||||
|
|
||||||
|
// Ambient
|
||||||
|
vec3 ambient = u_ambient * 0.1;
|
||||||
|
|
||||||
|
// Diffuse
|
||||||
|
float diff = max(dot(normal, light_dir), 0.0);
|
||||||
|
vec3 diffuse = diff * u_diffuse * u_light_color;
|
||||||
|
|
||||||
|
// Specular (Blinn-Phong)
|
||||||
|
float spec = pow(max(dot(normal, halfway), 0.0), u_shininess);
|
||||||
|
vec3 specular = spec * u_specular * u_light_color;
|
||||||
|
|
||||||
|
vec3 result = ambient + diffuse + specular;
|
||||||
|
frag_color = vec4(result, 1.0);
|
||||||
|
}"#;
|
||||||
|
|
||||||
|
pub const VERTEX_SHADER_2D: &str = r#"
|
||||||
|
#version 330 core
|
||||||
|
|
||||||
|
layout (location = 0) in vec2 a_position;
|
||||||
|
layout (location = 2) in vec4 a_color;
|
||||||
|
|
||||||
|
out vec4 v_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = vec4(a_position, 0.0, 1.0);
|
||||||
|
v_color = a_color;
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
pub const FRAGMENT_SHADER_2D: &str = r#"
|
||||||
|
#version 330 core
|
||||||
|
|
||||||
|
in vec4 v_color;
|
||||||
|
|
||||||
|
out vec4 frag_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
frag_color = v_color;
|
||||||
|
}
|
||||||
|
"#;
|
||||||
55
src/shaders/inputs.rs
Normal file
55
src/shaders/inputs.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
use crate::geometry;
|
||||||
|
|
||||||
|
pub enum InputRequirement {
|
||||||
|
Required,
|
||||||
|
Optional
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ShaderInput {
|
||||||
|
pub semantic: geometry::VertexSemantic,
|
||||||
|
pub component_count: usize,
|
||||||
|
pub data_type: geometry::AttributeType,
|
||||||
|
pub requirement: InputRequirement
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ShaderInputs {
|
||||||
|
pub inputs: Vec<ShaderInput>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShaderInputs {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
inputs: vec![]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn required(
|
||||||
|
mut self,
|
||||||
|
semantic: geometry::VertexSemantic,
|
||||||
|
component_count: usize,
|
||||||
|
data_type: geometry::AttributeType
|
||||||
|
) -> Self {
|
||||||
|
self.inputs.push(ShaderInput {
|
||||||
|
semantic,
|
||||||
|
data_type,
|
||||||
|
component_count,
|
||||||
|
requirement: InputRequirement::Required,
|
||||||
|
});
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn optional(
|
||||||
|
mut self,
|
||||||
|
semantic: geometry::VertexSemantic,
|
||||||
|
component_count: usize,
|
||||||
|
data_type: geometry::AttributeType
|
||||||
|
) -> Self {
|
||||||
|
self.inputs.push(ShaderInput {
|
||||||
|
semantic,
|
||||||
|
data_type,
|
||||||
|
component_count,
|
||||||
|
requirement: InputRequirement::Optional,
|
||||||
|
});
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
19
src/shaders/types.rs
Normal file
19
src/shaders/types.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
pub struct ShaderSource {}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Shader(pub u32);
|
||||||
|
|
||||||
|
impl From<Shader> for u32 {
|
||||||
|
fn from(value: Shader) -> Self {
|
||||||
|
value.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Shader {
|
||||||
|
type Target = u32;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user