Skip to content

Commit

Permalink
pal4: Support raycasting to detect floor height
Browse files Browse the repository at this point in the history
  • Loading branch information
dontpanic92 committed Apr 13, 2024
1 parent a27cdf5 commit 03fbca0
Show file tree
Hide file tree
Showing 18 changed files with 466 additions and 31 deletions.
5 changes: 4 additions & 1 deletion crosscom/ccidl/idl/radiance.idl
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,10 @@ interface IEntity: IComponentContainer {
class Entity: IEntity {}

[uuid(8dd91852-476b-401b-8668-ba9cc331b7a1)]
interface IStaticMeshComponent: IComponent {}
interface IStaticMeshComponent: IComponent {
[internal(), rust()]
&'static radiance::components::mesh::static_mesh::StaticMeshComponent get();
}

[uuid(aa9cfbdc-59a2-4e9e-9280-f77d52e79494)]
class StaticMeshComponent: IStaticMeshComponent {}
Expand Down
26 changes: 25 additions & 1 deletion radiance/radiance/src/comdef.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1996,6 +1996,9 @@ pub struct IStaticMeshComponentVirtualTable {
delta_sec: std::os::raw::c_float,
) -> (),
pub on_unloading: unsafe extern "system" fn(this: *const *const std::os::raw::c_void) -> (),
pub get: fn(
this: *const *const std::os::raw::c_void,
) -> &'static radiance::components::mesh::static_mesh::StaticMeshComponent,
}

#[repr(C)]
Expand Down Expand Up @@ -2077,13 +2080,24 @@ impl IStaticMeshComponent {
}
}

pub fn get(&self) -> &'static radiance::components::mesh::static_mesh::StaticMeshComponent {
unsafe {
let this = self as *const IStaticMeshComponent as *const *const std::os::raw::c_void;
let ret = ((*self.vtable).get)(this);

ret
}
}

pub fn uuid() -> uuid::Uuid {
use crosscom::ComInterface;
uuid::Uuid::from_bytes(IStaticMeshComponent::INTERFACE_ID)
}
}

pub trait IStaticMeshComponentImpl {}
pub trait IStaticMeshComponentImpl {
fn get(&self) -> &'static radiance::components::mesh::static_mesh::StaticMeshComponent;
}

impl crosscom::ComInterface for IStaticMeshComponent {
// 8dd91852-476b-401b-8668-ba9cc331b7a1
Expand Down Expand Up @@ -2184,6 +2198,15 @@ macro_rules! ComObject_StaticMeshComponent {
(previous - 1) as std::os::raw::c_long
}

fn get(
this: *const *const std::os::raw::c_void,
) -> &'static radiance::components::mesh::static_mesh::StaticMeshComponent {
unsafe {
let __crosscom_object = crosscom::get_object::<StaticMeshComponentCcw>(this);
(*__crosscom_object).inner.get()
}
}

unsafe extern "system" fn on_loading(this: *const *const std::os::raw::c_void) -> () {
let __crosscom_object = crosscom::get_object::<StaticMeshComponentCcw>(this);
(*__crosscom_object).inner.on_loading().into()
Expand Down Expand Up @@ -2219,6 +2242,7 @@ macro_rules! ComObject_StaticMeshComponent {
on_loading,
on_updating,
on_unloading,
get,
},
};

Expand Down
12 changes: 11 additions & 1 deletion radiance/radiance/src/components/mesh/static_mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::rc::Rc;
use crosscom::ComRc;

use crate::{
comdef::{IComponentImpl, IEntity},
comdef::{IComponentImpl, IEntity, IStaticMeshComponent, IStaticMeshComponentImpl},
rendering::ComponentFactory,
ComObject_StaticMeshComponent,
};
Expand All @@ -30,6 +30,16 @@ impl StaticMeshComponent {
component_factory,
}
}

pub fn get_geometries(&self) -> &[Geometry] {
&self.geometries
}
}

impl IStaticMeshComponentImpl for StaticMeshComponent {
fn get(&self) -> &'static StaticMeshComponent {
unsafe { &*(self as *const _) }
}
}

