Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/bsp')
-rw-r--r--intern/bsp/Makefile55
-rwxr-xr-xintern/bsp/extern/CSG_BooleanOps.h428
-rwxr-xr-xintern/bsp/intern/BSP_CSGException.h58
-rw-r--r--intern/bsp/intern/BSP_CSGHelper.cpp430
-rw-r--r--intern/bsp/intern/BSP_CSGHelper.h99
-rwxr-xr-xintern/bsp/intern/BSP_CSGISplitter.h118
-rwxr-xr-xintern/bsp/intern/BSP_CSGMesh.cpp883
-rwxr-xr-xintern/bsp/intern/BSP_CSGMesh.h345
-rwxr-xr-xintern/bsp/intern/BSP_CSGMeshBuilder.cpp152
-rwxr-xr-xintern/bsp/intern/BSP_CSGMeshBuilder.h74
-rwxr-xr-xintern/bsp/intern/BSP_CSGMeshSplitter.cpp715
-rwxr-xr-xintern/bsp/intern/BSP_CSGMeshSplitter.h208
-rwxr-xr-xintern/bsp/intern/BSP_CSGMesh_CFIterator.h272
-rwxr-xr-xintern/bsp/intern/BSP_CSGNCMeshSplitter.cpp241
-rwxr-xr-xintern/bsp/intern/BSP_CSGNCMeshSplitter.h139
-rwxr-xr-xintern/bsp/intern/BSP_CSGUserData.cpp133
-rwxr-xr-xintern/bsp/intern/BSP_CSGUserData.h136
-rwxr-xr-xintern/bsp/intern/BSP_FragNode.cpp313
-rwxr-xr-xintern/bsp/intern/BSP_FragNode.h127
-rwxr-xr-xintern/bsp/intern/BSP_FragTree.cpp319
-rwxr-xr-xintern/bsp/intern/BSP_FragTree.h146
-rwxr-xr-xintern/bsp/intern/BSP_MeshFragment.cpp279
-rwxr-xr-xintern/bsp/intern/BSP_MeshFragment.h152
-rwxr-xr-xintern/bsp/intern/BSP_MeshPrimitives.cpp301
-rw-r--r--intern/bsp/intern/BSP_MeshPrimitives.h289
-rwxr-xr-xintern/bsp/intern/BSP_Triangulate.cpp249
-rwxr-xr-xintern/bsp/intern/BSP_Triangulate.h132
-rwxr-xr-xintern/bsp/intern/CSG_BooleanOps.cpp255
-rw-r--r--intern/bsp/intern/Makefile48
-rw-r--r--intern/bsp/make/msvc6_0/bsplib.dsp211
-rw-r--r--intern/bsp/make/msvc6_0/bsplib.dsw29
-rwxr-xr-xintern/bsp/test/BSP_GhostTest/BSP_GhostTest.dsp130
-rwxr-xr-xintern/bsp/test/BSP_GhostTest/BSP_GhostTest.dsw125
-rwxr-xr-xintern/bsp/test/BSP_GhostTest/BSP_GhostTest3D.cpp656
-rwxr-xr-xintern/bsp/test/BSP_GhostTest/BSP_GhostTest3D.h165
-rwxr-xr-xintern/bsp/test/BSP_GhostTest/BSP_MeshDrawer.cpp160
-rwxr-xr-xintern/bsp/test/BSP_GhostTest/BSP_MeshDrawer.h77
-rwxr-xr-xintern/bsp/test/BSP_GhostTest/BSP_PlyLoader.cpp196
-rwxr-xr-xintern/bsp/test/BSP_GhostTest/BSP_PlyLoader.h64
-rwxr-xr-xintern/bsp/test/BSP_GhostTest/BSP_TMesh.h354
-rw-r--r--intern/bsp/test/BSP_GhostTest/Makefile56
-rwxr-xr-xintern/bsp/test/BSP_GhostTest/main.cpp147
-rwxr-xr-xintern/bsp/test/BSP_GhostTest/ply.h200
-rwxr-xr-xintern/bsp/test/BSP_GhostTest/plyfile.c2548
-rw-r--r--intern/bsp/test/Makefile72
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
+
+
+
+
+