diff options
author | Hans Lambermont <hans@lambermont.dyndns.org> | 2002-10-12 15:37:38 +0400 |
---|---|---|
committer | Hans Lambermont <hans@lambermont.dyndns.org> | 2002-10-12 15:37:38 +0400 |
commit | 12315f4d0e0ae993805f141f64cb8c73c5297311 (patch) | |
tree | 59b45827cd8293cfb727758989c7a74b40183974 /intern/bsp |
Initial revisionv2.25
Diffstat (limited to 'intern/bsp')
45 files changed, 12286 insertions, 0 deletions
diff --git a/intern/bsp/Makefile b/intern/bsp/Makefile new file mode 100644 index 00000000000..371c43c848a --- /dev/null +++ b/intern/bsp/Makefile @@ -0,0 +1,55 @@ +# +# $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 ***** +# bsp main makefile. +# + +include nan_definitions.mk + +LIBNAME = bsp +SOURCEDIR = intern/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) +DIRS = intern +# not yet TESTDIRS = test + +include nan_subdirs.mk + +install: all debug + @[ -d $(NAN_BSP) ] || mkdir $(NAN_BSP) + @[ -d $(NAN_BSP)/include ] || mkdir $(NAN_BSP)/include + @[ -d $(NAN_BSP)/lib ] || mkdir $(NAN_BSP)/lib + @[ -d $(NAN_BSP)/lib/debug ] || mkdir $(NAN_BSP)/lib/debug + cp -f $(DIR)/libbsp.a $(NAN_BSP)/lib/ + cp -f $(DIR)/debug/libbsp.a $(NAN_BSP)/lib/debug/ + cp -f extern/*.h $(NAN_BSP)/include/ + + + + diff --git a/intern/bsp/extern/CSG_BooleanOps.h b/intern/bsp/extern/CSG_BooleanOps.h new file mode 100755 index 00000000000..0a348fdc05e --- /dev/null +++ b/intern/bsp/extern/CSG_BooleanOps.h @@ -0,0 +1,428 @@ +/** + * $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 ***** + */ + +#ifndef CSG_BOOLEANOPS_H + +#define CSG_BOOLEANOPS_H + +/** + * @section Interface structures for CSG module. + * This interface falls into 2 categories. + * The first section deals with an abstract mesh description + * between blender and this module. The second deals with + * the module functions. + * The CSG module needs to know about the following entities: + */ + +/** + * CSG_IFace -- an interface polygon structure. + * vertex_index is a fixed size array of 4 elements containing indices into + * an abstract vertex container. 3 or 4 of these elements may be used to + * describe either quads or triangles. + * vertex_number is the number of vertices in this face - either 3 or 4. + * vertex_colors is an array of {r,g,b} triplets one for each vertex index. + * tex_coords is an array of {u,v} triplets one for each vertex index. + * user_data is a pointer to arbitary data of fixed width , + * this data is copied around with the face, and duplicated if a face is + * split. Contains things like material index. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + int vertex_index[4]; + int vertex_number; + + void *user_face_vertex_data[4]; + void *user_face_data; +} CSG_IFace; + +/** + * CSG_IVertex -- an interface vertex structure. + * position is the location of the vertex in 3d space. + */ + +typedef struct { + float position[3]; +} CSG_IVertex; + +/** + * The actual useful data contained in a group of faces is + * described by the following struct + */ + +/** + * Descibes the data stored in a mesh available through the + * CSG_IFace interface. + * user_data_size is the number of bytes of user_data associated with each CSG_IFace + * user_face_vertex_data size is the number of bytes of user data associated with + * every face vertex tuple. + * . + */ + +typedef struct CSG_MeshPropertyDescriptor{ + unsigned int user_face_vertex_data_size; + unsigned int user_data_size; +} CSG_MeshPropertyDescriptor; + + + +/** + * @section Iterator abstraction. + * + * The CSG module asks blender to fill in an instance of the above + * structure, and requests blender to move up and down (iterate) through + * it's face and vertex containers. + * + * An iterator supports the following functions. + * int IsDone(iterator *it) -- returns true if the iterator has reached + * the end of it's container. + * + * void Fill(iterator *it,DataType *data) -- Return the contents of the + * container at the current iterator position. + * + * void Step(iterator *it) -- increment the iterator to the next position + * in the container. + * + * The iterator is used in the following manner. + * + * MyIterator * iterator = ... + * DataType data; + * + * while (!IsDone(iterator)) { + * Fill(iterator,&data); + * //process information pointed to by data + * ... + * Step(iterator); + * } + * + * The CSG module does not want to know about the implementation of these + * functions so we use the c function ptr mechanism to hide them. Our + * iterator descriptor now looks like this. + */ + +typedef void* CSG_IteratorPtr; + +typedef int (*CSG_FaceItDoneFunc)(CSG_IteratorPtr it); +typedef void (*CSG_FaceItFillFunc)(CSG_IteratorPtr it,CSG_IFace *face); +typedef void (*CSG_FaceItStepFunc)(CSG_IteratorPtr it); +typedef void (*CSG_FaceItResetFunc)(CSG_IteratorPtr it); + +typedef struct CSG_FaceIteratorDescriptor { + CSG_IteratorPtr it; + CSG_FaceItDoneFunc Done; + CSG_FaceItFillFunc Fill; + CSG_FaceItStepFunc Step; + CSG_FaceItResetFunc Reset; + unsigned int num_elements; +} CSG_FaceIteratorDescriptor; + +/** + * Similarly to walk through the vertex arrays we have. + */ +typedef int (*CSG_VertexItDoneFunc)(CSG_IteratorPtr it); +typedef void (*CSG_VertexItFillFunc)(CSG_IteratorPtr it,CSG_IVertex *face); +typedef void (*CSG_VertexItStepFunc)(CSG_IteratorPtr it); +typedef void (*CSG_VertexItResetFunc)(CSG_IteratorPtr it); + +typedef struct CSG_VertexIteratorDescriptor { + CSG_IteratorPtr it; + CSG_VertexItDoneFunc Done; + CSG_VertexItFillFunc Fill; + CSG_VertexItStepFunc Step; + CSG_VertexItResetFunc Reset; + unsigned int num_elements; +} CSG_VertexIteratorDescriptor; + +/** + * The actual iterator structures are not exposed to the CSG module, they + * will contain datatypes specific to blender. + */ + +/** + * @section CSG Module interface functions. + * + * The functions below are to be used in the following way: + * + * // Create a boolean operation handle + * CSG_BooleanOperation *operation = CSG_NewBooleanFunction(); + * if (operation == NULL) { + * // deal with low memory exception + * } + * + * // Describe each mesh operand to the module. + * // NOTE: example properties! + * CSG_MeshPropertyDescriptor propA,propB; + * propA.user_data_size = 0; + * propA.user_face_vertex_data = 0; + * propB.user_face_vertex_data = 0; + * propB.user_data_size = 0; + * + * // Get the output properties of the mesh. + * CSG_MeshPropertyDescriptor output_properties; + * output_properties = CSG_DescibeOperands( + * operation, + * propA, + * propB + * ); + * + * // Report to the user if they will loose any data! + * ... + * + * // Get some mesh iterators for your mesh data structures + * CSG_FaceIteratorDescriptor obA_faces = ... + * CSG_VertexIteratorDescriptor obA_verts = ... + * + * // same for object B + * CSG_FaceIteratorDescriptor obB_faces = ... + * CSG_VertexIteratorDescriptor obB_verts = ... + * + * // perform the operation...! + * + * int success = CSG_PerformBooleanOperation( + * operation, + * e_csg_intersection, + * obA_faces, + * obA_vertices, + * obB_faces, + * obB_vertices + * ); + * + * // if the operation failes report miserable faiulre to user + * // and clear up data structures. + * if (!success) { + * ... + * CSG_FreeBooleanOperation(operation); + * return; + * } + * + * // read the new mesh vertices back from the module + * // and assign to your own mesh structure. + * + * // First we need to create a CSG_IVertex so the module can fill it in. + * CSG_IVertex vertex; + * CSG_VertexIteratorDescriptor * verts_it = CSG_OutputVertexDescriptor(operation); + * + * // initialize your vertex container with the number of verts (verts_it->num_elements) + * + * while (!verts_it->Done(verts_it->it)) { + * verts_it->Fill(verts_it->it,&vertex); + * + * // create a new vertex of your own type and add it + * // to your mesh structure. + * verts_it->Step(verts_it->it); + * } + * // Free the vertex iterator + * CSG_FreeVertexDescriptor(verts_it); + * + * // similarly for faces. + * CSG_IFace face; + * + * // you may need to reserve some memory in face->user_data here. + * + * // initialize your face container with the number of faces (faces_it->num_elements) + * + * CSG_FaceIteratorDescriptor * faces_it = CSG_OutputFaceDescriptor(operation); + * + * while (!faces_it->Done(faces_it->it)) { + * faces_it->Fill(faces_it->it,&face); + * + * // create a new face of your own type and add it + * // to your mesh structure. + * faces_it->Step(&faces_it->it); + * } + * + * // Free the face iterator + * CSG_FreeVertexDescriptor(faces_it); + * + * // that's it free the operation. + * + * CSG_FreeBooleanOperation(operation); + * return; + * + */ + +/** + * Description of boolean operation type. + */ + +typedef enum { + e_csg_union, + e_csg_intersection, + e_csg_difference, + e_csg_classify +} CSG_OperationType; + +/** + * 'Handle' into the CSG module that identifies a particular CSG operation. + * the pointer CSG_info containers module specific data, and should not + * be touched in anyway outside of the module. + */ + +typedef struct { + void *CSG_info; +} CSG_BooleanOperation; + +/** + * Return a ptr to a CSG_BooleanOperation object allocated + * on the heap. The CSG module owns the memory associated with + * the returned ptr, use CSG_FreeBooleanOperation() to free this memory. + */ + CSG_BooleanOperation * +CSG_NewBooleanFunction( + void +); + +/** + * Describe the operands of a boolean function to the module. + * The description takes the form of a pair of CSG_MeshPropertyDescriptors + * one for each input mesh. The operands do not have to have the same + * properties, for example operandA may have vertex colours but operandB none. + * In this case the CSG module will choose the lowest common denominator in + * mesh properies. The function returns a description of + * the output mesh. You can use this to warn the user that certain properties + * will be lost. Of course it also describes what fields in the output mesh + * will contain valid data. + */ + CSG_MeshPropertyDescriptor +CSG_DescibeOperands( + CSG_BooleanOperation * operation, + CSG_MeshPropertyDescriptor operandA_desciption, + CSG_MeshPropertyDescriptor operandB_desciption +); + +/** + * The user data is handled by the BSP modules through + * the following function which is called whenever the + * module needs new face vertex properties (when a face is split). + * d1,d2 are pointers to existing vertex face data. dnew is + * a pointer to an allocated but unfilled area of user data of + * size user_face_vertex_data_size in the CSG_MeshPropertyDescriptor + * returned by a call to the above function. Epsilon is the relative + * distance (between [0,1]) of the new vertex and the vertex associated + * with d1. Use epsilon to interpolate the face vertex data in d1 and d2 + * and fill dnew + */ + +typedef int (*CSG_InterpolateUserFaceVertexDataFunc)(void *d1, void * d2, void *dnew, float epsilon); + + +/** + * Attempt to perform a boolean operation between the 2 objects of the + * desired type. This may fail due to an internal error or lack of memory. + * In this case 0 is returned, otehrwise 1 is returned indicating success. + * @param operation is a 'handle' into the CSG_Module created by CSG_NewBooleanFunction() + * @param op_type is the operation to perform. + * @param obAFaces is an iterator over the faces of objectA, + * @param obAVertices is an iterator over the vertices of objectA + * @param obAFaces is an iterator over the faces of objectB, + * @param obAVertices is an iterator over the vertices of objectB + * @param interp_func the face_vertex data interpolation function.(see above) + * + * All iterators must be valid and pointing to the first element in their + * respective containers. + */ + int +CSG_PerformBooleanOperation( + CSG_BooleanOperation * operation, + CSG_OperationType op_type, + CSG_FaceIteratorDescriptor obAFaces, + CSG_VertexIteratorDescriptor obAVertices, + CSG_FaceIteratorDescriptor obBFaces, + CSG_VertexIteratorDescriptor obBVertices, + CSG_InterpolateUserFaceVertexDataFunc interp_func +); + +/** + * If the a boolean operation was successful, you may access the results + * through the following functions. + * + * CSG_OuputFaceDescriptor() returns a ptr to a CSG_FaceIteratorDesciptor + * allocated on the heap and owned by the CSG module. The iterator is + * positioned at the start of the internal face container. + * CSG_OutputVertexDescriptor() returns a ptr to a CSG_VertexIteratorDescriptor + * allocated on the heap and owned by the CSG module. The iterator is + * positioned at the start of the internal vertex container. + * There is no function to rewind an iterator but you may obtain more + * than one + * iterator at a time. Please use the function CSG_FreeFaceIterator() + * and CSG_FreeVertexIterator to free internal memory allocated for these + * iterators. + * + * If the last operation was not successful, these functions return NULL. + */ + int +CSG_OutputFaceDescriptor( + CSG_BooleanOperation * operation, + CSG_FaceIteratorDescriptor * output +); + + int +CSG_OutputVertexDescriptor( + CSG_BooleanOperation * operation, + CSG_VertexIteratorDescriptor *output +); + +/** + * Clean up functions. + * Free internal memory associated with CSG interface structures. You must + * call these functions on any structures created by the module, even if + * subsequent operations did not succeed. + */ + void +CSG_FreeVertexDescriptor( + CSG_VertexIteratorDescriptor * v_descriptor +); + + void +CSG_FreeFaceDescriptor( + CSG_FaceIteratorDescriptor * f_descriptor +); + +/** + * Free the memory associated with a boolean operation. + * NOTE any iterator descriptor describing the output will become + * invalid after this call and should be freed immediately. + */ + void +CSG_FreeBooleanOperation( + CSG_BooleanOperation *operation +); + +#ifdef __cplusplus +} +#endif + + + +#endif
\ No newline at end of file diff --git a/intern/bsp/intern/BSP_CSGException.h b/intern/bsp/intern/BSP_CSGException.h new file mode 100755 index 00000000000..7224d8b0910 --- /dev/null +++ b/intern/bsp/intern/BSP_CSGException.h @@ -0,0 +1,58 @@ +/** + * $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 ***** + */ + +#ifndef NAN_INCLUDED_CSGException_h + +#define NAN_INCLUDED_CSGException_h + +// stick in more error types as you think of them + +enum BSP_ExceptionType{ + e_split_error, + e_mesh_error, + e_mesh_input_error, + e_param_error, + e_tree_build_error +}; + + +class BSP_CSGException { +public : + BSP_ExceptionType m_e_type; + + BSP_CSGException ( + BSP_ExceptionType type + ) : m_e_type (type) + { + } +}; + +#endif diff --git a/intern/bsp/intern/BSP_CSGHelper.cpp b/intern/bsp/intern/BSP_CSGHelper.cpp new file mode 100644 index 00000000000..72ad30b6f0f --- /dev/null +++ b/intern/bsp/intern/BSP_CSGHelper.cpp @@ -0,0 +1,430 @@ +/** + * $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 ***** + */ + +#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.begin() + 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); + } +} + + + + + + + diff --git a/intern/bsp/intern/BSP_CSGHelper.h b/intern/bsp/intern/BSP_CSGHelper.h new file mode 100644 index 00000000000..f122fc3cf31 --- /dev/null +++ b/intern/bsp/intern/BSP_CSGHelper.h @@ -0,0 +1,99 @@ +/** + * $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 ***** + */ + +#ifndef BSP_CSGHELPER_H + +#define BSP_CSGHELPER_H + +class BSP_CSGMesh; +class BSP_MeshFragment; + +#include "../extern/CSG_BooleanOps.h" +#include "BSP_MeshPrimitives.h" + +enum BSP_OperationType{ + e_intern_csg_union, + e_intern_csg_intersection, + e_intern_csg_difference +}; + +class BSP_CSGHelper { +public : + + BSP_CSGHelper( + ); + + bool + ComputeOp( + BSP_CSGMesh * obA, + BSP_CSGMesh * obB, + BSP_OperationType op_type, + BSP_CSGMesh & output, + CSG_InterpolateUserFaceVertexDataFunc fv_func + ); + + + ~BSP_CSGHelper( + ); + +private: + + // Iterate through the fragment, + // add new vertices to output, + // map polygons to new vertices. + + void + DuplicateMesh( + const BSP_MeshFragment & frag, + BSP_CSGMesh & output + ); + + void + 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 + ); + + void + MergeFrags( + const BSP_MeshFragment & in, + BSP_MeshFragment & out + ); + + + +}; + +#endif diff --git a/intern/bsp/intern/BSP_CSGISplitter.h b/intern/bsp/intern/BSP_CSGISplitter.h new file mode 100755 index 00000000000..c88a04a7932 --- /dev/null +++ b/intern/bsp/intern/BSP_CSGISplitter.h @@ -0,0 +1,118 @@ +/** + * $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 ***** + */ + +#ifndef BSP_CSGISplitter_h + +#define BSP_CSGISplitter_h + +class BSP_MeshFragment; +class BSP_CSGMesh; + +class MT_Plane3; + +/** + * This class defines a mesh splitter interface. + * It embodies the action of splitting a mesh by a plane. + * Depending on the context of the operation subclasses + * may wish to define different implementations. For example + * with building a BSP tree from a mesh, the mesh does not + * need to be kept consistent, it doesn't matter if the edges + * are maintained etc. However when pushing polygons through + * a BSP tree (say for CSG operations)it is important to + * try and maintain mesh connectivity and thus a different + * splitter implementation may be needed. + * + * This is an abstract interface class. + */ + +class BSP_CSGISplitter +{ + +public: + + /** + * Split the incoming mesh fragment (frag) + * by the plane, put the output into (in,out and on) + * Subclasses should clear the contents of the + * in_coming fragment. + */ + + virtual + void + Split( + const MT_Plane3& plane, + BSP_MeshFragment *frag, + BSP_MeshFragment *in_frag, + BSP_MeshFragment *out_frag, + BSP_MeshFragment *on_frag, + BSP_MeshFragment *spanning_frag + )= 0; + + /** + * Split the entire mesh with respect to the plane. + * and place ouput into (in,out and on). + * Subclasses should clear the contents of the + * in_coming fragment. + */ + virtual + void + Split( + BSP_CSGMesh & mesh, + const MT_Plane3& plane, + BSP_MeshFragment *in_frag, + BSP_MeshFragment *out_frag, + BSP_MeshFragment *on_frag, + BSP_MeshFragment *spanning_frag + )=0; + + virtual + ~BSP_CSGISplitter( + ){ + }; + +protected : + + BSP_CSGISplitter( + ) { + //nothing to do + } + + BSP_CSGISplitter( + const BSP_CSGISplitter & + ) { + //nothing to do + } +}; + + + +#endif + diff --git a/intern/bsp/intern/BSP_CSGMesh.cpp b/intern/bsp/intern/BSP_CSGMesh.cpp new file mode 100755 index 00000000000..d1721cb692b --- /dev/null +++ b/intern/bsp/intern/BSP_CSGMesh.cpp @@ -0,0 +1,883 @@ +/** + * $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 ***** + */ + + + +#include "BSP_CSGMesh.h" +#include "MT_assert.h" +#include "CTR_TaggedSetOps.h" +#include "BSP_MeshFragment.h" +#include "MT_Plane3.h" +#include "BSP_CSGException.h" + +// for vector reverse +#include <algorithm> +using namespace std; + +BSP_CSGMesh:: +BSP_CSGMesh( +) : + MEM_RefCountable() +{ + // nothing to do +} + + BSP_CSGMesh * +BSP_CSGMesh:: +New( +){ + return new BSP_CSGMesh(); +} + + BSP_CSGMesh * +BSP_CSGMesh:: +NewCopy( +) const { + + MEM_SmartPtr<BSP_CSGMesh> mesh = New(); + if (mesh == NULL) return NULL; + + mesh->m_bbox_max = m_bbox_max; + mesh->m_bbox_min = m_bbox_min; + + if (m_edges != NULL) { + mesh->m_edges = new vector<BSP_MEdge>(m_edges.Ref()); + if (mesh->m_edges == NULL) return NULL; + } + if (m_verts != NULL) { + mesh->m_verts = new vector<BSP_MVertex>(m_verts.Ref()); + if (mesh->m_verts == NULL) return NULL; + } + if (m_faces != NULL) { + mesh->m_faces = new vector<BSP_MFace>(m_faces.Ref()); + if (mesh->m_faces == NULL) return NULL; + } + if (m_fv_data != NULL) { + mesh->m_fv_data = new BSP_CSGUserData(m_fv_data.Ref()); + if (mesh->m_fv_data == NULL) return NULL; + } + if (m_face_data != NULL) { + mesh->m_face_data = new BSP_CSGUserData(m_face_data.Ref()); + if (mesh->m_face_data == NULL) return NULL; + } + + return mesh.Release(); +} + + void +BSP_CSGMesh:: +Invert( +){ + + vector<BSP_MFace> & faces = FaceSet(); + + vector<BSP_MFace>::const_iterator faces_end = faces.end(); + vector<BSP_MFace>::iterator faces_it = faces.begin(); + + for (; faces_it != faces_end; ++faces_it) { + faces_it->Invert(); + } +} + + bool +BSP_CSGMesh:: +SetVertices( + MEM_SmartPtr<vector<BSP_MVertex> > verts +){ + if (verts == NULL) return false; + + // create polygon and edge arrays and reserve some space. + m_faces = new vector<BSP_MFace>; + if (!m_faces) return false; + + m_faces->reserve(verts->size()/2); + + // previous verts get deleted here. + m_verts = verts; + return true; +} + + void +BSP_CSGMesh:: +SetFaceVertexData( + MEM_SmartPtr<BSP_CSGUserData> fv_data +){ + m_fv_data = fv_data; +} + + void +BSP_CSGMesh:: +SetFaceData( + MEM_SmartPtr<BSP_CSGUserData> f_data +) { + m_face_data = f_data; +} + + + void +BSP_CSGMesh:: +AddPolygon( + const int * verts, + int num_verts +){ + MT_assert(verts != NULL); + MT_assert(num_verts >=3); + + if (verts == NULL || num_verts <3) return; + + const int vertex_num = m_verts->size(); + + // make a polyscone from these vertex indices. + + const BSP_FaceInd fi = m_faces->size(); + m_faces->push_back(BSP_MFace()); + BSP_MFace & face = m_faces->back(); + + insert_iterator<vector<BSP_VertexInd> > insert_point(face.m_verts,face.m_verts.end()); + copy (verts,verts + num_verts,insert_point); + + // compute and store the plane equation for this face. + + MT_Plane3 face_plane = FacePlane(fi); + face.m_plane = face_plane; +}; + + void +BSP_CSGMesh:: +AddPolygon( + const int * verts, + const int * fv_indices, + int num_verts +){ + // This creates a new polygon on the end of the face list. + AddPolygon(verts,num_verts); + + BSP_MFace & face = m_faces->back(); + // now we just fill in the fv indices + + if (fv_indices) { + insert_iterator<vector<BSP_UserFVInd> > insert_point(face.m_fv_data,face.m_fv_data.end()); + copy(fv_indices,fv_indices + num_verts,insert_point); + } else { + face.m_fv_data.insert(face.m_fv_data.end(),num_verts,BSP_UserFVInd::Empty()); + } +} + + + void +BSP_CSGMesh:: +AddSubTriangle( + const BSP_MFace &iface, + const int * index_info +){ + // This creates a new polygon on the end of the face list. + + const BSP_FaceInd fi = m_faces->size(); + m_faces->push_back(BSP_MFace()); + BSP_MFace & face = m_faces->back(); + + face.m_verts.push_back(iface.m_verts[index_info[0]]); + face.m_verts.push_back(iface.m_verts[index_info[1]]); + face.m_verts.push_back(iface.m_verts[index_info[2]]); + + face.m_fv_data.push_back(iface.m_fv_data[index_info[0]]); + face.m_fv_data.push_back(iface.m_fv_data[index_info[1]]); + face.m_fv_data.push_back(iface.m_fv_data[index_info[2]]); + + face.m_plane = iface.m_plane; +} + + +// assumes that the face already has a plane equation + void +BSP_CSGMesh:: +AddPolygon( + const BSP_MFace &face +){ + m_faces->push_back(face); +}; + + + bool +BSP_CSGMesh:: +BuildEdges( +){ + + if (m_faces == NULL) return false; + + if (m_edges != NULL) { + DestroyEdges(); + } + + m_edges = new vector<BSP_MEdge>; + + if (m_edges == NULL) { + return false; + } + + + //iterate through the face set and add edges for all polygon + //edges + + vector<BSP_MFace>::const_iterator f_it_end = FaceSet().end(); + vector<BSP_MFace>::const_iterator f_it_begin = FaceSet().begin(); + vector<BSP_MFace>::iterator f_it = FaceSet().begin(); + + vector<BSP_MVertex> & vertex_set = VertexSet(); + + vector<BSP_EdgeInd> dummy; + + for (;f_it != f_it_end; ++f_it) { + + BSP_MFace & face = *f_it; + + int vertex_num = face.m_verts.size(); + BSP_VertexInd prev_vi(face.m_verts[vertex_num-1]); + + for (int vert = 0; vert < vertex_num; ++vert) { + + BSP_FaceInd fi(f_it - f_it_begin); + InsertEdge(prev_vi,face.m_verts[vert],fi,dummy); + prev_vi = face.m_verts[vert]; + } + + } + dummy.clear(); + return true; +} + + void +BSP_CSGMesh:: +DestroyEdges( +){ + m_edges.Delete(); + + // Run through the vertices + // and clear their edge arrays. + + if (m_verts){ + + vector<BSP_MVertex>::const_iterator vertex_end = VertexSet().end(); + vector<BSP_MVertex>::iterator vertex_it = VertexSet().begin(); + + for (; vertex_it != vertex_end; ++vertex_it) { + vertex_it->m_edges.clear(); + } + } +} + + + BSP_EdgeInd +BSP_CSGMesh:: +FindEdge( + const BSP_VertexInd & v1, + const BSP_VertexInd & v2 +) const { + + vector<BSP_MVertex> &verts = VertexSet(); + vector<BSP_MEdge> &edges = EdgeSet(); + + BSP_MEdge e; + e.m_verts[0] = v1; + e.m_verts[1] = v2; + + vector<BSP_EdgeInd> &v1_edges = verts[v1].m_edges; + vector<BSP_EdgeInd>::const_iterator v1_end = v1_edges.end(); + vector<BSP_EdgeInd>::const_iterator v1_begin = v1_edges.begin(); + + for (; v1_begin != v1_end; ++v1_begin) { + if (edges[*v1_begin] == e) return *v1_begin; + } + + return BSP_EdgeInd::Empty(); +} + + void +BSP_CSGMesh:: +InsertEdge( + const BSP_VertexInd & v1, + const BSP_VertexInd & v2, + const BSP_FaceInd & f, + vector<BSP_EdgeInd> &new_edges +){ + + MT_assert(!v1.IsEmpty()); + MT_assert(!v2.IsEmpty()); + MT_assert(!f.IsEmpty()); + + if (v1.IsEmpty() || v2.IsEmpty() || f.IsEmpty()) { + BSP_CSGException e(e_mesh_error); + throw (e); + } + + vector<BSP_MVertex> &verts = VertexSet(); + vector<BSP_MEdge> &edges = EdgeSet(); + + BSP_EdgeInd e; + + e = FindEdge(v1,v2); + if (e.IsEmpty()) { + // This edge does not exist -- make a new one + + BSP_MEdge temp_e; + temp_e.m_verts[0] = v1; + temp_e.m_verts[1] = v2; + + e = m_edges->size(); + // set the face index from the edge back to this polygon. + temp_e.m_faces.push_back(f); + + m_edges->push_back(temp_e); + + // add the edge index to it's vertices + verts[v1].AddEdge(e); + verts[v2].AddEdge(e); + + new_edges.push_back(e); + + } else { + + // edge already exists + // insure that there is no polygon already + // attached to the other side of this edge + // swap the empty face pointer in edge with f + + BSP_MEdge &edge = edges[e]; + + // set the face index from the edge back to this polygon. + edge.m_faces.push_back(f); + } +} + + +// geometry access +////////////////// + + vector<BSP_MVertex> & +BSP_CSGMesh:: +VertexSet( +) const { + return m_verts.Ref(); +} + + vector<BSP_MFace> & +BSP_CSGMesh:: +FaceSet( +) const { + return m_faces.Ref(); +} + + vector<BSP_MEdge> & +BSP_CSGMesh:: +EdgeSet( +) const { + return m_edges.Ref(); +} + + BSP_CSGUserData & +BSP_CSGMesh:: +FaceVertexData( +) const { + return m_fv_data.Ref(); +} + + BSP_CSGUserData & +BSP_CSGMesh:: +FaceData( +) const { + return m_face_data.Ref(); +} + + +BSP_CSGMesh:: +~BSP_CSGMesh( +){ + // member deletion handled by smart ptr; +} + +// local geometry queries. +///////////////////////// + +// face queries +/////////////// + + void +BSP_CSGMesh:: +FaceVertices( + const BSP_FaceInd & f, + vector<BSP_VertexInd> &output +){ + vector<BSP_MFace> & face_set = FaceSet(); + output.insert( + output.end(), + face_set[f].m_verts.begin(), + face_set[f].m_verts.end() + ); +} + + + void +BSP_CSGMesh:: +FaceEdges( + const BSP_FaceInd & fi, + vector<BSP_EdgeInd> &output +){ + // take intersection of the edges emminating from all the vertices + // of this polygon; + + vector<BSP_MFace> &faces = FaceSet(); + vector<BSP_MEdge> &edges = EdgeSet(); + + const BSP_MFace & f = faces[fi]; + + // collect vertex edges; + + vector<BSP_VertexInd>::const_iterator face_verts_it = f.m_verts.begin(); + vector<BSP_VertexInd>::const_iterator face_verts_end = f.m_verts.end(); + + vector< vector<BSP_EdgeInd> > vertex_edges(f.m_verts.size()); + + int vector_slot = 0; + + for (;face_verts_it != face_verts_end; ++face_verts_it, ++vector_slot) { + VertexEdges(*face_verts_it,vertex_edges[vector_slot]); + } + + int prev = vector_slot - 1; + + // intersect pairs of edge sets + + for (int i = 0; i < vector_slot;i++) { + CTR_TaggedSetOps<BSP_EdgeInd,BSP_MEdge>::IntersectPair(vertex_edges[prev],vertex_edges[i],edges,output); + prev = i; + } + + // should always have 3 or more unique edges per face. + MT_assert(output.size() >=3); + + if (output.size() < 3) { + BSP_CSGException e(e_mesh_error); + throw(e); + } +}; + +// edge queries +/////////////// + + void +BSP_CSGMesh:: +EdgeVertices( + const BSP_EdgeInd & e, + vector<BSP_VertexInd> &output +){ + const vector<BSP_MEdge> &edges = EdgeSet(); + output.push_back(edges[e].m_verts[0]); + output.push_back(edges[e].m_verts[1]); +} + + void +BSP_CSGMesh:: +EdgeFaces( + const BSP_EdgeInd & e, + vector<BSP_FaceInd> &output +){ + + vector<BSP_MEdge> & edge_set = EdgeSet(); + output.insert( + output.end(), + edge_set[e].m_faces.begin(), + edge_set[e].m_faces.end() + ); + +} + +// vertex queries +///////////////// + + void +BSP_CSGMesh:: +VertexEdges( + const BSP_VertexInd &v, + vector<BSP_EdgeInd> &output +){ + + vector<BSP_MVertex> & vertex_set = VertexSet(); + output.insert( + output.end(), + vertex_set[v].m_edges.begin(), + vertex_set[v].m_edges.end() + ); +} + + void +BSP_CSGMesh:: +VertexFaces( + const BSP_VertexInd &vi, + vector<BSP_FaceInd> &output +) { + + vector<BSP_MEdge> &edges = EdgeSet(); + vector<BSP_MFace> &faces = FaceSet(); + vector<BSP_MVertex> &verts = VertexSet(); + + const vector<BSP_EdgeInd> &v_edges = verts[vi].m_edges; + vector<BSP_EdgeInd>::const_iterator e_it = v_edges.begin(); + + for (; e_it != v_edges.end(); ++e_it) { + + BSP_MEdge &e = edges[*e_it]; + + // iterate through the faces of this edge - push unselected + // edges to ouput and then select the edge + + vector<BSP_FaceInd>::const_iterator e_faces_end = e.m_faces.end(); + vector<BSP_FaceInd>::iterator e_faces_it = e.m_faces.begin(); + + for (;e_faces_it != e_faces_end; ++e_faces_it) { + + if (!faces[*e_faces_it].SelectTag()) { + output.push_back(*e_faces_it); + faces[*e_faces_it].SetSelectTag(true); + } + } + } + + // deselect selected faces. + vector<BSP_FaceInd>::iterator f_it = output.begin(); + + for (; f_it != output.end(); ++f_it) { + faces[*f_it].SetSelectTag(false); + } +} + + void +BSP_CSGMesh:: +InsertVertexIntoFace( + BSP_MFace & face, + const BSP_VertexInd & v1, + const BSP_VertexInd & v2, + const BSP_VertexInd & vi, + CSG_InterpolateUserFaceVertexDataFunc fv_split_func, + MT_Scalar epsilon +){ + // We assume that the face vertex data indices + // are consistent with the vertex inidex data. + + // look for v1 + vector<BSP_VertexInd>::iterator result = + find(face.m_verts.begin(),face.m_verts.end(),v1); + + MT_assert(result != face.m_verts.end()); + + BSP_CSGUserData & fv_data = m_fv_data.Ref(); + + // now we have to check on either side of the result for the + // other vertex + + vector<BSP_VertexInd>::iterator prev = result - 1; + if (prev < face.m_verts.begin()) { + prev = face.m_verts.end() -1; + } + if (*prev == v2) { + + // so result <=> v2 and prev <=> v1 + + // create space for new face vertex data + + int vf_i = fv_data.Size(); + fv_data.IncSize(); + + int vf_i2 = prev - face.m_verts.begin(); + int vf_i1 = result - face.m_verts.begin(); + + (*fv_split_func)( + fv_data[int(face.m_fv_data[vf_i1])], + fv_data[int(face.m_fv_data[vf_i2])], + fv_data[vf_i], + epsilon + ); + + // insert vertex data index. + face.m_fv_data.insert(face.m_fv_data.begin() + vf_i1,vf_i); + face.m_verts.insert(result,vi); + + return; + } + + vector<BSP_VertexInd>::iterator next = result + 1; + if (next >= face.m_verts.end()) { + next = face.m_verts.begin(); + } + if (*next == v2) { + + // so result <=> v1 and next <=> v2 + + int vf_i = fv_data.Size(); + fv_data.IncSize(); + + int vf_i2 = int(next - face.m_verts.begin()); + int vf_i1 = int(result - face.m_verts.begin()); + + (*fv_split_func)( + fv_data[int(face.m_fv_data[vf_i1])], + fv_data[int(face.m_fv_data[vf_i2])], + fv_data[vf_i], + epsilon + ); + + // insert vertex data index. + face.m_fv_data.insert(face.m_fv_data.begin() + vf_i2,vf_i); + face.m_verts.insert(next,vi); + + return; + } + + // if we get here we are in trouble. + MT_assert(false); + BSP_CSGException e(e_mesh_error); + throw(e); +} + + void +BSP_CSGMesh:: +SetBBox( + const MT_Vector3 & min, + const MT_Vector3 & max +){ + m_bbox_min = min; + m_bbox_max = max; +} + + + void +BSP_CSGMesh:: +BBox( + MT_Vector3 &min, + MT_Vector3 &max +) const { + min = m_bbox_min; + max = m_bbox_max; +} + + +// Update the BBox +////////////////// + + void +BSP_CSGMesh:: +UpdateBBox( +){ + // TODO +}; + + void +BSP_CSGMesh:: +SC_Classification( + BSP_FaceInd f, + const MT_Plane3& plane +){ + const BSP_MFace & face = FaceSet()[f]; + + vector<BSP_VertexInd>::const_iterator f_verts_it = face.m_verts.begin(); + vector<BSP_VertexInd>::const_iterator f_verts_end = face.m_verts.end(); + + for (;f_verts_it != f_verts_end; ++f_verts_it) { + + const BSP_MVertex & vert = VertexSet()[*f_verts_it]; + + MT_Scalar dist = plane.signedDistance( + vert.m_pos + ); + + if (fabs(dist) <= BSP_SPLIT_EPSILON ){ + MT_assert(BSP_Classification(vert.OpenTag()) == e_classified_on); + } else + if (dist > BSP_SPLIT_EPSILON) { + MT_assert(BSP_Classification(vert.OpenTag()) == e_classified_out); + } else + if (dist < BSP_SPLIT_EPSILON) { + MT_assert(BSP_Classification(vert.OpenTag()) == e_classified_in); + } + } +} + + + bool +BSP_CSGMesh:: +SC_Face( + BSP_FaceInd f +){ + + + +#if 0 + { + // check area is greater than zero. + + vector<BSP_MVertex> & verts = VertexSet(); + + vector<BSP_VertexInd> f_verts; + FaceVertices(f,f_verts); + + MT_assert(f_verts.size() >= 3); + + BSP_VertexInd root = f_verts[0]; + + MT_Scalar area = 0; + + for (int i=2; i < f_verts.size(); i++) { + MT_Vector3 a = verts[root].m_pos; + MT_Vector3 b = verts[f_verts[i-1]].m_pos; + MT_Vector3 c = verts[f_verts[i]].m_pos; + + MT_Vector3 l1 = b-a; + MT_Vector3 l2 = c-b; + + area += (l1.cross(l2)).length()/2; + } + + MT_assert(!MT_fuzzyZero(area)); + } +#endif + // Check coplanarity +#if 0 + MT_Plane3 plane = FacePlane(f); + + const BSP_MFace & face = FaceSet()[f]; + vector<BSP_VertexInd>::const_iterator f_verts_it = face.m_verts.begin(); + vector<BSP_VertexInd>::const_iterator f_verts_end = face.m_verts.end(); + + for (;f_verts_it != f_verts_end; ++f_verts_it) { + MT_Scalar dist = plane.signedDistance( + VertexSet()[*f_verts_it].m_pos + ); + + MT_assert(fabs(dist) < BSP_SPLIT_EPSILON); + } +#endif + + + // Check connectivity + + vector<BSP_EdgeInd> f_edges; + FaceEdges(f,f_edges); + + MT_assert(f_edges.size() == FaceSet()[f].m_verts.size()); + + unsigned int i; + for (i = 0; i < f_edges.size(); ++i) { + + int matches = 0; + for (unsigned int j = 0; j < EdgeSet()[f_edges[i]].m_faces.size(); j++) { + + if (EdgeSet()[f_edges[i]].m_faces[j] == f) matches++; + } + + MT_assert(matches == 1); + + } + return true; +} + + MT_Plane3 +BSP_CSGMesh:: +FacePlane( + const BSP_FaceInd & fi +) const{ + + const BSP_MFace & f0 = FaceSet()[fi]; + + // Have to be a bit careful here coz the poly may have + // a lot of parallel edges. Should walk round the polygon + // and check length of cross product. + + const MT_Vector3 & p1 = VertexSet()[f0.m_verts[0]].m_pos; + const MT_Vector3 & p2 = VertexSet()[f0.m_verts[1]].m_pos; + + int face_size = f0.m_verts.size(); + MT_Vector3 n; + + for (int i = 2 ; i <face_size; i++) { + const MT_Vector3 & pi = VertexSet()[f0.m_verts[i]].m_pos; + + MT_Vector3 l1 = p2-p1; + MT_Vector3 l2 = pi-p2; + n = l1.cross(l2); + MT_Scalar length = n.length(); + + if (!MT_fuzzyZero(length)) { + n = n * (1/length); + break; + } + } + return MT_Plane3(n,p1); +} + + void +BSP_CSGMesh:: +ComputeFacePlanes( +){ + + int fsize = FaceSet().size(); + int i=0; + for (i = 0; i < fsize; i++) { + + FaceSet()[i].m_plane = FacePlane(i); + } +}; + + + int +BSP_CSGMesh:: +CountTriangles( +) const { + + // Each polygon of n sides can be partitioned into n-3 triangles. + // So we just go through and sum this function of polygon size. + + vector<BSP_MFace> & face_set = FaceSet(); + + vector<BSP_MFace>::const_iterator face_it = face_set.begin(); + vector<BSP_MFace>::const_iterator face_end = face_set.end(); + + int sum = 0; + + for (;face_it != face_end; face_it++) { + + // Should be careful about degenerate faces here. + sum += face_it->m_verts.size() - 2; + } + + return sum; +} + + + diff --git a/intern/bsp/intern/BSP_CSGMesh.h b/intern/bsp/intern/BSP_CSGMesh.h new file mode 100755 index 00000000000..1b56ca7a3e5 --- /dev/null +++ b/intern/bsp/intern/BSP_CSGMesh.h @@ -0,0 +1,345 @@ +/** + * $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 ***** + */ + +#ifndef NAN_INCLUDED_BSP_CSGMesh_h + +#define NAN_INCLUDED_BSP_CSGMesh_h + +#include "BSP_MeshPrimitives.h" +#include "MEM_SmartPtr.h" +#include "MEM_RefCountPtr.h" +#include "MEM_NonCopyable.h" +#include "BSP_CSGUserData.h" +#include "../extern/CSG_BooleanOps.h" + + +class MT_Plane3; +class BSP_MeshFragment; + +class BSP_CSGMesh : + public MEM_NonCopyable, + public MEM_RefCountable +{ + +public : + + static + BSP_CSGMesh * + New( + ); + + bool + SetVertices( + MEM_SmartPtr<std::vector<BSP_MVertex> > verts + ); + + void + SetFaceVertexData( + MEM_SmartPtr<BSP_CSGUserData> fv_data + ); + + void + SetFaceData( + MEM_SmartPtr<BSP_CSGUserData> f_data + ); + + void + AddPolygon( + const int * verts, + int num_verts + ); + + void + AddPolygon( + const int * verts, + const int * fv_indices, + int num_verts + ); + + void + AddSubTriangle( + const BSP_MFace &iface, + const int * index_info + ); + + // assumes that the face already has a plane equation + void + AddPolygon( + const BSP_MFace &face + ); + + + // Allocate and build the mesh edges. + //////////////////////////////////// + + bool + BuildEdges( + ); + + // Clean the mesh of edges. and edge pointers + // This removes the circular connectivity information + ///////////////////////////////////////////// + + void + DestroyEdges( + ); + + // return a new seperate copy of the + // mesh allocated on the heap. + + BSP_CSGMesh * + NewCopy( + ) const; + + + // Reverse the winding order of every polygon + // in the mesh and swap the planes around. + + void + Invert( + ); + + + // geometry access + ////////////////// + + std::vector<BSP_MVertex> & + VertexSet( + ) const ; + + std::vector<BSP_MFace> & + FaceSet( + ) const ; + + std::vector<BSP_MEdge> & + EdgeSet( + ) const; + + BSP_CSGUserData & + FaceVertexData( + ) const; + + BSP_CSGUserData & + FaceData( + ) const; + + ~BSP_CSGMesh( + ); + + // local geometry queries. + ///////////////////////// + + // face queries + /////////////// + + void + FaceVertices( + const BSP_FaceInd & f, + std::vector<BSP_VertexInd> &output + ); + + void + FaceEdges( + const BSP_FaceInd & f, + std::vector<BSP_EdgeInd> &output + ); + + // edge queries + /////////////// + + void + EdgeVertices( + const BSP_EdgeInd & e, + std::vector<BSP_VertexInd> &output + ); + + void + EdgeFaces( + const BSP_EdgeInd & e, + std::vector<BSP_FaceInd> &output + ); + + // vertex queries + ///////////////// + + void + VertexEdges( + const BSP_VertexInd & v, + std::vector<BSP_EdgeInd> &output + ); + + void + VertexFaces( + const BSP_VertexInd & v, + std::vector<BSP_FaceInd> &output + ); + + // Returns the edge index of the edge from v1 to v2. + // Does this by searching the edge sets of v1 - but not v2. + // If you are paranoid you should check both and make sure the + // indices are the same. If the edge doe not exist edgeInd is empty. + + BSP_EdgeInd + FindEdge( + const BSP_VertexInd &v1, + const BSP_VertexInd &v2 + ) const; + + + // Bounding box methods + /////////////////////// + + void + SetBBox( + const MT_Vector3 & min, + const MT_Vector3 & max + ); + + void + BBox( + MT_Vector3 &min, + MT_Vector3 &max + ) const ; + + // Update the BBox + ////////////////// + + void + UpdateBBox( + ); + + + /** + * Sanity checkers + */ + + // make sure the edge faces have a pointer to f + + bool + SC_Face( + BSP_FaceInd f + ); + + /** + * Make sure the polygons vertex classification is correct + */ + + void + SC_Classification( + BSP_FaceInd f, + const MT_Plane3&plane + ); + + /** + * Return the face plane equation + */ + + MT_Plane3 + FacePlane( + const BSP_FaceInd &fi + )const; + + + /** + * Recompute Face plane equations. + * essential if you have been messing with the object. + */ + + void + ComputeFacePlanes( + ); + + /** + * Count the number of trinagles in the mesh. + * This is not the same as the number of polygons. + */ + + int + CountTriangles( + ) const; + + /** + * Insert a vertex index into a polygon + * and call the external splitting function to + * generate a new face vertex property. + */ + + void + InsertVertexIntoFace( + BSP_MFace & face, + const BSP_VertexInd & v1, + const BSP_VertexInd & v2, + const BSP_VertexInd & vi, + CSG_InterpolateUserFaceVertexDataFunc fv_split_func, + MT_Scalar epsilon + ); + + +private : + + void + InsertEdge( + const BSP_VertexInd &v1, + const BSP_VertexInd &v2, + const BSP_FaceInd &f, + std::vector<BSP_EdgeInd> &new_edges + ); + + + // Private to insure heap instantiation. + + BSP_CSGMesh( + ); + + + MEM_SmartPtr< std::vector<BSP_MVertex> > m_verts; + MEM_SmartPtr< std::vector<BSP_MFace> > m_faces; + MEM_SmartPtr< std::vector<BSP_MEdge> > m_edges; + + // The face_vertex user data associated with this mesh + + MEM_SmartPtr<BSP_CSGUserData> m_fv_data; + + // The face user data associated with this mesh - + // This is a buffer that maps directly to the face buffer. + // An index into the faces is alos an index into m_face_data + // for that face + + MEM_SmartPtr<BSP_CSGUserData> m_face_data; + + + MT_Vector3 m_bbox_min; + MT_Vector3 m_bbox_max; + +}; + + +#endif
\ No newline at end of file diff --git a/intern/bsp/intern/BSP_CSGMeshBuilder.cpp b/intern/bsp/intern/BSP_CSGMeshBuilder.cpp new file mode 100755 index 00000000000..cbe4bfc920d --- /dev/null +++ b/intern/bsp/intern/BSP_CSGMeshBuilder.cpp @@ -0,0 +1,152 @@ +/** + * $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 ***** + */ + +#include "BSP_CSGMeshBuilder.h" + + +using namespace std; + + MEM_SmartPtr<BSP_CSGMesh> +BSP_CSGMeshBuilder:: +NewMesh( + CSG_MeshPropertyDescriptor &props, + CSG_FaceIteratorDescriptor &face_it, + CSG_VertexIteratorDescriptor &vertex_it +) { + + MEM_SmartPtr<BSP_CSGMesh> mesh = BSP_CSGMesh::New(); + if (mesh == NULL) return NULL; + + MEM_SmartPtr<BSP_CSGUserData> fv_data = new BSP_CSGUserData(props.user_face_vertex_data_size); + MEM_SmartPtr<BSP_CSGUserData> face_data = new BSP_CSGUserData(props.user_data_size); + + + MEM_SmartPtr<vector<BSP_MVertex> > vertices(new vector<BSP_MVertex>); + if (vertices == NULL || fv_data == NULL || face_data == NULL) return NULL; + + // The size of the vertex data array will be at least the number of faces. + + fv_data->Reserve(face_it.num_elements); + face_data->Reserve(face_it.num_elements); + + vertices->reserve(vertex_it.num_elements); + + CSG_IVertex vertex; + + while (!vertex_it.Done(vertex_it.it)) { + vertex_it.Fill(vertex_it.it,&vertex); + + MT_Point3 pos(vertex.position); + vertices->push_back(BSP_MVertex(pos)); + + vertex_it.Step(vertex_it.it); + } + + // pass ownership of the vertices to the mesh. + mesh->SetVertices(vertices); + + // now for the polygons. + + CSG_IFace face; + // we may need to decalare some memory for user defined face properties. + + if (props.user_data_size) { + face.user_face_data = new char[props.user_data_size]; + } else { + face.user_face_data = NULL; + } + + if (props.user_face_vertex_data_size) { + char * fv_data = NULL; + fv_data = new char[4 * props.user_face_vertex_data_size]; + + face.user_face_vertex_data[0] = fv_data; + face.user_face_vertex_data[1] = fv_data + props.user_face_vertex_data_size; + face.user_face_vertex_data[2] = fv_data + 2*props.user_face_vertex_data_size; + face.user_face_vertex_data[3] = fv_data + 3*props.user_face_vertex_data_size; + } else { + face.user_face_vertex_data[0] = NULL; + face.user_face_vertex_data[1] = NULL; + face.user_face_vertex_data[2] = NULL; + face.user_face_vertex_data[3] = NULL; + } + + + int tri_index[3]; + int fv_index[3]; + + while (!face_it.Done(face_it.it)) { + face_it.Fill(face_it.it,&face); + + // Let's not rely on quads being coplanar - especially if they + // are coming out of that soup of code from blender... + if (face.vertex_number == 4) { + tri_index[0] = face.vertex_index[2]; + tri_index[1] = face.vertex_index[3]; + tri_index[2] = face.vertex_index[0]; + + fv_index[0] = fv_data->Duplicate(face.user_face_vertex_data[2]); + fv_index[1] = fv_data->Duplicate(face.user_face_vertex_data[3]); + fv_index[2] = fv_data->Duplicate(face.user_face_vertex_data[0]); + + mesh->AddPolygon(tri_index,fv_index,3); + + // bit of an unspoken relationship between mesh face buffer + // and the face data which I guess should be changed. + face_data->Duplicate(face.user_face_data); + + } + + fv_index[0] = fv_data->Duplicate(face.user_face_vertex_data[0]); + fv_index[1] = fv_data->Duplicate(face.user_face_vertex_data[1]); + fv_index[2] = fv_data->Duplicate(face.user_face_vertex_data[2]); + + mesh->AddPolygon(face.vertex_index,fv_index,3); + // bit of an unspoken relationship between mesh face buffer + // and the face data which I guess should be changed. + face_data->Duplicate(face.user_face_data); + + + face_it.Step(face_it.it); + } + + // give the user face vertex data over to the mesh. + + mesh->SetFaceVertexData(fv_data); + mesh->SetFaceData(face_data); + + // that's it + + delete[] static_cast<char *>(face.user_face_data); + delete[] static_cast<char *>(face.user_face_vertex_data[0]); + return mesh; +} + diff --git a/intern/bsp/intern/BSP_CSGMeshBuilder.h b/intern/bsp/intern/BSP_CSGMeshBuilder.h new file mode 100755 index 00000000000..b79b65ba55b --- /dev/null +++ b/intern/bsp/intern/BSP_CSGMeshBuilder.h @@ -0,0 +1,74 @@ +/** + * $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 ***** + */ + +#ifndef BSP_CSGMeshBuilder_h + +#define BSP_CSGMeshBuilder_h + +#include "../extern/CSG_BooleanOps.h" +#include "BSP_CSGMesh.h" +#include "MEM_NonCopyable.h" +#include "MEM_SmartPtr.h" + +/** + * This class helps you to build a mesh from 2 seperate vertex/face + * iterators defined in the external interface of the bsp module. + * This code should really become party of a generic C++ mesh interface + * but later... + */ + +class BSP_CSGMeshBuilder : public MEM_NonCopyable{ + +public : + + /** + * Return a new BSP_CSGMesh with the desired props + * built from the given face and vertex iterators. + * The iterators are exhausted by this action. + */ + + static + MEM_SmartPtr<BSP_CSGMesh> + NewMesh( + CSG_MeshPropertyDescriptor &props, + CSG_FaceIteratorDescriptor &face_it, + CSG_VertexIteratorDescriptor &vertex_it + ); + +private : + + BSP_CSGMeshBuilder( + ); + +}; + + +#endif diff --git a/intern/bsp/intern/BSP_CSGMeshSplitter.cpp b/intern/bsp/intern/BSP_CSGMeshSplitter.cpp new file mode 100755 index 00000000000..eac926085ef --- /dev/null +++ b/intern/bsp/intern/BSP_CSGMeshSplitter.cpp @@ -0,0 +1,715 @@ +/** + * $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 ***** + */ + +#include "BSP_CSGMeshSplitter.h" + +#include "BSP_CSGMesh.h" +#include "BSP_MeshFragment.h" +#include "BSP_CSGException.h" +#include "MT_MinMax.h" +#include "MT_assert.h" + +using namespace std; + + +BSP_CSGMeshSplitter:: +BSP_CSGMeshSplitter( + CSG_InterpolateUserFaceVertexDataFunc fv_split_func +) : m_fv_func(fv_split_func) +{ + // nothing to do +}; + + void +BSP_CSGMeshSplitter:: +Split( + const MT_Plane3& plane, + BSP_MeshFragment *frag, + BSP_MeshFragment *in_frag, + BSP_MeshFragment *out_frag, + BSP_MeshFragment *on_frag, + BSP_MeshFragment *spanning_frag +){ + // First classify the vertices and the polygons of the + // incoming fragment. + frag->Classify(plane,in_frag,out_frag,on_frag,m_spanning_faces,m_tagged_verts); + + SplitImp(*(frag->Mesh()),plane,m_spanning_faces,in_frag,out_frag,on_frag,m_tagged_verts); + + m_spanning_faces.clear(); + m_tagged_verts.clear(); + +} + + void +BSP_CSGMeshSplitter:: +Split( + BSP_CSGMesh & mesh, + const MT_Plane3& plane, + BSP_MeshFragment *in_frag, + BSP_MeshFragment *out_frag, + BSP_MeshFragment *on_frag, + BSP_MeshFragment *spanning_frag +){ + BSP_MeshFragment::Classify(mesh, plane,in_frag,out_frag,on_frag,m_spanning_faces,m_tagged_verts); + + SplitImp(mesh,plane,m_spanning_faces,in_frag,out_frag,on_frag,m_tagged_verts); + m_spanning_faces.clear(); + m_tagged_verts.clear(); +} + +BSP_CSGMeshSplitter:: +~BSP_CSGMeshSplitter( +){ + // nothing to do +} + + void +BSP_CSGMeshSplitter:: +SplitImp( + BSP_CSGMesh & mesh, + const MT_Plane3& plane, + const std::vector<BSP_FaceInd> & spanning_faces, + BSP_MeshFragment *in_frag, + BSP_MeshFragment *out_frag, + BSP_MeshFragment *on_frag, + std::vector<BSP_VertexInd> & classified_verts +){ + // Assumes you have already classified the vertices. + // and generated a set of spanning faces. + + vector<BSP_MEdge> & edge_set = mesh.EdgeSet(); + vector<BSP_MVertex> & vertex_set = mesh.VertexSet(); + vector<BSP_MFace> & face_set = mesh.FaceSet(); + + // Now identify the spanning edges. + // These can be computed in many ways but probably the most + // efficient is to select all edges from the vertices of the + // spanning polygons that cross the plane. + + vector<BSP_FaceInd>::const_iterator sface_end = m_spanning_faces.end(); + vector<BSP_FaceInd>::const_iterator sface_it = m_spanning_faces.begin(); + + for (;sface_it != sface_end; ++sface_it) { + + BSP_MFace & sface = face_set[*sface_it]; + + vector<BSP_VertexInd>::const_iterator sf_vert_end = sface.m_verts.end(); + vector<BSP_VertexInd>::iterator sf_vert_it = sface.m_verts.begin(); + + for (;sf_vert_it != sf_vert_end; ++sf_vert_it) { + BSP_MVertex & vert = vertex_set[*sf_vert_it]; + + if (!vert.SelectTag()) { + // what classification does this vertex have? + + BSP_Classification root_vert_class = BSP_Classification(vert.OpenTag()); + + // we are only interested in edges whose vertices are in and out. + if (root_vert_class != e_classified_on) { + + BSP_Classification opp_class = e_classified_out; + if (root_vert_class == e_classified_out) { + opp_class = e_classified_in; + } + // we haven't visited this vertex before so lets + // analyse it's edges. + + vector<BSP_EdgeInd>::const_iterator v_edge_end = vert.m_edges.end(); + vector<BSP_EdgeInd>::iterator v_edge_it = vert.m_edges.begin(); + + for (; v_edge_it != v_edge_end; ++v_edge_it) { + BSP_MEdge & edge = edge_set[*v_edge_it]; + + if (!edge.SelectTag()) { + // we haven't visited this edge before so check it's + // end points + + // we know that a spanning polygon can have at most + // 2 on vertices (even at this point where we haven't + // yet split the edge!) We are interested in edges whose + // vertices are in and out the plane. + + BSP_VertexInd opp_vi = edge.OpVertex(*sf_vert_it); + if (vertex_set[opp_vi].OpenTag() == opp_class) { + // we have found an edge !!!! + m_spanning_edges.push_back(*v_edge_it); + } + edge.SetSelectTag(true); + m_visited_edges.push_back(*v_edge_it); + } + } + } + + vert.SetSelectTag(true); + m_visited_verts.push_back(*sf_vert_it); + } + } + } + + // clear the tags we used in the above + + unsigned int i; + + for (i = 0; i < m_visited_edges.size(); ++i) { + edge_set[m_visited_edges[i]].SetSelectTag(false); + } + for (i=0;i < m_visited_verts.size(); ++i) { + vertex_set[m_visited_verts[i]].SetSelectTag(false); + } + for (i=0; i < m_spanning_faces.size(); ++i) { + face_set[m_spanning_faces[i]].SetSelectTag(false); + } + + // The spanning edge set constains unique edges. Next we run + // through the edge set and compute the intersection with the + // plane --- the edge is guarenteed not to be parallel to the plane! + // we then split the edge with the new vertex. + + // We identify the polygons affected by the split + + vector<BSP_EdgeInd>::const_iterator s_edge_end = m_spanning_edges.end(); + vector<BSP_EdgeInd>::iterator s_edge_it = m_spanning_edges.begin(); + + for (;s_edge_it != s_edge_end; ++s_edge_it) { + + const BSP_MEdge & edge = edge_set[*s_edge_it]; + + const BSP_MVertex &v1 = vertex_set[edge.m_verts[0]]; + const BSP_MVertex &v2 = vertex_set[edge.m_verts[1]]; + + const MT_Vector3 & ptA = v1.m_pos; + const MT_Vector3 & ptB = v2.m_pos; + + // compute the intersection point of plane and ptA->ptB + MT_Vector3 v = ptB - ptA; + MT_Scalar sideA = plane.signedDistance(ptA); + + MT_Scalar epsilon = -sideA/plane.Normal().dot(v); + MT_Vector3 new_p = ptA + (v * epsilon); + + // so new_p is the intersection of the plane and the edge. + // split the edge at new_p + + BSP_MVertex new_vert; + new_vert.m_pos = new_p; + + BSP_VertexInd new_vi = SplitEdge(mesh,*s_edge_it,new_vert,epsilon); + + // tag the new vertex as 'on' the plane - we use this information + // to split the affected polygons below. + vertex_set[new_vi].SetOpenTag(e_classified_on); + + // We add it to the tagged verts so we can remove the tag later. + classified_verts.push_back(new_vi); + } + + // We start with the spanning polygons... + // not forgetting to add the new polygon fragments to the correct fragment bins. + + sface_end = m_spanning_faces.end(); + sface_it = m_spanning_faces.begin(); + + for (;sface_it != sface_end; ++sface_it) { + + BSP_FaceInd f_in,f_out; + + SplitPolygon(mesh,*sface_it,f_in,f_out); + in_frag->FaceSet().push_back(f_in); + out_frag->FaceSet().push_back(f_out); + } + + // Finally we have to clean up the vertex tags we set on all the vertices + // There will be some overlap between the vertex sets, so this operation + // is a tiny bit inefficient. + + vector<BSP_VertexInd>::const_iterator v_end = classified_verts.end(); + vector<BSP_VertexInd>::const_iterator v_it = classified_verts.begin(); + + for (; v_it != v_end; ++v_it) { + vertex_set[*v_it].SetOpenTag(e_unclassified); + } + + // tidy up the cached arrays. + + m_spanning_edges.clear(); + m_visited_edges.clear(); + m_visited_verts.clear(); + + + // le fin. + +} + + + BSP_VertexInd +BSP_CSGMeshSplitter:: +SplitEdge( + BSP_CSGMesh & mesh, + BSP_EdgeInd ei, + BSP_MVertex &vertex, + MT_Scalar epsilon +){ + vector<BSP_MEdge> & edge_set = mesh.EdgeSet(); + vector<BSP_MVertex> & vertex_set = mesh.VertexSet(); + vector<BSP_MFace> & face_set = mesh.FaceSet(); + + MT_assert(edge_set.size() > (unsigned int)(ei)); + + if (edge_set.size() <= (unsigned int)(ei)) { + BSP_CSGException e(e_param_error); + throw(e); + } + + // push the vertex onto the vertex array + BSP_VertexInd new_vi = vertex_set.size(); + vertex_set.push_back(vertex); + BSP_MVertex & new_v = vertex_set[new_vi]; + + // copy the edge because the new edge will have + // exactly the same face set. + + BSP_EdgeInd new_ei = edge_set.size(); + + // Note never use set.push_back(set[i]) + // coz push_back excepts a reference which may become + // invalid if the set is resized + + edge_set.push_back(BSP_MEdge()); + edge_set[new_ei] = edge_set[ei]; + BSP_MEdge & new_e = edge_set[new_ei]; + + BSP_MEdge &e = edge_set[ei]; + + // get the edge vertices. + BSP_MVertex & e_v2 = vertex_set[e.m_verts[1]]; + + // Remove the split edge from vertex 2. + // Let's hope that the vertex isn't using this edge for + // its' open tag!! + + BSP_Classification v2_class = BSP_Classification(e_v2.OpenTag()); + + e_v2.RemoveEdge(ei); + + // add the split edge to the new vertex. + new_v.AddEdge(ei); + + // add the new edge to the new vertex. + new_v.AddEdge(new_ei); + + // add the new edge to vertex 2 + e_v2.AddEdge(new_ei); + + // Reset the tags for modified vertex. + + e_v2.SetOpenTag(v2_class); + + + // Replace the old vertex indices in the new edge. + new_e.m_verts[0] = new_vi; + e.m_verts[1] = new_vi; + + // Finally add the vertex in the correct position to the + // neighbouring polygons. + + vector<BSP_FaceInd>::iterator neighbour_face_it = e.m_faces.begin(); + vector<BSP_FaceInd>::const_iterator neighbour_face_end = e.m_faces.end(); + + for (; neighbour_face_it != neighbour_face_end; ++neighbour_face_it) { + + mesh.InsertVertexIntoFace( + face_set[*neighbour_face_it], + new_e.m_verts[1], + e.m_verts[0], + new_vi, + m_fv_func, + epsilon + ); + } + + // That should be it (cough) + return new_vi; + +} + + void +BSP_CSGMeshSplitter:: +SplitPolygon( + BSP_CSGMesh & mesh, + BSP_FaceInd fi, + BSP_FaceInd &fin, + BSP_FaceInd &fout +){ + vector<BSP_MEdge> & edge_set = mesh.EdgeSet(); + vector<BSP_MVertex> & vertex_set = mesh.VertexSet(); + vector<BSP_MFace> & face_set = mesh.FaceSet(); + + MT_assert(face_set.size() > (unsigned int)(fi)); + if (face_set.size() <= (unsigned int)(fi)) { + BSP_CSGException e(e_param_error); + throw(e); + } + + BSP_MFace & face = face_set[fi]; + + // Walk throught the vertices of this polygon. + // generate inside and outside loops. + + vector<BSP_VertexInd>::const_iterator f_verts_end = face.m_verts.end(); + vector<BSP_VertexInd>::iterator f_verts_it = face.m_verts.begin(); + + vector<BSP_UserFVInd>::const_iterator f_fv_data_it = face.m_fv_data.begin(); + + // NOTE we don't actually duplicate fv data for this face + // we just duplicate the indices, so both on vertices + // will share the fv data. + + for (;f_verts_it != f_verts_end; ++f_verts_it, ++f_fv_data_it) { + + BSP_MVertex & vert = vertex_set[*f_verts_it]; + BSP_Classification v_class = BSP_Classification(vert.OpenTag()); + + if (v_class == e_classified_in) { + m_in_loop.push_back(*f_verts_it); + m_fv_in_loop.push_back(*f_fv_data_it); + } else + if (v_class == e_classified_out) { + m_out_loop.push_back(*f_verts_it); + m_fv_out_loop.push_back(*f_fv_data_it); + + } else + if (v_class == e_classified_on) { + m_in_loop.push_back(*f_verts_it); + m_out_loop.push_back(*f_verts_it); + m_on_loop.push_back(*f_verts_it); + m_fv_in_loop.push_back(*f_fv_data_it); + m_fv_out_loop.push_back(*f_fv_data_it); + } else { + // The vertex is unclassified this is an error! + MT_assert(false); + BSP_CSGException e(e_split_error); + throw(e); + } + } + + if ((m_in_loop.size() == 1) || (m_out_loop.size() == 1)) { + // Then there was only 1 tagged vertex I guess this is fine + // but should be reviewed! + + // NOT fine - we only ever split spanning polygons. + MT_assert(false); + BSP_CSGException e(e_split_error); + throw(e); + } + + MT_assert(m_in_loop.size() >=3 && m_out_loop.size() >=3 && m_on_loop.size() == 2); + + if (m_in_loop.size() <3 || m_out_loop.size() <3 || m_on_loop.size() !=2) { + BSP_CSGException e(e_split_error); + throw(e); + } + // Now we have 2 seperate vertex loops representing the polygon + // halves. + + // create a new polygon for the out_loop of vertices. + //////////////////////////////////////////////////// + + // Duplicate face data. + + mesh.FaceData().Duplicate(fi); + + BSP_FaceInd new_fi = face_set.size(); + face_set.push_back(BSP_MFace()); + BSP_MFace & new_f = face_set[new_fi]; + + // assign plane equation for new face - this is the same as the + // original of course. + + new_f.m_plane = face_set[fi].m_plane; + + // note that face may have become invalid because we just been adding + // more polygons to the array. We can't assign a new reference to the old + // invlaid one! It will call try and call the assignment operator on + // the original face!!!! The joys of references! We just use face_set[fi] + // from now on to be safe + + // We need to insert an edge between m_on_loop[0] and m_on_loop[1] + + // Make sure the edge does not already exist between these 2 vertices! + // This can happen if the original mesh has duplicate polygons. + // We still wire up the new polygons to this edge, which will + // lead to duplicate polygons in the output -- but algorithm + // should still work. + BSP_EdgeInd new_ei = mesh.FindEdge(m_on_loop[0],m_on_loop[1]); + + if (new_ei.IsEmpty()) { + + // create a new edge. + + new_ei = edge_set.size(); + edge_set.push_back(BSP_MEdge()); + BSP_MEdge & new_e = edge_set[new_ei]; + + new_e.m_verts[0] = m_on_loop[0]; + new_e.m_verts[1] = m_on_loop[1]; + + // Now tie the edge to it's vertices. + + vertex_set[m_on_loop[0]].AddEdge(new_ei); + vertex_set[m_on_loop[1]].AddEdge(new_ei); + } + + edge_set[new_ei].m_faces.push_back(fi); + // This next line is a trick we are going to replace it in a moment + // with new_fi. It means that all the edges of the new polygon have + // pointers to the old polygon which we can replace. + edge_set[new_ei].m_faces.push_back(fi); + + + // Replace the old polygons vertex loop with the in_loop of vertices. + + face_set[fi].m_verts = m_in_loop; + new_f.m_verts = m_out_loop; + + // Replace the olf fv loops. + face_set[fi].m_fv_data = m_fv_in_loop; + new_f.m_fv_data = m_fv_out_loop; + + + // That should be it for the old polygon; + // For the new polygon we just need to iterate around it's + // edges and replace pointers to the old polygon with pointers + // to the new one. + + f_verts_end = new_f.m_verts.end(); + f_verts_it = new_f.m_verts.begin(); + + BSP_VertexInd prev = new_f.m_verts.back(); + + for (;f_verts_it != f_verts_end; ++f_verts_it) { + BSP_EdgeInd new_f_ei = mesh.FindEdge(prev,*f_verts_it); + + MT_assert(!new_f_ei.IsEmpty()); + + if (new_f_ei.IsEmpty()) { + BSP_CSGException e(e_split_error); + throw(e); + } + + edge_set[new_f_ei].SwapFace(fi,new_fi); + prev = *f_verts_it; + + } + + // That should be everything. + + fin = fi; + fout = new_fi; + + // clear up cached helpers. + m_in_loop.clear(); + m_on_loop.clear(); + m_out_loop.clear(); + + m_fv_in_loop.clear(); + m_fv_out_loop.clear(); + +} + + BSP_FaceInd +BSP_CSGMeshSplitter:: +TriangulateConvexQuad( + BSP_CSGMesh & mesh, + const BSP_FaceInd fi +){ + + // we assume that the fi points to a face with + // exactly 4 vertices. + + + // We are definately going to create a new face + // so lets make space for it in the face array. + + vector<BSP_MFace> & face_set = mesh.FaceSet(); + vector<BSP_MVertex> & vertex_set = mesh.VertexSet(); + vector<BSP_MEdge> & edge_set = mesh.EdgeSet(); + + if (face_set[fi].m_verts.size() == 3) { + return BSP_FaceInd::Empty(); + } + + // duplicate face data + mesh.FaceData().Duplicate(fi); + + const BSP_FaceInd new_fi = face_set.size(); + face_set.push_back(BSP_MFace()); + BSP_MFace & new_face = face_set[new_fi]; + BSP_MFace & face = face_set[fi]; + + new_face.m_plane = face.m_plane; + + // The internal edges are [0,2] and [1,3] + // these split the quad into the triangles + // [0,1,2],[2,3,0] and [0,1,3],[1,2,3] respectively + + const MT_Point3 & p0 = vertex_set[face.m_verts[0]].m_pos; + const MT_Point3 & p1 = vertex_set[face.m_verts[1]].m_pos; + const MT_Point3 & p2 = vertex_set[face.m_verts[2]].m_pos; + const MT_Point3 & p3 = vertex_set[face.m_verts[3]].m_pos; + + MT_Vector3 e0 = p1 - p0; + MT_Vector3 e1 = p2 - p1; + MT_Vector3 e2 = p3 - p2; + MT_Vector3 e3 = p0 - p3; + + MT_Scalar A = (e0.cross(e1)).length2(); + MT_Scalar B = (e2.cross(e3)).length2(); + MT_Scalar C = (e3.cross(e0)).length2(); + MT_Scalar D = (e1.cross(e2)).length2(); + + MT_Scalar minab = MT_min(A,B); + MT_Scalar maxab = MT_max(A,B); + + MT_Scalar mincd = MT_min(C,D); + MT_Scalar maxcd = MT_max(C,D); + + MT_Scalar ratioab = minab/maxab; + MT_Scalar ratiocd = mincd/maxcd; + + ratioab = MT_abs(1-ratioab); + ratiocd = MT_abs(1-ratiocd); + + vector<BSP_VertexInd> loop1(3),loop2(3); + vector<BSP_UserFVInd> fv_loop1(3),fv_loop2(3); + + if (ratioab < ratiocd) { + // then use [0,2] as splitting edge. + loop1[0] = face.m_verts[1]; + loop1[1] = face.m_verts[2]; + loop1[2] = face.m_verts[0]; + + loop2[0] = face.m_verts[2]; + loop2[1] = face.m_verts[3]; + loop2[2] = face.m_verts[0]; + + // same for fv indices. + fv_loop1[0] = face.m_fv_data[1]; + fv_loop1[1] = face.m_fv_data[2]; + fv_loop1[2] = face.m_fv_data[0]; + + fv_loop2[0] = face.m_fv_data[2]; + fv_loop2[1] = face.m_fv_data[3]; + fv_loop2[2] = face.m_fv_data[0]; + + + } else { + // use [1,3] as splitting edge + loop1[0] = face.m_verts[0]; + loop1[1] = face.m_verts[1]; + loop1[2] = face.m_verts[3]; + + loop2[0] = face.m_verts[1]; + loop2[1] = face.m_verts[2]; + loop2[2] = face.m_verts[3]; + + // same for fv indices. + fv_loop1[0] = face.m_fv_data[0]; + fv_loop1[1] = face.m_fv_data[1]; + fv_loop1[2] = face.m_fv_data[3]; + + fv_loop2[0] = face.m_fv_data[1]; + fv_loop2[1] = face.m_fv_data[2]; + fv_loop2[2] = face.m_fv_data[3]; + + } + + // TODO factor out commmon code between here and SplitPolygon. + + BSP_EdgeInd new_ei = mesh.FindEdge(loop1[1],loop1[2]); + + if (new_ei.IsEmpty()) { + + // create a new edge. + + new_ei = edge_set.size(); + edge_set.push_back(BSP_MEdge()); + BSP_MEdge & new_e = edge_set[new_ei]; + + new_e.m_verts[0] = loop1[1]; + new_e.m_verts[1] = loop1[2]; + + // Now tie the edge to it's vertices. + + vertex_set[loop1[1]].AddEdge(new_ei); + vertex_set[loop1[2]].AddEdge(new_ei); + } + + edge_set[new_ei].m_faces.push_back(fi); + // This next line is a trick we are going to replace it in a moment + // with new_fi. It means that all the edges of the new polygon have + // pointers to the old polygon which we can replace. + edge_set[new_ei].m_faces.push_back(fi); + + + // Replace the old polygons vertex loop with the in_loop of vertices. + + face.m_verts = loop1; + face.m_fv_data = fv_loop1; + new_face.m_verts = loop2; + new_face.m_fv_data = fv_loop2; + + // That should be it for the old polygon; + // For the new polygon we just need to iterate around it's + // edges and replace pointers to the old polygon with pointers + // to the new one. + + vector<BSP_VertexInd>::const_iterator f_verts_end = new_face.m_verts.end(); + vector<BSP_VertexInd>::const_iterator f_verts_it = new_face.m_verts.begin(); + + BSP_VertexInd prev = new_face.m_verts.back(); + + for (;f_verts_it != f_verts_end; ++f_verts_it) { + BSP_EdgeInd new_f_ei = mesh.FindEdge(prev,*f_verts_it); + + MT_assert(!new_f_ei.IsEmpty()); + + if (new_f_ei.IsEmpty()) { + BSP_CSGException e(e_split_error); + throw(e); + } + + edge_set[new_f_ei].SwapFace(fi,new_fi); + prev = *f_verts_it; + + } + return new_fi; +} diff --git a/intern/bsp/intern/BSP_CSGMeshSplitter.h b/intern/bsp/intern/BSP_CSGMeshSplitter.h new file mode 100755 index 00000000000..8216082d007 --- /dev/null +++ b/intern/bsp/intern/BSP_CSGMeshSplitter.h @@ -0,0 +1,208 @@ +/** + * $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 ***** + */ + +#ifndef BSP_CSGMeshSplitter_h + +#define BSP_CSGMeshSplitter_h + +class BSP_MeshFragment; +class MT_Plane3; +class BSP_CSGMesh; + +#include "BSP_MeshPrimitives.h" +#include "../extern/CSG_BooleanOps.h" +#include "BSP_CSGISplitter.h" + + +/** + * This class contains splitting functions for a CSGMesh. + * The atomic operation of a bsp CSG algorithm is to split + * a mesh fragment (connected collection of polygons contained + * in a convex cell) by a plane. It is vital to leave the + * CSGMesh in a valid state after each such operation + * this class insures this (or tries it's best!). + */ + + +class BSP_CSGMeshSplitter : public BSP_CSGISplitter +{ +public : + + /// construction + + BSP_CSGMeshSplitter( + CSG_InterpolateUserFaceVertexDataFunc fv_split_func + ); + + BSP_CSGMeshSplitter( + const BSP_CSGMeshSplitter & other + ); + + /** + * @section BSP specific mesh operations. + * Inherited from BSP_CSGISplitter + */ + + /** + * Split a mesh fragment wrt plane. Generates 3 mesh fragments, + * in, out and on. Makes sure the mesh is coherent after the + * operation. The contents of frag are consumed by this oepration. + */ + + void + Split( + const MT_Plane3& plane, + BSP_MeshFragment *frag, + BSP_MeshFragment *in_frag, + BSP_MeshFragment *out_frag, + BSP_MeshFragment *on_frag, + BSP_MeshFragment *spanning_frag + ); + + /// Split the entire mesh with respect to the plane. + + void + Split( + BSP_CSGMesh & mesh, + const MT_Plane3& plane, + BSP_MeshFragment *in_frag, + BSP_MeshFragment *out_frag, + BSP_MeshFragment *on_frag, + BSP_MeshFragment *spanning_frag + ); + + ~BSP_CSGMeshSplitter( + ); + +private : + + void + SplitImp( + BSP_CSGMesh & mesh, + const MT_Plane3& plane, + const std::vector<BSP_FaceInd> & spanning_faces, + BSP_MeshFragment *in_frag, + BSP_MeshFragment *out_frag, + BSP_MeshFragment *on_frag, + std::vector<BSP_VertexInd> & classified_verts + ); + + + /** + * @section Atomic mesh operations. + */ + + /** + * Add a vertex to the mesh, along + * a given edge. Leaves the mesh in a valid state. + * The vertex gets copied onto the back of the + * current vertex array. It's upto you to insure + * that the vertex actually lies on the edge and leaves + * the neighbouring faces convex. Returns the vertex index + * of the new vertex. + * + * epsilon is the relative distance [0,1] of the new + * vertex from the first vertex of the edge. This is + * used to intepolate face properties. + */ + + BSP_VertexInd + SplitEdge( + BSP_CSGMesh & mesh, + BSP_EdgeInd ei, + BSP_MVertex &vertex, + MT_Scalar epsilon + ); + + /** + * Split a polygon along an edge connecting the + * two tagged (on) vertices of the polygon. It assumes + * that you have already introduced two new vertex indices + * into the polygon that point to vertices tagged with + * {in,out,on} information. It creates a new edge from the + * 2 on vertices that must be present. It then splits up + * the polygon into 2 fragments on the inside and outside. + * It returns 2 indices into the face list. 1 for the inside + * polygon and 1 for the outside polygon. + */ + + void + SplitPolygon( + BSP_CSGMesh & mesh, + BSP_FaceInd fi, + BSP_FaceInd &fin, + BSP_FaceInd &fout + ); + + /** + * Triangulate a convex quad (the maximum size polygon + * resulting from splitting a triangle). This can create up + * to one new face - which is added to the mesh. Note + * that this method does not preserve references. It uses + * the edge which divides the quad into roughly equal triangular + * areas as the splitting edge. - This should avoid creating + * degenerate triangles. + */ + + BSP_FaceInd + TriangulateConvexQuad( + BSP_CSGMesh & mesh, + const BSP_FaceInd fi + ); + +private : + + // The function pointer used to split face vertex properties. + + CSG_InterpolateUserFaceVertexDataFunc m_fv_func; + + /// Cached helpers + + /// Split function responsibe for: + std::vector<BSP_FaceInd> m_spanning_faces; + std::vector<BSP_VertexInd> m_tagged_verts; + + /// SplitImp responsible for: + std::vector<BSP_EdgeInd> m_spanning_edges; + // The list of faces affected by splitting the spanning edge set. + std::vector<BSP_EdgeInd> m_visited_edges; + std::vector<BSP_VertexInd> m_visited_verts; + + /// SplitPolygon responsible for: + std::vector<BSP_FaceInd> m_in_loop,m_out_loop,m_on_loop; + std::vector<BSP_UserFVInd> m_fv_in_loop,m_fv_out_loop; + +}; + +#endif + + + diff --git a/intern/bsp/intern/BSP_CSGMesh_CFIterator.h b/intern/bsp/intern/BSP_CSGMesh_CFIterator.h new file mode 100755 index 00000000000..5d4e28e4647 --- /dev/null +++ b/intern/bsp/intern/BSP_CSGMesh_CFIterator.h @@ -0,0 +1,272 @@ +/** + * $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 ***** + */ + +#ifndef BSP_CSGMesh_CFIterator_h + +#define BSP_CSGMesh_CFIterator_h + +#include "BSP_CSGMesh.h" +#include "../extern/CSG_BooleanOps.h" +/** + * This class defines 2 C style iterators over a CSG mesh, one for + * vertices and 1 for faces. They conform to the iterator interface + * defined in CSG_BooleanOps.h + */ + +struct BSP_CSGMesh_VertexIt { + MEM_RefCountPtr<BSP_CSGMesh> mesh; + BSP_MVertex * pos; +}; + + +static + void +BSP_CSGMesh_VertexIt_Destruct( + CSG_VertexIteratorDescriptor * iterator +) { + delete ((BSP_CSGMesh_VertexIt *)(iterator->it)); + iterator->it = NULL; + iterator->Done = NULL; + iterator->Fill = NULL; + iterator->Reset = NULL; + iterator->Step = NULL; + iterator->num_elements = 0; +}; + + +static + int +BSP_CSGMesh_VertexIt_Done( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + BSP_CSGMesh_VertexIt * vertex_it = (BSP_CSGMesh_VertexIt *)it; + + if (vertex_it->pos < vertex_it->mesh->VertexSet().end()) return 0; + return 1; +}; + +static + void +BSP_CSGMesh_VertexIt_Fill( + CSG_IteratorPtr it, + CSG_IVertex *vert +) { + // assume CSG_IteratorPtr is of the correct type. + BSP_CSGMesh_VertexIt * vertex_it = (BSP_CSGMesh_VertexIt *)it; + + vertex_it->pos->m_pos.getValue(vert->position); +}; + +static + void +BSP_CSGMesh_VertexIt_Step( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + BSP_CSGMesh_VertexIt * vertex_it = (BSP_CSGMesh_VertexIt *)it; + + ++(vertex_it->pos); +}; + +static + void +BSP_CSGMesh_VertexIt_Reset( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + BSP_CSGMesh_VertexIt * vertex_it = (BSP_CSGMesh_VertexIt *)it; + vertex_it->pos = vertex_it->mesh->VertexSet().begin(); +}; + +static + void +BSP_CSGMeshVertexIt_Construct( + BSP_CSGMesh *mesh, + CSG_VertexIteratorDescriptor *output +){ + // user should have insured mesh is not equal to NULL. + + output->Done = BSP_CSGMesh_VertexIt_Done; + output->Fill = BSP_CSGMesh_VertexIt_Fill; + output->Step = BSP_CSGMesh_VertexIt_Step; + output->Reset = BSP_CSGMesh_VertexIt_Reset; + output->num_elements = mesh->VertexSet().size(); + + BSP_CSGMesh_VertexIt * v_it = new BSP_CSGMesh_VertexIt; + v_it->mesh = mesh; + v_it->pos = mesh->VertexSet().begin(); + output->it = v_it; +}; + + +/** + * Face iterator. + */ + +struct BSP_CSGMesh_FaceIt { + MEM_RefCountPtr<BSP_CSGMesh> mesh; + BSP_MFace *pos; + int face_triangle; +}; + + +static + void +BSP_CSGMesh_FaceIt_Destruct( + CSG_FaceIteratorDescriptor *iterator +) { + delete ((BSP_CSGMesh_FaceIt *)(iterator->it)); + iterator->it = NULL; + iterator->Done = NULL; + iterator->Fill = NULL; + iterator->Reset = NULL; + iterator->Step = NULL; + iterator->num_elements = 0; +}; + + +static + int +BSP_CSGMesh_FaceIt_Done( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + BSP_CSGMesh_FaceIt * face_it = (BSP_CSGMesh_FaceIt *)it; + + if (face_it->pos < face_it->mesh->FaceSet().end()) { + if (face_it->face_triangle + 3 <= face_it->pos->m_verts.size()) { + return 0; + } + } + return 1; +}; + +static + void +BSP_CSGMesh_FaceIt_Fill( + CSG_IteratorPtr it, + CSG_IFace *face +){ + // assume CSG_IteratorPtr is of the correct type. + BSP_CSGMesh_FaceIt * face_it = (BSP_CSGMesh_FaceIt *)it; + // essentially iterating through a triangle fan here. + const int tri_index = face_it->face_triangle; + + face->vertex_index[0] = int(face_it->pos->m_verts[0]); + face->vertex_index[1] = int(face_it->pos->m_verts[tri_index + 1]); + face->vertex_index[2] = int(face_it->pos->m_verts[tri_index + 2]); + + // Copy the user face data across - this does nothing + // if there was no mesh user data. + + // time to change the iterator type to an integer... + face_it->mesh->FaceData().Copy( + face->user_face_data, + int(face_it->pos - face_it->mesh->FaceSet().begin()) + ); + + // Copy face vertex data across... + + face_it->mesh->FaceVertexData().Copy( + face->user_face_vertex_data[0], + face_it->pos->m_fv_data[0] + ); + + face_it->mesh->FaceVertexData().Copy( + face->user_face_vertex_data[1], + face_it->pos->m_fv_data[tri_index + 1] + ); + + face_it->mesh->FaceVertexData().Copy( + face->user_face_vertex_data[2], + face_it->pos->m_fv_data[tri_index + 2] + ); + + face->vertex_number = 3; +}; + +static + void +BSP_CSGMesh_FaceIt_Step( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + BSP_CSGMesh_FaceIt * face_it = (BSP_CSGMesh_FaceIt *)it; + + // safety guard + if (face_it->pos < face_it->mesh->FaceSet().end()) { + + if (face_it->face_triangle + 3 < face_it->pos->m_verts.size()) { + (face_it->face_triangle)++; + } else { + face_it->face_triangle = 0; + (face_it->pos) ++; + } + } +}; + +static + void +BSP_CSGMesh_FaceIt_Reset( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + BSP_CSGMesh_FaceIt * f_it = (BSP_CSGMesh_FaceIt *)it; + f_it->pos = f_it->mesh->FaceSet().begin(); + f_it->face_triangle = 0; +}; + +static + void +BSP_CSGMesh_FaceIt_Construct( + BSP_CSGMesh * mesh, + CSG_FaceIteratorDescriptor *output +) { + + output->Done = BSP_CSGMesh_FaceIt_Done; + output->Fill = BSP_CSGMesh_FaceIt_Fill; + output->Step = BSP_CSGMesh_FaceIt_Step; + output->Reset = BSP_CSGMesh_FaceIt_Reset; + + output->num_elements = mesh->CountTriangles(); + + BSP_CSGMesh_FaceIt * f_it = new BSP_CSGMesh_FaceIt; + f_it->mesh = mesh; + f_it->pos = mesh->FaceSet().begin(); + f_it->face_triangle = 0; + + output->it = f_it; + +}; + + +#endif
\ No newline at end of file diff --git a/intern/bsp/intern/BSP_CSGNCMeshSplitter.cpp b/intern/bsp/intern/BSP_CSGNCMeshSplitter.cpp new file mode 100755 index 00000000000..4ffe5c73e47 --- /dev/null +++ b/intern/bsp/intern/BSP_CSGNCMeshSplitter.cpp @@ -0,0 +1,241 @@ +/** + * $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 ***** + */ + +#include "BSP_CSGNCMeshSplitter.h" + +#include "BSP_CSGMesh.h" +#include "BSP_MeshFragment.h" +#include "BSP_CSGException.h" +#include "MT_MinMax.h" +#include "MT_assert.h" +#include <vector> + +using namespace std; + +BSP_CSGNCMeshSplitter:: +BSP_CSGNCMeshSplitter( +){ + //nothing to do +} + +BSP_CSGNCMeshSplitter:: +BSP_CSGNCMeshSplitter( + const BSP_CSGNCMeshSplitter & other +){ + //nothing to do +}; + + + void +BSP_CSGNCMeshSplitter:: +Split( + const MT_Plane3& plane, + BSP_MeshFragment *frag, + BSP_MeshFragment *in_frag, + BSP_MeshFragment *out_frag, + BSP_MeshFragment *on_frag, + BSP_MeshFragment *spanning_frag +){ + // First classify the vertices and the polygons of the + // incoming fragment. + frag->Classify(plane,in_frag,out_frag,on_frag,m_spanning_faces,m_tagged_verts); + + SplitImp(*(frag->Mesh()),plane,m_spanning_faces,in_frag,out_frag,on_frag,m_tagged_verts); + + m_spanning_faces.clear(); + m_tagged_verts.clear(); +} + +/// Split the entire mesh with respect to the plane. + + void +BSP_CSGNCMeshSplitter:: +Split( + BSP_CSGMesh & mesh, + const MT_Plane3& plane, + BSP_MeshFragment *in_frag, + BSP_MeshFragment *out_frag, + BSP_MeshFragment *on_frag, + BSP_MeshFragment *spanning_frag +){ + BSP_MeshFragment::Classify(mesh, plane,in_frag,out_frag,on_frag,m_spanning_faces,m_tagged_verts); + + SplitImp(mesh,plane,m_spanning_faces,in_frag,out_frag,on_frag,m_tagged_verts); + m_spanning_faces.clear(); + m_tagged_verts.clear(); +} + + +BSP_CSGNCMeshSplitter:: +~BSP_CSGNCMeshSplitter( +){ + //nothing to do +} + + void +BSP_CSGNCMeshSplitter:: +SplitImp( + BSP_CSGMesh & mesh, + const MT_Plane3& plane, + const std::vector<BSP_FaceInd> & spanning_faces, + BSP_MeshFragment *in_frag, + BSP_MeshFragment *out_frag, + BSP_MeshFragment *on_frag, + std::vector<BSP_VertexInd> & classified_verts +){ + + // Just iterate through the spanning faces. + // Identify the spanning 'edges' and create new vertices + // and split the polygons. We make no attempt to share + // vertices or preserve edge connectivity or maintain any + // face properties etc. + + // Assumes you have already classified the vertices. + // and generated a set of spanning faces. + + vector<BSP_MVertex> & vertex_set = mesh.VertexSet(); + vector<BSP_MFace> & face_set = mesh.FaceSet(); + + vector<BSP_FaceInd>::const_iterator sface_end = m_spanning_faces.end(); + vector<BSP_FaceInd>::const_iterator sface_it = m_spanning_faces.begin(); + + for (;sface_it != sface_end; ++sface_it) { + BSP_FaceInd f_in,f_out; + SplitPolygon(plane,mesh,*sface_it,f_in,f_out); + + // Use the open tag to store the original index of the face. + // This is originally -1. + + if (face_set[*sface_it].OpenTag() == -1) { + face_set[f_in].SetOpenTag(*sface_it); + face_set[f_out].SetOpenTag(*sface_it); + } else { + face_set[f_in].SetOpenTag(face_set[*sface_it].OpenTag()); + face_set[f_out].SetOpenTag(face_set[*sface_it].OpenTag()); + } + + in_frag->FaceSet().push_back(f_in); + out_frag->FaceSet().push_back(f_out); + } + + vector<BSP_VertexInd>::const_iterator v_end = classified_verts.end(); + vector<BSP_VertexInd>::const_iterator v_it = classified_verts.begin(); + + for (; v_it != v_end; ++v_it) { + vertex_set[*v_it].SetOpenTag(e_unclassified); + } +} + + void +BSP_CSGNCMeshSplitter:: +SplitPolygon( + const MT_Plane3& plane, + BSP_CSGMesh & mesh, + BSP_FaceInd fi, + BSP_FaceInd &fin, + BSP_FaceInd &fout +){ + + vector<BSP_MVertex> & vertex_set = mesh.VertexSet(); + vector<BSP_MFace> & face_set = mesh.FaceSet(); + + BSP_FaceInd new_fi = face_set.size(); + face_set.push_back(BSP_MFace()); + + BSP_MFace & face = face_set[fi]; + BSP_MFace &new_face = face_set[new_fi]; + + vector<BSP_VertexInd>::const_iterator f_verts_it = face.m_verts.begin(); + vector<BSP_VertexInd>::const_iterator f_verts_end = face.m_verts.end(); + + MT_Point3 ptA = vertex_set[face.m_verts.back()].m_pos; + BSP_Classification prev_class = BSP_Classification(vertex_set[face.m_verts.back()].OpenTag()); + + for (; f_verts_it != f_verts_end;++f_verts_it) { + + BSP_Classification v_class = BSP_Classification(vertex_set[*f_verts_it].OpenTag()); + + if (v_class == e_classified_on) { + m_in_loop.push_back(*f_verts_it); + m_out_loop.push_back(*f_verts_it); + prev_class = e_classified_on; + continue; + } else + if (v_class == e_classified_in) { + m_in_loop.push_back(*f_verts_it); + } else + if (v_class == e_classified_out) { + m_out_loop.push_back(*f_verts_it); + } + + if ((prev_class != e_classified_on) && + (prev_class != v_class)) { + // spanning edge + + const MT_Point3 & ptB = vertex_set[*f_verts_it].m_pos; + + // compute the intersection point of plane and ptA->ptB + MT_Vector3 v = ptB - ptA; + MT_Scalar sideA = plane.signedDistance(ptA); + + MT_Scalar epsilon = -sideA/plane.Normal().dot(v); + MT_Point3 new_p = ptA + (v * epsilon); + + BSP_VertexInd new_vi(vertex_set.size()); + vertex_set.push_back(BSP_MVertex(new_p)); + + m_in_loop.push_back(new_vi); + m_out_loop.push_back(new_vi); + } + + ptA = vertex_set[*f_verts_it].m_pos; + prev_class = v_class; + } + + // Ok should have 2 loops 1 representing the in_loop and + // 1 for the out_loop + + new_face.m_verts = m_out_loop; + face.m_verts = m_in_loop; + + new_face.m_plane = face.m_plane; + + // we don't bother maintaining any of the other + // properties. + + fin = fi; + fout = new_fi; + + m_in_loop.clear(); + m_out_loop.clear(); +}; + + diff --git a/intern/bsp/intern/BSP_CSGNCMeshSplitter.h b/intern/bsp/intern/BSP_CSGNCMeshSplitter.h new file mode 100755 index 00000000000..56c1258f5c4 --- /dev/null +++ b/intern/bsp/intern/BSP_CSGNCMeshSplitter.h @@ -0,0 +1,139 @@ +/** + * $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 ***** + */ + +#ifndef BSP_CSGNCMeshSplitter_h + +#define BSP_CSGNCMeshSplitter_h + +class BSP_MeshFragment; +class MT_Plane3; +class BSP_CSGMesh; + +#include "BSP_MeshPrimitives.h" +#include "../extern/CSG_BooleanOps.h" +#include "BSP_CSGISplitter.h" + + +/** + * This class contains splitting functions for a CSGMesh. + * The atomic operation of a bsp CSG algorithm is to split + * a mesh fragment (connected collection of polygons contained + * in a convex cell) by a plane. This class makes no attempt + * to maintain edge connectivity in the mesh. It just rips + * up the polygons. This is fine for tree building. + */ + + +class BSP_CSGNCMeshSplitter : public BSP_CSGISplitter +{ +public : + + /// construction + + BSP_CSGNCMeshSplitter( + ); + + BSP_CSGNCMeshSplitter( + const BSP_CSGNCMeshSplitter & other + ); + + /** + * @section BSP specific mesh operations. + * Inherited from BSP_CSGISplitter + */ + + /** + * Split a mesh fragment wrt plane. Generates 3 mesh fragments, + * in, out and on. Only splits polygons - not edges, does not maintain + * connectivity information. The contents of frag are consumed by this oepration. + */ + void + Split( + const MT_Plane3& plane, + BSP_MeshFragment *frag, + BSP_MeshFragment *in_frag, + BSP_MeshFragment *out_frag, + BSP_MeshFragment *on_frag, + BSP_MeshFragment *spanning_frag + ); + + /// Split the entire mesh with respect to the plane. + + void + Split( + BSP_CSGMesh & mesh, + const MT_Plane3& plane, + BSP_MeshFragment *in_frag, + BSP_MeshFragment *out_frag, + BSP_MeshFragment *on_frag, + BSP_MeshFragment *spanning_frag + ); + + ~BSP_CSGNCMeshSplitter( + ); + +private : + + void + SplitImp( + BSP_CSGMesh & mesh, + const MT_Plane3& plane, + const std::vector<BSP_FaceInd> & spanning_faces, + BSP_MeshFragment *in_frag, + BSP_MeshFragment *out_frag, + BSP_MeshFragment *on_frag, + std::vector<BSP_VertexInd> & classified_verts + + ); + + void + SplitPolygon( + const MT_Plane3 &plane, + BSP_CSGMesh & mesh, + BSP_FaceInd fi, + BSP_FaceInd &fin, + BSP_FaceInd &fout + ); + + /// Cached helpers + + /// Split function responsibe for: + std::vector<BSP_FaceInd> m_spanning_faces; + std::vector<BSP_VertexInd> m_tagged_verts; + + /// SplitPolygon responsible for: + std::vector<BSP_FaceInd> m_in_loop,m_out_loop,m_on_loop; + +}; + + +#endif + diff --git a/intern/bsp/intern/BSP_CSGUserData.cpp b/intern/bsp/intern/BSP_CSGUserData.cpp new file mode 100755 index 00000000000..a630c9fc25d --- /dev/null +++ b/intern/bsp/intern/BSP_CSGUserData.cpp @@ -0,0 +1,133 @@ +/** + * $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 ***** + */ + +#include "BSP_CSGUserData.h" + + + +BSP_CSGUserData:: +BSP_CSGUserData( + const int width +): + m_width (width) +{ +} + +/** + * Add a new uninitialized record to the end of the + * array + */ + + void +BSP_CSGUserData:: +IncSize( +){ + m_data.insert(m_data.end(),m_width,char(0)); +} + + int +BSP_CSGUserData:: +Duplicate( + void *record +){ + if (m_width) { + int output = Size(); + IncSize(); + + memcpy(m_data.end() - m_width,record,m_width); + + return output; + } + return 0; +} + + void +BSP_CSGUserData:: +Duplicate( + int record_index +){ + if (m_width) { + int output = Size(); + IncSize(); + memcpy(m_data.end() - m_width,m_data.begin() + record_index * m_width,m_width); + } +} + + + void +BSP_CSGUserData:: +Copy( + void *output, + int pos +){ + if (m_width) { + memcpy(output,m_data.begin() + m_width*pos,m_width); + } +} + void +BSP_CSGUserData:: +Reserve( + int size +){ + m_data.reserve(size * m_width); +} + + +/// Return the width of an individual record + + int +BSP_CSGUserData:: +Width( +) const{ + return m_width; +} + + +/// return the current number of records stored in the array. + int +BSP_CSGUserData:: +Size( +) const { + if (m_width == 0) return 0; + return m_data.size() / m_width; +} + + +/// return a pointer to the start of the nth record in the array. + + void * +BSP_CSGUserData:: +operator [] ( + const int pos +){ + return m_data.begin() + m_width*pos; +} + diff --git a/intern/bsp/intern/BSP_CSGUserData.h b/intern/bsp/intern/BSP_CSGUserData.h new file mode 100755 index 00000000000..86d86cdd0b1 --- /dev/null +++ b/intern/bsp/intern/BSP_CSGUserData.h @@ -0,0 +1,136 @@ +/** + * $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 ***** + */ + +#ifndef BSP_CSGUserData_h + +#define BSP_CSGUserData_h + +#include <vector> + +/** + * This data represents a continuous block of + * data of unknown type. This holds the user + * data during a BSP operation. + */ + +class BSP_CSGUserData +{ +public : + + /** + * width defines the size in bytes of a + * single element (record) of user data + */ + + BSP_CSGUserData( + const int width + ); + + /** + * Reserve some space in the array + */ + void + Reserve( + int size + ); + + /** + * Add a new uninitialized record to the end of the + * array + */ + + void + IncSize( + ); + + /** + * duplicate a recod and insert it into the end of the array + * returns the index of the new record. Make sure that the + * record does not belong to this buffer as this can cause errors. + */ + + int + Duplicate( + void * + ); + + void + Duplicate( + int record_index + ); + + /** + * Copies the record at position pos in the array to the + * memory pointed to by output + */ + + void + Copy( + void *output, + int pos + ); + + /// Return the width of an individual record + + int + Width( + ) const; + + + /// return the current number of records stored in the array. + int + Size( + ) const; + + + /// return a pointer to the start of the nth record in the array. + + void * + operator [] ( + const int pos + ); + +private : + + /// Private - force use of public constructor only. + + BSP_CSGUserData( + ); + + + /// The block of data. + std::vector<char> m_data; + /// The width of a record in this array. + int m_width; +}; + + +#endif diff --git a/intern/bsp/intern/BSP_FragNode.cpp b/intern/bsp/intern/BSP_FragNode.cpp new file mode 100755 index 00000000000..e23fdd835c7 --- /dev/null +++ b/intern/bsp/intern/BSP_FragNode.cpp @@ -0,0 +1,313 @@ +/** + * $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 ***** + */ + +#include "BSP_CSGMesh.h" + +#include "BSP_FragNode.h" +#include "BSP_CSGISplitter.h" + + +BSP_FragNode:: +BSP_FragNode( + const MT_Plane3 & plane, + BSP_CSGMesh *mesh +): + m_plane(plane), + m_in_tree(mesh), + m_out_tree(mesh) +{ +} + +/** + * Public methods + * Should only be called by BSP_FragTree + */ + +BSP_FragNode:: +~BSP_FragNode( +){ + // nothing to do +} + + MEM_SmartPtr<BSP_FragNode> +BSP_FragNode:: +New( + const MT_Plane3 & plane, + BSP_CSGMesh *mesh +){ + return new BSP_FragNode(plane,mesh); +} + + + void +BSP_FragNode:: +Build( + BSP_MeshFragment *frag, + BSP_CSGISplitter & splitter +){ + // we know there must be some polygons still in + // the fragment otherwise this node would not hve been + // constructed. + + BSP_CSGMesh *mesh = frag->Mesh(); + + // split the incoming fragment by the plane + // generating in,out,on fragments which are + // passed down the in and out trees. + + BSP_MeshFragment in_frag(mesh,e_classified_in),out_frag(mesh,e_classified_out); + MEM_SmartPtr<BSP_MeshFragment> on_frag = new BSP_MeshFragment(mesh,e_classified_on); + splitter.Split(m_plane,frag,&in_frag,&out_frag,on_frag,NULL); + + // We are not interested in the on fragments. + on_frag.Delete(); + + m_in_tree.Build(&in_frag,splitter); + m_out_tree.Build(&out_frag,splitter); +} + + void +BSP_FragNode:: +Push( + BSP_MeshFragment *in_frag, + BSP_MeshFragment *output, + const BSP_Classification keep, + const bool dominant, + BSP_CSGISplitter & splitter +){ + BSP_CSGMesh *mesh = in_frag->Mesh(); + + + MEM_SmartPtr<BSP_MeshFragment> inside_frag = new BSP_MeshFragment(mesh,e_classified_in); + MEM_SmartPtr<BSP_MeshFragment> outside_frag = new BSP_MeshFragment(mesh,e_classified_out); + MEM_SmartPtr<BSP_MeshFragment> on_frag = new BSP_MeshFragment(mesh,e_classified_on); + + // deal with memory exceptions here. + + splitter.Split(m_plane,in_frag,inside_frag,outside_frag,on_frag,NULL); + + // deal with the on_fragments. + + if (on_frag->FaceSet().size()) { + + // The on fragment contains polygons that are outside both subtrees and polygons + // that are inside one or more sub trees. If we are taking the union then we can + // immediately add that first set of polygons to the ouput. We must then decide what + // to do with potenially overlapping polygons from both objects. If we assume both + // objects are closed then we can identify the conflict zones as + // polygons outside B- and inside B+ + // polygons outside B+ and inside B- + + // In these conflict zones we must choose a dominant object this is indicated + // by the bool parameter to this function. If the object is not dominant then + // we do nothing inside these conflict zones. + // The first set should correspond with on polygons from object B with the same + // orientation as this node. The second corresponding with polygons with opposite + // orientation. + // We don't want to replace polygons from A with polygons of opposite orientation + // from B. So we split up the on polygons of A into 2 sets according to their orientation. + // We add to output (A- out B-) in B+ and (A+ out B+) in B- + + +#if 1 + + if (keep == e_classified_out) { + // we are doing a union operation. + // Make sure that this is not a leaf node. + if(m_in_tree.m_node != NULL || m_out_tree.m_node != NULL) { + BSP_MeshFragment frag_outBneg_outBpos(mesh,e_classified_on); + BSP_MeshFragment temp1(on_frag.Ref()); + m_in_tree.Push( + &temp1,&frag_outBneg_outBpos, + e_classified_out,e_classified_on, + false,splitter + ); + + m_out_tree.Push( + &frag_outBneg_outBpos,output,e_classified_out,e_classified_on, + false,splitter + ); + } +#if 1 + if (dominant) { + + // Here we compute the intersection zones. + BSP_MeshFragment frag_on_pos(mesh,e_classified_on),frag_on_neg(mesh,e_classified_on); + on_frag->ClassifyOnFragments(m_plane,&frag_on_pos,&frag_on_neg); + + BSP_MeshFragment temp1(mesh,e_classified_in); + + // push -ve fragments down inside tree, push result down outside + m_in_tree.Push(&frag_on_neg,&temp1,e_classified_out,e_classified_on,false,splitter); + m_out_tree.Push(&temp1,output,e_classified_in,e_classified_on,false,splitter); + temp1.FaceSet().clear(); + + // push +ve fragments down outside tree, push result down inside. + m_out_tree.Push(&frag_on_pos,&temp1,e_classified_out,e_classified_on,false,splitter); + m_in_tree.Push(&temp1,output,e_classified_in,e_classified_on,false,splitter); + } +#endif + } else if (keep == e_classified_in) { + + // we are doing an intersection + + // A = on_frag in X+ out X- + // B = on_frag in X- out X+ + // C = on_frag in X- in X+ + + // If X+ is NULL then A = F out X-, B = 0, C = F in X- + // If X- is NULLL then A = 0, B = F out X+ , C = F in X+ + // If both NULL then A = C = 0, B = F + + // Conflicts only happen in A and B. + // negative fragments only in A, positive fragments only in B, anything in C. + // First compute F in C an add to ouput. + + BSP_MeshFragment frag_on_pos(mesh,e_classified_on),frag_on_neg(mesh,e_classified_on); + on_frag->ClassifyOnFragments(m_plane,&frag_on_pos,&frag_on_neg); + + if (m_in_tree.m_node == NULL) { + if (m_out_tree.m_node == NULL) { + // pick stuff that points in the same direction as this node + // only if priority. + if (dominant) { + // pass +ve frags into B = F. + // trick just pass down in tree... just adds to output. + m_in_tree.Push(&frag_on_pos,output,e_classified_in,e_classified_on,false,splitter); + } + } else { + // A = 0, B= F out X+ , C = F in X+ + if (dominant) { + // m_out_tree.Push(&frag_on_pos,output,e_classified_out,e_classified_on,false,splitter); + m_out_tree.Push(on_frag,output,e_classified_in,e_classified_on,false,splitter); + } + } + } else { + if (m_out_tree.m_node == NULL) { + // A = F out X-, B=0, C = F in X- + if (dominant) { + // m_in_tree.Push(&frag_on_neg,output,e_classified_out,e_classified_on,false,splitter); + m_in_tree.Push(on_frag,output,e_classified_in,e_classified_on,false,splitter); + } + } else { + // The normals case + if (dominant) { + BSP_MeshFragment temp1(mesh,e_classified_on); + m_out_tree.Push(&frag_on_neg,&temp1,e_classified_in,e_classified_on,false,splitter); + m_in_tree.Push(&temp1,output,e_classified_out,e_classified_on,false,splitter); + temp1.FaceSet().clear(); + + m_in_tree.Push(&frag_on_pos,&temp1,e_classified_in,e_classified_on,false,splitter); + m_out_tree.Push(&temp1,output,e_classified_out,e_classified_on,false,splitter); + } + BSP_MeshFragment temp1(mesh,e_classified_on); + m_in_tree.Push(on_frag,&temp1,e_classified_in,e_classified_on,false,splitter); + m_out_tree.Push(&temp1,output,e_classified_in,e_classified_on,false,splitter); + } + } + } + + +#endif + on_frag.Delete(); + } + + m_in_tree.Push(inside_frag,output,keep,e_classified_in,dominant,splitter); + m_out_tree.Push(outside_frag,output,keep,e_classified_out,dominant,splitter); +}; + + void +BSP_FragNode:: +Classify( + BSP_MeshFragment * frag, + BSP_MeshFragment *in_frag, + BSP_MeshFragment *out_frag, + BSP_MeshFragment *on_frag, + BSP_CSGISplitter & splitter +){ + + BSP_CSGMesh *mesh = frag->Mesh(); + + MEM_SmartPtr<BSP_MeshFragment> inside_frag = new BSP_MeshFragment(mesh,e_classified_in); + MEM_SmartPtr<BSP_MeshFragment> outside_frag = new BSP_MeshFragment(mesh,e_classified_out); + MEM_SmartPtr<BSP_MeshFragment> frag_on = new BSP_MeshFragment(mesh,e_classified_on); + + splitter.Split(m_plane,frag,inside_frag,outside_frag,frag_on,NULL); + + // copy the on fragments into the on_frag output. + + if (frag_on->FaceSet().size()) { + + on_frag->FaceSet().insert( + on_frag->FaceSet().end(), + frag_on->FaceSet().begin(), + frag_on->FaceSet().end() + ); + } + + frag_on.Delete(); + + // pass everything else down the tree. + + m_in_tree.Classify(inside_frag,in_frag,out_frag,on_frag,e_classified_in,splitter); + m_out_tree.Classify(outside_frag,in_frag,out_frag,on_frag,e_classified_out,splitter); +} + + +/** + * Accessor methods + */ + + BSP_FragTree & +BSP_FragNode:: +InTree( +){ + return m_in_tree; +} + + BSP_FragTree & +BSP_FragNode:: +OutTree( +){ + return m_out_tree; +} + + MT_Plane3& +BSP_FragNode:: +Plane( +){ + return m_plane; +} + + + + + diff --git a/intern/bsp/intern/BSP_FragNode.h b/intern/bsp/intern/BSP_FragNode.h new file mode 100755 index 00000000000..f289419950b --- /dev/null +++ b/intern/bsp/intern/BSP_FragNode.h @@ -0,0 +1,127 @@ +/** + * $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 ***** + */ + +#ifndef BSP_FragNode_h + +#define BSP_FragNode_h + +#include "BSP_FragTree.h" +#include "BSP_MeshFragment.h" +#include "MT_Plane3.h" + +class BSP_CSGISplitter; + +class BSP_FragNode : public MEM_NonCopyable +{ +private: + + /** + * The plane defining this node. + */ + + MT_Plane3 m_plane; + + /** + * Children of this node. + */ + + BSP_FragTree m_in_tree; + BSP_FragTree m_out_tree; + +private : + + BSP_FragNode( + const MT_Plane3 & plane, + BSP_CSGMesh *mesh + ); + +public : + + /** + * Public methods + * Should only be called by BSP_FragTree + */ + + ~BSP_FragNode( + ); + + static + MEM_SmartPtr<BSP_FragNode> + New( + const MT_Plane3 & plane, + BSP_CSGMesh *mesh + ); + + void + Build( + BSP_MeshFragment *frag, + BSP_CSGISplitter & splitter + ); + + void + Push( + BSP_MeshFragment *in_frag, + BSP_MeshFragment *output, + const BSP_Classification keep, + const bool dominant, + BSP_CSGISplitter & splitter + ); + + void + Classify( + BSP_MeshFragment * frag, + BSP_MeshFragment *in_frag, + BSP_MeshFragment *out_frag, + BSP_MeshFragment *on_frag, + BSP_CSGISplitter & splitter + ); + + /** + * Accessor methods + */ + + BSP_FragTree & + InTree( + ); + + BSP_FragTree & + OutTree( + ); + + MT_Plane3& + Plane( + ); + +}; + + + +#endif
\ No newline at end of file diff --git a/intern/bsp/intern/BSP_FragTree.cpp b/intern/bsp/intern/BSP_FragTree.cpp new file mode 100755 index 00000000000..3668db6cf7c --- /dev/null +++ b/intern/bsp/intern/BSP_FragTree.cpp @@ -0,0 +1,319 @@ +/** + * $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 ***** + */ + +#include "BSP_FragTree.h" + +#include "BSP_FragNode.h" +#include "BSP_CSGMesh.h" +#include "BSP_MeshFragment.h" +#include "MT_Plane3.h" +#include "BSP_CSGException.h" +#include <vector> +#include "BSP_CSGISplitter.h" + +using namespace std; + + MEM_SmartPtr<BSP_FragTree> +BSP_FragTree:: +New( + BSP_CSGMesh *mesh, + BSP_CSGISplitter & splitter +){ + if (mesh == NULL) return NULL; + if (mesh->FaceSet().size() == 0) return NULL; + + // This is the external tree construction method + // (not the internal method!) + // We need to build a tree root with an initial + // node based on the mesh rather than a mesh fragment. + + // For now we pick an arbitrary polygon for the initial + // plane. + + vector<BSP_MVertex> verts = mesh->VertexSet(); + const BSP_MFace & f0 = mesh->FaceSet()[0]; + + const MT_Vector3 & p1 = verts[f0.m_verts[0]].m_pos; + const MT_Vector3 & p2 = verts[f0.m_verts[1]].m_pos; + const MT_Vector3 & p3 = verts[f0.m_verts[2]].m_pos; + + MT_Plane3 plane = f0.m_plane; + + MEM_SmartPtr<BSP_FragTree> output(new BSP_FragTree(mesh)); + MEM_SmartPtr<BSP_FragNode> node(BSP_FragNode::New(plane,mesh)); + + if (output == NULL || node == NULL) return NULL; + + // Generate initial mesh fragments for this plane pass into + // first node. + + BSP_MeshFragment frag_in(mesh,e_classified_in),frag_out(mesh,e_classified_out); + + MEM_SmartPtr<BSP_MeshFragment> on_frag = new BSP_MeshFragment(mesh,e_classified_on); + + splitter.Split(*mesh,plane,&frag_in,&frag_out,on_frag,NULL); + + // We are not interested in the on_frag. + on_frag.Delete(); + + // Build the in_tree of the first node(recursive) + node->InTree().Build(&frag_in,splitter); + + // Build the out tree of the first node(recursive) + node->OutTree().Build(&frag_out,splitter); + + output->m_node = node; + + return output; +} + + void +BSP_FragTree:: +Classify( + BSP_CSGMesh *mesh, + BSP_MeshFragment *in_frag, + BSP_MeshFragment *out_frag, + BSP_MeshFragment *on_frag, + BSP_CSGISplitter & splitter +){ + + if (mesh == NULL) return; + if (mesh->FaceSet().size() == 0) return; + if (m_node == NULL) return; + + BSP_MeshFragment frag_in(mesh,e_classified_in); + BSP_MeshFragment frag_out(mesh,e_classified_out); + BSP_MeshFragment frag_on(mesh,e_classified_on); + BSP_MeshFragment frag_spanning(mesh,e_classified_spanning); + + splitter.Split(*mesh,m_node->Plane(),&frag_in,&frag_out,&frag_on,NULL); + + if (frag_on.FaceSet().size()) { + + on_frag->FaceSet().insert( + on_frag->FaceSet().end(), + frag_on.FaceSet().begin(), + frag_on.FaceSet().end() + ); + + frag_on.FaceSet().clear(); + } + + // recurse into subtrees. + m_node->InTree().Classify(&frag_in,in_frag,out_frag,on_frag,e_classified_in,splitter); + m_node->OutTree().Classify(&frag_out,in_frag,out_frag,on_frag,e_classified_out,splitter); + +} + + + + + +BSP_FragTree:: +~BSP_FragTree( +){ + // nothing to do +} + +BSP_FragTree:: +BSP_FragTree( + BSP_CSGMesh * mesh +): + m_mesh(mesh) +{ + //nothing to do +} + +BSP_FragTree:: +BSP_FragTree( +){ + // nothing to do +} + + void +BSP_FragTree:: +Build( + BSP_MeshFragment * frag, + BSP_CSGISplitter & splitter +){ + + // Node must be NULL because we are building the tree. + + MT_assert(m_node == NULL); + + if (frag->FaceSet().size()) { + + // choose a plane for the node. The first index in this + // mesh fragment will do for now. + vector<BSP_MVertex> & verts = m_mesh->VertexSet(); + + // choose a random splitting plane + + MT_Plane3 plane; + { + int rand_index; +#if 1 + if (frag->FaceSet().size() > 1) { + rand_index = rand() % frag->FaceSet().size(); + } else { + rand_index = 0; + } +#else + rand_index = 0; +#endif + + const BSP_MFace & f0 = m_mesh->FaceSet()[frag->FaceSet()[rand_index]]; + plane = f0.m_plane; + } + + // build the node. + m_node = BSP_FragNode::New(plane,frag->Mesh()); + + if (m_node == NULL) { + BSP_CSGException e(e_tree_build_error); + throw(e); + } + + m_node->Build(frag,splitter); + } +} + + + void +BSP_FragTree:: +Push( + BSP_MeshFragment *in_frag, + BSP_MeshFragment *output, + const BSP_Classification keep, + const BSP_Classification current, + const bool dominant, + BSP_CSGISplitter & splitter +){ + + if (in_frag->FaceSet().size()) { + + if (m_node == NULL) { + + // we have reached a leaf node. + // if the current classification matches + // the classification we want to keep + // copy the polygons of the current + // fragment onto the output + vector<BSP_FaceInd>::const_iterator in_frag_it = in_frag->FaceSet().begin(); + vector<BSP_FaceInd>::const_iterator in_frag_end = in_frag->FaceSet().end(); + vector<BSP_MFace>::iterator faces = in_frag->Mesh()->FaceSet().begin(); + + if (keep == current || current == e_classified_on) { + for (;in_frag_it != in_frag_end; ++ in_frag_it) { + output->FaceSet().push_back(*in_frag_it); + } + + in_frag->FaceSet().clear(); + } + } else { + + m_node->Push(in_frag,output,keep,dominant,splitter); + } + } +} + + + void +BSP_FragTree:: +Classify( + BSP_MeshFragment * frag, + BSP_MeshFragment *in_frag, + BSP_MeshFragment *out_frag, + BSP_MeshFragment *on_frag, + const BSP_Classification current, + BSP_CSGISplitter & splitter +){ + + if (frag->FaceSet().size()) { + + if (m_node == NULL) { + + vector<BSP_FaceInd>::const_iterator frag_it = frag->FaceSet().begin(); + vector<BSP_FaceInd>::const_iterator frag_end = frag->FaceSet().end(); + + BSP_MeshFragment *output; + if (current == e_classified_in) { + output = in_frag; + } else { + //must be e_classified_out + output = out_frag; + } + // Copy the selected indices into the correct output fragment. + + for (;frag_it != frag_end; ++ frag_it) { + output->FaceSet().push_back(*frag_it); + } + + frag->FaceSet().clear(); + } else { + + m_node->Classify(frag,in_frag,out_frag,on_frag,splitter); + } + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/bsp/intern/BSP_FragTree.h b/intern/bsp/intern/BSP_FragTree.h new file mode 100755 index 00000000000..7965a055c92 --- /dev/null +++ b/intern/bsp/intern/BSP_FragTree.h @@ -0,0 +1,146 @@ +/** + * $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 ***** + */ + +#ifndef BSP_FragTree_h + +#define BSP_FragTree_h + +class BSP_FragNode; + +#include "MEM_SmartPtr.h" +#include "MEM_NonCopyable.h" +#include "BSP_MeshPrimitives.h" + +class BSP_CSGMesh; +class BSP_MeshFragment; +class BSP_CSGISplitter; + +class BSP_FragTree : public MEM_NonCopyable +{ +public : + + /** + * Create a new BSP_FragTree allocated + * on the heap for mesh. Note mesh will + * be divided up by this operation. If you + * want to retain the original mesh make a copy + * of it first. + */ + + static + MEM_SmartPtr<BSP_FragTree> + New( + BSP_CSGMesh *mesh, + BSP_CSGISplitter & splitter + ); + + + /** + * Push a mesh fragment down the tree, + * splitting the mesh as it goes. + * upon reaching leaves it puts polygons from fragments + * of type keep into the output fragment. + */ + + void + Push( + BSP_MeshFragment *in_frag, + BSP_MeshFragment *output, + const BSP_Classification keep, + const BSP_Classification current, + const bool dominant, + BSP_CSGISplitter & splitter + ); + + void + Classify( + BSP_CSGMesh *mesh, + BSP_MeshFragment *in_frag, + BSP_MeshFragment *out_frag, + BSP_MeshFragment *on_frag, + BSP_CSGISplitter & splitter + ); + + + ~BSP_FragTree( + ); + +private : + + friend class BSP_FragNode; + + BSP_FragTree( + ); + + BSP_FragTree( + BSP_CSGMesh *mesh + ); + + void + Build( + BSP_MeshFragment * frag, + BSP_CSGISplitter & splitter + ); + + + void + Classify( + BSP_MeshFragment * frag, + BSP_MeshFragment *in_frag, + BSP_MeshFragment *out_frag, + BSP_MeshFragment *on_frag, + const BSP_Classification current, + BSP_CSGISplitter & splitter + ); + +private : + + /** + * pointer to the mesh for this tree. + * Tree is only valid whilst mesh is around. + */ + + BSP_CSGMesh *m_mesh; + + /** + * The node owned by this tree. + */ + + MEM_SmartPtr<BSP_FragNode> m_node; + +}; + + +#endif + + + + diff --git a/intern/bsp/intern/BSP_MeshFragment.cpp b/intern/bsp/intern/BSP_MeshFragment.cpp new file mode 100755 index 00000000000..408a13d6cd9 --- /dev/null +++ b/intern/bsp/intern/BSP_MeshFragment.cpp @@ -0,0 +1,279 @@ +/** + * $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 ***** + */ + +#include "BSP_MeshFragment.h" + +#include "BSP_CSGMesh.h" +#include "MT_Plane3.h" +#include <math.h> + +using namespace std; + + +BSP_MeshFragment:: +BSP_MeshFragment( + BSP_CSGMesh *mesh, + BSP_Classification classification +): + m_mesh(mesh), + m_classification(classification) +{ + MT_assert(m_mesh != NULL); + //nothing to do +} + +const + vector<BSP_FaceInd> & +BSP_MeshFragment:: +FaceSet( +) const { + return m_faces; +} + + vector<BSP_FaceInd> & +BSP_MeshFragment:: +FaceSet( +) { + return m_faces; +} + + BSP_CSGMesh * +BSP_MeshFragment:: +Mesh( +){ + return m_mesh; +} + + BSP_CSGMesh * +BSP_MeshFragment:: +Mesh( +) const { + return m_mesh; +} + + BSP_Classification +BSP_MeshFragment:: +ClassifyPolygon( + const MT_Plane3 &plane, + const BSP_MFace & face, + std::vector<BSP_MVertex>::const_iterator verts, + vector<BSP_VertexInd> & visited_verts +){ + + vector<BSP_VertexInd>::const_iterator f_vi_end = face.m_verts.end(); + vector<BSP_VertexInd>::const_iterator f_vi_it = face.m_verts.begin(); + + BSP_Classification p_class = e_unclassified; + + int on_count = 0; + + for (;f_vi_it != f_vi_end; ++f_vi_it) { + + BSP_MVertex & vert = const_cast<BSP_MVertex &>(verts[int(*f_vi_it)]); + + if (BSP_Classification(vert.OpenTag()) == e_unclassified) + { + MT_Scalar sdistance = plane.signedDistance(vert.m_pos); + MT_Scalar fsdistance = fabs(sdistance); + + if (fabs(sdistance) <= BSP_SPLIT_EPSILON) { + // this vertex is on + vert.SetOpenTag(e_classified_on); + } else + if (sdistance > MT_Scalar(0)) { + vert.SetOpenTag(e_classified_out); + } else { + vert.SetOpenTag(e_classified_in); + } + visited_verts.push_back(*f_vi_it); + } + BSP_Classification v_class = BSP_Classification(vert.OpenTag()); + + if (v_class == e_classified_on) on_count++; + + + if (p_class == e_unclassified || p_class == e_classified_on) { + p_class = v_class; + } else + if (p_class == e_classified_spanning) { + } else + if (p_class == e_classified_in) { + if (v_class == e_classified_out) { + p_class = e_classified_spanning; + } + } else { + if (v_class == e_classified_in) { + p_class = e_classified_spanning; + } + } + } + + if (on_count > 2) p_class = e_classified_on; + + return p_class; +} + + +// Classify this mesh fragment with respect +// to plane. The index sets of this fragment +// are consumed by this action. Vertices +// are tagged with a classification enum. + + void +BSP_MeshFragment:: +Classify( + const MT_Plane3 & plane, + BSP_MeshFragment * in_frag, + BSP_MeshFragment * out_frag, + BSP_MeshFragment * on_frag, + vector<BSP_FaceInd> & spanning_faces, + vector<BSP_VertexInd> & visited_verts +){ + + vector<BSP_MVertex> & vertex_set = m_mesh->VertexSet(); + vector<BSP_MFace> & face_set = m_mesh->FaceSet(); + + // Now iterate through the polygons and classify. + + vector<BSP_FaceInd>::const_iterator fi_end = m_faces.end(); + vector<BSP_FaceInd>::iterator fi_it = m_faces.begin(); + + vector<BSP_FaceInd> & face_in_set = in_frag->FaceSet(); + vector<BSP_FaceInd> & face_out_set = out_frag->FaceSet(); + vector<BSP_FaceInd> & face_on_set = on_frag->FaceSet(); + + for (;fi_it != fi_end; ++fi_it) { + + BSP_Classification p_class = ClassifyPolygon( + plane, + face_set[*fi_it], + vertex_set.begin(), + visited_verts + ); + // p_class now holds the classification for this polygon. + // assign to the appropriate bucket. + + if (p_class == e_classified_in) { + face_in_set.push_back(*fi_it); + } else + if (p_class == e_classified_out) { + face_out_set.push_back(*fi_it); + } else + if (p_class == e_classified_on) { + face_on_set.push_back(*fi_it); + } else { + spanning_faces.push_back(*fi_it); + // This is assigned later when we split the polygons in two. + } + } + + m_faces.clear(); + +} + + void +BSP_MeshFragment:: +Classify( + BSP_CSGMesh & mesh, + const MT_Plane3 & plane, + BSP_MeshFragment * in_frag, + BSP_MeshFragment * out_frag, + BSP_MeshFragment * on_frag, + vector<BSP_FaceInd> & spanning_faces, + vector<BSP_VertexInd> & visited_verts +){ + + vector<BSP_MVertex> & vertex_set = mesh.VertexSet(); + vector<BSP_MFace> & face_set = mesh.FaceSet(); + + // Now iterate through the polygons and classify. + + int fi_end = mesh.FaceSet().size(); + int fi_it = 0; + + vector<BSP_FaceInd> & face_in_set = in_frag->FaceSet(); + vector<BSP_FaceInd> & face_out_set = out_frag->FaceSet(); + vector<BSP_FaceInd> & face_on_set = on_frag->FaceSet(); + + for (;fi_it != fi_end; ++fi_it) { + + BSP_Classification p_class = ClassifyPolygon( + plane, + face_set[fi_it], + vertex_set.begin(), + visited_verts + ); + // p_class now holds the classification for this polygon. + // assign to the appropriate bucket. + + if (p_class == e_classified_in) { + face_in_set.push_back(fi_it); + } else + if (p_class == e_classified_out) { + face_out_set.push_back(fi_it); + } else + if (p_class == e_classified_on) { + face_on_set.push_back(fi_it); + } else { + spanning_faces.push_back(fi_it); + } + } + +} + void +BSP_MeshFragment:: +ClassifyOnFragments( + const MT_Plane3 &plane, + BSP_MeshFragment *pos_frag, + BSP_MeshFragment *neg_frag +){ + + vector<BSP_MFace> & face_set = m_mesh->FaceSet(); + vector<BSP_FaceInd>::const_iterator fi_end = m_faces.end(); + vector<BSP_FaceInd>::iterator fi_it = m_faces.begin(); + + MT_Scalar d = plane.Scalar(); + + for (;fi_it != fi_end; ++fi_it) { + if (fabs(d + face_set[*fi_it].m_plane.Scalar()) > BSP_SPLIT_EPSILON) { + pos_frag->FaceSet().push_back(*fi_it); + } else { + neg_frag->FaceSet().push_back(*fi_it); + } + } +} + +BSP_MeshFragment:: +~BSP_MeshFragment( +){ +} + + diff --git a/intern/bsp/intern/BSP_MeshFragment.h b/intern/bsp/intern/BSP_MeshFragment.h new file mode 100755 index 00000000000..e0068d1c9e7 --- /dev/null +++ b/intern/bsp/intern/BSP_MeshFragment.h @@ -0,0 +1,152 @@ +/** + * $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 ***** + */ + +#ifndef NAN_INCLUDED_BSP_MeshFragment_h + +#define NAN_INCLUDED_BSP_MeshFragment_h + +#define BSP_SPLIT_EPSILON MT_Scalar(1e-5) + +#include <vector> +#include "BSP_MeshPrimitives.h" + + +class BSP_CSGMesh; +class MT_Plane3; +/** + * This class encodes a collection of polygons from a mesh. + * This class only remains valid when mesh indices do not change + * internally and of course whilst the mesh is still around. + * + * Polygons in the mesh point back to the unique mesh fragment + * containing them. + */ + + +class BSP_MeshFragment { +public: + + BSP_MeshFragment( + BSP_CSGMesh *mesh, + BSP_Classification classification + ); + + std::vector<BSP_FaceInd> & + FaceSet( + ) ; + + const + std::vector<BSP_FaceInd> & + FaceSet( + ) const ; + + BSP_CSGMesh * + Mesh( + ); + + BSP_CSGMesh * + Mesh( + ) const; + + + // Classify this mesh fragment with respect + // to plane. The index sets of this fragment + // are consumed by this action. Vertices + // are tagged with a classification enum. + + void + Classify( + const MT_Plane3 & plane, + BSP_MeshFragment * in_frag, + BSP_MeshFragment * out_frag, + BSP_MeshFragment * on_frag, + std::vector<BSP_FaceInd> & spanning_faces, + std::vector<BSP_VertexInd> & visited_verts + ); + + // Classify all the vertices and faces of mesh, generate + // in,out and on mesh fragments. + + static + void + Classify( + BSP_CSGMesh & mesh, + const MT_Plane3 & plane, + BSP_MeshFragment * in_frag, + BSP_MeshFragment * out_frag, + BSP_MeshFragment * on_frag, + std::vector<BSP_FaceInd> & spanning_faces, + std::vector<BSP_VertexInd> & visited_verts + ); + + // Classify the on fragment into + // 2 sets, the +ve on frags those whose polygon + // normals point in the same direction as the plane, + // and the -ve frag whose normals point in the other direction. + + void + ClassifyOnFragments( + const MT_Plane3 &plane, + BSP_MeshFragment *pos_frag, + BSP_MeshFragment *neg_frag + ); + + + ~BSP_MeshFragment( + ); + + /** + * Sanity checkers. + */ + + +private: + + // Classify the polygon wrt to the plane + static + BSP_Classification + ClassifyPolygon( + const MT_Plane3 &plane, + const BSP_MFace & face, + std::vector<BSP_MVertex>::const_iterator verts, + std::vector<BSP_VertexInd> & visited_verts + ); + +private : + + + BSP_CSGMesh * m_mesh; + BSP_Classification m_classification; + std::vector<BSP_FaceInd> m_faces; +}; + + +#endif diff --git a/intern/bsp/intern/BSP_MeshPrimitives.cpp b/intern/bsp/intern/BSP_MeshPrimitives.cpp new file mode 100755 index 00000000000..7425510b6a4 --- /dev/null +++ b/intern/bsp/intern/BSP_MeshPrimitives.cpp @@ -0,0 +1,301 @@ +/** + * $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 ***** + */ + +#include "BSP_MeshPrimitives.h" + +#include "MT_assert.h" +#include "BSP_CSGException.h" +#include <algorithm> + +using namespace std; + +BSP_MVertex:: +BSP_MVertex( +) : + m_pos (MT_Point3()), + m_select_tag (false), + m_open_tag (0) +{ +}; + +BSP_MVertex:: +BSP_MVertex( + const MT_Point3 & pos +) : + m_pos(pos), + m_select_tag (false), + m_open_tag (0) +{ +}; + + + bool +BSP_MVertex:: +RemoveEdge( + BSP_EdgeInd e +){ + vector<BSP_EdgeInd>::iterator result = find(m_edges.begin(),m_edges.end(),e); + if (result == m_edges.end()) { + return false; + } + BSP_EdgeInd last = m_edges.back(); + m_edges.pop_back(); + if (m_edges.empty()) return true; + + *result = last; + return true; +} + + void +BSP_MVertex:: +AddEdge( + BSP_EdgeInd e +){ + m_edges.push_back(e); +} + + void +BSP_MVertex:: +SwapEdge( + BSP_EdgeInd e_old, + BSP_EdgeInd e_new +){ + vector<BSP_EdgeInd>::iterator result = + find(m_edges.begin(),m_edges.end(),e_old); + if (result == m_edges.end()) { + BSP_CSGException e(e_mesh_error); + throw(e); + MT_assert(false); + } + + *result = e_new; +} + + bool +BSP_MVertex:: +SelectTag( +) const{ + return m_select_tag; +} + + void +BSP_MVertex:: +SetSelectTag( + bool tag +){ + m_select_tag = tag; +} + + int +BSP_MVertex:: +OpenTag( +) const { + return m_open_tag; +} + + void +BSP_MVertex:: +SetOpenTag( + int tag +){ + m_open_tag = tag; +} + + +/** + * Edge Primitive Methods. + */ + +BSP_MEdge:: +BSP_MEdge( +){ + m_verts[0] = m_verts[1] = BSP_VertexInd::Empty(); +} + + bool +BSP_MEdge:: +operator == ( + BSP_MEdge & rhs +){ + // edges are the same if their vertex indices are the + // same!!! Other properties are not checked + + int matches = 0; + + if (this->m_verts[0] == rhs.m_verts[0]) { + ++matches; + } + if (this->m_verts[1] == rhs.m_verts[0]) { + ++matches; + } + if (this->m_verts[0] == rhs.m_verts[1]) { + ++matches; + } + if (this->m_verts[1] == rhs.m_verts[1]) { + ++matches; + } + + if (matches >= 2) { + return true; + } + return false; +} + + void +BSP_MEdge:: +SwapFace( + BSP_FaceInd old_f, + BSP_FaceInd new_f +){ + vector<BSP_FaceInd>::iterator result = + find(m_faces.begin(),m_faces.end(),old_f); + if (result == m_faces.end()) { + BSP_CSGException e(e_mesh_error); + throw(e); + MT_assert(false); + } + + *result = new_f; +} + + BSP_VertexInd +BSP_MEdge:: +OpVertex( + BSP_VertexInd vi +) const { + if (vi == m_verts[0]) return m_verts[1]; + if (vi == m_verts[1]) return m_verts[0]; + MT_assert(false); + BSP_CSGException e(e_mesh_error); + throw(e); + + return BSP_VertexInd::Empty(); +} + + bool +BSP_MEdge:: +SelectTag( +) const { + return bool(m_verts[1].Tag() & 0x1); +} + void +BSP_MEdge:: +SetSelectTag( + bool tag +){ + m_verts[1].SetTag(int(tag)); +} + + int +BSP_MEdge:: +OpenTag( +) const { + return m_verts[0].Tag(); +} + + void +BSP_MEdge:: +SetOpenTag( + int tag +) { + // Note conversion from int to unsigned int!!!!! + m_verts[0].SetTag(tag); +} + + +/** + * Face primitive methods + */ + + +BSP_MFace:: +BSP_MFace( +): + m_open_tag(-1) +{ + // nothing to do +} + + void +BSP_MFace:: +Invert( +){ + + // TODO replace reverse as I think some compilers + // do not support the STL routines employed. + + reverse( + m_verts.begin(), + m_verts.end() + ); + + reverse( + m_fv_data.begin(), + m_fv_data.end() + ); + + // invert the normal + m_plane.Invert(); +} + + bool +BSP_MFace:: +SelectTag( +) const { + return bool(m_verts[1].Tag() & 0x1); +} + + void +BSP_MFace:: +SetSelectTag( + bool tag +){ + m_verts[1].SetTag(int(tag)); +}; + + int +BSP_MFace:: +OpenTag( +) const { + return m_open_tag; +} + + void +BSP_MFace:: +SetOpenTag( + int tag +){ + // Note conversion from int to unsigned int!!!!! + m_open_tag = tag; +} + + + diff --git a/intern/bsp/intern/BSP_MeshPrimitives.h b/intern/bsp/intern/BSP_MeshPrimitives.h new file mode 100644 index 00000000000..8ba9cc6b83e --- /dev/null +++ b/intern/bsp/intern/BSP_MeshPrimitives.h @@ -0,0 +1,289 @@ +/** + * $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 ***** + */ + +#ifndef NAN_INCLUDED_BSP_MeshPrimitives + +#define NAN_INCLUDED_BSP_MeshPrimitives + +#include "CTR_TaggedIndex.h" +#include "MT_Vector3.h" +#include "MT_Plane3.h" + +class BSP_MeshFragment; + +#include <vector> + +typedef CTR_TaggedIndex<24,0x00ffffff> BSP_VertexInd; +typedef CTR_TaggedIndex<24,0x00ffffff> BSP_EdgeInd; +typedef CTR_TaggedIndex<24,0x00ffffff> BSP_FaceInd; +typedef CTR_TaggedIndex<24,0x00ffffff> BSP_FragInd; +typedef CTR_TaggedIndex<24,0x00ffffff> BSP_UserFVInd; + + +typedef std::vector<BSP_VertexInd> BSP_VertexList; +typedef std::vector<BSP_EdgeInd> BSP_EdgeList; +typedef std::vector<BSP_FaceInd> BSP_FaceList; +typedef std::vector<BSP_UserFVInd> BSP_UserFVDataList; + +/** + * Enum representing classification of primitives + * with respect to a hyperplane. + */ + +enum BSP_Classification{ + e_unclassified = 0, + e_classified_in = 1, + e_classified_out = 2, + e_classified_on = 4, + e_classified_spanning = 7 +}; + +/** + * @section Mesh linkage + * The mesh is linked in a similar way to the decimation mesh, + * although the primitives are a little more general and not + * limited to manifold meshes. + * Vertices -> (2+)Edges + * Edges -> (1+)Polygons + * Edges -> (2)Vertices. + * Polygons -> (3+)Vertices. + * + * this structure allows for arbitrary polygons (assumed to be convex). + * Edges can point to more than 2 polygons (non-manifold) + * + * We also define 2 different link types between edges and their + * neighbouring polygons. A weak link and a strong link. + * A weak link means the polygon is in a different mesh fragment + * to the other polygon. A strong link means the polygon is in the + * same fragment. + * This is not entirely consistent as it means edges have to be associated + * with fragments, in reality only polygons will be - edges and vertices + * will live in global pools. I guess we should mark edges as being on plane + * boundaries. This leaves a problem with non-manifold edges because for example + * 3 of 4 possible edges could lie in 1 fragment and the remaining edge lie in + * another, there is no way to work out then from one polygon which neighbouring + * polygons are in the same/different mesh fragment. + * + * By definition an edge will only ever lie on 1 hyperplane. We can then just + * tag neighbouring polygons with one of 3 tags to group them. + */ + +class BSP_MVertex { +public : + MT_Point3 m_pos; + BSP_EdgeList m_edges; + + /** + * TODO + * Is this boolean necessary or can we nick a few bits of m_edges[0] + * for example? + * The only problem with this is that if the vertex is degenerate then + * m_edges[0] may not exist. If the algorithm guarentees that this is + * not the case then it should be changed. + */ + + bool m_select_tag; + int m_open_tag; + + BSP_MVertex( + ); + + BSP_MVertex( + const MT_Point3 & pos + ); + + BSP_MVertex & + operator = ( + const BSP_MVertex & other + ) { + m_pos = other.m_pos; + m_edges = other.m_edges; + m_select_tag = other.m_select_tag; + m_open_tag = other.m_open_tag; + return (*this); + }; + + bool + RemoveEdge( + BSP_EdgeInd e + ); + + void + AddEdge( + BSP_EdgeInd e + ); + + void + SwapEdge( + BSP_EdgeInd e_old, + BSP_EdgeInd e_new + ); + + /** + * These operations are ONLY valid when the + * vertex has some edges associated with it. + * This is left to the user to guarentee. + * Also note that these tag's are not guarenteed + * to survive after a call to RemoveEdge(), + * because we use edges for the open tag. + */ + + int + OpenTag( + ) const; + + void + SetOpenTag( + int tag + ); + + bool + SelectTag( + ) const; + + void + SetSelectTag( + bool tag + ); +}; + +class BSP_MEdge { +public : + BSP_VertexInd m_verts[2]; + BSP_FaceList m_faces; + + BSP_MEdge( + ); + + bool operator == ( + BSP_MEdge & rhs + ); + + void + SwapFace( + BSP_FaceInd old_f, + BSP_FaceInd new_f + ); + + BSP_VertexInd + OpVertex( + BSP_VertexInd vi + ) const; + + bool + SelectTag( + ) const; + + void + SetSelectTag( + bool tag + ); + + /** + * We use one of the vertex indices for tag informtaion. + * This means these tags will not survive if you change + * the vertex indices. + */ + + int + OpenTag( + ) const; + + void + SetOpenTag( + int tag + ) ; +}; + +class BSP_MFace { +public : + + BSP_VertexList m_verts; + + // This is a list of face vertex data indices. + // Each vertex index in the list has an equivalent + // index into an array of face vertex data. This data + // is stored externally - the mesh does not know about it's + // contents. + + BSP_UserFVDataList m_fv_data; + // We also store the plane equation of this + // face. Generating on the fly during tree + // construction can lead to a lot of numerical errors. + // because the polygon size can get very small. + + MT_Plane3 m_plane; + + int m_open_tag; + + BSP_MFace( + ); + + // Invert the face , done by reversing the vertex order + // and inverting the face normal. + + void + Invert( + ); + + /** + * Tagging + * We use the tag from m_verts[1] for the select tag + * and the the tag from m_verts[0] for the open tag. + * There is always a chance that the polygon contains + * no vertices but this should be checked at construction + * time. + * Also note that changing the vertex indices of this polygon + * will likely remove tagging information. + * + */ + + bool + SelectTag( + ) const; + + void + SetSelectTag( + bool tag + ); + + int + OpenTag( + ) const; + + void + SetOpenTag( + int tag + ) ; + +}; + +#endif
\ No newline at end of file diff --git a/intern/bsp/intern/BSP_Triangulate.cpp b/intern/bsp/intern/BSP_Triangulate.cpp new file mode 100755 index 00000000000..a78b8ff0a92 --- /dev/null +++ b/intern/bsp/intern/BSP_Triangulate.cpp @@ -0,0 +1,249 @@ +/** + * $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 ***** + */ + +#include <stdio.h> + +#include <stdlib.h> +#include "MT_Plane3.h" +#include "BSP_Triangulate.h" +#include "MT_assert.h" + +static const MT_Scalar EPSILON = MT_Scalar(1e-10); + +using namespace std; + +BSP_Triangulate:: +BSP_Triangulate( +): + m_xi(0), + m_yi(1) +{ +} + +BSP_Triangulate:: +~BSP_Triangulate( +){ +} + + + MT_Scalar +BSP_Triangulate:: +Area( + const vector<BSP_MVertex> &verts, + const BSP_VertexList &contour +){ + + int n = contour.size(); + + MT_Scalar A(0.0); + + for(int p=n-1,q=0; q<n; p=q++) + { + A+= verts[contour[p]].m_pos[m_xi]*verts[contour[q]].m_pos[m_yi] - + verts[contour[q]].m_pos[m_xi]*verts[contour[p]].m_pos[m_yi]; + } + return A*MT_Scalar(0.5); +} + +/* + InsideTriangle decides if a point P is Inside of the triangle + defined by A, B, C. + Or within an epsilon of it. +*/ + + bool +BSP_Triangulate:: +InsideTriangle( + MT_Scalar Ax, MT_Scalar Ay, + MT_Scalar Bx, MT_Scalar By, + MT_Scalar Cx, MT_Scalar Cy, + MT_Scalar Px, MT_Scalar Py +){ + MT_Scalar ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy; + MT_Scalar cCROSSap, bCROSScp, aCROSSbp; + + ax = Cx - Bx; ay = Cy - By; + bx = Ax - Cx; by = Ay - Cy; + cx = Bx - Ax; cy = By - Ay; + apx= Px - Ax; apy= Py - Ay; + bpx= Px - Bx; bpy= Py - By; + cpx= Px - Cx; cpy= Py - Cy; + + aCROSSbp = ax*bpy - ay*bpx; + cCROSSap = cx*apy - cy*apx; + bCROSScp = bx*cpy - by*cpx; + + return ((aCROSSbp >= -EPSILON) && (bCROSScp >= -EPSILON) && (cCROSSap >= -EPSILON)); +}; + + bool +BSP_Triangulate:: +Snip( + const vector<BSP_MVertex> &verts, + const BSP_VertexList &contour, + int u,int v, + int w,int n, + int *V +){ + int p; + MT_Scalar Ax, Ay, Bx, By, Cx, Cy, Px, Py; + + Ax = verts[contour[V[u]]].m_pos[m_xi]; + Ay = verts[contour[V[u]]].m_pos[m_yi]; + + Bx = verts[contour[V[v]]].m_pos[m_xi]; + By = verts[contour[V[v]]].m_pos[m_yi]; + + Cx = verts[contour[V[w]]].m_pos[m_xi]; + Cy = verts[contour[V[w]]].m_pos[m_yi]; + + // Snip is passes if the area of the candidate triangle is + // greater than 2*epsilon + // And if none of the remaining vertices are inside the polygon + // or within an epsilon of the boundary, + + if ( EPSILON > (((Bx-Ax)*(Cy-Ay)) - ((By-Ay)*(Cx-Ax))) ) return false; + + for (p=0;p<n;p++) + { + if( (p == u) || (p == v) || (p == w) ) continue; + Px = verts[contour[V[p]]].m_pos[m_xi]; + Py = verts[contour[V[p]]].m_pos[m_yi]; + if (InsideTriangle(Ax,Ay,Bx,By,Cx,Cy,Px,Py)) return false; + } + + return true; +} + + bool +BSP_Triangulate:: +Process( + const vector<BSP_MVertex> &verts, + const BSP_VertexList &contour, + const MT_Plane3 &normal, + std::vector<int> &result +){ + + // Choose major axis of normal and assign + // 'projection' indices m_xi,m_yi; + + int maj_axis = normal.Normal().closestAxis(); + + if (maj_axis == 0) { + m_xi = 1; m_yi = 2; + } else + if (maj_axis == 1) { + m_xi = 0; m_yi = 2; + } else { + m_xi = 0; m_yi = 1; + } + + /* initialize list of Vertices in polygon */ + + int n = contour.size(); + if ( n < 3 ) return false; + + /* we want a counter-clockwise polygon in V */ + /* to true but we also nead to preserve the winding order + of polygons going into the routine. We keep track of what + we did with a little bool */ + bool is_flipped = false; + + if ( 0.0f < Area(verts,contour) ) { + for (int v=0; v<n; v++) m_V.push_back(v); + } else { + for(int v=0; v<n; v++) m_V.push_back((n-1)-v); + is_flipped = true; + } + + int nv = n; + + /* remove nv-2 Vertices, creating 1 triangle every time */ + int count = 2*nv; /* error detection */ + + for(int m=0, v=nv-1; nv>2; ) + { + /* if we loop, it is probably a non-simple polygon */ + if (0 >= (count--)) + { +#if 0 + int deb = 0; + for (deb= 0; deb < contour.size(); deb++) { + cout << verts[contour[deb]].m_pos << "\n"; + } + cout.flush(); +#endif + //** Triangulate: ERROR - probable bad polygon! + m_V.clear(); + return false; + } + + /* three consecutive vertices in current polygon, <u,v,w> */ + int u = v ; if (nv <= u) u = 0; /* previous */ + v = u+1; if (nv <= v) v = 0; /* new v */ + int w = v+1; if (nv <= w) w = 0; /* next */ + + /* Try and snip this triangle off from the + current polygon.*/ + + if ( Snip(verts,contour,u,v,w,nv,m_V.begin()) ) + { + int a,b,c,s,t; + + /* true names of the vertices */ + a = m_V[u]; b = m_V[v]; c = m_V[w]; + + /* output Triangle indices*/ + if (is_flipped) { + result.push_back( c ); + result.push_back( b ); + result.push_back( a ); + } else { + result.push_back( a ); + result.push_back( b ); + result.push_back( c ); + } + + m++; + + /* remove v from remaining polygon */ + for(s=v,t=v+1;t<nv;s++,t++) m_V[s] = m_V[t]; nv--; + + /* resest error detection counter */ + count = 2*nv; + } + } + + m_V.clear(); + return true; +} + + diff --git a/intern/bsp/intern/BSP_Triangulate.h b/intern/bsp/intern/BSP_Triangulate.h new file mode 100755 index 00000000000..bee8e9711a9 --- /dev/null +++ b/intern/bsp/intern/BSP_Triangulate.h @@ -0,0 +1,132 @@ +/** + * $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 ***** + */ + +#ifndef TRIANGULATE_H + + +#define TRIANGULATE_H + +/*****************************************************************/ +/** Static class to triangulate any contour/polygon efficiently **/ +/** You should replace Vector2d with whatever your own Vector **/ +/** class might be. Does not support polygons with holes. **/ +/** Uses STL vectors to represent a dynamic array of vertices. **/ +/** This code snippet was submitted to FlipCode.com by **/ +/** John W. Ratcliff (jratcliff@verant.com) on July 22, 2000 **/ +/** I did not write the original code/algorithm for this **/ +/** this triangulator, in fact, I can't even remember where I **/ +/** found it in the first place. However, I did rework it into **/ +/** the following black-box static class so you can make easy **/ +/** use of it in your own code. Simply replace Vector2d with **/ +/** whatever your own Vector implementation might be. **/ +/*****************************************************************/ + + +#include <vector> // Include STL vector class. +#include "MT_Point3.h" +#include "BSP_MeshPrimitives.h" + +class MT_Plane3; + +class BSP_Triangulate +{ +public: + + BSP_Triangulate( + ); + + // triangulate a contour/polygon, places results in STL vector + // as series of triangles. IT uses the major axis of the normal + // to turn it into a 2d problem. + + // Should chaange this to accept a point array and a list of + // indices into that point array. Result should be indices of those + // indices. + // + // MT_Point3 global_array + // vector<BSP_VertexInd> polygon + // result is vector<int> into polygon. + + bool + Process( + const std::vector<BSP_MVertex> &verts, + const BSP_VertexList &contour, + const MT_Plane3 &normal, + std::vector<int> &result + ); + + // compute area of a contour/polygon + MT_Scalar + Area( + const std::vector<BSP_MVertex> &verts, + const BSP_VertexList &contour + ); + + // decide if point Px/Py is inside triangle defined by + // (Ax,Ay) (Bx,By) (Cx,Cy) + + bool + InsideTriangle( + MT_Scalar Ax, MT_Scalar Ay, + MT_Scalar Bx, MT_Scalar By, + MT_Scalar Cx, MT_Scalar Cy, + MT_Scalar Px, MT_Scalar Py + ); + + ~BSP_Triangulate( + ); + +private: + + bool + Snip( + const std::vector<BSP_MVertex> &verts, + const BSP_VertexList &contour, + int u, + int v, + int w, + int n, + int *V + ); + + int m_xi; + int m_yi; + + // Temporary storage + + std::vector<int> m_V; + +}; + + +#endif + + diff --git a/intern/bsp/intern/CSG_BooleanOps.cpp b/intern/bsp/intern/CSG_BooleanOps.cpp new file mode 100755 index 00000000000..01b8bfc0b68 --- /dev/null +++ b/intern/bsp/intern/CSG_BooleanOps.cpp @@ -0,0 +1,255 @@ +/** + * $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 ***** + */ + +/** + + * Implementation of external api for CSG part of BSP lib interface. + */ + +#include "../extern/CSG_BooleanOps.h" +#include "BSP_CSGMesh_CFIterator.h" +#include "BSP_CSGMeshBuilder.h" +#include "BSP_CSGHelper.h" +#include "BSP_CSGUserData.h" +#include "MEM_RefCountPtr.h" + +struct BSP_MeshInfo { + MEM_RefCountPtr<BSP_CSGMesh> output_mesh; + CSG_MeshPropertyDescriptor obA_descriptor; + CSG_MeshPropertyDescriptor obB_descriptor; + CSG_MeshPropertyDescriptor output_descriptor; +}; + +using namespace std; + + CSG_BooleanOperation * +CSG_NewBooleanFunction( + void +){ + BSP_MeshInfo * mesh_info = new BSP_MeshInfo; + CSG_BooleanOperation * output = new CSG_BooleanOperation; + + if (mesh_info==NULL || output==NULL) return NULL; + + mesh_info->output_mesh = NULL; + output->CSG_info = mesh_info; + + return output; +} + + CSG_MeshPropertyDescriptor +CSG_DescibeOperands( + CSG_BooleanOperation * operation, + CSG_MeshPropertyDescriptor operandA_desciption, + CSG_MeshPropertyDescriptor operandB_desciption +){ + BSP_MeshInfo * mesh_info = static_cast<BSP_MeshInfo *>(operation->CSG_info); + + mesh_info->obA_descriptor = operandA_desciption; + mesh_info->obB_descriptor = operandB_desciption; + + if ( + (operandA_desciption.user_data_size == operandB_desciption.user_data_size) && + (operandA_desciption.user_face_vertex_data_size == operandB_desciption.user_face_vertex_data_size) + ) { + // Then both operands have the same sets of data we can cope with this! + mesh_info->output_descriptor.user_data_size = operandA_desciption.user_data_size; + mesh_info->output_descriptor.user_face_vertex_data_size = operandA_desciption.user_face_vertex_data_size; + } else { + // There maybe some common subset of data we can seperate out but for now we just use the + // default + mesh_info->output_descriptor.user_data_size = 0; + mesh_info->output_descriptor.user_face_vertex_data_size = 0; + } + return mesh_info->output_descriptor; +} + + int +CSG_PerformBooleanOperation( + CSG_BooleanOperation * operation, + CSG_OperationType op_type, + CSG_FaceIteratorDescriptor obAFaces, + CSG_VertexIteratorDescriptor obAVertices, + CSG_FaceIteratorDescriptor obBFaces, + CSG_VertexIteratorDescriptor obBVertices, + CSG_InterpolateUserFaceVertexDataFunc interp_func +){ + + if (operation == NULL) return 0; + BSP_MeshInfo * mesh_info = static_cast<BSP_MeshInfo *>(operation->CSG_info); + if (mesh_info == NULL) return 0; + + bool success = 0; + + obAFaces.Reset(obAFaces.it); + obBFaces.Reset(obBFaces.it); + obAVertices.Reset(obAVertices.it); + obBVertices.Reset(obBVertices.it); + + + try { + // Build the individual meshes + + MEM_SmartPtr<BSP_CSGMesh> obA = + BSP_CSGMeshBuilder::NewMesh(mesh_info->obA_descriptor,obAFaces,obAVertices); + + MEM_SmartPtr<BSP_CSGMesh> obB = + BSP_CSGMeshBuilder::NewMesh(mesh_info->obB_descriptor,obBFaces,obBVertices); + + // create an empty vertex array for the output mesh + MEM_SmartPtr<vector<BSP_MVertex> > output_verts(new vector<BSP_MVertex>); + // and some user data arrays matching the output descriptor + + MEM_SmartPtr<BSP_CSGUserData> output_f_data = new BSP_CSGUserData( + mesh_info->output_descriptor.user_data_size + ); + MEM_SmartPtr<BSP_CSGUserData> output_fv_data = new BSP_CSGUserData( + mesh_info->output_descriptor.user_face_vertex_data_size + ); + + // create the output mesh! + mesh_info->output_mesh = BSP_CSGMesh::New(); + + if ( + obA == NULL || + obB == NULL || + output_verts == NULL || + mesh_info->output_mesh == NULL || + output_f_data == NULL || + output_fv_data == NULL + ) { + return 0; + } + + mesh_info->output_mesh->SetVertices(output_verts); + mesh_info->output_mesh->SetFaceData(output_f_data); + mesh_info->output_mesh->SetFaceVertexData(output_fv_data); + + BSP_CSGHelper helper; + // translate enums! + + switch(op_type) { + case e_csg_union : + case e_csg_classify : + success = helper.ComputeOp(obA,obB,e_intern_csg_union, + mesh_info->output_mesh.Ref(),interp_func + ); + break; + case e_csg_intersection : + success = helper.ComputeOp(obA,obB,e_intern_csg_intersection, + mesh_info->output_mesh.Ref(),interp_func + ); + break; + case e_csg_difference : + success = helper.ComputeOp(obA,obB,e_intern_csg_difference, + mesh_info->output_mesh.Ref(),interp_func + ); + break; + default : + success = 0; + } + } + catch(...) { + return 0; + } + + return success; +} + + int +CSG_OutputFaceDescriptor( + CSG_BooleanOperation * operation, + CSG_FaceIteratorDescriptor * output +){ + if (operation == NULL) return 0; + BSP_MeshInfo * mesh_info = static_cast<BSP_MeshInfo *>(operation->CSG_info); + + if (mesh_info == NULL) return 0; + if (mesh_info->output_mesh == NULL) return 0; + + BSP_CSGMesh_FaceIt_Construct(mesh_info->output_mesh,output); + return 1; +} + + + int +CSG_OutputVertexDescriptor( + CSG_BooleanOperation * operation, + CSG_VertexIteratorDescriptor *output +){ + if (operation == NULL) return 0; + BSP_MeshInfo * mesh_info = static_cast<BSP_MeshInfo *>(operation->CSG_info); + + if (mesh_info == NULL) return 0; + if (mesh_info->output_mesh == NULL) return 0; + + BSP_CSGMeshVertexIt_Construct(mesh_info->output_mesh,output); + return 1; +} + + void +CSG_FreeVertexDescriptor( + CSG_VertexIteratorDescriptor * v_descriptor +){ + BSP_CSGMesh_VertexIt_Destruct(v_descriptor); +} + + + void +CSG_FreeFaceDescriptor( + CSG_FaceIteratorDescriptor * f_descriptor +){ + BSP_CSGMesh_FaceIt_Destruct(f_descriptor); +} + + + void +CSG_FreeBooleanOperation( + CSG_BooleanOperation *operation +){ + if (operation != NULL) { + BSP_MeshInfo * mesh_info = static_cast<BSP_MeshInfo *>(operation->CSG_info); + delete(mesh_info); + delete(operation); + } +} + + + + + + + + + + + + diff --git a/intern/bsp/intern/Makefile b/intern/bsp/intern/Makefile new file mode 100644 index 00000000000..a5e8565a6ff --- /dev/null +++ b/intern/bsp/intern/Makefile @@ -0,0 +1,48 @@ +# +# $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 ***** +# string intern Makefile +# + +LIBNAME = bsp +DIR = $(OCGDIR)/intern/$(LIBNAME) +DIRS = common + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I../extern +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I$(NAN_MEMUTIL)/include +CPPFLAGS += -I$(NAN_CONTAINER)/include +CPPFLAGS += -Icommon + + diff --git a/intern/bsp/make/msvc6_0/bsplib.dsp b/intern/bsp/make/msvc6_0/bsplib.dsp new file mode 100644 index 00000000000..8e161dcd30e --- /dev/null +++ b/intern/bsp/make/msvc6_0/bsplib.dsp @@ -0,0 +1,211 @@ +# Microsoft Developer Studio Project File - Name="bsplib" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=bsplib - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "bsplib.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "bsplib.mak" CFG="bsplib - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "bsplib - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "bsplib - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "bsplib - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /Ob2 /I "../../../../lib/windows/memutil/include" /I "../.." /I "../../../../lib/windows/moto/include" /I "../../../../lib/windows/container/include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"Release\libbsp.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files COPY "..\..\extern\*.h" "..\..\..\..\lib\windows\bsp\include\" ECHO Copying lib COPY "Release\libbsp.lib" "..\..\..\..\lib\windows\bsp\lib\libbsp.a" ECHO Done +# End Special Build Tool + +!ELSEIF "$(CFG)" == "bsplib - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +LINK32=link.exe -lib +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../../../lib/windows/memutil" /I "../.." /I "../../../../lib/windows/moto/include" /I "../../../../lib/windows/container/include" /I "../../../../lib/windows/memutil/include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"Debug\libbsp.lib" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=ECHO Copying header files COPY "..\..\extern\*.h" "..\..\..\..\lib\windows\bsp\include\" ECHO Copying lib COPY "Debug\libbsp.lib" "..\..\..\..\lib\windows\bsp\lib\debug\libbsp.a" ECHO Copying Debug info. COPY "Debug\vc60.*" "..\..\..\..\lib\windows\bsp\lib\debug\" ECHO Done +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "bsplib - Win32 Release" +# Name "bsplib - Win32 Debug" +# Begin Group "intern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGException.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGHelper.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGHelper.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGISplitter.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGMesh.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGMesh.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGMesh_CFIterator.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGMeshBuilder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGMeshBuilder.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGMeshSplitter.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGMeshSplitter.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGNCMeshSplitter.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGNCMeshSplitter.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGUserData.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_CSGUserData.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_FragNode.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_FragNode.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_FragTree.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_FragTree.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_MeshFragment.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_MeshFragment.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_MeshPrimitives.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_MeshPrimitives.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_Triangulate.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\intern\BSP_Triangulate.h +# End Source File +# Begin Source File + +SOURCE=..\..\intern\CSG_BooleanOps.cpp +# End Source File +# End Group +# Begin Group "extern" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\extern\CSG_BooleanOps.h +# End Source File +# End Group +# End Target +# End Project diff --git a/intern/bsp/make/msvc6_0/bsplib.dsw b/intern/bsp/make/msvc6_0/bsplib.dsw new file mode 100644 index 00000000000..1827dc3746e --- /dev/null +++ b/intern/bsp/make/msvc6_0/bsplib.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "bsplib"=.\bsplib.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/bsp/test/BSP_GhostTest/BSP_GhostTest.dsp b/intern/bsp/test/BSP_GhostTest/BSP_GhostTest.dsp new file mode 100755 index 00000000000..1e913289824 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_GhostTest.dsp @@ -0,0 +1,130 @@ +# Microsoft Developer Studio Project File - Name="BSP_GhostTest" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=BSP_GhostTest - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "BSP_GhostTest.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "BSP_GhostTest.mak" CFG="BSP_GhostTest - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "BSP_GhostTest - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "BSP_GhostTest - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "BSP_GhostTest - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /G6 /MT /W3 /GX /O2 /Ob2 /I "../../extern/" /I "../../../../lib/windows/string/include" /I "../../../../lib/windows/ghost/include" /I "../../../../lib/windows/moto/include" /I "../../../../lib/windows/memutil/include" /I "../../../../lib/windows/container/include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x413 /d "NDEBUG" +# ADD RSC /l 0x413 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 glu32.lib opengl32.lib kernel32.lib user32.lib gdi32.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\..\..\lib\windows\glut-3.7\lib\\" + +!ELSEIF "$(CFG)" == "BSP_GhostTest - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../extern/" /I "../../../../lib/windows/string/include" /I "../../../../lib/windows/ghost/include" /I "../../../../lib/windows/moto/include" /I "../../../../lib/windows/memutil/include" /I "../../../../lib/windows/container/include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x413 /d "_DEBUG" +# ADD RSC /l 0x413 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 glu32.lib opengl32.lib user32.lib gdi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\..\..\lib\windows\glut-3.7\lib\\" + +!ENDIF + +# Begin Target + +# Name "BSP_GhostTest - Win32 Release" +# Name "BSP_GhostTest - Win32 Debug" +# Begin Source File + +SOURCE=.\BSP_GhostTest3D.cpp +# End Source File +# Begin Source File + +SOURCE=.\BSP_GhostTest3D.h +# End Source File +# Begin Source File + +SOURCE=.\BSP_MeshDrawer.cpp +# End Source File +# Begin Source File + +SOURCE=.\BSP_MeshDrawer.h +# End Source File +# Begin Source File + +SOURCE=.\BSP_PlyLoader.cpp +# End Source File +# Begin Source File + +SOURCE=.\BSP_PlyLoader.h +# End Source File +# Begin Source File + +SOURCE=.\BSP_TMesh.cpp +# End Source File +# Begin Source File + +SOURCE=.\BSP_TMesh.h +# End Source File +# Begin Source File + +SOURCE=.\main.cpp +# End Source File +# Begin Source File + +SOURCE=.\ply.h +# End Source File +# Begin Source File + +SOURCE=.\plyfile.c +# End Source File +# End Target +# End Project diff --git a/intern/bsp/test/BSP_GhostTest/BSP_GhostTest.dsw b/intern/bsp/test/BSP_GhostTest/BSP_GhostTest.dsw new file mode 100755 index 00000000000..802fba84bef --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_GhostTest.dsw @@ -0,0 +1,125 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "BSP_GhostTest"=.\BSP_GhostTest.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name bsplib + End Project Dependency + Begin Project Dependency + Project_Dep_Name ghost + End Project Dependency + Begin Project Dependency + Project_Dep_Name string + End Project Dependency + Begin Project Dependency + Project_Dep_Name MoTo + End Project Dependency +}}} + +############################################################################### + +Project: "MoTo"=..\..\..\moto\make\msvc_6_0\MoTo.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "bsplib"=..\..\make\msvc6_0\bsplib.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name container + End Project Dependency + Begin Project Dependency + Project_Dep_Name memutil + End Project Dependency + Begin Project Dependency + Project_Dep_Name MoTo + End Project Dependency +}}} + +############################################################################### + +Project: "container"=..\..\..\container\make\msvc_6_0\container.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name memutil + End Project Dependency +}}} + +############################################################################### + +Project: "ghost"=..\..\..\ghost\make\msvc\ghost.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "memutil"=..\..\..\memutil\make\msvc_60\memutil.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "string"=..\..\..\string\make\msvc_6_0\string.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/intern/bsp/test/BSP_GhostTest/BSP_GhostTest3D.cpp b/intern/bsp/test/BSP_GhostTest/BSP_GhostTest3D.cpp new file mode 100755 index 00000000000..92e5198f139 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_GhostTest3D.cpp @@ -0,0 +1,656 @@ +/** + * $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 ***** + */ + +/** + +* $Id$ +* Copyright (C) 2001 NaN Technologies B.V. +*/ + +#if defined(WIN32) || defined(__APPLE__) +# ifdef WIN32 +# include <windows.h> +# include <GL/gl.h> +# include <GL/glu.h> +# else // WIN32 +# include <AGL/gl.h> +# endif // WIN32 +#else // defined(WIN32) || defined(__APPLE__) +# include <GL/gl.h> +# include <GL/glu.h> +#endif // defined(WIN32) || defined(__APPLE__) + + +#include "BSP_GhostTest3D.h" +#include "BSP_MeshDrawer.h" + +#include "GHOST_ISystem.h" +#include "GHOST_IWindow.h" + +#include "MT_Quaternion.h" +#include "MT_Transform.h" +#include "CSG_BooleanOps.h" + +#include <iostream> + + +using namespace std; + + +BSP_GhostTestApp3D:: +BSP_GhostTestApp3D( +) : + m_window(NULL), + m_system(NULL), + m_finish_me_off(false), + m_current_object(0) +{ + //nothing to do; +} + + void +BSP_GhostTestApp3D:: +SetMesh( + MEM_SmartPtr<BSP_TMesh> mesh +){ + m_meshes.push_back(mesh); + + BSP_RotationSetting rotation_setting; + BSP_TranslationSetting translation_setting; + + rotation_setting.m_angle_x = MT_Scalar(0); + rotation_setting.m_angle_y = MT_Scalar(0); + rotation_setting.m_moving = false; + rotation_setting.x_old = 0; + rotation_setting.y_old = 0; + + translation_setting.m_t_x = MT_Scalar(0); + translation_setting.m_t_y = MT_Scalar(0); + translation_setting.m_t_z = MT_Scalar(0); + translation_setting.m_moving = false; + translation_setting.x_old = 0; + translation_setting.y_old = 0; + + m_rotation_settings.push_back(rotation_setting); + m_translation_settings.push_back(translation_setting); + m_render_modes.push_back(e_wireframe_shaded); + m_scale_settings.push_back(MT_Scalar(1)); + +} + + void +BSP_GhostTestApp3D:: +Swap( + int i +){ + + if (!m_rotation_settings[i].m_moving && !m_translation_settings[i].m_moving) { + swap(m_meshes[i],m_meshes.back()); + swap(m_rotation_settings[i],m_rotation_settings.back()); + swap(m_translation_settings[i],m_translation_settings.back()); + swap(m_scale_settings[i],m_scale_settings.back()); + swap(m_render_modes[i],m_render_modes.back()); + } +} + + + + + + + MT_Transform +BSP_GhostTestApp3D:: +GetTransform( + int i +){ + + MT_Quaternion q_ax(MT_Vector3(0,1,0),m_rotation_settings[i].m_angle_x); + MT_Quaternion q_ay(MT_Vector3(1,0,0),m_rotation_settings[i].m_angle_y); + + MT_Point3 tr( + m_translation_settings[i].m_t_x, + m_translation_settings[i].m_t_y, + m_translation_settings[i].m_t_z + ); + + + MT_Matrix3x3 rotx(q_ax); + MT_Matrix3x3 roty(q_ay); + + MT_Matrix3x3 rot = rotx * roty; + + MT_Transform trans(tr,rot); + + MT_Transform scalet; + scalet.setIdentity(); + scalet.scale(m_scale_settings[i],m_scale_settings[i],m_scale_settings[i]); + + return trans * scalet; +} + + void +BSP_GhostTestApp3D:: +Operate( + int type +){ + + CSG_VertexIteratorDescriptor * vA = VertexIt_Construct(m_meshes[0],GetTransform(0)); + CSG_FaceIteratorDescriptor * fA = FaceIt_Construct(m_meshes[0]); + + CSG_VertexIteratorDescriptor * vB = VertexIt_Construct(m_meshes[1],GetTransform(1)); + CSG_FaceIteratorDescriptor * fB = FaceIt_Construct(m_meshes[1]); + + // describe properties. + + CSG_MeshPropertyDescriptor props; + props.mesh_property_flags = 0; + props.user_data_size = 0; + + CSG_BooleanOperation * op = CSG_NewBooleanFunction(); + props = CSG_DescibeOperands(op,props,props); + + CSG_PerformBooleanOperation(op,CSG_OperationType(type), + *fA,*vA,*fB,*vB + ); + + CSG_FaceIteratorDescriptor * out_f = CSG_OutputFaceDescriptor(op); + CSG_VertexIteratorDescriptor * out_v = CSG_OutputVertexDescriptor(op); + + MEM_SmartPtr<BSP_TMesh> new_mesh (BuildMesh(props,*out_f,*out_v)); + + // free stuff + + CSG_FreeVertexDescriptor(out_v); + CSG_FreeFaceDescriptor(out_f); + CSG_FreeBooleanOperation(op); + + op = NULL; + SetMesh(new_mesh); +} + + + void +BSP_GhostTestApp3D:: +UpdateFrame( +){ +if (m_window) { + + GHOST_Rect v_rect; + m_window->getClientBounds(v_rect); + + glViewport(0,0,v_rect.getWidth(),v_rect.getHeight()); + +} +} + + +MT_Vector3 +BSP_GhostTestApp3D:: +UnProject( + const MT_Vector3 & vec +) { + + GLint viewport[4]; + GLdouble mvmatrix[16],projmatrix[16]; + + glGetIntegerv(GL_VIEWPORT,viewport); + glGetDoublev(GL_MODELVIEW_MATRIX,mvmatrix); + glGetDoublev(GL_PROJECTION_MATRIX,projmatrix); + + GLdouble realy = viewport[3] - vec.y() - 1; + GLdouble outx,outy,outz; + + gluUnProject(vec.x(),realy,vec.z(),mvmatrix,projmatrix,viewport,&outx,&outy,&outz); + + return MT_Vector3(outx,outy,outz); +} + + + bool +BSP_GhostTestApp3D:: +InitApp( +){ + + // create a system and window with opengl + // rendering context. + + GHOST_TSuccess success = GHOST_ISystem::createSystem(); + if (success == GHOST_kFailure) return false; + + m_system = GHOST_ISystem::getSystem(); + if (m_system == NULL) return false; + + m_system->addEventConsumer(this); + + m_window = m_system->createWindow( + "GHOST crud3D!", + 100,100,640,480,GHOST_kWindowStateNormal, + GHOST_kDrawingContextTypeOpenGL + ); + + if ( + m_window == NULL + ) { + m_system = NULL; + GHOST_ISystem::disposeSystem(); + return false; + } + + // make an opengl frustum for this wind + + MT_Vector3 min,max; + + min = m_meshes[0]->m_min; + max = m_meshes[0]->m_max; + InitOpenGl(min,max); + + return true; +} + + void +BSP_GhostTestApp3D:: +Run( +){ + if (m_system == NULL) { + return; + } + + while (!m_finish_me_off) { + m_system->processEvents(true); + m_system->dispatchEvents(); + }; +} + + bool +BSP_GhostTestApp3D:: +processEvent( + GHOST_IEvent* event +){ + + bool handled = false; + + switch(event->getType()) { + case GHOST_kEventWindowSize: + case GHOST_kEventWindowActivate: + UpdateFrame(); + case GHOST_kEventWindowUpdate: + DrawPolies(); + handled = true; + break; + case GHOST_kEventButtonDown: + { + int x,y; + m_system->getCursorPosition(x,y); + + int wx,wy; + m_window->screenToClient(x,y,wx,wy); + + GHOST_TButtonMask button = + static_cast<GHOST_TEventButtonData *>(event->getData())->button; + + if (button == GHOST_kButtonMaskLeft) { + m_rotation_settings[m_current_object].m_moving = true; + m_rotation_settings[m_current_object].x_old = x; + m_rotation_settings[m_current_object].y_old = y; + } else + if (button == GHOST_kButtonMaskRight) { + m_translation_settings[m_current_object].m_moving = true; + m_translation_settings[m_current_object].x_old = x; + m_translation_settings[m_current_object].y_old = y; + } else + + m_window->invalidate(); + handled = true; + break; + + } + + case GHOST_kEventButtonUp: + { + + GHOST_TButtonMask button = + static_cast<GHOST_TEventButtonData *>(event->getData())->button; + + if (button == GHOST_kButtonMaskLeft) { + m_rotation_settings[m_current_object].m_moving = false; + m_rotation_settings[m_current_object].x_old = 0; + m_rotation_settings[m_current_object].y_old = 0; + } else + if (button == GHOST_kButtonMaskRight) { + m_translation_settings[m_current_object].m_moving = false; + m_translation_settings[m_current_object].x_old; + m_translation_settings[m_current_object].y_old; + + } + m_window->invalidate(); + handled = true; + break; + + } + + case GHOST_kEventCursorMove: + { + int x,y; + m_system->getCursorPosition(x,y); + int wx,wy; + m_window->screenToClient(x,y,wx,wy); + + if (m_rotation_settings[m_current_object].m_moving) { + m_rotation_settings[m_current_object].m_angle_x = MT_Scalar(wx)/20; + m_rotation_settings[m_current_object].x_old = wx; + m_rotation_settings[m_current_object].m_angle_y = MT_Scalar(wy)/20; + m_rotation_settings[m_current_object].y_old = wy; + + m_window->invalidate(); + } + if (m_translation_settings[m_current_object].m_moving) { + + // project current objects bounding box centre into screen space. + // unproject mouse point into object space using z-value from + // projected bounding box centre. + + GHOST_Rect bounds; + m_window->getClientBounds(bounds); + + int w_h = bounds.getWidth(); + + y = w_h - wy; + + double mvmatrix[16]; + double projmatrix[16]; + GLint viewport[4]; + + double px, py, pz,sz; + + /* Get the matrices needed for gluUnProject */ + glGetIntegerv(GL_VIEWPORT, viewport); + glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix); + glGetDoublev(GL_PROJECTION_MATRIX, projmatrix); + + // work out the position of the end effector in screen space + + GLdouble ex,ey,ez; + + MT_Vector3 bbox_min, bbox_max; + + bbox_min = m_meshes[0]->m_min; + bbox_max = m_meshes[0]->m_max; + + MT_Vector3 bbox_centre = (bbox_min + bbox_max)/2; + + ex = bbox_centre.x(); + ey = bbox_centre.y(); + ez = bbox_centre.z(); + + gluProject(ex, ey, ez, mvmatrix, projmatrix, viewport, &px, &py, &sz); + gluUnProject((GLdouble) x, (GLdouble) y, sz, mvmatrix, projmatrix, viewport, &px, &py, &pz); + + m_translation_settings[m_current_object].m_t_x = px; + m_translation_settings[m_current_object].m_t_y = py; + m_translation_settings[m_current_object].m_t_z = pz; + m_window->invalidate(); + + } + + handled = true; + break; + } + + case GHOST_kEventKeyDown : + { + GHOST_TEventKeyData *kd = + static_cast<GHOST_TEventKeyData *>(event->getData()); + + + switch(kd->key) { + case GHOST_kKeyI: + { + // now intersect meshes. + Operate(e_csg_intersection); + handled = true; + m_window->invalidate(); + break; + } + case GHOST_kKeyU: + { + Operate(e_csg_union); + handled = true; + m_window->invalidate(); + break; + } + case GHOST_kKeyD: + { + Operate(e_csg_difference); + handled = true; + m_window->invalidate(); + break; + } + + case GHOST_kKeyA: + { + + m_scale_settings[m_current_object] *= 1.1; + handled = true; + m_window->invalidate(); + break; + } + case GHOST_kKeyZ: + { + m_scale_settings[m_current_object] *= 0.8; + + handled = true; + m_window->invalidate(); + break; + } + + case GHOST_kKeyR: + + m_render_modes[m_current_object]++; + + if (m_render_modes[m_current_object] > e_last_render_mode) { + m_render_modes[m_current_object] = e_first_render_mode; + } + + handled = true; + m_window->invalidate(); + break; + + + + case GHOST_kKeyB: + handled = true; + m_window->invalidate(); + break; + + case GHOST_kKeyQ: + m_finish_me_off = true; + handled = true; + break; + + case GHOST_kKeyS: + Swap(m_current_object); + m_window->invalidate(); + handled = true; + break; + + case GHOST_kKeySpace: + + // increment the current object only if the object is not being + // manipulated. + if (! (m_rotation_settings[m_current_object].m_moving || m_translation_settings[m_current_object].m_moving)) { + m_current_object ++; + if (m_current_object >= m_meshes.size()) { + m_current_object = 0; + } + } + m_window->invalidate(); + + + handled = true; + break; + default : + break; + } + } + + default : + break; + } + + return handled; + +}; + +BSP_GhostTestApp3D:: +~BSP_GhostTestApp3D( +){ + + if (m_window) { + m_system->disposeWindow(m_window); + m_window = NULL; + GHOST_ISystem::disposeSystem(); + m_system = NULL; + } +}; + + void +BSP_GhostTestApp3D:: +DrawPolies( +){ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + for (int i = 0; i < m_meshes.size(); ++i) { + + MT_Transform trans = GetTransform(i); + + float opengl_mat[16]; + trans.getValue(opengl_mat); + + opengl_mat[14] -= 30; + + glPushMatrix(); + glLoadMatrixf(opengl_mat); + + MT_Vector3 color(1.0,1.0,1.0); + + if (i == m_current_object) { + color = MT_Vector3(1.0,0,0); + } + + BSP_MeshDrawer::DrawMesh(m_meshes[i].Ref(),m_render_modes[i]); + + glPopMatrix(); + } + + m_window->swapBuffers(); +} + + void +BSP_GhostTestApp3D:: +InitOpenGl( + const MT_Vector3 &min, + const MT_Vector3 &max +){ + + GLfloat light_diffuse0[] = {1.0, 0.0, 0.0, 0.5}; /* Red diffuse light. */ + GLfloat light_position0[] = {1.0, 1.0, 1.0, 0.0}; /* Infinite light location. */ + + GLfloat light_diffuse1[] = {1.0, 1.0, 1.0, 0.5}; /* Red diffuse light. */ + GLfloat light_position1[] = {1.0, 0, 0, 0.0}; /* Infinite light location. */ + + /* Enable a single OpenGL light. */ + glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse0); + glLightfv(GL_LIGHT0, GL_POSITION, light_position0); + + glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse1); + glLightfv(GL_LIGHT1, GL_POSITION, light_position1); + + glEnable(GL_LIGHT0); + glEnable(GL_LIGHT1); + glEnable(GL_LIGHTING); + + // make sure there is no back face culling. +// glDisable(GL_CULL_FACE); + + + // use two sided lighting model + + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE); + + /* Use depth buffering for hidden surface elimination. */ + glEnable(GL_DEPTH_TEST); + + /* Setup the view of the cube. */ + glMatrixMode(GL_PROJECTION); + + // centre of the box + 3* depth of box + + MT_Vector3 centre = (min + max) * 0.5; + MT_Vector3 diag = max - min; + + float depth = diag.length(); + float distance = 5; + + gluPerspective( + /* field of view in degree */ 40.0, + /* aspect ratio */ 1.0, + /* Z near */ 1.0, + /* Z far */ distance * depth * 2 + ); + glMatrixMode(GL_MODELVIEW); + + gluLookAt( + centre.x(), centre.y(), centre.z() + distance*depth, //eye + centre.x(), centre.y(), centre.z(), //centre + 0.0, 1.0, 0.); /* up is in positive Y direction */ + +} + + + + + + + + + + + + + + + + + + + + + diff --git a/intern/bsp/test/BSP_GhostTest/BSP_GhostTest3D.h b/intern/bsp/test/BSP_GhostTest/BSP_GhostTest3D.h new file mode 100755 index 00000000000..086ee42b903 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_GhostTest3D.h @@ -0,0 +1,165 @@ +/** + * $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 ***** + */ + +#ifndef BSP_GhostTest_h + +#define BSP_GhostTest_h + + + +#include "GHOST_IEventConsumer.h" +#include "MT_Vector3.h" +#include "BSP_TMesh.h" +#include "BSP_MeshDrawer.h" + +#include <vector> + +class GHOST_IWindow; +class GHOST_ISystem; + + +class BSP_GhostTestApp3D : +public GHOST_IEventConsumer +{ +public : + // Construct an instance of the application; + + BSP_GhostTestApp3D( + ); + + // initialize the applicaton + + bool + InitApp( + ); + + // Run the application untill internal return. + void + Run( + ); + + ~BSP_GhostTestApp3D( + ); + + void + SetMesh( + MEM_SmartPtr<BSP_TMesh> mesh + ); + +private : + + struct BSP_RotationSetting { + MT_Scalar m_angle_x; + MT_Scalar m_angle_y; + int x_old; + int y_old; + bool m_moving; + }; + + struct BSP_TranslationSetting { + MT_Scalar m_t_x; + MT_Scalar m_t_y; + MT_Scalar m_t_z; + int x_old; + int y_old; + bool m_moving; + }; + + // Return the transform of object i + + MT_Transform + GetTransform( + int active_object + ); + + // Perform an operation between the first two objects in the + // list + + void + Operate( + int type + ); + + // Swap mesh i and settings with the last mesh in list. + + void + Swap( + int i + ); + + void + DrawPolies( + ); + + void + UpdateFrame( + ); + + MT_Vector3 + UnProject( + const MT_Vector3 & vec + ); + + // Create a frustum and projection matrix to + // look at the bounding box + + void + InitOpenGl( + const MT_Vector3 &min, + const MT_Vector3 &max + ); + + + // inherited from GHOST_IEventConsumer + bool + processEvent( + GHOST_IEvent* event + ); + + GHOST_IWindow *m_window; + GHOST_ISystem *m_system; + + bool m_finish_me_off; + + // List of current meshes. + std::vector< MEM_SmartPtr<BSP_TMesh> > m_meshes; + + std::vector< BSP_RotationSetting> m_rotation_settings; + std::vector< BSP_TranslationSetting> m_translation_settings; + std::vector< MT_Scalar> m_scale_settings; + std::vector< int> m_render_modes; + + int m_current_object; + + +}; + +#endif
\ No newline at end of file diff --git a/intern/bsp/test/BSP_GhostTest/BSP_MeshDrawer.cpp b/intern/bsp/test/BSP_GhostTest/BSP_MeshDrawer.cpp new file mode 100755 index 00000000000..9df6d166263 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_MeshDrawer.cpp @@ -0,0 +1,160 @@ +/** + * $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 ***** + */ + +#include "BSP_MeshDrawer.h" + +#include "BSP_TMesh.h" + +#if defined(WIN32) || defined(__APPLE__) +# ifdef WIN32 +# include <windows.h> +# include <GL/gl.h> +# include <GL/glu.h> +# else // WIN32 +# include <AGL/gl.h> +# endif // WIN32 +#else // defined(WIN32) || defined(__APPLE__) +# include <GL/gl.h> +# include <GL/glu.h> +#endif // defined(WIN32) || defined(__APPLE__) + +#include <vector> + +using namespace std; + + void +BSP_MeshDrawer:: +DrawMesh( + BSP_TMesh &mesh, + int render_mode +){ + + + if (render_mode == e_none) return; + + // decompose polygons into triangles. + + glEnable(GL_LIGHTING); + + + if (render_mode == e_wireframe || render_mode == e_wireframe_shaded) { + + glColor3f(0.0, 0.0, 0.0); + + if (render_mode == e_wireframe) { + glDisable(GL_LIGHTING); + } else { + glEnable(GL_LIGHTING); + } + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(1.0,1.0); + + glBegin(GL_TRIANGLES); + DrawPolies(mesh); + glEnd(); + + glColor3f(1.0, 1.0, 1.0); + glDisable(GL_LIGHTING); + glDisable(GL_POLYGON_OFFSET_FILL); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + glBegin(GL_TRIANGLES); + DrawPolies(mesh); + glEnd(); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } else { + + glEnable(GL_LIGHTING); + + glBegin(GL_TRIANGLES); + DrawPolies(mesh); + glEnd(); + } + + +} + + + void +BSP_MeshDrawer:: +DrawPolies( + BSP_TMesh &mesh +){ + + const vector<BSP_TVertex> & verts = mesh.VertexSet(); + const vector<BSP_TFace> &faces = mesh.FaceSet(); + + // just draw the edges for now. + + vector<BSP_TVertex>::const_iterator vertex_it = verts.begin(); + + + vector<BSP_TFace>::const_iterator faces_it = faces.begin(); + vector<BSP_TFace>::const_iterator faces_end = faces.end(); + + for (;faces_it != faces_end; ++faces_it ){ + + glNormal3f( + faces_it->m_normal.x(), + faces_it->m_normal.y(), + faces_it->m_normal.z() + ); + + glVertex3f( + verts[faces_it->m_verts[0]].m_pos.x(), + verts[faces_it->m_verts[0]].m_pos.y(), + verts[faces_it->m_verts[0]].m_pos.z() + ); + glVertex3f( + verts[faces_it->m_verts[1]].m_pos.x(), + verts[faces_it->m_verts[1]].m_pos.y(), + verts[faces_it->m_verts[1]].m_pos.z() + ); + glVertex3f( + verts[faces_it->m_verts[2]].m_pos.x(), + verts[faces_it->m_verts[2]].m_pos.y(), + verts[faces_it->m_verts[2]].m_pos.z() + ); + } +} + + + + + + + + + + diff --git a/intern/bsp/test/BSP_GhostTest/BSP_MeshDrawer.h b/intern/bsp/test/BSP_GhostTest/BSP_MeshDrawer.h new file mode 100755 index 00000000000..427c6a34f4d --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_MeshDrawer.h @@ -0,0 +1,77 @@ +/** + * $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 ***** + */ + +#ifndef BSP_MeshDrawer_h + +#define BSP_MeshDrawer_h + + + +class BSP_TMesh; +class MT_Vector3; + +enum BSP_TRenderMode { + e_shaded, + e_none, + e_wireframe, + e_wireframe_shaded, + e_first_render_mode = e_shaded, + e_last_render_mode = e_wireframe_shaded +}; + +class BSP_MeshDrawer +{ +public : + static + void + DrawMesh( + BSP_TMesh &mesh, + int render_mode + ); + +private : + + static + void + DrawPolies( + BSP_TMesh &mesh + ); + + + BSP_MeshDrawer( + ); + + ~BSP_MeshDrawer( + ); + +}; + +#endif
\ No newline at end of file diff --git a/intern/bsp/test/BSP_GhostTest/BSP_PlyLoader.cpp b/intern/bsp/test/BSP_GhostTest/BSP_PlyLoader.cpp new file mode 100755 index 00000000000..aa7dfbc3818 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_PlyLoader.cpp @@ -0,0 +1,196 @@ +/** + * $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 ***** + */ + +#include "BSP_PlyLoader.h" + +#include "MT_Vector3.h" +#include "ply.h" + +struct LoadVertex { + float x,y,z; /* the usual 3-space position of a vertex */ +}; + +struct LoadFace { + unsigned char intensity; /* this user attaches intensity to faces */ + unsigned char nverts; /* number of vertex indices in list */ + int *verts; /* vertex index list */ +}; + + + MEM_SmartPtr<BSP_TMesh> +BSP_PlyLoader:: +NewMeshFromFile( + char * file_name, + MT_Vector3 &min, + MT_Vector3 &max + +) { + + min = MT_Vector3(MT_INFINITY,MT_INFINITY,MT_INFINITY); + max = MT_Vector3(-MT_INFINITY,-MT_INFINITY,-MT_INFINITY); + + PlyProperty vert_props[] = { /* list of property information for a vertex */ + {"x", PLY_FLOAT, PLY_FLOAT, offsetof(LoadVertex,x), 0, 0, 0, 0}, + {"y", PLY_FLOAT, PLY_FLOAT, offsetof(LoadVertex,y), 0, 0, 0, 0}, + {"z", PLY_FLOAT, PLY_FLOAT, offsetof(LoadVertex,z), 0, 0, 0, 0}, + }; + + PlyProperty face_props[] = { /* list of property information for a vertex */ + {"vertex_indices", PLY_INT, PLY_INT, offsetof(LoadFace,verts), + 1, PLY_UCHAR, PLY_UCHAR, offsetof(LoadFace,nverts)}, + }; + + MEM_SmartPtr<BSP_TMesh> mesh = new BSP_TMesh; + + if (mesh == NULL) return NULL; + + int i,j; + PlyFile *ply; + int nelems; + char **elist; + int file_type; + float version; + int nprops; + int num_elems; + PlyProperty **plist; + + char *elem_name; + + LoadVertex load_vertex; + LoadFace load_face; + + /* open a PLY file for reading */ + ply = ply_open_for_reading( + file_name, + &nelems, + &elist, + &file_type, + &version + ); + + if (ply == NULL) return NULL; + + /* go through each kind of element that we learned is in the file */ + /* and read them */ + + for (i = 0; i < nelems; i++) { + + /* get the description of the first element */ + + elem_name = elist[i]; + plist = ply_get_element_description (ply, elem_name, &num_elems, &nprops); + + /* print the name of the element, for debugging */ + + /* if we're on vertex elements, read them in */ + + if (equal_strings ("vertex", elem_name)) { + + /* set up for getting vertex elements */ + + ply_get_property (ply, elem_name, &vert_props[0]); + ply_get_property (ply, elem_name, &vert_props[1]); + ply_get_property (ply, elem_name, &vert_props[2]); + + // make some memory for the vertices + mesh->VertexSet().reserve(num_elems); + + /* grab all the vertex elements */ + for (j = 0; j < num_elems; j++) { + + /* grab and element from the file */ + ply_get_element (ply, (void *)&load_vertex); + // pass the vertex into the mesh builder. + + if (load_vertex.x < min.x()) { + min.x() = load_vertex.x; + } else + if (load_vertex.x > max.x()) { + max.x()= load_vertex.x; + } + + if (load_vertex.y < min.y()) { + min.y() = load_vertex.y; + } else + if (load_vertex.y > max.y()) { + max.y()= load_vertex.y; + } + + if (load_vertex.z < min.z()) { + min.z() = load_vertex.z; + } else + if (load_vertex.z > max.z()) { + max.z()= load_vertex.z; + } + + BSP_TVertex my_vert; + my_vert.m_pos = MT_Vector3(load_vertex.x,load_vertex.y,load_vertex.z); + mesh->VertexSet().push_back(my_vert); + } + + + } + + /* if we're on face elements, read them in */ + if (equal_strings ("face", elem_name)) { + + /* set up for getting face elements */ + + ply_get_property (ply, elem_name, &face_props[0]); + + /* grab all the face elements */ + for (j = 0; j < num_elems; j++) { + + ply_get_element (ply, (void *)&load_face); + + int v; + for (v = 2; v< load_face.nverts; v++) { + + BSP_TFace f; + + f.m_verts[0] = load_face.verts[0]; + f.m_verts[1] = load_face.verts[v-1]; + f.m_verts[2] = load_face.verts[v]; + + mesh->BuildNormal(f); + mesh->FaceSet().push_back(f); + } + // free up the memory this pile of shit used to allocate the polygon's vertices + free (load_face.verts); + } + + } + } + /* close the PLY file */ + ply_close (ply); + + return mesh; +}
\ No newline at end of file diff --git a/intern/bsp/test/BSP_GhostTest/BSP_PlyLoader.h b/intern/bsp/test/BSP_GhostTest/BSP_PlyLoader.h new file mode 100755 index 00000000000..5f7a793267e --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_PlyLoader.h @@ -0,0 +1,64 @@ +/** + * $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 ***** + */ + +#ifndef BSP_PlyLoader_h + +#define BSP_PlyLoader_h + +#include "MEM_SmartPtr.h" +#include "BSP_TMesh.h" + +class BSP_PlyLoader { +public : + + static + MEM_SmartPtr<BSP_TMesh> + NewMeshFromFile( + char * file_name, + MT_Vector3 &min, + MT_Vector3 &max + ); + + +private : + + // unimplemented - not for instantiation. + + BSP_PlyLoader( + ); + + ~BSP_PlyLoader( + ); +}; + + + +#endif
\ No newline at end of file diff --git a/intern/bsp/test/BSP_GhostTest/BSP_TMesh.h b/intern/bsp/test/BSP_GhostTest/BSP_TMesh.h new file mode 100755 index 00000000000..d2429cd3330 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/BSP_TMesh.h @@ -0,0 +1,354 @@ +/** + * $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 ***** + */ + +#ifndef BSP_TMesh_h + +#define BSP_TMesh_h + +#include "MT_Point3.h" +#include "MT_Vector3.h" +#include "MT_Transform.h" + +#include "MEM_SmartPtr.h" + +#include <vector> + +#include "CSG_BooleanOps.h" + +/** + * A very basic test mesh. + */ + +struct BSP_TVertex { + MT_Point3 m_pos; +}; + +struct BSP_TFace { + int m_verts[3]; + MT_Vector3 m_normal; +}; + + +class BSP_TMesh { +public : + + std::vector<BSP_TVertex> m_verts; + std::vector<BSP_TFace> m_faces; + + MT_Vector3 m_min,m_max; + + std::vector<BSP_TVertex> & + VertexSet( + ){ + return m_verts; + } + + std::vector<BSP_TFace> & + FaceSet( + ) { + return m_faces; + } + + void + AddFace( + int *verts, + int num_verts + ); + + void + BuildNormal( + BSP_TFace & f + ) const ; + +}; + + + +/** + * some iterator functions to describe the mesh to the BSP module. + */ + +/** + * This class defines 2 C style iterators over a CSG mesh, one for + * vertices and 1 for faces. They conform to the iterator interface + * defined in CSG_BooleanOps.h + */ + +struct VertexIt { + BSP_TMesh * mesh; + BSP_TVertex * pos; + MT_Transform trans; +}; + + +static + void +VertexIt_Destruct( + CSG_VertexIteratorDescriptor * iterator +) { + delete ((VertexIt *)(iterator->it)); + iterator->it = NULL; + delete(iterator); +}; + + +static + int +VertexIt_Done( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + VertexIt * vertex_it = (VertexIt *)it; + + if (vertex_it->pos < vertex_it->mesh->VertexSet().end()) return 0; + return 1; +}; + +static + void +VertexIt_Fill( + CSG_IteratorPtr it, + CSG_IVertex *vert +) { + // assume CSG_IteratorPtr is of the correct type. + VertexIt * vertex_it = (VertexIt *)it; + + MT_Point3 p = vertex_it->pos->m_pos; + p = vertex_it->trans * p; + + p.getValue(vert->position); +}; + +static + void +VertexIt_Step( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + VertexIt * vertex_it = (VertexIt *)it; + + ++(vertex_it->pos); +}; + +static + CSG_VertexIteratorDescriptor * +VertexIt_Construct( + BSP_TMesh *mesh, + MT_Transform trans +){ + // user should have insured mesh is not equal to NULL. + + CSG_VertexIteratorDescriptor * output = new CSG_VertexIteratorDescriptor; + if (output == NULL) return NULL; + output->Done = VertexIt_Done; + output->Fill = VertexIt_Fill; + output->Step = VertexIt_Step; + output->num_elements = mesh->VertexSet().size(); + + VertexIt * v_it = new VertexIt; + v_it->mesh = mesh; + v_it->pos = mesh->VertexSet().begin(); + v_it->trans = trans; + output->it = v_it; + return output; +}; + + +/** + * Face iterator. + */ + +struct FaceIt { + BSP_TMesh * mesh; + BSP_TFace *pos; +}; + + +static + void +FaceIt_Destruct( + CSG_FaceIteratorDescriptor * iterator +) { + delete ((FaceIt *)(iterator->it)); + iterator->it = NULL; + delete(iterator); +}; + + +static + int +FaceIt_Done( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + FaceIt * face_it = (FaceIt *)it; + + if (face_it->pos < face_it->mesh->FaceSet().end()) { + return 0; + } + return 1; +}; + +static + void +FaceIt_Fill( + CSG_IteratorPtr it, + CSG_IFace *face +){ + // assume CSG_IteratorPtr is of the correct type. + FaceIt * face_it = (FaceIt *)it; + // essentially iterating through a triangle fan here. + + face->vertex_index[0] = int(face_it->pos->m_verts[0]); + face->vertex_index[1] = int(face_it->pos->m_verts[1]); + face->vertex_index[2] = int(face_it->pos->m_verts[2]); + + face->vertex_number = 3; +}; + +static + void +FaceIt_Step( + CSG_IteratorPtr it +) { + // assume CSG_IteratorPtr is of the correct type. + FaceIt * face_it = (FaceIt *)it; + + face_it->pos ++; +}; + +static + CSG_FaceIteratorDescriptor * +FaceIt_Construct( + BSP_TMesh * mesh +) { + CSG_FaceIteratorDescriptor * output = new CSG_FaceIteratorDescriptor; + if (output == NULL) return NULL; + + output->Done = FaceIt_Done; + output->Fill = FaceIt_Fill; + output->Step = FaceIt_Step; + + output->num_elements = mesh->FaceSet().size(); + + FaceIt * f_it = new FaceIt; + f_it->mesh = mesh; + f_it->pos = mesh->FaceSet().begin(); + + output->it = f_it; + + return output; +}; + +/** + * Some Build functions. + */ + +static + MEM_SmartPtr<BSP_TMesh> +BuildMesh( + CSG_MeshPropertyDescriptor &props, + CSG_FaceIteratorDescriptor &face_it, + CSG_VertexIteratorDescriptor &vertex_it +) { + MEM_SmartPtr<BSP_TMesh> mesh = new BSP_TMesh(); + + CSG_IVertex vert; + + while (!vertex_it.Done(vertex_it.it)) { + + vertex_it.Fill(vertex_it.it,&vert); + + BSP_TVertex v; + v.m_pos = MT_Point3(vert.position); + mesh->VertexSet().push_back(v); + + vertex_it.Step(vertex_it.it); + } + + + CSG_IFace face; + + while (!face_it.Done(face_it.it)) { + face_it.Fill(face_it.it,&face); + + BSP_TFace f; + + f.m_verts[0] = face.vertex_index[0], + f.m_verts[1] = face.vertex_index[1], + f.m_verts[2] = face.vertex_index[2], + + mesh->BuildNormal(f); + + mesh->FaceSet().push_back(f); + + face_it.Step(face_it.it); + } + + return mesh; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#endif
\ No newline at end of file diff --git a/intern/bsp/test/BSP_GhostTest/Makefile b/intern/bsp/test/BSP_GhostTest/Makefile new file mode 100644 index 00000000000..06dded40a17 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/Makefile @@ -0,0 +1,56 @@ +# +# $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 ***** +# BSP_GhostTest Makefile +# + +LIBNAME = BSP_GhostTest +SOURCEDIR = intern/bsp/test/$(LIBNAME) +DIR = $(OCGDIR)/$(SOURCEDIR) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_2_CPP_WARNINGS) + +CPPFLAGS += -I$(OPENGL_HEADERS) +CPPFLAGS += -I$(NAN_BSP)/include +CPPFLAGS += -I$(NAN_MEMUTIL)/include +CPPFLAGS += -I$(NAN_CONTAINER)/include +CPPFLAGS += -I$(NAN_MOTO)/include +CPPFLAGS += -I$(NAN_GHOST)/include +CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I../../extern/ + +ifeq ($(OS),windows) + CPPFLAGS += -I$(NAN_LIBDIR)/windows/glut-3.7/include +endif + + + diff --git a/intern/bsp/test/BSP_GhostTest/main.cpp b/intern/bsp/test/BSP_GhostTest/main.cpp new file mode 100755 index 00000000000..e7875047651 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/main.cpp @@ -0,0 +1,147 @@ +/** + * $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 ***** + */ + +#include "BSP_GhostTest3D.h" + +#include "BSP_TMesh.h" +#include "MEM_SmartPtr.h" +#include "BSP_PlyLoader.h" + +#include <iostream> + +using namespace std; +#if 1 + MEM_SmartPtr<BSP_TMesh> +NewTestMesh( + int x, + int y, + MT_Scalar fx, + MT_Scalar fy, + MT_Scalar ampx, + MT_Scalar ampy, + MT_Scalar sx, + MT_Scalar sy +) { + + MEM_SmartPtr<BSP_TMesh> output = new BSP_TMesh; + + std::vector<BSP_TVertex> &verts = output->VertexSet(); + + int i,j; + + MT_Scalar x_scale = fx*MT_PI/x; + MT_Scalar y_scale = fy*MT_PI/y; + + MT_Scalar fsx = sx/x; + MT_Scalar fsy = sy/y; + + for (j = 0; j < y; j++) { + for (i = 0; i < x; i++) { + float z = ampx*sin(x_scale * i) + ampy*sin(y_scale * j); + + MT_Vector3 val(i*fsx - sx/2,j*fsy - sy/2,z); + + BSP_TVertex chuff; + chuff.m_pos = val; + verts.push_back(chuff); + } + } + + int poly[4]; + + for (j = 0; j < (y-1); j++) { + for (i = 0; i < (x-1); i++) { + + poly[0] = j*x + i; + poly[1] = poly[0] + 1; + poly[2] = poly[1] + y; + poly[3] = poly[2] -1; + + output->AddFace(poly,4); + } + } + + output->m_min = MT_Vector3(-sx/2,-sy/2,-ampx -ampy); + output->m_max = MT_Vector3(sx/2,sy/2,ampx + ampy); + + return output; +} +#endif + + +int main() { + + MT_Vector3 min,max; + MT_Vector3 min2,max2; + +#if 1 + MEM_SmartPtr<BSP_TMesh> mesh1 = BSP_PlyLoader::NewMeshFromFile("bsp_cube.ply",min,max); + MEM_SmartPtr<BSP_TMesh> mesh2 = BSP_PlyLoader::NewMeshFromFile("bsp_cube.ply",min2,max2); + + mesh1->m_min = min; + mesh1->m_max = max; + mesh2->m_min = min2; + mesh1->m_max = max2; + +#else + MEM_SmartPtr<BSP_TMesh> mesh1 = NewTestMesh(10,10,2,2,4,4,20,20); + MEM_SmartPtr<BSP_TMesh> mesh2 = NewTestMesh(10,10,2,2,4,4,20,20); +#endif + + if (!mesh1) { + cout << "could not load mesh!"; + return 0; + } + + + +// MEM_SmartPtr<BSP_TMesh> mesh2 = new BSP_TMesh(mesh1.Ref()); + + BSP_GhostTestApp3D app; + + cout << "Mesh polygons :" << mesh1->FaceSet().size() << "\n"; + cout << "Mesh vertices :" << mesh1->VertexSet().size() << "\n"; + + app.SetMesh(mesh1); + app.SetMesh(mesh2); + + + app.InitApp(); + + app.Run(); + + return 0; + +} + + + + diff --git a/intern/bsp/test/BSP_GhostTest/ply.h b/intern/bsp/test/BSP_GhostTest/ply.h new file mode 100755 index 00000000000..7947d224c5f --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/ply.h @@ -0,0 +1,200 @@ +/** + * $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 ***** + */ + +/* + +Header for PLY polygon files. + +- Greg Turk, March 1994 + +A PLY file contains a single polygonal _object_. + +An object is composed of lists of _elements_. Typical elements are +vertices, faces, edges and materials. + +Each type of element for a given object has one or more _properties_ +associated with the element type. For instance, a vertex element may +have as properties three floating-point values x,y,z and three unsigned +chars for red, green and blue. + +--------------------------------------------------------------- + +Copyright (c) 1994 The Board of Trustees of The Leland Stanford +Junior University. All rights reserved. + +Permission to use, copy, modify and distribute this software and its +documentation for any purpose is hereby granted without fee, provided +that the above copyright notice and this permission notice appear in +all copies of this software and that you do not sell the software. + +THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, +EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY +WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +*/ + +#ifndef __PLY_H__ +#define __PLY_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdio.h> +#include <stddef.h> + +#define PLY_ASCII 1 /* ascii PLY file */ +#define PLY_BINARY_BE 2 /* binary PLY file, big endian */ +#define PLY_BINARY_LE 3 /* binary PLY file, little endian */ + +#define PLY_OKAY 0 /* ply routine worked okay */ +#define PLY_ERROR -1 /* error in ply routine */ + +/* scalar data types supported by PLY format */ + +#define PLY_START_TYPE 0 +#define PLY_CHAR 1 +#define PLY_SHORT 2 +#define PLY_INT 3 +#define PLY_UCHAR 4 +#define PLY_USHORT 5 +#define PLY_UINT 6 +#define PLY_FLOAT 7 +#define PLY_DOUBLE 8 +#define PLY_END_TYPE 9 + +#define PLY_SCALAR 0 +#define PLY_LIST 1 + + +typedef struct PlyProperty { /* description of a property */ + + char *name; /* property name */ + int external_type; /* file's data type */ + int internal_type; /* program's data type */ + int offset; /* offset bytes of prop in a struct */ + + int is_list; /* 1 = list, 0 = scalar */ + int count_external; /* file's count type */ + int count_internal; /* program's count type */ + int count_offset; /* offset byte for list count */ + +} PlyProperty; + +typedef struct PlyElement { /* description of an element */ + char *name; /* element name */ + int num; /* number of elements in this object */ + int size; /* size of element (bytes) or -1 if variable */ + int nprops; /* number of properties for this element */ + PlyProperty **props; /* list of properties in the file */ + char *store_prop; /* flags: property wanted by user? */ + int other_offset; /* offset to un-asked-for props, or -1 if none*/ + int other_size; /* size of other_props structure */ +} PlyElement; + +typedef struct PlyOtherProp { /* describes other properties in an element */ + char *name; /* element name */ + int size; /* size of other_props */ + int nprops; /* number of properties in other_props */ + PlyProperty **props; /* list of properties in other_props */ +} PlyOtherProp; + +typedef struct OtherData { /* for storing other_props for an other element */ + void *other_props; +} OtherData; + +typedef struct OtherElem { /* data for one "other" element */ + char *elem_name; /* names of other elements */ + int elem_count; /* count of instances of each element */ + OtherData **other_data; /* actual property data for the elements */ + PlyOtherProp *other_props; /* description of the property data */ +} OtherElem; + +typedef struct PlyOtherElems { /* "other" elements, not interpreted by user */ + int num_elems; /* number of other elements */ + OtherElem *other_list; /* list of data for other elements */ +} PlyOtherElems; + +typedef struct PlyFile { /* description of PLY file */ + FILE *fp; /* file pointer */ + int file_type; /* ascii or binary */ + float version; /* version number of file */ + int nelems; /* number of elements of object */ + PlyElement **elems; /* list of elements */ + int num_comments; /* number of comments */ + char **comments; /* list of comments */ + int num_obj_info; /* number of items of object information */ + char **obj_info; /* list of object info items */ + PlyElement *which_elem; /* which element we're currently writing */ + PlyOtherElems *other_elems; /* "other" elements from a PLY file */ +} PlyFile; + +/* memory allocation */ +static char *my_alloc(); +#define myalloc(mem_size) my_alloc((mem_size), __LINE__, __FILE__) + + +/*** delcaration of routines ***/ + +extern PlyFile *ply_write(FILE *, int, char **, int); +extern PlyFile *ply_open_for_writing(char *, int, char **, int, float *); +extern void ply_describe_element(PlyFile *, char *, int, int, PlyProperty *); +extern void ply_describe_property(PlyFile *, char *, PlyProperty *); +extern void ply_element_count(PlyFile *, char *, int); +extern void ply_header_complete(PlyFile *); +extern void ply_put_element_setup(PlyFile *, char *); +extern void ply_put_element(PlyFile *, void *); +extern void ply_put_comment(PlyFile *, char *); +extern void ply_put_obj_info(PlyFile *, char *); +extern PlyFile *ply_read(FILE *, int *, char ***); +extern PlyFile *ply_open_for_reading( char *, int *, char ***, int *, float *); +extern PlyProperty **ply_get_element_description(PlyFile *, char *, int*, int*); +extern void ply_get_element_setup( PlyFile *, char *, int, PlyProperty *); +extern void ply_get_property(PlyFile *, char *, PlyProperty *); +extern PlyOtherProp *ply_get_other_properties(PlyFile *, char *, int); +extern void ply_get_element(PlyFile *, void *); +extern char **ply_get_comments(PlyFile *, int *); +extern char **ply_get_obj_info(PlyFile *, int *); +extern void ply_close(PlyFile *); +extern void ply_get_info(PlyFile *, float *, int *); +extern PlyOtherElems *ply_get_other_element (PlyFile *, char *, int); +extern void ply_describe_other_elements ( PlyFile *, PlyOtherElems *); +extern void ply_put_other_elements (PlyFile *); +extern void ply_free_other_elements (PlyOtherElems *); + +extern int equal_strings(char *, char *); + + +#ifdef __cplusplus +} +#endif +#endif /* !__PLY_H__ */ + diff --git a/intern/bsp/test/BSP_GhostTest/plyfile.c b/intern/bsp/test/BSP_GhostTest/plyfile.c new file mode 100755 index 00000000000..1fda4c77454 --- /dev/null +++ b/intern/bsp/test/BSP_GhostTest/plyfile.c @@ -0,0 +1,2548 @@ +/** + * $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 ***** + */ + +/* + + +The interface routines for reading and writing PLY polygon files. + +Greg Turk, February 1994 + +--------------------------------------------------------------- + +A PLY file contains a single polygonal _object_. + +An object is composed of lists of _elements_. Typical elements are +vertices, faces, edges and materials. + +Each type of element for a given object has one or more _properties_ +associated with the element type. For instance, a vertex element may +have as properties the floating-point values x,y,z and the three unsigned +chars representing red, green and blue. + +--------------------------------------------------------------- + +Copyright (c) 1994 The Board of Trustees of The Leland Stanford +Junior University. All rights reserved. + +Permission to use, copy, modify and distribute this software and its +documentation for any purpose is hereby granted without fee, provided +that the above copyright notice and this permission notice appear in +all copies of this software and that you do not sell the software. + +THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, +EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY +WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <string.h> +#include "ply.h" + +char *type_names[] = { +"invalid", +"char", "short", "int", +"uchar", "ushort", "uint", +"float", "double", +}; + +int ply_type_size[] = { + 0, 1, 2, 4, 1, 2, 4, 4, 8 +}; + +#define NO_OTHER_PROPS -1 + +#define DONT_STORE_PROP 0 +#define STORE_PROP 1 + +#define OTHER_PROP 0 +#define NAMED_PROP 1 + + +/* returns 1 if strings are equal, 0 if not */ +int equal_strings(char *, char *); + +/* find an element in a plyfile's list */ +PlyElement *find_element(PlyFile *, char *); + +/* find a property in an element's list */ +PlyProperty *find_property(PlyElement *, char *, int *); + +/* write to a file the word describing a PLY file data type */ +void write_scalar_type (FILE *, int); + +/* read a line from a file and break it up into separate words */ +char **get_words(FILE *, int *, char **); +char **old_get_words(FILE *, int *); + +/* write an item to a file */ +void write_binary_item(FILE *, int, unsigned int, double, int); +void write_ascii_item(FILE *, int, unsigned int, double, int); +double old_write_ascii_item(FILE *, char *, int); + +/* add information to a PLY file descriptor */ +void add_element(PlyFile *, char **); +void add_property(PlyFile *, char **); +void add_comment(PlyFile *, char *); +void add_obj_info(PlyFile *, char *); + +/* copy a property */ +void copy_property(PlyProperty *, PlyProperty *); + +/* store a value into where a pointer and a type specify */ +void store_item(char *, int, int, unsigned int, double); + +/* return the value of a stored item */ +void get_stored_item( void *, int, int *, unsigned int *, double *); + +/* return the value stored in an item, given ptr to it and its type */ +double get_item_value(char *, int); + +/* get binary or ascii item and store it according to ptr and type */ +void get_ascii_item(char *, int, int *, unsigned int *, double *); +void get_binary_item(FILE *, int, int *, unsigned int *, double *); + +/* get a bunch of elements from a file */ +void ascii_get_element(PlyFile *, char *); +void binary_get_element(PlyFile *, char *); + +/* memory allocation */ +char *my_alloc(int, int, char *); + + +/*************/ +/* Writing */ +/*************/ + + +/****************************************************************************** +Given a file pointer, get ready to write PLY data to the file. + +Entry: + fp - the given file pointer + nelems - number of elements in object + elem_names - list of element names + file_type - file type, either ascii or binary + +Exit: + returns a pointer to a PlyFile, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *ply_write( + FILE *fp, + int nelems, + char **elem_names, + int file_type +) +{ + int i; + PlyFile *plyfile; + PlyElement *elem; + + /* check for NULL file pointer */ + if (fp == NULL) + return (NULL); + + /* create a record for this object */ + + plyfile = (PlyFile *) myalloc (sizeof (PlyFile)); + plyfile->file_type = file_type; + plyfile->num_comments = 0; + plyfile->num_obj_info = 0; + plyfile->nelems = nelems; + plyfile->version = 1.0; + plyfile->fp = fp; + plyfile->other_elems = NULL; + + /* tuck aside the names of the elements */ + + plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *) * nelems); + for (i = 0; i < nelems; i++) { + elem = (PlyElement *) myalloc (sizeof (PlyElement)); + plyfile->elems[i] = elem; + elem->name = strdup (elem_names[i]); + elem->num = 0; + elem->nprops = 0; + } + + /* return pointer to the file descriptor */ + return (plyfile); +} + + +/****************************************************************************** +Open a polygon file for writing. + +Entry: + filename - name of file to read from + nelems - number of elements in object + elem_names - list of element names + file_type - file type, either ascii or binary + +Exit: + version - version number of PLY file + returns a file identifier, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *ply_open_for_writing( + char *filename, + int nelems, + char **elem_names, + int file_type, + float *version +) +{ + PlyFile *plyfile; + char *name; + FILE *fp; + + /* tack on the extension .ply, if necessary */ + + name = (char *) myalloc (sizeof (char) * (strlen (filename) + 5)); + strcpy (name, filename); + if (strlen (name) < 4 || + strcmp (name + strlen (name) - 4, ".ply") != 0) + strcat (name, ".ply"); + + /* open the file for writing */ + + fp = fopen (name, "w"); + if (fp == NULL) { + return (NULL); + } + + /* create the actual PlyFile structure */ + + plyfile = ply_write (fp, nelems, elem_names, file_type); + if (plyfile == NULL) + return (NULL); + + /* say what PLY file version number we're writing */ + *version = plyfile->version; + + /* return pointer to the file descriptor */ + return (plyfile); +} + + +/****************************************************************************** +Describe an element, including its properties and how many will be written +to the file. + +Entry: + plyfile - file identifier + elem_name - name of element that information is being specified about + nelems - number of elements of this type to be written + nprops - number of properties contained in the element + prop_list - list of properties +******************************************************************************/ + +void ply_describe_element( + PlyFile *plyfile, + char *elem_name, + int nelems, + int nprops, + PlyProperty *prop_list +) +{ + int i; + PlyElement *elem; + PlyProperty *prop; + + /* look for appropriate element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf(stderr,"ply_describe_element: can't find element '%s'\n",elem_name); + exit (-1); + } + + elem->num = nelems; + + /* copy the list of properties */ + + elem->nprops = nprops; + elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *) * nprops); + elem->store_prop = (char *) myalloc (sizeof (char) * nprops); + + for (i = 0; i < nprops; i++) { + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + elem->props[i] = prop; + elem->store_prop[i] = NAMED_PROP; + copy_property (prop, &prop_list[i]); + } +} + + +/****************************************************************************** +Describe a property of an element. + +Entry: + plyfile - file identifier + elem_name - name of element that information is being specified about + prop - the new property +******************************************************************************/ + +void ply_describe_property( + PlyFile *plyfile, + char *elem_name, + PlyProperty *prop +) +{ + PlyElement *elem; + PlyProperty *elem_prop; + + /* look for appropriate element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf(stderr, "ply_describe_property: can't find element '%s'\n", + elem_name); + return; + } + + /* create room for new property */ + + if (elem->nprops == 0) { + elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *)); + elem->store_prop = (char *) myalloc (sizeof (char)); + elem->nprops = 1; + } + else { + elem->nprops++; + elem->props = (PlyProperty **) + realloc (elem->props, sizeof (PlyProperty *) * elem->nprops); + elem->store_prop = (char *) + realloc (elem->store_prop, sizeof (char) * elem->nprops); + } + + /* copy the new property */ + + elem_prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + elem->props[elem->nprops - 1] = elem_prop; + elem->store_prop[elem->nprops - 1] = NAMED_PROP; + copy_property (elem_prop, prop); +} + + +/****************************************************************************** +Describe what the "other" properties are that are to be stored, and where +they are in an element. +******************************************************************************/ + +void ply_describe_other_properties( + PlyFile *plyfile, + PlyOtherProp *other, + int offset +) +{ + int i; + PlyElement *elem; + PlyProperty *prop; + + /* look for appropriate element */ + elem = find_element (plyfile, other->name); + if (elem == NULL) { + fprintf(stderr, "ply_describe_other_properties: can't find element '%s'\n", + other->name); + return; + } + + /* create room for other properties */ + + if (elem->nprops == 0) { + elem->props = (PlyProperty **) + myalloc (sizeof (PlyProperty *) * other->nprops); + elem->store_prop = (char *) myalloc (sizeof (char) * other->nprops); + elem->nprops = 0; + } + else { + int newsize; + newsize = elem->nprops + other->nprops; + elem->props = (PlyProperty **) + realloc (elem->props, sizeof (PlyProperty *) * newsize); + elem->store_prop = (char *) + realloc (elem->store_prop, sizeof (char) * newsize); + } + + /* copy the other properties */ + + for (i = 0; i < other->nprops; i++) { + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + copy_property (prop, other->props[i]); + elem->props[elem->nprops] = prop; + elem->store_prop[elem->nprops] = OTHER_PROP; + elem->nprops++; + } + + /* save other info about other properties */ + elem->other_size = other->size; + elem->other_offset = offset; +} + + +/****************************************************************************** +State how many of a given element will be written. + +Entry: + plyfile - file identifier + elem_name - name of element that information is being specified about + nelems - number of elements of this type to be written +******************************************************************************/ + +void ply_element_count( + PlyFile *plyfile, + char *elem_name, + int nelems +) +{ + PlyElement *elem; + + /* look for appropriate element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf(stderr,"ply_element_count: can't find element '%s'\n",elem_name); + exit (-1); + } + + elem->num = nelems; +} + + +/****************************************************************************** +Signal that we've described everything a PLY file's header and that the +header should be written to the file. + +Entry: + plyfile - file identifier +******************************************************************************/ + +void ply_header_complete(PlyFile *plyfile) +{ + int i,j; + FILE *fp = plyfile->fp; + PlyElement *elem; + PlyProperty *prop; + + fprintf (fp, "ply\n"); + + switch (plyfile->file_type) { + case PLY_ASCII: + fprintf (fp, "format ascii 1.0\n"); + break; + case PLY_BINARY_BE: + fprintf (fp, "format binary_big_endian 1.0\n"); + break; + case PLY_BINARY_LE: + fprintf (fp, "format binary_little_endian 1.0\n"); + break; + default: + fprintf (stderr, "ply_header_complete: bad file type = %d\n", + plyfile->file_type); + exit (-1); + } + + /* write out the comments */ + + for (i = 0; i < plyfile->num_comments; i++) + fprintf (fp, "comment %s\n", plyfile->comments[i]); + + /* write out object information */ + + for (i = 0; i < plyfile->num_obj_info; i++) + fprintf (fp, "obj_info %s\n", plyfile->obj_info[i]); + + /* write out information about each element */ + + for (i = 0; i < plyfile->nelems; i++) { + + elem = plyfile->elems[i]; + fprintf (fp, "element %s %d\n", elem->name, elem->num); + + /* write out each property */ + for (j = 0; j < elem->nprops; j++) { + prop = elem->props[j]; + if (prop->is_list) { + fprintf (fp, "property list "); + write_scalar_type (fp, prop->count_external); + fprintf (fp, " "); + write_scalar_type (fp, prop->external_type); + fprintf (fp, " %s\n", prop->name); + } + else { + fprintf (fp, "property "); + write_scalar_type (fp, prop->external_type); + fprintf (fp, " %s\n", prop->name); + } + } + } + + fprintf (fp, "end_header\n"); +} + + +/****************************************************************************** +Specify which elements are going to be written. This should be called +before a call to the routine ply_put_element(). + +Entry: + plyfile - file identifier + elem_name - name of element we're talking about +******************************************************************************/ + +void ply_put_element_setup(PlyFile *plyfile, char *elem_name) +{ + PlyElement *elem; + + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf(stderr, "ply_elements_setup: can't find element '%s'\n", elem_name); + exit (-1); + } + + plyfile->which_elem = elem; +} + + +/****************************************************************************** +Write an element to the file. This routine assumes that we're +writing the type of element specified in the last call to the routine +ply_put_element_setup(). + +Entry: + plyfile - file identifier + elem_ptr - pointer to the element +******************************************************************************/ + +void ply_put_element(PlyFile *plyfile, void *elem_ptr) +{ + int j,k; + FILE *fp = plyfile->fp; + PlyElement *elem; + PlyProperty *prop; + char *elem_data,*item; + char **item_ptr; + int list_count; + int item_size; + int int_val; + unsigned int uint_val; + double double_val; + char **other_ptr; + + elem = plyfile->which_elem; + elem_data = elem_ptr; + other_ptr = (char **) (((char *) elem_ptr) + elem->other_offset); + + /* write out either to an ascii or binary file */ + + if (plyfile->file_type == PLY_ASCII) { + + /* write an ascii file */ + + /* write out each property of the element */ + for (j = 0; j < elem->nprops; j++) { + prop = elem->props[j]; + if (elem->store_prop[j] == OTHER_PROP) + elem_data = *other_ptr; + else + elem_data = elem_ptr; + if (prop->is_list) { + item = elem_data + prop->count_offset; + get_stored_item ((void *) item, prop->count_internal, + &int_val, &uint_val, &double_val); + write_ascii_item (fp, int_val, uint_val, double_val, + prop->count_external); + list_count = uint_val; + item_ptr = (char **) (elem_data + prop->offset); + item = item_ptr[0]; + item_size = ply_type_size[prop->internal_type]; + for (k = 0; k < list_count; k++) { + get_stored_item ((void *) item, prop->internal_type, + &int_val, &uint_val, &double_val); + write_ascii_item (fp, int_val, uint_val, double_val, + prop->external_type); + item += item_size; + } + } + else { + item = elem_data + prop->offset; + get_stored_item ((void *) item, prop->internal_type, + &int_val, &uint_val, &double_val); + write_ascii_item (fp, int_val, uint_val, double_val, + prop->external_type); + } + } + + fprintf (fp, "\n"); + } + else { + + /* write a binary file */ + + /* write out each property of the element */ + for (j = 0; j < elem->nprops; j++) { + prop = elem->props[j]; + if (elem->store_prop[j] == OTHER_PROP) + elem_data = *other_ptr; + else + elem_data = elem_ptr; + if (prop->is_list) { + item = elem_data + prop->count_offset; + item_size = ply_type_size[prop->count_internal]; + get_stored_item ((void *) item, prop->count_internal, + &int_val, &uint_val, &double_val); + write_binary_item (fp, int_val, uint_val, double_val, + prop->count_external); + list_count = uint_val; + item_ptr = (char **) (elem_data + prop->offset); + item = item_ptr[0]; + item_size = ply_type_size[prop->internal_type]; + for (k = 0; k < list_count; k++) { + get_stored_item ((void *) item, prop->internal_type, + &int_val, &uint_val, &double_val); + write_binary_item (fp, int_val, uint_val, double_val, + prop->external_type); + item += item_size; + } + } + else { + item = elem_data + prop->offset; + item_size = ply_type_size[prop->internal_type]; + get_stored_item ((void *) item, prop->internal_type, + &int_val, &uint_val, &double_val); + write_binary_item (fp, int_val, uint_val, double_val, + prop->external_type); + } + } + + } +} + + +/****************************************************************************** +Specify a comment that will be written in the header. + +Entry: + plyfile - file identifier + comment - the comment to be written +******************************************************************************/ + +void ply_put_comment(PlyFile *plyfile, char *comment) +{ + /* (re)allocate space for new comment */ + if (plyfile->num_comments == 0) + plyfile->comments = (char **) myalloc (sizeof (char *)); + else + plyfile->comments = (char **) realloc (plyfile->comments, + sizeof (char *) * (plyfile->num_comments + 1)); + + /* add comment to list */ + plyfile->comments[plyfile->num_comments] = strdup (comment); + plyfile->num_comments++; +} + + +/****************************************************************************** +Specify a piece of object information (arbitrary text) that will be written +in the header. + +Entry: + plyfile - file identifier + obj_info - the text information to be written +******************************************************************************/ + +void ply_put_obj_info(PlyFile *plyfile, char *obj_info) +{ + /* (re)allocate space for new info */ + if (plyfile->num_obj_info == 0) + plyfile->obj_info = (char **) myalloc (sizeof (char *)); + else + plyfile->obj_info = (char **) realloc (plyfile->obj_info, + sizeof (char *) * (plyfile->num_obj_info + 1)); + + /* add info to list */ + plyfile->obj_info[plyfile->num_obj_info] = strdup (obj_info); + plyfile->num_obj_info++; +} + + + + + + + +/*************/ +/* Reading */ +/*************/ + + + +/****************************************************************************** +Given a file pointer, get ready to read PLY data from the file. + +Entry: + fp - the given file pointer + +Exit: + nelems - number of elements in object + elem_names - list of element names + returns a pointer to a PlyFile, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *ply_read(FILE *fp, int *nelems, char ***elem_names) +{ + int i,j; + PlyFile *plyfile; + int nwords; + char **words; + int found_format = 0; + char **elist; + PlyElement *elem; + char *orig_line; + + /* check for NULL file pointer */ + if (fp == NULL) + return (NULL); + + /* create record for this object */ + + plyfile = (PlyFile *) myalloc (sizeof (PlyFile)); + plyfile->nelems = 0; + plyfile->comments = NULL; + plyfile->num_comments = 0; + plyfile->obj_info = NULL; + plyfile->num_obj_info = 0; + plyfile->fp = fp; + plyfile->other_elems = NULL; + + /* read and parse the file's header */ + + words = get_words (plyfile->fp, &nwords, &orig_line); + if (!words || !equal_strings (words[0], "ply")) + return (NULL); + + while (words) { + + /* parse words */ + + if (equal_strings (words[0], "format")) { + if (nwords != 3) + return (NULL); + if (equal_strings (words[1], "ascii")) + plyfile->file_type = PLY_ASCII; + else if (equal_strings (words[1], "binary_big_endian")) + plyfile->file_type = PLY_BINARY_BE; + else if (equal_strings (words[1], "binary_little_endian")) + plyfile->file_type = PLY_BINARY_LE; + else + return (NULL); + plyfile->version = (float)atof (words[2]); + found_format = 1; + } + else if (equal_strings (words[0], "element")) + add_element (plyfile, words); + else if (equal_strings (words[0], "property")) + add_property (plyfile, words); + else if (equal_strings (words[0], "comment")) + add_comment (plyfile, orig_line); + else if (equal_strings (words[0], "obj_info")) + add_obj_info (plyfile, orig_line); + else if (equal_strings (words[0], "end_header")) + break; + + /* free up words space */ + free (words); + + words = get_words (plyfile->fp, &nwords, &orig_line); + } + + /* create tags for each property of each element, to be used */ + /* later to say whether or not to store each property for the user */ + + for (i = 0; i < plyfile->nelems; i++) { + elem = plyfile->elems[i]; + elem->store_prop = (char *) myalloc (sizeof (char) * elem->nprops); + for (j = 0; j < elem->nprops; j++) + elem->store_prop[j] = DONT_STORE_PROP; + elem->other_offset = NO_OTHER_PROPS; /* no "other" props by default */ + } + + /* set return values about the elements */ + + elist = (char **) myalloc (sizeof (char *) * plyfile->nelems); + for (i = 0; i < plyfile->nelems; i++) + elist[i] = strdup (plyfile->elems[i]->name); + + *elem_names = elist; + *nelems = plyfile->nelems; + + /* return a pointer to the file's information */ + + return (plyfile); +} + + +/****************************************************************************** +Open a polygon file for reading. + +Entry: + filename - name of file to read from + +Exit: + nelems - number of elements in object + elem_names - list of element names + file_type - file type, either ascii or binary + version - version number of PLY file + returns a file identifier, used to refer to this file, or NULL if error +******************************************************************************/ + +PlyFile *ply_open_for_reading( + char *filename, + int *nelems, + char ***elem_names, + int *file_type, + float *version +) +{ + FILE *fp; + PlyFile *plyfile; + char *name; + + /* tack on the extension .ply, if necessary */ + + name = (char *) myalloc (sizeof (char) * (strlen (filename) + 5)); + strcpy (name, filename); + if (strlen (name) < 4 || + strcmp (name + strlen (name) - 4, ".ply") != 0) + strcat (name, ".ply"); + + /* open the file for reading */ + + fp = fopen (name, "r"); + if (fp == NULL) + return (NULL); + + /* create the PlyFile data structure */ + + plyfile = ply_read (fp, nelems, elem_names); + + /* determine the file type and version */ + + *file_type = plyfile->file_type; + *version = plyfile->version; + + /* return a pointer to the file's information */ + + return (plyfile); +} + + +/****************************************************************************** +Get information about a particular element. + +Entry: + plyfile - file identifier + elem_name - name of element to get information about + +Exit: + nelems - number of elements of this type in the file + nprops - number of properties + returns a list of properties, or NULL if the file doesn't contain that elem +******************************************************************************/ + +PlyProperty **ply_get_element_description( + PlyFile *plyfile, + char *elem_name, + int *nelems, + int *nprops +) +{ + int i; + PlyElement *elem; + PlyProperty *prop; + PlyProperty **prop_list; + + /* find information about the element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) + return (NULL); + + *nelems = elem->num; + *nprops = elem->nprops; + + /* make a copy of the element's property list */ + prop_list = (PlyProperty **) myalloc (sizeof (PlyProperty *) * elem->nprops); + for (i = 0; i < elem->nprops; i++) { + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + copy_property (prop, elem->props[i]); + prop_list[i] = prop; + } + + /* return this duplicate property list */ + return (prop_list); +} + + +/****************************************************************************** +Specify which properties of an element are to be returned. This should be +called before a call to the routine ply_get_element(). + +Entry: + plyfile - file identifier + elem_name - which element we're talking about + nprops - number of properties + prop_list - list of properties +******************************************************************************/ + +void ply_get_element_setup( + PlyFile *plyfile, + char *elem_name, + int nprops, + PlyProperty *prop_list +) +{ + int i; + PlyElement *elem; + PlyProperty *prop; + int index; + + /* find information about the element */ + elem = find_element (plyfile, elem_name); + plyfile->which_elem = elem; + + /* deposit the property information into the element's description */ + for (i = 0; i < nprops; i++) { + + /* look for actual property */ + prop = find_property (elem, prop_list[i].name, &index); + if (prop == NULL) { + fprintf (stderr, "Warning: Can't find property '%s' in element '%s'\n", + prop_list[i].name, elem_name); + continue; + } + + /* store its description */ + prop->internal_type = prop_list[i].internal_type; + prop->offset = prop_list[i].offset; + prop->count_internal = prop_list[i].count_internal; + prop->count_offset = prop_list[i].count_offset; + + /* specify that the user wants this property */ + elem->store_prop[index] = STORE_PROP; + } +} + + +/****************************************************************************** +Specify a property of an element that is to be returned. This should be +called (usually multiple times) before a call to the routine ply_get_element(). +This routine should be used in preference to the less flexible old routine +called ply_get_element_setup(). + +Entry: + plyfile - file identifier + elem_name - which element we're talking about + prop - property to add to those that will be returned +******************************************************************************/ + +void ply_get_property( + PlyFile *plyfile, + char *elem_name, + PlyProperty *prop +) +{ + PlyElement *elem; + PlyProperty *prop_ptr; + int index; + + /* find information about the element */ + elem = find_element (plyfile, elem_name); + plyfile->which_elem = elem; + + /* deposit the property information into the element's description */ + + prop_ptr = find_property (elem, prop->name, &index); + if (prop_ptr == NULL) { + fprintf (stderr, "Warning: Can't find property '%s' in element '%s'\n", + prop->name, elem_name); + return; + } + prop_ptr->internal_type = prop->internal_type; + prop_ptr->offset = prop->offset; + prop_ptr->count_internal = prop->count_internal; + prop_ptr->count_offset = prop->count_offset; + + /* specify that the user wants this property */ + elem->store_prop[index] = STORE_PROP; +} + + +/****************************************************************************** +Read one element from the file. This routine assumes that we're reading +the type of element specified in the last call to the routine +ply_get_element_setup(). + +Entry: + plyfile - file identifier + elem_ptr - pointer to location where the element information should be put +******************************************************************************/ + +void ply_get_element(PlyFile *plyfile, void *elem_ptr) +{ + if (plyfile->file_type == PLY_ASCII) + ascii_get_element (plyfile, (char *) elem_ptr); + else + binary_get_element (plyfile, (char *) elem_ptr); +} + + +/****************************************************************************** +Extract the comments from the header information of a PLY file. + +Entry: + plyfile - file identifier + +Exit: + num_comments - number of comments returned + returns a pointer to a list of comments +******************************************************************************/ + +char **ply_get_comments(PlyFile *plyfile, int *num_comments) +{ + *num_comments = plyfile->num_comments; + return (plyfile->comments); +} + + +/****************************************************************************** +Extract the object information (arbitrary text) from the header information +of a PLY file. + +Entry: + plyfile - file identifier + +Exit: + num_obj_info - number of lines of text information returned + returns a pointer to a list of object info lines +******************************************************************************/ + +char **ply_get_obj_info(PlyFile *plyfile, int *num_obj_info) +{ + *num_obj_info = plyfile->num_obj_info; + return (plyfile->obj_info); +} + + +/****************************************************************************** +Make ready for "other" properties of an element-- those properties that +the user has not explicitly asked for, but that are to be stashed away +in a special structure to be carried along with the element's other +information. + +Entry: + plyfile - file identifier + elem - element for which we want to save away other properties +******************************************************************************/ + +void setup_other_props(PlyElement *elem) +{ + int i; + PlyProperty *prop; + int size = 0; + int type_size; + + /* Examine each property in decreasing order of size. */ + /* We do this so that all data types will be aligned by */ + /* word, half-word, or whatever within the structure. */ + + for (type_size = 8; type_size > 0; type_size /= 2) { + + /* add up the space taken by each property, and save this information */ + /* away in the property descriptor */ + + for (i = 0; i < elem->nprops; i++) { + + /* don't bother with properties we've been asked to store explicitly */ + if (elem->store_prop[i]) + continue; + + prop = elem->props[i]; + + /* internal types will be same as external */ + prop->internal_type = prop->external_type; + prop->count_internal = prop->count_external; + + /* check list case */ + if (prop->is_list) { + + /* pointer to list */ + if (type_size == sizeof (void *)) { + prop->offset = size; + size += sizeof (void *); /* always use size of a pointer here */ + } + + /* count of number of list elements */ + if (type_size == ply_type_size[prop->count_external]) { + prop->count_offset = size; + size += ply_type_size[prop->count_external]; + } + } + /* not list */ + else if (type_size == ply_type_size[prop->external_type]) { + prop->offset = size; + size += ply_type_size[prop->external_type]; + } + } + + } + + /* save the size for the other_props structure */ + elem->other_size = size; +} + + +/****************************************************************************** +Specify that we want the "other" properties of an element to be tucked +away within the user's structure. The user needn't be concerned for how +these properties are stored. + +Entry: + plyfile - file identifier + elem_name - name of element that we want to store other_props in + offset - offset to where other_props will be stored inside user's structure + +Exit: + returns pointer to structure containing description of other_props +******************************************************************************/ + +PlyOtherProp *ply_get_other_properties( + PlyFile *plyfile, + char *elem_name, + int offset +) +{ + int i; + PlyElement *elem; + PlyOtherProp *other; + PlyProperty *prop; + int nprops; + + /* find information about the element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf (stderr, "ply_get_other_properties: Can't find element '%s'\n", + elem_name); + return (NULL); + } + + /* remember that this is the "current" element */ + plyfile->which_elem = elem; + + /* save the offset to where to store the other_props */ + elem->other_offset = offset; + + /* place the appropriate pointers, etc. in the element's property list */ + setup_other_props (elem); + + /* create structure for describing other_props */ + other = (PlyOtherProp *) myalloc (sizeof (PlyOtherProp)); + other->name = strdup (elem_name); +#if 0 + if (elem->other_offset == NO_OTHER_PROPS) { + other->size = 0; + other->props = NULL; + other->nprops = 0; + return (other); + } +#endif + other->size = elem->other_size; + other->props = (PlyProperty **) myalloc (sizeof(PlyProperty) * elem->nprops); + + /* save descriptions of each "other" property */ + nprops = 0; + for (i = 0; i < elem->nprops; i++) { + if (elem->store_prop[i]) + continue; + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + copy_property (prop, elem->props[i]); + other->props[nprops] = prop; + nprops++; + } + other->nprops = nprops; + +#if 1 + /* set other_offset pointer appropriately if there are NO other properties */ + if (other->nprops == 0) { + elem->other_offset = NO_OTHER_PROPS; + } +#endif + + /* return structure */ + return (other); +} + + + + +/*************************/ +/* Other Element Stuff */ +/*************************/ + + + + +/****************************************************************************** +Grab all the data for an element that a user does not want to explicitly +read in. + +Entry: + plyfile - pointer to file + elem_name - name of element whose data is to be read in + elem_count - number of instances of this element stored in the file + +Exit: + returns pointer to ALL the "other" element data for this PLY file +******************************************************************************/ + +PlyOtherElems *ply_get_other_element ( + PlyFile *plyfile, + char *elem_name, + int elem_count +) +{ + int i; + PlyElement *elem; + PlyOtherElems *other_elems; + OtherElem *other; + + /* look for appropriate element */ + elem = find_element (plyfile, elem_name); + if (elem == NULL) { + fprintf (stderr, + "ply_get_other_element: can't find element '%s'\n", elem_name); + exit (-1); + } + + /* create room for the new "other" element, initializing the */ + /* other data structure if necessary */ + + if (plyfile->other_elems == NULL) { + plyfile->other_elems = (PlyOtherElems *) myalloc (sizeof (PlyOtherElems)); + other_elems = plyfile->other_elems; + other_elems->other_list = (OtherElem *) myalloc (sizeof (OtherElem)); + other = &(other_elems->other_list[0]); + other_elems->num_elems = 1; + } + else { + other_elems = plyfile->other_elems; + other_elems->other_list = (OtherElem *) realloc (other_elems->other_list, + sizeof (OtherElem) * other_elems->num_elems + 1); + other = &(other_elems->other_list[other_elems->num_elems]); + other_elems->num_elems++; + } + + /* count of element instances in file */ + other->elem_count = elem_count; + + /* save name of element */ + other->elem_name = strdup (elem_name); + + /* create a list to hold all the current elements */ + other->other_data = (OtherData **) + malloc (sizeof (OtherData *) * other->elem_count); + + /* set up for getting elements */ + other->other_props = ply_get_other_properties (plyfile, elem_name, + offsetof(OtherData,other_props)); + + /* grab all these elements */ + for (i = 0; i < other->elem_count; i++) { + /* grab and element from the file */ + other->other_data[i] = (OtherData *) malloc (sizeof (OtherData)); + ply_get_element (plyfile, (void *) other->other_data[i]); + } + + /* return pointer to the other elements data */ + return (other_elems); +} + + +/****************************************************************************** +Pass along a pointer to "other" elements that we want to save in a given +PLY file. These other elements were presumably read from another PLY file. + +Entry: + plyfile - file pointer in which to store this other element info + other_elems - info about other elements that we want to store +******************************************************************************/ + +void ply_describe_other_elements ( + PlyFile *plyfile, + PlyOtherElems *other_elems +) +{ + int i; + OtherElem *other; + + /* ignore this call if there is no other element */ + if (other_elems == NULL) + return; + + /* save pointer to this information */ + plyfile->other_elems = other_elems; + + /* describe the other properties of this element */ + + for (i = 0; i < other_elems->num_elems; i++) { + other = &(other_elems->other_list[i]); + ply_element_count (plyfile, other->elem_name, other->elem_count); + ply_describe_other_properties (plyfile, other->other_props, + offsetof(OtherData,other_props)); + } +} + + +/****************************************************************************** +Write out the "other" elements specified for this PLY file. + +Entry: + plyfile - pointer to PLY file to write out other elements for +******************************************************************************/ + +void ply_put_other_elements (PlyFile *plyfile) +{ + int i,j; + OtherElem *other; + + /* make sure we have other elements to write */ + if (plyfile->other_elems == NULL) + return; + + /* write out the data for each "other" element */ + + for (i = 0; i < plyfile->other_elems->num_elems; i++) { + + other = &(plyfile->other_elems->other_list[i]); + ply_put_element_setup (plyfile, other->elem_name); + + /* write out each instance of the current element */ + for (j = 0; j < other->elem_count; j++) + ply_put_element (plyfile, (void *) other->other_data[j]); + } +} + + +/****************************************************************************** +Free up storage used by an "other" elements data structure. + +Entry: + other_elems - data structure to free up +******************************************************************************/ + + + + +/*******************/ +/* Miscellaneous */ +/*******************/ + + + +/****************************************************************************** +Close a PLY file. + +Entry: + plyfile - identifier of file to close +******************************************************************************/ + +void ply_close(PlyFile *plyfile) +{ + fclose (plyfile->fp); + + /* free up memory associated with the PLY file */ + free (plyfile); +} + + +/****************************************************************************** +Get version number and file type of a PlyFile. + +Entry: + ply - pointer to PLY file + +Exit: + version - version of the file + file_type - PLY_ASCII, PLY_BINARY_BE, or PLY_BINARY_LE +******************************************************************************/ + +void ply_get_info(PlyFile *ply, float *version, int *file_type) +{ + if (ply == NULL) + return; + + *version = ply->version; + *file_type = ply->file_type; +} + + +/****************************************************************************** +Compare two strings. Returns 1 if they are the same, 0 if not. +******************************************************************************/ + +int equal_strings(char *s1, char *s2) +{ + + while (*s1 && *s2) + if (*s1++ != *s2++) + return (0); + + if (*s1 != *s2) + return (0); + else + return (1); +} + + +/****************************************************************************** +Find an element from the element list of a given PLY object. + +Entry: + plyfile - file id for PLY file + element - name of element we're looking for + +Exit: + returns the element, or NULL if not found +******************************************************************************/ + +PlyElement *find_element(PlyFile *plyfile, char *element) +{ + int i; + + for (i = 0; i < plyfile->nelems; i++) + if (equal_strings (element, plyfile->elems[i]->name)) + return (plyfile->elems[i]); + + return (NULL); +} + + +/****************************************************************************** +Find a property in the list of properties of a given element. + +Entry: + elem - pointer to element in which we want to find the property + prop_name - name of property to find + +Exit: + index - index to position in list + returns a pointer to the property, or NULL if not found +******************************************************************************/ + +PlyProperty *find_property(PlyElement *elem, char *prop_name, int *index) +{ + int i; + + for (i = 0; i < elem->nprops; i++) + if (equal_strings (prop_name, elem->props[i]->name)) { + *index = i; + return (elem->props[i]); + } + + *index = -1; + return (NULL); +} + + +/****************************************************************************** +Read an element from an ascii file. + +Entry: + plyfile - file identifier + elem_ptr - pointer to element +******************************************************************************/ + +void ascii_get_element(PlyFile *plyfile, char *elem_ptr) +{ + int j,k; + PlyElement *elem; + PlyProperty *prop; + char **words; + int nwords; + int which_word; + char *elem_data,*item; + char *item_ptr; + int item_size; + int int_val; + unsigned int uint_val; + double double_val; + int list_count; + int store_it; + char **store_array; + char *orig_line; + char *other_data; + int other_flag; + + other_flag = 0; + other_data = NULL; + item = NULL; + item_size = 0; + + /* the kind of element we're reading currently */ + elem = plyfile->which_elem; + + /* do we need to setup for other_props? */ + + if (elem->other_offset != NO_OTHER_PROPS) { + char **ptr; + other_flag = 1; + /* make room for other_props */ + other_data = (char *) myalloc (elem->other_size); + /* store pointer in user's structure to the other_props */ + ptr = (char **) (elem_ptr + elem->other_offset); + *ptr = other_data; + } else { + other_flag = 0; + other_data = NULL; + item = NULL; + item_size = 0; + } + + /* read in the element */ + + words = get_words (plyfile->fp, &nwords, &orig_line); + if (words == NULL) { + fprintf (stderr, "ply_get_element: unexpected end of file\n"); + exit (-1); + } + + which_word = 0; + + for (j = 0; j < elem->nprops; j++) { + + prop = elem->props[j]; + store_it = (elem->store_prop[j] | other_flag); + + /* store either in the user's structure or in other_props */ + if (elem->store_prop[j]) + elem_data = elem_ptr; + else + elem_data = other_data; + + if (prop->is_list) { /* a list */ + + /* get and store the number of items in the list */ + get_ascii_item (words[which_word++], prop->count_external, + &int_val, &uint_val, &double_val); + if (store_it) { + item = elem_data + prop->count_offset; + store_item(item, prop->count_internal, int_val, uint_val, double_val); + } + + /* allocate space for an array of items and store a ptr to the array */ + list_count = int_val; + item_size = ply_type_size[prop->internal_type]; + store_array = (char **) (elem_data + prop->offset); + + if (list_count == 0) { + if (store_it) + *store_array = NULL; + } + else { + if (store_it) { + item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count); + item = item_ptr; + *store_array = item_ptr; + } + + /* read items and store them into the array */ + for (k = 0; k < list_count; k++) { + get_ascii_item (words[which_word++], prop->external_type, + &int_val, &uint_val, &double_val); + if (store_it) { + store_item (item, prop->internal_type, + int_val, uint_val, double_val); + item += item_size; + } + } + } + + } + else { /* not a list */ + get_ascii_item (words[which_word++], prop->external_type, + &int_val, &uint_val, &double_val); + if (store_it) { + item = elem_data + prop->offset; + store_item (item, prop->internal_type, int_val, uint_val, double_val); + } + } + + } + + free (words); +} + + +/****************************************************************************** +Read an element from a binary file. + +Entry: + plyfile - file identifier + elem_ptr - pointer to an element +******************************************************************************/ + +void binary_get_element(PlyFile *plyfile, char *elem_ptr) +{ + int j,k; + PlyElement *elem; + PlyProperty *prop; + FILE *fp = plyfile->fp; + char *elem_data,*item; + char *item_ptr; + int item_size; + int int_val; + unsigned int uint_val; + double double_val; + int list_count; + int store_it; + char **store_array; + char *other_data; + int other_flag; + + + other_flag = 0; + other_data = NULL; + item = NULL; + item_size = 0; + + /* the kind of element we're reading currently */ + elem = plyfile->which_elem; + + /* do we need to setup for other_props? */ + + if (elem->other_offset != NO_OTHER_PROPS) { + char **ptr; + other_flag = 1; + /* make room for other_props */ + other_data = (char *) myalloc (elem->other_size); + /* store pointer in user's structure to the other_props */ + ptr = (char **) (elem_ptr + elem->other_offset); + *ptr = other_data; + } + else { + other_flag = 0; + other_data = NULL; + item = NULL; + item_size = 0; + } + /* read in a number of elements */ + + for (j = 0; j < elem->nprops; j++) { + + prop = elem->props[j]; + store_it = (elem->store_prop[j] | other_flag); + + /* store either in the user's structure or in other_props */ + if (elem->store_prop[j]) + elem_data = elem_ptr; + else + elem_data = other_data; + + if (prop->is_list) { /* a list */ + + /* get and store the number of items in the list */ + get_binary_item (fp, prop->count_external, + &int_val, &uint_val, &double_val); + if (store_it) { + item = elem_data + prop->count_offset; + store_item(item, prop->count_internal, int_val, uint_val, double_val); + } + + /* allocate space for an array of items and store a ptr to the array */ + list_count = int_val; + /* The "if" was added by Afra Zomorodian 8/22/95 + * so that zipper won't crash reading plies that have additional + * properties. + */ + if (store_it) { + item_size = ply_type_size[prop->internal_type]; + } + store_array = (char **) (elem_data + prop->offset); + if (list_count == 0) { + if (store_it) + *store_array = NULL; + } + else { + if (store_it) { + item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count); + item = item_ptr; + *store_array = item_ptr; + } + + /* read items and store them into the array */ + for (k = 0; k < list_count; k++) { + get_binary_item (fp, prop->external_type, + &int_val, &uint_val, &double_val); + if (store_it) { + store_item (item, prop->internal_type, + int_val, uint_val, double_val); + item += item_size; + } + } + } + + } + else { /* not a list */ + get_binary_item (fp, prop->external_type, + &int_val, &uint_val, &double_val); + if (store_it) { + item = elem_data + prop->offset; + store_item (item, prop->internal_type, int_val, uint_val, double_val); + } + } + + } +} + + +/****************************************************************************** +Write to a file the word that represents a PLY data type. + +Entry: + fp - file pointer + code - code for type +******************************************************************************/ + +void write_scalar_type (FILE *fp, int code) +{ + /* make sure this is a valid code */ + + if (code <= PLY_START_TYPE || code >= PLY_END_TYPE) { + fprintf (stderr, "write_scalar_type: bad data code = %d\n", code); + exit (-1); + } + + /* write the code to a file */ + + fprintf (fp, "%s", type_names[code]); +} + + +/****************************************************************************** +Get a text line from a file and break it up into words. + +IMPORTANT: The calling routine call "free" on the returned pointer once +finished with it. + +Entry: + fp - file to read from + +Exit: + nwords - number of words returned + orig_line - the original line of characters + returns a list of words from the line, or NULL if end-of-file +******************************************************************************/ + +char **get_words(FILE *fp, int *nwords, char **orig_line) +{ +#define BIG_STRING 4096 + static char str[BIG_STRING]; + static char str_copy[BIG_STRING]; + char **words; + int max_words = 10; + int num_words = 0; + char *ptr,*ptr2; + char *result; + + words = (char **) myalloc (sizeof (char *) * max_words); + + /* read in a line */ + result = fgets (str, BIG_STRING, fp); + if (result == NULL) { + *nwords = 0; + *orig_line = NULL; + return (NULL); + } + + /* convert line-feed and tabs into spaces */ + /* (this guarentees that there will be a space before the */ + /* null character at the end of the string) */ + + str[BIG_STRING-2] = ' '; + str[BIG_STRING-1] = '\0'; + + for (ptr = str, ptr2 = str_copy; *ptr != '\0'; ptr++, ptr2++) { + *ptr2 = *ptr; + if (*ptr == '\t') { + *ptr = ' '; + *ptr2 = ' '; + } + else if (*ptr == '\n') { + *ptr = ' '; + *ptr2 = '\0'; + break; + } + } + + /* find the words in the line */ + + ptr = str; + while (*ptr != '\0') { + + /* jump over leading spaces */ + while (*ptr == ' ') + ptr++; + + /* break if we reach the end */ + if (*ptr == '\0') + break; + + /* save pointer to beginning of word */ + if (num_words >= max_words) { + max_words += 10; + words = (char **) realloc (words, sizeof (char *) * max_words); + } + words[num_words++] = ptr; + + /* jump over non-spaces */ + while (*ptr != ' ') + ptr++; + + /* place a null character here to mark the end of the word */ + *ptr++ = '\0'; + } + + /* return the list of words */ + *nwords = num_words; + *orig_line = str_copy; + return (words); +} + + +/****************************************************************************** +Return the value of an item, given a pointer to it and its type. + +Entry: + item - pointer to item + type - data type that "item" points to + +Exit: + returns a double-precision float that contains the value of the item +******************************************************************************/ + +double get_item_value(char *item, int type) +{ + unsigned char *puchar; + char *pchar; + short int *pshort; + unsigned short int *pushort; + int *pint; + unsigned int *puint; + float *pfloat; + double *pdouble; + int int_value; + unsigned int uint_value; + double double_value; + + switch (type) { + case PLY_CHAR: + pchar = (char *) item; + int_value = *pchar; + return ((double) int_value); + case PLY_UCHAR: + puchar = (unsigned char *) item; + int_value = *puchar; + return ((double) int_value); + case PLY_SHORT: + pshort = (short int *) item; + int_value = *pshort; + return ((double) int_value); + case PLY_USHORT: + pushort = (unsigned short int *) item; + int_value = *pushort; + return ((double) int_value); + case PLY_INT: + pint = (int *) item; + int_value = *pint; + return ((double) int_value); + case PLY_UINT: + puint = (unsigned int *) item; + uint_value = *puint; + return ((double) uint_value); + case PLY_FLOAT: + pfloat = (float *) item; + double_value = *pfloat; + return (double_value); + case PLY_DOUBLE: + pdouble = (double *) item; + double_value = *pdouble; + return (double_value); + default: + fprintf (stderr, "get_item_value: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Write out an item to a file as raw binary bytes. + +Entry: + fp - file to write to + int_val - integer version of item + uint_val - unsigned integer version of item + double_val - double-precision float version of item + type - data type to write out +******************************************************************************/ + +void write_binary_item( + FILE *fp, + int int_val, + unsigned int uint_val, + double double_val, + int type +) +{ + unsigned char uchar_val; + char char_val; + unsigned short ushort_val; + short short_val; + float float_val; + + switch (type) { + case PLY_CHAR: + char_val = (char)int_val; + fwrite (&char_val, 1, 1, fp); + break; + case PLY_SHORT: + short_val = (short)int_val; + fwrite (&short_val, 2, 1, fp); + break; + case PLY_INT: + fwrite (&int_val, 4, 1, fp); + break; + case PLY_UCHAR: + uchar_val = (unsigned char) uint_val; + fwrite (&uchar_val, 1, 1, fp); + break; + case PLY_USHORT: + ushort_val = (unsigned short)uint_val; + fwrite (&ushort_val, 2, 1, fp); + break; + case PLY_UINT: + fwrite (&uint_val, 4, 1, fp); + break; + case PLY_FLOAT: + float_val = (float) double_val; + fwrite (&float_val, 4, 1, fp); + break; + case PLY_DOUBLE: + fwrite (&double_val, 8, 1, fp); + break; + default: + fprintf (stderr, "write_binary_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Write out an item to a file as ascii characters. + +Entry: + fp - file to write to + int_val - integer version of item + uint_val - unsigned integer version of item + double_val - double-precision float version of item + type - data type to write out +******************************************************************************/ + +void write_ascii_item( + FILE *fp, + int int_val, + unsigned int uint_val, + double double_val, + int type +) +{ + switch (type) { + case PLY_CHAR: + case PLY_SHORT: + case PLY_INT: + fprintf (fp, "%d ", int_val); + break; + case PLY_UCHAR: + case PLY_USHORT: + case PLY_UINT: + fprintf (fp, "%u ", uint_val); + break; + case PLY_FLOAT: + case PLY_DOUBLE: + fprintf (fp, "%g ", double_val); + break; + default: + fprintf (stderr, "write_ascii_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Write out an item to a file as ascii characters. + +Entry: + fp - file to write to + item - pointer to item to write + type - data type that "item" points to + +Exit: + returns a double-precision float that contains the value of the written item +******************************************************************************/ + +double old_write_ascii_item(FILE *fp, char *item, int type) +{ + unsigned char *puchar; + char *pchar; + short int *pshort; + unsigned short int *pushort; + int *pint; + unsigned int *puint; + float *pfloat; + double *pdouble; + int int_value; + unsigned int uint_value; + double double_value; + + switch (type) { + case PLY_CHAR: + pchar = (char *) item; + int_value = *pchar; + fprintf (fp, "%d ", int_value); + return ((double) int_value); + case PLY_UCHAR: + puchar = (unsigned char *) item; + int_value = *puchar; + fprintf (fp, "%d ", int_value); + return ((double) int_value); + case PLY_SHORT: + pshort = (short int *) item; + int_value = *pshort; + fprintf (fp, "%d ", int_value); + return ((double) int_value); + case PLY_USHORT: + pushort = (unsigned short int *) item; + int_value = *pushort; + fprintf (fp, "%d ", int_value); + return ((double) int_value); + case PLY_INT: + pint = (int *) item; + int_value = *pint; + fprintf (fp, "%d ", int_value); + return ((double) int_value); + case PLY_UINT: + puint = (unsigned int *) item; + uint_value = *puint; + fprintf (fp, "%u ", uint_value); + return ((double) uint_value); + case PLY_FLOAT: + pfloat = (float *) item; + double_value = *pfloat; + fprintf (fp, "%g ", double_value); + return (double_value); + case PLY_DOUBLE: + pdouble = (double *) item; + double_value = *pdouble; + fprintf (fp, "%g ", double_value); + return (double_value); + default: + fprintf (stderr, "old_write_ascii_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Get the value of an item that is in memory, and place the result +into an integer, an unsigned integer and a double. + +Entry: + ptr - pointer to the item + type - data type supposedly in the item + +Exit: + int_val - integer value + uint_val - unsigned integer value + double_val - double-precision floating point value +******************************************************************************/ + +void get_stored_item( + void *ptr, + int type, + int *int_val, + unsigned int *uint_val, + double *double_val +) +{ + switch (type) { + case PLY_CHAR: + *int_val = *((char *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case PLY_UCHAR: + *uint_val = *((unsigned char *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case PLY_SHORT: + *int_val = *((short int *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case PLY_USHORT: + *uint_val = *((unsigned short int *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case PLY_INT: + *int_val = *((int *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case PLY_UINT: + *uint_val = *((unsigned int *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case PLY_FLOAT: + *double_val = *((float *) ptr); + *int_val = (int)*double_val; + *uint_val = (unsigned int)*double_val; + break; + case PLY_DOUBLE: + *double_val = *((double *) ptr); + *int_val = (int)*double_val; + *uint_val =(unsigned int) *double_val; + break; + default: + fprintf (stderr, "get_stored_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Get the value of an item from a binary file, and place the result +into an integer, an unsigned integer and a double. + +Entry: + fp - file to get item from + type - data type supposedly in the word + +Exit: + int_val - integer value + uint_val - unsigned integer value + double_val - double-precision floating point value +******************************************************************************/ + +void get_binary_item( + FILE *fp, + int type, + int *int_val, + unsigned int *uint_val, + double *double_val +) +{ + char c[8]; + void *ptr; + + ptr = (void *) c; + + switch (type) { + case PLY_CHAR: + fread (ptr, 1, 1, fp); + *int_val = *((char *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case PLY_UCHAR: + fread (ptr, 1, 1, fp); + *uint_val = *((unsigned char *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case PLY_SHORT: + fread (ptr, 2, 1, fp); + *int_val = *((short int *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case PLY_USHORT: + fread (ptr, 2, 1, fp); + *uint_val = *((unsigned short int *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case PLY_INT: + fread (ptr, 4, 1, fp); + *int_val = *((int *) ptr); + *uint_val = *int_val; + *double_val = *int_val; + break; + case PLY_UINT: + fread (ptr, 4, 1, fp); + *uint_val = *((unsigned int *) ptr); + *int_val = *uint_val; + *double_val = *uint_val; + break; + case PLY_FLOAT: + fread (ptr, 4, 1, fp); + *double_val = *((float *) ptr); + *int_val = (int)*double_val; + *uint_val =(unsigned int) *double_val; + break; + case PLY_DOUBLE: + fread (ptr, 8, 1, fp); + *double_val = *((double *) ptr); + *int_val = (int)*double_val; + *uint_val = (unsigned int)*double_val; + break; + default: + fprintf (stderr, "get_binary_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Extract the value of an item from an ascii word, and place the result +into an integer, an unsigned integer and a double. + +Entry: + word - word to extract value from + type - data type supposedly in the word + +Exit: + int_val - integer value + uint_val - unsigned integer value + double_val - double-precision floating point value +******************************************************************************/ + +void get_ascii_item( + char *word, + int type, + int *int_val, + unsigned int *uint_val, + double *double_val +) +{ + switch (type) { + case PLY_CHAR: + case PLY_UCHAR: + case PLY_SHORT: + case PLY_USHORT: + case PLY_INT: + *int_val = atoi (word); + *uint_val = *int_val; + *double_val = *int_val; + break; + + case PLY_UINT: + *uint_val = strtoul (word, (char **) NULL, 10); + *int_val = *uint_val; + *double_val = *uint_val; + break; + + case PLY_FLOAT: + case PLY_DOUBLE: + *double_val = atof (word); + *int_val = (int) *double_val; + *uint_val = (unsigned int) *double_val; + break; + + default: + fprintf (stderr, "get_ascii_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Store a value into a place being pointed to, guided by a data type. + +Entry: + item - place to store value + type - data type + int_val - integer version of value + uint_val - unsigned integer version of value + double_val - double version of value + +Exit: + item - pointer to stored value +******************************************************************************/ + +void store_item ( + char *item, + int type, + int int_val, + unsigned int uint_val, + double double_val +) +{ + unsigned char *puchar; + short int *pshort; + unsigned short int *pushort; + int *pint; + unsigned int *puint; + float *pfloat; + double *pdouble; + + switch (type) { + case PLY_CHAR: + *item = (char) int_val; + break; + case PLY_UCHAR: + puchar = (unsigned char *) item; + *puchar = (unsigned char)uint_val; + break; + case PLY_SHORT: + pshort = (short *) item; + *pshort = (short)int_val; + break; + case PLY_USHORT: + pushort = (unsigned short *) item; + *pushort = (unsigned short)uint_val; + break; + case PLY_INT: + pint = (int *) item; + *pint = int_val; + break; + case PLY_UINT: + puint = (unsigned int *) item; + *puint = uint_val; + break; + case PLY_FLOAT: + pfloat = (float *) item; + *pfloat = (float)double_val; + break; + case PLY_DOUBLE: + pdouble = (double *) item; + *pdouble = double_val; + break; + default: + fprintf (stderr, "store_item: bad type = %d\n", type); + exit (-1); + } +} + + +/****************************************************************************** +Add an element to a PLY file descriptor. + +Entry: + plyfile - PLY file descriptor + words - list of words describing the element + nwords - number of words in the list +******************************************************************************/ + +void add_element (PlyFile *plyfile, char **words) +{ + PlyElement *elem; + + /* create the new element */ + elem = (PlyElement *) myalloc (sizeof (PlyElement)); + elem->name = strdup (words[1]); + elem->num = atoi (words[2]); + elem->nprops = 0; + + /* make room for new element in the object's list of elements */ + if (plyfile->nelems == 0) + plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *)); + else + plyfile->elems = (PlyElement **) realloc (plyfile->elems, + sizeof (PlyElement *) * (plyfile->nelems + 1)); + + /* add the new element to the object's list */ + plyfile->elems[plyfile->nelems] = elem; + plyfile->nelems++; +} + + +/****************************************************************************** +Return the type of a property, given the name of the property. + +Entry: + name - name of property type + +Exit: + returns integer code for property, or 0 if not found +******************************************************************************/ + +int get_prop_type(char *type_name) +{ + int i; + + for (i = PLY_START_TYPE + 1; i < PLY_END_TYPE; i++) + if (equal_strings (type_name, type_names[i])) + return (i); + + /* if we get here, we didn't find the type */ + return (0); +} + + +/****************************************************************************** +Add a property to a PLY file descriptor. + +Entry: + plyfile - PLY file descriptor + words - list of words describing the property + nwords - number of words in the list +******************************************************************************/ + +void add_property (PlyFile *plyfile, char **words) +{ + PlyProperty *prop; + PlyElement *elem; + + /* create the new property */ + + prop = (PlyProperty *) myalloc (sizeof (PlyProperty)); + + if (equal_strings (words[1], "list")) { /* is a list */ + prop->count_external = get_prop_type (words[2]); + prop->external_type = get_prop_type (words[3]); + prop->name = strdup (words[4]); + prop->is_list = 1; + } + else { /* not a list */ + prop->external_type = get_prop_type (words[1]); + prop->name = strdup (words[2]); + prop->is_list = 0; + } + + /* add this property to the list of properties of the current element */ + + elem = plyfile->elems[plyfile->nelems - 1]; + + if (elem->nprops == 0) + elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *)); + else + elem->props = (PlyProperty **) realloc (elem->props, + sizeof (PlyProperty *) * (elem->nprops + 1)); + + elem->props[elem->nprops] = prop; + elem->nprops++; +} + + +/****************************************************************************** +Add a comment to a PLY file descriptor. + +Entry: + plyfile - PLY file descriptor + line - line containing comment +******************************************************************************/ + +void add_comment (PlyFile *plyfile, char *line) +{ + int i; + + /* skip over "comment" and leading spaces and tabs */ + i = 7; + while (line[i] == ' ' || line[i] == '\t') + i++; + + ply_put_comment (plyfile, &line[i]); +} + + +/****************************************************************************** +Add a some object information to a PLY file descriptor. + +Entry: + plyfile - PLY file descriptor + line - line containing text info +******************************************************************************/ + +void add_obj_info (PlyFile *plyfile, char *line) +{ + int i; + + /* skip over "obj_info" and leading spaces and tabs */ + i = 8; + while (line[i] == ' ' || line[i] == '\t') + i++; + + ply_put_obj_info (plyfile, &line[i]); +} + + +/****************************************************************************** +Copy a property. +******************************************************************************/ + +void copy_property(PlyProperty *dest, PlyProperty *src) +{ + dest->name = strdup (src->name); + dest->external_type = src->external_type; + dest->internal_type = src->internal_type; + dest->offset = src->offset; + + dest->is_list = src->is_list; + dest->count_external = src->count_external; + dest->count_internal = src->count_internal; + dest->count_offset = src->count_offset; +} + + +/****************************************************************************** +Allocate some memory. + +Entry: + size - amount of memory requested (in bytes) + lnum - line number from which memory was requested + fname - file name from which memory was requested +******************************************************************************/ + +static char *my_alloc(int size, int lnum, char *fname) +{ + char *ptr; + + ptr = (char *) malloc (size); + + if (ptr == 0) { + fprintf(stderr, "Memory allocation bombed on line %d in %s\n", lnum, fname); + } + + return (ptr); +} + diff --git a/intern/bsp/test/Makefile b/intern/bsp/test/Makefile new file mode 100644 index 00000000000..17ed638d745 --- /dev/null +++ b/intern/bsp/test/Makefile @@ -0,0 +1,72 @@ +# +# $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 ***** +# bsp test makefile. +# + +LIBNAME = bsp +SOURCEDIR = intern/$(LIBNAME)/test +DIR = $(OCGDIR)/$(SOURCEDIR) + +include nan_compile.mk + +DIRS = BSP_GhostTest + +include nan_subdirs.mk + +include nan_link.mk + +LIBS = $(OCGDIR)/intern/$(LIBNAME)/test/BSP_GhostTest/$(DEBUG_DIR)libBSP_GhostTest.a +LIBS += $(OCGDIR)/intern/$(LIBNAME)/$(DEBUG_DIR)libbsp.a + +SLIBS += $(NAN_MOTO)/lib/$(DEBUG_DIR)libmoto.a +SLIBS += $(NAN_GHOST)/lib/$(DEBUG_DIR)libghost.a +SLIBS += $(NAN_STRING)/lib/$(DEBUG_DIR)libstring.a + +ifeq ($(OS),$(findstring $(OS), "beos darwin linux freebsd openbsd")) + LLIBS = -L/usr/X11R6/lib -lglut -pthread -lXi -lXmu +endif + +all debug:: $(LIBS) $(DIR)/$(DEBUG_DIR)BSPGhostTest + +$(DIR)/$(DEBUG_DIR)BSPGhostTest: + @echo "****> linking $@ in $(DIR)" + $(CCC) $(LDFLAGS) -o $(DIR)/$(DEBUG_DIR)BSPGhostTest $(LIBS) $(SLIBS) $(LLIBS) $(DADD) + +clean:: + $(RM) $(DIR)/BSPGhostTest $(DIR)/debug/BSPGhostTest + +test:: all + $(DIR)/BSPGhostTest + + + + + |