Get rid of c++ in blenkernel and modifiers
[blender.git] / source / blender / modifiers / intern / MOD_navmesh.c
index 72fd1c401338ce6167800653243dabfef38dadef..e05f91058f3fc4719312e859be562488247c6bd2 100644 (file)
 * ***** END GPL LICENSE BLOCK *****
 *
 */
+#include <math.h>
 
+#include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h"
+
+#ifdef WITH_GAMEENGINE
+#  include "recast-capi.h"
+#  include "BKE_navmesh_conversion.h"
+#  include "GL/glew.h"
+#  include "GPU_buffers.h"
+#  include "GPU_draw.h"
+#endif
+
 #include "BLI_math.h"
+#include "BLI_utildefines.h"
+
 #include "BKE_cdderivedmesh.h"
 #include "BKE_mesh.h"
 #include "BKE_modifier.h"
 #include "BKE_particle.h"
+#include "BKE_customdata.h"
+#include "MEM_guardedalloc.h"
 
-
-static void initData(ModifierData *md)
+static inline int bit(int a, int b)
 {
-       NavMeshModifierData *nmmd = (NavMeshModifierData*) md;
-
-       nmmd->cellsize = 0.3f;
-       nmmd->cellheight = 0.2f;
-       nmmd->agentmaxslope = 45.0f;
-       nmmd->agentmaxclimb = 0.9f;
-       nmmd->agentheight = 2.0f;
-       nmmd->agentradius = 0.6f;
-       nmmd->edgemaxlen = 12.0f;
-       nmmd->edgemaxerror = 1.3f;
-       nmmd->regionminsize = 50.f;
-       nmmd->regionmergesize = 20.f;
-       nmmd->vertsperpoly = 6;
-       nmmd->detailsampledist = 6.0f;
-       nmmd->detailsamplemaxerror = 1.0f;
+       return (a & (1 << b)) >> b;
 }
 
-static void copyData(ModifierData *md, ModifierData *target)
+static inline void intToCol(int i, float* col)
 {
-       NavMeshModifierData *nmmd = (NavMeshModifierData*) md;
-       NavMeshModifierData *tnmmd = (NavMeshModifierData*) target;
-
+       int     r = bit(i, 0) + bit(i, 3) * 2 + 1;
+       int     g = bit(i, 1) + bit(i, 4) * 2 + 1;
+       int     b = bit(i, 2) + bit(i, 5) * 2 + 1;
+       col[0] = 1 - r*63.0f/255.0f;
+       col[1] = 1 - g*63.0f/255.0f;
+       col[2] = 1 - b*63.0f/255.0f;
 }
 
