svn merge ^/trunk/blender -r40872:40890
authorCampbell Barton <ideasman42@gmail.com>
Thu, 13 Oct 2011 22:50:01 +0000 (22:50 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 13 Oct 2011 22:50:01 +0000 (22:50 +0000)
21 files changed:
po/update_msg.py
release/scripts/startup/bl_ui/properties_data_modifier.py
release/scripts/startup/bl_ui/properties_game.py
source/blender/blenkernel/BKE_mesh.h
source/blender/blenkernel/CMakeLists.txt
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/cdderivedmesh.c
source/blender/blenkernel/intern/editderivedbmesh.c
source/blender/blenkernel/intern/mesh.c
source/blender/blenloader/intern/readfile.c
source/blender/editors/interface/interface_handlers.c
source/blender/editors/mesh/mesh_navmesh.c
source/blender/editors/space_view3d/drawmesh.c
source/blender/editors/space_view3d/view3d_select.c
source/blender/makesdna/DNA_modifier_types.h
source/blender/makesrna/intern/rna_modifier.c
source/blender/makesrna/intern/rna_object.c
source/blender/modifiers/CMakeLists.txt
source/blender/modifiers/intern/MOD_navmesh.c [deleted file]
source/blender/modifiers/intern/MOD_util.c
source/tests/CMakeLists.txt

index ca19e0366376d14a1d05114b34e4e891795cbe4a..5986d96f14b333f98b9f71262c3030dfb65b6403 100644 (file)
@@ -123,8 +123,10 @@ def dump_messages_rna(messages):
                 continue
 
             msgsrc = "bpy.types.%s.%s" % (bl_rna.identifier, prop.identifier)
-            messages.setdefault(prop.name, []).append(msgsrc)
-            messages.setdefault(prop.description, []).append(msgsrc)
+            if prop.name and prop.name != prop.identifier:
+                messages.setdefault(prop.name, []).append(msgsrc)
+            if prop.description:
+                messages.setdefault(prop.description, []).append(msgsrc)
 
             if isinstance(prop, bpy.types.EnumProperty):
                 for item in prop.enum_items:
@@ -132,8 +134,11 @@ def dump_messages_rna(messages):
                                                         prop.identifier,
                                                         item.identifier,
                                                         )
-                    messages.setdefault(item.name, []).append(msgsrc)
-                    messages.setdefault(item.description, []).append(msgsrc)
+                    # Here identifier and name can be the same!
+                    if item.name: # and item.name != item.identifier:
+                        messages.setdefault(item.name, []).append(msgsrc)
+                    if item.description:
+                        messages.setdefault(item.description, []).append(msgsrc)
 
     def walkRNA(bl_rna):
 
index 7d4d970b2389957247a6ceb114ca3de999196bb6..146855bb806ebe5cc4823d116c18a3a9659dd029 100644 (file)
@@ -383,10 +383,6 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
         col.label(text="Mirror Object:")
         col.prop(md, "mirror_object", text="")
 
-    def NAVMESH(self, layout, ob, md):
-        layout.operator("mesh.assign_navpolygon")
-        layout.operator("mesh.assign_new_navpolygon")
-
     def MULTIRES(self, layout, ob, md):
         layout.row().prop(md, "subdivision_type", expand=True)
 
index 7650e7b6ee1dce8469350de8474fa775db3d525f..55ab33135795da37a6a20ff08c586ddf54ce0ac2 100644 (file)
@@ -47,8 +47,9 @@ class PHYSICS_PT_game_physics(PhysicsButtonsPanel, Panel):
         layout.prop(game, "physics_type")
         layout.separator()
 
-        #if game.physics_type == 'DYNAMIC':
-        if game.physics_type in {'DYNAMIC', 'RIGID_BODY'}:
+        physics_type = game.physics_type
+
+        if physics_type in {'DYNAMIC', 'RIGID_BODY'}:
             split = layout.split()
 
             col = split.column()
@@ -108,7 +109,7 @@ class PHYSICS_PT_game_physics(PhysicsButtonsPanel, Panel):
             col.prop(game, "lock_rotation_y", text="Y")
             col.prop(game, "lock_rotation_z", text="Z")
 
-        elif game.physics_type == 'SOFT_BODY':
+        elif physics_type == 'SOFT_BODY':
             col = layout.column()
             col.prop(game, "use_actor")
             col.prop(game, "use_ghost")
@@ -143,7 +144,7 @@ class PHYSICS_PT_game_physics(PhysicsButtonsPanel, Panel):
             sub.active = (soft.use_cluster_rigid_to_softbody or soft.use_cluster_soft_to_softbody)
             sub.prop(soft, "cluster_iterations", text="Iterations")
 
-        elif game.physics_type == 'STATIC':
+        elif physics_type == 'STATIC':
             col = layout.column()
             col.prop(game, "use_actor")
             col.prop(game, "use_ghost")
@@ -164,9 +165,13 @@ class PHYSICS_PT_game_physics(PhysicsButtonsPanel, Panel):
             subsub.active = game.use_anisotropic_friction
             subsub.prop(game, "friction_coefficients", text="", slider=True)
 
-        elif game.physics_type in {'SENSOR', 'INVISIBLE', 'NO_COLLISION', 'OCCLUDE'}:
+        elif physics_type in {'SENSOR', 'INVISIBLE', 'NO_COLLISION', 'OCCLUDE'}:
             layout.prop(ob, "hide_render", text="Invisible")
 