impl IComponentImpl for StaticMeshComponent {
Expand Down
6 changes: 5 additions & 1 deletion radiance/radiance/src/math/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,14 @@ impl Vec3 {
Vec3::new(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z)
}

pub fn dot(lhs: f32, rhs: &Vec3) -> Self {
pub fn scalar_mul(lhs: f32, rhs: &Vec3) -> Self {
Vec3::new(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z)
}

pub fn dot(lhs: &Vec3, rhs: &Vec3) -> f32 {
lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z
}

pub fn cross(lhs: &Vec3, rhs: &Vec3) -> Self {
Vec3::new(
lhs.y * rhs.z - lhs.z * rhs.y,
Expand Down
17 changes: 17 additions & 0 deletions radiance/radiance/src/rendering/vertex_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,4 +288,21 @@ impl VertexBuffer {
pub fn components(&self) -> VertexComponents {
self.layout.components
}

pub fn to_position_vec(&self) -> Vec<Vec3> {
let vertex_size = self.layout.size;
let mut result = Vec::with_capacity(self.count);
let offset = self.layout.get_offset(VertexComponents::POSITION).unwrap();
for i in 0..self.count {
let data: &Vec3 = unsafe {
&*(self
.data
.as_ptr()
.offset((i * vertex_size + offset) as isize) as *const Vec3)
};
result.push(*data);
}

result
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ float4 main(
float2 texcoord : TEXCOORD0
) {
float4 color = tex2D(texSampler, texcoord);
if (color.a < 0.9) {
if (color.a < 0.4) {
discard;
}
} else {
color.a = 1.0;
}

return color;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@ void main() {
outColor = texture(texSampler, fragTexCoord);
if (outColor.a < 0.4) {
discard;
} else {
outColor.a = 1.0;
}
}
}
4 changes: 2 additions & 2 deletions radiance/radiance/src/utils/free_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ impl FreeViewController {

if movement.norm() > 0.0 {
movement.normalize();
movement = Vec3::dot(SPEED * delta_sec, &movement);
movement = Vec3::scalar_mul(SPEED * delta_sec, &movement);

transform.translate_local(&movement);
}
Expand All @@ -62,7 +62,7 @@ impl FreeViewController {

if movement.norm() > 0.0 {
movement.normalize();
movement = Vec3::dot(SPEED * delta_sec, &movement);
movement = Vec3::scalar_mul(SPEED * delta_sec, &movement);

transform.translate(&movement);
}
Expand Down
1 change: 1 addition & 0 deletions radiance/radiance/src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod act_drop;
pub mod free_view;
pub mod interp_value;
pub mod ray_casting;

use std::io::{Read, Seek};

Expand Down
178 changes: 178 additions & 0 deletions radiance/radiance/src/utils/ray_casting/mesh.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
use crate::math::Vec3;

use super::AARayDirection;

struct Triangle {
indices: [u32; 3],
aabb_min: Vec3,
aabb_max: Vec3,
}

impl Triangle {
pub fn new(indices: [u32; 3], vertices: &Vec<Vec3>) -> Self {
let a = vertices[indices[0] as usize];
let b = vertices[indices[1] as usize];
let c = vertices[indices[2] as usize];
let aabb_min = Vec3::new(
a.x.min(b.x).min(c.x),
a.y.min(b.y).min(c.y),
a.z.min(b.z).min(c.z),
);
let aabb_max = Vec3::new(
a.x.max(b.x).max(c.x),
a.y.max(b.y).max(c.y),
a.z.max(b.z).max(c.z),
);

Self {
indices,
aabb_min,
aabb_max,
}
}

pub fn cast_aaray(
&self,
ray_origin: Vec3,
aaray: AARayDirection,
vertices: &Vec<Vec3>,
) -> Option<f32> {
let aabb_min = self.aabb_min;
let aabb_max = self.aabb_max;
let ray_direction = aaray.get_direction();

if ray_direction.x != 0. {
if ray_origin.y < aabb_min.y
|| ray_origin.y > aabb_max.y
|| ray_origin.z < aabb_min.z
|| ray_origin.z > aabb_max.z
{
return None;
}
} else if ray_direction.y != 0. {
if ray_origin.x < aabb_min.x
|| ray_origin.x > aabb_max.x
|| ray_origin.z < aabb_min.z
|| ray_origin.z > aabb_max.z
{
return None;
}
} else if ray_direction.z != 0. {
if ray_origin.x < aabb_min.x
|| ray_origin.x > aabb_max.x
|| ray_origin.y < aabb_min.y
|| ray_origin.y > aabb_max.y
{
return None;
}
}

self.cast_ray(ray_origin, ray_direction, vertices)
}

pub fn cast_ray(
&self,
ray_origin: Vec3,
ray_direction: Vec3,
vertices: &Vec<Vec3>,
) -> Option<f32> {
const EPSILON: f32 = 0.00001;
let edge1 = Vec3::sub(
&vertices[self.indices[1] as usize],
&vertices[self.indices[0] as usize],
);
let edge2 = Vec3::sub(
&vertices[self.indices[2] as usize],
&vertices[self.indices[0] as usize],
);

let h = Vec3::cross(&ray_direction, &edge2);
let a = Vec3::dot(&edge1, &h);

if a > -EPSILON && a < EPSILON {
// println!("none1");
return None;
}

let f = 1.0 / a;
let s = Vec3::sub(&ray_origin, &vertices[self.indices[0] as usize]);
let u = f * Vec3::dot(&s, &h);
if u < 0.0 || u > 1.0 {
// println!("none2");
return None;
}

let q = Vec3::cross(&s, &edge1);
let v = f * Vec3::dot(&ray_direction, &q);

if v < 0.0 || u + v > 1.0 {
// println!("none3");
return None;
}

let t = f * Vec3::dot(&edge2, &q);

if t > EPSILON {
Some(t)
} else {
// println!("none4 t: {}", t);
None
}
}
}

pub(crate) struct Mesh {
vertices: Vec<Vec3>,
triangles: Vec<Triangle>,
}

impl Mesh {
pub fn new(vertices: Vec<Vec3>, indices: Vec<u32>) -> Self {
let mut triangles = Vec::new();
for i in (0..indices.len()).step_by(3) {
triangles.push(Triangle::new(
[indices[i], indices[i + 1], indices[i + 2]],
&vertices,
));
}

Self {
vertices,
triangles,
}
}

pub fn cast_aaray(&self, ray_origin: Vec3, aaray: AARayDirection) -> Option<f32> {
let mut min_distance = None;
for triangle in &self.triangles {
if let Some(distance) = triangle.cast_aaray(ray_origin, aaray, &self.vertices) {
if let Some(md) = min_distance {
if distance < md {
min_distance = Some(distance);
}
} else {
min_distance = Some(distance);
}
}
}

min_distance
}

pub fn cast_ray(&self, ray_origin: Vec3, ray_direction: Vec3) -> Option<f32> {
let mut min_distance = None;
for triangle in &self.triangles {
if let Some(distance) = triangle.cast_ray(ray_origin, ray_direction, &self.vertices) {
if let Some(md) = min_distance {
if distance < md {
min_distance = Some(distance);
}
} else {
min_distance = Some(distance);
}
}
}

min_distance
}
}
Loading

0 comments on commit 03fbca0

Please sign in to comment.