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