+        elif physics_type == 'NAVMESH':
+            layout.operator("mesh.assign_navpolygon")
+            layout.operator("mesh.assign_new_navpolygon")
+
 
 class PHYSICS_PT_game_collision_bounds(PhysicsButtonsPanel, Panel):
     bl_label = "Collision Bounds"
index df22fdcc78af4555166ff19a40f5d8f4ed47b11f..b414bcef474a4114f6bf3883c81d1022e3974aa5 100644 (file)
@@ -196,6 +196,8 @@ int BKE_mesh_validate_dm(struct DerivedMesh *dm);
 
 void BKE_mesh_calc_edges(struct Mesh *mesh, int update);
 
+void BKE_mesh_ensure_navmesh(struct Mesh *me);
+
 /*convert a triangle of loop facedata to mface facedata*/
 void mesh_loops_to_tri_corners(struct CustomData *fdata, struct CustomData *ldata, 
                           struct CustomData *pdata, int lindex[3], int findex, 
index 2a8d0fb0fb9d4d035faab6625b5240058683618b..35116a7e2f41ae784853b80fa71102fa3935864f 100644 (file)
@@ -357,12 +357,14 @@ endif()
 
 if(WITH_GAMEENGINE)
        list(APPEND INC_SYS
-       ../../../extern/recastnavigation
+               ../../../extern/recastnavigation
        )
        list(APPEND SRC
                intern/navmesh_conversion.c
                BKE_navmesh_conversion.h
        )
+
+       add_definitions(-DWITH_GAMEENGINE)
 endif()
 
 ## Warnings as errors, this is too strict!
index 5e0ccac360fc8787ebba92c2e3c3eda5842f0510..1578eebb4fe7099031d6892957e51549674571cc 100644 (file)
 #include "BKE_tessmesh.h"
 #include "BKE_bvhutils.h"
 
+#ifdef WITH_GAMEENGINE
+#include "BKE_navmesh_conversion.h"
+#endif
+
 #include "BLO_sys_types.h" // for intptr_t support
 
 #include "GL/glew.h"
@@ -80,7 +84,9 @@ extern GLubyte stipple_quarttone[128]; /* glutil.c, bad level data */
 static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *ob);
 static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape_uid);
 
-               ///////////////////////////////////
+static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm);
+
+///////////////////////////////////
 ///////////////////////////////////
 
 static MVert *dm_getVertArray(DerivedMesh *dm)
@@ -1432,6 +1438,18 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
                        add_orco_dm(ob, NULL, *deform_r, NULL, CD_ORCO);
        }
 
+#ifdef WITH_GAMEENGINE
+       /* NavMesh - this is a hack but saves having a NavMesh modifier */
+       if ((ob->gameflag & OB_NAVMESH) && (finaldm->type == DM_TYPE_CDDM)) {
+               DerivedMesh *tdm;
+               tdm= navmesh_dm_createNavMeshForVisualization(finaldm);
+               if (finaldm != tdm) {
+                       finaldm->release(finaldm);
+                       finaldm= tdm;
+               }
+       }
+#endif /* WITH_GAMEENGINE */
+
        *final_r = finaldm;
 
        if(orcodm)
@@ -2282,3 +2300,167 @@ void DM_set_object_boundbox(Object *ob, DerivedMesh *dm)
 
        boundbox_set_from_min_max(ob->bb, min, max);
 }
+
+/* --- NAVMESH (begin) --- */
+#ifdef WITH_GAMEENGINE
+
+BM_INLINE int navmesh_bit(int a, int b)
+{
+       return (a & (1 << b)) >> b;
+}
+
+static void navmesh_intToCol(int i, float* col)
+{
+       int     r = navmesh_bit(i, 0) + navmesh_bit(i, 3) * 2 + 1;
+       int     g = navmesh_bit(i, 1) + navmesh_bit(i, 4) * 2 + 1;
+       int     b = navmesh_bit(i, 2) + navmesh_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 void navmesh_drawColored(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
+                               navmesh_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);
+}
+
+static void navmesh_DM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, int has_mcol, int matnr))
+{
+       (void) setDrawOptions;
+
+       navmesh_drawColored(dm);
+}
+
+static void navmesh_DM_drawFacesSolid(DerivedMesh *dm,
+                                      float (*partial_redraw_planes)[4],
+                                      int UNUSED(fast), int (*setMaterial)(int, void *attribs))
+{
+       (void) partial_redraw_planes;
+       (void) setMaterial;
+
+       //drawFacesSolid_original(dm, partial_redraw_planes, fast, setMaterial);
+       navmesh_drawColored(dm);
+}
+
+static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm)
+{
+       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");
+       }
+       recastData = (int*)CustomData_get_layer(&result->faceData, CD_RECAST);
+
+       /* note: This is not good design! - really should not be doing this */
+       result->drawFacesTex =  navmesh_DM_drawFacesTex;
+       result->drawFacesSolid = navmesh_DM_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++) {
+                       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");
+       }
+
+       /* 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;
+}
+
+#endif /* WITH_GAMEENGINE */
+
+/* --- NAVMESH (end) --- */
index f8dfbd4b7b6c36ed189a1a2025f66dbd1fe18863..5fbb87e618c48f5827f04cbef6be78d86a3f3b66 100644 (file)
@@ -787,9 +787,10 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
                                unsigned char *colors = MEM_mallocN(dm->getNumTessFaces(dm)*4*3*sizeof(unsigned char), "cdDM_drawFacesTex_common");
                                for( i=0; i < dm->getNumTessFaces(dm); i++ ) {
                                        for( j=0; j < 4; j++ ) {
-                                               colors[i*12+j*3] = col[i*4+j].r;
+                                               /* bgr -> rgb is intentional (and stupid), but how its stored internally */
+                                               colors[i*12+j*3] = col[i*4+j].b;
                                                colors[i*12+j*3+1] = col[i*4+j].g;
-                                               colors[i*12+j*3+2] = col[i*4+j].b;
+                                               colors[i*12+j*3+2] = col[i*4+j].r;
                                        }
                                }
                                GPU_color3_upload(dm,colors);