-static DerivedMesh *createNavMesh(NavMeshModifierData *mmd,DerivedMesh *dm)
-{
-       int i;
-       DerivedMesh *result;
-       int numVerts, numEdges, numFaces;
-       int maxVerts = dm->getNumVerts(dm);
-       int maxEdges = dm->getNumEdges(dm);
-       int maxFaces = dm->getNumFaces(dm);
-
-       numVerts = numEdges = numFaces = 0;
 
-       result = CDDM_from_template(dm, maxVerts * 2, maxEdges * 2, maxFaces * 2);
+static void initData(ModifierData *UNUSED(md))
+{
+       /* NavMeshModifierData *nmmd = (NavMeshModifierData*) md; */ /* UNUSED */
+}
 
-       for(i = 0; i < maxVerts; i++) {
-               MVert inMV;
-               MVert *mv = CDDM_get_vert(result, numVerts);
-               float co[3];
+static void copyData(ModifierData *UNUSED(md), ModifierData *UNUSED(target))
+{
+       /* NavMeshModifierData *nmmd = (NavMeshModifierData*) md; */
+       /* NavMeshModifierData *tnmmd = (NavMeshModifierData*) target; */
 
-               dm->getVert(dm, i, &inMV);
+       //.todo - deep copy
+}
 
-               copy_v3_v3(co, inMV.co);
-               DM_copy_vert_data(dm, result, i, numVerts, 1);
-               *mv = inMV;
-               numVerts++;
+/*
+static void (*drawFacesSolid_original)(DerivedMesh *dm, float (*partial_redraw_planes)[4],
+                                          int fast, int (*setMaterial)(int, void *attribs)) = NULL;*/
 
+#ifdef WITH_GAMEENGINE
 
-               {
-                       MVert *mv2 = CDDM_get_vert(result, numVerts);
-                       DM_copy_vert_data(dm, result, i, numVerts, 1);
-                       *mv2 = *mv;
-                       co[2] +=.5f;
-                       copy_v3_v3(mv2->co, co);
-                       numVerts++;
+static void drawNavMeshColored(DerivedMesh *dm)
+{
+       int a, glmode;
+       MVert *mvert = (MVert *)CustomData_get_layer(&dm->vertData, CD_MVERT);
+       MFace *mface = (MFace *)CustomData_get_layer(&dm->faceData, CD_MFACE);
+       int* polygonIdx = (int*)CustomData_get_layer(&dm->faceData, CD_RECAST);
+       const float BLACK_COLOR[3] = {0.f, 0.f, 0.f};
+       float col[3];
+
+       if (!polygonIdx)
+               return;
+
+       /*
+       //UI_ThemeColor(TH_WIRE);
+       glDisable(GL_LIGHTING);
+       glLineWidth(2.0);
+       dm->drawEdges(dm, 0, 1);
+       glLineWidth(1.0);
+       glEnable(GL_LIGHTING);*/
+
+       glDisable(GL_LIGHTING);
+       if(GPU_buffer_legacy(dm) ) {
+               DEBUG_VBO( "Using legacy code. drawNavMeshColored\n" );
+               //glShadeModel(GL_SMOOTH);
+               glBegin(glmode = GL_QUADS);
+               for(a = 0; a < dm->numFaceData; a++, mface++) {
+                       int new_glmode = mface->v4?GL_QUADS:GL_TRIANGLES;
+                       int polygonIdx = *(int*)CustomData_get(&dm->faceData, a, CD_RECAST);
+                       if (polygonIdx<=0)
+                               memcpy(col, BLACK_COLOR, 3*sizeof(float));
+                       else
+                               intToCol(polygonIdx, col);
+
+                       if(new_glmode != glmode) {
+                               glEnd();
+                               glBegin(glmode = new_glmode);
+                       }
+                       glColor3fv(col);
+                       glVertex3fv(mvert[mface->v1].co);
+                       glVertex3fv(mvert[mface->v2].co);
+                       glVertex3fv(mvert[mface->v3].co);
+                       if(mface->v4) {
+                               glVertex3fv(mvert[mface->v4].co);
+                       }
                }
-
+               glEnd();
        }
+       glEnable(GL_LIGHTING);
+}
 
-       for(i = 0; i < maxEdges; i++) {
-               MEdge inMED;
-               MEdge *med = CDDM_get_edge(result, numEdges);
-
-               dm->getEdge(dm, i, &inMED);
-
-               DM_copy_edge_data(dm, result, i, numEdges, 1);
-               *med = inMED;
-               numEdges++;
+static void navDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr))
+{
+       (void) setDrawOptions;
 
-               med->v1 = inMED.v1*2;
-               med->v2 = inMED.v2*2;
-               //med->flag |= ME_EDGEDRAW | ME_EDGERENDER;
+       drawNavMeshColored(dm);
+}
 
-               {
-                       MEdge *med2 = CDDM_get_edge(result, numEdges);
+static void navDM_drawFacesSolid(DerivedMesh *dm,
+                                                               float (*partial_redraw_planes)[4],
+                                                               int UNUSED(fast), int (*setMaterial)(int, void *attribs))
+{
+       (void) partial_redraw_planes;
+       (void) setMaterial;
 
-                       DM_copy_edge_data(dm, result, i, numEdges, 1);
-                       *med2 = *med;
-                       numEdges++;
+       //drawFacesSolid_original(dm, partial_redraw_planes, fast, setMaterial);
+       drawNavMeshColored(dm);
+}
+#endif /* WITH_GAMEENGINE */
 
-                       med2->v1 += 1;
-                       med2->v2 += 1;
-               }               
+static DerivedMesh *createNavMeshForVisualization(NavMeshModifierData *UNUSED(mmd), DerivedMesh *dm)
+{
+#ifdef WITH_GAMEENGINE
+       DerivedMesh *result;
+       int maxFaces = dm->getNumFaces(dm);
+       int *recastData;
+       int vertsPerPoly=0, nverts=0, ndtris=0, npolys=0; 
+       float* verts=NULL;
+       unsigned short *dtris=NULL, *dmeshes=NULL, *polys=NULL;
+       int *dtrisToPolysMap=NULL, *dtrisToTrisMap=NULL, *trisToFacesMap=NULL;
+       int res;
+
+       result = CDDM_copy(dm);
+       if (!CustomData_has_layer(&result->faceData, CD_RECAST)) 
+       {
+               int *sourceRecastData = (int*)CustomData_get_layer(&dm->faceData, CD_RECAST);
+               CustomData_add_layer_named(&result->faceData, CD_RECAST, CD_DUPLICATE, 
+                       sourceRecastData, maxFaces, "recastData");
        }
-
-       for(i = 0; i < maxFaces; i++) {
-               MFace inMF;
-               MFace *mf = CDDM_get_face(result, numFaces);
-
-               dm->getFace(dm, i, &inMF);
-
-               DM_copy_face_data(dm, result, i, numFaces, 1);
-               *mf = inMF;
-               numFaces++;
-
-               mf->v1 = inMF.v1*2;
-               mf->v2 = inMF.v2*2;
-               mf->v3 = inMF.v3*2;
-               mf->v4 = inMF.v4*2;
-
+       recastData = (int*)CustomData_get_layer(&result->faceData, CD_RECAST);
+       result->drawFacesTex =  navDM_drawFacesTex;
+       result->drawFacesSolid = navDM_drawFacesSolid;
+       
+       
+       //process mesh
+       res  = buildNavMeshDataByDerivedMesh(dm, &vertsPerPoly, &nverts, &verts, &ndtris, &dtris,
+                                                                               &npolys, &dmeshes, &polys, &dtrisToPolysMap, &dtrisToTrisMap,
+                                                                               &trisToFacesMap);
+       if (res)
+       {
+               size_t polyIdx;
+
+               //invalidate concave polygon
+               for (polyIdx=0; polyIdx<(size_t)npolys; polyIdx++)
                {
-                       MFace *mf2 = CDDM_get_face(result, numFaces);
-                       DM_copy_face_data(dm, result, i, numFaces, 1);
-                       *mf2 = *mf;
-
-                       mf2->v1 += 1;
-                       mf2->v2 += 1;
-                       mf2->v3 += 1;
-                       if(inMF.v4) mf2->v4 += 1;
-
-                       //test_index_face(mf2, &result->faceData, numFaces, inMF.v4?4:3);
-                       numFaces++;
+                       unsigned short* poly = &polys[polyIdx*2*vertsPerPoly];
+                       if (!polyIsConvex(poly, vertsPerPoly, verts))
+                       {
+                               //set negative polygon idx to all faces
+                               unsigned short *dmesh = &dmeshes[4*polyIdx];
+                               unsigned short tbase = dmesh[2];
+                               unsigned short tnum = dmesh[3];
+                               unsigned short ti;
+
+                               for (ti=0; ti<tnum; ti++)
+                               {
+                                       unsigned short triidx = dtrisToTrisMap[tbase+ti];
+                                       unsigned short faceidx = trisToFacesMap[triidx];
+                                       if (recastData[faceidx]>0)
+                                               recastData[faceidx] = -recastData[faceidx];
+                               }                               
+                       }
                }
+
+       }
+       else
+       {
+               printf("Error during creation polygon infos\n");
        }
 
-/*
-       CDDM_lower_num_verts(result, numVerts);
-       CDDM_lower_num_edges(result, numEdges);
-       CDDM_lower_num_faces(result, numFaces);*/       
+       //clean up
+       if (verts!=NULL)
+               MEM_freeN(verts);
+       if (dtris!=NULL)
+               MEM_freeN(dtris);
+       if (dmeshes!=NULL)
+               MEM_freeN(dmeshes);
+       if (polys!=NULL)
+               MEM_freeN(polys);
+       if (dtrisToPolysMap!=NULL)
+               MEM_freeN(dtrisToPolysMap);
+       if (dtrisToTrisMap!=NULL)
+               MEM_freeN(dtrisToTrisMap);
+       if (trisToFacesMap!=NULL)
+               MEM_freeN(trisToFacesMap);
 
        return result;
+#else // WITH_GAMEENGINE
+       return dm;
+#endif // WITH_GAMEENGINE
 }
 
+/*
+static int isDisabled(ModifierData *md, int useRenderParams)
+{
+       NavMeshModifierData *amd = (NavMeshModifierData*) md;
+       return false; 
+}*/
+
+
 
 static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData,
-                                                                 int useRenderParams, int isFinalCalc)
+                                                                 int UNUSED(useRenderParams), int UNUSED(isFinalCalc))
 {
-       DerivedMesh *result;
-
+       DerivedMesh *result = NULL;
        NavMeshModifierData *nmmd = (NavMeshModifierData*) md;
+       int hasRecastData = CustomData_has_layer(&derivedData->faceData, CD_RECAST)>0;
+       if (ob->body_type!=OB_BODY_TYPE_NAVMESH || !hasRecastData )
+       {
+               //convert to nav mesh object:
+               //1)set physics type
+               ob->gameflag &= ~OB_COLLISION;
+               ob->gameflag |= OB_NAVMESH;
+               ob->body_type = OB_BODY_TYPE_NAVMESH;
+               //2)add and init recast data layer
+               if (!hasRecastData)
+               {
+                       Mesh* obmesh = (Mesh *)ob->data;
+                       if (obmesh)
+                       {
+                               int i;
+                               int numFaces = obmesh->totface;
+                               int* recastData;
+                               CustomData_add_layer_named(&obmesh->fdata, CD_RECAST, CD_CALLOC, NULL, numFaces, "recastData");
+                               recastData = (int*)CustomData_get_layer(&obmesh->fdata, CD_RECAST);
+                               for (i=0; i<numFaces; i++)
+                               {
+                                       recastData[i] = i+1;
+                               }
+                               CustomData_add_layer_named(&derivedData->faceData, CD_RECAST, CD_REFERENCE, recastData, numFaces, "recastData");
+                       }
+               }
+       }
 
-       result = createNavMesh(nmmd, derivedData);
-
+       result = createNavMeshForVisualization(nmmd, derivedData);
+       
        return result;
 }
 
@@ -180,9 +287,11 @@ ModifierTypeInfo modifierType_NavMesh = {
        /* structName */        "NavMeshModifierData",
        /* structSize */        sizeof(NavMeshModifierData),
        /* type */              eModifierTypeType_Constructive,
-       /* flags */             eModifierTypeFlag_AcceptsMesh,
+       /* flags */             (ModifierTypeFlag) (eModifierTypeFlag_AcceptsMesh
+                                                       | eModifierTypeFlag_Single),
        /* copyData */          copyData,
        /* deformVerts */       0,
+       /* deformMatrices */    0,
        /* deformVertsEM */     0,
        /* deformMatricesEM */  0,
        /* applyModifier */     applyModifier,