diff options
author | Bastien Montagne <montagne29@wanadoo.fr> | 2016-06-27 16:59:01 +0300 |
---|---|---|
committer | Bastien Montagne <montagne29@wanadoo.fr> | 2016-06-27 16:59:01 +0300 |
commit | cbce7fef1604fdfd3099fd196b2a44f61b22eb76 (patch) | |
tree | b11963a42641ef95c61c01a7b2b83dddce4cd1a2 /source/blender | |
parent | c2dc77983dc4d3271858737a15ee058ef48fb833 (diff) | |
parent | e2c7ee773311734450a229051673fbfea61b641a (diff) |
Merge branch 'master' into blender2.8
Conflicts:
source/blender/blenkernel/intern/pointcache.c
source/blender/makesrna/intern/rna_main_api.c
source/blender/makesrna/intern/rna_particle.c
Diffstat (limited to 'source/blender')
92 files changed, 1514 insertions, 1125 deletions
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 8ce85c8e615..d2d9c763031 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -50,6 +50,11 @@ void BKE_blender_userdef_refresh(void); void BKE_blender_callback_test_break_set(void (*func)(void)); int BKE_blender_test_break(void); +/* Blenders' own atexit (avoids leaking) */ +void BKE_blender_atexit_register(void (*func)(void *user_data), void *user_data); +void BKE_blender_atexit_unregister(void (*func)(void *user_data), const void *user_data); +void BKE_blender_atexit(void); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_blender_undo.h b/source/blender/blenkernel/BKE_blender_undo.h index cd18bd8db40..9547eeb9838 100644 --- a/source/blender/blenkernel/BKE_blender_undo.h +++ b/source/blender/blenkernel/BKE_blender_undo.h @@ -45,6 +45,8 @@ extern const char *BKE_undo_get_name(int nr, bool *r_active); extern bool BKE_undo_save_file(const char *filename); extern struct Main *BKE_undo_get_main(struct Scene **r_scene); +extern void BKE_undo_callback_wm_kill_jobs_set(void (*callback)(struct bContext *C)); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h index 3b096773d96..9625f05192a 100644 --- a/source/blender/blenkernel/BKE_displist.h +++ b/source/blender/blenkernel/BKE_displist.h @@ -45,10 +45,14 @@ #define DL_VERTS 7 /* dl->flag */ -#define DL_CYCL_U 1 -#define DL_CYCL_V 2 -#define DL_FRONT_CURVE 4 -#define DL_BACK_CURVE 8 +enum { + /** U/V swapped here compared with #Nurb.flagu, #Nurb.flagv and #CU_NURB_CYCLIC */ + DL_CYCL_U = (1 << 0), + DL_CYCL_V = (1 << 1), + + DL_FRONT_CURVE = (1 << 2), + DL_BACK_CURVE = (1 << 3), +}; /* prototypes */ @@ -70,7 +74,7 @@ typedef struct DispList { int charidx; int totindex; /* indexed array drawing surfaces */ - unsigned int *bevelSplitFlag; + unsigned int *bevel_split; /* BLI_bitmap */ } DispList; void BKE_displist_copy(struct ListBase *lbn, struct ListBase *lb); diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h index afca326c727..3d963ac109c 100644 --- a/source/blender/blenkernel/BKE_movieclip.h +++ b/source/blender/blenkernel/BKE_movieclip.h @@ -40,7 +40,6 @@ struct MovieClipUser; struct MovieDistortion; void BKE_movieclip_free(struct MovieClip *clip); -void BKE_movieclip_unlink(struct Main *bmain, struct MovieClip *clip); struct MovieClip *BKE_movieclip_file_add(struct Main *bmain, const char *name); struct MovieClip *BKE_movieclip_file_add_exists_ex(struct Main *bmain, const char *name, bool *r_exists); diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h index b14593f5a56..858feeeab10 100644 --- a/source/blender/blenkernel/BKE_text.h +++ b/source/blender/blenkernel/BKE_text.h @@ -53,7 +53,6 @@ struct Text *BKE_text_load_ex(struct Main *bmain, const char *file, const cha const bool is_internal); struct Text *BKE_text_load (struct Main *bmain, const char *file, const char *relpath); struct Text *BKE_text_copy (struct Main *bmain, struct Text *ta); -void BKE_text_unlink (struct Main *bmain, struct Text *text); void BKE_text_clear (struct Text *text); void BKE_text_write (struct Text *text, const char *str); int BKE_text_file_modified_check(struct Text *text); diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index df715531cb7..74930dbea4a 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -49,9 +49,6 @@ set(INC ../../../intern/smoke/extern ../../../intern/atomic ../../../intern/libmv - - # XXX - BAD LEVEL CALL WM_api.h - ../windowmanager ) set(INC_SYS diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 15492fbd20d..0805335da66 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -226,3 +226,56 @@ int BKE_blender_test_break(void) return (G.is_break == true); } + +/** \name Blender's AtExit + * + * \note Don't use MEM_mallocN so functions can be registered at any time. + * \{ */ + +struct AtExitData { + struct AtExitData *next; + + void (*func)(void *user_data); + void *user_data; +} *g_atexit = NULL; + +void BKE_blender_atexit_register(void (*func)(void *user_data), void *user_data) +{ + struct AtExitData *ae = malloc(sizeof(*ae)); + ae->next = g_atexit; + ae->func = func; + ae->user_data = user_data; + g_atexit = ae; +} + +void BKE_blender_atexit_unregister(void (*func)(void *user_data), const void *user_data) +{ + struct AtExitData *ae = g_atexit; + struct AtExitData **ae_p = &g_atexit; + + while (ae) { + if ((ae->func == func) && (ae->user_data == user_data)) { + *ae_p = ae->next; + free(ae); + return; + } + ae_p = &ae; + ae = ae->next; + } +} + +void BKE_blender_atexit(void) +{ + struct AtExitData *ae = g_atexit, *ae_next; + while (ae) { + ae_next = ae->next; + + ae->func(ae->user_data); + + free(ae); + ae = ae_next; + } + g_atexit = NULL; +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c index ca0a1b91cea..d64bf7ecf43 100644 --- a/source/blender/blenkernel/intern/blender_undo.c +++ b/source/blender/blenkernel/intern/blender_undo.c @@ -66,9 +66,6 @@ #include "BLO_readfile.h" #include "BLO_writefile.h" -#include "WM_api.h" // XXXXX BAD, very BAD dependency (bad level call) - remove asap, elubie - - /* -------------------------------------------------------------------- */ /** \name Global Undo @@ -87,6 +84,15 @@ typedef struct UndoElem { static ListBase undobase = {NULL, NULL}; static UndoElem *curundo = NULL; +/** + * Avoid bad-level call to #WM_jobs_kill_all_except() + */ +static void (*undo_wm_job_kill_callback)(struct bContext *C) = NULL; + +void BKE_undo_callback_wm_kill_jobs_set(void (*callback)(struct bContext *C)) +{ + undo_wm_job_kill_callback = callback; +} static int read_undosave(bContext *C, UndoElem *uel) { @@ -94,7 +100,7 @@ static int read_undosave(bContext *C, UndoElem *uel) int success = 0, fileflags; /* This is needed so undoing/redoing doesn't crash with threaded previews going */ - WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C)); + undo_wm_job_kill_callback(C); BLI_strncpy(mainstr, G.main->name, sizeof(mainstr)); /* temporal store */ diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index a3e006a162f..44cacffb71f 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -216,21 +216,6 @@ void BKE_brush_free(Brush *brush) BKE_previewimg_free(&(brush->preview)); } -/** - * \note Currently users don't remove brushes from the UI (as is done for scene, text... etc) - * This is only used by RNA, which can remove brushes. - */ -void BKE_brush_unlink(Main *bmain, Brush *brush) -{ - Brush *brush_iter; - - for (brush_iter = bmain->brush.first; brush_iter; brush_iter = brush_iter->id.next) { - if (brush_iter->toggle_brush == brush) { - brush_iter->toggle_brush = NULL; - } - } -} - static void extern_local_brush(Brush *brush) { id_lib_extern((ID *)brush->mtex.tex); diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index 7821946eb6e..e0277c38e61 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -565,7 +565,7 @@ BVHTree *bvhtree_from_mesh_verts( /** * Builds a bvh tree where nodes are the given vertices (note: does not copy given mverts!). * \param vert_allocated if true, vert freeing will be done when freeing data. - * \param mask if not null, true elements give which vert to add to BVH tree. + * \param verts_mask if not null, true elements give which vert to add to BVH tree. * \param verts_num_active if >= 0, number of active verts to add to BVH tree (else will be computed from mask). */ BVHTree *bvhtree_from_mesh_verts_ex( @@ -804,7 +804,7 @@ BVHTree *bvhtree_from_mesh_faces( * Builds a bvh tree where nodes are the given tessellated faces (note: does not copy given mfaces!). * \param vert_allocated if true, vert freeing will be done when freeing data. * \param face_allocated if true, face freeing will be done when freeing data. - * \param mask if not null, true elements give which faces to add to BVH tree. + * \param faces_mask: if not null, true elements give which faces to add to BVH tree. * \param numFaces_active if >= 0, number of active faces to add to BVH tree (else will be computed from mask). */ BVHTree *bvhtree_from_mesh_faces_ex( diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 267f7a65e00..159d5b82a6c 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -61,8 +61,6 @@ #include "GPU_shader.h" #include "GPU_basic_shader.h" -#include "WM_api.h" - #include <string.h> #include <limits.h> #include <math.h> @@ -699,10 +697,10 @@ static void cdDM_drawMappedFaces( } if ((orig != ORIGINDEX_NONE) && !is_hidden) - WM_framebuffer_index_get(orig + 1, &selcol); + GPU_select_index_get(orig + 1, &selcol); } else if (orig != ORIGINDEX_NONE) - WM_framebuffer_index_get(orig + 1, &selcol); + GPU_select_index_get(orig + 1, &selcol); for (j = 0; j < mpoly->totloop; j++) fi_map[start_element++] = selcol; diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 98cbe47c7f9..49db75a0474 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -71,7 +71,7 @@ void BKE_displist_elem_free(DispList *dl) if (dl->verts) MEM_freeN(dl->verts); if (dl->nors) MEM_freeN(dl->nors); if (dl->index) MEM_freeN(dl->index); - if (dl->bevelSplitFlag) MEM_freeN(dl->bevelSplitFlag); + if (dl->bevel_split) MEM_freeN(dl->bevel_split); MEM_freeN(dl); } } @@ -144,8 +144,9 @@ void BKE_displist_copy(ListBase *lbn, ListBase *lb) dln->nors = MEM_dupallocN(dl->nors); dln->index = MEM_dupallocN(dl->index); - if (dl->bevelSplitFlag) - dln->bevelSplitFlag = MEM_dupallocN(dl->bevelSplitFlag); + if (dl->bevel_split) { + dln->bevel_split = MEM_dupallocN(dl->bevel_split); + } dl = dl->next; } @@ -1629,7 +1630,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba if (dlb->type == DL_POLY) { dl->flag |= DL_CYCL_U; } - if ((bl->poly >= 0) && (steps != 2)) { + if ((bl->poly >= 0) && (steps > 2)) { dl->flag |= DL_CYCL_V; } @@ -1642,8 +1643,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba /* CU_2D conflicts with R_NOPUNOFLIP */ dl->rt = nu->flag & ~CU_2D; - dl->bevelSplitFlag = MEM_callocN(sizeof(*dl->bevelSplitFlag) * ((steps + 0x1F) >> 5), - "bevelSplitFlag"); + dl->bevel_split = BLI_BITMAP_NEW(steps, "bevel_split"); /* for each point of poly make a bevel piece */ bevp_first = bl->bevpoints; @@ -1683,7 +1683,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba } if (bevp->split_tag) { - dl->bevelSplitFlag[a >> 5] |= 1 << (a & 0x1F); + BLI_BITMAP_ENABLE(dl->bevel_split, a); } /* rotate bevel piece and write in data */ diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c index ea99fa8f55a..c7a346d49ec 100644 --- a/source/blender/blenkernel/intern/idcode.c +++ b/source/blender/blenkernel/intern/idcode.c @@ -123,7 +123,7 @@ static IDType *idtype_from_code(short idcode) /** * Return if the ID code is a valid ID code. * - * \param code The code to check. + * \param idcode: The code to check. * \return Boolean, 0 when invalid. */ bool BKE_idcode_is_valid(short idcode) @@ -134,7 +134,7 @@ bool BKE_idcode_is_valid(short idcode) /** * Return non-zero when an ID type is linkable. * - * \param code The code to check. + * \param idcode: The code to check. * \return Boolean, 0 when non linkable. */ bool BKE_idcode_is_linkable(short idcode) @@ -147,7 +147,7 @@ bool BKE_idcode_is_linkable(short idcode) /** * Convert an idcode into a name. * - * \param code The code to convert. + * \param idcode: The code to convert. * \return A static string representing the name of * the code. */ @@ -258,7 +258,7 @@ short BKE_idcode_from_idfilter(const int idfilter) /** * Convert an idcode into a name (plural). * - * \param code The code to convert. + * \param idcode: The code to convert. * \return A static string representing the name of * the code. */ @@ -272,7 +272,7 @@ const char *BKE_idcode_to_name_plural(short idcode) /** * Convert an idcode into its translations' context. * - * \param code The code to convert. + * \param idcode: The code to convert. * \return A static string representing the i18n context of the code. */ const char *BKE_idcode_to_translation_context(short idcode) diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 14a445649ad..69384a70969 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -95,8 +95,6 @@ #include "DNA_screen_types.h" #include "DNA_view3d_types.h" -#include "WM_api.h" - static SpinLock image_spin; /* prototypes */ diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index 9335d41f399..3747b09fd99 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -162,15 +162,14 @@ static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self), } if (*id_p && (*id_p == old_id)) { + const bool is_indirect = (id->lib != NULL); + const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0; /* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct, * on the other hand since they get reset to lib data on file open/reload it is indirect too... * Edit Mode is also a 'skip direct' case. */ const bool is_obj = (GS(id->name) == ID_OB); const bool is_proxy = (is_obj && (((Object *)id)->proxy || ((Object *)id)->proxy_group)); const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id)); - /* Note that indirect data from same file as processed ID is **not** considered indirect! */ - const bool is_indirect = ((id->lib != NULL) && (id->lib != old_id->lib)); - const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0; const bool is_never_null = ((cb_flag & IDWALK_NEVER_NULL) && (new_id == NULL) && (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0); const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0; @@ -184,7 +183,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self), (is_obj_editmode && (((Object *)id)->data == *id_p)) || (skip_indirect && (is_proxy || is_indirect))) { - if (is_never_null || is_proxy || is_obj_editmode) { + if (!is_indirect && (is_never_null || is_proxy || is_obj_editmode)) { id_remap_data->skipped_direct++; } else { diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 4e47dfcce74..f82e5cf61b3 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -427,12 +427,6 @@ bool BKE_mesh_has_custom_loop_normals(Mesh *me) } } -/* Note: unlinking is called when me->id.us is 0, question remains how - * much unlinking of Library data in Mesh should be done... probably - * we need a more generic method, like the expand() functions in - * readfile.c */ - - /** Free (or release) any data used by this mesh (does not free the mesh itself). */ void BKE_mesh_free(Mesh *me) { diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index 5f667732b04..f99457a4c26 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -1491,73 +1491,6 @@ void BKE_movieclip_free(MovieClip *clip) BKE_tracking_free(&clip->tracking); } -void BKE_movieclip_unlink(Main *bmain, MovieClip *clip) -{ - bScreen *scr; - ScrArea *area; - SpaceLink *sl; - Scene *sce; - Object *ob; - - for (scr = bmain->screen.first; scr; scr = scr->id.next) { - for (area = scr->areabase.first; area; area = area->next) { - for (sl = area->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_CLIP) { - SpaceClip *sc = (SpaceClip *) sl; - - if (sc->clip == clip) - sc->clip = NULL; - } - else if (sl->spacetype == SPACE_VIEW3D) { - View3D *v3d = (View3D *) sl; - BGpic *bgpic; - - for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) { - if (bgpic->clip == clip) - bgpic->clip = NULL; - } - } - } - } - } - - for (sce = bmain->scene.first; sce; sce = sce->id.next) { - if (sce->clip == clip) - sce->clip = NULL; - } - - for (ob = bmain->object.first; ob; ob = ob->id.next) { - bConstraint *con; - - for (con = ob->constraints.first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_FOLLOWTRACK) { - bFollowTrackConstraint *data = (bFollowTrackConstraint *) con->data; - - if (data->clip == clip) - data->clip = NULL; - } - else if (con->type == CONSTRAINT_TYPE_CAMERASOLVER) { - bCameraSolverConstraint *data = (bCameraSolverConstraint *) con->data; - - if (data->clip == clip) - data->clip = NULL; - } - else if (con->type == CONSTRAINT_TYPE_OBJECTSOLVER) { - bObjectSolverConstraint *data = (bObjectSolverConstraint *) con->data; - - if (data->clip == clip) - data->clip = NULL; - } - } - } - - FOREACH_NODETREE(bmain, ntree, id) { - BKE_node_tree_unlink_id((ID *)clip, ntree); - } FOREACH_NODETREE_END - - clip->id.us = 0; -} - float BKE_movieclip_remap_scene_to_clip_frame(MovieClip *clip, float framenr) { return framenr - (float) clip->start_frame + 1.0f; diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 594f9dffbee..fdc2edba57f 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -498,191 +498,6 @@ Text *BKE_text_copy(Main *bmain, Text *ta) return tan; } -void BKE_text_unlink(Main *bmain, Text *text) -{ - bScreen *scr; - ScrArea *area; - SpaceLink *sl; - Object *ob; - bController *cont; - bActuator *act; - bConstraint *con; - bNodeTree *ntree; - bNode *node; - Material *mat; - Lamp *la; - Tex *te; - World *wo; - FreestyleLineStyle *linestyle; - Scene *sce; - SceneRenderLayer *srl; - FreestyleModuleConfig *module; - bool update; - - for (ob = bmain->object.first; ob; ob = ob->id.next) { - /* game controllers */ - for (cont = ob->controllers.first; cont; cont = cont->next) { - if (cont->type == CONT_PYTHON) { - bPythonCont *pc; - - pc = cont->data; - if (pc->text == text) pc->text = NULL; - } - } - /* game actuators */ - for (act = ob->actuators.first; act; act = act->next) { - if (act->type == ACT_2DFILTER) { - bTwoDFilterActuator *tfa; - - tfa = act->data; - if (tfa->text == text) tfa->text = NULL; - } - } - - /* pyconstraints */ - update = 0; - - if (ob->type == OB_ARMATURE && ob->pose) { - bPoseChannel *pchan; - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - for (con = pchan->constraints.first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_PYTHON) { - bPythonConstraint *data = con->data; - if (data->text == text) data->text = NULL; - update = 1; - - } - } - } - } - - for (con = ob->constraints.first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_PYTHON) { - bPythonConstraint *data = con->data; - if (data->text == text) data->text = NULL; - update = 1; - } - } - - if (update) - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - } - - /* nodes */ - for (la = bmain->lamp.first; la; la = la->id.next) { - ntree = la->nodetree; - if (!ntree) - continue; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == NODE_FRAME) { - if ((Text *)node->id == text) { - node->id = NULL; - } - } - } - } - - for (linestyle = bmain->linestyle.first; linestyle; linestyle = linestyle->id.next) { - ntree = linestyle->nodetree; - if (!ntree) - continue; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == NODE_FRAME) { - if ((Text *)node->id == text) { - node->id = NULL; - } - } - } - } - - for (mat = bmain->mat.first; mat; mat = mat->id.next) { - ntree = mat->nodetree; - if (!ntree) - continue; - for (node = ntree->nodes.first; node; node = node->next) { - if (ELEM(node->type, SH_NODE_SCRIPT, NODE_FRAME)) { - if ((Text *)node->id == text) { - node->id = NULL; - } - } - } - } - - for (te = bmain->tex.first; te; te = te->id.next) { - ntree = te->nodetree; - if (!ntree) - continue; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == NODE_FRAME) { - if ((Text *)node->id == text) { - node->id = NULL; - } - } - } - } - - for (wo = bmain->world.first; wo; wo = wo->id.next) { - ntree = wo->nodetree; - if (!ntree) - continue; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == NODE_FRAME) { - if ((Text *)node->id == text) { - node->id = NULL; - } - } - } - } - - for (sce = bmain->scene.first; sce; sce = sce->id.next) { - ntree = sce->nodetree; - if (!ntree) - continue; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == NODE_FRAME) { - Text *ntext = (Text *)node->id; - if (ntext == text) node->id = NULL; - } - } - - /* Freestyle (while looping over the scene) */ - for (srl = sce->r.layers.first; srl; srl = srl->next) { - for (module = srl->freestyleConfig.modules.first; module; module = module->next) { - if (module->script == text) - module->script = NULL; - } - } - } - - for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) { - for (node = ntree->nodes.first; node; node = node->next) { - if (ELEM(node->type, SH_NODE_SCRIPT, NODE_FRAME)) { - if ((Text *)node->id == text) { - node->id = NULL; - } - } - } - } - - /* text space */ - for (scr = bmain->screen.first; scr; scr = scr->id.next) { - for (area = scr->areabase.first; area; area = area->next) { - for (sl = area->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_TEXT) { - SpaceText *st = (SpaceText *) sl; - - if (st->text == text) { - st->text = NULL; - st->top = 0; - } - } - } - } - } - - text->id.us = 0; -} - void BKE_text_clear(Text *text) /* called directly from rna */ { int oldstate; diff --git a/source/blender/blenlib/BLI_array_utils.h b/source/blender/blenlib/BLI_array_utils.h index 5ef8421c003..a46c87cec40 100644 --- a/source/blender/blenlib/BLI_array_utils.h +++ b/source/blender/blenlib/BLI_array_utils.h @@ -48,6 +48,10 @@ int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_strid #define BLI_array_findindex(arr, arr_len, p) \ _bli_array_findindex(arr, arr_len, sizeof(*(arr)), p) +int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p); +#define BLI_array_rfindindex(arr, arr_len, p) \ + _bli_array_rfindindex(arr, arr_len, sizeof(*(arr)), p) + void _bli_array_binary_and( void *arr, const void *arr_a, const void *arr_b, unsigned int arr_len, size_t arr_stride); diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h index 9120d9f53f7..8124e07dd47 100644 --- a/source/blender/blenlib/BLI_math_matrix.h +++ b/source/blender/blenlib/BLI_math_matrix.h @@ -273,7 +273,7 @@ void BLI_space_transform_invert_normal(const struct SpaceTransform *data, float /*********************************** Other ***********************************/ void print_m3(const char *str, float M[3][3]); -void print_m4(const char *str, float M[3][4]); +void print_m4(const char *str, float M[4][4]); #define print_m3_id(M) print_m3(STRINGIFY(M), M) #define print_m4_id(M) print_m4(STRINGIFY(M), M) diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c index 527d9934797..76de52bda66 100644 --- a/source/blender/blenlib/intern/BLI_filelist.c +++ b/source/blender/blenlib/intern/BLI_filelist.c @@ -352,8 +352,6 @@ void BLI_filelist_entry_datetime_to_string( /** * Deep-duplicate of a single direntry. - * - * \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over. */ void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *src) { @@ -368,8 +366,6 @@ void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *s /** * Deep-duplicate of an array of direntries, including the array itself. - * - * \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over. */ void BLI_filelist_duplicate( struct direntry **dest_filelist, struct direntry * const src_filelist, const unsigned int nrentries) diff --git a/source/blender/blenlib/intern/array_utils.c b/source/blender/blenlib/intern/array_utils.c index 9c91da4abee..32f0111babd 100644 --- a/source/blender/blenlib/intern/array_utils.c +++ b/source/blender/blenlib/intern/array_utils.c @@ -134,8 +134,22 @@ void _bli_array_permute( int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p) { const char *arr_step = (const char *)arr; - unsigned int i; - for (i = 0; i < arr_len; i++, arr_step += arr_stride) { + for (unsigned int i = 0; i < arr_len; i++, arr_step += arr_stride) { + if (memcmp(arr_step, p, arr_stride) == 0) { + return (int)i; + } + } + return -1; +} + +/** + * A version of #BLI_array_findindex that searches from the end of the list. + */ +int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p) +{ + const char *arr_step = (const char *)arr + (arr_stride * arr_len); + for (unsigned int i = arr_len; i-- != 0; ) { + arr_step -= arr_stride; if (memcmp(arr_step, p, arr_stride) == 0) { return (int)i; } diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 370e8bb0035..124f0c7abb8 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -2692,7 +2692,7 @@ bool isect_point_tri_prism_v3(const float p[3], const float v1[3], const float v } /** - * \param r_vi The point \a p projected onto the triangle. + * \param r_isect_co: The point \a p projected onto the triangle. * \return True when \a p is inside the triangle. * \note Its up to the caller to check the distance between \a p and \a r_vi against an error margin. */ diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 2b793841c38..ded10ad7713 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -310,7 +310,7 @@ static int BLI_path_unc_prefix_len(const char *path); /* defined below in same f /** * Remove redundant characters from \a path and optionally make absolute. * - * \param relbase: The path this is relative to, or ignored when NULL. + * \param relabase: The path this is relative to, or ignored when NULL. * \param path: Can be any input, and this function converts it to a regular full path. * Also removes garbage from directory paths, like `/../` or double slashes etc. * diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 3262f740b09..2e01456dbd5 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -1324,6 +1324,7 @@ bool BLO_has_bfile_extension(const char *str) * * \param path the full path to explode. * \param r_dir the string that'll contain path up to blend file itself ('library' path). + * WARNING! Must be FILE_MAX_LIBEXTRA long (it also stores group and name strings)! * \param r_group the string that'll contain 'group' part of the path, if any. May be NULL. * \param r_name the string that'll contain data's name part of the path, if any. May be NULL. * \return true if path contains a blend file. diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 3393be059bd..194ad72100c 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -29,15 +29,22 @@ */ -/* - * FILEFORMAT: IFF-style structure (but not IFF compatible!) +/** + * + * FILE FORMAT + * =========== + * + * IFF-style structure (but not IFF compatible!) * * start file: + * <pre> * BLENDER_V100 12 bytes (versie 1.00) * V = big endian, v = little endian * _ = 4 byte pointer, - = 8 byte pointer + * </pre> * - * datablocks: also see struct BHead + * datablocks: (also see struct #BHead). + * <pre> * <bh.code> 4 chars * <bh.len> int, len data after BHead * <bh.old> void, old pointer @@ -46,29 +53,32 @@ * data * ... * ... + * </pre> * * Almost all data in Blender are structures. Each struct saved * gets a BHead header. With BHead the struct can be linked again * and compared with StructDNA . * + * * WRITE + * ===== * * Preferred writing order: (not really a must, but why would you do it random?) * Any case: direct data is ALWAYS after the lib block * * (Local file data) * - for each LibBlock - * - write LibBlock - * - write associated direct data + * - write LibBlock + * - write associated direct data * (External file data) * - per library - * - write library block - * - per LibBlock - * - write the ID of LibBlock - * - write TEST (128x128, blend file preview, optional) - * - write FileGlobal (some global vars) - * - write SDNA - * - write USER if filename is ~/X.XX/config/startup.blend + * - write library block + * - per LibBlock + * - write the ID of LibBlock + * - write #TEST (#RenderInfo struct. 128x128 blend file preview is optional). + * - write #GLOB (#FileGlobal struct) (some global vars). + * - write #DNA1 (#SDNA struct) + * - write #USER (#UserDef struct) if filename is ``~/X.XX/config/startup.blend``. */ @@ -309,12 +319,6 @@ static WriteData *writedata_new(WriteWrap *ww) { WriteData *wd= MEM_callocN(sizeof(*wd), "writedata"); - /* XXX, see note about this in readfile.c, remove - * once we have an xp lock - zr - */ - - if (wd == NULL) return NULL; - wd->sdna = DNA_sdna_from_data(DNAstr, DNAlen, false); wd->ww = ww; diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c index c142dcae514..5ee0e904a33 100644 --- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c +++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c @@ -97,12 +97,22 @@ static BMLoop *bm_edge_flagged_radial_first(BMEdge *e) return NULL; } +static void normalize_v2_m3_v3v3(float out[2], float axis_mat[3][3], const float v1[3], const float v2[3]) +{ + float dir[3]; + sub_v3_v3v3(dir, v1, v2); + mul_v2_m3v3(out, axis_mat, dir); + normalize_v2(out); +} + + /** * \note Be sure to update #bm_face_split_edgenet_find_loop_pair_exists * when making changed to edge picking logic. */ static bool bm_face_split_edgenet_find_loop_pair( - BMVert *v_init, const float face_normal[3], + BMVert *v_init, + const float face_normal[3], float face_normal_matrix[3][3], BMEdge *e_pair[2]) { /* Always find one boundary edge (to determine winding) @@ -142,10 +152,17 @@ static bool bm_face_split_edgenet_find_loop_pair( } e_pair[0] = BLI_SMALLSTACK_POP(edges_boundary); + /* use to hold boundary OR wire edges */ + BLI_SMALLSTACK_DECLARE(edges_search, BMEdge *); + /* attempt one boundary and one wire, or 2 boundary */ if (edges_wire_len == 0) { - if (edges_boundary_len >= 2) { + if (edges_boundary_len > 1) { e_pair[1] = BLI_SMALLSTACK_POP(edges_boundary); + + if (edges_boundary_len > 2) { + BLI_SMALLSTACK_SWAP(edges_search, edges_wire); + } } else { /* one boundary and no wire */ @@ -154,28 +171,37 @@ static bool bm_face_split_edgenet_find_loop_pair( } else { e_pair[1] = BLI_SMALLSTACK_POP(edges_wire); - if (edges_wire_len > 1) { - BMVert *v_prev = BM_edge_other_vert(e_pair[0], v_init); - BMVert *v_next; - float angle_best; - - v_next = BM_edge_other_vert(e_pair[1], v_init); - angle_best = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal); - - BMEdge *e; - while ((e = BLI_SMALLSTACK_POP(edges_wire))) { - float angle_test; - v_next = BM_edge_other_vert(e, v_init); - angle_test = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal); - if (angle_test < angle_best) { - angle_best = angle_test; - e_pair[1] = e; - } - } + BLI_SMALLSTACK_SWAP(edges_search, edges_wire); } } + /* if we swapped above, search this list for the best edge */ + if (!BLI_SMALLSTACK_IS_EMPTY(edges_search)) { + /* find the best edge in 'edge_list' to use for 'e_pair[1]' */ + const BMVert *v_prev = BM_edge_other_vert(e_pair[0], v_init); + const BMVert *v_next = BM_edge_other_vert(e_pair[1], v_init); + + float dir_prev[2], dir_next[2]; + + normalize_v2_m3_v3v3(dir_prev, face_normal_matrix, v_prev->co, v_init->co); + normalize_v2_m3_v3v3(dir_next, face_normal_matrix, v_next->co, v_init->co); + float angle_best_cos = dot_v2v2(dir_next, dir_prev); + + BMEdge *e; + while ((e = BLI_SMALLSTACK_POP(edges_search))) { + v_next = BM_edge_other_vert(e, v_init); + float dir_test[2]; + + normalize_v2_m3_v3v3(dir_test, face_normal_matrix, v_next->co, v_init->co); + const float angle_test_cos = dot_v2v2(dir_prev, dir_test); + + if (angle_test_cos > angle_best_cos) { + angle_best_cos = angle_test_cos; + e_pair[1] = e; + } + } + } /* flip based on winding */ l_walk = bm_edge_flagged_radial_first(e_pair[0]); @@ -309,36 +335,40 @@ walk_nofork: BMEdge *e_next, *e_first; e_first = v->e; e_next = BM_DISK_EDGE_NEXT(e_first, v); /* always skip this verts edge */ - do { - BLI_assert(v->e != e_next); - if ((BM_ELEM_API_FLAG_TEST(e_next, EDGE_NET)) && - (bm_edge_flagged_radial_count(e_next) < 2)) - { - BMVert *v_next; - v_next = BM_edge_other_vert(e_next, v); + /* in rare cases there may be edges with a single connecting vertex */ + if (e_next != e_first) { + do { + if ((BM_ELEM_API_FLAG_TEST(e_next, EDGE_NET)) && + (bm_edge_flagged_radial_count(e_next) < 2)) + { + BMVert *v_next; + + v_next = BM_edge_other_vert(e_next, v); + BLI_assert(v->e != e_next); #ifdef DEBUG_PRINT - /* indent and print */ - { - BMVert *_v = v; - do { - printf(" "); - } while ((_v = BM_edge_other_vert(_v->e, _v)) != v_init); - printf("vert %d -> %d (add=%d)\n", - BM_elem_index_get(v), BM_elem_index_get(v_next), - BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT) == 0); - } + /* indent and print */ + { + BMVert *_v = v; + do { + printf(" "); + } while ((_v = BM_edge_other_vert(_v->e, _v)) != v_init); + printf("vert %d -> %d (add=%d)\n", + BM_elem_index_get(v), BM_elem_index_get(v_next), + BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT) == 0); + } #endif - if (!BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT)) { - eo = STACK_PUSH_RET_PTR(edge_order); - eo->v = v_next; + if (!BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT)) { + eo = STACK_PUSH_RET_PTR(edge_order); + eo->v = v_next; - v_next->e = e_next; + v_next->e = e_next; + } } - } - } while ((e_next = BM_DISK_EDGE_NEXT(e_next, v)) != e_first); + } while ((e_next = BM_DISK_EDGE_NEXT(e_next, v)) != e_first); + } #ifdef USE_FASTPATH_NOFORK if (STACK_SIZE(edge_order) == 1) { @@ -388,7 +418,7 @@ finally: } static bool bm_face_split_edgenet_find_loop( - BMVert *v_init, const float face_normal[3], + BMVert *v_init, const float face_normal[3], float face_normal_matrix[3][3], /* cache to avoid realloc every time */ struct VertOrder *edge_order, const unsigned int edge_order_len, BMVert **r_face_verts, int *r_face_verts_len) @@ -396,7 +426,7 @@ static bool bm_face_split_edgenet_find_loop( BMEdge *e_pair[2]; BMVert *v; - if (!bm_face_split_edgenet_find_loop_pair(v_init, face_normal, e_pair)) { + if (!bm_face_split_edgenet_find_loop_pair(v_init, face_normal, face_normal_matrix, e_pair)) { return false; } @@ -491,12 +521,18 @@ bool BM_face_split_edgenet( BM_ELEM_API_FLAG_ENABLE(l_iter->e, EDGE_NET); } while ((l_iter = l_iter->next) != l_first); + float face_normal_matrix[3][3]; + axis_dominant_v3_to_m3(face_normal_matrix, f->no); + /* any vert can be used to begin with */ STACK_PUSH(vert_queue, l_first->v); while ((v = STACK_POP(vert_queue))) { - if (bm_face_split_edgenet_find_loop(v, f->no, edge_order, edge_order_len, face_verts, &face_verts_len)) { + if (bm_face_split_edgenet_find_loop( + v, f->no, face_normal_matrix, + edge_order, edge_order_len, face_verts, &face_verts_len)) + { BMFace *f_new; f_new = BM_face_create_verts(bm, face_verts, face_verts_len, f, BM_CREATE_NOP, false); diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c index b4e8bb06afe..52a0df5b9d1 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c +++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c @@ -1292,7 +1292,8 @@ static bool bm_decim_edge_collapse( * \param factor face count multiplier [0 - 1] * \param vweights Optional array of vertex aligned weights [0 - 1], * a vertex group is the usual source for this. - * \param axis: Axis of symmetry, -1 to disable mirror decimate. + * \param symmetry_axis: Axis of symmetry, -1 to disable mirror decimate. + * \param symmetry_eps: Threshold when matching mirror verts. */ void BM_mesh_decimate_collapse( BMesh *bm, diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c index 9d1f7fa45d2..bd6a68faabb 100644 --- a/source/blender/bmesh/tools/bmesh_intersect.c +++ b/source/blender/bmesh/tools/bmesh_intersect.c @@ -87,6 +87,18 @@ // #define USE_DUMP +/* use only for small arrays */ +BLI_INLINE bool array_contains_pointer(const void **arr, unsigned int arr_len, const void *item) +{ + BLI_assert(arr_len < 3); + for (unsigned int i = 0; i < arr_len; i++) { + if (arr[i] == item) { + return true; + } + } + return false; +} + static void tri_v3_scale( float v1[3], float v2[3], float v3[3], const float t) @@ -535,6 +547,7 @@ static void bm_isect_tri_tri( const float *f_b_cos[3] = {UNPACK3_EX(, fv_b, ->co)}; float f_a_nor[3]; float f_b_nor[3]; + /* track vertices which have been added to 'iv_ls_a' & 'iv_ls_b' */ int a_mask = 0; int b_mask = 0; unsigned int i; @@ -556,6 +569,24 @@ static void bm_isect_tri_tri( STACK_INIT(iv_ls_a, ARRAY_SIZE(iv_ls_a)); STACK_INIT(iv_ls_b, ARRAY_SIZE(iv_ls_b)); + /* don't test, but we must be sure not to add doubles (assert instead). */ +#ifndef NDEBUG +# define STACK_PUSH_NOTEST(arr, ele) \ + { \ + BLI_assert(BLI_array_findindex(arr, STACK_SIZE(arr), &(ele)) == -1); \ + STACK_PUSH(arr, ele); \ + } ((void)0) +#else +# define STACK_PUSH_NOTEST STACK_PUSH +#endif + + /* warning, this seems like it might be inefficent, + * however there will be <3 items in this case. */ +# define STACK_PUSH_TEST(arr, ele, arr_offset) \ + if (!array_contains_pointer((const void **)(&(arr)[arr_offset]), STACK_SIZE(arr) - (arr_offset), (void *)ele)) { \ + STACK_PUSH(arr, ele); \ + } ((void)0) + /* vert-vert * --------- */ { @@ -568,7 +599,7 @@ static void bm_isect_tri_tri( for (i_b = 0; i_b < 3; i_b++) { if (len_squared_v3v3(fv_a[i_a]->co, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) { if (!((1 << i_a) & a_mask)) { - STACK_PUSH(iv_ls_a, fv_a[i_a]); + STACK_PUSH_NOTEST(iv_ls_a, fv_a[i_a]); a_mask |= (1 << i_a); #ifdef USE_DUMP printf(" ('VERT-VERT-A') %d, %d),\n", @@ -576,7 +607,7 @@ static void bm_isect_tri_tri( #endif } if (!((1 << i_b) & b_mask)) { - STACK_PUSH(iv_ls_b, fv_b[i_b]); + STACK_PUSH_NOTEST(iv_ls_b, fv_b[i_b]); b_mask |= (1 << i_b); #ifdef USE_DUMP printf(" ('VERT-VERT-B') %d, %d),\n", @@ -606,8 +637,8 @@ static void bm_isect_tri_tri( interp_v3_v3v3(ix, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co, fac); if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) { BMEdge *e; - STACK_PUSH(iv_ls_b, fv_a[i_a]); - // STACK_PUSH(iv_ls_a, fv_a[i_a]); + STACK_PUSH_NOTEST(iv_ls_b, fv_a[i_a]); + // STACK_PUSH_NOTEST(iv_ls_a, fv_a[i_a]); a_mask |= (1 << i_a); e = BM_edge_exists(fv_b[i_b_e0], fv_b[i_b_e1]); #ifdef USE_DUMP @@ -644,8 +675,8 @@ static void bm_isect_tri_tri( interp_v3_v3v3(ix, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co, fac); if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) { BMEdge *e; - STACK_PUSH(iv_ls_a, fv_b[i_b]); - // STACK_PUSH(iv_ls_b, fv_b[i_b]); + STACK_PUSH_NOTEST(iv_ls_a, fv_b[i_b]); + // STACK_PUSH_NOTEST(iv_ls_b, fv_b[i_b]); b_mask |= (1 << i_b); e = BM_edge_exists(fv_a[i_a_e0], fv_a[i_a_e1]); #ifdef USE_DUMP @@ -685,11 +716,8 @@ static void bm_isect_tri_tri( continue; if (isect_point_tri_v3(fv_a[i_a]->co, UNPACK3(t_scale), ix)) { if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) { - BLI_assert(BLI_array_findindex(iv_ls_a, STACK_SIZE(iv_ls_a), fv_a[i_a]) == -1); - BLI_assert(BLI_array_findindex(iv_ls_b, STACK_SIZE(iv_ls_b), fv_a[i_a]) == -1); - - STACK_PUSH(iv_ls_a, fv_a[i_a]); - STACK_PUSH(iv_ls_b, fv_a[i_a]); + STACK_PUSH_NOTEST(iv_ls_a, fv_a[i_a]); + STACK_PUSH_NOTEST(iv_ls_b, fv_a[i_a]); a_mask |= (1 << i_a); #ifdef USE_DUMP printf(" 'VERT TRI-A',\n"); @@ -715,11 +743,8 @@ static void bm_isect_tri_tri( if (isect_point_tri_v3(fv_b[i_b]->co, UNPACK3(t_scale), ix)) { if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) { - BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), fv_b[i_b]) == -1); - BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), fv_b[i_b]) == -1); - - STACK_PUSH(iv_ls_a, fv_b[i_b]); - STACK_PUSH(iv_ls_b, fv_b[i_b]); + STACK_PUSH_NOTEST(iv_ls_a, fv_b[i_b]); + STACK_PUSH_NOTEST(iv_ls_b, fv_b[i_b]); b_mask |= (1 << i_b); #ifdef USE_DUMP printf(" 'VERT TRI-B',\n"); @@ -744,6 +769,17 @@ static void bm_isect_tri_tri( /* edge-tri & edge-edge * -------------------- */ { + /** + * Note that its possible to add the same vertex multiple times + * with near degenerate faces (or a large epsilon). + * + * For this reason we have #STACK_PUSH_TEST macro which only adds vertices that aren't already added. + * Since we know none of the vertices from #bm_isect_edge_tri, the check can be offset. + */ + + const unsigned int iv_ls_a_offset = STACK_SIZE(iv_ls_a); + const unsigned int iv_ls_b_offset = STACK_SIZE(iv_ls_b); + unsigned int i_e0; for (i_e0 = 0; i_e0 < 3; i_e0++) { unsigned int i_e1 = (i_e0 + 1) % 3; @@ -753,10 +789,8 @@ static void bm_isect_tri_tri( continue; iv = bm_isect_edge_tri(s, fv_a[i_e0], fv_a[i_e1], fv_b, b_index, f_b_cos, f_b_nor, &side); if (iv) { - BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), iv) == -1); - BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), iv) == -1); - STACK_PUSH(iv_ls_a, iv); - STACK_PUSH(iv_ls_b, iv); + STACK_PUSH_TEST(iv_ls_a, iv, iv_ls_a_offset); + STACK_PUSH_TEST(iv_ls_b, iv, iv_ls_b_offset); #ifdef USE_DUMP printf(" ('EDGE-TRI-A', %d),\n", side); #endif @@ -771,10 +805,8 @@ static void bm_isect_tri_tri( continue; iv = bm_isect_edge_tri(s, fv_b[i_e0], fv_b[i_e1], fv_a, a_index, f_a_cos, f_a_nor, &side); if (iv) { - BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), iv) == -1); - BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), iv) == -1); - STACK_PUSH(iv_ls_a, iv); - STACK_PUSH(iv_ls_b, iv); + STACK_PUSH_TEST(iv_ls_a, iv, iv_ls_a_offset); + STACK_PUSH_TEST(iv_ls_b, iv, iv_ls_b_offset); #ifdef USE_DUMP printf(" ('EDGE-TRI-B', %d),\n", side); #endif diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index a82cca9e52a..c24ca1e7027 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -158,7 +158,7 @@ static int add_driver_with_target( ReportList *UNUSED(reports), ID *dst_id, const char dst_path[], int dst_index, ID *src_id, const char src_path[], int src_index, - PointerRNA *UNUSED(dst_ptr), PropertyRNA *dst_prop, + PointerRNA *dst_ptr, PropertyRNA *dst_prop, PointerRNA *src_ptr, PropertyRNA *src_prop, short flag, int driver_type) { @@ -207,11 +207,15 @@ static int add_driver_with_target( /* Create a driver variable for the target * - For transform properties, we want to automatically use "transform channel" instead * (The only issue is with quat rotations vs euler channels...) + * - To avoid problems with transform properties depending on the final transform that they + * control (thus creating pseudo-cycles - see T48734), we don't use transform channels + * when both the source and destinaions are in same places. */ dvar = driver_add_new_variable(driver); if (ELEM(src_ptr->type, &RNA_Object, &RNA_PoseBone) && - (STREQ(prop_name, "location") || STREQ(prop_name, "scale") || STRPREFIX(prop_name, "rotation_"))) + (STREQ(prop_name, "location") || STREQ(prop_name, "scale") || STRPREFIX(prop_name, "rotation_")) && + (src_ptr->data != dst_ptr->data)) { /* Transform Channel */ DriverTarget *dtar; diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index 08a7355694b..7b35a154fc8 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -539,10 +539,10 @@ static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt) } /** - * only called from #ok_bezier_region_lasso + * Called from #ok_bezier_region_lasso and #ok_bezier_channel_lasso */ -static bool bezier_region_lasso_test( - const struct KeyframeEdit_LassoData *data_lasso, +bool keyframe_region_lasso_test( + const KeyframeEdit_LassoData *data_lasso, const float xy[2]) { if (BLI_rctf_isect_pt_v(data_lasso->rectf_scaled, xy)) { @@ -564,7 +564,7 @@ static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt) if (ked->data) { short ok = 0; -#define KEY_CHECK_OK(_index) bezier_region_lasso_test(ked->data, bezt->vec[_index]) +#define KEY_CHECK_OK(_index) keyframe_region_lasso_test(ked->data, bezt->vec[_index]) KEYFRAME_OK_CHECKS(KEY_CHECK_OK); #undef KEY_CHECK_OK @@ -575,11 +575,38 @@ static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt) return 0; } +static short ok_bezier_channel_lasso(KeyframeEditData *ked, BezTriple *bezt) +{ + /* check for lasso customdata (KeyframeEdit_LassoData) */ + if (ked->data) { + KeyframeEdit_LassoData *data = ked->data; + float pt[2]; + + /* late-binding remap of the x values (for summary channels) */ + /* XXX: Ideally we reset, but it should be fine just leaving it as-is + * as the next channel will reset it properly, while the next summary-channel + * curve will also reset by itself... + */ + if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) { + data->rectf_scaled->xmin = ked->f1; + data->rectf_scaled->xmax = ked->f2; + } + + /* only use the x-coordinate of the point; the y is the channel range... */ + pt[0] = bezt->vec[1][0]; + pt[1] = ked->channel_y; + + if (keyframe_region_lasso_test(data, pt)) + return KEYFRAME_OK_KEY; + } + return 0; +} + /** - * only called from #ok_bezier_region_circle + * Called from #ok_bezier_region_circle and #ok_bezier_channel_circle */ -static bool bezier_region_circle_test( - const struct KeyframeEdit_CircleData *data_circle, +bool keyframe_region_circle_test( + const KeyframeEdit_CircleData *data_circle, const float xy[2]) { if (BLI_rctf_isect_pt_v(data_circle->rectf_scaled, xy)) { @@ -602,7 +629,7 @@ static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt) if (ked->data) { short ok = 0; -#define KEY_CHECK_OK(_index) bezier_region_circle_test(ked->data, bezt->vec[_index]) +#define KEY_CHECK_OK(_index) keyframe_region_circle_test(ked->data, bezt->vec[_index]) KEYFRAME_OK_CHECKS(KEY_CHECK_OK); #undef KEY_CHECK_OK @@ -613,6 +640,33 @@ static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt) return 0; } +static short ok_bezier_channel_circle(KeyframeEditData *ked, BezTriple *bezt) +{ + /* check for circle select customdata (KeyframeEdit_CircleData) */ + if (ked->data) { + KeyframeEdit_CircleData *data = ked->data; + float pt[2]; + + /* late-binding remap of the x values (for summary channels) */ + /* XXX: Ideally we reset, but it should be fine just leaving it as-is + * as the next channel will reset it properly, while the next summary-channel + * curve will also reset by itself... + */ + if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) { + data->rectf_scaled->xmin = ked->f1; + data->rectf_scaled->xmax = ked->f2; + } + + /* only use the x-coordinate of the point; the y is the channel range... */ + pt[0] = bezt->vec[1][0]; + pt[1] = ked->channel_y; + + if (keyframe_region_circle_test(data, pt)) + return KEYFRAME_OK_KEY; + } + return 0; +} + KeyframeEditFunc ANIM_editkeyframes_ok(short mode) { @@ -634,6 +688,10 @@ KeyframeEditFunc ANIM_editkeyframes_ok(short mode) return ok_bezier_region_lasso; case BEZT_OK_REGION_CIRCLE: /* only if the point falls within KeyframeEdit_CircleData defined data */ return ok_bezier_region_circle; + case BEZT_OK_CHANNEL_LASSO: /* same as BEZT_OK_REGION_LASSO, but we're only using the x-value of the points */ + return ok_bezier_channel_lasso; + case BEZT_OK_CHANNEL_CIRCLE: /* same as BEZT_OK_REGION_CIRCLE, but we're only using the x-value of the points */ + return ok_bezier_channel_circle; default: /* nothing was ok */ return NULL; } diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 66b3a63c669..0c0f54f0179 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -1069,6 +1069,9 @@ short insert_keyframe(ReportList *reports, ID *id, bAction *act, const char grou if (ELEM(RNA_property_subtype(prop), PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) { fcu->color_mode = FCURVE_COLOR_AUTO_RGB; } + else if (RNA_property_subtype(prop), PROP_QUATERNION) { + fcu->color_mode = FCURVE_COLOR_AUTO_YRGB; + } } /* insert keyframe */ diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c index a49b3362155..738496a67c6 100644 --- a/source/blender/editors/gpencil/editaction_gpencil.c +++ b/source/blender/editors/gpencil/editaction_gpencil.c @@ -205,6 +205,36 @@ void ED_gplayer_frames_select_border(bGPDlayer *gpl, float min, float max, short } } +/* select the frames in this layer that occur within the lasso/circle region specified */ +void ED_gplayer_frames_select_region(KeyframeEditData *ked, bGPDlayer *gpl, short tool, short select_mode) +{ + bGPDframe *gpf; + + if (gpl == NULL) + return; + + /* only select frames which are within the region */ + for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + /* construct a dummy point coordinate to do this testing with */ + float pt[2] = {0}; + + pt[0] = gpf->framenum; + pt[1] = ked->channel_y; + + /* check the necessary regions */ + if (tool == BEZT_OK_CHANNEL_LASSO) { + /* Lasso */ + if (keyframe_region_lasso_test(ked->data, pt)) + gpframe_select(gpf, select_mode); + } + else if (tool == BEZT_OK_CHANNEL_CIRCLE) { + /* Circle */ + if (keyframe_region_circle_test(ked->data, pt)) + gpframe_select(gpf, select_mode); + } + } +} + /* ***************************************** */ /* Frame Editing Tools */ diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index bd1697b9a54..ac49a51c716 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -652,7 +652,7 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot) /* identifiers */ ot->name = "Delete Active Frame"; ot->idname = "GPENCIL_OT_active_frame_delete"; - ot->description = "Delete the active frame for the active Grease Pencil datablock"; + ot->description = "Delete the active frame for the active Grease Pencil Layer"; ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -661,6 +661,64 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot) ot->poll = gp_actframe_delete_poll; } +/* **************** Delete All Active Frames ****************** */ + +static int gp_actframe_delete_all_poll(bContext *C) +{ + bGPdata *gpd = ED_gpencil_data_get_active(C); + + /* 1) There must be grease pencil data + * 2) Hopefully some of the layers have stuff we can use + */ + return (gpd && gpd->layers.first); +} + +static int gp_actframe_delete_all_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + bool success = false; + + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) + { + /* try to get the "active" frame - but only if it actually occurs on this frame */ + bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0); + + if (gpf == NULL) + continue; + + /* delete it... */ + gpencil_layer_delframe(gpl, gpf); + + /* we successfully modified something */ + success = true; + } + CTX_DATA_END; + + /* updates */ + if (success) { + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + return OPERATOR_FINISHED; + } + else { + BKE_report(op->reports, RPT_ERROR, "No active frame(s) to delete"); + return OPERATOR_CANCELLED; + } +} + +void GPENCIL_OT_active_frames_delete_all(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Delete All Active Frames"; + ot->idname = "GPENCIL_OT_active_frames_delete_all"; + ot->description = "Delete the active frame(s) of all editable Grease Pencil layers"; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* callbacks */ + ot->exec = gp_actframe_delete_all_exec; + ot->poll = gp_actframe_delete_all_poll; +} + /* ******************* Delete Operator ************************ */ typedef enum eGP_DeleteMode { diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index dd28f6ac531..53fb33eeb9b 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -218,6 +218,7 @@ void GPENCIL_OT_unlock_all(struct wmOperatorType *ot); void GPENCIL_OT_layer_isolate(struct wmOperatorType *ot); void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot); +void GPENCIL_OT_active_frames_delete_all(struct wmOperatorType *ot); void GPENCIL_OT_convert(struct wmOperatorType *ot); diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 405b673c42b..65ee1122b56 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -105,7 +105,7 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf) /* Delete Active Frame - For easier video tutorials/review sessions */ /* NOTE: This works even when not in EditMode */ - WM_keymap_add_item(keymap, "GPENCIL_OT_active_frame_delete", XKEY, KM_PRESS, 0, DKEY); + WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, 0, DKEY); } /* ==================== */ @@ -238,7 +238,7 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", XKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", DELKEY, KM_PRESS, KM_CTRL, 0); - WM_keymap_add_item(keymap, "GPENCIL_OT_active_frame_delete", XKEY, KM_PRESS, KM_SHIFT, 0); + WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, KM_SHIFT, 0); /* copy + paste */ WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0); @@ -364,6 +364,7 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_layer_isolate); WM_operatortype_append(GPENCIL_OT_active_frame_delete); + WM_operatortype_append(GPENCIL_OT_active_frames_delete_all); WM_operatortype_append(GPENCIL_OT_convert); diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index fba2f30e715..a570d586f50 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -97,7 +97,8 @@ typedef enum eGP_StrokeAdd_Result { typedef enum eGPencil_PaintFlags { GP_PAINTFLAG_FIRSTRUN = (1 << 0), /* operator just started */ GP_PAINTFLAG_STROKEADDED = (1 << 1), - GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2) + GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2), + GP_PAINTFLAG_SELECTMASK = (1 << 3), } eGPencil_PaintFlags; @@ -813,18 +814,21 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, BLI_freelinkN(&gpf->strokes, gps); } else if (gps->totpoints == 1) { - gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]); - - /* do boundbox check first */ - if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { - /* only check if point is inside */ - if (len_v2v2_int(mval, pc1) <= radius) { - /* free stroke */ - // XXX: pressure sensitive eraser should apply here too? - MEM_freeN(gps->points); - if (gps->triangles) - MEM_freeN(gps->triangles); - BLI_freelinkN(&gpf->strokes, gps); + /* only process if it hasn't been masked out... */ + if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) { + gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]); + + /* do boundbox check first */ + if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { + /* only check if point is inside */ + if (len_v2v2_int(mval, pc1) <= radius) { + /* free stroke */ + // XXX: pressure sensitive eraser should apply here too? + MEM_freeN(gps->points); + if (gps->triangles) + MEM_freeN(gps->triangles); + BLI_freelinkN(&gpf->strokes, gps); + } } } } @@ -862,6 +866,11 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, pt1 = gps->points + i; pt2 = gps->points + i + 1; + /* only process if it hasn't been masked out... */ + if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT)) + continue; + + /* get coordinates of point in screenspace */ gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]); gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]); @@ -1199,6 +1208,7 @@ static void gp_session_cleanup(tGPsdata *p) static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode) { Scene *scene = p->scene; + ToolSettings *ts = scene->toolsettings; /* get active layer (or add a new one if non-existent) */ p->gpl = gpencil_layer_getactive(p->gpd); @@ -1242,6 +1252,15 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode) /* Ensure this gets set... */ p->gpf = p->gpl->actframe; + /* Restrict eraser to only affecting selected strokes, if the "selection mask" is on + * (though this is only available in editmode) + */ + if (p->gpd->flag & GP_DATA_STROKE_EDITMODE) { + if (ts->gp_sculpt.flag & GP_BRUSHEDIT_FLAG_SELECT_MASK) { + p->flags |= GP_PAINTFLAG_SELECTMASK; + } + } + if (p->gpf == NULL) { p->status = GP_STATUS_ERROR; //if (G.debug & G_DEBUG) @@ -1251,7 +1270,6 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode) } else { /* Drawing Modes - Add a new frame if needed on the active layer */ - ToolSettings *ts = p->scene->toolsettings; short add_frame_mode; if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h index 80f930a0c30..92acfa6c1d2 100644 --- a/source/blender/editors/include/ED_fileselect.h +++ b/source/blender/editors/include/ED_fileselect.h @@ -109,7 +109,7 @@ int ED_file_extension_icon(const char *path); void ED_file_read_bookmarks(void); -void ED_file_change_dir(struct bContext *C, const bool checkdir); +void ED_file_change_dir(struct bContext *C); /* File menu stuff */ diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index 255827db373..de5ab80a88f 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -42,6 +42,7 @@ struct bGPDlayer; struct bGPDframe; struct bGPDstroke; struct bAnimContext; +struct KeyframeEditData; struct PointerRNA; struct wmWindowManager; struct wmKeyConfig; @@ -120,6 +121,7 @@ void ED_gplayer_make_cfra_list(struct bGPDlayer *gpl, ListBase *elems, bool only bool ED_gplayer_frame_select_check(struct bGPDlayer *gpl); void ED_gplayer_frame_select_set(struct bGPDlayer *gpl, short mode); void ED_gplayer_frames_select_border(struct bGPDlayer *gpl, float min, float max, short select_mode); +void ED_gplayer_frames_select_region(struct KeyframeEditData *ked, struct bGPDlayer *gpl, short tool, short select_mode); void ED_gpencil_select_frames(struct bGPDlayer *gpl, short select_mode); void ED_gpencil_select_frame(struct bGPDlayer *gpl, int selx, short select_mode); diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h index fae3e3677a0..c0eb88cd982 100644 --- a/source/blender/editors/include/ED_keyframes_edit.h +++ b/source/blender/editors/include/ED_keyframes_edit.h @@ -45,14 +45,21 @@ struct Scene; /* bezt validation */ typedef enum eEditKeyframes_Validate { + /* Frame range */ BEZT_OK_FRAME = 1, BEZT_OK_FRAMERANGE, + /* Selection status */ BEZT_OK_SELECTED, + /* Values (y-val) only */ BEZT_OK_VALUE, BEZT_OK_VALUERANGE, + /* For graph editor keyframes (2D tests) */ BEZT_OK_REGION, BEZT_OK_REGION_LASSO, BEZT_OK_REGION_CIRCLE, + /* Only for keyframes a certain Dopesheet channel */ + BEZT_OK_CHANNEL_LASSO, + BEZT_OK_CHANNEL_CIRCLE, } eEditKeyframes_Validate; /* ------------ */ @@ -97,20 +104,20 @@ typedef enum eEditKeyframes_Mirror { } eEditKeyframes_Mirror; /* use with BEZT_OK_REGION_LASSO */ -struct KeyframeEdit_LassoData { - const rctf *rectf_scaled; +typedef struct KeyframeEdit_LassoData { + rctf *rectf_scaled; const rctf *rectf_view; const int (*mcords)[2]; int mcords_tot; -}; +} KeyframeEdit_LassoData; /* use with BEZT_OK_REGION_CIRCLE */ -struct KeyframeEdit_CircleData { - const rctf *rectf_scaled; +typedef struct KeyframeEdit_CircleData { + rctf *rectf_scaled; const rctf *rectf_view; float mval[2]; float radius_squared; -}; +} KeyframeEdit_CircleData; /* ************************************************ */ @@ -157,7 +164,8 @@ typedef struct KeyframeEditData { /* current iteration data */ struct FCurve *fcu; /* F-Curve that is being iterated over */ int curIndex; /* index of current keyframe being iterated over */ - + float channel_y; /* y-position of midpoint of the channel (for the dopesheet) */ + /* flags */ eKeyframeVertOk curflags; /* current flags for the keyframe we're reached in the iteration process */ eKeyframeIterFlags iterflags; /* settings for iteration process */ @@ -258,6 +266,18 @@ short bezt_to_cfraelem(KeyframeEditData *ked, struct BezTriple *bezt); */ void bezt_remap_times(KeyframeEditData *ked, struct BezTriple *bezt); +/* ------ 1.5-D Region Testing Uitls (Lasso/Circle Select) ------- */ +/* XXX: These are temporary, until we can unify GP/Mask Keyframe handling and standard FCurve Keyframe handling */ + +bool keyframe_region_lasso_test( + const KeyframeEdit_LassoData *data_lasso, + const float xy[2]); + +bool keyframe_region_circle_test( + const KeyframeEdit_CircleData *data_circle, + const float xy[2]); + + /* ************************************************ */ /* Destructive Editing API (keyframes_general.c) */ diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h index 1f13b46ff2a..2ab788d5e2a 100644 --- a/source/blender/editors/include/ED_mask.h +++ b/source/blender/editors/include/ED_mask.h @@ -35,6 +35,7 @@ struct bContext; struct wmKeyConfig; struct MaskLayer; struct MaskLayerShape; +struct KeyframeEditData; /* mask_edit.c */ void ED_mask_get_size(struct ScrArea *sa, int *width, int *height); @@ -80,6 +81,7 @@ void ED_masklayer_make_cfra_list(struct MaskLayer *masklay, ListBase *elems, boo bool ED_masklayer_frame_select_check(struct MaskLayer *masklay); void ED_masklayer_frame_select_set(struct MaskLayer *masklay, short mode); void ED_masklayer_frames_select_border(struct MaskLayer *masklay, float min, float max, short select_mode); +void ED_masklayer_frames_select_region(struct KeyframeEditData *ked, struct MaskLayer *masklay, short tool, short select_mode); void ED_mask_select_frames(struct MaskLayer *masklay, short select_mode); void ED_mask_select_frame(struct MaskLayer *masklay, int selx, short select_mode); diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 9aad340d2fb..a623f5cfb9c 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -1020,12 +1020,18 @@ bool UI_context_copy_to_selected_list( /* Helpers for Operators */ uiBut *UI_context_active_but_get(const struct bContext *C); -void UI_context_active_but_prop_get(const struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index); +void UI_context_active_but_prop_get( + const struct bContext *C, + struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index); void UI_context_active_but_prop_handle(struct bContext *C); struct wmOperator *UI_context_active_operator_get(const struct bContext *C); void UI_context_update_anim_flag(const struct bContext *C); -void UI_context_active_but_prop_get_filebrowser(const struct bContext *C, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, bool *r_is_undo); -void UI_context_active_but_prop_get_templateID(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop); +void UI_context_active_but_prop_get_filebrowser( + const struct bContext *C, + struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, bool *r_is_undo); +void UI_context_active_but_prop_get_templateID( + struct bContext *C, + struct PointerRNA *r_ptr, struct PropertyRNA **r_prop); /* Styled text draw */ void UI_fontstyle_set(const struct uiFontStyle *fs); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index fac1267cc62..77990066027 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -4323,7 +4323,7 @@ uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxle /** - * \param sfunc, bfunc: both get it as \a arg. + * \param search_func, bfunc: both get it as \a arg. * \param arg: user value, * \param active: when set, button opens with this item visible and selected. */ diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 133487e1846..f941993a9e1 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -8013,20 +8013,21 @@ uiBut *UI_context_active_but_get(const struct bContext *C) } /* helper function for insert keyframe, reset to default, etc operators */ -void UI_context_active_but_prop_get(const bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index) +void UI_context_active_but_prop_get( + const bContext *C, + struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index) { uiBut *activebut = ui_context_rna_button_active(C); - memset(ptr, 0, sizeof(*ptr)); - if (activebut && activebut->rnapoin.data) { - *ptr = activebut->rnapoin; - *prop = activebut->rnaprop; - *index = activebut->rnaindex; + *r_ptr = activebut->rnapoin; + *r_prop = activebut->rnaprop; + *r_index = activebut->rnaindex; } else { - *prop = NULL; - *index = 0; + memset(r_ptr, 0, sizeof(*r_ptr)); + *r_prop = NULL; + *r_index = 0; } } @@ -9812,10 +9813,17 @@ static int ui_handle_menus_recursive( retval = ui_pie_handler(C, event, menu); } else if (event->type == LEFTMOUSE || event->val != KM_DBL_CLICK) { + bool handled = false; + if (listbox) { - retval = ui_handle_list_event(C, event, menu->region, listbox); + int retval_test = ui_handle_list_event(C, event, menu->region, listbox); + if (retval_test != WM_UI_HANDLER_CONTINUE) { + retval = retval_test; + handled = true; + } } - if (retval == WM_UI_HANDLER_CONTINUE) { + + if (handled == false) { retval = ui_handle_menu_event( C, event, menu, level, is_parent_inside, is_parent_menu, is_floating); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index f1f9c4ef0cb..cf3a50d632a 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -231,15 +231,17 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem) /* This is for browsing and editing the ID-blocks used */ /* for new/open operators */ -void UI_context_active_but_prop_get_templateID(bContext *C, PointerRNA *ptr, PropertyRNA **prop) +void UI_context_active_but_prop_get_templateID( + bContext *C, + PointerRNA *r_ptr, PropertyRNA **r_prop) { TemplateID *template; ARegion *ar = CTX_wm_region(C); uiBlock *block; uiBut *but; - memset(ptr, 0, sizeof(*ptr)); - *prop = NULL; + memset(r_ptr, 0, sizeof(*r_ptr)); + *r_prop = NULL; if (!ar) return; @@ -250,8 +252,8 @@ void UI_context_active_but_prop_get_templateID(bContext *C, PointerRNA *ptr, Pro if ((but->flag & (UI_BUT_LAST_ACTIVE | UI_ACTIVE))) { if (but->func_argN) { template = but->func_argN; - *ptr = template->ptr; - *prop = template->prop; + *r_ptr = template->ptr; + *r_prop = template->prop; return; } } diff --git a/source/blender/editors/mask/mask_editaction.c b/source/blender/editors/mask/mask_editaction.c index bcf9ee5c88d..16147bdc7f8 100644 --- a/source/blender/editors/mask/mask_editaction.c +++ b/source/blender/editors/mask/mask_editaction.c @@ -201,6 +201,36 @@ void ED_masklayer_frames_select_border(MaskLayer *masklay, float min, float max, } } +/* select the frames in this layer that occur within the lasso/circle region specified */ +void ED_masklayer_frames_select_region(KeyframeEditData *ked, MaskLayer *masklay, short tool, short select_mode) +{ + MaskLayerShape *masklay_shape; + + if (masklay == NULL) + return; + + /* only select frames which are within the region */ + for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) { + /* construct a dummy point coordinate to do this testing with */ + float pt[2] = {0}; + + pt[0] = masklay_shape->frame; + pt[1] = ked->channel_y; + + /* check the necessary regions */ + if (tool == BEZT_OK_CHANNEL_LASSO) { + /* Lasso */ + if (keyframe_region_lasso_test(ked->data, pt)) + masklayshape_select(masklay_shape, select_mode); + } + else if (tool == BEZT_OK_CHANNEL_CIRCLE) { + /* Circle */ + if (keyframe_region_circle_test(ked->data, pt)) + masklayshape_select(masklay_shape, select_mode); + } + } +} + /* ***************************************** */ /* Frame Editing Tools */ diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index 01be8f848aa..c4e87614732 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -53,6 +53,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "GPU_draw.h" #include "GPU_buffers.h" /* own include */ @@ -433,7 +434,7 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool exten if (ENDIAN_ORDER == B_ENDIAN) { IMB_convert_rgba_to_abgr(ibuf); } - WM_framebuffer_to_index_array(ibuf->rect, size[0] * size[1]); + GPU_select_to_index_array(ibuf->rect, size[0] * size[1]); a = size[0] * size[1]; while (a--) { diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index efd1ebbd51b..9c2806f6f5a 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -1560,12 +1560,12 @@ void OBJECT_OT_constraints_copy(wmOperatorType *ot) /************************ add constraint operators *********************/ /* get the Object and/or PoseChannel to use as target */ -static short get_new_constraint_target(bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, short add) +static bool get_new_constraint_target(bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, bool add) { Object *obact = ED_object_active_context(C); bPoseChannel *pchanact = BKE_pose_channel_active(obact); - short only_curve = 0, only_mesh = 0, only_ob = 0; - short found = 0; + bool only_curve = false, only_mesh = false, only_ob = false; + bool found = false; /* clear tar_ob and tar_pchan fields before use * - assume for now that both always exist... @@ -1585,7 +1585,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o case CONSTRAINT_TYPE_ROTLIMIT: case CONSTRAINT_TYPE_SIZELIMIT: case CONSTRAINT_TYPE_SAMEVOL: - return 0; + return false; /* restricted target-type constraints -------------- */ /* NOTE: for these, we cannot try to add a target object if no valid ones are found, since that doesn't work */ @@ -1593,26 +1593,26 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o case CONSTRAINT_TYPE_CLAMPTO: case CONSTRAINT_TYPE_FOLLOWPATH: case CONSTRAINT_TYPE_SPLINEIK: - only_curve = 1; - only_ob = 1; - add = 0; + only_curve = true; + only_ob = true; + add = false; break; /* mesh only? */ case CONSTRAINT_TYPE_SHRINKWRAP: - only_mesh = 1; - only_ob = 1; - add = 0; + only_mesh = true; + only_ob = true; + add = false; break; /* object only - add here is ok? */ case CONSTRAINT_TYPE_RIGIDBODYJOINT: - only_ob = 1; + only_ob = true; break; } /* if the active Object is Armature, and we can search for bones, do so... */ - if ((obact->type == OB_ARMATURE) && (only_ob == 0)) { + if ((obact->type == OB_ARMATURE) && (only_ob == false)) { /* search in list of selected Pose-Channels for target */ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones) { @@ -1620,7 +1620,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o if (pchan != pchanact) { *tar_ob = obact; *tar_pchan = pchan; - found = 1; + found = true; break; } @@ -1629,36 +1629,50 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o } /* if not yet found, try selected Objects... */ - if (found == 0) { + if (found == false) { /* search in selected objects context */ CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { /* just use the first object we encounter (that isn't the active object) * and which fulfills the criteria for the object-target that we've got */ - if ((ob != obact) && - ((!only_curve) || (ob->type == OB_CURVE)) && - ((!only_mesh) || (ob->type == OB_MESH))) - { - /* set target */ - *tar_ob = ob; - found = 1; - - /* perform some special operations on the target */ - if (only_curve) { - /* Curve-Path option must be enabled for follow-path constraints to be able to work */ - Curve *cu = (Curve *)ob->data; - cu->flag |= CU_PATH; + if (ob != obact) { + /* for armatures in pose mode, look inside the armature for the active bone + * so that we set up cross-armature constraints with less effort + */ + if ((ob->type == OB_ARMATURE) && (ob->mode & OB_MODE_POSE) && + (!only_curve && !only_mesh)) + { + /* just use the active bone, and assume that it is visible + usable */ + *tar_ob = ob; + *tar_pchan = BKE_pose_channel_active(ob); + found = true; + + break; + } + else if (((!only_curve) || (ob->type == OB_CURVE)) && + ((!only_mesh) || (ob->type == OB_MESH))) + { + /* set target */ + *tar_ob = ob; + found = true; + + /* perform some special operations on the target */ + if (only_curve) { + /* Curve-Path option must be enabled for follow-path constraints to be able to work */ + Curve *cu = (Curve *)ob->data; + cu->flag |= CU_PATH; + } + + break; } - - break; } } CTX_DATA_END; } /* if still not found, add a new empty to act as a target (if allowed) */ - if ((found == 0) && (add)) { + if ((found == false) && (add)) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Base *base = BASACT, *newbase = NULL; @@ -1692,7 +1706,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o /* make our new target the new object */ *tar_ob = obt; - found = 1; + found = true; } /* return whether there's any target */ diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 31b7b584a3a..7a55418b082 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -436,7 +436,7 @@ typedef enum eObClearParentTypes { EnumPropertyItem prop_clear_parent_types[] = { {CLEAR_PARENT_ALL, "CLEAR", 0, "Clear Parent", - "Completely clear the parenting relationship, including involved modifiers is any"}, + "Completely clear the parenting relationship, including involved modifiers if any"}, {CLEAR_PARENT_KEEP_TRANSFORM, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation", "As 'Clear Parent', but keep the current visual transformations of the object"}, {CLEAR_PARENT_INVERSE, "CLEAR_INVERSE", 0, "Clear Parent Inverse", diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h index 50e10e7e154..408eb38d386 100644 --- a/source/blender/editors/space_action/action_intern.h +++ b/source/blender/editors/space_action/action_intern.h @@ -59,6 +59,8 @@ void draw_channel_strips(struct bAnimContext *ac, struct SpaceAction *saction, s void ACTION_OT_select_all_toggle(struct wmOperatorType *ot); void ACTION_OT_select_border(struct wmOperatorType *ot); +void ACTION_OT_select_lasso(struct wmOperatorType *ot); +void ACTION_OT_select_circle(struct wmOperatorType *ot); void ACTION_OT_select_column(struct wmOperatorType *ot); void ACTION_OT_select_linked(struct wmOperatorType *ot); void ACTION_OT_select_more(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c index f69f9944f8a..a261202b690 100644 --- a/source/blender/editors/space_action/action_ops.c +++ b/source/blender/editors/space_action/action_ops.c @@ -59,6 +59,8 @@ void action_operatortypes(void) WM_operatortype_append(ACTION_OT_clickselect); WM_operatortype_append(ACTION_OT_select_all_toggle); WM_operatortype_append(ACTION_OT_select_border); + WM_operatortype_append(ACTION_OT_select_lasso); + WM_operatortype_append(ACTION_OT_select_circle); WM_operatortype_append(ACTION_OT_select_column); WM_operatortype_append(ACTION_OT_select_linked); WM_operatortype_append(ACTION_OT_select_more); @@ -178,6 +180,14 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap) kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0); RNA_boolean_set(kmi->ptr, "axis_range", true); + /* region select */ + kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0); + RNA_boolean_set(kmi->ptr, "deselect", false); + kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "deselect", true); + + WM_keymap_add_item(keymap, "ACTION_OT_select_circle", CKEY, KM_PRESS, 0, 0); + /* column select */ RNA_enum_set(WM_keymap_add_item(keymap, "ACTION_OT_select_column", KKEY, KM_PRESS, 0, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_KEYS); RNA_enum_set(WM_keymap_add_item(keymap, "ACTION_OT_select_column", KKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_CFRA); diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index f2813b2a8d3..0b6d3cb1f60 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -36,6 +36,7 @@ #include "BLI_blenlib.h" #include "BLI_dlrbTree.h" +#include "BLI_lasso.h" #include "BLI_utildefines.h" #include "DNA_anim_types.h" @@ -375,6 +376,264 @@ void ACTION_OT_select_border(wmOperatorType *ot) ot->prop = RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", ""); } +/* ******************** Region Select Operators ***************************** */ +/* "Region Select" operators include the Lasso and Circle Select operators. + * These two ended up being lumped together, as it was easier in the + * original Graph Editor implmentation of these to do it this way. + */ + +static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view, short mode, short selectmode, void *data) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + KeyframeEditData ked; + KeyframeEditFunc ok_cb, select_cb; + View2D *v2d = &ac->ar->v2d; + rctf rectf, scaled_rectf; + float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF); + + /* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */ + UI_view2d_region_to_view_rctf(v2d, rectf_view, &rectf); + + /* filter data */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* get beztriple editing/validation funcs */ + select_cb = ANIM_editkeyframes_select(selectmode); + ok_cb = ANIM_editkeyframes_ok(mode); + + /* init editing data */ + memset(&ked, 0, sizeof(KeyframeEditData)); + if (mode == BEZT_OK_CHANNEL_LASSO) { + KeyframeEdit_LassoData *data_lasso = data; + data_lasso->rectf_scaled = &scaled_rectf; + ked.data = data_lasso; + } + else if (mode == BEZT_OK_CHANNEL_CIRCLE) { + KeyframeEdit_CircleData *data_circle = data; + data_circle->rectf_scaled = &scaled_rectf; + ked.data = data; + } + else { + ked.data = &scaled_rectf; + } + + /* loop over data, doing region select */ + for (ale = anim_data.first; ale; ale = ale->next) { + AnimData *adt = ANIM_nla_mapping_get(ac, ale); + + /* get new vertical minimum extent of channel */ + ymin = ymax - ACHANNEL_STEP; + + /* compute midpoint of channel (used for testing if the key is in the region or not) */ + ked.channel_y = ymin + ACHANNEL_HEIGHT_HALF; + + /* if channel is mapped in NLA, apply correction + * - Apply to the bounds being checked, not all the keyframe points, + * to avoid having scaling everything + * - Save result to the scaled_rect, which is all that these operators + * will read from + */ + if (adt) { + ked.iterflags &= ~(KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); + ked.f1 = BKE_nla_tweakedit_remap(adt, rectf.xmin, NLATIME_CONVERT_UNMAP); + ked.f2 = BKE_nla_tweakedit_remap(adt, rectf.xmax, NLATIME_CONVERT_UNMAP); + } + else { + ked.iterflags |= (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); /* for summary tracks */ + ked.f1 = rectf.xmin; + ked.f2 = rectf.xmax; + } + + /* Update values for scaled_rectf - which is used to compute the mapping in the callbacks + * NOTE: Since summary tracks need late-binding remapping, the callbacks may overwrite these + * with the properly remapped ked.f1/f2 values, when needed + */ + scaled_rectf.xmin = ked.f1; + scaled_rectf.xmax = ked.f2; + scaled_rectf.ymin = ymin; + scaled_rectf.ymax = ymax; + + /* perform vertical suitability check (if applicable) */ + if ((mode == ACTKEYS_BORDERSEL_FRAMERANGE) || + !((ymax < rectf.ymin) || (ymin > rectf.ymax))) + { + /* loop over data selecting */ + switch (ale->type) { + case ANIMTYPE_GPDATABLOCK: + { + bGPdata *gpd = ale->data; + bGPDlayer *gpl; + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode); + } + break; + } + case ANIMTYPE_GPLAYER: + { + ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode); + break; + } + case ANIMTYPE_MASKDATABLOCK: + { + Mask *mask = ale->data; + MaskLayer *masklay; + for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { + ED_masklayer_frames_select_region(&ked, masklay, mode, selectmode); + } + break; + } + case ANIMTYPE_MASKLAYER: + { + ED_masklayer_frames_select_region(&ked, ale->data, mode, selectmode); + break; + } + default: + ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL); + break; + } + } + + /* set minimum extent to be the maximum of the next channel */ + ymax = ymin; + } + + /* cleanup */ + ANIM_animdata_freelist(&anim_data); +} + +/* ----------------------------------- */ + +static int actkeys_lassoselect_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + + KeyframeEdit_LassoData data_lasso; + rcti rect; + rctf rect_fl; + + short selectmode; + bool extend; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + data_lasso.rectf_view = &rect_fl; + data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot); + if (data_lasso.mcords == NULL) + return OPERATOR_CANCELLED; + + /* clear all selection if not extending selection */ + extend = RNA_boolean_get(op->ptr, "extend"); + if (!extend) + deselect_action_keys(&ac, 1, SELECT_SUBTRACT); + + if (!RNA_boolean_get(op->ptr, "deselect")) + selectmode = SELECT_ADD; + else + selectmode = SELECT_SUBTRACT; + + /* get settings from operator */ + BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot); + BLI_rctf_rcti_copy(&rect_fl, &rect); + + /* apply borderselect action */ + region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_LASSO, selectmode, &data_lasso); + + MEM_freeN((void *)data_lasso.mcords); + + /* send notifier that keyframe selection has changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + + return OPERATOR_FINISHED; +} + +void ACTION_OT_select_lasso(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Lasso Select"; + ot->description = "Select keyframe points using lasso selection"; + ot->idname = "ACTION_OT_select_lasso"; + + /* api callbacks */ + ot->invoke = WM_gesture_lasso_invoke; + ot->modal = WM_gesture_lasso_modal; + ot->exec = actkeys_lassoselect_exec; + ot->poll = ED_operator_action_active; + ot->cancel = WM_gesture_lasso_cancel; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* properties */ + RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", ""); + RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items"); + RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first"); +} + +/* ------------------- */ + +static int action_circle_select_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode"); + const short selectmode = (gesture_mode == GESTURE_MODAL_SELECT) ? SELECT_ADD : SELECT_SUBTRACT; + + KeyframeEdit_CircleData data = {0}; + rctf rect_fl; + + float x = RNA_int_get(op->ptr, "x"); + float y = RNA_int_get(op->ptr, "y"); + float radius = RNA_int_get(op->ptr, "radius"); + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + data.mval[0] = x; + data.mval[1] = y; + data.radius_squared = radius * radius; + data.rectf_view = &rect_fl; + + rect_fl.xmin = x - radius; + rect_fl.xmax = x + radius; + rect_fl.ymin = y - radius; + rect_fl.ymax = y + radius; + + /* apply region select action */ + region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_CIRCLE, selectmode, &data); + + /* send notifier that keyframe selection has changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + + return OPERATOR_FINISHED; +} + +void ACTION_OT_select_circle(wmOperatorType *ot) +{ + ot->name = "Circle Select"; + ot->description = "Select keyframe points using circle selection"; + ot->idname = "ACTION_OT_select_circle"; + + ot->invoke = WM_gesture_circle_invoke; + ot->modal = WM_gesture_circle_modal; + ot->exec = action_circle_select_exec; + ot->poll = ED_operator_action_active; + ot->cancel = WM_gesture_circle_cancel; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX); + RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX); + RNA_def_int(ot->srna, "radius", 1, 1, INT_MAX, "Radius", "", 1, INT_MAX); + RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX); +} + /* ******************** Column Select Operator **************************** */ /* This operator works in one of four ways: * - 1) select all keyframes in the same frame as a selected one (KKEY) diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index 71e38f72a7a..a55b18a2212 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -128,6 +128,7 @@ void file_panels_register(struct ARegionType *art); /* file_utils.c */ void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, rcti *r_bounds); +bool file_is_dir(struct SpaceFile *sfile, const char *path); #endif /* __FILE_INTERN_H__ */ diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index d83a7d5ea62..c42ff120102 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -208,7 +208,7 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen) BLI_add_slash(params->dir); } - ED_file_change_dir(C, false); + ED_file_change_dir(C); retval = FILE_SELECT_DIR; } } @@ -826,7 +826,7 @@ static int bookmark_select_exec(bContext *C, wmOperator *op) RNA_property_string_get(op->ptr, prop, entry); BLI_strncpy(params->dir, entry, sizeof(params->dir)); BLI_cleanup_dir(G.main->name, params->dir); - ED_file_change_dir(C, true); + ED_file_change_dir(C); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); } @@ -1379,7 +1379,7 @@ int file_exec(bContext *C, wmOperator *exec_op) BLI_add_slash(sfile->params->dir); } - ED_file_change_dir(C, false); + ED_file_change_dir(C); } /* opening file - sends events now, so things get handled on windowqueue level */ else if (sfile->op) { @@ -1447,19 +1447,7 @@ int file_parent_exec(bContext *C, wmOperator *UNUSED(unused)) if (sfile->params) { if (BLI_parent_dir(sfile->params->dir)) { BLI_cleanup_dir(G.main->name, sfile->params->dir); - /* if not browsing in .blend file, we still want to check whether the path is a directory */ - if (sfile->params->type == FILE_LOADLIB) { - char tdir[FILE_MAX]; - if (BLO_library_path_explode(sfile->params->dir, tdir, NULL, NULL)) { - ED_file_change_dir(C, false); - } - else { - ED_file_change_dir(C, true); - } - } - else { - ED_file_change_dir(C, true); - } + ED_file_change_dir(C); if (sfile->params->recursion_level > 1) { /* Disable 'dirtree' recursion when going up in tree. */ sfile->params->recursion_level = 0; @@ -1529,7 +1517,7 @@ int file_previous_exec(bContext *C, wmOperator *UNUSED(unused)) folderlist_popdir(sfile->folders_prev, sfile->params->dir); folderlist_pushdir(sfile->folders_next, sfile->params->dir); - ED_file_change_dir(C, true); + ED_file_change_dir(C); } WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); @@ -1561,7 +1549,7 @@ int file_next_exec(bContext *C, wmOperator *UNUSED(unused)) // update folders_prev so we can check for it in folderlist_clear_next() folderlist_pushdir(sfile->folders_prev, sfile->params->dir); - ED_file_change_dir(C, true); + ED_file_change_dir(C); } WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); @@ -1809,7 +1797,7 @@ int file_directory_new_exec(bContext *C, wmOperator *op) if (RNA_boolean_get(op->ptr, "open")) { BLI_strncpy(sfile->params->dir, path, sizeof(sfile->params->dir)); - ED_file_change_dir(C, true); + ED_file_change_dir(C); } WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); @@ -1906,17 +1894,35 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN file_expand_directory(C); /* special case, user may have pasted a filepath into the directory */ - if (BLI_is_file(sfile->params->dir)) { - char path[sizeof(sfile->params->dir)]; - BLI_strncpy(path, sfile->params->dir, sizeof(path)); - BLI_split_dirfile(path, sfile->params->dir, sfile->params->file, sizeof(sfile->params->dir), sizeof(sfile->params->file)); + if (!file_is_dir(sfile, sfile->params->dir)) { + char tdir[FILE_MAX_LIBEXTRA]; + char *group, *name; + + if (BLI_is_file(sfile->params->dir)) { + char path[sizeof(sfile->params->dir)]; + BLI_strncpy(path, sfile->params->dir, sizeof(path)); + BLI_split_dirfile(path, sfile->params->dir, sfile->params->file, + sizeof(sfile->params->dir), sizeof(sfile->params->file)); + } + else if (BLO_library_path_explode(sfile->params->dir, tdir, &group, &name)) { + if (group) { + BLI_path_append(tdir, sizeof(tdir), group); + } + BLI_strncpy(sfile->params->dir, tdir, sizeof(sfile->params->dir)); + if (name) { + BLI_strncpy(sfile->params->file, name, sizeof(sfile->params->file)); + } + else { + sfile->params->file[0] = '\0'; + } + } } BLI_cleanup_dir(G.main->name, sfile->params->dir); - if (BLI_exists(sfile->params->dir)) { + if (file_is_dir(sfile, sfile->params->dir)) { /* if directory exists, enter it immediately */ - ED_file_change_dir(C, true); + ED_file_change_dir(C); /* don't do for now because it selects entire text instead of * placing cursor at the end */ @@ -1931,20 +1937,26 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN #endif else { const char *lastdir = folderlist_peeklastdir(sfile->folders_prev); + char tdir[FILE_MAX_LIBEXTRA]; - /* if not, ask to create it and enter if confirmed */ - wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false); - PointerRNA ptr; - WM_operator_properties_create_ptr(&ptr, ot); - RNA_string_set(&ptr, "directory", sfile->params->dir); - RNA_boolean_set(&ptr, "open", true); - - if (lastdir) + /* If we are 'inside' a blend library, we cannot do anything... */ + if (lastdir && BLO_library_path_explode(lastdir, tdir, NULL, NULL)) { BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir)); - - - WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); - WM_operator_properties_free(&ptr); + } + else { + /* if not, ask to create it and enter if confirmed */ + wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false); + PointerRNA ptr; + WM_operator_properties_create_ptr(&ptr, ot); + RNA_string_set(&ptr, "directory", sfile->params->dir); + RNA_boolean_set(&ptr, "open", true); + + if (lastdir) + BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir)); + + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); + WM_operator_properties_free(&ptr); + } } WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); @@ -1971,8 +1983,6 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg BLI_filename_make_safe(sfile->params->file); if (matches) { - /* int i, numfiles = filelist_numfiles(sfile->files); */ /* XXX UNUSED */ - sfile->params->file[0] = '\0'; /* replace the pattern (or filename that the user typed in, with the first selected file of the match */ BLI_strncpy(sfile->params->file, matched_file, sizeof(sfile->params->file)); @@ -1980,30 +1990,17 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg } if (matches == 1) { - BLI_join_dirfile(filepath, sizeof(sfile->params->dir), sfile->params->dir, sfile->params->file); /* if directory, open it and empty filename field */ - if (BLI_is_dir(filepath)) { + if (file_is_dir(sfile, filepath)) { BLI_cleanup_dir(G.main->name, filepath); BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir)); sfile->params->file[0] = '\0'; - ED_file_change_dir(C, true); + ED_file_change_dir(C); UI_textbutton_activate_but(C, but); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); } - else if (sfile->params->type == FILE_LOADLIB) { - char tdir[FILE_MAX]; - BLI_add_slash(filepath); - if (BLO_library_path_explode(filepath, tdir, NULL, NULL)) { - BLI_cleanup_dir(G.main->name, filepath); - BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir)); - sfile->params->file[0] = '\0'; - ED_file_change_dir(C, false); - UI_textbutton_activate_but(C, but); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); - } - } } else if (matches > 1) { file_draw_check(C); diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c index 3c007f25da3..f19e301064d 100644 --- a/source/blender/editors/space_file/file_utils.c +++ b/source/blender/editors/space_file/file_utils.c @@ -25,6 +25,9 @@ */ #include "BLI_rect.h" +#include "BLI_fileops.h" + +#include "BLO_readfile.h" #include "BKE_context.h" @@ -45,3 +48,17 @@ void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, r BLI_rcti_init(r_bounds, xmin, xmin + layout->tile_w + layout->tile_border_x, ymax - layout->tile_h - layout->tile_border_y, ymax); } + +/* Cannot directly use BLI_is_dir in libloading context... */ +bool file_is_dir(struct SpaceFile *sfile, const char *path) +{ + if (sfile->params->type == FILE_LOADLIB) { + char tdir[FILE_MAX_LIBEXTRA]; + char *name; + if (BLO_library_path_explode(sfile->params->dir, tdir, NULL, &name) && BLI_is_file(tdir)) { + /* .blend file itself and group are considered as directories, not final datablock names. */ + return name ? false : true; + } + } + return BLI_is_dir(path); +} diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index fc3341bfb92..5e9eb1f9207 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -624,7 +624,7 @@ static bool is_filtered_file(FileListInternEntry *file, const char *UNUSED(root) static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter) { bool is_filtered; - char path[FILE_MAX_LIBEXTRA], dir[FILE_MAXDIR], *group, *name; + char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name; BLI_join_dirfile(path, sizeof(path), root, file->relpath); @@ -697,7 +697,7 @@ void filelist_filter(FileList *filelist) if (filelist->max_recursion) { /* Never show lib ID 'categories' directories when we are in 'flat' mode, unless * root path is a blend file. */ - char dir[FILE_MAXDIR]; + char dir[FILE_MAX_LIBEXTRA]; if (!filelist_islibrary(filelist, dir, NULL)) { filelist->filter_data.flags |= FLF_HIDE_LIB_DIR; } @@ -947,7 +947,7 @@ static void filelist_checkdir_dir(struct FileList *UNUSED(filelist), char *r_dir static void filelist_checkdir_lib(struct FileList *UNUSED(filelist), char *r_dir) { - char dir[FILE_MAXDIR]; + char dir[FILE_MAX_LIBEXTRA]; if (!BLO_library_path_explode(r_dir, dir, NULL, NULL)) { /* if not a valid library, we need it to be a valid directory! */ BLI_make_exist(r_dir); @@ -2113,6 +2113,7 @@ unsigned int filelist_entry_select_index_get(FileList *filelist, const int index return 0; } +/* WARNING! dir must be FILE_MAX_LIBEXTRA long! */ bool filelist_islibrary(struct FileList *filelist, char *dir, char **group) { return BLO_library_path_explode(filelist->filelist.root, dir, group, NULL); @@ -2208,7 +2209,7 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const FileListInternEntry *entry; LinkNode *ln, *names; int i, nnames, idcode = 0, nbr_entries = 0; - char dir[FILE_MAX], *group; + char dir[FILE_MAX_LIBEXTRA], *group; bool ok; struct BlendHandle *libfiledata = NULL; diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 2a3f964f477..2d28108f544 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -576,7 +576,7 @@ FileLayout *ED_fileselect_get_layout(struct SpaceFile *sfile, ARegion *ar) return sfile->layout; } -void ED_file_change_dir(bContext *C, const bool checkdir) +void ED_file_change_dir(bContext *C) { wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); @@ -590,7 +590,7 @@ void ED_file_change_dir(bContext *C, const bool checkdir) sfile->params->filter_search[0] = '\0'; sfile->params->active_file = -1; - if (checkdir && !BLI_is_dir(sfile->params->dir)) { + if (!file_is_dir(sfile, sfile->params->dir)) { BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), sizeof(sfile->params->dir)); /* could return but just refresh the current dir */ } diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index 6b860990c10..478dbd3d9c0 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -555,19 +555,20 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap) kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0); RNA_boolean_set(kmi->ptr, "axis_range", true); RNA_boolean_set(kmi->ptr, "include_handles", false); - + kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_CTRL, 0); RNA_boolean_set(kmi->ptr, "axis_range", false); RNA_boolean_set(kmi->ptr, "include_handles", true); kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); RNA_boolean_set(kmi->ptr, "axis_range", true); RNA_boolean_set(kmi->ptr, "include_handles", true); - + + /* region select */ kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0); RNA_boolean_set(kmi->ptr, "deselect", false); kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "deselect", true); - + WM_keymap_add_item(keymap, "GRAPH_OT_select_circle", CKEY, KM_PRESS, 0, 0); /* column select */ diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index eb786d872ec..67b960bfa53 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -210,6 +210,8 @@ void GRAPH_OT_select_all_toggle(wmOperatorType *ot) * -> ALT-BKEY - depending on which axis of the region was larger... * -> 2) x-axis, so select all frames within frame range (validation with BEZT_OK_FRAMERANGE) * -> 3) y-axis, so select all frames within channels that region included (validation with BEZT_OK_VALUERANGE) + * + * The selection backend is also reused for the Lasso and Circle select operators. */ /* Borderselect only selects keyframes now, as overshooting handles often get caught too, @@ -245,12 +247,12 @@ static void borderselect_graphkeys( /* init editing data */ memset(&ked, 0, sizeof(KeyframeEditData)); if (mode == BEZT_OK_REGION_LASSO) { - struct KeyframeEdit_LassoData *data_lasso = data; + KeyframeEdit_LassoData *data_lasso = data; data_lasso->rectf_scaled = &scaled_rectf; ked.data = data_lasso; } else if (mode == BEZT_OK_REGION_CIRCLE) { - struct KeyframeEdit_CircleData *data_circle = data; + KeyframeEdit_CircleData *data_circle = data; data_circle->rectf_scaled = &scaled_rectf; ked.data = data; } @@ -265,27 +267,27 @@ static void borderselect_graphkeys( } else mapping_flag = ANIM_UNITCONV_ONLYKEYS; - + mapping_flag |= ANIM_get_normalization_flags(ac); - + /* loop over data, doing border select */ for (ale = anim_data.first; ale; ale = ale->next) { AnimData *adt = ANIM_nla_mapping_get(ac, ale); FCurve *fcu = (FCurve *)ale->key_data; float offset; float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset); - + /* apply NLA mapping to all the keyframes, since it's easier than trying to * guess when a callback might use something different */ if (adt) ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, incl_handles == 0); - + scaled_rectf.xmin = rectf.xmin; scaled_rectf.xmax = rectf.xmax; scaled_rectf.ymin = rectf.ymin / unit_scale - offset; scaled_rectf.ymax = rectf.ymax / unit_scale - offset; - + /* set horizontal range (if applicable) * NOTE: these values are only used for x-range and y-range but not region * (which uses ked.data, i.e. rectf) @@ -406,37 +408,41 @@ void GRAPH_OT_select_border(wmOperatorType *ot) RNA_def_boolean(ot->srna, "include_handles", 0, "Include Handles", "Are handles tested individually against the selection criteria"); } + +/* ------------------- */ + static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op) { bAnimContext ac; + + KeyframeEdit_LassoData data_lasso = {0}; rcti rect; rctf rect_fl; + short selectmode; bool incl_handles; bool extend; - - struct KeyframeEdit_LassoData data_lasso; - + /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) return OPERATOR_CANCELLED; - + data_lasso.rectf_view = &rect_fl; data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot); if (data_lasso.mcords == NULL) return OPERATOR_CANCELLED; - + /* clear all selection if not extending selection */ extend = RNA_boolean_get(op->ptr, "extend"); if (!extend) deselect_graph_keys(&ac, 1, SELECT_SUBTRACT, true); - + if (!RNA_boolean_get(op->ptr, "deselect")) selectmode = SELECT_ADD; else selectmode = SELECT_SUBTRACT; - - if (ac.spacetype == SPACE_IPO) { + + { SpaceIpo *sipo = (SpaceIpo *)ac.sl; if (selectmode == SELECT_ADD) { incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) || @@ -446,60 +452,57 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op) incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0; } } - else { - incl_handles = false; - } - - + /* get settings from operator */ BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot); - BLI_rctf_rcti_copy(&rect_fl, &rect); - + /* apply borderselect action */ borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_LASSO, selectmode, incl_handles, &data_lasso); - + MEM_freeN((void *)data_lasso.mcords); - - + /* send notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); - + return OPERATOR_FINISHED; } - void GRAPH_OT_select_lasso(wmOperatorType *ot) { /* identifiers */ ot->name = "Lasso Select"; ot->description = "Select keyframe points using lasso selection"; ot->idname = "GRAPH_OT_select_lasso"; - + /* api callbacks */ ot->invoke = WM_gesture_lasso_invoke; ot->modal = WM_gesture_lasso_modal; ot->exec = graphkeys_lassoselect_exec; ot->poll = graphop_visible_keyframes_poll; ot->cancel = WM_gesture_lasso_cancel; - + /* flags */ ot->flag = OPTYPE_UNDO; - + /* properties */ RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", ""); RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items"); RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first"); } +/* ------------------- */ + static int graph_circle_select_exec(bContext *C, wmOperator *op) { bAnimContext ac; const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode"); - short selectmode; - bool incl_handles; + const short selectmode = (gesture_mode == GESTURE_MODAL_SELECT) ? SELECT_ADD : SELECT_SUBTRACT; + bool incl_handles = false; + + KeyframeEdit_CircleData data = {0}; rctf rect_fl; - struct KeyframeEdit_CircleData data; + float x = RNA_int_get(op->ptr, "x"); float y = RNA_int_get(op->ptr, "y"); float radius = RNA_int_get(op->ptr, "radius"); @@ -507,23 +510,18 @@ static int graph_circle_select_exec(bContext *C, wmOperator *op) /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) return OPERATOR_CANCELLED; - + data.mval[0] = x; data.mval[1] = y; data.radius_squared = radius * radius; data.rectf_view = &rect_fl; - if (gesture_mode == GESTURE_MODAL_SELECT) - selectmode = SELECT_ADD; - else - selectmode = SELECT_SUBTRACT; - rect_fl.xmin = x - radius; rect_fl.xmax = x + radius; rect_fl.ymin = y - radius; rect_fl.ymax = y + radius; - if (ac.spacetype == SPACE_IPO) { + { SpaceIpo *sipo = (SpaceIpo *)ac.sl; if (selectmode == SELECT_ADD) { incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) || @@ -533,10 +531,7 @@ static int graph_circle_select_exec(bContext *C, wmOperator *op) incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0; } } - else { - incl_handles = false; - } - + /* apply borderselect action */ borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_CIRCLE, selectmode, incl_handles, &data); diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index a7284694f64..8ae5932f3fd 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -611,6 +611,51 @@ static void graph_refresh(const bContext *C, ScrArea *sa) } break; } + case FCURVE_COLOR_AUTO_YRGB: + { + /* Like FCURVE_COLOR_AUTO_RGB, except this is for quaternions... */ + float *col = fcu->color; + + switch (fcu->array_index) { + case 1: + UI_GetThemeColor3fv(TH_AXIS_X, col); + break; + case 2: + UI_GetThemeColor3fv(TH_AXIS_Y, col); + break; + case 3: + UI_GetThemeColor3fv(TH_AXIS_Z, col); + break; + + case 0: + { + /* Special Case: "W" channel should be yellowish, so blend X and Y channel colors... */ + float c1[3], c2[3]; + float h1[3], h2[3]; + float hresult[3]; + + /* - get colors (rgb) */ + UI_GetThemeColor3fv(TH_AXIS_X, c1); + UI_GetThemeColor3fv(TH_AXIS_Y, c2); + + /* - perform blending in HSV space (to keep brightness similar) */ + rgb_to_hsv_v(c1, h1); + rgb_to_hsv_v(c2, h2); + + interp_v3_v3v3(hresult, h1, h2, 0.5f); + + /* - convert back to RGB for display */ + hsv_to_rgb_v(hresult, col); + break; + } + + default: + /* 'unknown' color - bluish so as to not conflict with handles */ + col[0] = 0.3f; col[1] = 0.8f; col[2] = 1.0f; + break; + } + break; + } case FCURVE_COLOR_AUTO_RAINBOW: default: { diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 687869ae727..57d9ff7825b 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -399,13 +399,22 @@ static int outliner_id_remap_exec(bContext *C, wmOperator *op) ID *new_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "new_id")); /* check for invalid states */ - if (soops == NULL) + if (soops == NULL) { return OPERATOR_CANCELLED; + } if (!(old_id && (old_id != new_id) && (GS(old_id->name) == GS(new_id->name)))) { + BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, "Invalid old/new ID pair ('%s' / '%s')", + old_id->name, new_id->name); return OPERATOR_CANCELLED; } + if (old_id->lib) { + BKE_reportf(op->reports, RPT_WARNING, + "Old ID '%s' is linked from a library, indirect usages of this datablock will not be remapped", + old_id->name); + } + BKE_libblock_remap(bmain, old_id, new_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE); diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index d404e7aaf15..94ed280f792 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -384,8 +384,7 @@ static int text_unlink_exec(bContext *C, wmOperator *UNUSED(op)) } } - BKE_text_unlink(bmain, text); - BKE_libblock_free(bmain, text); + BKE_libblock_delete(bmain, text); text_drawcache_tag_update(st, 1); WM_event_add_notifier(C, NC_TEXT | NA_REMOVED, NULL); diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index c32de6eafc3..3b1ce5f8ab0 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -7032,7 +7032,7 @@ static void bbs_obmode_mesh_verts__mapFunc(void *userData, int index, const floa MVert *mv = &data->mvert[index]; if (!(mv->flag & ME_HIDE)) { - WM_framebuffer_index_set(data->offset + index); + GPU_select_index_set(data->offset + index); glVertex3fv(co); } } @@ -7057,7 +7057,7 @@ static void bbs_mesh_verts__mapFunc(void *userData, int index, const float co[3] BMVert *eve = BM_vert_at_index(data->bm, index); if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - WM_framebuffer_index_set(data->offset + index); + GPU_select_index_set(data->offset + index); glVertex3fv(co); } } @@ -7076,7 +7076,7 @@ static DMDrawOption bbs_mesh_wire__setDrawOptions(void *userData, int index) BMEdge *eed = BM_edge_at_index(data->bm, index); if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { - WM_framebuffer_index_set(data->offset + index); + GPU_select_index_set(data->offset + index); return DM_DRAW_OPTION_NORMAL; } else { @@ -7090,7 +7090,7 @@ static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset) } /** - * dont set #WM_framebuffer_index_set. just use to mask other + * dont set #GPU_framebuffer_index_set. just use to mask other */ static DMDrawOption bbs_mesh_mask__setSolidDrawOptions(void *userData, int index) { @@ -7109,7 +7109,7 @@ static DMDrawOption bbs_mesh_solid__setSolidDrawOptions(void *userData, int inde BMFace *efa = BM_face_at_index(userData, index); if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - WM_framebuffer_index_set(index + 1); + GPU_select_index_set(index + 1); return DM_DRAW_OPTION_NORMAL; } else { @@ -7122,7 +7122,7 @@ static void bbs_mesh_solid__drawCenter(void *userData, int index, const float ce BMFace *efa = BM_face_at_index(userData, index); if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - WM_framebuffer_index_set(index + 1); + GPU_select_index_set(index + 1); glVertex3fv(cent); } @@ -7153,7 +7153,7 @@ static void bbs_mesh_solid_EM(BMEditMesh *em, Scene *scene, View3D *v3d, static DMDrawOption bbs_mesh_solid__setDrawOpts(void *UNUSED(userData), int index) { - WM_framebuffer_index_set(index + 1); + GPU_select_index_set(index + 1); return DM_DRAW_OPTION_NORMAL; } @@ -7162,7 +7162,7 @@ static DMDrawOption bbs_mesh_solid_hide__setDrawOpts(void *userData, int index) Mesh *me = userData; if (!(me->mpoly[index].flag & ME_HIDE)) { - WM_framebuffer_index_set(index + 1); + GPU_select_index_set(index + 1); return DM_DRAW_OPTION_NORMAL; } else { @@ -7170,7 +7170,7 @@ static DMDrawOption bbs_mesh_solid_hide__setDrawOpts(void *userData, int index) } } -/* must have called WM_framebuffer_index_set beforehand */ +/* must have called GPU_framebuffer_index_set beforehand */ static DMDrawOption bbs_mesh_solid_hide2__setDrawOpts(void *userData, int index) { Mesh *me = userData; diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 64b12498ae2..dcab05c80d6 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1483,7 +1483,7 @@ unsigned int ED_view3d_backbuf_sample(ViewContext *vc, int x, int y) BLI_endian_switch_uint32(&col); } - return WM_framebuffer_to_index(col); + return GPU_select_to_index(col); } /* reads full rect, converts indices */ @@ -1516,7 +1516,7 @@ ImBuf *ED_view3d_backbuf_read(ViewContext *vc, int xmin, int ymin, int xmax, int IMB_convert_rgba_to_abgr(ibuf_clip); } - WM_framebuffer_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]); + GPU_select_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]); if ((clip.xmin == xmin) && (clip.xmax == xmax) && diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index fd7179d06dd..148db20b41d 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -93,6 +93,8 @@ #include "UI_interface.h" +#include "GPU_draw.h" + #include "view3d_intern.h" /* own include */ float ED_view3d_select_dist_px(void) @@ -1687,7 +1689,7 @@ static int do_paintvert_box_select(ViewContext *vc, rcti *rect, bool select, boo if (ENDIAN_ORDER == B_ENDIAN) { IMB_convert_rgba_to_abgr(ibuf); } - WM_framebuffer_to_index_array(ibuf->rect, size[0] * size[1]); + GPU_select_to_index_array(ibuf->rect, size[0] * size[1]); a = size[0] * size[1]; while (a--) { diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 943490bbc3a..c94b0d53468 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1202,8 +1202,12 @@ int transformEvent(TransInfo *t, const wmEvent *event) if (t->flag & T_PROP_EDIT) { float fac = 1.0f + 0.005f *(event->y - event->prevy); t->prop_size *= fac; - if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) - t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far); + if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) { + t->prop_size = max_ff(min_ff(t->prop_size, ((View3D *)t->view)->far), T_PROP_SIZE_MIN); + } + else { + t->prop_size = max_ff(min_ff(t->prop_size, T_PROP_SIZE_MAX), T_PROP_SIZE_MIN); + } calculatePropRatio(t); t->redraw |= TREDRAW_HARD; handled = true; @@ -1212,8 +1216,12 @@ int transformEvent(TransInfo *t, const wmEvent *event) case TFM_MODAL_PROPSIZE_UP: if (t->flag & T_PROP_EDIT) { t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f; - if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) + if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) { t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far); + } + else { + t->prop_size = min_ff(t->prop_size, T_PROP_SIZE_MAX); + } calculatePropRatio(t); t->redraw |= TREDRAW_HARD; handled = true; @@ -1222,6 +1230,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) case TFM_MODAL_PROPSIZE_DOWN: if (t->flag & T_PROP_EDIT) { t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f; + t->prop_size = max_ff(t->prop_size, T_PROP_SIZE_MIN); calculatePropRatio(t); t->redraw |= TREDRAW_HARD; handled = true; diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 4e8aa0cc20b..da448faa16b 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -592,6 +592,10 @@ typedef struct TransInfo { #define POINT_INIT 4 #define MULTI_POINTS 8 +/* Hard min/max for proportional size. */ +#define T_PROP_SIZE_MIN 1e-6f +#define T_PROP_SIZE_MAX 1e12f + bool initTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op, const struct wmEvent *event, int mode); void saveTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op); int transformEvent(TransInfo *t, const struct wmEvent *event); diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 2fb92d73515..6e399d9fde3 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -528,7 +528,8 @@ void Transform_Properties(struct wmOperatorType *ot, int flags) prop = RNA_def_enum(ot->srna, "proportional_edit_falloff", rna_enum_proportional_falloff_items, 0, "Proportional Editing Falloff", "Falloff type for proportional editing mode"); RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */ - RNA_def_float(ot->srna, "proportional_size", 1, 0.00001f, FLT_MAX, "Proportional Size", "", 0.001, 100); + RNA_def_float(ot->srna, "proportional_size", 1, T_PROP_SIZE_MIN, T_PROP_SIZE_MAX, + "Proportional Size", "", 0.001f, 100.0f); } if (flags & P_SNAP) { diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index d706c574d1f..1db4ee0e2e5 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -1627,7 +1627,7 @@ static bool transform_snap_context_project_view3d_mixed_impl( * Given a 2D region value, snap to vert/edge/face. * * \param sctx: Snap context. - * \param mval: Screenspace coordinate. + * \param mval_fl: Screenspace coordinate. * \param dist_px: Maximum distance to snap (in pixels). * \param use_depth: Snap to the closest element, use when using more than one snap type. * \param r_co: hit location. diff --git a/source/blender/freestyle/intern/system/PythonInterpreter.h b/source/blender/freestyle/intern/system/PythonInterpreter.h index 5403ec6b13b..0e08af1bac8 100644 --- a/source/blender/freestyle/intern/system/PythonInterpreter.h +++ b/source/blender/freestyle/intern/system/PythonInterpreter.h @@ -84,8 +84,7 @@ public: Text *text = BKE_text_load(&_freestyle_bmain, fn, G.main->name); if (text) { ok = BPY_execute_text(_context, text, reports, false); - BKE_text_unlink(&_freestyle_bmain, text); - BKE_libblock_free(&_freestyle_bmain, text); + BKE_libblock_delete(&_freestyle_bmain, text); } else { BKE_reportf(reports, RPT_ERROR, "Cannot open file: %s", fn); diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h index bc732387c85..90b65af87c8 100644 --- a/source/blender/gpu/GPU_draw.h +++ b/source/blender/gpu/GPU_draw.h @@ -160,6 +160,12 @@ struct DerivedMesh; void GPU_draw_update_fvar_offset(struct DerivedMesh *dm); #endif +/* utilities */ +void GPU_select_index_set(int index); +void GPU_select_index_get(int index, int *r_col); +int GPU_select_to_index(unsigned int col); +void GPU_select_to_index_array(unsigned int *col, const unsigned int size); + #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 52177b756c5..3ea64e1f6d5 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -2327,3 +2327,152 @@ void GPU_draw_update_fvar_offset(DerivedMesh *dm) } } #endif + + +/** \name Framebuffer color depth, for selection codes + * \{ */ + +#ifdef __APPLE__ + +/* apple seems to round colors to below and up on some configs */ + +static unsigned int index_to_framebuffer(int index) +{ + unsigned int i = index; + + switch (GPU_color_depth()) { + case 12: + i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4); + /* sometimes dithering subtracts! */ + i |= 0x070707; + break; + case 15: + case 16: + i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3); + i |= 0x030303; + break; + case 24: + break; + default: /* 18 bits... */ + i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2); + i |= 0x010101; + break; + } + + return i; +} + +#else + +/* this is the old method as being in use for ages.... seems to work? colors are rounded to lower values */ + +static unsigned int index_to_framebuffer(int index) +{ + unsigned int i = index; + + switch (GPU_color_depth()) { + case 8: + i = ((i & 48) << 18) + ((i & 12) << 12) + ((i & 3) << 6); + i |= 0x3F3F3F; + break; + case 12: + i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4); + /* sometimes dithering subtracts! */ + i |= 0x0F0F0F; + break; + case 15: + case 16: + i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3); + i |= 0x070707; + break; + case 24: + break; + default: /* 18 bits... */ + i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2); + i |= 0x030303; + break; + } + + return i; +} + +#endif + + +void GPU_select_index_set(int index) +{ + const int col = index_to_framebuffer(index); + glColor3ub(( (col) & 0xFF), + (((col) >> 8) & 0xFF), + (((col) >> 16) & 0xFF)); +} + +void GPU_select_index_get(int index, int *r_col) +{ + const int col = index_to_framebuffer(index); + char *c_col = (char *)r_col; + c_col[0] = (col & 0xFF); /* red */ + c_col[1] = ((col >> 8) & 0xFF); /* green */ + c_col[2] = ((col >> 16) & 0xFF); /* blue */ + c_col[3] = 0xFF; /* alpha */ +} + + +#define INDEX_FROM_BUF_8(col) ((((col) & 0xC00000) >> 18) + (((col) & 0xC000) >> 12) + (((col) & 0xC0) >> 6)) +#define INDEX_FROM_BUF_12(col) ((((col) & 0xF00000) >> 12) + (((col) & 0xF000) >> 8) + (((col) & 0xF0) >> 4)) +#define INDEX_FROM_BUF_15_16(col) ((((col) & 0xF80000) >> 9) + (((col) & 0xF800) >> 6) + (((col) & 0xF8) >> 3)) +#define INDEX_FROM_BUF_18(col) ((((col) & 0xFC0000) >> 6) + (((col) & 0xFC00) >> 4) + (((col) & 0xFC) >> 2)) +#define INDEX_FROM_BUF_24(col) ((col) & 0xFFFFFF) + +int GPU_select_to_index(unsigned int col) +{ + if (col == 0) { + return 0; + } + + switch (GPU_color_depth()) { + case 8: return INDEX_FROM_BUF_8(col); + case 12: return INDEX_FROM_BUF_12(col); + case 15: + case 16: return INDEX_FROM_BUF_15_16(col); + case 24: return INDEX_FROM_BUF_24(col); + default: return INDEX_FROM_BUF_18(col); + } +} + +void GPU_select_to_index_array(unsigned int *col, const unsigned int size) +{ +#define INDEX_BUF_ARRAY(INDEX_FROM_BUF_BITS) \ + for (i = size; i--; col++) { \ + if ((c = *col)) { \ + *col = INDEX_FROM_BUF_BITS(c); \ + } \ + } ((void)0) + + if (size > 0) { + unsigned int i, c; + + switch (GPU_color_depth()) { + case 8: + INDEX_BUF_ARRAY(INDEX_FROM_BUF_8); + break; + case 12: + INDEX_BUF_ARRAY(INDEX_FROM_BUF_12); + break; + case 15: + case 16: + INDEX_BUF_ARRAY(INDEX_FROM_BUF_15_16); + break; + case 24: + INDEX_BUF_ARRAY(INDEX_FROM_BUF_24); + break; + default: + INDEX_BUF_ARRAY(INDEX_FROM_BUF_18); + break; + } + } + +#undef INDEX_BUF_ARRAY +} + +/** \} */ diff --git a/source/blender/gpu/shaders/gpu_shader_vertex.glsl b/source/blender/gpu/shaders/gpu_shader_vertex.glsl index 9a6537b4f09..db0068d2f3d 100644 --- a/source/blender/gpu/shaders/gpu_shader_vertex.glsl +++ b/source/blender/gpu/shaders/gpu_shader_vertex.glsl @@ -14,6 +14,9 @@ varying vec3 varnormal; varying float gl_ClipDistance[6]; #endif + +/* Color, keep in sync with: gpu_shader_vertex_world.glsl */ + float srgb_to_linearrgb(float c) { if (c < 0.04045) @@ -76,6 +79,9 @@ void set_var_from_attr(vec4 attr, int info, out vec4 var) } } +/* end color code */ + + void main() { #ifndef USE_OPENSUBDIV diff --git a/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl index 9dbcaeb7a32..d45a4b316a8 100644 --- a/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl +++ b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl @@ -2,6 +2,74 @@ varying vec3 varposition; varying vec3 varnormal; + +/* Color, keep in sync with: gpu_shader_vertex.glsl */ + +float srgb_to_linearrgb(float c) +{ + if (c < 0.04045) + return (c < 0.0) ? 0.0 : c * (1.0 / 12.92); + else + return pow((c + 0.055) * (1.0 / 1.055), 2.4); +} + +void srgb_to_linearrgb(vec3 col_from, out vec3 col_to) +{ + col_to.r = srgb_to_linearrgb(col_from.r); + col_to.g = srgb_to_linearrgb(col_from.g); + col_to.b = srgb_to_linearrgb(col_from.b); +} + +void srgb_to_linearrgb(vec4 col_from, out vec4 col_to) +{ + col_to.r = srgb_to_linearrgb(col_from.r); + col_to.g = srgb_to_linearrgb(col_from.g); + col_to.b = srgb_to_linearrgb(col_from.b); + col_to.a = col_from.a; +} + +bool is_srgb(int info) +{ +#ifdef USE_NEW_SHADING + return (info == 1)? true: false; +#else + return false; +#endif +} + +void set_var_from_attr(float attr, int info, out float var) +{ + var = attr; +} + +void set_var_from_attr(vec2 attr, int info, out vec2 var) +{ + var = attr; +} + +void set_var_from_attr(vec3 attr, int info, out vec3 var) +{ + if (is_srgb(info)) { + srgb_to_linearrgb(attr, var); + } + else { + var = attr; + } +} + +void set_var_from_attr(vec4 attr, int info, out vec4 var) +{ + if (is_srgb(info)) { + srgb_to_linearrgb(attr, var); + } + else { + var = attr; + } +} + +/* end color code */ + + void main() { /* position does not need to be transformed, we already have it */ diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c index 95d061bcb75..3629332a4ac 100644 --- a/source/blender/imbuf/intern/thumbs.c +++ b/source/blender/imbuf/intern/thumbs.c @@ -46,6 +46,8 @@ #include "BLO_readfile.h" +#include "DNA_space_types.h" /* For FILE_MAX_LIBEXTRA */ + #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" #include "IMB_thumbs.h" @@ -533,7 +535,7 @@ ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source char thumb_path[FILE_MAX]; char thumb_name[40]; char uri[URI_MAX]; - char path_buff[FILE_MAX]; + char path_buff[FILE_MAX_LIBEXTRA]; const char *file_path; const char *path; BLI_stat_t st; diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index 4c1283452ff..6bd7b3a4999 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -537,8 +537,9 @@ typedef enum eFCurve_Extend { /* curve coloring modes */ typedef enum eFCurve_Coloring { FCURVE_COLOR_AUTO_RAINBOW = 0, /* automatically determine color using rainbow (calculated at drawtime) */ - FCURVE_COLOR_AUTO_RGB, /* automatically determine color using XYZ (array index) <-> RGB */ - FCURVE_COLOR_CUSTOM /* custom color */ + FCURVE_COLOR_AUTO_RGB = 1, /* automatically determine color using XYZ (array index) <-> RGB */ + FCURVE_COLOR_AUTO_YRGB = 3, /* automatically determine color where XYZ <-> RGB, but index(X) != 0 */ + FCURVE_COLOR_CUSTOM = 2, /* custom color */ } eFCurve_Coloring; /* ************************************************ */ diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 6cba3322135..46b30f41f5b 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -912,7 +912,8 @@ typedef struct NodeSunBeams { #define SHD_GLOSSY_BECKMANN 0 #define SHD_GLOSSY_SHARP 1 #define SHD_GLOSSY_GGX 2 -#define SHD_GLOSSY_ASHIKHMIN_SHIRLEY 3 +#define SHD_GLOSSY_ASHIKHMIN_SHIRLEY 3 +#define SHD_GLOSSY_MULTI_GGX 4 /* vector transform */ #define SHD_VECT_TRANSFORM_TYPE_VECTOR 0 diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 19545336f46..6851f380cd8 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -324,11 +324,6 @@ static void rna_ID_user_clear(ID *id) id->us = 0; /* don't save */ } -static void rna_ID_delete(ID *id, Main *bmain) -{ - BKE_libblock_delete(bmain, id); -} - static void rna_ID_user_remap(ID *id, Main *bmain, ID *new_id) { if (GS(id->name) == GS(new_id->name)) { @@ -977,10 +972,6 @@ static void rna_def_ID(BlenderRNA *brna) parm = RNA_def_pointer(func, "id", "ID", "", "New copy of the ID"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "destroy", "rna_ID_delete"); - RNA_def_function_flag(func, FUNC_USE_MAIN); - RNA_def_function_ui_description(func, "Delete this ID from Blender (WARNING: no undo, do not use it after calling this!)"); - func = RNA_def_function(srna, "user_clear", "rna_ID_user_clear"); RNA_def_function_ui_description(func, "Clear the user count of a data-block so its not saved, " "on reload the data will be removed"); diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c index 678b0ac8f1f..492430fbda6 100644 --- a/source/blender/makesrna/intern/rna_camera.c +++ b/source/blender/makesrna/intern/rna_camera.c @@ -257,13 +257,15 @@ void RNA_def_camera(BlenderRNA *brna) prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "clipsta"); - RNA_def_property_range(prop, 0.001f, FLT_MAX); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); RNA_def_property_ui_text(prop, "Clip Start", "Camera near clipping distance"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "clipend"); - RNA_def_property_range(prop, 1.0f, FLT_MAX); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); RNA_def_property_ui_text(prop, "Clip End", "Camera far clipping distance"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index 1487dfa074e..3043c5452c0 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -1844,6 +1844,8 @@ static void rna_def_fcurve(BlenderRNA *brna) "Cycle through the rainbow, trying to give each curve a unique color"}, {FCURVE_COLOR_AUTO_RGB, "AUTO_RGB", 0, "Auto XYZ to RGB", "Use axis colors for transform and color properties, and auto-rainbow for the rest"}, + {FCURVE_COLOR_AUTO_YRGB, "AUTO_YRGB", 0, "Auto WXYZ to YRGB", + "Use axis colors for XYZ parts of transform, and yellow for the 'W' channel"}, {FCURVE_COLOR_CUSTOM, "CUSTOM", 0, "User Defined", "Use custom hand-picked color for F-Curve"}, {0, NULL, 0, NULL, NULL} diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index cd379603901..c30414ab585 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -62,6 +62,7 @@ #include "BKE_object.h" #include "BKE_material.h" #include "BKE_icons.h" +#include "BKE_idcode.h" #include "BKE_image.h" #include "BKE_texture.h" #include "BKE_scene.h" @@ -112,30 +113,38 @@ # include "BPY_extern.h" #endif + +static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_ptr, int do_unlink) +{ + ID *id = id_ptr->data; + if (do_unlink) { + BKE_libblock_delete(bmain, id); + RNA_POINTER_INVALIDATE(id_ptr); + } + else if (ID_REAL_USERS(id) <= 0) { + BKE_libblock_free(bmain, id); + RNA_POINTER_INVALIDATE(id_ptr); + } + else { + BKE_reportf(reports, RPT_ERROR, + "%s '%s' must have zero users to be removed, found %d (try with unlink=True parameter)", + BKE_idcode_to_name(GS(id->name)), id->name + 2, ID_REAL_USERS(id)); + } +} + + static Camera *rna_Main_cameras_new(Main *bmain, const char *name) { ID *id = BKE_camera_add(bmain, name); id_us_min(id); return (Camera *)id; } -static void rna_Main_cameras_remove(Main *bmain, ReportList *reports, PointerRNA *camera_ptr) -{ - Camera *camera = camera_ptr->data; - if (ID_REAL_USERS(camera) <= 0) { - BKE_libblock_free(bmain, camera); - RNA_POINTER_INVALIDATE(camera_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Camera '%s' must have zero users to be removed, found %d", - camera->id.name + 2, ID_REAL_USERS(camera)); - } -} static Scene *rna_Main_scenes_new(Main *bmain, const char *name) { return BKE_scene_add(bmain, name); } -static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports, PointerRNA *scene_ptr) +static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports, PointerRNA *scene_ptr, int do_unlink) { /* don't call BKE_libblock_free(...) directly */ Scene *scene = scene_ptr->data; @@ -144,24 +153,23 @@ static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports if ((scene_new = scene->id.prev) || (scene_new = scene->id.next)) { - bScreen *sc = CTX_wm_screen(C); - if (sc->scene == scene) { + if (do_unlink) { + bScreen *sc = CTX_wm_screen(C); + if (sc->scene == scene) { #ifdef WITH_PYTHON - BPy_BEGIN_ALLOW_THREADS; + BPy_BEGIN_ALLOW_THREADS; #endif - ED_screen_set_scene(C, sc, scene_new); + ED_screen_set_scene(C, sc, scene_new); #ifdef WITH_PYTHON - BPy_END_ALLOW_THREADS; + BPy_END_ALLOW_THREADS; #endif + } } - - BKE_libblock_remap(bmain, scene, scene_new, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE); - BKE_libblock_free(bmain, scene); - RNA_POINTER_INVALIDATE(scene_ptr); + rna_Main_ID_remove(bmain, reports, scene_ptr, do_unlink); } else { BKE_reportf(reports, RPT_ERROR, "Scene '%s' is the last, cannot be removed", scene->id.name + 2); @@ -222,38 +230,12 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char return ob; } -static void rna_Main_objects_remove(Main *bmain, ReportList *reports, PointerRNA *object_ptr) -{ - Object *object = object_ptr->data; - if (ID_REAL_USERS(object) <= 0) { - BKE_libblock_unlink(bmain, object, false); - BKE_libblock_free(bmain, object); - RNA_POINTER_INVALIDATE(object_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Object '%s' must have zero users to be removed, found %d", - object->id.name + 2, ID_REAL_USERS(object)); - } -} - static Material *rna_Main_materials_new(Main *bmain, const char *name) { ID *id = (ID *)BKE_material_add(bmain, name); id_us_min(id); return (Material *)id; } -static void rna_Main_materials_remove(Main *bmain, ReportList *reports, PointerRNA *material_ptr) -{ - Material *material = material_ptr->data; - if (ID_REAL_USERS(material) <= 0) { - BKE_libblock_free(bmain, material); - RNA_POINTER_INVALIDATE(material_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Material '%s' must have zero users to be removed, found %d", - material->id.name + 2, ID_REAL_USERS(material)); - } -} static EnumPropertyItem *rna_Main_nodetree_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) { @@ -271,18 +253,6 @@ static struct bNodeTree *rna_Main_nodetree_new(Main *bmain, const char *name, in else return NULL; } -static void rna_Main_nodetree_remove(Main *bmain, ReportList *reports, PointerRNA *ntree_ptr) -{ - bNodeTree *ntree = ntree_ptr->data; - if (ID_REAL_USERS(ntree) <= 0) { - BKE_libblock_free(bmain, ntree); - RNA_POINTER_INVALIDATE(ntree_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Node tree '%s' must have zero users to be removed, found %d", - ntree->id.name + 2, ID_REAL_USERS(ntree)); - } -} static Mesh *rna_Main_meshes_new(Main *bmain, const char *name) { @@ -312,19 +282,6 @@ Mesh *rna_Main_meshes_new_from_object( return BKE_mesh_new_from_object(bmain, sce, ob, apply_modifiers, settings, calc_tessface, calc_undeformed); } -static void rna_Main_meshes_remove(Main *bmain, ReportList *reports, PointerRNA *mesh_ptr) -{ - Mesh *mesh = mesh_ptr->data; - if (ID_REAL_USERS(mesh) <= 0) { - BKE_libblock_free(bmain, mesh); - RNA_POINTER_INVALIDATE(mesh_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Mesh '%s' must have zero users to be removed, found %d", - mesh->id.name + 2, ID_REAL_USERS(mesh)); - } -} - static Lamp *rna_Main_lamps_new(Main *bmain, const char *name, int type) { Lamp *lamp = BKE_lamp_add(bmain, name); @@ -332,18 +289,6 @@ static Lamp *rna_Main_lamps_new(Main *bmain, const char *name, int type) id_us_min(&lamp->id); return lamp; } -static void rna_Main_lamps_remove(Main *bmain, ReportList *reports, PointerRNA *lamp_ptr) -{ - Lamp *lamp = lamp_ptr->data; - if (ID_REAL_USERS(lamp) <= 0) { - BKE_libblock_free(bmain, lamp); - RNA_POINTER_INVALIDATE(lamp_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Lamp '%s' must have zero users to be removed, found %d", - lamp->id.name + 2, ID_REAL_USERS(lamp)); - } -} static Image *rna_Main_images_new(Main *bmain, const char *name, int width, int height, int alpha, int float_buffer, int stereo3d) { @@ -372,18 +317,6 @@ static Image *rna_Main_images_load(Main *bmain, ReportList *reports, const char id_us_min((ID *)ima); return ima; } -static void rna_Main_images_remove(Main *bmain, ReportList *reports, PointerRNA *image_ptr) -{ - Image *image = image_ptr->data; - if (ID_REAL_USERS(image) <= 0) { - BKE_libblock_free(bmain, image); - RNA_POINTER_INVALIDATE(image_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Image '%s' must have zero users to be removed, found %d", - image->id.name + 2, ID_REAL_USERS(image)); - } -} static Lattice *rna_Main_lattices_new(Main *bmain, const char *name) { @@ -391,18 +324,6 @@ static Lattice *rna_Main_lattices_new(Main *bmain, const char *name) id_us_min(<->id); return lt; } -static void rna_Main_lattices_remove(Main *bmain, ReportList *reports, PointerRNA *lt_ptr) -{ - Lattice *lt = lt_ptr->data; - if (ID_REAL_USERS(lt) <= 0) { - BKE_libblock_free(bmain, lt); - RNA_POINTER_INVALIDATE(lt_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Lattice '%s' must have zero users to be removed, found %d", - lt->id.name + 2, ID_REAL_USERS(lt)); - } -} static Curve *rna_Main_curves_new(Main *bmain, const char *name, int type) { @@ -410,18 +331,6 @@ static Curve *rna_Main_curves_new(Main *bmain, const char *name, int type) id_us_min(&cu->id); return cu; } -static void rna_Main_curves_remove(Main *bmain, ReportList *reports, PointerRNA *cu_ptr) -{ - Curve *cu = cu_ptr->data; - if (ID_REAL_USERS(cu) <= 0) { - BKE_libblock_free(bmain, cu); - RNA_POINTER_INVALIDATE(cu_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Curve '%s' must have zero users to be removed, found %d", - cu->id.name + 2, ID_REAL_USERS(cu)); - } -} static MetaBall *rna_Main_metaballs_new(Main *bmain, const char *name) { @@ -429,18 +338,6 @@ static MetaBall *rna_Main_metaballs_new(Main *bmain, const char *name) id_us_min(&mb->id); return mb; } -static void rna_Main_metaballs_remove(Main *bmain, ReportList *reports, PointerRNA *mb_ptr) -{ - MetaBall *mb = mb_ptr->data; - if (ID_REAL_USERS(mb) <= 0) { - BKE_libblock_free(bmain, mb); - RNA_POINTER_INVALIDATE(mb_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Metaball '%s' must have zero users to be removed, found %d", - mb->id.name + 2, ID_REAL_USERS(mb)); - } -} static VFont *rna_Main_fonts_load(Main *bmain, ReportList *reports, const char *filepath, int check_existing) { @@ -462,18 +359,6 @@ static VFont *rna_Main_fonts_load(Main *bmain, ReportList *reports, const char * return font; } -static void rna_Main_fonts_remove(Main *bmain, ReportList *reports, PointerRNA *vfont_ptr) -{ - VFont *vfont = vfont_ptr->data; - if (ID_REAL_USERS(vfont) <= 0) { - BKE_libblock_free(bmain, vfont); - RNA_POINTER_INVALIDATE(vfont_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Font '%s' must have zero users to be removed, found %d", - vfont->id.name + 2, ID_REAL_USERS(vfont)); - } -} static Tex *rna_Main_textures_new(Main *bmain, const char *name, int type) { @@ -482,18 +367,6 @@ static Tex *rna_Main_textures_new(Main *bmain, const char *name, int type) id_us_min(&tex->id); return tex; } -static void rna_Main_textures_remove(Main *bmain, ReportList *reports, PointerRNA *tex_ptr) -{ - Tex *tex = tex_ptr->data; - if (ID_REAL_USERS(tex) <= 0) { - BKE_libblock_free(bmain, tex); - RNA_POINTER_INVALIDATE(tex_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Texture '%s' must have zero users to be removed, found %d", - tex->id.name + 2, ID_REAL_USERS(tex)); - } -} static Brush *rna_Main_brushes_new(Main *bmain, const char *name, int mode) { @@ -502,50 +375,17 @@ static Brush *rna_Main_brushes_new(Main *bmain, const char *name, int mode) return brush; } -static void rna_Main_brushes_remove(Main *bmain, ReportList *reports, PointerRNA *brush_ptr) -{ - Brush *brush = brush_ptr->data; - if (ID_REAL_USERS(brush) <= 0) { - BKE_brush_unlink(bmain, brush); - BKE_libblock_free(bmain, brush); - RNA_POINTER_INVALIDATE(brush_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Brush '%s' must have zero users to be removed, found %d", - brush->id.name + 2, ID_REAL_USERS(brush)); - } -} - static World *rna_Main_worlds_new(Main *bmain, const char *name) { World *world = add_world(bmain, name); id_us_min(&world->id); return world; } -static void rna_Main_worlds_remove(Main *bmain, ReportList *reports, PointerRNA *world_ptr) -{ - Group *world = world_ptr->data; - if (ID_REAL_USERS(world) <= 0) { - BKE_libblock_free(bmain, world); - RNA_POINTER_INVALIDATE(world_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "World '%s' must have zero users to be removed, found %d", - world->id.name + 2, ID_REAL_USERS(world)); - } -} static Group *rna_Main_groups_new(Main *bmain, const char *name) { return BKE_group_add(bmain, name); } -static void rna_Main_groups_remove(Main *bmain, PointerRNA *group_ptr) -{ - Group *group = group_ptr->data; - BKE_libblock_unlink(bmain, group, false); - BKE_libblock_free(bmain, group); - RNA_POINTER_INVALIDATE(group_ptr); -} static Speaker *rna_Main_speakers_new(Main *bmain, const char *name) { @@ -553,18 +393,6 @@ static Speaker *rna_Main_speakers_new(Main *bmain, const char *name) id_us_min(&speaker->id); return speaker; } -static void rna_Main_speakers_remove(Main *bmain, ReportList *reports, PointerRNA *speaker_ptr) -{ - Speaker *speaker = speaker_ptr->data; - if (ID_REAL_USERS(speaker) <= 0) { - BKE_libblock_free(bmain, speaker); - RNA_POINTER_INVALIDATE(speaker_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Speaker '%s' must have zero users to be removed, found %d", - speaker->id.name + 2, ID_REAL_USERS(speaker)); - } -} static bSound *rna_Main_sounds_load(Main *bmain, const char *name, int check_existing) { @@ -580,30 +408,11 @@ static bSound *rna_Main_sounds_load(Main *bmain, const char *name, int check_exi id_us_min(&sound->id); return sound; } -static void rna_Main_sounds_remove(Main *bmain, ReportList *reports, PointerRNA *sound_ptr) -{ - Speaker *sound = sound_ptr->data; - if (ID_REAL_USERS(sound) <= 0) { - BKE_libblock_free(bmain, sound); - RNA_POINTER_INVALIDATE(sound_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Sound '%s' must have zero users to be removed, found %d", - sound->id.name + 2, ID_REAL_USERS(sound)); - } -} static Text *rna_Main_texts_new(Main *bmain, const char *name) { return BKE_text_add(bmain, name); } -static void rna_Main_texts_remove(Main *bmain, PointerRNA *text_ptr) -{ - Text *text = text_ptr->data; - BKE_text_unlink(bmain, text); - BKE_libblock_free(bmain, text); - RNA_POINTER_INVALIDATE(text_ptr); -} static Text *rna_Main_texts_load(Main *bmain, ReportList *reports, const char *filepath, int is_internal) { @@ -625,37 +434,12 @@ static bArmature *rna_Main_armatures_new(Main *bmain, const char *name) id_us_min(&arm->id); return arm; } -static void rna_Main_armatures_remove(Main *bmain, ReportList *reports, PointerRNA *arm_ptr) -{ - bArmature *arm = arm_ptr->data; - if (ID_REAL_USERS(arm) <= 0) { - BKE_libblock_free(bmain, arm); - RNA_POINTER_INVALIDATE(arm_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Armature '%s' must have zero users to be removed, found %d", - arm->id.name + 2, ID_REAL_USERS(arm)); - } -} static bAction *rna_Main_actions_new(Main *bmain, const char *name) { bAction *act = add_empty_action(bmain, name); id_fake_user_clear(&act->id); return act; -} -static void rna_Main_actions_remove(Main *bmain, ReportList *reports, PointerRNA *act_ptr) -{ - bAction *act = act_ptr->data; - if (ID_REAL_USERS(act) <= 0) { - BKE_libblock_free(bmain, act); - RNA_POINTER_INVALIDATE(act_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Action '%s' must have zero users to be removed, found %d", - act->id.name + 2, ID_REAL_USERS(act)); - } -} static Palette *rna_Main_palettes_new(Main *bmain, const char *name) { @@ -663,18 +447,6 @@ static Palette *rna_Main_palettes_new(Main *bmain, const char *name) id_us_min(&palette->id); return (Palette *)palette; } -static void rna_Main_palettes_remove(Main *bmain, ReportList *reports, PointerRNA *palette_ptr) -{ - Palette *palette = palette_ptr->data; - if (ID_REAL_USERS(palette) <= 0) { - BKE_libblock_free(bmain, palette); - RNA_POINTER_INVALIDATE(palette_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Palette settings '%s' must have zero users to be removed, found %d", - palette->id.name + 2, ID_REAL_USERS(palette)); - } -} static MovieClip *rna_Main_movieclip_load(Main *bmain, ReportList *reports, const char *filepath, int check_existing) { @@ -697,14 +469,6 @@ static MovieClip *rna_Main_movieclip_load(Main *bmain, ReportList *reports, cons return clip; } -static void rna_Main_movieclips_remove(Main *bmain, PointerRNA *clip_ptr) -{ - MovieClip *clip = clip_ptr->data; - BKE_movieclip_unlink(bmain, clip); - BKE_libblock_free(bmain, clip); - RNA_POINTER_INVALIDATE(clip_ptr); -} - static Mask *rna_Main_mask_new(Main *bmain, const char *name) { Mask *mask; @@ -714,26 +478,6 @@ static Mask *rna_Main_mask_new(Main *bmain, const char *name) return mask; } -static void rna_Main_masks_remove(Main *bmain, PointerRNA *mask_ptr) -{ - Mask *mask = mask_ptr->data; - BKE_libblock_free(bmain, mask); - RNA_POINTER_INVALIDATE(mask_ptr); -} - -static void rna_Main_grease_pencil_remove(Main *bmain, ReportList *reports, PointerRNA *gpd_ptr) -{ - bGPdata *gpd = gpd_ptr->data; - if (ID_REAL_USERS(gpd) <= 0) { - BKE_gpencil_free(gpd); - BKE_libblock_free(bmain, gpd); - RNA_POINTER_INVALIDATE(gpd_ptr); - } - else - BKE_reportf(reports, RPT_ERROR, "Grease pencil '%s' must have zero users to be removed, found %d", - gpd->id.name + 2, ID_REAL_USERS(gpd)); -} - static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name) { FreestyleLineStyle *linestyle = BKE_linestyle_new(bmain, name); @@ -741,17 +485,6 @@ static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name return linestyle; } -static void rna_Main_linestyles_remove(Main *bmain, ReportList *reports, FreestyleLineStyle *linestyle) -{ - if (ID_REAL_USERS(linestyle) <= 0) - BKE_libblock_free(bmain, linestyle); - else - BKE_reportf(reports, RPT_ERROR, "Line style '%s' must have zero users to be removed, found %d", - linestyle->id.name + 2, ID_REAL_USERS(linestyle)); - - /* XXX python now has invalid pointer? */ -} - /* tag and is_updated functions, all the same */ #define RNA_MAIN_ID_TAG_FUNCS_DEF(_func_name, _listbase_name, _id_type) \ static void rna_Main_##_func_name##_tag(Main *bmain, int value) { \ @@ -833,12 +566,15 @@ void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "camera", "Camera", "", "New camera data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_cameras_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a camera from the current blendfile"); parm = RNA_def_pointer(func, "camera", "Camera", "", "Camera to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", + "Unlink all usages of this camera before deleting it " + "(WARNING: will also delete objects instancing that camera data)"); func = RNA_def_function(srna, "tag", "rna_Main_cameras_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -875,6 +611,7 @@ void RNA_def_main_scenes(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this scene before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_scenes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -909,12 +646,13 @@ void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "object", "Object", "", "New object data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_objects_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_ui_description(func, "Remove a object from the current blendfile"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "object", "Object", "", "Object to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this object before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_objects_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -945,12 +683,13 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "material", "Material", "", "New material data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_materials_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a material from the current blendfile"); parm = RNA_def_pointer(func, "material", "Material", "", "Material to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this material before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_materials_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -988,12 +727,13 @@ void RNA_def_main_node_groups(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "tree", "NodeTree", "", "New node tree data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_nodetree_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a node tree from the current blendfile"); parm = RNA_def_pointer(func, "tree", "NodeTree", "", "Node tree to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this node tree before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_node_groups_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1046,12 +786,15 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop) "Mesh created from object, remove it if it is only used for export"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_meshes_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a mesh from the current blendfile"); parm = RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", + "Unlink all usages of this mesh before deleting it " + "(WARNING: will also delete objects instancing that mesh data)"); func = RNA_def_function(srna, "tag", "rna_Main_meshes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1083,12 +826,15 @@ void RNA_def_main_lamps(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "lamp", "Lamp", "", "New lamp data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_lamps_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a lamp from the current blendfile"); parm = RNA_def_pointer(func, "lamp", "Lamp", "", "Lamp to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", + "Unlink all usages of this lamp before deleting it " + "(WARNING: will also delete objects instancing that lamp data)"); func = RNA_def_function(srna, "tag", "rna_Main_lamps_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1198,12 +944,13 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "image", "Image", "", "New image data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_images_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove an image from the current blendfile"); parm = RNA_def_pointer(func, "image", "Image", "", "Image to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this image before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_images_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1234,12 +981,15 @@ void RNA_def_main_lattices(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "lattice", "Lattice", "", "New lattices data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_lattices_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a lattice from the current blendfile"); parm = RNA_def_pointer(func, "lattice", "Lattice", "", "Lattice to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", + "Unlink all usages of this lattice before deleting it " + "(WARNING: will also delete objects instancing that lattice data)"); func = RNA_def_function(srna, "tag", "rna_Main_lattices_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1271,12 +1021,15 @@ void RNA_def_main_curves(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "curve", "Curve", "", "New curve data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_curves_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a curve from the current blendfile"); parm = RNA_def_pointer(func, "curve", "Curve", "", "Curve to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", + "Unlink all usages of this curve before deleting it " + "(WARNING: will also delete objects instancing that curve data)"); func = RNA_def_function(srna, "tag", "rna_Main_curves_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1306,12 +1059,15 @@ void RNA_def_main_metaballs(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "metaball", "MetaBall", "", "New metaball data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_metaballs_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a metaball from the current blendfile"); parm = RNA_def_pointer(func, "metaball", "MetaBall", "", "Metaball to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", + "Unlink all usages of this metaball before deleting it " + "(WARNING: will also delete objects instancing that metaball data)"); func = RNA_def_function(srna, "tag", "rna_Main_metaballs_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1343,12 +1099,13 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "New font data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_fonts_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a font from the current blendfile"); parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "Font to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this font before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_fonts_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1380,12 +1137,13 @@ void RNA_def_main_textures(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "texture", "Texture", "", "New texture data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_textures_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a texture from the current blendfile"); parm = RNA_def_pointer(func, "texture", "Texture", "", "Texture to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this texture before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_textures_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1416,12 +1174,13 @@ void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "brush", "Brush", "", "New brush data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_brushes_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a brush from the current blendfile"); parm = RNA_def_pointer(func, "brush", "Brush", "", "Brush to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this brush before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_brushes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1452,12 +1211,13 @@ void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "world", "World", "", "New world data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_worlds_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a world from the current blendfile"); parm = RNA_def_pointer(func, "world", "World", "", "World to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this world before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_worlds_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1488,11 +1248,13 @@ void RNA_def_main_groups(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "group", "Group", "", "New group data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_groups_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_ui_description(func, "Remove a group from the current blendfile"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "group", "Group", "", "Group to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this group before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_groups_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1523,12 +1285,15 @@ void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "speaker", "Speaker", "", "New speaker data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_speakers_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a speaker from the current blendfile"); parm = RNA_def_pointer(func, "speaker", "Speaker", "", "Speaker to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", + "Unlink all usages of this speaker before deleting it " + "(WARNING: will also delete objects instancing that speaker data)"); func = RNA_def_function(srna, "tag", "rna_Main_speakers_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1559,11 +1324,13 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "text", "Text", "", "New text data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_texts_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_ui_description(func, "Remove a text from the current blendfile"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "text", "Text", "", "Text to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this text before deleting it"); /* load func */ func = RNA_def_function(srna, "load", "rna_Main_texts_load"); @@ -1607,12 +1374,13 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "sound", "Sound", "", "New text data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_sounds_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a sound from the current blendfile"); parm = RNA_def_pointer(func, "sound", "Sound", "", "Sound to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this sound before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_sounds_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1643,12 +1411,15 @@ void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "armature", "Armature", "", "New armature data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_armatures_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a armature from the current blendfile"); parm = RNA_def_pointer(func, "armature", "Armature", "", "Armature to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", + "Unlink all usages of this armature before deleting it " + "(WARNING: will also delete objects instancing that armature data)"); func = RNA_def_function(srna, "tag", "rna_Main_armatures_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1678,12 +1449,13 @@ void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "action", "Action", "", "New action data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_actions_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a action from the current blendfile"); parm = RNA_def_pointer(func, "action", "Action", "", "Action to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this action before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_actions_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1713,12 +1485,13 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "palette", "Palette", "", "New palette data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_palettes_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a palette from the current blendfile"); parm = RNA_def_pointer(func, "palette", "Palette", "", "Palette to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this palette before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_palettes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1752,12 +1525,13 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "grease_pencil", "GreasePencil", "", "New grease pencil data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_grease_pencil_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a grease pencil instance from the current blendfile"); parm = RNA_def_pointer(func, "grease_pencil", "GreasePencil", "", "Grease Pencil to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this grease pencil before deleting it"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1780,11 +1554,13 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_boolean(func, "value", 0, "Value", ""); RNA_def_property_flag(parm, PROP_REQUIRED); - func = RNA_def_function(srna, "remove", "rna_Main_movieclips_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a movie clip from the current blendfile."); parm = RNA_def_pointer(func, "clip", "MovieClip", "", "Movie clip to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this movie clip before deleting it"); /* load func */ func = RNA_def_function(srna, "load", "rna_Main_movieclip_load"); @@ -1830,11 +1606,13 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_return(func, parm); /* remove func */ - func = RNA_def_function(srna, "remove", "rna_Main_masks_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a masks from the current blendfile."); parm = RNA_def_pointer(func, "mask", "Mask", "", "Mask to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this mask before deleting it"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1865,11 +1643,13 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "New line style data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_linestyles_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a line style instance from the current blendfile"); parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "Line style to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); + RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this line style before deleting it"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 1ab52aa45d3..e5dc613a0cd 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1812,6 +1812,12 @@ static void rna_def_modifier_hook(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Hook Center", ""); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "matrix_inverse", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_float_sdna(prop, NULL, "parentinv"); + RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); + RNA_def_property_ui_text(prop, "Matrix", "Reverse the transformation between this object and its target"); + RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Modifier_update"); + prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "Object", "Parent Object for hook, also recalculates and clears offset"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index dffdd7fe6c7..95f258e95f4 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -3162,12 +3162,14 @@ static EnumPropertyItem node_glossy_items[] = { {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""}, {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, {SHD_GLOSSY_ASHIKHMIN_SHIRLEY, "ASHIKHMIN_SHIRLEY", 0, "Ashikhmin-Shirley", ""}, + {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""}, {0, NULL, 0, NULL, NULL} }; static EnumPropertyItem node_anisotropic_items[] = { {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""}, {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, + {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""}, {SHD_GLOSSY_ASHIKHMIN_SHIRLEY, "ASHIKHMIN_SHIRLEY", 0, "Ashikhmin-Shirley", ""}, {0, NULL, 0, NULL, NULL} }; @@ -3176,6 +3178,14 @@ static EnumPropertyItem node_glass_items[] = { {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""}, {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""}, {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, + {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""}, + {0, NULL, 0, NULL, NULL} +}; + +static EnumPropertyItem node_refraction_items[] = { + {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""}, + {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""}, + {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, {0, NULL, 0, NULL, NULL} }; @@ -4120,6 +4130,17 @@ static void def_glass(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_refraction(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "custom1"); + RNA_def_property_enum_items(prop, node_refraction_items); + RNA_def_property_ui_text(prop, "Distribution", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); +} + static void def_anisotropic(StructRNA *srna) { PropertyRNA *prop; diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 0b8717fc982..559d7e82076 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -1793,7 +1793,7 @@ static void rna_FileBrowser_FSMenu_active_range( static void rna_FileBrowser_FSMenu_active_update(struct bContext *C, PointerRNA *UNUSED(ptr)) { - ED_file_change_dir(C, true); + ED_file_change_dir(C); } static int rna_FileBrowser_FSMenuSystem_active_get(PointerRNA *ptr) @@ -2437,14 +2437,16 @@ static void rna_def_space_view3d(BlenderRNA *brna) prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "near"); - RNA_def_property_range(prop, 0.001f, FLT_MAX); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); RNA_def_property_float_default(prop, 0.1f); RNA_def_property_ui_text(prop, "Clip Start", "3D View near clipping distance (perspective view only)"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "far"); - RNA_def_property_range(prop, 1.0f, FLT_MAX); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); RNA_def_property_float_default(prop, 1000.0f); RNA_def_property_ui_text(prop, "Clip End", "3D View far clipping distance"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 9e1a0c926fa..171d5313c1d 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -82,7 +82,7 @@ DefNode( ShaderNode, SH_NODE_BSDF_ANISOTROPIC, def_anisotropic, "BS DefNode( ShaderNode, SH_NODE_BSDF_DIFFUSE, 0, "BSDF_DIFFUSE", BsdfDiffuse, "Diffuse BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_GLOSSY, def_glossy, "BSDF_GLOSSY", BsdfGlossy, "Glossy BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_GLASS, def_glass, "BSDF_GLASS", BsdfGlass, "Glass BSDF", "" ) -DefNode( ShaderNode, SH_NODE_BSDF_REFRACTION, def_glass, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "" ) +DefNode( ShaderNode, SH_NODE_BSDF_REFRACTION, def_refraction, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_TRANSLUCENT, 0, "BSDF_TRANSLUCENT", BsdfTranslucent, "Translucent BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_TRANSPARENT, 0, "BSDF_TRANSPARENT", BsdfTransparent, "Transparent BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_VELVET, 0, "BSDF_VELVET", BsdfVelvet, "Velvet BSDF", "" ) diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index d6c57f4c302..eaa96e6243c 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -264,6 +264,11 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args) if ((reports->flag & RPT_FREE) == 0) { MEM_freeN(reports); } + else { + /* The WM is now responsible for running the modal operator, + * show reports in the info window. */ + reports->flag &= ~RPT_OP_HOLD; + } } WM_operator_properties_free(&ptr); diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 69ae7433fff..af6ac4a8fbf 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -1672,7 +1672,7 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset) } } - if (dl->bevelSplitFlag || timeoffset==0) { + if (dl->bevel_split || timeoffset == 0) { const int startvlak= obr->totvlak; for (a=0; a<dl->parts; a++) { @@ -1712,10 +1712,15 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset) } } - if (dl->bevelSplitFlag) { - for (a=0; a<dl->parts-1+!!(dl->flag&DL_CYCL_V); a++) - if (dl->bevelSplitFlag[a>>5]&(1<<(a&0x1F))) - split_v_renderfaces(obr, startvlak, startvert, dl->parts, dl->nr, a, dl->flag&DL_CYCL_V, dl->flag&DL_CYCL_U); + if (dl->bevel_split) { + for (a = 0; a < dl->parts - 1 + !!(dl->flag & DL_CYCL_V); a++) { + if (BLI_BITMAP_TEST(dl->bevel_split, a)) { + split_v_renderfaces( + obr, startvlak, startvert, dl->parts, dl->nr, a, + /* intentionally swap (v, u) --> (u, v) */ + dl->flag & DL_CYCL_V, dl->flag & DL_CYCL_U); + } + } } /* vertex normals */ diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 9bb2462a4e9..7a247d9791b 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -413,12 +413,6 @@ void wmOrtho2 (float x1, float x2, float y1, float y2); void wmOrtho2_region_pixelspace(const struct ARegion *ar); void wmOrtho2_pixelspace(const float x, const float y); - /* utilities */ -void WM_framebuffer_index_set(int index); -void WM_framebuffer_index_get(int index, int *r_col); -int WM_framebuffer_to_index(unsigned int col); -void WM_framebuffer_to_index_array(unsigned int *col, const unsigned int size); - /* threaded Jobs Manager */ enum { WM_JOB_PRIORITY = (1 << 0), diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index a1ca89c6a8c..9d1083bbf63 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -141,6 +141,11 @@ static void wm_free_reports(bContext *C) BKE_reports_clear(reports); } +static void wm_undo_kill_callback(bContext *C) +{ + WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C)); +} + bool wm_start_with_console = false; /* used in creator.c */ /* only called once, for startup */ @@ -159,6 +164,8 @@ void WM_init(bContext *C, int argc, const char **argv) WM_menutype_init(); WM_uilisttype_init(); + BKE_undo_callback_wm_kill_jobs_set(wm_undo_kill_callback); + BKE_library_callback_free_window_manager_set(wm_close_and_free); /* library.c */ BKE_library_callback_free_notifier_reference_set(WM_main_remove_notifier_reference); /* library.c */ BKE_library_callback_remap_editor_id_reference_set(WM_main_remap_editor_id_reference); /* library.c */ @@ -579,6 +586,8 @@ void WM_exit_ext(bContext *C, const bool do_python) BLI_threadapi_exit(); + BKE_blender_atexit(); + if (MEM_get_memory_blocks_in_use() != 0) { size_t mem_in_use = MEM_get_memory_in_use() + MEM_get_memory_in_use(); printf("Error: Not freed memory blocks: %u, total unfreed memory %f MB\n", diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index a51648290db..8968c2a4543 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -4208,7 +4208,8 @@ static void gesture_circle_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_assign(keymap, "MASK_OT_select_circle"); WM_modalkeymap_assign(keymap, "NODE_OT_select_circle"); WM_modalkeymap_assign(keymap, "GPENCIL_OT_select_circle"); - WM_modalkeymap_assign(keymap, "GRAPH_OT_select_circle"); + WM_modalkeymap_assign(keymap, "GRAPH_OT_select_circle"); + WM_modalkeymap_assign(keymap, "ACTION_OT_select_circle"); } diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c index 6526d419914..458ac4a121a 100644 --- a/source/blender/windowmanager/intern/wm_subwindow.c +++ b/source/blender/windowmanager/intern/wm_subwindow.c @@ -378,149 +378,5 @@ void wmOrtho2_pixelspace(const float x, const float y) wmOrtho2_offset(x, y, -GLA_PIXEL_OFS); } -/* *************************** Framebuffer color depth, for selection codes ********************** */ - -#ifdef __APPLE__ - -/* apple seems to round colors to below and up on some configs */ - -unsigned int index_to_framebuffer(int index) -{ - unsigned int i = index; - - switch (GPU_color_depth()) { - case 12: - i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4); - /* sometimes dithering subtracts! */ - i |= 0x070707; - break; - case 15: - case 16: - i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3); - i |= 0x030303; - break; - case 24: - break; - default: /* 18 bits... */ - i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2); - i |= 0x010101; - break; - } - - return i; -} - -#else - -/* this is the old method as being in use for ages.... seems to work? colors are rounded to lower values */ - -unsigned int index_to_framebuffer(int index) -{ - unsigned int i = index; - - switch (GPU_color_depth()) { - case 8: - i = ((i & 48) << 18) + ((i & 12) << 12) + ((i & 3) << 6); - i |= 0x3F3F3F; - break; - case 12: - i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4); - /* sometimes dithering subtracts! */ - i |= 0x0F0F0F; - break; - case 15: - case 16: - i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3); - i |= 0x070707; - break; - case 24: - break; - default: /* 18 bits... */ - i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2); - i |= 0x030303; - break; - } - - return i; -} - -#endif - -void WM_framebuffer_index_set(int index) -{ - const int col = index_to_framebuffer(index); - cpack(col); -} - -void WM_framebuffer_index_get(int index, int *r_col) -{ - const int col = index_to_framebuffer(index); - char *c_col = (char *)r_col; - c_col[0] = (col & 0xFF); /* red */ - c_col[1] = ((col >> 8) & 0xFF); /* green */ - c_col[2] = ((col >> 16) & 0xFF); /* blue */ - c_col[3] = 0xFF; /* alpha */ -} - - - -#define INDEX_FROM_BUF_8(col) (((col & 0xC00000) >> 18) + ((col & 0xC000) >> 12) + ((col & 0xC0) >> 6)) -#define INDEX_FROM_BUF_12(col) (((col & 0xF00000) >> 12) + ((col & 0xF000) >> 8) + ((col & 0xF0) >> 4)) -#define INDEX_FROM_BUF_15_16(col) (((col & 0xF80000) >> 9) + ((col & 0xF800) >> 6) + ((col & 0xF8) >> 3)) -#define INDEX_FROM_BUF_18(col) (((col & 0xFC0000) >> 6) + ((col & 0xFC00) >> 4) + ((col & 0xFC) >> 2)) -#define INDEX_FROM_BUF_24(col) (col & 0xFFFFFF) - -int WM_framebuffer_to_index(unsigned int col) -{ - if (col == 0) { - return 0; - } - - switch (GPU_color_depth()) { - case 8: return INDEX_FROM_BUF_8(col); - case 12: return INDEX_FROM_BUF_12(col); - case 15: - case 16: return INDEX_FROM_BUF_15_16(col); - case 24: return INDEX_FROM_BUF_24(col); - default: return INDEX_FROM_BUF_18(col); - } -} - -void WM_framebuffer_to_index_array(unsigned int *col, const unsigned int size) -{ -#define INDEX_BUF_ARRAY(INDEX_FROM_BUF_BITS) \ - for (i = size; i--; col++) { \ - if ((c = *col)) { \ - *col = INDEX_FROM_BUF_BITS(c); \ - } \ - } ((void)0) - - if (size > 0) { - unsigned int i, c; - - switch (GPU_color_depth()) { - case 8: - INDEX_BUF_ARRAY(INDEX_FROM_BUF_8); - break; - case 12: - INDEX_BUF_ARRAY(INDEX_FROM_BUF_12); - break; - case 15: - case 16: - INDEX_BUF_ARRAY(INDEX_FROM_BUF_15_16); - break; - case 24: - INDEX_BUF_ARRAY(INDEX_FROM_BUF_24); - break; - default: - INDEX_BUF_ARRAY(INDEX_FROM_BUF_18); - break; - } - } - -#undef INDEX_BUF_ARRAY -} - - /* ********** END MY WINDOW ************** */ diff --git a/source/blender/windowmanager/wm_subwindow.h b/source/blender/windowmanager/wm_subwindow.h index 2a8118a726b..cc9abf87514 100644 --- a/source/blender/windowmanager/wm_subwindow.h +++ b/source/blender/windowmanager/wm_subwindow.h @@ -48,7 +48,5 @@ void wm_subwindow_matrix_get(wmWindow *win, int swinid, float mat[4][4]); void wm_subwindow_rect_get(wmWindow *win, int swinid, struct rcti *r_rect); void wm_subwindow_rect_set(wmWindow *win, int swinid, const rcti *rect); -unsigned int index_to_framebuffer(int index); - #endif /* __WM_SUBWINDOW_H__ */ |