index 1b9116a75338811a4cf30ad471ef104133ffff08..acc58b1899ed5690ddd9fd620c79ae998bb98264 100644 (file)
@@ -660,7 +660,9 @@ static void bmDM_drawMappedFaces(DerivedMesh *dm,
                                else {
                                        const GLenum shade_type= drawSmooth ? GL_SMOOTH : GL_FLAT;
                                        if (shade_type != shade_prev) {
-                                               glShadeModel((shade_prev= shade_type));
+                                               if(poly_prev != GL_ZERO) glEnd();
+                                               glShadeModel((shade_prev= shade_type)); /* same as below but switch shading */
+                                               glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
                                        }
                                        if(poly_type != poly_prev) {
                                                if(poly_prev != GL_ZERO) glEnd();
@@ -726,7 +728,9 @@ static void bmDM_drawMappedFaces(DerivedMesh *dm,
                                else {
                                        const GLenum shade_type= drawSmooth ? GL_SMOOTH : GL_FLAT;
                                        if (shade_type != shade_prev) {
-                                               glShadeModel((shade_prev= shade_type));
+                                               if(poly_prev != GL_ZERO) glEnd();
+                                               glShadeModel((shade_prev= shade_type)); /* same as below but switch shading */
+                                               glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
                                        }
                                        if(poly_type != poly_prev) {
                                                if(poly_prev != GL_ZERO) glEnd();
index ce2193fe09a0f098651219a409684d8228f2096b..01f521e3a0265f50531cca3ed1f15a51649a60f7 100644 (file)
@@ -2558,3 +2558,19 @@ void mesh_translate(Mesh *me, float offset[3], int do_keys)
                }
        }
 }
+
+
+void BKE_mesh_ensure_navmesh(Mesh *me)
+{
+       if (!CustomData_has_layer(&me->fdata, CD_RECAST)) {
+               int i;
+               int numFaces = me->totface;
+               int* recastData;
+               CustomData_add_layer_named(&me->fdata, CD_RECAST, CD_CALLOC, NULL, numFaces, "recastData");
+               recastData = (int*)CustomData_get_layer(&me->fdata, CD_RECAST);
+               for (i=0; i<numFaces; i++) {
+                       recastData[i] = i+1;
+               }
+               CustomData_add_layer_named(&me->fdata, CD_RECAST, CD_REFERENCE, recastData, numFaces, "recastData");
+       }
+}
index 6530f25f3499d9fa1ea4d92520f9b83cfb0dd156..91b17d783ab4276ad019085a048aea07501c8a1c 100644 (file)
@@ -4560,7 +4560,9 @@ static void lib_link_scene(FileData *fd, Main *main)
                                seq->scene_sound = NULL;
                                if(seq->scene) {
                                        seq->scene= newlibadr(fd, sce->id.lib, seq->scene);
-                                       seq->scene_sound = sound_scene_add_scene_sound(sce, seq, seq->startdisp, seq->enddisp, seq->startofs + seq->anim_startofs);
+                                       if(seq->scene) {
+                                               seq->scene_sound = sound_scene_add_scene_sound(sce, seq, seq->startdisp, seq->enddisp, seq->startofs + seq->anim_startofs);
+                                       }
                                }
                                if(seq->scene_camera) seq->scene_camera= newlibadr(fd, sce->id.lib, seq->scene_camera);
                                if(seq->sound) {
index 9ad828f91c16c13fa04247c968fc45ddabacb8ac..6417a6b58ddb9e063ae93a406e23c0d2fecb5ddd 100644 (file)
@@ -1481,13 +1481,12 @@ static void ui_textedit_move(uiBut *but, uiHandleButtonData *data, int direction
        }
 }
 
-static int ui_textedit_delete(uiBut *but, uiHandleButtonData *data, int direction, int all)
+static int ui_textedit_delete(uiBut *but, uiHandleButtonData *data, int direction, const int all, const int jump)
 {
-       char *str;
-       int len, x, changed= 0;
+       char *str= data->str;
+       const int len= strlen(str);
 
-       str= data->str;
-       len= strlen(str);
+       int x, changed= 0;
 
        if(all) {
                if(len) changed=1;
@@ -1499,9 +1498,24 @@ static int ui_textedit_delete(uiBut *but, uiHandleButtonData *data, int directio
                        changed= ui_textedit_delete_selection(but, data);
                }
                else if(but->pos>=0 && but->pos<len) {
+                       int step;
+
+                       if (jump) {
+                               x = but->pos;
+                               step= 0;
+                               while(x < len) {
+                                       x++;
+                                       step++;
+                                       if(test_special_char(str[x])) break;
+                               }
+                       }
+                       else {
+                               step= 1;
+                       }
+
                        for(x=but->pos; x<len; x++)
-                               str[x]= str[x+1];
-                       str[len-1]='\0';
+                               str[x]= str[x+step];
+                       str[len-step]='\0';
                        changed= 1;
                }
        }
@@ -1511,11 +1525,26 @@ static int ui_textedit_delete(uiBut *but, uiHandleButtonData *data, int directio
                                changed= ui_textedit_delete_selection(but, data);
                        }
                        else if(but->pos>0) {
+                               int step;
+
+                               if (jump) {
+                                       x = but->pos;
+                                       step= 0;
+                                       while(x > 0) {
+                                               x--;
+                                               step++;
+                                               if((step > 1) && test_special_char(str[x])) break;
+                                       }
+                               }
+                               else {
+                                       step= 1;
+                               }
+
                                for(x=but->pos; x<len; x++)
-                                       str[x-1]= str[x];
-                               str[len-1]='\0';
+                                       str[x-step]= str[x];
+                               str[len-step]='\0';
 
-                               but->pos--;
+                               but->pos -= step;
                                changed= 1;
                        }
                } 
@@ -1846,12 +1875,12 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
                                retval= WM_UI_HANDLER_BREAK;
                                break;
                        case DELKEY:
-                               changed= ui_textedit_delete(but, data, 1, 0);
+                               changed= ui_textedit_delete(but, data, 1, 0, event->ctrl);
                                retval= WM_UI_HANDLER_BREAK;
                                break;
 
                        case BACKSPACEKEY:
-                               changed= ui_textedit_delete(but, data, 0, event->shift);
+                               changed= ui_textedit_delete(but, data, 0, event->shift, event->ctrl);
                                retval= WM_UI_HANDLER_BREAK;
                                break;
                                
index e4b884744e1a3a13f4ab986dff242f08bfb8bc48..f427b51570bfab65681ae67459f6c3cd37a4be5b 100644 (file)
@@ -296,7 +296,6 @@ static Object* createRepresentation(bContext *C, struct recast_polyMesh *pmesh,
        int i,j, k;
        unsigned short* v;
        int face[3];
-       Main *bmain= CTX_data_main(C);
        Scene *scene= CTX_data_scene(C);
        Object* obedit;
        int createob= base==NULL;
@@ -305,7 +304,6 @@ static Object* createRepresentation(bContext *C, struct recast_polyMesh *pmesh,
        unsigned int *meshes;
        float bmin[3], cs, ch, *dverts;
        unsigned char *tris;
-       ModifierData *md;
 
        zero_v3(co);
        zero_v3(rot);
@@ -419,11 +417,8 @@ static Object* createRepresentation(bContext *C, struct recast_polyMesh *pmesh,
                obedit->body_type= OB_BODY_TYPE_NAVMESH;
                rename_id((ID *)obedit, "Navmesh");
        }
-       
-       md= modifiers_findByType(obedit, eModifierType_NavMesh);
-       if(!md) {
-               ED_object_modifier_add(NULL, bmain, scene, obedit, NULL, eModifierType_NavMesh);
-       }
+
+       BKE_mesh_ensure_navmesh(obedit->data);
 
        return obedit;
 }
index 7e8448917b1cb16fbc86763cc33aec4f37e53f93..ae9ef2c4dfdbe4db983d7b8387a35c1c2146938d 100644 (file)
@@ -453,9 +453,9 @@ static void add_tface_color_layer(DerivedMesh *dm)
                        }
                } else if (tface && tface->mode&TF_OBCOL) {
                        for(j=0;j<4;j++) {
-                               finalCol[i*4+j].r = FTOCHAR(Gtexdraw.obcol[0]);
+                               finalCol[i*4+j].b = FTOCHAR(Gtexdraw.obcol[0]);
                                finalCol[i*4+j].g = FTOCHAR(Gtexdraw.obcol[1]);
-                               finalCol[i*4+j].b = FTOCHAR(Gtexdraw.obcol[2]);
+                               finalCol[i*4+j].r = FTOCHAR(Gtexdraw.obcol[2]);
                        }
                } else if (!mcol) {
                        if (tface) {
@@ -474,9 +474,9 @@ static void add_tface_color_layer(DerivedMesh *dm)
                                        else copy_v3_v3(col, &ma->r);
                                        
                                        for(j=0;j<4;j++) {
-                                               finalCol[i*4+j].b = FTOCHAR(col[2]);
+                                               finalCol[i*4+j].b = FTOCHAR(col[0]);
                                                finalCol[i*4+j].g = FTOCHAR(col[1]);
-                                               finalCol[i*4+j].r = FTOCHAR(col[0]);
+                                               finalCol[i*4+j].r = FTOCHAR(col[2]);
                                        }
                                }
                                else
@@ -488,9 +488,9 @@ static void add_tface_color_layer(DerivedMesh *dm)
                        }
                } else {
                        for(j=0;j<4;j++) {
-                               finalCol[i*4+j].b = mcol[i*4+j].r;
+                               finalCol[i*4+j].r = mcol[i*4+j].r;
                                finalCol[i*4+j].g = mcol[i*4+j].g;
-                               finalCol[i*4+j].r = mcol[i*4+j].b;
+                               finalCol[i*4+j].b = mcol[i*4+j].b;
                        }
                }
        }
