Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2018-05-15 11:25:49 +0300
committerCampbell Barton <ideasman42@gmail.com>2018-05-15 11:25:49 +0300
commitf1bc8991461fcda33eb34820bd3aa153f6122c5b (patch)
treef6e2c533feeff8a9cf0ff36aef8035e95a5e0f0b /source
parent55b241d32a2c3192a439c51aff99a0a248ca9ef2 (diff)
parent9636cab0098f96b9c6b6493fb7120f32d7506cd6 (diff)
Merge branch 'master' into blender2.8
Diffstat (limited to 'source')
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c5
-rw-r--r--source/blender/editors/curve/editcurve_add.c4
-rw-r--r--source/blender/editors/include/ED_object.h3
-rw-r--r--source/blender/editors/mesh/editmesh_add.c4
-rw-r--r--source/blender/editors/mesh/mesh_navmesh.c732
-rw-r--r--source/blender/editors/object/object_add.c5
-rw-r--r--source/blender/editors/object/object_edit.c27
-rw-r--r--source/blender/editors/object/object_modes.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c12
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c4
10 files changed, 757 insertions, 41 deletions
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 36402b82cbf..0163a7f68d6 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -2725,8 +2725,9 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
adt->flag |= ADT_UI_ACTIVE;
/* ensure we exit editmode on whatever object was active before to avoid getting stuck there - T48747 */
- if (ob != CTX_data_edit_object(C))
- ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO);
+ if (ob != CTX_data_edit_object(C)) {
+ ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR);
+ }
notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
}
diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c
index f269799973f..7f788b447f6 100644
--- a/source/blender/editors/curve/editcurve_add.c
+++ b/source/blender/editors/curve/editcurve_add.c
@@ -517,10 +517,6 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
}
}
- /* ED_object_add_type doesnt do an undo, is needed for redo operator on primitive */
- if (newob && enter_editmode)
- ED_undo_push(C, "Enter Editmode");
-
ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
dia = RNA_float_get(op->ptr, "radius");
mul_mat3_m4_fl(mat, dia);
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 0775c2b953b..8e844d327e2 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -122,12 +122,11 @@ void ED_object_parent(struct Object *ob, struct Object *parent, const int type,
enum {
EM_FREEDATA = (1 << 0),
EM_WAITCURSOR = (1 << 1),
- EM_DO_UNDO = (1 << 2),
EM_IGNORE_LAYER = (1 << 3),
EM_NO_CONTEXT = (1 << 4),
};
void ED_object_editmode_exit_ex(
- struct bContext *C, struct Scene *scene, struct Object *obedit, int flag);
+ struct Scene *scene, struct Object *obedit, int flag);
void ED_object_editmode_exit(struct bContext *C, int flag);
void ED_object_editmode_enter_ex(struct Scene *scene, struct Object *ob, int flag);
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index 292b28c772c..66ad057e3ec 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -77,7 +77,7 @@ static Object *make_prim_init(
obedit = ED_object_add_type(C, OB_MESH, idname, loc, rot, false, layer);
/* create editmode */
- ED_object_editmode_enter(C, EM_DO_UNDO | EM_IGNORE_LAYER); /* rare cases the active layer is messed up */
+ ED_object_editmode_enter(C, EM_IGNORE_LAYER); /* rare cases the active layer is messed up */
r_creation_data->was_editmode = true;
}
@@ -100,7 +100,7 @@ static void make_prim_finish(bContext *C, Object *obedit, const MakePrimitiveDat
/* userdef */
if (exit_editmode) {
- ED_object_editmode_exit(C, EM_FREEDATA); /* adding EM_DO_UNDO messes up operator redo */
+ ED_object_editmode_exit(C, EM_FREEDATA);
}
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit);
}
diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c
new file mode 100644
index 00000000000..0d6c7320a95
--- /dev/null
+++ b/source/blender/editors/mesh/mesh_navmesh.c
@@ -0,0 +1,732 @@
+/*
+ * ***** 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) 2011 by Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Benoit Bolsee,
+ * Nick Samarin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/mesh/mesh_navmesh.c
+ * \ingroup edmesh
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math_vector.h"
+#include "BLI_linklist.h"
+
+#include "BKE_library.h"
+#include "BKE_depsgraph.h"
+#include "BKE_context.h"
+#include "BKE_mesh.h"
+#include "BKE_scene.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_report.h"
+#include "BKE_editmesh.h"
+
+#include "ED_object.h"
+#include "ED_mesh.h"
+#include "ED_screen.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "recast-capi.h"
+
+#include "mesh_intern.h" /* own include */
+
+
+static void createVertsTrisData(bContext *C, LinkNode *obs,
+ int *nverts_r, float **verts_r, int *ntris_r, int **tris_r, unsigned int *r_lay)
+{
+ MVert *mvert;
+ int nfaces = 0, *tri, i, curnverts, basenverts, curnfaces;
+ MFace *mface;
+ float co[3], wco[3];
+ Object *ob;
+ LinkNode *oblink, *dmlink;
+ DerivedMesh *dm;
+ Scene *scene = CTX_data_scene(C);
+ LinkNodePair dms_pair = {NULL, NULL};
+
+ int nverts, ntris, *tris;
+ float *verts;
+
+ nverts = 0;
+ ntris = 0;
+
+ /* calculate number of verts and tris */
+ for (oblink = obs; oblink; oblink = oblink->next) {
+ ob = (Object *) oblink->link;
+ dm = mesh_create_derived_no_virtual(scene, ob, NULL, CD_MASK_MESH);
+ DM_ensure_tessface(dm);
+ BLI_linklist_append(&dms_pair, dm);
+
+ nverts += dm->getNumVerts(dm);
+ nfaces = dm->getNumTessFaces(dm);
+ ntris += nfaces;
+
+ /* resolve quad faces */
+ mface = dm->getTessFaceArray(dm);
+ for (i = 0; i < nfaces; i++) {
+ MFace *mf = &mface[i];
+ if (mf->v4)
+ ntris += 1;
+ }
+
+ *r_lay |= ob->lay;
+ }
+ LinkNode *dms = dms_pair.list;
+
+ /* create data */
+ verts = MEM_mallocN(sizeof(float) * 3 * nverts, "createVertsTrisData verts");
+ tris = MEM_mallocN(sizeof(int) * 3 * ntris, "createVertsTrisData faces");
+
+ basenverts = 0;
+ tri = tris;
+ for (oblink = obs, dmlink = dms; oblink && dmlink;
+ oblink = oblink->next, dmlink = dmlink->next)
+ {
+ ob = (Object *) oblink->link;
+ dm = (DerivedMesh *) dmlink->link;
+
+ curnverts = dm->getNumVerts(dm);
+ mvert = dm->getVertArray(dm);
+
+ /* copy verts */
+ for (i = 0; i < curnverts; i++) {
+ MVert *v = &mvert[i];
+
+ copy_v3_v3(co, v->co);
+ mul_v3_m4v3(wco, ob->obmat, co);
+
+ verts[3 * (basenverts + i) + 0] = wco[0];
+ verts[3 * (basenverts + i) + 1] = wco[2];
+ verts[3 * (basenverts + i) + 2] = wco[1];
+ }
+
+ /* create tris */
+ curnfaces = dm->getNumTessFaces(dm);
+ mface = dm->getTessFaceArray(dm);
+
+ for (i = 0; i < curnfaces; i++) {
+ MFace *mf = &mface[i];
+
+ tri[0] = basenverts + mf->v1;
+ tri[1] = basenverts + mf->v3;
+ tri[2] = basenverts + mf->v2;
+ tri += 3;
+
+ if (mf->v4) {
+ tri[0] = basenverts + mf->v1;
+ tri[1] = basenverts + mf->v4;
+ tri[2] = basenverts + mf->v3;
+ tri += 3;
+ }
+ }
+
+ basenverts += curnverts;
+ }
+
+ /* release derived mesh */
+ for (dmlink = dms; dmlink; dmlink = dmlink->next) {
+ dm = (DerivedMesh *) dmlink->link;
+ dm->release(dm);
+ }
+
+ BLI_linklist_free(dms, NULL);
+
+ *nverts_r = nverts;
+ *verts_r = verts;
+ *ntris_r = ntris;
+ *tris_r = tris;
+}
+
+static bool buildNavMesh(const RecastData *recastParams, int nverts, float *verts, int ntris, int *tris,
+ struct recast_polyMesh **pmesh, struct recast_polyMeshDetail **dmesh,
+ ReportList *reports)
+{
+ float bmin[3], bmax[3];
+ struct recast_heightfield *solid;
+ unsigned char *triflags;
+ struct recast_compactHeightfield *chf;
+ struct recast_contourSet *cset;
+ int width, height, walkableHeight, walkableClimb, walkableRadius;
+ int minRegionArea, mergeRegionArea, maxEdgeLen;
+ float detailSampleDist, detailSampleMaxError;
+
+ recast_calcBounds(verts, nverts, bmin, bmax);
+
+ /* ** Step 1. Initialize build config ** */
+ walkableHeight = (int)ceilf(recastParams->agentheight / recastParams->cellheight);
+ walkableClimb = (int)floorf(recastParams->agentmaxclimb / recastParams->cellheight);
+ walkableRadius = (int)ceilf(recastParams->agentradius / recastParams->cellsize);
+ minRegionArea = (int)(recastParams->regionminsize * recastParams->regionminsize);
+ mergeRegionArea = (int)(recastParams->regionmergesize * recastParams->regionmergesize);
+ maxEdgeLen = (int)(recastParams->edgemaxlen / recastParams->cellsize);
+ detailSampleDist = recastParams->detailsampledist < 0.9f ? 0 :
+ recastParams->cellsize * recastParams->detailsampledist;
+ detailSampleMaxError = recastParams->cellheight * recastParams->detailsamplemaxerror;
+
+ /* Set the area where the navigation will be build. */
+ recast_calcGridSize(bmin, bmax, recastParams->cellsize, &width, &height);
+
+ /* zero dimensions cause zero alloc later on [#33758] */
+ if (width <= 0 || height <= 0) {
+ BKE_report(reports, RPT_ERROR, "Object has a width or height of zero");
+ return false;
+ }
+
+ /* ** Step 2: Rasterize input polygon soup ** */
+ /* Allocate voxel heightfield where we rasterize our input data to */
+ solid = recast_newHeightfield();
+
+ if (!recast_createHeightfield(solid, width, height, bmin, bmax, recastParams->cellsize, recastParams->cellheight)) {
+ recast_destroyHeightfield(solid);
+ BKE_report(reports, RPT_ERROR, "Failed to create height field");
+ return false;
+ }
+
+ /* Allocate array that can hold triangle flags */
+ triflags = MEM_callocN(sizeof(unsigned char) * ntris, "buildNavMesh triflags");
+
+ /* Find triangles which are walkable based on their slope and rasterize them */
+ recast_markWalkableTriangles(RAD2DEGF(recastParams->agentmaxslope), verts, nverts, tris, ntris, triflags);
+ recast_rasterizeTriangles(verts, nverts, tris, triflags, ntris, solid, 1);
+ MEM_freeN(triflags);
+
+ /* ** Step 3: Filter walkables surfaces ** */
+ recast_filterLowHangingWalkableObstacles(walkableClimb, solid);
+ recast_filterLedgeSpans(walkableHeight, walkableClimb, solid);
+ recast_filterWalkableLowHeightSpans(walkableHeight, solid);
+
+ /* ** Step 4: Partition walkable surface to simple regions ** */
+
+ chf = recast_newCompactHeightfield();
+ if (!recast_buildCompactHeightfield(walkableHeight, walkableClimb, solid, chf)) {
+ recast_destroyHeightfield(solid);
+ recast_destroyCompactHeightfield(chf);
+
+ BKE_report(reports, RPT_ERROR, "Failed to create compact height field");
+ return false;
+ }
+
+ recast_destroyHeightfield(solid);
+ solid = NULL;
+
+ if (!recast_erodeWalkableArea(walkableRadius, chf)) {
+ recast_destroyCompactHeightfield(chf);
+
+ BKE_report(reports, RPT_ERROR, "Failed to erode walkable area");
+ return false;
+ }
+
+ if (recastParams->partitioning == RC_PARTITION_WATERSHED) {
+ /* Prepare for region partitioning, by calculating distance field along the walkable surface */
+ if (!recast_buildDistanceField(chf)) {
+ recast_destroyCompactHeightfield(chf);
+
+ BKE_report(reports, RPT_ERROR, "Failed to build distance field");
+ return false;
+ }
+
+ /* Partition the walkable surface into simple regions without holes */
+ if (!recast_buildRegions(chf, 0, minRegionArea, mergeRegionArea)) {
+ recast_destroyCompactHeightfield(chf);
+
+ BKE_report(reports, RPT_ERROR, "Failed to build watershed regions");
+ return false;
+ }
+ }
+ else if (recastParams->partitioning == RC_PARTITION_MONOTONE) {
+ /* Partition the walkable surface into simple regions without holes */
+ /* Monotone partitioning does not need distancefield. */
+ if (!recast_buildRegionsMonotone(chf, 0, minRegionArea, mergeRegionArea)) {
+ recast_destroyCompactHeightfield(chf);
+
+ BKE_report(reports, RPT_ERROR, "Failed to build monotone regions");
+ return false;
+ }
+ }
+ else { /* RC_PARTITION_LAYERS */
+ /* Partition the walkable surface into simple regions without holes */
+ if (!recast_buildLayerRegions(chf, 0, minRegionArea)) {
+ recast_destroyCompactHeightfield(chf);
+
+ BKE_report(reports, RPT_ERROR, "Failed to build layer regions");
+ return false;
+ }
+ }
+
+ /* ** Step 5: Trace and simplify region contours ** */
+ /* Create contours */
+ cset = recast_newContourSet();
+
+ if (!recast_buildContours(chf, recastParams->edgemaxerror, maxEdgeLen, cset, RECAST_CONTOUR_TESS_WALL_EDGES)) {
+ recast_destroyCompactHeightfield(chf);
+ recast_destroyContourSet(cset);
+
+ BKE_report(reports, RPT_ERROR, "Failed to build contours");
+ return false;
+ }
+
+ /* ** Step 6: Build polygons mesh from contours ** */
+ *pmesh = recast_newPolyMesh();
+ if (!recast_buildPolyMesh(cset, recastParams->vertsperpoly, *pmesh)) {
+ recast_destroyCompactHeightfield(chf);
+ recast_destroyContourSet(cset);
+ recast_destroyPolyMesh(*pmesh);
+
+ BKE_report(reports, RPT_ERROR, "Failed to build poly mesh");
+ return false;
+ }
+
+
+ /* ** Step 7: Create detail mesh which allows to access approximate height on each polygon ** */
+
+ *dmesh = recast_newPolyMeshDetail();
+ if (!recast_buildPolyMeshDetail(*pmesh, chf, detailSampleDist, detailSampleMaxError, *dmesh)) {
+ recast_destroyCompactHeightfield(chf);
+ recast_destroyContourSet(cset);
+ recast_destroyPolyMesh(*pmesh);
+ recast_destroyPolyMeshDetail(*dmesh);
+
+ BKE_report(reports, RPT_ERROR, "Failed to build poly mesh detail");
+ return false;
+ }
+
+ recast_destroyCompactHeightfield(chf);
+ recast_destroyContourSet(cset);
+
+ return true;
+}
+
+static Object *createRepresentation(bContext *C, struct recast_polyMesh *pmesh, struct recast_polyMeshDetail *dmesh,
+ Base *base, unsigned int lay)
+{
+ float co[3], rot[3];
+ BMEditMesh *em;
+ int i, j, k;
+ unsigned short *v;
+ int face[3];
+ Scene *scene = CTX_data_scene(C);
+ Object *obedit;
+ int createob = base == NULL;
+ int nverts, nmeshes, nvp;
+ unsigned short *verts, *polys;
+ unsigned int *meshes;
+ float bmin[3], cs, ch, *dverts;
+ unsigned char *tris;
+
+ zero_v3(co);
+ zero_v3(rot);
+
+ if (createob) {
+ /* create new object */
+ obedit = ED_object_add_type(C, OB_MESH, "Navmesh", co, rot, false, lay);
+ }
+ else {
+ obedit = base->object;
+ BKE_scene_base_deselect_all(scene);
+ BKE_scene_base_select(scene, base);
+ copy_v3_v3(obedit->loc, co);
+ copy_v3_v3(obedit->rot, rot);
+ }
+
+ ED_object_editmode_enter(C, EM_IGNORE_LAYER);
+ em = BKE_editmesh_from_object(obedit);
+
+ if (!createob) {
+ /* clear */
+ EDBM_mesh_clear(em);
+ }
+
+ /* create verts for polygon mesh */
+ verts = recast_polyMeshGetVerts(pmesh, &nverts);
+ recast_polyMeshGetBoundbox(pmesh, bmin, NULL);
+ recast_polyMeshGetCell(pmesh, &cs, &ch);
+
+ for (i = 0; i < nverts; i++) {
+ v = &verts[3 * i];
+ co[0] = bmin[0] + v[0] * cs;
+ co[1] = bmin[1] + v[1] * ch;
+ co[2] = bmin[2] + v[2] * cs;
+ SWAP(float, co[1], co[2]);
+ BM_vert_create(em->bm, co, NULL, BM_CREATE_NOP);
+ }
+
+ /* create custom data layer to save polygon idx */
+ CustomData_add_layer_named(&em->bm->pdata, CD_RECAST, CD_CALLOC, NULL, 0, "createRepresentation recastData");
+ CustomData_bmesh_init_pool(&em->bm->pdata, 0, BM_FACE);
+
+ /* create verts and faces for detailed mesh */
+ meshes = recast_polyMeshDetailGetMeshes(dmesh, &nmeshes);
+ polys = recast_polyMeshGetPolys(pmesh, NULL, &nvp);
+ dverts = recast_polyMeshDetailGetVerts(dmesh, NULL);
+ tris = recast_polyMeshDetailGetTris(dmesh, NULL);
+
+ for (i = 0; i < nmeshes; i++) {
+ int uniquevbase = em->bm->totvert;
+ unsigned int vbase = meshes[4 * i + 0];
+ unsigned short ndv = meshes[4 * i + 1];
+ unsigned short tribase = meshes[4 * i + 2];
+ unsigned short trinum = meshes[4 * i + 3];
+ const unsigned short *p = &polys[i * nvp * 2];
+ int nv = 0;
+
+ for (j = 0; j < nvp; ++j) {
+ if (p[j] == 0xffff) break;
+ nv++;
+ }
+
+ /* create unique verts */
+ for (j = nv; j < ndv; j++) {
+ copy_v3_v3(co, &dverts[3 * (vbase + j)]);
+ SWAP(float, co[1], co[2]);
+ BM_vert_create(em->bm, co, NULL, BM_CREATE_NOP);
+ }
+
+ /* need to rebuild entirely because array size changes */
+ BM_mesh_elem_table_init(em->bm, BM_VERT);
+
+ /* create faces */
+ for (j = 0; j < trinum; j++) {
+ unsigned char *tri = &tris[4 * (tribase + j)];
+ BMFace *newFace;
+ int *polygonIdx;
+
+ for (k = 0; k < 3; k++) {
+ if (tri[k] < nv)
+ face[k] = p[tri[k]]; /* shared vertex */
+ else
+ face[k] = uniquevbase + tri[k] - nv; /* unique vertex */
+ }
+ newFace = BM_face_create_quad_tri(em->bm,
+ BM_vert_at_index(em->bm, face[0]),
+ BM_vert_at_index(em->bm, face[2]),
+ BM_vert_at_index(em->bm, face[1]), NULL,
+ NULL, BM_CREATE_NOP);
+
+ /* set navigation polygon idx to the custom layer */
+ polygonIdx = (int *)CustomData_bmesh_get(&em->bm->pdata, newFace->head.data, CD_RECAST);
+ *polygonIdx = i + 1; /* add 1 to avoid zero idx */
+ }
+ }
+
+ recast_destroyPolyMesh(pmesh);
+ recast_destroyPolyMeshDetail(dmesh);
+
+ DAG_id_tag_update((ID *)obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+
+
+ ED_object_editmode_exit(C, EM_FREEDATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obedit);
+
+ if (createob) {
+ obedit->gameflag &= ~OB_COLLISION;
+ obedit->gameflag |= OB_NAVMESH;
+ obedit->body_type = OB_BODY_TYPE_NAVMESH;
+ }
+
+ BKE_mesh_ensure_navmesh(obedit->data);
+
+ return obedit;
+}
+
+static int navmesh_create_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ LinkNode *obs = NULL;
+ Base *navmeshBase = NULL;
+
+ CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
+ {
+ if (base->object->type == OB_MESH) {
+ if (base->object->body_type == OB_BODY_TYPE_NAVMESH) {
+ if (!navmeshBase || base == scene->basact) {
+ navmeshBase = base;
+ }
+ }
+ else {
+ BLI_linklist_prepend(&obs, base->object);
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ if (obs) {
+ struct recast_polyMesh *pmesh = NULL;
+ struct recast_polyMeshDetail *dmesh = NULL;
+ bool ok;
+ unsigned int lay = 0;
+
+ int nverts = 0, ntris = 0;
+ int *tris = NULL;
+ float *verts = NULL;
+
+ createVertsTrisData(C, obs, &nverts, &verts, &ntris, &tris, &lay);
+ BLI_linklist_free(obs, NULL);
+ if ((ok = buildNavMesh(&scene->gm.recastData, nverts, verts, ntris, tris, &pmesh, &dmesh, op->reports))) {
+ createRepresentation(C, pmesh, dmesh, navmeshBase, lay);
+ }
+
+ MEM_freeN(verts);
+ MEM_freeN(tris);
+
+ return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "No mesh objects found");
+
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void MESH_OT_navmesh_make(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Create Navigation Mesh";
+ ot->description = "Create navigation mesh for selected objects";
+ ot->idname = "MESH_OT_navmesh_make";
+
+ /* api callbacks */
+ ot->exec = navmesh_create_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int navmesh_face_copy_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ /* do work here */
+ BMFace *efa_act = BM_mesh_active_face_get(em->bm, false, false);
+
+ if (efa_act) {
+ if (CustomData_has_layer(&em->bm->pdata, CD_RECAST)) {
+ BMFace *efa;
+ BMIter iter;
+ int targetPolyIdx = *(int *)CustomData_bmesh_get(&em->bm->pdata, efa_act->head.data, CD_RECAST);
+ targetPolyIdx = targetPolyIdx >= 0 ? targetPolyIdx : -targetPolyIdx;
+
+ if (targetPolyIdx > 0) {
+ /* set target poly idx to other selected faces */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && efa != efa_act) {
+ int *recastDataBlock = (int *)CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_RECAST);
+ *recastDataBlock = targetPolyIdx;
+ }
+ }
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "Active face has no index set");
+ }
+ }
+ }
+
+ DAG_id_tag_update((ID *)obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_navmesh_face_copy(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "NavMesh Copy Face Index";
+ ot->description = "Copy the index from the active face";
+ ot->idname = "MESH_OT_navmesh_face_copy";
+
+ /* api callbacks */
+ ot->poll = ED_operator_editmesh;
+ ot->exec = navmesh_face_copy_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int compare(const void *a, const void *b)
+{
+ return (*(int *)a - *(int *)b);
+}
+
+static int findFreeNavPolyIndex(BMEditMesh *em)
+{
+ /* construct vector of indices */
+ int numfaces = em->bm->totface;
+ int *indices = MEM_callocN(sizeof(int) * numfaces, "findFreeNavPolyIndex(indices)");
+ BMFace *ef;
+ BMIter iter;
+ int i, idx = em->bm->totface - 1, freeIdx = 1;
+
+ /*XXX this originally went last to first, but that isn't possible anymore*/
+ BM_ITER_MESH (ef, &iter, em->bm, BM_FACES_OF_MESH) {
+ int polyIdx = *(int *)CustomData_bmesh_get(&em->bm->pdata, ef->head.data, CD_RECAST);
+ indices[idx] = polyIdx;
+ idx--;
+ }
+
+ qsort(indices, numfaces, sizeof(int), compare);
+
+ /* search first free index */
+ freeIdx = 1;
+ for (i = 0; i < numfaces; i++) {
+ if (indices[i] == freeIdx)
+ freeIdx++;
+ else if (indices[i] > freeIdx)
+ break;
+ }
+
+ MEM_freeN(indices);
+
+ return freeIdx;
+}
+
+static int navmesh_face_add_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *ef;
+ BMIter iter;
+
+ if (CustomData_has_layer(&em->bm->pdata, CD_RECAST)) {
+ int targetPolyIdx = findFreeNavPolyIndex(em);
+
+ if (targetPolyIdx > 0) {
+ /* set target poly idx to selected faces */
+ /*XXX this originally went last to first, but that isn't possible anymore*/
+
+ BM_ITER_MESH (ef, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(ef, BM_ELEM_SELECT)) {
+ int *recastDataBlock = (int *)CustomData_bmesh_get(&em->bm->pdata, ef->head.data, CD_RECAST);
+ *recastDataBlock = targetPolyIdx;
+ }
+ }
+ }
+ }
+
+ DAG_id_tag_update((ID *)obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_navmesh_face_add(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "NavMesh New Face Index";
+ ot->description = "Add a new index and assign it to selected faces";
+ ot->idname = "MESH_OT_navmesh_face_add";
+
+ /* api callbacks */
+ ot->poll = ED_operator_editmesh;
+ ot->exec = navmesh_face_add_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int navmesh_obmode_data_poll(bContext *C)
+{
+ Object *ob = ED_object_active_context(C);
+ if (ob && (ob->mode == OB_MODE_OBJECT) && (ob->type == OB_MESH)) {
+ Mesh *me = ob->data;
+ return CustomData_has_layer(&me->pdata, CD_RECAST);
+ }
+ return false;
+}
+
+static int navmesh_obmode_poll(bContext *C)
+{
+ Object *ob = ED_object_active_context(C);
+ if (ob && (ob->mode == OB_MODE_OBJECT) && (ob->type == OB_MESH)) {
+ return true;
+ }
+ return false;
+}
+
+static int navmesh_reset_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_object_active_context(C);
+ Mesh *me = ob->data;
+
+ CustomData_free_layers(&me->pdata, CD_RECAST, me->totpoly);
+
+ BKE_mesh_ensure_navmesh(me);
+
+ DAG_id_tag_update(&me->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, &me->id);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_navmesh_reset(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "NavMesh Reset Index Values";
+ ot->description = "Assign a new index to every face";
+ ot->idname = "MESH_OT_navmesh_reset";
+
+ /* api callbacks */
+ ot->poll = navmesh_obmode_poll;
+ ot->exec = navmesh_reset_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int navmesh_clear_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_object_active_context(C);
+ Mesh *me = ob->data;
+
+ CustomData_free_layers(&me->pdata, CD_RECAST, me->totpoly);
+
+ DAG_id_tag_update(&me->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, &me->id);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_navmesh_clear(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "NavMesh Clear Data";
+ ot->description = "Remove navmesh data from this mesh";
+ ot->idname = "MESH_OT_navmesh_clear";
+
+ /* api callbacks */
+ ot->poll = navmesh_obmode_data_poll;
+ ot->exec = navmesh_clear_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 366667163b0..b1c3c8bc59b 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -424,8 +424,9 @@ Object *ED_object_add_type(
Object *ob;
/* for as long scene has editmode... */
- if (CTX_data_edit_object(C))
- ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO); /* freedata, and undo */
+ if (CTX_data_edit_object(C)) {
+ ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR);
+ }
/* deselects all, sets scene->basact */
ob = BKE_object_add(bmain, scene, view_layer, type, name);
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 4b13419f425..e87a24b3af0 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -268,14 +268,11 @@ bool ED_object_editmode_load(Object *obedit)
}
/**
- * \param C: Can be NULL, only if #EM_DO_UNDO isn't set.
* \param flag:
- * - Only in exceptional cases should #EM_DO_UNDO NOT be in the flag.
* - If #EM_FREEDATA isn't in the flag, use ED_object_editmode_load directly.
*/
-void ED_object_editmode_exit_ex(bContext *C, Scene *scene, Object *obedit, int flag)
+void ED_object_editmode_exit_ex(Scene *scene, Object *obedit, int flag)
{
- BLI_assert(C || !(flag & EM_DO_UNDO));
const bool freedata = (flag & EM_FREEDATA) != 0;
if (flag & EM_WAITCURSOR) waitcursor(1);
@@ -307,16 +304,8 @@ void ED_object_editmode_exit_ex(bContext *C, Scene *scene, Object *obedit, int f
/* also flush ob recalc, doesn't take much overhead, but used for particles */
DEG_id_tag_update(&obedit->id, OB_RECALC_OB | OB_RECALC_DATA);
-
- if (flag & EM_DO_UNDO)
- ED_undo_push(C, "Editmode");
- if (C != NULL) {
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene);
- }
- else {
- WM_main_add_notifier(NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene);
- }
+ WM_main_add_notifier(NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene);
obedit->mode &= ~OB_MODE_EDIT;
@@ -329,7 +318,7 @@ void ED_object_editmode_exit(bContext *C, int flag)
{
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
- ED_object_editmode_exit_ex(C, scene, obedit, flag);
+ ED_object_editmode_exit_ex(scene, obedit, flag);
}
void ED_object_editmode_enter_ex(Scene *scene, Object *ob, int flag)
@@ -428,7 +417,6 @@ void ED_object_editmode_enter_ex(Scene *scene, Object *ob, int flag)
}
if (flag & EM_WAITCURSOR) waitcursor(0);
- BLI_assert((flag & EM_DO_UNDO) == 0);
}
void ED_object_editmode_enter(bContext *C, int flag)
@@ -446,8 +434,7 @@ void ED_object_editmode_enter(bContext *C, int flag)
if (ob == NULL) return;
if (ID_IS_LINKED(ob)) return;
- ED_object_editmode_enter_ex(scene, ob, flag & ~EM_DO_UNDO);
- if (flag & EM_DO_UNDO) ED_undo_push(C, "Enter Editmode");
+ ED_object_editmode_enter_ex(scene, ob, flag);
}
static int editmode_toggle_exec(bContext *C, wmOperator *op)
@@ -478,12 +465,12 @@ static int editmode_toggle_exec(bContext *C, wmOperator *op)
}
}
else {
- ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR); /* had EM_DO_UNDO but op flag calls undo too [#24685] */
+ ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR);
if ((obact->mode & mode_flag) == 0) {
FOREACH_SELECTED_OBJECT_BEGIN(view_layer, ob)
{
if ((ob != obact) && (ob->type == obact->type)) {
- ED_object_editmode_exit_ex(NULL, scene, ob, EM_FREEDATA | EM_WAITCURSOR);
+ ED_object_editmode_exit_ex(scene, ob, EM_FREEDATA | EM_WAITCURSOR);
}
}
FOREACH_SELECTED_OBJECT_END;
@@ -550,7 +537,7 @@ static int posemode_exec(bContext *C, wmOperator *op)
}
if (obact == CTX_data_edit_object(C)) {
- ED_object_editmode_exit(C, EM_FREEDATA | EM_DO_UNDO);
+ ED_object_editmode_exit(C, EM_FREEDATA);
is_mode_set = false;
}
diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c
index 3fb0e75a01e..7a30c154f23 100644
--- a/source/blender/editors/object/object_modes.c
+++ b/source/blender/editors/object/object_modes.c
@@ -206,7 +206,7 @@ static bool ed_object_mode_generic_exit_ex(
if (only_test) {
return true;
}
- ED_object_editmode_exit_ex(NULL, scene, ob, EM_FREEDATA);
+ ED_object_editmode_exit_ex(scene, ob, EM_FREEDATA);
}
}
else if (ob->mode & OB_MODE_VERTEX_PAINT) {
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index a3dbab1b3fd..b966b0f3dfa 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -197,10 +197,10 @@ static eOLDrawState tree_element_set_active_object(
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
}
-
- if (ob != OBEDIT_FROM_VIEW_LAYER(view_layer))
- ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO);
-
+
+ if (ob != OBEDIT_FROM_VIEW_LAYER(view_layer)) {
+ ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR);
+ }
return OL_DRAWSEL_NORMAL;
}
@@ -585,9 +585,9 @@ static eOLDrawState tree_element_active_pose(
if (set != OL_SETSEL_NONE) {
if (OBEDIT_FROM_VIEW_LAYER(view_layer)) {
- ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO);
+ ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR);
}
-
+
if (ob->mode & OB_MODE_POSE) {
ED_object_posemode_exit(C, ob);
}
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index ab08d6a0025..fff1bafdfff 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -408,7 +408,7 @@ static void object_delete_cb(
// check also library later
if (ob == CTX_data_edit_object(C)) {
- ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO);
+ ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR);
}
ED_object_base_free_and_unlink(CTX_data_main(C), scene, ob);
/* leave for ED_outliner_id_unref to handle */
@@ -977,7 +977,7 @@ static void object_delete_hierarchy_cb(
/* Check also library later. */
for (; obedit && (obedit != base->object); obedit = obedit->parent);
if (obedit == base->object) {
- ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO);
+ ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR);
}
outline_delete_hierarchy(C, reports, scene, base);