New files from new booleans
[blender.git] / intern / boolop / intern / BOP_MaterialContainer.cpp
1 /**
2  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. The Blender
8  * Foundation also sells licenses for use in proprietary software under
9  * the Blender License.  See http://www.blender.org/BL/ for information
10  * about this.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software Foundation,
19  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  *
21  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
22  * All rights reserved.
23  *
24  * The Original Code is: all of this file.
25  *
26  * Contributor(s): none yet.
27  *
28  * ***** END GPL/BL DUAL LICENSE BLOCK *****
29  */
30  
31 #include <iostream>
32 #include "BOP_MaterialContainer.h"
33 #include "BOP_MathUtils.h"
34 #include "MEM_SmartPtr.h"
35
36 /**
37  * Constructs a new material container.
38  */
39 BOP_MaterialContainer::BOP_MaterialContainer()
40 {
41         m_interpFunc = NULL;
42 }
43
44 /**
45  * Destroys a material container.
46  */
47 BOP_MaterialContainer::~BOP_MaterialContainer()
48 {
49 }
50
51 /**
52  * Adds a new material to this container.
53  * @param m material material object to add.
54  * @return the new material index.
55  */
56 BOP_Index BOP_MaterialContainer::addMaterial(BOP_Material m)
57 {
58         m_materialList.push_back(m);
59         return m_materialList.size()-1;
60 }
61
62 /**
63  * Updates the interpolation function of this container.
64  * @param interpFunc the interpolation function.
65  */
66 void BOP_MaterialContainer::setInterpFunc(CSG_InterpolateUserFaceVertexDataFunc interpFunc)
67 {
68         m_interpFunc = interpFunc;
69 }
70
71 /**
72  * Returns the material list.
73  * @return
74  */
75 BOP_Materials& BOP_MaterialContainer::getMaterialList()
76 {
77         return m_materialList;
78 }
79
80 /**
81  * Returns the material with the specified index.
82  * @param index material index.
83  * @return material with the specified index.
84  */
85 BOP_Material* BOP_MaterialContainer::getMaterial(BOP_Index index)
86 {
87         return index < m_materialList.size() ? &(m_materialList[index]) : NULL;
88 }
89
90 /**
91  * Returns the pointer to face material specified by index.
92  * @param index material index.
93  * @return pointer to face material.
94  */
95 char* BOP_MaterialContainer::getFaceMaterial(BOP_Index index)
96 {
97         if (index < m_materialList.size())
98                 return m_materialList[index].getFaceMaterial();
99         else return NULL;
100 }
101
102 /**
103  * Returns a pointer to face vertex material, if is the material not exist, then
104  * returns an interpoled material.
105  * @param mesh original mesh data.
106  * @param originalFaceIndex index to the original mesh face.
107  * @param point point who needs a material.
108  * @param faceVertexMaterial pointer to mem region where the material will be 
109  * saved.
110  * @return pointer to the face vertex material.
111  */
112 char* BOP_MaterialContainer::getFaceVertexMaterial(BOP_Mesh *mesh, 
113                                                                                                    BOP_Index originalFaceIndex, 
114                                                                                                    MT_Point3 point, 
115                                                                                                    char* faceVertexMaterial)
116 {
117         if (originalFaceIndex>=m_materialList.size()) return NULL;
118
119         BOP_Material& material = m_materialList[originalFaceIndex];
120         
121         if (material.isQuad()) {
122                 
123                 BOP_Face *face1 = mesh->getFace(material.getOriginalFace());
124                 BOP_Face *face2 = mesh->getFace(material.getOriginalFace()+1);
125                 
126                 if (!face1 || !face2) return NULL;
127                 
128                 // Search original point
129                 for (unsigned int i=0;i<face1->size();i++) {
130                         if (point == mesh->getVertex(face1->getVertex(i))->getPoint()) {
131                                 return material.getOriginalFaceVertexMaterial(face1->getVertex(i));
132                         }
133                 }
134                 for (unsigned int i=0;i<face2->size();i++) {
135                         if (point == mesh->getVertex(face2->getVertex(i))->getPoint()) {
136                                 return material.getOriginalFaceVertexMaterial(face2->getVertex(i));
137                         }
138                 }
139                 // wich is the half quad where the point is?
140                 MT_Vector3 N = face1->getPlane().Normal();
141                 MT_Point3 p0 = mesh->getVertex(face1->getVertex(0))->getPoint();
142                 MT_Point3 q(p0.x()+N.x(),p0.y()+N.y(),p0.z()+N.z());
143                 MT_Point3 p2 = mesh->getVertex(face1->getVertex(1))->getPoint();
144                 MT_Plane3 plane(p0,p2,q);
145                 
146                 if (BOP_sign(plane.signedDistance(point))==-1) {
147                         // first half quad
148                         faceVertexMaterial = interpolateMaterial(mesh, face1, material, point, faceVertexMaterial);
149                 }
150                 else {
151                         // second half quad
152                         faceVertexMaterial = interpolateMaterial(mesh, face2, material, point, faceVertexMaterial);
153                 }
154         }
155         else {
156                 BOP_Face *face1 = mesh->getFace(material.getOriginalFace());
157                 
158                 if (!face1) return NULL;
159                 
160                 // Search original point
161                 for (unsigned int i=0;i<face1->size();i++) {
162                         if (point == mesh->getVertex(face1->getVertex(i))->getPoint())
163                                 return material.getOriginalFaceVertexMaterial(face1->getVertex(i));
164                 }
165                 
166                 faceVertexMaterial = interpolateMaterial(mesh, face1, material, point, faceVertexMaterial);
167         }
168         
169         return faceVertexMaterial;
170 }
171
172 /**
173  * Performs vertex data interpolation.
174  * @param mesh original mesh data.
175  * @param face face used to interpolate an interior face point material
176  * @param material face material, input data for implementation.
177  * @param point interpolated point.
178  * @param faceVertexMaterial pointer to memory region.
179  * @return pointer to face vertex material.
180  */
181 char* BOP_MaterialContainer::interpolateMaterial(BOP_Mesh* mesh,
182                                                                                                  BOP_Face* face, 
183                                                                                                  BOP_Material& material,
184                                                                                                  MT_Point3 point, 
185                                                                                                  char* faceVertexMaterial)
186 {
187         //  (p1)-----(I)------(p2)
188         //    \       |        /
189         //     \      |       /
190         //      \     |      /
191         //       \ (point)  /
192         //        \   |    /
193         //         \  |   /
194         //          \ |  /
195         //           (p3)
196
197         MT_Point3 p1 = mesh->getVertex(face->getVertex(0))->getPoint();
198         MT_Point3 p2 = mesh->getVertex(face->getVertex(1))->getPoint();
199         MT_Point3 p3 = mesh->getVertex(face->getVertex(2))->getPoint();
200         MT_Point3 I = BOP_4PointIntersect(p1, p2, p3, point);
201         MT_Scalar epsilon0 = 1.0-BOP_EpsilonDistance(p1, p2, I);
202         MT_Scalar epsilon1 = 1.0-BOP_EpsilonDistance(I, p3, point);
203         
204         // Interpolate data
205         if (m_interpFunc) {
206                 // temporal data
207                 char* faceVertexMaterialTemp = new char[material.getFaceVertexWidth()];
208                 
209                 (*m_interpFunc)(material.getOriginalFaceVertexMaterial(face->getVertex(0)),
210                                                 material.getOriginalFaceVertexMaterial(face->getVertex(1)),
211                                                 faceVertexMaterialTemp,
212                                                 epsilon0);
213
214                 (*m_interpFunc)(faceVertexMaterialTemp,
215                                                 material.getOriginalFaceVertexMaterial(face->getVertex(2)),
216                                                 faceVertexMaterial,
217                                                 epsilon1);
218
219                 // free temporal data
220                 delete[] faceVertexMaterialTemp;
221                 
222         }
223         else faceVertexMaterial = NULL;
224         
225         // return the result
226         return (char*) faceVertexMaterial;
227 }
228
229 /**
230  * Implements operator <<
231  */
232 ostream &operator<<(ostream &stream, BOP_MaterialContainer *mc)
233 {
234         stream << "***[ Material List ]***********************************************" << endl;
235         BOP_IT_Materials it;
236         for (it=mc->getMaterialList().begin();it!=mc->getMaterialList().end();++it) {
237                 stream << "[" << it - mc->getMaterialList().begin() << "] ";
238                 stream << &(*it);
239         }
240         stream << "*******************************************************************" << endl;
241         return stream;
242 }