svn merge ^/trunk/blender -r40644:40720
[blender-staging.git] / extern / recastnavigation / recast-capi.cpp
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2011 Blender Foundation.
21  * All rights reserved.
22  *
23  * Contributor(s): Sergey Sharybin
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include "recast-capi.h"
29
30 #include <math.h>
31 #include "Recast.h"
32
33 static rcContext *sctx;
34
35 #define INIT_SCTX()                     \
36         if (sctx == NULL) sctx = new rcContext(false)
37
38 int recast_buildMeshAdjacency(unsigned short* polys, const int npolys,
39                         const int nverts, const int vertsPerPoly)
40 {
41         return (int) buildMeshAdjacency(polys, npolys, nverts, vertsPerPoly);
42 }
43
44 void recast_calcBounds(const float *verts, int nv, float *bmin, float *bmax)
45 {
46         rcCalcBounds(verts, nv, bmin, bmax);
47 }
48
49 void recast_calcGridSize(const float *bmin, const float *bmax, float cs, int *w, int *h)
50 {
51         rcCalcGridSize(bmin, bmax, cs, w, h);
52 }
53
54 struct recast_heightfield *recast_newHeightfield(void)
55 {
56         return (struct recast_heightfield *) rcAllocHeightfield();
57 }
58
59 void recast_destroyHeightfield(struct recast_heightfield *heightfield)
60 {
61         rcFreeHeightField((rcHeightfield *) heightfield);
62 }
63
64 int recast_createHeightfield(struct recast_heightfield *hf, int width, int height,
65                         const float *bmin, const float* bmax, float cs, float ch)
66 {
67         INIT_SCTX();
68         return rcCreateHeightfield(sctx, *(rcHeightfield *)hf, width, height, bmin, bmax, cs, ch);
69 }
70
71 void recast_markWalkableTriangles(const float walkableSlopeAngle,const float *verts, int nv,
72                         const int *tris, int nt, unsigned char *flags)
73 {
74         INIT_SCTX();
75         rcMarkWalkableTriangles(sctx, walkableSlopeAngle, verts, nv, tris, nt, flags);
76 }
77
78 void recast_rasterizeTriangles(const float *verts, int nv, const int *tris,
79                         const unsigned char *flags, int nt, struct recast_heightfield *solid)
80 {
81         INIT_SCTX();
82         rcRasterizeTriangles(sctx, verts, nv, tris, flags, nt, *(rcHeightfield *) solid);
83 }
84
85 void recast_filterLedgeSpans(const int walkableHeight, const int walkableClimb,
86                         struct recast_heightfield *solid)
87 {
88         INIT_SCTX();
89         rcFilterLedgeSpans(sctx, walkableHeight, walkableClimb, *(rcHeightfield *) solid);
90 }
91
92 void recast_filterWalkableLowHeightSpans(int walkableHeight, struct recast_heightfield *solid)
93 {
94         INIT_SCTX();
95         rcFilterWalkableLowHeightSpans(sctx, walkableHeight, *(rcHeightfield *) solid);
96 }
97
98 void recast_filterLowHangingWalkableObstacles(const int walkableClimb, struct recast_heightfield *solid)
99 {
100         INIT_SCTX();
101         rcFilterLowHangingWalkableObstacles(sctx, walkableClimb, *(rcHeightfield *) solid);
102 }
103
104 struct recast_compactHeightfield *recast_newCompactHeightfield(void)
105 {
106         return (struct recast_compactHeightfield *) rcAllocCompactHeightfield();
107 }
108
109 void recast_destroyCompactHeightfield(struct recast_compactHeightfield *compactHeightfield)
110 {
111         rcFreeCompactHeightfield( (rcCompactHeightfield *) compactHeightfield);
112 }
113
114 int recast_buildCompactHeightfield(const int walkableHeight, const int walkableClimb,
115                         struct recast_heightfield *hf, struct recast_compactHeightfield *chf)
116 {
117         INIT_SCTX();
118         return rcBuildCompactHeightfield(sctx, walkableHeight, walkableClimb, 
119                 *(rcHeightfield *) hf, *(rcCompactHeightfield *) chf);
120 }
121
122 int recast_erodeWalkableArea(int radius, struct recast_compactHeightfield *chf)
123 {
124         INIT_SCTX();
125         return rcErodeWalkableArea(sctx, radius, *(rcCompactHeightfield *) chf);
126 }
127
128 int recast_buildDistanceField(struct recast_compactHeightfield *chf)
129 {
130         INIT_SCTX();
131         return rcBuildDistanceField(sctx, *(rcCompactHeightfield *) chf);
132 }
133
134 int recast_buildRegions(struct recast_compactHeightfield *chf, int borderSize,
135         int minRegionSize, int mergeRegionSize)
136 {
137         INIT_SCTX();
138         return rcBuildRegions(sctx, *(rcCompactHeightfield *) chf, borderSize,
139                                 minRegionSize, mergeRegionSize);
140 }
141
142 struct recast_contourSet *recast_newContourSet(void)
143 {
144         return (struct recast_contourSet *) rcAllocContourSet();
145 }
146
147 void recast_destroyContourSet(struct recast_contourSet *contourSet)
148 {
149         rcFreeContourSet((rcContourSet *) contourSet);
150 }
151
152 int recast_buildContours(struct recast_compactHeightfield *chf,
153                         const float maxError, const int maxEdgeLen, struct recast_contourSet *cset)
154 {
155         INIT_SCTX();
156         return rcBuildContours(sctx, *(rcCompactHeightfield *) chf, maxError, maxEdgeLen, *(rcContourSet *) cset);
157 }
158
159 struct recast_polyMesh *recast_newPolyMesh(void)
160 {
161         return (recast_polyMesh *) rcAllocPolyMesh();
162 }
163
164 void recast_destroyPolyMesh(struct recast_polyMesh *polyMesh)
165 {
166         rcFreePolyMesh((rcPolyMesh *) polyMesh);
167 }
168
169 int recast_buildPolyMesh(struct recast_contourSet *cset, int nvp, struct recast_polyMesh *mesh)
170 {
171         INIT_SCTX();
172         return rcBuildPolyMesh(sctx, *(rcContourSet *) cset, nvp, * (rcPolyMesh *) mesh);
173 }
174
175 unsigned short *recast_polyMeshGetVerts(struct recast_polyMesh *mesh, int *nverts)
176 {
177         rcPolyMesh *pmesh = (rcPolyMesh *)mesh;
178
179         if (nverts)
180                 *nverts = pmesh->nverts;
181
182         return pmesh->verts;
183 }
184
185 void recast_polyMeshGetBoundbox(struct recast_polyMesh *mesh, float *bmin, float *bmax)
186 {
187         rcPolyMesh *pmesh = (rcPolyMesh *)mesh;
188
189         if (bmin) {
190                 bmin[0] = pmesh->bmin[0];
191                 bmin[1] = pmesh->bmin[1];
192                 bmin[2] = pmesh->bmin[2];
193         }
194
195         if (bmax) {
196                 bmax[0] = pmesh->bmax[0];
197                 bmax[1] = pmesh->bmax[1];
198                 bmax[2] = pmesh->bmax[2];
199         }
200 }
201
202 void recast_polyMeshGetCell(struct recast_polyMesh *mesh, float *cs, float *ch)
203 {
204         rcPolyMesh *pmesh = (rcPolyMesh *)mesh;
205
206         if (cs)
207                 *cs = pmesh->cs;
208
209         if (ch)
210                 *ch = pmesh->ch;
211 }
212
213 unsigned short *recast_polyMeshGetPolys(struct recast_polyMesh *mesh, int *npolys, int *nvp)
214 {
215         rcPolyMesh *pmesh = (rcPolyMesh *)mesh;
216
217         if (npolys)
218                 *npolys = pmesh->npolys;
219
220         if (nvp)
221                 *nvp = pmesh->nvp;
222
223         return pmesh->polys;
224 }
225
226 struct recast_polyMeshDetail *recast_newPolyMeshDetail(void)
227 {
228         return (struct recast_polyMeshDetail *) rcAllocPolyMeshDetail();
229 }
230
231 void recast_destroyPolyMeshDetail(struct recast_polyMeshDetail *polyMeshDetail)
232 {
233         rcFreePolyMeshDetail((rcPolyMeshDetail *) polyMeshDetail);
234 }
235
236 int recast_buildPolyMeshDetail(const struct recast_polyMesh *mesh, const struct recast_compactHeightfield *chf,
237                         const float sampleDist, const float sampleMaxError, struct recast_polyMeshDetail *dmesh)
238 {
239         INIT_SCTX();
240         return rcBuildPolyMeshDetail(sctx, *(rcPolyMesh *) mesh, *(rcCompactHeightfield *) chf,
241                         sampleDist, sampleMaxError, *(rcPolyMeshDetail *) dmesh);
242 }
243
244 float *recast_polyMeshDetailGetVerts(struct recast_polyMeshDetail *mesh, int *nverts)
245 {
246         rcPolyMeshDetail *dmesh = (rcPolyMeshDetail *)mesh;
247
248         if (nverts)
249                 *nverts = dmesh->nverts;
250
251         return dmesh->verts;
252 }
253
254 unsigned char *recast_polyMeshDetailGetTris(struct recast_polyMeshDetail *mesh, int *ntris)
255 {
256         rcPolyMeshDetail *dmesh = (rcPolyMeshDetail *)mesh;
257
258         if (ntris)
259                 *ntris = dmesh->ntris;
260
261         return dmesh->tris;
262 }
263
264 unsigned int *recast_polyMeshDetailGetMeshes(struct recast_polyMeshDetail *mesh, int *nmeshes)
265 {
266         rcPolyMeshDetail *dmesh = (rcPolyMeshDetail *)mesh;
267
268         if (nmeshes)
269                 *nmeshes = dmesh->nmeshes;
270
271         return dmesh->meshes;
272 }
273
274 //  qsort based on FreeBSD source (libkern\qsort.c)
275 typedef int     cmp_t(void *, const void *, const void *);
276 static inline char      *med3(char *, char *, char *, cmp_t *, void *);
277 static inline void       swapfunc(char *, char *, int, int);
278
279 #define min(a, b)       (a) < (b) ? a : b
280 #define swapcode(TYPE, parmi, parmj, n)         \
281 {                                                                                       \
282         long i = (n) / sizeof (TYPE);                   \
283         TYPE *pi = (TYPE *) (parmi);                    \
284         TYPE *pj = (TYPE *) (parmj);                    \
285         do {                                                                    \
286                 TYPE    t = *pi;                                        \
287                 *pi++ = *pj;                                            \
288                 *pj++ = t;                                                      \
289         } while (--i > 0);                                              \
290 }
291 #define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
292         es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
293
294 static inline void swapfunc(char* a, char* b, int n, int swaptype)
295 {
296         if(swaptype <= 1)
297                 swapcode(long, a, b, n)
298         else
299         swapcode(char, a, b, n)
300 }
301
302 #define swap(a, b)                                      \
303         if (swaptype == 0) {                    \
304                 long t = *(long *)(a);          \
305                 *(long *)(a) = *(long *)(b);\
306                 *(long *)(b) = t;                       \
307         } else                                                  \
308                 swapfunc(a, b, es, swaptype)
309
310 #define vecswap(a, b, n)        if ((n) > 0) swapfunc(a, b, n, swaptype)
311 #define CMP(t, x, y) (cmp((t), (x), (y)))
312
313 static inline char * med3(char *a, char *b, char *c, cmp_t *cmp, void *thunk)
314 {
315         return CMP(thunk, a, b) < 0 ?
316                 (CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a ))
317                 :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c ));
318 }
319
320 void recast_qsort(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp)
321 {
322         char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
323         int d, r, swaptype, swap_cnt;
324
325 loop:   
326         SWAPINIT(a, es);
327         swap_cnt = 0;
328         if (n < 7) {
329                 for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
330                         for (pl = pm; 
331                                 pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
332                                 pl -= es)
333                                 swap(pl, pl - es);
334                 return;
335         }
336         pm = (char *)a + (n / 2) * es;
337         if (n > 7) {
338                 pl = (char *)a;
339                 pn = (char *)a + (n - 1) * es;
340                 if (n > 40) {
341                         d = (n / 8) * es;
342                         pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk);
343                         pm = med3(pm - d, pm, pm + d, cmp, thunk);
344                         pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk);
345                 }
346                 pm = med3(pl, pm, pn, cmp, thunk);
347         }
348         swap((char *)a, pm);
349         pa = pb = (char *)a + es;
350
351         pc = pd = (char *)a + (n - 1) * es;
352         for (;;) {
353                 while (pb <= pc && (r = CMP(thunk, pb, a)) <= 0) {
354                         if (r == 0) {
355                                 swap_cnt = 1;
356                                 swap(pa, pb);
357                                 pa += es;
358                         }
359                         pb += es;
360                 }
361                 while (pb <= pc && (r = CMP(thunk, pc, a)) >= 0) {
362                         if (r == 0) {
363                                 swap_cnt = 1;
364                                 swap(pc, pd);
365                                 pd -= es;
366                         }
367                         pc -= es;
368                 }
369                 if (pb > pc)
370                         break;
371                 swap(pb, pc);
372                 swap_cnt = 1;
373                 pb += es;
374                 pc -= es;
375         }
376         if (swap_cnt == 0) {  /* Switch to insertion sort */
377                 for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
378                         for (pl = pm; 
379                                 pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
380                                 pl -= es)
381                                 swap(pl, pl - es);
382                 return;
383         }
384
385         pn = (char *)a + n * es;
386         r = min(pa - (char *)a, pb - pa);
387         vecswap((char *)a, pb - r, r);
388         r = min(pd - pc, pn - pd - es);
389         vecswap(pb, pn - r, r);
390         if ((r = pb - pa) > es)
391                 recast_qsort(a, r / es, es, thunk, cmp);
392         if ((r = pd - pc) > es) {
393                 /* Iterate rather than recurse to save stack space */
394                 a = pn - r;
395                 n = r / es;
396                 goto loop;
397         }
398 }
399