major gfx refactor from fixed function to shader based
This commit is contained in:
parent
0c0aa792c1
commit
40b385607d
58 changed files with 3681 additions and 2982 deletions
|
|
@ -36,9 +36,8 @@ fn main() {
|
|||
|
||||
let bindings = bindgen::Builder::default()
|
||||
.header(pxl8_src.join("core/pxl8_log.h").to_str().unwrap())
|
||||
.header(pxl8_src.join("sim/pxl8_sim.h").to_str().unwrap())
|
||||
.header(pxl8_src.join("vxl/pxl8_vxl.h").to_str().unwrap())
|
||||
.header(pxl8_src.join("math/pxl8_noise.h").to_str().unwrap())
|
||||
.header(pxl8_src.join("sim/pxl8_sim.h").to_str().unwrap())
|
||||
.clang_arg(format!("-I{}", pxl8_src.join("bsp").display()))
|
||||
.clang_arg(format!("-I{}", pxl8_src.join("core").display()))
|
||||
.clang_arg(format!("-I{}", pxl8_src.join("math").display()))
|
||||
|
|
@ -50,6 +49,11 @@ fn main() {
|
|||
.blocklist_item("FP_ZERO")
|
||||
.blocklist_item("FP_SUBNORMAL")
|
||||
.blocklist_item("FP_NORMAL")
|
||||
.blocklist_type("pxl8_vec2")
|
||||
.blocklist_type("pxl8_vec3")
|
||||
.blocklist_type("pxl8_vec4")
|
||||
.blocklist_type("pxl8_mat4")
|
||||
.raw_line("pub use crate::math::{pxl8_vec2, pxl8_vec3, pxl8_vec4, pxl8_mat4};")
|
||||
.clang_arg("-DPXL8_NO_SIMD")
|
||||
.use_core()
|
||||
.rustified_enum(".*")
|
||||
|
|
|
|||
|
|
@ -101,6 +101,38 @@ impl Default for CellPortals {
|
|||
}
|
||||
}
|
||||
|
||||
impl Clone for Face {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
first_edge: self.first_edge,
|
||||
lightmap_offset: self.lightmap_offset,
|
||||
num_edges: self.num_edges,
|
||||
plane_id: self.plane_id,
|
||||
side: self.side,
|
||||
styles: self.styles,
|
||||
material_id: self.material_id,
|
||||
aabb_min: self.aabb_min,
|
||||
aabb_max: self.aabb_max,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Plane {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
dist: self.dist,
|
||||
normal: self.normal,
|
||||
type_: self.type_,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Vertex {
|
||||
fn clone(&self) -> Self {
|
||||
Self { position: self.position }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Bsp {
|
||||
inner: pxl8_bsp,
|
||||
pub cell_portals: Box<[CellPortals]>,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,43 @@
|
|||
use core::ops::{Add, Mul, Sub};
|
||||
|
||||
use crate::pxl8::pxl8_vec3;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Vec2 {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
}
|
||||
|
||||
pub type Vec3 = pxl8_vec3;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Vec3 {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
pub z: f32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Vec4 {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
pub z: f32,
|
||||
pub w: f32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Mat4 {
|
||||
pub m: [f32; 16],
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type pxl8_vec2 = Vec2;
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type pxl8_vec3 = Vec3;
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type pxl8_vec4 = Vec4;
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type pxl8_mat4 = Mat4;
|
||||
|
||||
pub const VEC3_ZERO: Vec3 = Vec3 { x: 0.0, y: 0.0, z: 0.0 };
|
||||
pub const VEC3_Y: Vec3 = Vec3 { x: 0.0, y: 1.0, z: 0.0 };
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use libm::sqrtf;
|
|||
|
||||
use crate::bsp::{Bsp, BspBuilder, CellPortals, Edge, Face, Leaf, Node, Plane, Portal, Vertex};
|
||||
use crate::math::{Vec3, Vec3Ext};
|
||||
use crate::pxl8::{pxl8_vec3_cross, pxl8_vec3_dot, pxl8_vec3_normalize, pxl8_vec3_scale, pxl8_vec3_add, pxl8_vec3_sub};
|
||||
|
||||
pub const CELL_SIZE: f32 = 64.0;
|
||||
pub const WALL_HEIGHT: f32 = 128.0;
|
||||
|
|
@ -402,36 +403,139 @@ fn build_pvs_data(bsp: &mut BspBuilder, portals: &[CellPortals]) {
|
|||
bsp.visdata = visdata;
|
||||
}
|
||||
|
||||
const AO_NUM_SAMPLES: usize = 16;
|
||||
const AO_RAY_LENGTH: f32 = 48.0;
|
||||
|
||||
fn generate_hemisphere_samples(normal: Vec3) -> [Vec3; AO_NUM_SAMPLES] {
|
||||
let tangent = if normal.y.abs() < 0.9 {
|
||||
unsafe { pxl8_vec3_normalize(pxl8_vec3_cross(normal, Vec3::new(0.0, 1.0, 0.0))) }
|
||||
} else {
|
||||
unsafe { pxl8_vec3_normalize(pxl8_vec3_cross(normal, Vec3::new(1.0, 0.0, 0.0))) }
|
||||
};
|
||||
let bitangent = unsafe { pxl8_vec3_cross(normal, tangent) };
|
||||
|
||||
let mut samples = [Vec3::new(0.0, 0.0, 0.0); AO_NUM_SAMPLES];
|
||||
for i in 0..AO_NUM_SAMPLES {
|
||||
let phi = (i as f32 / AO_NUM_SAMPLES as f32) * core::f32::consts::TAU;
|
||||
let theta = ((i as f32 + 0.5) / AO_NUM_SAMPLES as f32) * (core::f32::consts::PI * 0.45);
|
||||
let (sin_phi, cos_phi) = (libm::sinf(phi), libm::cosf(phi));
|
||||
let (sin_theta, cos_theta) = (libm::sinf(theta), libm::cosf(theta));
|
||||
|
||||
let local_x = sin_theta * cos_phi;
|
||||
let local_y = cos_theta;
|
||||
let local_z = sin_theta * sin_phi;
|
||||
|
||||
unsafe {
|
||||
let t_contrib = pxl8_vec3_scale(tangent, local_x);
|
||||
let n_contrib = pxl8_vec3_scale(normal, local_y);
|
||||
let b_contrib = pxl8_vec3_scale(bitangent, local_z);
|
||||
samples[i] = pxl8_vec3_normalize(pxl8_vec3_add(pxl8_vec3_add(t_contrib, n_contrib), b_contrib));
|
||||
}
|
||||
}
|
||||
samples
|
||||
}
|
||||
|
||||
fn ray_triangle_intersect(origin: Vec3, dir: Vec3, v0: Vec3, v1: Vec3, v2: Vec3, max_dist: f32) -> bool {
|
||||
let edge1 = unsafe { pxl8_vec3_sub(v1, v0) };
|
||||
let edge2 = unsafe { pxl8_vec3_sub(v2, v0) };
|
||||
let h = unsafe { pxl8_vec3_cross(dir, edge2) };
|
||||
let a = unsafe { pxl8_vec3_dot(edge1, h) };
|
||||
|
||||
if a > -0.0001 && a < 0.0001 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let f = 1.0 / a;
|
||||
let s = unsafe { pxl8_vec3_sub(origin, v0) };
|
||||
let u = f * unsafe { pxl8_vec3_dot(s, h) };
|
||||
if u < 0.0 || u > 1.0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let q = unsafe { pxl8_vec3_cross(s, edge1) };
|
||||
let v = f * unsafe { pxl8_vec3_dot(dir, q) };
|
||||
if v < 0.0 || u + v > 1.0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let t = f * unsafe { pxl8_vec3_dot(edge2, q) };
|
||||
t > 0.001 && t < max_dist
|
||||
}
|
||||
|
||||
fn compute_vertex_ao(bsp: &BspBuilder, pos: Vec3, normal: Vec3) -> f32 {
|
||||
let samples = generate_hemisphere_samples(normal);
|
||||
let offset_pos = unsafe { pxl8_vec3_add(pos, pxl8_vec3_scale(normal, 0.5)) };
|
||||
|
||||
let mut occluded = 0;
|
||||
|
||||
for sample_dir in &samples {
|
||||
'face_loop: for face in &bsp.faces {
|
||||
if face.num_edges < 3 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut verts = [Vec3::new(0.0, 0.0, 0.0); 4];
|
||||
let mut num_verts = 0usize;
|
||||
|
||||
for e in 0..face.num_edges.min(4) {
|
||||
let surfedge_idx = (face.first_edge + e as u32) as usize;
|
||||
if surfedge_idx >= bsp.surfedges.len() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let edge_idx = bsp.surfedges[surfedge_idx];
|
||||
let vert_idx = if edge_idx >= 0 {
|
||||
let ei = edge_idx as usize;
|
||||
if ei >= bsp.edges.len() { continue; }
|
||||
bsp.edges[ei].vertex[0] as usize
|
||||
} else {
|
||||
let ei = (-edge_idx) as usize;
|
||||
if ei >= bsp.edges.len() { continue; }
|
||||
bsp.edges[ei].vertex[1] as usize
|
||||
};
|
||||
|
||||
if vert_idx < bsp.vertices.len() {
|
||||
verts[num_verts] = bsp.vertices[vert_idx].position;
|
||||
num_verts += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if num_verts >= 3 {
|
||||
if ray_triangle_intersect(offset_pos, *sample_dir, verts[0], verts[1], verts[2], AO_RAY_LENGTH) {
|
||||
occluded += 1;
|
||||
break 'face_loop;
|
||||
}
|
||||
if num_verts == 4 {
|
||||
if ray_triangle_intersect(offset_pos, *sample_dir, verts[0], verts[2], verts[3], AO_RAY_LENGTH) {
|
||||
occluded += 1;
|
||||
break 'face_loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1.0 - (occluded as f32 / AO_NUM_SAMPLES as f32)
|
||||
}
|
||||
|
||||
fn compute_vertex_light(
|
||||
pos: Vec3,
|
||||
normal: Vec3,
|
||||
lights: &[LightSource],
|
||||
ambient: f32,
|
||||
) -> f32 {
|
||||
let mut total = ambient;
|
||||
let mut total = 0.0;
|
||||
|
||||
for light in lights {
|
||||
let to_light = Vec3::new(
|
||||
light.position.x - pos.x,
|
||||
light.position.y - pos.y,
|
||||
light.position.z - pos.z,
|
||||
);
|
||||
|
||||
let dist_sq = to_light.x * to_light.x + to_light.y * to_light.y + to_light.z * to_light.z;
|
||||
let dist = sqrtf(dist_sq).max(1.0);
|
||||
let to_light = unsafe { pxl8_vec3_sub(light.position, pos) };
|
||||
let dist = unsafe { pxl8_vec3_dot(to_light, to_light) };
|
||||
let dist = sqrtf(dist).max(1.0);
|
||||
|
||||
if dist > light.radius {
|
||||
continue;
|
||||
}
|
||||
|
||||
let inv_dist = 1.0 / dist;
|
||||
let light_dir = Vec3::new(
|
||||
to_light.x * inv_dist,
|
||||
to_light.y * inv_dist,
|
||||
to_light.z * inv_dist,
|
||||
);
|
||||
|
||||
let ndotl = (normal.x * light_dir.x + normal.y * light_dir.y + normal.z * light_dir.z).max(0.0);
|
||||
let light_dir = unsafe { pxl8_vec3_normalize(to_light) };
|
||||
let ndotl = unsafe { pxl8_vec3_dot(normal, light_dir) }.max(0.0);
|
||||
|
||||
let attenuation = (1.0 - dist / light.radius).max(0.0);
|
||||
let attenuation = attenuation * attenuation;
|
||||
|
|
@ -442,12 +546,13 @@ fn compute_vertex_light(
|
|||
total.min(1.0)
|
||||
}
|
||||
|
||||
fn compute_bsp_vertex_lighting(bsp: &mut BspBuilder, lights: &[LightSource], ambient: f32) {
|
||||
fn compute_bsp_vertex_lighting(bsp: &mut BspBuilder, lights: &[LightSource]) {
|
||||
if bsp.vertices.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
bsp.vertex_lights = vec![0u32; bsp.vertices.len()];
|
||||
let mut vertex_normals: Vec<Option<Vec3>> = vec![None; bsp.vertices.len()];
|
||||
|
||||
for f in 0..bsp.faces.len() {
|
||||
let face = &bsp.faces[f];
|
||||
|
|
@ -478,13 +583,27 @@ fn compute_bsp_vertex_lighting(bsp: &mut BspBuilder, lights: &[LightSource], amb
|
|||
continue;
|
||||
}
|
||||
|
||||
let pos = bsp.vertices[vert_idx].position;
|
||||
let light = compute_vertex_light(pos, normal, lights, ambient);
|
||||
vertex_normals[vert_idx] = Some(normal);
|
||||
|
||||
let light_byte = (light * 255.0) as u8;
|
||||
bsp.vertex_lights[vert_idx] = ((light_byte as u32) << 24) | 0x00FFFFFF;
|
||||
let pos = bsp.vertices[vert_idx].position;
|
||||
let direct = compute_vertex_light(pos, normal, lights);
|
||||
let direct_byte = ((direct * 255.0).min(255.0)) as u8;
|
||||
|
||||
bsp.vertex_lights[vert_idx] = (bsp.vertex_lights[vert_idx] & 0x00FFFFFF) | ((direct_byte as u32) << 24);
|
||||
}
|
||||
}
|
||||
|
||||
for vert_idx in 0..bsp.vertices.len() {
|
||||
let normal = match vertex_normals[vert_idx] {
|
||||
Some(n) => n,
|
||||
None => continue,
|
||||
};
|
||||
let pos = bsp.vertices[vert_idx].position;
|
||||
let ao = compute_vertex_ao(bsp, pos, normal);
|
||||
let ao_byte = ((ao * 255.0).min(255.0)) as u8;
|
||||
|
||||
bsp.vertex_lights[vert_idx] = (bsp.vertex_lights[vert_idx] & 0xFF00FFFF) | ((ao_byte as u32) << 16);
|
||||
}
|
||||
}
|
||||
|
||||
fn grid_to_bsp(bsp: &mut BspBuilder, grid: &RoomGrid) {
|
||||
|
|
@ -926,17 +1045,27 @@ pub fn generate_rooms(params: &ProcgenParams) -> Bsp {
|
|||
grid_to_bsp(&mut bsp, &grid);
|
||||
|
||||
let light_height = 80.0;
|
||||
let lights: Vec<LightSource> = rooms.iter().map(|room| {
|
||||
let fireball_pos = Vec3::new(384.0, light_height, 324.0);
|
||||
let fireball_exclusion_radius = 150.0;
|
||||
|
||||
let lights: Vec<LightSource> = rooms.iter().filter_map(|room| {
|
||||
let cx = (room.x as f32 + room.w as f32 / 2.0) * CELL_SIZE;
|
||||
let cy = (room.y as f32 + room.h as f32 / 2.0) * CELL_SIZE;
|
||||
LightSource {
|
||||
position: Vec3::new(cx, light_height, cy),
|
||||
intensity: 0.8,
|
||||
radius: 300.0,
|
||||
let cz = (room.y as f32 + room.h as f32 / 2.0) * CELL_SIZE;
|
||||
|
||||
let dx = cx - fireball_pos.x;
|
||||
let dz = cz - fireball_pos.z;
|
||||
if dx * dx + dz * dz < fireball_exclusion_radius * fireball_exclusion_radius {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(LightSource {
|
||||
position: Vec3::new(cx, light_height, cz),
|
||||
intensity: 1.8,
|
||||
radius: 160.0,
|
||||
})
|
||||
}).collect();
|
||||
|
||||
compute_bsp_vertex_lighting(&mut bsp, &lights, 0.1);
|
||||
compute_bsp_vertex_lighting(&mut bsp, &lights);
|
||||
|
||||
bsp.into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,20 @@ impl Default for Entity {
|
|||
}
|
||||
}
|
||||
|
||||
impl Clone for Entity {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
pos: self.pos,
|
||||
vel: self.vel,
|
||||
yaw: self.yaw,
|
||||
pitch: self.pitch,
|
||||
flags: self.flags,
|
||||
kind: self.kind,
|
||||
_pad: self._pad,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Simulation {
|
||||
pub entities: Vec<Entity>,
|
||||
pub free_list: Vec<u32>,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue