added the following 3 lines to everything in the intern dir: #ifdef HAVE_CONFIG_H #include <config.h> #endif Kent -- mein@cs.umn.edu
435 lines
12 KiB
C++
435 lines
12 KiB
C++
/**
|
|
* $Id$
|
|
* ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version. The Blender
|
|
* Foundation also sells licenses for use in proprietary software under
|
|
* the Blender License. See http://www.blender.org/BL/ for information
|
|
* about this.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
* All rights reserved.
|
|
*
|
|
* The Original Code is: all of this file.
|
|
*
|
|
* Contributor(s): none yet.
|
|
*
|
|
* ***** END GPL/BL DUAL LICENSE BLOCK *****
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include "BSP_CSGHelper.h"
|
|
|
|
#include "BSP_CSGMesh.h"
|
|
#include "BSP_MeshFragment.h"
|
|
#include "BSP_FragTree.h"
|
|
#include "BSP_CSGMeshSplitter.h"
|
|
#include "BSP_CSGNCMeshSplitter.h"
|
|
#include "BSP_Triangulate.h"
|
|
|
|
#include "MEM_SmartPtr.h"
|
|
|
|
using namespace std;
|
|
|
|
BSP_CSGHelper::
|
|
BSP_CSGHelper(
|
|
)
|
|
{
|
|
// nothing to do
|
|
}
|
|
|
|
bool
|
|
BSP_CSGHelper::
|
|
ComputeOp(
|
|
BSP_CSGMesh * obA,
|
|
BSP_CSGMesh * obB,
|
|
BSP_OperationType op_type,
|
|
BSP_CSGMesh & output,
|
|
CSG_InterpolateUserFaceVertexDataFunc fv_func
|
|
){
|
|
// First work out which parts of polygons we want to keep as we pass stuff
|
|
// down the tree.
|
|
|
|
BSP_Classification e_ATreeB,e_BTreeA;
|
|
bool invertA(false),invertB(false);
|
|
|
|
switch (op_type) {
|
|
case e_intern_csg_union :
|
|
e_ATreeB = e_classified_out;
|
|
e_BTreeA = e_classified_out;
|
|
break;
|
|
case e_intern_csg_intersection :
|
|
e_ATreeB = e_classified_in;
|
|
e_BTreeA = e_classified_in;
|
|
break;
|
|
case e_intern_csg_difference :
|
|
invertA = true;
|
|
e_ATreeB = e_classified_in;
|
|
e_BTreeA = e_classified_in;
|
|
break;
|
|
default :
|
|
return false;
|
|
}
|
|
|
|
if (invertA) {
|
|
obA->Invert();
|
|
}
|
|
|
|
if (invertB) {
|
|
obB->Invert();
|
|
}
|
|
|
|
MEM_SmartPtr<BSP_CSGMesh> obA_copy = obA->NewCopy();
|
|
MEM_SmartPtr<BSP_CSGMesh> obB_copy = obB->NewCopy();
|
|
|
|
// ok we need yet another copy...
|
|
|
|
MEM_SmartPtr<BSP_CSGMesh> obA_copy2 = obA->NewCopy();
|
|
MEM_SmartPtr<BSP_CSGMesh> obB_copy2 = obB->NewCopy();
|
|
|
|
obA_copy->BuildEdges();
|
|
obB_copy->BuildEdges();
|
|
|
|
// Create a splitter to help chop up the mesh and preserrve.
|
|
// mesh connectivity
|
|
|
|
MEM_SmartPtr<BSP_CSGMeshSplitter> splitter = new BSP_CSGMeshSplitter(fv_func);
|
|
if (splitter == NULL) return false;
|
|
|
|
// Create a splitter to help chop the mesh for tree building.
|
|
MEM_SmartPtr<BSP_CSGNCMeshSplitter> nc_splitter = new BSP_CSGNCMeshSplitter();
|
|
|
|
if (splitter == NULL || nc_splitter == NULL) return false;
|
|
|
|
// Create a tree for both meshes.
|
|
|
|
MEM_SmartPtr<BSP_FragTree> treeA = treeA->New(obA,nc_splitter.Ref());
|
|
MEM_SmartPtr<BSP_FragTree> treeB = treeB->New(obB,nc_splitter.Ref());
|
|
|
|
if (treeA == NULL || treeB == NULL) {
|
|
return false;
|
|
}
|
|
|
|
// Classify each object wrt the other tree.
|
|
|
|
MEM_SmartPtr<BSP_MeshFragment> AinB = new BSP_MeshFragment(obA_copy2,e_classified_in);
|
|
MEM_SmartPtr<BSP_MeshFragment> AoutB = new BSP_MeshFragment(obA_copy2,e_classified_out);
|
|
MEM_SmartPtr<BSP_MeshFragment> AonB = new BSP_MeshFragment(obA_copy2,e_classified_on);
|
|
|
|
treeB->Classify(obA_copy2,AinB,AoutB,AonB,nc_splitter.Ref());
|
|
|
|
MEM_SmartPtr<BSP_MeshFragment> BinA = new BSP_MeshFragment(obB_copy2,e_classified_in);
|
|
MEM_SmartPtr<BSP_MeshFragment> BoutA = new BSP_MeshFragment(obB_copy2,e_classified_out);
|
|
MEM_SmartPtr<BSP_MeshFragment> BonA = new BSP_MeshFragment(obB_copy2,e_classified_on);
|
|
|
|
treeA->Classify(obB_copy2,BinA,BoutA,BonA,nc_splitter.Ref());
|
|
|
|
// Now we need to work what were the spanning polygons from the original mesh.
|
|
// Build a spanning fragment from them and pass split those mothers.
|
|
|
|
MEM_SmartPtr<BSP_MeshFragment> frag_BTreeA2 = new BSP_MeshFragment(obA_copy,e_BTreeA);
|
|
MEM_SmartPtr<BSP_MeshFragment> AspanningB = new BSP_MeshFragment(obA_copy,e_classified_spanning);
|
|
|
|
TranslateSplitFragments(AinB.Ref(),AoutB.Ref(),AonB.Ref(),e_BTreeA,AspanningB.Ref(),frag_BTreeA2.Ref());
|
|
|
|
MEM_SmartPtr<BSP_MeshFragment> frag_ATreeB2 = new BSP_MeshFragment(obB_copy,e_ATreeB);
|
|
MEM_SmartPtr<BSP_MeshFragment> BspanningA = new BSP_MeshFragment(obB_copy,e_classified_spanning);
|
|
|
|
TranslateSplitFragments(BinA.Ref(),BoutA.Ref(),BonA.Ref(),e_ATreeB,BspanningA.Ref(),frag_ATreeB2.Ref());
|
|
|
|
|
|
MEM_SmartPtr<BSP_MeshFragment> frag_ATreeB = new BSP_MeshFragment(obB_copy,e_ATreeB);
|
|
MEM_SmartPtr<BSP_MeshFragment> frag_BTreeA = new BSP_MeshFragment(obA_copy,e_BTreeA);
|
|
|
|
if (frag_ATreeB == NULL || frag_BTreeA == NULL) return false;
|
|
|
|
// Pass the spanning polygons of copyB through the tree of copyA.
|
|
treeA->Push(BspanningA,frag_ATreeB,e_ATreeB,e_classified_spanning,true,splitter.Ref());
|
|
|
|
// Add the result of the push to the fragments we are interested in.
|
|
MergeFrags(frag_ATreeB2.Ref(),frag_ATreeB.Ref());
|
|
|
|
// Pass the spanning polygons of copyA through the tree of copyB
|
|
treeB->Push(AspanningB,frag_BTreeA,e_BTreeA,e_classified_spanning,false,splitter.Ref());
|
|
MergeFrags(frag_BTreeA2.Ref(),frag_BTreeA.Ref());
|
|
|
|
// Copy the fragments into a new mesh.
|
|
DuplicateMesh(frag_ATreeB.Ref(),output);
|
|
DuplicateMesh(frag_BTreeA.Ref(),output);
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
void
|
|
BSP_CSGHelper::
|
|
TranslateSplitFragments(
|
|
const BSP_MeshFragment & in_frag,
|
|
const BSP_MeshFragment & out_frag,
|
|
const BSP_MeshFragment & on_frag,
|
|
BSP_Classification keep,
|
|
BSP_MeshFragment & spanning_frag,
|
|
BSP_MeshFragment & output
|
|
){
|
|
|
|
// iterate through the 3 input fragments
|
|
// tag the polygons in the output fragments according to
|
|
// the classification of the input frags.
|
|
|
|
const BSP_CSGMesh *i_mesh = in_frag.Mesh();
|
|
BSP_CSGMesh *o_mesh = output.Mesh();
|
|
|
|
const vector<BSP_MFace> &i_faces = i_mesh->FaceSet();
|
|
vector<BSP_MFace> &o_faces = o_mesh->FaceSet();
|
|
|
|
vector<BSP_FaceInd>::const_iterator if_it = in_frag.FaceSet().begin();
|
|
vector<BSP_FaceInd>::const_iterator if_end = in_frag.FaceSet().end();
|
|
|
|
for (;if_it != if_end; ++if_it) {
|
|
int original_index = i_faces[*if_it].OpenTag();
|
|
if (original_index == -1) {
|
|
// then this face was never split and the original_index is
|
|
// the actual face index.
|
|
original_index = *if_it;
|
|
}
|
|
// tag the output faces with the in flag.
|
|
if (o_faces[original_index].OpenTag() == -1) {
|
|
o_faces[original_index].SetOpenTag(0);
|
|
}
|
|
o_faces[original_index].SetOpenTag(
|
|
o_faces[original_index].OpenTag() | e_classified_in
|
|
);
|
|
}
|
|
|
|
// same for out fragments.
|
|
if_it = out_frag.FaceSet().begin();
|
|
if_end = out_frag.FaceSet().end();
|
|
|
|
for (;if_it != if_end; ++if_it) {
|
|
int original_index = i_faces[*if_it].OpenTag();
|
|
if (original_index == -1) {
|
|
// then this face was never split and the original_index is
|
|
// the actual face index.
|
|
original_index = *if_it;
|
|
}
|
|
// tag the output faces with the in flag.
|
|
if (o_faces[original_index].OpenTag() == -1) {
|
|
o_faces[original_index].SetOpenTag(0);
|
|
}
|
|
o_faces[original_index].SetOpenTag(
|
|
o_faces[original_index].OpenTag() | e_classified_out
|
|
);
|
|
}
|
|
|
|
// on fragments just get set as spanning for now.
|
|
|
|
if_it = on_frag.FaceSet().begin();
|
|
if_end = on_frag.FaceSet().end();
|
|
|
|
for (;if_it != if_end; ++if_it) {
|
|
int original_index = i_faces[*if_it].OpenTag();
|
|
if (original_index == -1) {
|
|
// then this face was never split and the original_index is
|
|
// the actual face index.
|
|
original_index = *if_it;
|
|
}
|
|
// tag the output faces with the in flag.
|
|
if (o_faces[original_index].OpenTag() == -1) {
|
|
o_faces[original_index].SetOpenTag(0);
|
|
}
|
|
o_faces[original_index].SetOpenTag(
|
|
o_faces[original_index].OpenTag() | e_classified_spanning
|
|
);
|
|
}
|
|
// now run through the output faces.
|
|
// collect the ones we are interested in into output
|
|
// and collect the spanning faces.
|
|
|
|
int of_it = 0;
|
|
int of_size = o_faces.size();
|
|
|
|
for (;of_it < of_size; ++of_it) {
|
|
|
|
int p_class = o_faces[of_it].OpenTag();
|
|
|
|
if (p_class == int(keep)) {
|
|
output.FaceSet().push_back(BSP_FaceInd(of_it));
|
|
} else
|
|
if (
|
|
(p_class == (e_classified_in | e_classified_out)) ||
|
|
p_class == e_classified_spanning
|
|
) {
|
|
spanning_frag.FaceSet().push_back(BSP_FaceInd(of_it));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
BSP_CSGHelper::
|
|
MergeFrags(
|
|
const BSP_MeshFragment & in,
|
|
BSP_MeshFragment & out
|
|
){
|
|
|
|
// Add the 2 frags together.
|
|
|
|
out.FaceSet().insert(
|
|
out.FaceSet().end(),
|
|
in.FaceSet().begin(),
|
|
in.FaceSet().end()
|
|
);
|
|
}
|
|
|
|
|
|
|
|
BSP_CSGHelper::
|
|
~BSP_CSGHelper(
|
|
){
|
|
// nothing to do
|
|
}
|
|
|
|
void
|
|
BSP_CSGHelper::
|
|
DuplicateMesh(
|
|
const BSP_MeshFragment & frag,
|
|
BSP_CSGMesh & output
|
|
){
|
|
|
|
// This stuff is a real waste of time.
|
|
// much better to create an output iterator based upon
|
|
// the 2 mesh fragments alone.
|
|
|
|
vector<BSP_MVertex> & o_verts = output.VertexSet();
|
|
BSP_CSGUserData & o_fv_data = output.FaceVertexData();
|
|
BSP_CSGUserData & o_f_data = output.FaceData();
|
|
|
|
// A temporary buffer containing the triangulated
|
|
// vertex indices.
|
|
|
|
vector<int> triangle_indices;
|
|
|
|
BSP_CSGMesh * i_mesh = frag.Mesh();
|
|
|
|
if (i_mesh == NULL) return;
|
|
|
|
vector<BSP_MVertex> & i_verts = i_mesh->VertexSet();
|
|
const vector<BSP_MFace> & i_faces = i_mesh->FaceSet();
|
|
BSP_CSGUserData & i_fv_data = i_mesh->FaceVertexData();
|
|
BSP_CSGUserData & i_f_data = i_mesh->FaceData();
|
|
|
|
// iterate through the fragment's face set
|
|
const vector<BSP_FaceInd> & frag_faces = frag.FaceSet();
|
|
|
|
vector<BSP_FaceInd>::const_iterator f_faces_it = frag_faces.begin();
|
|
vector<BSP_FaceInd>::const_iterator f_faces_end = frag_faces.end();
|
|
|
|
// We need to keep track of which vertices we are selecting.
|
|
vector<int> selected_vi;
|
|
|
|
BSP_Triangulate triangulator;
|
|
|
|
for (; f_faces_it != f_faces_end; ++f_faces_it) {
|
|
|
|
BSP_FaceInd fi = *f_faces_it;
|
|
const BSP_MFace &face = i_faces[fi];
|
|
|
|
// duplicate the face
|
|
BSP_MFace dup_face(face);
|
|
|
|
// iterate through the face's vertex indices.
|
|
vector<BSP_VertexInd>::iterator dup_f_verts_it = dup_face.m_verts.begin();
|
|
vector<BSP_VertexInd>::const_iterator dup_f_verts_end = dup_face.m_verts.end();
|
|
|
|
for (; dup_f_verts_it != dup_f_verts_end; ++dup_f_verts_it) {
|
|
|
|
if (i_verts[*dup_f_verts_it].SelectTag() == false) {
|
|
// copy this vertex onto the output mesh vertex array.
|
|
|
|
BSP_VertexInd new_vi(o_verts.size());
|
|
o_verts.push_back(i_verts[*dup_f_verts_it]);
|
|
|
|
// should kill the old vertices edge ptrs.
|
|
o_verts[new_vi].m_edges.clear();
|
|
|
|
// set the open tag in the old vert to the new one.
|
|
i_verts[*dup_f_verts_it].SetOpenTag(new_vi);
|
|
|
|
// select the old vertex
|
|
i_verts[*dup_f_verts_it].SetSelectTag(true);
|
|
selected_vi.push_back(*dup_f_verts_it);
|
|
}
|
|
|
|
// we have been to this vertex before and there should be
|
|
// a corresponding vertex in the new mesh vertex set.
|
|
*dup_f_verts_it = i_verts[*dup_f_verts_it].OpenTag();
|
|
}
|
|
|
|
// duplicate the face vertex data for this polygon.
|
|
|
|
vector<BSP_UserFVInd>::iterator dup_fv_it = dup_face.m_fv_data.begin();
|
|
vector<BSP_UserFVInd>::const_iterator dup_fv_end = dup_face.m_fv_data.end();
|
|
|
|
for (;dup_fv_it != dup_fv_end; ++dup_fv_it) {
|
|
*dup_fv_it = o_fv_data.Duplicate(i_fv_data[int(*dup_fv_it)]);
|
|
}
|
|
|
|
triangle_indices.clear();
|
|
|
|
// Now triangulate the polygon.
|
|
if (!triangulator.Process(
|
|
o_verts,
|
|
dup_face.m_verts,
|
|
dup_face.m_plane,
|
|
triangle_indices
|
|
)) {
|
|
// Sometimes the triangulator can fail for very small
|
|
// polygons or very thing polygons. This should be
|
|
// handled more elegantly but for now we just leave out the
|
|
// polygon from the mesh.
|
|
continue;
|
|
}
|
|
|
|
// Run through the result and add in the triangle faces.
|
|
|
|
int i;
|
|
for (i = 0; i < triangle_indices.size(); i+=3) {
|
|
// duplicate the face data for this face.
|
|
o_f_data.Duplicate(i_f_data[*f_faces_it]);
|
|
|
|
output.AddSubTriangle(dup_face,&triangle_indices[i]);
|
|
}
|
|
}
|
|
|
|
// of course we have to deselect the vertices again.
|
|
|
|
vector<int>::const_iterator selected_vi_it = selected_vi.begin();
|
|
vector<int>::const_iterator selected_vi_end = selected_vi.end();
|
|
|
|
for (; selected_vi_it != selected_vi_end; ++selected_vi_it) {
|
|
i_verts[*selected_vi_it].SetSelectTag(false);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|