Fix for remesh modifier crash mentioned in comments of bug [#30966]
[blender.git] / intern / dualcon / intern / dualcon_c_api.cpp
1 /*
2  * ***** BEGIN GPL 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.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Nicholas Bishop
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 #include <cassert>
24 #include "dualcon.h"
25 #include "ModelReader.h"
26 #include "octree.h"
27
28 #include <cstdio>
29
30 void veccopy(float dst[3], const float src[3])
31 {
32         dst[0] = src[0];
33         dst[1] = src[1];
34         dst[2] = src[2];
35 }
36
37 #define GET_FACE(_mesh, _n) \
38         (*(DualConFaces)(((char*)(_mesh)->faces) + ((_n) * (_mesh)->face_stride)))
39
40 #define GET_CO(_mesh, _n) \
41         (*(DualConCo)(((char*)(_mesh)->co) + ((_n) * (_mesh)->co_stride)))
42
43 class DualConInputReader : public ModelReader
44 {
45 private:
46         const DualConInput *input_mesh;
47         int tottri, curface, offset;
48         float min[3], max[3], maxsize;
49         float scale;
50 public:
51         DualConInputReader(const DualConInput *mesh, float _scale)
52         : input_mesh(mesh), scale(_scale)
53         {
54                 reset();
55         }
56
57         void reset()
58         {
59                 tottri = 0;
60                 curface = 0;
61                 offset = 0;
62                 maxsize = 0;
63
64                 /* initialize tottri */
65                 for(int i = 0; i < input_mesh->totface; i++)
66                         tottri += GET_FACE(input_mesh, i)[3] ? 2 : 1;
67
68                 veccopy(min, input_mesh->min);
69                 veccopy(max, input_mesh->max);
70
71                 /* initialize maxsize */
72                 for(int i = 0; i < 3; i++) {
73                         float d = max[i] - min[i];
74                         if(d > maxsize)
75                                 maxsize = d;
76                 }
77
78                 /* redo the bounds */
79                 for(int i = 0; i < 3; i++)
80                 {
81                         min[i] = (max[i] + min[i]) / 2 - maxsize / 2;
82                         max[i] = (max[i] + min[i]) / 2 + maxsize / 2;
83                 }
84
85                 for(int i = 0; i < 3; i++)
86                         min[i] -= maxsize * (1 / scale - 1) / 2;
87                 maxsize *= 1 / scale;
88         }
89
90         Triangle* getNextTriangle()
91         {
92                 if(curface == input_mesh->totface)
93                         return 0;
94
95                 Triangle* t = new Triangle();
96                 
97                 unsigned int *f = GET_FACE(input_mesh, curface);
98                 if(offset == 0) {
99                         veccopy(t->vt[0], GET_CO(input_mesh, f[0]));
100                         veccopy(t->vt[1], GET_CO(input_mesh, f[1]));
101                         veccopy(t->vt[2], GET_CO(input_mesh, f[2]));
102                 }
103                 else {
104                         veccopy(t->vt[0], GET_CO(input_mesh, f[2]));
105                         veccopy(t->vt[1], GET_CO(input_mesh, f[3]));
106                         veccopy(t->vt[2], GET_CO(input_mesh, f[0]));
107                 }
108
109                 if(offset == 0 && f[3])
110                         offset++;
111                 else {
112                         offset = 0;
113                         curface++;
114                 }
115
116                 /* remove triangle if it contains invalid coords */
117                 for(int i = 0; i < 3; i++) {
118                         const float *co = t->vt[i];
119                         if(isnan(co[0]) || isnan(co[1]) || isnan(co[2])) {
120                                 delete t;
121                                 return getNextTriangle();
122                         }
123                 }
124
125                 return t;
126         }
127
128         int getNextTriangle(int t[3])
129         {
130                 if(curface == input_mesh->totface)
131                         return 0;
132                 
133                 unsigned int *f = GET_FACE(input_mesh, curface);
134                 if(offset == 0) {
135                         t[0] = f[0];
136                         t[1] = f[1];
137                         t[2] = f[2];
138                 }
139                 else {
140                         t[0] = f[2];
141                         t[1] = f[3];
142                         t[2] = f[0];
143                 }
144
145                 if(offset == 0 && f[3])
146                         offset++;
147                 else {
148                         offset = 0;
149                         curface++;
150                 }
151
152                 return 1;
153         }
154
155         int getNumTriangles()
156         {
157                 return tottri;
158         }
159
160         int getNumVertices()
161         {
162                 return input_mesh->totco;
163         }
164
165         float getBoundingBox(float origin[3])
166         {
167                 veccopy(origin, min);
168                 return maxsize ;
169         }
170
171         /* output */
172         void getNextVertex(float v[3])
173         {
174                 /* not used */
175         }
176
177         /* stubs */
178         void printInfo() {}
179         int getMemory() { return sizeof(DualConInputReader); }
180 };
181
182 void *dualcon(const DualConInput *input_mesh,
183                           /* callbacks for output */
184                           DualConAllocOutput alloc_output,
185                           DualConAddVert add_vert,
186                           DualConAddQuad add_quad,
187                                          
188                           DualConFlags flags,
189                           DualConMode mode,
190                           float threshold,
191                           float hermite_num,
192                           float scale,
193                           int depth)
194 {
195         DualConInputReader r(input_mesh, scale);
196         Octree o(&r, alloc_output, add_vert, add_quad,
197                          flags, mode, depth, threshold, hermite_num);
198         o.scanConvert();
199         return o.getOutputMesh();
200 }