index 28f220cd6d005f6f738473837bf5d858454a643c..f30b20ba7d681ed8a043e1af015d21ce5b7af313 100644 (file)
@@ -1953,7 +1953,7 @@ void VIEW3D_OT_select_border(wmOperatorType *ot)
 
 /* much like facesel_face_pick()*/
 /* returns 0 if not found, otherwise 1 */
-static int vertsel_vert_pick(struct bContext *C, Mesh *me, const int mval[2], unsigned int *index, short rect)
+static int vertsel_vert_pick(struct bContext *C, Mesh *me, const int mval[2], unsigned int *index, int size)
 {
        ViewContext vc;
        view3d_set_viewcontext(C, &vc);
@@ -1961,12 +1961,12 @@ static int vertsel_vert_pick(struct bContext *C, Mesh *me, const int mval[2], un
        if (!me || me->totvert==0)
                return 0;
 
-       if (rect) {
+       if (size > 0) {
                /* sample rect to increase changes of selecting, so that when clicking
                   on an face in the backbuf, we can still select a vert */
 
                int dist;
-               *index = view3d_sample_backbuf_rect(&vc, mval, 3, 1, me->totvert+1, &dist,0,NULL, NULL);
+               *index = view3d_sample_backbuf_rect(&vc, mval, size, 1, me->totvert+1, &dist,0,NULL, NULL);
        }
        else {
                /* sample only on the exact position */
@@ -1988,7 +1988,8 @@ static int mouse_weight_paint_vertex_select(bContext *C, const int mval[2], shor
        Mesh* me= obact->data; /* already checked for NULL */
        unsigned int index = 0;
        MVert *mv;
-       if(vertsel_vert_pick(C, me, mval, &index, 1)) {
+
+       if(vertsel_vert_pick(C, me, mval, &index, 50)) {
                mv = me->mvert+index;
                if(extend) {
                        mv->flag ^= SELECT;
index 84c09e8ade9d18e4147ef811547e70aca093ede0..7bc81e7fe057dc3a82518deedb8aed453f603f1b 100644 (file)
@@ -74,7 +74,6 @@ typedef enum ModifierType {
        eModifierType_WeightVGEdit,
        eModifierType_WeightVGMix,
        eModifierType_WeightVGProximity,
-       eModifierType_NavMesh,
        eModifierType_DynamicPaint, /* reserve slot */
 
        /* BMESH ONLY - keeps getting bumped by new modifiers in trunk */
@@ -760,10 +759,6 @@ typedef struct NgonInterpModifierData {
        int             resolution, pad0;
 } NgonInterpModifierData;
 
-typedef struct NavMeshModifierData {
-       ModifierData modifier;
-} NavMeshModifierData;
-
 typedef struct WarpModifierData {
        ModifierData modifier;
        /* keep in sync with MappingInfoModifierData */
index 614e5ab243d405e3ef04ecbb8ed970eead809544..896f1eed12779f3d92c2952e38f6b5ccbc655e4a 100644 (file)
@@ -91,7 +91,6 @@ EnumPropertyItem modifier_type_items[] ={
        {eModifierType_Collision, "COLLISION", ICON_MOD_PHYSICS, "Collision", ""},
        {eModifierType_Explode, "EXPLODE", ICON_MOD_EXPLODE, "Explode", ""},
        {eModifierType_Fluidsim, "FLUID_SIMULATION", ICON_MOD_FLUIDSIM, "Fluid Simulation", ""},
-       {eModifierType_NavMesh, "NAVMESH", ICON_MOD_PHYSICS, "Navigation mesh", ""},
        {eModifierType_ParticleInstance, "PARTICLE_INSTANCE", ICON_MOD_PARTICLES, "Particle Instance", ""},
        {eModifierType_ParticleSystem, "PARTICLE_SYSTEM", ICON_MOD_PARTICLES, "Particle System", ""},
        {eModifierType_Smoke, "SMOKE", ICON_MOD_SMOKE, "Smoke", ""},
@@ -192,8 +191,6 @@ static StructRNA* rna_Modifier_refine(struct PointerRNA *ptr)
                        return &RNA_ScrewModifier;
                case eModifierType_Warp:
                        return &RNA_WarpModifier;
-               case eModifierType_NavMesh:
-                       return &RNA_NavMeshModifier;
                case eModifierType_WeightVGEdit:
                        return &RNA_VertexWeightEditModifier;
                case eModifierType_WeightVGMix:
@@ -2493,17 +2490,6 @@ static void rna_def_modifier_screw(BlenderRNA *brna)
        RNA_def_property_update(prop, 0, "rna_Modifier_update");*/
 }
 
-static void rna_def_modifier_navmesh(BlenderRNA *brna)
-{
-       StructRNA *srna;
-       /* PropertyRNA *prop; */ /* UNUSED */
-
-       srna= RNA_def_struct(brna, "NavMeshModifier", "Modifier");
-       RNA_def_struct_ui_text(srna, "NavMesh Modifier", "NavMesh modifier");
-       RNA_def_struct_sdna(srna, "NavMeshModifierData");
-       RNA_def_struct_ui_icon(srna, ICON_MOD_DECIM);
-}
-
 static void rna_def_modifier_weightvg_mask(BlenderRNA *brna, StructRNA *srna)
 {
        static EnumPropertyItem weightvg_mask_tex_map_items[] = {
@@ -2915,7 +2901,6 @@ void RNA_def_modifier(BlenderRNA *brna)
        rna_def_modifier_smoke(brna);
        rna_def_modifier_solidify(brna);
        rna_def_modifier_screw(brna);
-       rna_def_modifier_navmesh(brna);
        rna_def_modifier_weightvgedit(brna);
        rna_def_modifier_weightvgmix(brna);
        rna_def_modifier_weightvgproximity(brna);
index 0786a7d801bd26959ae0f6aa8ff4a8575e9796a7..58272fa7c5e9f2e1c0b362a1eeb10ef6e90130fb 100644 (file)
@@ -891,6 +891,7 @@ static int rna_GameObjectSettings_physics_type_get(PointerRNA *ptr)
 static void rna_GameObjectSettings_physics_type_set(PointerRNA *ptr, int value)
 {
        Object *ob= (Object*)ptr->id.data;
+       const int was_navmesh= (ob->gameflag & OB_NAVMESH);
        ob->body_type= value;
 
        switch (ob->body_type) {
@@ -906,6 +907,12 @@ static void rna_GameObjectSettings_physics_type_set(PointerRNA *ptr, int value)
        case OB_BODY_TYPE_NAVMESH:
                ob->gameflag |= OB_NAVMESH;
                ob->gameflag &= ~(OB_SENSOR|OB_COLLISION|OB_DYNAMIC|OB_OCCLUDER);
+
+               if (ob->type == OB_MESH) {
+                       /* could be moved into mesh UI but for now ensure mesh data layer */
+                       BKE_mesh_ensure_navmesh(ob->data);
+               }
+
                break;
        case OB_BODY_TYPE_NO_COLLISION:
                ob->gameflag &= ~(OB_SENSOR|OB_COLLISION|OB_OCCLUDER|OB_DYNAMIC|OB_NAVMESH);
@@ -937,6 +944,14 @@ static void rna_GameObjectSettings_physics_type_set(PointerRNA *ptr, int value)
                        ob->bsoft = bsbNew();
                break;
        }
+
+       if (was_navmesh != (ob->gameflag & OB_NAVMESH)) {
+               if (ob->type == OB_MESH) {
+                       DAG_id_tag_update(ptr->id.data, OB_RECALC_DATA);
+                       WM_main_add_notifier(NC_OBJECT|ND_DRAW, ptr->id.data);
+               }
+       }
+
 }
 
 static PointerRNA rna_Object_active_particle_system_get(PointerRNA *ptr)
index a50b769ee11d983c01c9baeb82786d059cd53635..f31565dd48e981bb8ff43f1ff9df87b7ec756bd4 100644 (file)
@@ -67,7 +67,6 @@ set(SRC
        intern/MOD_mirror.c
        intern/MOD_multires.c
        intern/MOD_ngoninterp.c
-       intern/MOD_navmesh.c
        intern/MOD_none.c
        intern/MOD_particleinstance.c
        intern/MOD_particlesystem.c
diff --git a/source/blender/modifiers/intern/MOD_navmesh.c b/source/blender/modifiers/intern/MOD_navmesh.c
deleted file mode 100644 (file)
index c259239..0000000
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
-* $Id$
-*
-* ***** BEGIN GPL LICENSE BLOCK *****
-*
-* This program is free software; you can redistribute it and/or
-* modify it under the terms of the GNU General Public License
-* as published by the Free Software Foundation; either version 2
-* of the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program; if not, write to the Free Software  Foundation,
-* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*
-* The Original Code is Copyright (C) 2005 by the Blender Foundation.
-* All rights reserved.
-*
-* Contributor(s): 
-*
-* ***** END GPL LICENSE BLOCK *****
-*
-*/
-
-/** \file blender/modifiers/intern/MOD_navmesh.c
- *  \ingroup modifiers
- */
-
-
-#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"
-
-BM_INLINE int bit(int a, int b)
-{
-       return (a & (1 << b)) >> b;
-}
-
-BM_INLINE void intToCol(int i, float* col)
-{
-       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 void initData(ModifierData *UNUSED(md))
-{
-       /* NavMeshModifierData *nmmd = (NavMeshModifierData*) md; */ /* UNUSED */
-}
-
-static void copyData(ModifierData *UNUSED(md), ModifierData *UNUSED(target))
-{
-       /* NavMeshModifierData *nmmd = (NavMeshModifierData*) md; */
-       /* NavMeshModifierData *tnmmd = (NavMeshModifierData*) target; */
-
-       //.todo - deep copy
-}
-
-/*
-static void (*drawFacesSolid_original)(DerivedMesh *dm, float (*partial_redraw_planes)[4],
-                                          int fast, int (*setMaterial)(int, void *attribs)) = NULL;*/
-
-#ifdef WITH_GAMEENGINE
-
-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);
-}
-
-static void navDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, int has_mcol, int matnr))
-{
-       (void) setDrawOptions;
-
-       drawNavMeshColored(dm);
-}
-
-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;
-
-       //drawFacesSolid_original(dm, partial_redraw_planes, fast, setMaterial);
-       drawNavMeshColored(dm);
-}
-#endif /* WITH_GAMEENGINE */
-
-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");
-       }
-       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++)
-               {
-                       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");
-       }
-
-       //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 UNUSED(useRenderParams), int UNUSED(isFinalCalc))
-{
-       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 = createNavMeshForVisualization(nmmd, derivedData);
-       
-       return result;
-}
-
-
-ModifierTypeInfo modifierType_NavMesh = {
-       /* name */              "NavMesh",
-       /* structName */        "NavMeshModifierData",
-       /* structSize */        sizeof(NavMeshModifierData),
-       /* type */              eModifierTypeType_Constructive,
-       /* flags */             (ModifierTypeFlag) (eModifierTypeFlag_AcceptsMesh
-                                                       | eModifierTypeFlag_Single),
-       /* copyData */          copyData,
-       /* deformVerts */       0,
-       /* deformMatrices */    0,
-       /* deformVertsEM */     0,
-       /* deformMatricesEM */  0,
-       /* applyModifier */     applyModifier,
-       /* applyModifierEM */   0,
-       /* initData */          initData,
-       /* requiredDataMask */  0,
-       /* freeData */          0,
-       /* isDisabled */        0,
-       /* updateDepgraph */    0,
-       /* dependsOnTime */     0,
-       /* foreachObjectLink */ 0,
-       /* foreachIDLink */     0,
-};
index 85ad559cb0a1618c7e6ff40c6e5c4e1cfd2c59c4..13abaa7058fcb2cc15070a6b36daecbef6d84583 100644 (file)
@@ -295,7 +295,6 @@ void modifier_type_init(ModifierTypeInfo *types[])
        INIT_TYPE(Solidify);
        INIT_TYPE(Screw);
        INIT_TYPE(Warp);
-       INIT_TYPE(NavMesh);
        INIT_TYPE(WeightVGEdit);
        INIT_TYPE(WeightVGMix);
        INIT_TYPE(WeightVGProximity);
index 3f802642d33381ca853237e03c7ceb3eea438daa..c5a6831a4cb388c2eee4673949d3d92f3b1ae3c1 100644 (file)
@@ -138,8 +138,30 @@ add_test(import_ply_small_holes ${TEST_BLENDER_EXE}
        --write-blend=${TEST_OUT_DIR}/import_ply_small_holes.blend
 )
 
-# PLY Export tests (TODO)
+# PLY Export
+add_test(export_ply_cube_all_data ${TEST_BLENDER_EXE}
+       ${TEST_SRC_DIR}/io_tests/blend_geometry/cube_all_data.blend
+       --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
+       --run={'FINISHED'}&bpy.ops.export_mesh.ply\(filepath='${TEST_OUT_DIR}/export_ply_cube_all_data.ply'\)
+       --md5_source=${TEST_OUT_DIR}/export_ply_cube_all_data.ply
+       --md5=6adc3748ceae8298496f99d0e7e76c15 --md5_method=FILE
+)
 
+add_test(export_ply_suzanne_all_data ${TEST_BLENDER_EXE}
+       ${TEST_SRC_DIR}/io_tests/blend_geometry/suzanne_all_data.blend
+       --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
+       --run={'FINISHED'}&bpy.ops.export_mesh.ply\(filepath='${TEST_OUT_DIR}/export_ply_suzanne_all_data.ply'\)
+       --md5_source=${TEST_OUT_DIR}/export_ply_suzanne_all_data.ply
+       --md5=68ba23f02efd6511bfd093f45f703221 --md5_method=FILE
+)
+
+add_test(export_ply_vertices ${TEST_BLENDER_EXE}  # lame, add a better one
+       ${TEST_SRC_DIR}/io_tests/blend_geometry/vertices.blend
+       --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
+       --run={'FINISHED'}&bpy.ops.export_mesh.ply\(filepath='${TEST_OUT_DIR}/export_ply_vertices.ply'\)
+       --md5_source=${TEST_OUT_DIR}/export_ply_vertices.ply
+       --md5=37faba0aa2014451b27f951afa92f870 --md5_method=FILE
+)
 
 
 # STL Import tests
@@ -164,8 +186,30 @@ add_test(import_stl_knot_max_simplified ${TEST_BLENDER_EXE}
        --write-blend=${TEST_OUT_DIR}/import_stl_knot_max_simplified.blend
 )
 
-# STL Export tests (TODO)
+# STL Export
+add_test(export_stl_cube_all_data ${TEST_BLENDER_EXE}
+       ${TEST_SRC_DIR}/io_tests/blend_geometry/cube_all_data.blend
+       --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
+       --run={'FINISHED'}&bpy.ops.export_mesh.stl\(filepath='${TEST_OUT_DIR}/export_stl_cube_all_data.stl'\)
+       --md5_source=${TEST_OUT_DIR}/export_stl_cube_all_data.stl
+       --md5=64cb97c0cabb015e1c3f76369835075a --md5_method=FILE
+)
 
+add_test(export_stl_suzanne_all_data ${TEST_BLENDER_EXE}
+       ${TEST_SRC_DIR}/io_tests/blend_geometry/suzanne_all_data.blend
+       --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
+       --run={'FINISHED'}&bpy.ops.export_mesh.stl\(filepath='${TEST_OUT_DIR}/export_stl_suzanne_all_data.stl'\)
+       --md5_source=${TEST_OUT_DIR}/export_stl_suzanne_all_data.stl
+       --md5=e9b23c97c139ad64961c635105bb9192 --md5_method=FILE
+)
+
+add_test(export_stl_vertices ${TEST_BLENDER_EXE}  # lame, add a better one
+       ${TEST_SRC_DIR}/io_tests/blend_geometry/vertices.blend
+       --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
+       --run={'FINISHED'}&bpy.ops.export_mesh.stl\(filepath='${TEST_OUT_DIR}/export_stl_vertices.stl'\)
+       --md5_source=${TEST_OUT_DIR}/export_stl_vertices.stl
+       --md5=3fd3c877e573beeebc782532cc005820 --md5_method=FILE
+)
 
 
 # X3D Import
@@ -196,7 +240,7 @@ add_test(export_x3d_cube ${TEST_BLENDER_EXE}
        --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
        --run={'FINISHED'}&bpy.ops.export_scene.x3d\(filepath='${TEST_OUT_DIR}/export_x3d_cube.x3d',use_selection=False\)
        --md5_source=${TEST_OUT_DIR}/export_x3d_cube.x3d
-       --md5=2621d8cc2cc1d34f6711c54519907dac --md5_method=FILE
+       --md5=05312d278fe41da33560fdfb9bdb268f --md5_method=FILE
 )
 
 add_test(export_x3d_nurbs ${TEST_BLENDER_EXE}
@@ -204,7 +248,7 @@ add_test(export_x3d_nurbs ${TEST_BLENDER_EXE}
        --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
        --run={'FINISHED'}&bpy.ops.export_scene.x3d\(filepath='${TEST_OUT_DIR}/export_x3d_nurbs.x3d',use_selection=False\)
        --md5_source=${TEST_OUT_DIR}/export_x3d_nurbs.x3d
-       --md5=d56b3736bab063d101d42079bd276f01 --md5_method=FILE
+       --md5=4286d4a2aa507ef78b22ddcbdcc88481 --md5_method=FILE
 )
 
 add_test(export_x3d_all_objects ${TEST_BLENDER_EXE}
@@ -212,7 +256,7 @@ add_test(export_x3d_all_objects ${TEST_BLENDER_EXE}
        --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
        --run={'FINISHED'}&bpy.ops.export_scene.x3d\(filepath='${TEST_OUT_DIR}/export_x3d_all_objects.x3d',use_selection=False\)
        --md5_source=${TEST_OUT_DIR}/export_x3d_all_objects.x3d
-       --md5=0914c9a7fcdbfc5741c1269497e9068b --md5_method=FILE
+       --md5=f5f9fa4c5619a0eeab66685aafd2f7f0 --md5_method=FILE
 )
 
 
@@ -245,7 +289,7 @@ add_test(export_3ds_cube ${TEST_BLENDER_EXE}
        --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
        --run={'FINISHED'}&bpy.ops.export_scene.autodesk_3ds\(filepath='${TEST_OUT_DIR}/export_3ds_cube.3ds',use_selection=False\)
        --md5_source=${TEST_OUT_DIR}/export_3ds_cube.3ds
-       --md5=0df6cfb130052d01e31ef77d391d4cc0 --md5_method=FILE
+       --md5=a31f5071b6c6dc7445b9099cdc7f63b3 --md5_method=FILE
 )
 
 add_test(export_3ds_nurbs ${TEST_BLENDER_EXE}
@@ -253,7 +297,7 @@ add_test(export_3ds_nurbs ${TEST_BLENDER_EXE}
        --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
        --run={'FINISHED'}&bpy.ops.export_scene.autodesk_3ds\(filepath='${TEST_OUT_DIR}/export_3ds_nurbs.3ds',use_selection=False\)
        --md5_source=${TEST_OUT_DIR}/export_3ds_nurbs.3ds
-       --md5=ba1a6d43346fee3bcadc7e30e3c95935 --md5_method=FILE
+       --md5=5bdd21be3c80d814fbc83cb25edb08c2 --md5_method=FILE
 )
 
 add_test(export_3ds_all_objects ${TEST_BLENDER_EXE}
@@ -261,7 +305,7 @@ add_test(export_3ds_all_objects ${TEST_BLENDER_EXE}
        --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
        --run={'FINISHED'}&bpy.ops.export_scene.autodesk_3ds\(filepath='${TEST_OUT_DIR}/export_3ds_all_objects.3ds',use_selection=False\)
        --md5_source=${TEST_OUT_DIR}/export_3ds_all_objects.3ds
-       --md5=0940ea889498cd437d503670738639ae --md5_method=FILE
+       --md5=68447761ab0ca38e1e22e7c177ed48a8 --md5_method=FILE
 )
 
 
@@ -273,7 +317,7 @@ add_test(export_fbx_cube ${TEST_BLENDER_EXE}
        --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
        --run={'FINISHED'}&bpy.ops.export_scene.fbx\(filepath='${TEST_OUT_DIR}/export_fbx_cube.fbx',use_selection=False,use_metadata=False\)
        --md5_source=${TEST_OUT_DIR}/export_fbx_cube.fbx
-       --md5=86da2495dffd7c270e682f599be6b3d1 --md5_method=FILE
+       --md5=59a35577462f95f9a0b4e6035226ce9b --md5_method=FILE
 )
 
 add_test(export_fbx_nurbs ${TEST_BLENDER_EXE}
@@ -281,7 +325,7 @@ add_test(export_fbx_nurbs ${TEST_BLENDER_EXE}
        --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
        --run={'FINISHED'}&bpy.ops.export_scene.fbx\(filepath='${TEST_OUT_DIR}/export_fbx_nurbs.fbx',use_selection=False,use_metadata=False\)
        --md5_source=${TEST_OUT_DIR}/export_fbx_nurbs.fbx
-       --md5=88a263ddb5181e6522dc214debb92ced --md5_method=FILE
+       --md5=d31875f18f613fa0c3b16e978f87f6f8 --md5_method=FILE
 )
 
 add_test(export_fbx_all_objects ${TEST_BLENDER_EXE}
@@ -289,5 +333,5 @@ add_test(export_fbx_all_objects ${TEST_BLENDER_EXE}
        --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
        --run={'FINISHED'}&bpy.ops.export_scene.fbx\(filepath='${TEST_OUT_DIR}/export_fbx_all_objects.fbx',use_selection=False,use_metadata=False\)
        --md5_source=${TEST_OUT_DIR}/export_fbx_all_objects.fbx
-       --md5=e6f75fe7de9aa366896456e13eafc76a --md5_method=FILE
+       --md5=b35eb2a9d0e73762ecae2278c25a38ac --md5_method=FILE
 )