diff options
author | Campbell Barton <ideasman42@gmail.com> | 2018-05-15 11:25:49 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2018-05-15 11:25:49 +0300 |
commit | f1bc8991461fcda33eb34820bd3aa153f6122c5b (patch) | |
tree | f6e2c533feeff8a9cf0ff36aef8035e95a5e0f0b /source | |
parent | 55b241d32a2c3192a439c51aff99a0a248ca9ef2 (diff) | |
parent | 9636cab0098f96b9c6b6493fb7120f32d7506cd6 (diff) |
Merge branch 'master' into blender2.8
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/editors/animation/anim_channels_edit.c | 5 | ||||
-rw-r--r-- | source/blender/editors/curve/editcurve_add.c | 4 | ||||
-rw-r--r-- | source/blender/editors/include/ED_object.h | 3 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_add.c | 4 | ||||
-rw-r--r-- | source/blender/editors/mesh/mesh_navmesh.c | 732 | ||||
-rw-r--r-- | source/blender/editors/object/object_add.c | 5 | ||||
-rw-r--r-- | source/blender/editors/object/object_edit.c | 27 | ||||
-rw-r--r-- | source/blender/editors/object/object_modes.c | 2 | ||||
-rw-r--r-- | source/blender/editors/space_outliner/outliner_select.c | 12 | ||||
-rw-r--r-- | source/blender/editors/space_outliner/outliner_tools.c | 4 |
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); |