svn merge ^/trunk/blender -r40394:40395
[blender.git] / source / blender / modifiers / intern / MOD_navmesh.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) 2005 by the Blender Foundation.
21 * All rights reserved.
22 *
23 * Contributor(s): 
24 *
25 * ***** END GPL LICENSE BLOCK *****
26 *
27 */
28 #include <math.h>
29
30 #ifdef WITH_GAMEENGINE
31 #  include "Recast.h"
32 #endif
33
34 extern "C"{
35
36 #ifdef WITH_GAMEENGINE
37 #  include "BKE_navmesh_conversion.h"
38 #  include "GL/glew.h"
39 #  include "GPU_buffers.h"
40 #  include "GPU_draw.h"
41 #endif
42
43 #include "DNA_mesh_types.h"
44 #include "DNA_meshdata_types.h"
45
46 #include "BLI_math.h"
47 #include "BLI_utildefines.h"
48
49 #include "BKE_cdderivedmesh.h"
50 #include "BKE_mesh.h"
51 #include "BKE_modifier.h"
52 #include "BKE_particle.h"
53 #include "BKE_customdata.h"
54 #include "MEM_guardedalloc.h"
55
56 inline int bit(int a, int b)
57 {
58         return (a & (1 << b)) >> b;
59 }
60
61 inline void intToCol(int i, float* col)
62 {
63         int     r = bit(i, 0) + bit(i, 3) * 2 + 1;
64         int     g = bit(i, 1) + bit(i, 4) * 2 + 1;
65         int     b = bit(i, 2) + bit(i, 5) * 2 + 1;
66         col[0] = 1 - r*63.0f/255.0f;
67         col[1] = 1 - g*63.0f/255.0f;
68         col[2] = 1 - b*63.0f/255.0f;
69 }
70
71
72 static void initData(ModifierData *md)
73 {
74         /* NavMeshModifierData *nmmd = (NavMeshModifierData*) md; */ /* UNUSED */
75 }
76
77 static void copyData(ModifierData *md, ModifierData *target)
78 {
79         /* NavMeshModifierData *nmmd = (NavMeshModifierData*) md; */
80         /* NavMeshModifierData *tnmmd = (NavMeshModifierData*) target; */
81
82         //.todo - deep copy
83 }
84
85 /*
86 static void (*drawFacesSolid_original)(DerivedMesh *dm, float (*partial_redraw_planes)[4],
87                                            int fast, int (*setMaterial)(int, void *attribs)) = NULL;*/
88
89 #ifdef WITH_GAMEENGINE
90
91 static void drawNavMeshColored(DerivedMesh *dm)
92 {
93         int a, glmode;
94         MVert *mvert = (MVert *)CustomData_get_layer(&dm->vertData, CD_MVERT);
95         MFace *mface = (MFace *)CustomData_get_layer(&dm->faceData, CD_MFACE);
96         int* polygonIdx = (int*)CustomData_get_layer(&dm->faceData, CD_RECAST);
97         if (!polygonIdx)
98                 return;
99         const float BLACK_COLOR[3] = {0.f, 0.f, 0.f};
100         float col[3];
101         /*
102         //UI_ThemeColor(TH_WIRE);
103         glDisable(GL_LIGHTING);
104         glLineWidth(2.0);
105         dm->drawEdges(dm, 0, 1);
106         glLineWidth(1.0);
107         glEnable(GL_LIGHTING);*/
108
109         glDisable(GL_LIGHTING);
110         if(GPU_buffer_legacy(dm) ) {
111                 DEBUG_VBO( "Using legacy code. drawNavMeshColored\n" );
112                 //glShadeModel(GL_SMOOTH);
113                 glBegin(glmode = GL_QUADS);
114                 for(a = 0; a < dm->numFaceData; a++, mface++) {
115                         int new_glmode = mface->v4?GL_QUADS:GL_TRIANGLES;
116                         int polygonIdx = *(int*)CustomData_get(&dm->faceData, a, CD_RECAST);
117                         if (polygonIdx<=0)
118                                 memcpy(col, BLACK_COLOR, 3*sizeof(float));
119                         else
120                                 intToCol(polygonIdx, col);
121
122                         if(new_glmode != glmode) {
123                                 glEnd();
124                                 glBegin(glmode = new_glmode);
125                         }
126                         glColor3fv(col);
127                         glVertex3fv(mvert[mface->v1].co);
128                         glVertex3fv(mvert[mface->v2].co);
129                         glVertex3fv(mvert[mface->v3].co);
130                         if(mface->v4) {
131                                 glVertex3fv(mvert[mface->v4].co);
132                         }
133                 }
134                 glEnd();
135         }
136         glEnable(GL_LIGHTING);
137 }
138
139 static void navDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr))
140 {
141         drawNavMeshColored(dm);
142 }
143
144 static void navDM_drawFacesSolid(DerivedMesh *dm,
145                                                                 float (*partial_redraw_planes)[4],
146                                                                 int fast, int (*setMaterial)(int, void *attribs))
147 {
148         //drawFacesSolid_original(dm, partial_redraw_planes, fast, setMaterial);
149         drawNavMeshColored(dm);
150 }
151 #endif /* WITH_GAMEENGINE */
152
153 static DerivedMesh *createNavMeshForVisualization(NavMeshModifierData *mmd,DerivedMesh *dm)
154 {
155 #ifdef WITH_GAMEENGINE
156         DerivedMesh *result;
157         int maxFaces = dm->getNumFaces(dm);
158
159         result = CDDM_copy(dm);
160         if (!CustomData_has_layer(&result->faceData, CD_RECAST)) 
161         {
162                 int *sourceRecastData = (int*)CustomData_get_layer(&dm->faceData, CD_RECAST);
163                 CustomData_add_layer_named(&result->faceData, CD_RECAST, CD_DUPLICATE, 
164                         sourceRecastData, maxFaces, "recastData");
165         }
166         int *recastData = (int*)CustomData_get_layer(&result->faceData, CD_RECAST);
167         result->drawFacesTex =  navDM_drawFacesTex;
168         result->drawFacesSolid = navDM_drawFacesSolid;
169         
170         
171         //process mesh
172         int vertsPerPoly=0, nverts=0, ndtris=0, npolys=0; 
173         float* verts=NULL;
174         unsigned short *dtris=NULL, *dmeshes=NULL, *polys=NULL;
175         int *dtrisToPolysMap=NULL, *dtrisToTrisMap=NULL, *trisToFacesMap=NULL;
176
177         bool res  = buildNavMeshDataByDerivedMesh(dm, vertsPerPoly, nverts, verts, ndtris, dtris,
178                                                                                 npolys, dmeshes, polys, dtrisToPolysMap, dtrisToTrisMap,
179                                                                                 trisToFacesMap);
180         if (res)
181         {
182                 //invalidate concave polygon
183                 for (size_t polyIdx=0; polyIdx<(size_t)npolys; polyIdx++)
184                 {
185                         unsigned short* poly = &polys[polyIdx*2*vertsPerPoly];
186                         if (!polyIsConvex(poly, vertsPerPoly, verts))
187                         {
188                                 //set negative polygon idx to all faces
189                                 unsigned short *dmesh = &dmeshes[4*polyIdx];
190                                 unsigned short tbase = dmesh[2];
191                                 unsigned short tnum = dmesh[3];
192                                 for (unsigned short ti=0; ti<tnum; ti++)
193                                 {
194                                         unsigned short triidx = dtrisToTrisMap[tbase+ti];
195                                         unsigned short faceidx = trisToFacesMap[triidx];
196                                         if (recastData[faceidx]>0)
197                                                 recastData[faceidx] = -recastData[faceidx];
198                                 }                               
199                         }
200                 }
201
202         }
203         else
204         {
205                 printf("Error during creation polygon infos\n");
206         }
207
208         //clean up
209         if (verts!=NULL)
210                 delete verts;
211         if (dtris!=NULL)
212                 delete dtris;
213         if (dmeshes!=NULL)
214                 delete dmeshes;
215         if (polys!=NULL)
216                 delete polys;
217         if (dtrisToPolysMap!=NULL)
218                 delete dtrisToPolysMap;
219         if (dtrisToTrisMap!=NULL)
220                 delete dtrisToTrisMap;  
221         if (trisToFacesMap!=NULL)
222                 delete trisToFacesMap;          
223
224         return result;
225 #else // WITH_GAMEENGINE
226         return dm;
227 #endif // WITH_GAMEENGINE
228 }
229
230 /*
231 static int isDisabled(ModifierData *md, int useRenderParams)
232 {
233         NavMeshModifierData *amd = (NavMeshModifierData*) md;
234         return false; 
235 }*/
236
237
238
239 static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData,
240                                                                   int useRenderParams, int isFinalCalc)
241 {
242         DerivedMesh *result = NULL;
243         NavMeshModifierData *nmmd = (NavMeshModifierData*) md;
244         bool hasRecastData = CustomData_has_layer(&derivedData->faceData, CD_RECAST)>0;
245         if (ob->body_type!=OB_BODY_TYPE_NAVMESH || !hasRecastData )
246         {
247                 //convert to nav mesh object:
248                 //1)set physics type
249                 ob->gameflag &= ~OB_COLLISION;
250                 ob->gameflag |= OB_NAVMESH;
251                 ob->body_type = OB_BODY_TYPE_NAVMESH;
252                 //2)add and init recast data layer
253                 if (!hasRecastData)
254                 {
255                         Mesh* obmesh = (Mesh *)ob->data;
256                         if (obmesh)
257                         {
258                                 int numFaces = obmesh->totface;
259                                 CustomData_add_layer_named(&obmesh->fdata, CD_RECAST, CD_CALLOC, NULL, numFaces, "recastData");
260                                 int* recastData = (int*)CustomData_get_layer(&obmesh->fdata, CD_RECAST);
261                                 for (int i=0; i<numFaces; i++)
262                                 {
263                                         recastData[i] = i+1;
264                                 }
265                                 CustomData_add_layer_named(&derivedData->faceData, CD_RECAST, CD_REFERENCE, recastData, numFaces, "recastData");
266                         }
267                 }
268         }
269
270         result = createNavMeshForVisualization(nmmd, derivedData);
271         
272         return result;
273 }
274
275
276 ModifierTypeInfo modifierType_NavMesh = {
277         /* name */              "NavMesh",
278         /* structName */        "NavMeshModifierData",
279         /* structSize */        sizeof(NavMeshModifierData),
280         /* type */              eModifierTypeType_Constructive,
281         /* flags */             (ModifierTypeFlag) (eModifierTypeFlag_AcceptsMesh
282                                                         | eModifierTypeFlag_Single),
283         /* copyData */          copyData,
284         /* deformVerts */       0,
285         /* deformMatrices */    0,
286         /* deformVertsEM */     0,
287         /* deformMatricesEM */  0,
288         /* applyModifier */     applyModifier,
289         /* applyModifierEM */   0,
290         /* initData */          initData,
291         /* requiredDataMask */  0,
292         /* freeData */          0,
293         /* isDisabled */        0,
294         /* updateDepgraph */    0,
295         /* dependsOnTime */     0,
296         /* foreachObjectLink */ 0,
297         /* foreachIDLink */     0,
298 };
299
300 };