Skip to content

Commit

Permalink
Exposing more BSP model info to Python
Browse files Browse the repository at this point in the history
Also fixed a bug with poly splitting
  • Loading branch information
cmbasnett committed Apr 24, 2024
1 parent ae031c6 commit 640769a
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 83 deletions.
8 changes: 6 additions & 2 deletions src/brush.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use crate::coords::{FCoords, FModelCoords};
#[derive(Debug, PartialEq)]
pub struct ABrush {
pub model: UModel,
pub id: usize,
pub name: String,
pub location: FVector,
pub pre_pivot: FVector,
pub poly_flags: EPolyFlags,
Expand All @@ -15,13 +17,15 @@ pub struct ABrush {

impl ABrush {
// TODO: consider just nuking the location & prepivot and expect the user to pass in the world-space polys.
pub fn new(polys: &[FPoly], location: FVector, poly_flags: EPolyFlags, csg_operation: ECsgOper) -> Self {
pub fn new(id: usize, name: String, polys: &[FPoly], poly_flags: EPolyFlags, csg_operation: ECsgOper) -> Self {
let mut model = UModel::new(true);
model.polys = polys.to_vec();
bsp_validate_brush(&mut model, false);
ABrush {
id,
name,
model,
location,
location: FVector::new(0.0, 0.0, 0.0),
pre_pivot: FVector::new(0.0, 0.0, 0.0),
poly_flags,
csg_operation,
Expand Down
31 changes: 5 additions & 26 deletions src/bsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ pub fn bsp_add_node(model: &mut UModel, mut parent_node_index: Option<usize>, no
surf.texture_u_index = model.bsp_add_vector(ed_poly.texture_u, false);
surf.texture_v_index = model.bsp_add_vector(ed_poly.texture_v, false);
// Surf->Material = EdPoly->Material;
// Surf->Actor = EdPoly->Actor;
surf.brush_id = ed_poly.brush_id.unwrap();
surf.poly_flags = ed_poly.poly_flags & !EPolyFlags::NoAddToBSP;
surf.light_map_scale = ed_poly.light_map_scale;
surf.brush_polygon_index = ed_poly.brush_poly_index;
Expand Down Expand Up @@ -498,7 +498,7 @@ fn filter_leaf(filter_func: BspFilterFunc, model: &mut UModel, node_index: usize
// in order to handle coplanar CSG properly.
fn filter_ed_poly(filter_func: BspFilterFunc, model: &mut UModel, mut node_index: usize, ed_poly: &mut FPoly, mut coplanar_info: FCoplanarInfo, mut outside: bool, filter_context: &mut FilterContext) {
loop {
if ed_poly.vertices.len() > FPOLY_VERTEX_THRESHOLD {
if ed_poly.vertices.len() >= FPOLY_VERTEX_THRESHOLD {
// Split EdPoly in half to prevent vertices from overflowing.
if let Some(mut temp) = ed_poly.split_in_half() {
filter_ed_poly(filter_func, model, node_index, &mut temp, coplanar_info, outside, filter_context);
Expand Down Expand Up @@ -533,8 +533,6 @@ fn filter_ed_poly(filter_func: BspFilterFunc, model: &mut UModel, mut node_index
}
}
ESplitType::Coplanar => {
println!("coplanar!");

if coplanar_info.original_node.is_some() {
// This will happen once in a blue moon when a polygon is barely outside the
// coplanar threshold and is split up into a new polygon that is
Expand Down Expand Up @@ -683,18 +681,9 @@ pub fn bsp_merge_coplanars(model: &mut UModel, should_remap_links: bool, should_
// Mark all polys as unprocessed.
model.polys.iter_mut().for_each(|poly| poly.poly_flags.remove(EPolyFlags::EdProcessed));

println!("BspMergeCoplanars: {} polys", model.polys.len());

// Find matching coplanars and merge them.
let mut poly_list: Vec<usize> = vec![0; model.polys.len()];

println!("Length of poly_list: {}", poly_list.len());

// Print out all the vertices for each poly.
for (i, poly) in model.polys.iter().enumerate() {
println!("Poly {} vertices: {:?}", i, poly.vertices);
}

let mut n = 0;

for i in 0..model.polys.len() {
Expand Down Expand Up @@ -819,7 +808,7 @@ fn bsp_node_to_fpoly(model: &UModel, node_index: usize) -> Option<FPoly> {
ed_poly.poly_flags &= !(EPolyFlags::EdCut | EPolyFlags::EdProcessed | EPolyFlags::Selected | EPolyFlags::Memorized);
ed_poly.link = Some(node.surface_index);
//ed_poly.material = poly.material;
//ed_poly.actor = poly.actor;
ed_poly.brush_id = Some(poly.brush_id);
ed_poly.brush_poly_index = poly.brush_polygon_index;

// TODO: item name crap
Expand Down Expand Up @@ -882,18 +871,13 @@ pub struct FilterContext<'a> {

/// Filter all relevant world polys through the brush.
fn filter_world_through_brush(model: &mut UModel, brush: &mut UModel, csg_operation: ECsgOper, mut node_index: usize, brush_sphere: FSphere) {
if csg_operation == ECsgOper::Add {
println!("filter_world_through_brush: node_index = {}", node_index);
}

// Loop through all coplanars.
loop {
// Get surface.
let surface_index = model.nodes[node_index].surface_index;

// Skip new nodes and their children, which are guaranteeed new.
if model.nodes[node_index].node_flags.contains(EBspNodeFlags::IsNew) {
println!("filter_world_through_brush: skipping new node");
return
}

Expand All @@ -906,7 +890,7 @@ fn filter_world_through_brush(model: &mut UModel, brush: &mut UModel, csg_operat
// Process only polys that aren't empty.
if do_front && do_back {
if let Some(mut temp_ed_poly) = bsp_node_to_fpoly(model, node_index) {
//temp_ed_poly.actor = model.surfaces[surface_index].actor;
temp_ed_poly.brush_id = Some(model.surfaces[surface_index].brush_id);
temp_ed_poly.brush_poly_index = model.surfaces[surface_index].brush_polygon_index;

// Find last coplanar in chain.
Expand Down Expand Up @@ -938,9 +922,6 @@ fn filter_world_through_brush(model: &mut UModel, brush: &mut UModel, csg_operat
filter_context.model.nodes[filter_context.last_coplanar_node_index].plane_index = None;
filter_context.model.nodes.truncate(node_count);
} else {

println!("original world poly tagged for deletion, {} fragments added", filter_context.discarded);

// Tag original world poly for deletion; has been deleted or replaced by partial fragments.
filter_context.model.nodes[filter_context.node_index].vertex_count = 0;
}
Expand Down Expand Up @@ -1004,7 +985,7 @@ pub fn bsp_brush_csg(
assert!(brush.polys[poly_index].link.is_none() || brush.polys[poly_index].link.unwrap() < brush.polys.len());

// Set its backward brush link.
// dest_ed_poly.actor = Some(actor_copy.clone());
dest_ed_poly.brush_id = Some(actor.id);
dest_ed_poly.brush_poly_index = Some(poly_index);

// Update its flags.
Expand Down Expand Up @@ -1079,8 +1060,6 @@ pub fn bsp_brush_csg(
// Does the sphere get modified here?
let brush_sphere = temp_model.bounding_sphere.clone();

println!("Bounding sphere: {:?}", brush_sphere);

filter_world_through_brush(model, &mut temp_model, csg_operation, 0, brush_sphere);
}

Expand Down
8 changes: 3 additions & 5 deletions src/fpoly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ use crate::fpoly::ESplitPlaneStatus::Front;
use crate::math::{self, transform_vector_by_coords, FLOAT_NORMAL_THRESH, SMALL_NUMBER, THRESH_POINT_ON_PLANE};
use crate::math::{point_plane_distance, line_plane_intersection, THRESH_SPLIT_POLY_WITH_PLANE, points_are_near, THRESH_ZERO_NORM_SQUARED};
use crate::model::UModel;
use crate::brush::ABrush;
use std::rc::Rc;
use std::cell::RefCell;

/// Maximum vertices an FPoly may have.
pub const FPOLY_MAX_VERTICES: usize = 16;
Expand Down Expand Up @@ -134,7 +131,7 @@ pub struct FPoly {
/// FPoly & Bsp poly bit flags (PF_).
pub poly_flags: EPolyFlags,
/// Brush where this originated, or NULL.
pub actor: Option<Rc<RefCell<ABrush>>>,
pub brush_id: Option<usize>,
/// Material.
//material: Rc<UMaterial>,
/// Item name.
Expand Down Expand Up @@ -166,6 +163,7 @@ impl FPoly {

pub fn from_vertices(vertices: &[FVector]) -> Self {
let mut fpoly = FPoly::new();
// TODO: this fails when there are more verts than can be added.
_ = fpoly.vertices.try_extend_from_slice(vertices);
fpoly.base = fpoly.vertices[0]; // TODO: the selection of the base vertex seems arbitrary
_ = fpoly.calc_normal();
Expand All @@ -189,7 +187,7 @@ impl FPoly {
texture_v: FVector { x: 0.0, y: 0.0, z: 0.0 },
vertices: Default::default(),
poly_flags: EPolyFlags::from_bits_retain(0),
actor: None,
brush_id: None,
link: Some(0),
brush_poly_index: None,
save_poly_index: None,
Expand Down
41 changes: 23 additions & 18 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ impl From<&str> for CsgOperation {

#[pyclass]
struct Brush {
id: usize,
name: String,
polys: Vec<Poly>,
poly_flags: HashSet<String>,
csg_operation: CsgOperation,
Expand Down Expand Up @@ -104,8 +106,9 @@ impl From<&PyRef<'_, Brush>> for crate::brush::ABrush {
fn from(brush: &PyRef<Brush>) -> Self {
let polys: Vec<FPoly> = brush.polys.iter().map(|poly| FPoly::from(poly)).collect();
crate::brush::ABrush::new(
brush.id,
brush.name.clone(),
polys.as_slice(),
math::FVector::new(0.0, 0.0, 0.0),
EPolyFlags::from(&brush.poly_flags),
brush.csg_operation.into())
}
Expand All @@ -114,13 +117,13 @@ impl From<&PyRef<'_, Brush>> for crate::brush::ABrush {
#[pymethods]
impl Brush {
#[new]
fn new(polys: Vec<PyRef<Poly>>, poly_flags: HashSet<String>, csg_operation: &str) -> Self {
fn new(id: usize, name: String, polys: Vec<PyRef<Poly>>, poly_flags: HashSet<String>, csg_operation: &str) -> Self {
// Create a copy of the polys and pass them to the brush.
let polys: Vec<Poly> = polys.iter().map(|poly|
Poly { vertices: poly.vertices.clone() }
).collect();

Brush { polys, poly_flags, csg_operation: CsgOperation::from(csg_operation) }
Brush { id, name, polys, poly_flags, csg_operation: CsgOperation::from(csg_operation) }
}
}

Expand All @@ -134,11 +137,27 @@ impl From<&Poly> for FPoly {
#[pyclass]
#[derive(Clone, Copy, Debug)]
struct BspSurface {
#[pyo3(get)]
pub normal_index: usize,
#[pyo3(get)]
pub texture_u_index: usize,
#[pyo3(get)]
pub texture_v_index: usize,
#[pyo3(get)]
pub brush_id: usize,
#[pyo3(get)]
pub brush_polygon_index: usize,
}

impl From<&FBspSurf> for BspSurface {
fn from(surface: &FBspSurf) -> Self {
BspSurface {}
BspSurface {
normal_index: surface.normal_index,
texture_u_index: surface.texture_u_index,
texture_v_index: surface.texture_v_index,
brush_id: surface.brush_id,
brush_polygon_index: surface.brush_polygon_index.unwrap(),
}
}
}

Expand Down Expand Up @@ -216,24 +235,10 @@ fn csg_rebuild(brushes: Vec<PyRef<Brush>>) -> PyResult<Model> {
// Convert the Brushes to ABrushes and add them to the level brush list.
let brushes: Vec<crate::brush::ABrush> = brushes.iter().map(|brush| brush.into()).collect();

println!("Brushes: {:?}", brushes.len());

let mut level = ULevel::new(brushes);

// Print debug info on the brushes.
for brush in &level.brushes {
brush.model.polys.iter().for_each(|poly| {
println!("Poly: {:?}", poly.vertices);
});
}

// Rebuild the CSG.
csg_rebuild(&mut level);

// TODO: dump the level geometry to an object and return it.
println!("Number of nodes: {}", level.model.nodes.len());
println!("Number of polys: {}", level.model.polys.len());
println!("Number of surfaces: {}", level.model.surfaces.len());

Ok(Model::from(&level.model))
}
Expand Down
3 changes: 3 additions & 0 deletions src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ pub struct FBspSurf {
pub texture_u_index: usize,
/// Texture V-vector index.
pub texture_v_index: usize,
// BDK: Brush ID
pub brush_id: usize,
/// Editor brush polygon index.
pub brush_polygon_index: Option<usize>,
/// Nodes which make up this surface
Expand All @@ -76,6 +78,7 @@ impl Default for FBspSurf {
fn default() -> Self {
FBspSurf {
poly_flags: EPolyFlags::empty(),
brush_id: 0,
base_point_index: 0,
normal_index: 0,
texture_u_index: 0,
Expand Down
57 changes: 25 additions & 32 deletions tests/bsp_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,13 +299,9 @@ fn bsp_brush_subtract_and_add_test() {

// Create the main subtraction brush.
let polys = create_cube_polys(FVector::new(0.0, 0.0, 0.0), FVector::new(1.0, 1.0, 1.0));
let mut subtraction_brush = ABrush {
model: UModel::new_from_polys(&polys),
location: FVector::new(0.0, 0.0, 0.0),
pre_pivot: FVector::new(0.0, 0.0, 0.0),
csg_operation: bdk_py::bsp::ECsgOper::Subtract,
poly_flags: EPolyFlags::empty(),
};
let mut subtraction_brush = ABrush::new(
0, "Brush.001".to_string(), &polys, EPolyFlags::empty(), bdk_py::bsp::ECsgOper::Subtract
);
bsp_validate_brush(&mut subtraction_brush.model, false);

// TODO: all the normals are flipped on the addition brush...
Expand All @@ -316,13 +312,14 @@ fn bsp_brush_subtract_and_add_test() {
for poly in polys.iter_mut() {
poly.normal = -poly.normal;
}
let mut addition_brush = ABrush {
model: UModel::new_from_polys(&polys),
location: FVector::new(0.0, 0.0, 0.0),
pre_pivot: FVector::new(0.0, 0.0, 0.0),
csg_operation: bdk_py::bsp::ECsgOper::Add,
poly_flags: EPolyFlags::empty(),
};
let mut addition_brush = ABrush::new(
0,
"Brush.001".to_string(),
&polys,
EPolyFlags::empty(),
bdk_py::bsp::ECsgOper::Add
);

bsp_validate_brush(&mut addition_brush.model, false);

// Act
Expand All @@ -339,14 +336,13 @@ fn bsp_brush_subtract_and_add_test() {
fn bsp_brush_csg_subtract_test() {
// Arrange
let mut model = UModel::new(false);
let polys = create_cube_polys(FVector::new(0.0, 0.0, 0.0), FVector::new(1.0, 1.0, 1.0));
let mut brush = ABrush {
model: UModel::new_from_polys(&polys),
location: FVector::new(5.0, 0.0, 0.0),
pre_pivot: FVector::new(0.0, 0.0, 0.0),
csg_operation: bdk_py::bsp::ECsgOper::Subtract,
poly_flags: EPolyFlags::empty(),
};
let mut brush = ABrush::new(
0,
"Brush.001".to_string(),
&create_cube_polys(FVector::new(0.0, 0.0, 0.0), FVector::new(1.0, 1.0, 1.0)),
EPolyFlags::empty(),
bdk_py::bsp::ECsgOper::Subtract
);

bsp_validate_brush(&mut brush.model, false);

Expand All @@ -360,18 +356,15 @@ fn bsp_brush_csg_subtract_test() {

#[test]
fn bsp_merge_coplanars_test() {
// TODO: make a more substantive test, this was just made to make sure it doesn't crash.

// Arrange
let mut model = UModel::new(false);
let polys = create_cube_polys(FVector::new(0.0, 0.0, 0.0), FVector::new(1.0, 1.0, 1.0));
let mut brush = ABrush {
model: UModel::new_from_polys(&polys),
location: FVector::new(0.0, 0.0, 0.0),
pre_pivot: FVector::new(0.0, 0.0, 0.0),
csg_operation: bdk_py::bsp::ECsgOper::Subtract,
poly_flags: EPolyFlags::empty(),
};
let mut brush = ABrush::new(
0,
"Brush.001".to_string(),
&create_cube_polys(FVector::new(0.0, 0.0, 0.0), FVector::new(1.0, 1.0, 1.0)),
EPolyFlags::empty(),
bdk_py::bsp::ECsgOper::Subtract
);

bsp_validate_brush(&mut brush.model, false);
bsp_brush_csg(&brush, &mut model, EPolyFlags::empty(), bdk_py::bsp::ECsgOper::Subtract, false);
Expand Down

0 comments on commit 640769a

Please sign in to comment.