diff options
Diffstat (limited to 'source')
402 files changed, 12000 insertions, 3570 deletions
diff --git a/source/blender/blenfont/intern/blf_lang.c b/source/blender/blenfont/intern/blf_lang.c index 2852b8161c8..12d71827136 100644 --- a/source/blender/blenfont/intern/blf_lang.c +++ b/source/blender/blenfont/intern/blf_lang.c @@ -235,15 +235,11 @@ void BLF_lang_set(const char *str) else { short_locale_utf8 = BLI_sprintfN("%s.UTF-8", short_locale); } + bl_locale_set(short_locale_utf8); + MEM_freeN((void *)short_locale_utf8); } else { - short_locale_utf8 = short_locale; - } - - bl_locale_set(short_locale_utf8); - - if (short_locale[0]) { - MEM_freeN((void *)short_locale_utf8); + bl_locale_set(short_locale); } #else (void)str; diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 1ab5ec51de8..c8fa3a4e202 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -150,8 +150,10 @@ typedef DMDrawOption (*DMSetDrawOptions)(void *userData, int index); typedef DMDrawOption (*DMSetDrawOptionsTex)(struct MTFace *tface, const bool has_vcol, int matnr); typedef enum DMDrawFlag { - DM_DRAW_USE_COLORS = 1, - DM_DRAW_ALWAYS_SMOOTH = 2 + DM_DRAW_USE_COLORS = (1 << 0), + DM_DRAW_ALWAYS_SMOOTH = (1 << 1), + DM_DRAW_USE_ACTIVE_UV = (1 << 2), + DM_DRAW_USE_TEXPAINT_UV = (1 << 3), } DMDrawFlag; typedef enum DMForeachFlag { @@ -389,7 +391,7 @@ struct DerivedMesh { void (*drawFacesTex)(DerivedMesh *dm, DMSetDrawOptionsTex setDrawOptions, DMCompareDrawOptions compareDrawOptions, - void *userData); + void *userData, DMDrawFlag uvflag); /** Draw all faces with GLSL materials * o setMaterial is called for every different material nr @@ -423,7 +425,7 @@ struct DerivedMesh { void (*drawMappedFacesTex)(DerivedMesh *dm, DMSetDrawOptions setDrawOptions, DMCompareDrawOptions compareDrawOptions, - void *userData); + void *userData, DMDrawFlag uvflag); /** Draw mapped faces with GLSL materials * - setMaterial is called for every different material nr @@ -593,6 +595,8 @@ void DM_ensure_tessface(DerivedMesh *dm); void DM_update_tessface_data(DerivedMesh *dm); void DM_update_materials(DerivedMesh *dm, struct Object *ob); +struct MTFace *DM_paint_uvlayer_active_get(DerivedMesh *dm, int mat_nr); + /** interpolates vertex data from the vertices indexed by src_indices in the * source mesh using the given weights and stores the result in the vertex * indexed by dest_index in the dest mesh @@ -687,6 +691,9 @@ DerivedMesh *editbmesh_get_derived_cage(struct Scene *scene, struct Object *, DerivedMesh *editbmesh_get_derived_cage_and_final(struct Scene *scene, struct Object *, struct BMEditMesh *em, DerivedMesh **r_final, CustomDataMask dataMask); + +DerivedMesh *object_get_derived_final(struct Object *ob, const bool for_render); + float (*editbmesh_get_vertex_cos(struct BMEditMesh *em, int *r_numVerts))[3]; bool editbmesh_modifier_is_enabled(struct Scene *scene, struct ModifierData *md, DerivedMesh *dm); void makeDerivedMesh(struct Scene *scene, struct Object *ob, struct BMEditMesh *em, diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 19fa60f5827..50639ba7ed7 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -42,7 +42,7 @@ extern "C" { * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ #define BLENDER_VERSION 271 -#define BLENDER_SUBVERSION 2 +#define BLENDER_SUBVERSION 3 /* 262 was the last editmesh release but it has compatibility code for bmesh data */ #define BLENDER_MINVERSION 270 #define BLENDER_MINSUBVERSION 5 @@ -69,10 +69,12 @@ int BKE_read_file(struct bContext *C, const char *filepath, struct ReportList *r #define BKE_READ_FILE_OK 1 /* OK */ #define BKE_READ_FILE_OK_USERPREFS 2 /* OK, and with new user settings */ -int BKE_read_file_from_memory(struct bContext *C, const void *filebuf, - int filelength, struct ReportList *reports, int update_defaults); -int BKE_read_file_from_memfile(struct bContext *C, struct MemFile *memfile, - struct ReportList *reports); +bool BKE_read_file_from_memory( + struct bContext *C, const void *filebuf, + int filelength, struct ReportList *reports, bool update_defaults); +bool BKE_read_file_from_memfile( + struct bContext *C, struct MemFile *memfile, + struct ReportList *reports); int BKE_read_file_userdef(const char *filepath, struct ReportList *reports); int BKE_write_file_userdef(const char *filepath, struct ReportList *reports); diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index 104e80e815c..d48753590bb 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -81,7 +81,11 @@ unsigned int *BKE_brush_gen_texture_cache(struct Brush *br, int half_side, bool /* radial control */ struct ImBuf *BKE_brush_gen_radial_control_imbuf(struct Brush *br, bool secondary); -/* unified strength and size */ +/* unified strength size and color */ + +float *BKE_brush_color_get(const struct Scene *scene, struct Brush *brush); +float *BKE_brush_secondary_color_get(const struct Scene *scene, struct Brush *brush); +void BKE_brush_color_set(struct Scene *scene, struct Brush *brush, const float color[3]); int BKE_brush_size_get(const struct Scene *scene, struct Brush *brush); void BKE_brush_size_set(struct Scene *scene, struct Brush *brush, int value); diff --git a/source/blender/blenkernel/BKE_editmesh_bvh.h b/source/blender/blenkernel/BKE_editmesh_bvh.h index 355e817f621..168f700d132 100644 --- a/source/blender/blenkernel/BKE_editmesh_bvh.h +++ b/source/blender/blenkernel/BKE_editmesh_bvh.h @@ -43,9 +43,16 @@ struct Scene; typedef struct BMBVHTree BMBVHTree; -BMBVHTree *BKE_bmbvh_new_from_editmesh(struct BMEditMesh *em, int flag, const float (*cos_cage)[3], const bool cos_cage_free); -BMBVHTree *BKE_bmbvh_new(struct BMesh *bm, struct BMLoop *(*looptris)[3], int looptris_tot, int flag, - const float (*cos_cage)[3], const bool cos_cage_free); +BMBVHTree *BKE_bmbvh_new_from_editmesh( + struct BMEditMesh *em, int flag, + const float (*cos_cage)[3], const bool cos_cage_free); +BMBVHTree *BKE_bmbvh_new_ex( + struct BMesh *bm, struct BMLoop *(*looptris)[3], int looptris_tot, int flag, + const float (*cos_cage)[3], const bool cos_cage_free, + bool (*test_fn)(struct BMFace *, void *user_data), void *user_data); +BMBVHTree *BKE_bmbvh_new( + struct BMesh *bm, struct BMLoop *(*looptris)[3], int looptris_tot, int flag, + const float (*cos_cage)[3], const bool cos_cage_free); void BKE_bmbvh_free(BMBVHTree *tree); struct BVHTree *BKE_bmbvh_tree_get(BMBVHTree *tree); struct BMFace *BKE_bmbvh_ray_cast(BMBVHTree *tree, const float co[3], const float dir[3], const float radius, diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h index 3cf944fa236..0230eaf92bc 100644 --- a/source/blender/blenkernel/BKE_idprop.h +++ b/source/blender/blenkernel/BKE_idprop.h @@ -121,11 +121,27 @@ void IDP_ClearProperty(IDProperty *prop); void IDP_UnlinkProperty(struct IDProperty *prop); #define IDP_Int(prop) ((prop)->data.val) -#define IDP_Float(prop) (*(float *)&(prop)->data.val) -#define IDP_Double(prop) (*(double *)&(prop)->data.val) -#define IDP_String(prop) ((char *) (prop)->data.pointer) #define IDP_Array(prop) ((prop)->data.pointer) -#define IDP_IDPArray(prop) ((IDProperty *) (prop)->data.pointer) +/* C11 const correctness for casts */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) +# define IDP_Float(prop) _Generic((prop), \ + IDProperty *: (*(float *)&(prop)->data.val), \ + const IDProperty *: (*(const float *)&(prop)->data.val)) +# define IDP_Double(prop) _Generic((prop), \ + IDProperty *: (*(double *)&(prop)->data.val), \ + const IDProperty *: (*(const double *)&(prop)->data.val)) +# define IDP_String(prop) _Generic((prop), \ + IDProperty *: ((char *) (prop)->data.pointer), \ + const IDProperty *: ((const char *) (prop)->data.pointer)) +# define IDP_IDPArray(prop) _Generic((prop), \ + IDProperty *: ((IDProperty *) (prop)->data.pointer), \ + const IDProperty *: ((const IDProperty *) (prop)->data.pointer)) +#else +# define IDP_Float(prop) (*(float *)&(prop)->data.val) +# define IDP_Double(prop) (*(double *)&(prop)->data.val) +# define IDP_String(prop) ((char *) (prop)->data.pointer) +# define IDP_IDPArray(prop) ((IDProperty *) (prop)->data.pointer) +#endif #ifdef DEBUG /* for printout only */ diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 0372931dc49..1d37f9e64e1 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -71,7 +71,7 @@ void id_clear_lib_data(struct Main *bmain, struct ID *id); struct ListBase *which_libbase(struct Main *mainlib, short type); -#define MAX_LIBARRAY 41 +#define MAX_LIBARRAY 43 int set_listbasepointers(struct Main *main, struct ListBase **lb); void BKE_libblock_free(struct Main *bmain, void *idv); @@ -104,6 +104,7 @@ void test_idbutton(char *name); void BKE_library_make_local(struct Main *bmain, struct Library *lib, bool untagged_only); +struct ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void set_free_windowmanager_cb(void (*func)(struct bContext *, struct wmWindowManager *) ); diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index 82b03127237..ec654ea4b71 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -87,6 +87,8 @@ typedef struct Main { ListBase nodetree; ListBase brush; ListBase particle; + ListBase palettes; + ListBase paintcurves; ListBase wm; ListBase gpencil; ListBase movieclip; diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h index 89d310753fc..e69299a36bf 100644 --- a/source/blender/blenkernel/BKE_material.h +++ b/source/blender/blenkernel/BKE_material.h @@ -86,6 +86,10 @@ short find_material_index(struct Object *ob, struct Material *ma); bool object_add_material_slot(struct Object *ob); bool object_remove_material_slot(struct Object *ob); +void BKE_texpaint_slot_refresh_cache(struct Material *ma, bool use_nodes); +void BKE_texpaint_slots_refresh_object(struct Object *ob, bool use_nodes); +void BKE_texpaint_slots_clear(struct Material *ma); + /* rna api */ void BKE_material_resize_id(struct ID *id, short totcol, bool do_id_user); void BKE_material_append_id(struct ID *id, struct Material *ma); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index c81133a85fa..5e786cbfb53 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -585,6 +585,9 @@ void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpufu void node_type_internal_links(struct bNodeType *ntype, void (*update_internal_links)(struct bNodeTree *, struct bNode *)); void node_type_compatibility(struct bNodeType *ntype, short compatibility); +/* ************** GENERIC NODE FUNCTIONS *************** */ +bool BKE_node_is_connected_to_output(struct bNodeTree *ntree, struct bNode *node); + /* ************** COMMON NODES *************** */ #define NODE_UNDEFINED -2 /* node type is not registered */ @@ -891,6 +894,7 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria #define CMP_NODE_GLARE 301 #define CMP_NODE_TONEMAP 302 #define CMP_NODE_LENSDIST 303 +#define CMP_NODE_SUNBEAMS 304 #define CMP_NODE_COLORCORRECTION 312 #define CMP_NODE_MASK_BOX 313 diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 43813300850..0bdac6822f1 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -40,11 +40,15 @@ struct CurveMapping; struct MDisps; struct MeshElemMap; struct GridPaintMask; +struct Main; struct MFace; struct MultireModifierData; struct MVert; struct Object; struct Paint; +struct PaintCurve; +struct Palette; +struct PaletteColor; struct PBVH; struct Scene; struct Sculpt; @@ -52,6 +56,7 @@ struct StrokeCache; struct Tex; struct ImagePool; struct UnifiedPaintSettings; +struct wmOperator; enum OverlayFlags; @@ -91,6 +96,19 @@ OverlayControlFlags BKE_paint_get_overlay_flags(void); void BKE_paint_reset_overlay_invalid(OverlayControlFlags flag); void BKE_paint_set_overlay_override(enum OverlayFlags flag); +/* palettes */ +void BKE_palette_free(struct Palette *palette); +struct Palette *BKE_palette_add(struct Main *bmain, const char *name); +struct PaletteColor *BKE_palette_color_add(struct Palette *palette); +void BKE_palette_color_delete(struct Palette *palette); +bool BKE_palette_is_empty(const struct Palette *palette); +void BKE_palette_color_remove(struct Palette *palette, struct PaletteColor *color); +void BKE_palette_cleanup(struct Palette *palette); + +/* paint curves */ +struct PaintCurve *BKE_paint_curve_add(struct Main *bmain, const char *name); +void BKE_paint_curve_free(struct PaintCurve *pc); + void BKE_paint_init(struct Paint *p, const char col[3]); void BKE_paint_free(struct Paint *p); void BKE_paint_copy(struct Paint *src, struct Paint *tar); @@ -100,6 +118,9 @@ struct Paint *BKE_paint_get_active_from_context(const struct bContext *C); PaintMode BKE_paintmode_get_active_from_context(const struct bContext *C); struct Brush *BKE_paint_brush(struct Paint *paint); void BKE_paint_brush_set(struct Paint *paint, struct Brush *br); +struct Palette *BKE_paint_palette(struct Paint *paint); +void BKE_paint_palette_set(struct Paint *p, struct Palette *palette); +void BKE_paint_curve_set(struct Brush *br, struct PaintCurve *pc); /* testing face select mode * Texture paint could be removed since selected faces are not used @@ -117,7 +138,10 @@ bool paint_is_bmesh_face_hidden(struct BMFace *f); /* paint masks */ float paint_grid_paint_mask(const struct GridPaintMask *gpm, unsigned level, unsigned x, unsigned y); + +/* stroke related */ void paint_calculate_rake_rotation(struct UnifiedPaintSettings *ups, const float mouse_pos[2]); + /* Session data (mode-specific) */ typedef struct SculptSession { diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index a10a3f3f59f..452e23bdcb8 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -84,6 +84,7 @@ typedef struct SceneBaseIter { struct ListBase *duplilist; struct DupliObject *dupob; float omat[4][4]; + struct Object *dupli_refob; int phase; } SceneBaseIter; diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h index 59de43af907..070cd4a9cf0 100644 --- a/source/blender/blenkernel/BKE_shrinkwrap.h +++ b/source/blender/blenkernel/BKE_shrinkwrap.h @@ -31,52 +31,6 @@ * \ingroup bke */ -/* mesh util */ - -//TODO: move this somewhere else -#include "BKE_customdata.h" -struct DerivedMesh; -struct Object; -struct DerivedMesh *object_get_derived_final(struct Object *ob, bool for_render); - - -/* SpaceTransform stuff */ -/* - * TODO: move this somewhere else - * - * this structs encapsulates all needed data to convert between 2 coordinate spaces - * (where conversion can be represented by a matrix multiplication) - * - * This is used to reduce the number of arguments to pass to functions that need to perform - * this kind of operation and make it easier for the coder, as he/she doenst needs to recode - * the matrix calculation. - * - * A SpaceTransform is initialized using: - * SPACE_TRANSFORM_SETUP( &data, ob1, ob2 ) - * - * After that the following calls can be used: - * space_transform_apply (&data, co); //converts a coordinate in ob1 coords space to the corresponding ob2 coords - * space_transform_invert(&data, co); //converts a coordinate in ob2 coords space to the corresponding ob1 coords - * - * //Same Concept as space_transform_apply and space_transform_invert, but no is normalized after conversion - * space_transform_apply_normal (&data, &no); - * space_transform_invert_normal(&data, &no); - * - */ -struct Object; - -typedef struct SpaceTransform { - float local2target[4][4]; - float target2local[4][4]; - -} SpaceTransform; - -void space_transform_from_matrixs(struct SpaceTransform *data, float local[4][4], float target[4][4]); -void space_transform_apply(const struct SpaceTransform *data, float co[3]); -void space_transform_invert(const struct SpaceTransform *data, float co[3]); - -#define SPACE_TRANSFORM_SETUP(data, local, target) space_transform_from_matrixs(data, (local)->obmat, (target)->obmat) - /* Shrinkwrap stuff */ #include "BKE_bvhutils.h" @@ -100,6 +54,7 @@ struct MDeformVert; struct ShrinkwrapModifierData; struct MDeformVert; struct BVHTree; +struct SpaceTransform; typedef struct ShrinkwrapCalcData { @@ -115,7 +70,7 @@ typedef struct ShrinkwrapCalcData { int vgroup; //Vertex group num struct DerivedMesh *target; //mesh we are shrinking to - SpaceTransform local2target; //transform to move between local and target space + struct SpaceTransform local2target; //transform to move between local and target space float keepDist; //Distance to keep above target surface (units are in local space) @@ -136,7 +91,7 @@ void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Object */ bool BKE_shrinkwrap_project_normal( char options, const float vert[3], const float dir[3], - const SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit, + const struct SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata); /* diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index d9af6ac3454..46f04ff03b2 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -37,6 +37,7 @@ #include "DNA_cloth_types.h" #include "DNA_key_types.h" +#include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" @@ -501,11 +502,36 @@ void DM_update_materials(DerivedMesh *dm, Object *ob) dm->mat = MEM_callocN(totmat * sizeof(*dm->mat), "DerivedMesh.mat"); - for (i = 1; i < totmat; i++) { - dm->mat[i] = give_current_material(ob, i); + /* we leave last material as empty - rationale here is being able to index + * the materials by using the mf->mat_nr directly and leaving the last + * material as NULL in case no materials exist on mesh, so indexing will not fail */ + for (i = 0; i < totmat - 1; i++) { + dm->mat[i] = give_current_material(ob, i + 1); } } +MTFace *DM_paint_uvlayer_active_get(DerivedMesh *dm, int mat_nr) +{ + MTFace *tf_base; + + BLI_assert(mat_nr < dm->totmat); + + if (dm->mat[mat_nr] && dm->mat[mat_nr]->texpaintslot && + dm->mat[mat_nr]->texpaintslot[dm->mat[mat_nr]->paint_active_slot].uvname) + { + tf_base = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, + dm->mat[mat_nr]->texpaintslot[dm->mat[mat_nr]->paint_active_slot].uvname); + /* This can fail if we have changed the name in the UV layer list and have assigned the old name in the material + * texture slot.*/ + if (!tf_base) + tf_base = CustomData_get_layer(&dm->faceData, CD_MTFACE); + } + else { + tf_base = CustomData_get_layer(&dm->faceData, CD_MTFACE); + } + + return tf_base; +} void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob, CustomDataMask mask) { @@ -2474,6 +2500,28 @@ DerivedMesh *editbmesh_get_derived_base(Object *obedit, BMEditMesh *em) return getEditDerivedBMesh(em, obedit, NULL); } +/***/ + +/* get derived mesh from an object, using editbmesh if available. */ +DerivedMesh *object_get_derived_final(Object *ob, const bool for_render) +{ + Mesh *me = ob->data; + BMEditMesh *em = me->edit_btmesh; + + if (for_render) { + /* TODO(sergey): use proper derived render here in the future. */ + return ob->derivedFinal; + } + + if (em) { + DerivedMesh *dm = em->derivedFinal; + return dm; + } + + return ob->derivedFinal; +} + + /* UNUSED */ #if 0 @@ -3091,7 +3139,7 @@ static void navmesh_drawColored(DerivedMesh *dm) static void navmesh_DM_drawFacesTex(DerivedMesh *dm, DMSetDrawOptionsTex setDrawOptions, DMCompareDrawOptions compareDrawOptions, - void *userData) + void *userData, DMDrawFlag UNUSED(flag)) { (void) setDrawOptions; (void) compareDrawOptions; diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 8f1382dacc3..c6dcca576fb 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -315,7 +315,7 @@ bActionGroup *action_groups_add_new(bAction *act, const char name[]) void action_groups_add_channel(bAction *act, bActionGroup *agrp, FCurve *fcurve) { /* sanity checks */ - if (ELEM3(NULL, act, agrp, fcurve)) + if (ELEM(NULL, act, agrp, fcurve)) return; /* if no channels anywhere, just add to two lists at the same time */ @@ -417,7 +417,7 @@ void action_groups_remove_channel(bAction *act, FCurve *fcu) bActionGroup *BKE_action_group_find_name(bAction *act, const char name[]) { /* sanity checks */ - if (ELEM3(NULL, act, act->groups.first, name) || (name[0] == 0)) + if (ELEM(NULL, act, act->groups.first, name) || (name[0] == 0)) return NULL; /* do string comparisons */ @@ -526,7 +526,7 @@ bPoseChannel *BKE_pose_channel_active(Object *ob) bArmature *arm = (ob) ? ob->data : NULL; bPoseChannel *pchan; - if (ELEM3(NULL, ob, ob->pose, arm)) { + if (ELEM(NULL, ob, ob->pose, arm)) { return NULL; } diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 995b2ac5321..5ee82bb5842 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -405,7 +405,7 @@ void action_move_fcurves_by_basepath(bAction *srcAct, bAction *dstAct, const cha FCurve *fcu, *fcn = NULL; /* sanity checks */ - if (ELEM3(NULL, srcAct, dstAct, basepath)) { + if (ELEM(NULL, srcAct, dstAct, basepath)) { if (G.debug & G_DEBUG) { printf("ERROR: action_partition_fcurves_by_basepath(%p, %p, %p) has insufficient info to work with\n", (void *)srcAct, (void *)dstAct, (void *)basepath); @@ -1062,7 +1062,7 @@ KS_Path *BKE_keyingset_find_path(KeyingSet *ks, ID *id, const char group_name[], KS_Path *ksp; /* sanity checks */ - if (ELEM3(NULL, ks, rna_path, id)) + if (ELEM(NULL, ks, rna_path, id)) return NULL; /* loop over paths in the current KeyingSet, finding the first one where all settings match @@ -2338,6 +2338,17 @@ static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData /* 3. free temporary evaluation data that's not used elsewhere */ BLI_freelistN(&estrips); + + /* Tag ID as updated so render engines will recognize changes in data + * which is animated but doesn't have actions. + */ + if (ptr->id.data != NULL) { + ID *id = ptr->id.data; + if (!(id->flag & LIB_ANIM_NO_RECALC)) { + id->flag |= LIB_ID_RECALC; + DAG_id_type_tag(G.main, GS(id->name)); + } + } } /* NLA Evaluation function (mostly for use through do_animdata) @@ -2392,7 +2403,7 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt) /* Overview of how this system works: * 1) Depsgraph sorts data as necessary, so that data is in an order that means - * that all dependencies are resolved before dependants. + * that all dependencies are resolved before dependents. * 2) All normal animation is evaluated, so that drivers have some basis values to * work with * a. NLA stacks are done first, as the Active Actions act as 'tweaking' tracks diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 95f8426872d..16b5574709e 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -574,7 +574,7 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB if (do_scale) { /* correct for scaling when this matrix is used in scaled space */ - mul_serie_m4(result_array[a].mat, iscalemat, result_array[a].mat, scalemat, NULL, NULL, NULL, NULL, NULL); + mul_m4_series(result_array[a].mat, iscalemat, result_array[a].mat, scalemat); } } } @@ -622,8 +622,7 @@ static void pchan_b_bone_defmats(bPoseChannel *pchan, bPoseChanDeform *pdef_info invert_m4_m4(tmat, b_bone_rest[a].mat); - mul_serie_m4(b_bone_mats[a + 1].mat, pchan->chan_mat, bone->arm_mat, b_bone[a].mat, tmat, b_bone_mats[0].mat, - NULL, NULL, NULL); + mul_m4_series(b_bone_mats[a + 1].mat, pchan->chan_mat, bone->arm_mat, b_bone[a].mat, tmat, b_bone_mats[0].mat); if (use_quaternion) mat4_to_dquat(&b_bone_dual_quats[a], bone->arm_mat, b_bone_mats[a + 1].mat); @@ -1042,7 +1041,7 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float if (!use_quaternion) /* quaternion already is scale corrected */ mul_m3_fl(smat, armature_weight / contrib); - mul_serie_m3(defMats[i], tmpmat, pre, smat, post, NULL, NULL, NULL, NULL); + mul_m3_series(defMats[i], post, smat, pre, tmpmat); } } @@ -1881,7 +1880,7 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos */ /* only happens on reload file, but violates depsgraph still... fix! */ - if (ELEM3(NULL, ikData->tar->curve_cache, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) { + if (ELEM(NULL, ikData->tar->curve_cache, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) { BKE_displist_make_curveTypes(scene, ikData->tar, 0); /* path building may fail in EditMode after removing verts [#33268]*/ diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 9be9db77d39..fff8265a158 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -170,7 +170,7 @@ static void clear_global(void) static bool clean_paths_visit_cb(void *UNUSED(userdata), char *path_dst, const char *path_src) { strcpy(path_dst, path_src); - BLI_clean(path_dst); + BLI_path_native_slash(path_dst); return !STREQ(path_dst, path_src); } @@ -182,7 +182,7 @@ static void clean_paths(Main *main) BKE_bpath_traverse_main(main, clean_paths_visit_cb, BKE_BPATH_TRAVERSE_SKIP_MULTIFILE, NULL); for (scene = main->scene.first; scene; scene = scene->id.next) { - BLI_clean(scene->r.pic); + BLI_path_native_slash(scene->r.pic); } } @@ -479,7 +479,9 @@ int BKE_read_file(bContext *C, const char *filepath, ReportList *reports) return (bfd ? retval : BKE_READ_FILE_FAIL); } -int BKE_read_file_from_memory(bContext *C, const void *filebuf, int filelength, ReportList *reports, int update_defaults) +bool BKE_read_file_from_memory( + bContext *C, const void *filebuf, int filelength, + ReportList *reports, bool update_defaults) { BlendFileData *bfd; @@ -496,7 +498,9 @@ int BKE_read_file_from_memory(bContext *C, const void *filebuf, int filelength, } /* memfile is the undo buffer */ -int BKE_read_file_from_memfile(bContext *C, MemFile *memfile, ReportList *reports) +bool BKE_read_file_from_memfile( + bContext *C, MemFile *memfile, + ReportList *reports) { BlendFileData *bfd; diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index dc2d0924bba..3cd26dacebd 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -107,7 +107,7 @@ typedef struct BPathRemap_Data { int count_failed; } BPathRemap_Data; -static bool makeFilesRelative_visit_cb(void *userdata, char *path_dst, const char *path_src) +static bool bpath_relative_convert_visit_cb(void *userdata, char *path_dst, const char *path_src) { BPathRemap_Data *data = (BPathRemap_Data *)userdata; @@ -133,6 +133,7 @@ static bool makeFilesRelative_visit_cb(void *userdata, char *path_dst, const cha void BKE_bpath_relative_convert(Main *bmain, const char *basedir, ReportList *reports) { BPathRemap_Data data = {NULL}; + const int flag = BKE_BPATH_TRAVERSE_SKIP_LIBRARY; if (basedir[0] == '\0') { printf("%s: basedir='', this is a bug\n", __func__); @@ -142,14 +143,14 @@ void BKE_bpath_relative_convert(Main *bmain, const char *basedir, ReportList *re data.basedir = basedir; data.reports = reports; - BKE_bpath_traverse_main(bmain, makeFilesRelative_visit_cb, 0, (void *)&data); + BKE_bpath_traverse_main(bmain, bpath_relative_convert_visit_cb, flag, (void *)&data); BKE_reportf(reports, data.count_failed ? RPT_WARNING : RPT_INFO, "Total files %d | Changed %d | Failed %d", data.count_tot, data.count_changed, data.count_failed); } -static bool makeFilesAbsolute_visit_cb(void *userdata, char *path_dst, const char *path_src) +static bool bpath_absolute_convert_visit_cb(void *userdata, char *path_dst, const char *path_src) { BPathRemap_Data *data = (BPathRemap_Data *)userdata; @@ -176,6 +177,7 @@ static bool makeFilesAbsolute_visit_cb(void *userdata, char *path_dst, const cha void BKE_bpath_absolute_convert(Main *bmain, const char *basedir, ReportList *reports) { BPathRemap_Data data = {NULL}; + const int flag = BKE_BPATH_TRAVERSE_SKIP_LIBRARY; if (basedir[0] == '\0') { printf("%s: basedir='', this is a bug\n", __func__); @@ -185,7 +187,7 @@ void BKE_bpath_absolute_convert(Main *bmain, const char *basedir, ReportList *re data.basedir = basedir; data.reports = reports; - BKE_bpath_traverse_main(bmain, makeFilesAbsolute_visit_cb, 0, (void *)&data); + BKE_bpath_traverse_main(bmain, bpath_absolute_convert_visit_cb, flag, (void *)&data); BKE_reportf(reports, data.count_failed ? RPT_WARNING : RPT_INFO, "Total files %d | Changed %d | Failed %d", @@ -422,7 +424,7 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int Image *ima; ima = (Image *)id; if (ima->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) { - if (ELEM3(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) { + if (ELEM(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) { if (rewrite_path_fixed(ima->name, visit_cb, absbase, bpath_user_data)) { if (!ima->packedfile) { BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD); diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 967e89e0dd1..cfdb1aa7a96 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -83,6 +83,7 @@ static void brush_defaults(Brush *brush) brush->plane_trim = 0.5f; brush->clone.alpha = 0.5f; brush->normal_weight = 0.0f; + brush->fill_threshold = 0.2f; brush->flag |= BRUSH_ALPHA_PRESSURE; /* BRUSH PAINT TOOL SETTINGS */ @@ -90,6 +91,8 @@ static void brush_defaults(Brush *brush) brush->rgb[1] = 1.0f; brush->rgb[2] = 1.0f; + zero_v3(brush->secondary_rgb); + /* BRUSH STROKE SETTINGS */ brush->flag |= (BRUSH_SPACE | BRUSH_SPACE_ATTEN); brush->spacing = 10; /* how far each brush dot should be spaced as a percentage of brush diameter */ @@ -161,6 +164,9 @@ Brush *BKE_brush_copy(Brush *brush) if (brush->mask_mtex.tex) id_us_plus((ID *)brush->mask_mtex.tex); + if (brush->paint_curve) + id_us_plus((ID *)brush->paint_curve); + if (brush->icon_imbuf) brushn->icon_imbuf = IMB_dupImBuf(brush->icon_imbuf); @@ -180,11 +186,9 @@ Brush *BKE_brush_copy(Brush *brush) /* not brush itself */ void BKE_brush_free(Brush *brush) { - if (brush->mtex.tex) - brush->mtex.tex->id.us--; - - if (brush->mask_mtex.tex) - brush->mask_mtex.tex->id.us--; + id_us_min((ID *)brush->mtex.tex); + id_us_min((ID *)brush->mask_mtex.tex); + id_us_min((ID *)brush->paint_curve); if (brush->icon_imbuf) IMB_freeImBuf(brush->icon_imbuf); @@ -192,6 +196,9 @@ void BKE_brush_free(Brush *brush) BKE_previewimg_free(&(brush->preview)); curvemapping_free(brush->curve); + + if (brush->gradient) + MEM_freeN(brush->gradient); } static void extern_local_brush(Brush *brush) @@ -199,6 +206,7 @@ static void extern_local_brush(Brush *brush) id_lib_extern((ID *)brush->mtex.tex); id_lib_extern((ID *)brush->mask_mtex.tex); id_lib_extern((ID *)brush->clone.image); + id_lib_extern((ID *)brush->paint_curve); } void BKE_brush_make_local(Brush *brush) @@ -742,10 +750,23 @@ float BKE_brush_sample_masktex(const Scene *scene, Brush *br, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool); } + CLAMP(intensity, 0.0f, 1.0f); + + switch (br->mask_pressure) { + case BRUSH_MASK_PRESSURE_CUTOFF: + intensity = ((1.0f - intensity) < ups->size_pressure_value) ? 1.0f : 0.0f; + break; + case BRUSH_MASK_PRESSURE_RAMP: + intensity = ups->size_pressure_value + intensity * (1.0f - ups->size_pressure_value); + break; + default: + break; + } + return intensity; } -/* Unified Size and Strength */ +/* Unified Size / Strength / Color */ /* XXX: be careful about setting size and unprojected radius * because they depend on one another @@ -760,6 +781,29 @@ float BKE_brush_sample_masktex(const Scene *scene, Brush *br, * In any case, a better solution is needed to prevent * inconsistency. */ + +float *BKE_brush_color_get(const struct Scene *scene, struct Brush *brush) +{ + UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; + return (ups->flag & UNIFIED_PAINT_COLOR) ? ups->rgb : brush->rgb; +} + +float *BKE_brush_secondary_color_get(const struct Scene *scene, struct Brush *brush) +{ + UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; + return (ups->flag & UNIFIED_PAINT_COLOR) ? ups->secondary_rgb : brush->secondary_rgb; +} + +void BKE_brush_color_set(struct Scene *scene, struct Brush *brush, const float color[3]) +{ + UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; + + if (ups->flag & UNIFIED_PAINT_COLOR) + copy_v3_v3(ups->rgb, color); + else + copy_v3_v3(brush->rgb, color); +} + void BKE_brush_size_set(Scene *scene, Brush *brush, int size) { UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 3f8edbcf1be..ca4a4b3196c 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -51,6 +51,7 @@ #include "BKE_editmesh.h" #include "BKE_curve.h" +#include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" @@ -669,7 +670,7 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, DMSetDrawOptionsTex drawParams, DMSetDrawOptions drawParamsMapped, DMCompareDrawOptions compareDrawOptions, - void *userData) + void *userData, DMDrawFlag uvflag) { CDDerivedMesh *cddm = (CDDerivedMesh *) dm; MVert *mv = cddm->mvert; @@ -680,6 +681,7 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, MCol *mcol; int i, orig; int colType, startFace = 0; + bool use_tface = (uvflag & DM_DRAW_USE_ACTIVE_UV) != 0; /* double lookup */ const int *index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX); @@ -718,14 +720,35 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, cdDM_update_normals_from_pbvh(dm); if (GPU_buffer_legacy(dm)) { + int mat_nr_cache = -1; + MTFace *tf_base = DM_get_tessface_data_layer(dm, CD_MTFACE); + MTFace *tf_stencil_base = NULL; + MTFace *tf_stencil = NULL; + + if (uvflag & DM_DRAW_USE_TEXPAINT_UV) { + int stencil = CustomData_get_stencil_layer(&dm->faceData, CD_MTFACE); + tf_stencil_base = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, stencil); + } + DEBUG_VBO("Using legacy code. cdDM_drawFacesTex_common\n"); for (i = 0; i < dm->numTessFaceData; i++, mf++) { MVert *mvert; DMDrawOption draw_option; unsigned char *cp = NULL; + if (uvflag & DM_DRAW_USE_TEXPAINT_UV) { + if (mf->mat_nr != mat_nr_cache) { + tf_base = DM_paint_uvlayer_active_get(dm, mf->mat_nr); + + mat_nr_cache = mf->mat_nr; + } + } + + tf = tf_base ? tf_base + i : NULL; + tf_stencil = tf_stencil_base ? tf_stencil_base + i : NULL; + if (drawParams) { - draw_option = drawParams(tf ? &tf[i] : NULL, (mcol != NULL), mf->mat_nr); + draw_option = drawParams(use_tface ? tf : NULL, (mcol != NULL), mf->mat_nr); } else { if (index_mf_to_mpoly) { @@ -778,21 +801,24 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, } glBegin(mf->v4 ? GL_QUADS : GL_TRIANGLES); - if (tf) glTexCoord2fv(tf[i].uv[0]); + if (tf) glTexCoord2fv(tf->uv[0]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf->uv[0]); if (cp) glColor3ub(cp[3], cp[2], cp[1]); mvert = &mv[mf->v1]; if (lnors) glNormal3sv((const GLshort *)lnors[0][0]); else if (mf->flag & ME_SMOOTH) glNormal3sv(mvert->no); glVertex3fv(mvert->co); - if (tf) glTexCoord2fv(tf[i].uv[1]); + if (tf) glTexCoord2fv(tf->uv[1]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf->uv[1]); if (cp) glColor3ub(cp[7], cp[6], cp[5]); mvert = &mv[mf->v2]; if (lnors) glNormal3sv((const GLshort *)lnors[0][1]); else if (mf->flag & ME_SMOOTH) glNormal3sv(mvert->no); glVertex3fv(mvert->co); - if (tf) glTexCoord2fv(tf[i].uv[2]); + if (tf) glTexCoord2fv(tf->uv[2]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf->uv[2]); if (cp) glColor3ub(cp[11], cp[10], cp[9]); mvert = &mv[mf->v3]; if (lnors) glNormal3sv((const GLshort *)lnors[0][2]); @@ -800,7 +826,8 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, glVertex3fv(mvert->co); if (mf->v4) { - if (tf) glTexCoord2fv(tf[i].uv[3]); + if (tf) glTexCoord2fv(tf->uv[3]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf->uv[3]); if (cp) glColor3ub(cp[15], cp[14], cp[13]); mvert = &mv[mf->v4]; if (lnors) glNormal3sv((const GLshort *)lnors[0][3]); @@ -819,7 +846,10 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, else { /* use OpenGL VBOs or Vertex Arrays instead for better, faster rendering */ GPU_vertex_setup(dm); GPU_normal_setup(dm); - GPU_uv_setup(dm); + if (uvflag & DM_DRAW_USE_TEXPAINT_UV) + GPU_texpaint_uv_setup(dm); + else + GPU_uv_setup(dm); if (mcol) { GPU_color_setup(dm, colType); } @@ -839,7 +869,7 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, next_actualFace = dm->drawObject->triangle_to_mface[i + 1]; if (drawParams) { - draw_option = drawParams(tf ? &tf[actualFace] : NULL, (mcol != NULL), mf[actualFace].mat_nr); + draw_option = drawParams(use_tface && tf ? &tf[actualFace] : NULL, (mcol != NULL), mf[actualFace].mat_nr); } else { if (index_mf_to_mpoly) { @@ -895,9 +925,9 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, static void cdDM_drawFacesTex(DerivedMesh *dm, DMSetDrawOptionsTex setDrawOptions, DMCompareDrawOptions compareDrawOptions, - void *userData) + void *userData, DMDrawFlag uvflag) { - cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData); + cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData, uvflag); } static void cdDM_drawMappedFaces(DerivedMesh *dm, @@ -1123,9 +1153,9 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, static void cdDM_drawMappedFacesTex(DerivedMesh *dm, DMSetDrawOptions setDrawOptions, DMCompareDrawOptions compareDrawOptions, - void *userData) + void *userData, DMDrawFlag flag) { - cdDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData); + cdDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData, flag); } static void cddm_draw_attrib_vertex(DMVertexAttribs *attribs, MVert *mvert, int a, int index, int vert, diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index b27655c8c19..d80529ee780 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -3375,7 +3375,7 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra unit_m4(ct->matrix); if (target != NULL) { - space_transform_from_matrixs(&transform, cob->matrix, ct->tar->obmat); + BLI_space_transform_from_matrices(&transform, cob->matrix, ct->tar->obmat); switch (scon->shrinkType) { case MOD_SHRINKWRAP_NEAREST_SURFACE: @@ -3397,7 +3397,7 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra break; } - space_transform_apply(&transform, co); + BLI_space_transform_apply(&transform, co); BLI_bvhtree_find_nearest(treeData.tree, co, &nearest, treeData.nearest_callback, &treeData); @@ -3405,7 +3405,7 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra if (dist != 0.0f) { interp_v3_v3v3(co, co, nearest.co, (dist - scon->dist) / dist); /* linear interpolation */ } - space_transform_invert(&transform, co); + BLI_space_transform_invert(&transform, co); break; } case MOD_SHRINKWRAP_PROJECT: @@ -3909,7 +3909,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, framenr, imat); invert_m4(imat); - mul_serie_m4(cob->matrix, obmat, mat, imat, NULL, NULL, NULL, NULL, NULL); + mul_m4_series(cob->matrix, obmat, mat, imat); translate_m4(cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]); } else { @@ -3943,19 +3943,31 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase if (len > FLT_EPSILON) { CameraParams params; + int width, height; float pos[2], rmat[4][4]; + BKE_movieclip_get_size(clip, NULL, &width, &height); + marker = BKE_tracking_marker_get(track, framenr); add_v2_v2v2(pos, marker->pos, track->offset); + if (data->flag & FOLLOWTRACK_USE_UNDISTORTION) { + /* Undistortion need to happen in pixel space. */ + pos[0] *= width; + pos[1] *= height; + + BKE_tracking_undistort_v2(tracking, pos, pos); + + /* Normalize pixel coordinates back. */ + pos[0] /= width; + pos[1] /= height; + } + /* aspect correction */ if (data->frame_method != FOLLOWTRACK_FRAME_STRETCH) { - int width, height; float w_src, h_src, w_dst, h_dst, asp_src, asp_dst; - BKE_movieclip_get_size(clip, NULL, &width, &height); - /* apply clip display aspect */ w_src = width * clip->aspx; h_src = height * clip->aspy; @@ -4187,7 +4199,7 @@ static void objectsolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase invert_m4_m4(imat, mat); - mul_serie_m4(cob->matrix, cammat, imat, camimat, parmat, obmat, NULL, NULL, NULL); + mul_m4_series(cob->matrix, cammat, imat, camimat, parmat, obmat); } } } diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index d072088ac8e..f6da41252a7 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -559,7 +559,7 @@ void defgroup_unique_name(bDeformGroup *dg, Object *ob) static bool is_char_sep(const char c) { - return ELEM4(c, '.', ' ', '-', '_'); + return ELEM(c, '.', ' ', '-', '_'); } /* based on BLI_split_dirfile() / os.path.splitext(), "a.b.c" -> ("a.b", ".c") */ diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 95e608a5d4d..5e01f9add1e 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -59,6 +59,7 @@ #include "DNA_movieclip_types.h" #include "DNA_mask_types.h" +#include "BKE_anim.h" #include "BKE_animsys.h" #include "BKE_action.h" #include "BKE_effect.h" @@ -524,7 +525,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O if (ct->tar->type == OB_MESH) node3->customdata_mask |= CD_MASK_MDEFORMVERT; } - else if (ELEM3(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_SPLINEIK)) + else if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_SPLINEIK)) dag_add_relation(dag, node3, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, cti->name); else dag_add_relation(dag, node3, node, DAG_RL_OB_DATA, cti->name); @@ -688,6 +689,29 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Curve Taper"); } if (ob->type == OB_FONT) { + /* Really rather dirty hack. needs to support font family to work + * reliably on render export. + * + * This totally mimics behavior of regular verts duplication with + * parenting. The only tricky thing here is to get list of objects + * used for the custom "font". + * + * This shouldn't harm so much because this code only runs on DAG + * rebuild and this feature is not that commonly used. + * + * - sergey - + */ + if (cu->family[0] != '\n') { + ListBase *duplilist; + DupliObject *dob; + duplilist = object_duplilist(G.main->eval_ctx, scene, ob); + for (dob = duplilist->first; dob; dob = dob->next) { + node2 = dag_get_node(dag, dob->ob); + dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Object Font"); + } + free_object_duplilist(duplilist); + } + if (cu->textoncurve) { node2 = dag_get_node(dag, cu->textoncurve); /* Text on curve requires path to be evaluated for the target curve. */ @@ -803,7 +827,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O continue; /* special case for camera tracking -- it doesn't use targets to define relations */ - if (ELEM3(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) { + if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) { int depends_on_camera = 0; if (cti->type == CONSTRAINT_TYPE_FOLLOWTRACK) { @@ -843,7 +867,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO)) dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, cti->name); else { - if (ELEM3(obt->type, OB_ARMATURE, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) { + if (ELEM(obt->type, OB_ARMATURE, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) { dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, cti->name); if (obt->type == OB_MESH) node2->customdata_mask |= CD_MASK_MDEFORMVERT; @@ -1386,7 +1410,7 @@ static bool check_object_needs_evaluation(Object *object) if (object->type == OB_MESH) { return object->derivedFinal == NULL; } - else if (ELEM5(object->type, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { + else if (ELEM(object->type, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { return object->curve_cache == NULL; } @@ -1400,7 +1424,7 @@ static bool check_object_tagged_for_update(Object *object) return true; } - if (ELEM6(object->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { + if (ELEM(object->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { ID *data_id = object->data; return (data_id->flag & (LIB_ID_RECALC_DATA | LIB_ID_RECALC)) != 0; } @@ -1983,7 +2007,7 @@ static void dag_object_time_update_flags(Main *bmain, Scene *scene, Object *ob) if (cti) { /* special case for camera tracking -- it doesn't use targets to define relations */ - if (ELEM3(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) { + if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) { ob->recalc |= OB_RECALC_OB; } else if (cti->get_constraint_targets) { @@ -2272,7 +2296,7 @@ static void dag_group_on_visible_update(Group *group) group->id.flag |= LIB_DOIT; for (go = group->gobject.first; go; go = go->next) { - if (ELEM6(go->ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { + if (ELEM(go->ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { go->ob->recalc |= OB_RECALC_DATA; go->ob->id.flag |= LIB_DOIT; lib_id_recalc_tag(G.main, &go->ob->id); @@ -2319,7 +2343,7 @@ void DAG_on_visible_update(Main *bmain, const bool do_time) oblay = (node) ? node->lay : ob->lay; if ((oblay & lay) & ~scene->lay_updated) { - if (ELEM6(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) { ob->recalc |= OB_RECALC_DATA; lib_id_recalc_tag(bmain, &ob->id); } @@ -2472,6 +2496,17 @@ static void dag_id_flush_update(Main *bmain, Scene *sce, ID *id) BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH); } + if (ELEM(idtype, ID_MA, ID_TE)) { + const bool new_shading_nodes = BKE_scene_use_new_shading_nodes(sce); + for (obt = bmain->object.first; obt; obt = obt->id.next) { + if (obt->mode & OB_MODE_TEXTURE_PAINT) { + obt->recalc |= OB_RECALC_DATA; + BKE_texpaint_slots_refresh_object(obt, new_shading_nodes); + lib_id_recalc_data_tag(bmain, &obt->id); + } + } + } + if (idtype == ID_MC) { MovieClip *clip = (MovieClip *) id; @@ -2481,7 +2516,7 @@ static void dag_id_flush_update(Main *bmain, Scene *sce, ID *id) bConstraint *con; for (con = obt->constraints.first; con; con = con->next) { bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - if (ELEM3(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, + if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) { obt->recalc |= OB_RECALC_OB; @@ -2759,7 +2794,7 @@ void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag) if (ob->type == OB_FONT) { Curve *cu = ob->data; - if (ELEM4((struct VFont *)id, cu->vfont, cu->vfontb, cu->vfonti, cu->vfontbi)) { + if (ELEM((struct VFont *)id, cu->vfont, cu->vfontb, cu->vfonti, cu->vfontbi)) { ob->recalc |= (flag & OB_RECALC_ALL); } } diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index d494115821a..43c13f1c896 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -122,7 +122,7 @@ bool BKE_displist_has_faces(ListBase *lb) DispList *dl; for (dl = lb->first; dl; dl = dl->next) { - if (ELEM3(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) { + if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) { return true; } } @@ -653,8 +653,8 @@ static void curve_to_filledpoly(Curve *cu, ListBase *UNUSED(nurb), ListBase *dis bevels_to_filledpoly(cu, dispbase); } else { - /* TODO, investigate passing zup instead of NULL */ - BKE_displist_fill(dispbase, dispbase, NULL, false); + const float z_up[3] = {0.0f, 0.0f, 1.0f}; + BKE_displist_fill(dispbase, dispbase, z_up, false); } } @@ -766,7 +766,7 @@ static ModifierData *curve_get_tessellate_point(Scene *scene, Object *ob, if (mti->type == eModifierTypeType_Constructive) return pretessellatePoint; - if (ELEM3(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) { + if (ELEM(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) { pretessellatePoint = md; /* this modifiers are moving point of tessellation automatically @@ -1566,7 +1566,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba Curve *cu = ob->data; /* we do allow duplis... this is only displist on curve level */ - if (!ELEM3(ob->type, OB_SURF, OB_CURVE, OB_FONT)) return; + if (!ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) return; if (ob->type == OB_SURF) { BKE_displist_make_surf(scene, ob, dispbase, r_dm_final, for_render, for_orco, use_render_resolution); @@ -1809,7 +1809,7 @@ void BKE_displist_make_curveTypes(Scene *scene, Object *ob, const bool for_orco) /* The same check for duplis as in do_makeDispListCurveTypes. * Happens when curve used for constraint/bevel was converted to mesh. * check there is still needed for render displist and orco displists. */ - if (!ELEM3(ob->type, OB_SURF, OB_CURVE, OB_FONT)) + if (!ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) return; BKE_object_free_derived_caches(ob); @@ -1894,7 +1894,7 @@ void BKE_displist_minmax(ListBase *dispbase, float min[3], float max[3]) /* this is confusing, there's also min_max_object, appplying the obmat... */ static void boundbox_displist_object(Object *ob) { - if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { + if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { /* Curve's BB is already calculated as a part of modifier stack, * here we only calculate object BB based on final display list. */ diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index 3a11b3431ae..40a4bc22ce9 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -911,7 +911,7 @@ static void emDM_drawFacesTex_common(DerivedMesh *dm, static void emDM_drawFacesTex(DerivedMesh *dm, DMSetDrawOptionsTex setDrawOptions, DMCompareDrawOptions compareDrawOptions, - void *userData) + void *userData, DMDrawFlag UNUSED(flag)) { emDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData); } @@ -919,7 +919,7 @@ static void emDM_drawFacesTex(DerivedMesh *dm, static void emDM_drawMappedFacesTex(DerivedMesh *dm, DMSetDrawOptions setDrawOptions, DMCompareDrawOptions compareDrawOptions, - void *userData) + void *userData, DMDrawFlag UNUSED(flag)) { emDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData); } diff --git a/source/blender/blenkernel/intern/editmesh_bvh.c b/source/blender/blenkernel/intern/editmesh_bvh.c index 76ea340ecbd..442ab26ffc8 100644 --- a/source/blender/blenkernel/intern/editmesh_bvh.c +++ b/source/blender/blenkernel/intern/editmesh_bvh.c @@ -53,13 +53,17 @@ struct BMBVHTree { int flag; }; -BMBVHTree *BKE_bmbvh_new_from_editmesh(BMEditMesh *em, int flag, const float (*cos_cage)[3], const bool cos_cage_free) +BMBVHTree *BKE_bmbvh_new_from_editmesh( + BMEditMesh *em, int flag, + const float (*cos_cage)[3], const bool cos_cage_free) { return BKE_bmbvh_new(em->bm, em->looptris, em->tottri, flag, cos_cage, cos_cage_free); } -BMBVHTree *BKE_bmbvh_new(BMesh *bm, BMLoop *(*looptris)[3], int looptris_tot, int flag, const float (*cos_cage)[3], -const bool cos_cage_free) +BMBVHTree *BKE_bmbvh_new_ex( + BMesh *bm, BMLoop *(*looptris)[3], int looptris_tot, int flag, + const float (*cos_cage)[3], const bool cos_cage_free, + bool (*test_fn)(BMFace *, void *user_data), void *user_data) { /* could become argument */ const float epsilon = FLT_EPSILON * 2.0f; @@ -69,6 +73,10 @@ const bool cos_cage_free) int i; int tottri; + /* avoid testing every tri */ + BMFace *f_test, *f_test_prev; + bool test_fn_ret; + /* BKE_editmesh_tessface_calc() must be called already */ BLI_assert(looptris_tot != 0 || bm->totface == 0); @@ -83,18 +91,22 @@ const bool cos_cage_free) bmtree->cos_cage_free = cos_cage_free; bmtree->flag = flag; - if (flag & (BMBVH_RESPECT_SELECT)) { + if (test_fn) { + /* callback must do... */ + BLI_assert(!(flag & (BMBVH_RESPECT_SELECT | BMBVH_RESPECT_HIDDEN))); + + f_test_prev = NULL; + test_fn_ret = false; + tottri = 0; for (i = 0; i < looptris_tot; i++) { - if (BM_elem_flag_test(looptris[i][0]->f, BM_ELEM_SELECT)) { - tottri++; + f_test = looptris[i][0]->f; + if (f_test != f_test_prev) { + test_fn_ret = test_fn(f_test, user_data); + f_test_prev = f_test; } - } - } - else if (flag & (BMBVH_RESPECT_HIDDEN)) { - tottri = 0; - for (i = 0; i < looptris_tot; i++) { - if (!BM_elem_flag_test(looptris[i][0]->f, BM_ELEM_HIDDEN)) { + + if (test_fn_ret) { tottri++; } } @@ -105,17 +117,19 @@ const bool cos_cage_free) bmtree->tree = BLI_bvhtree_new(tottri, epsilon, 8, 8); - for (i = 0; i < looptris_tot; i++) { + f_test_prev = NULL; + test_fn_ret = false; - if (flag & BMBVH_RESPECT_SELECT) { + for (i = 0; i < looptris_tot; i++) { + if (test_fn) { /* note, the arrays wont align now! take care */ - if (!BM_elem_flag_test(looptris[i][0]->f, BM_ELEM_SELECT)) { - continue; + f_test = looptris[i][0]->f; + if (f_test != f_test_prev) { + test_fn_ret = test_fn(f_test, user_data); + f_test_prev = f_test; } - } - else if (flag & BMBVH_RESPECT_HIDDEN) { - /* note, the arrays wont align now! take care */ - if (BM_elem_flag_test(looptris[i][0]->f, BM_ELEM_HIDDEN)) { + + if (!test_fn_ret) { continue; } } @@ -139,6 +153,38 @@ const bool cos_cage_free) return bmtree; } +static bool bm_face_is_select(BMFace *f, void *UNUSED(user_data)) +{ + return (BM_elem_flag_test(f, BM_ELEM_SELECT) != 0); +} + +static bool bm_face_is_not_hidden(BMFace *f, void *UNUSED(user_data)) +{ + return (BM_elem_flag_test(f, BM_ELEM_HIDDEN) == 0); +} + +BMBVHTree *BKE_bmbvh_new( + BMesh *bm, BMLoop *(*looptris)[3], int looptris_tot, int flag, + const float (*cos_cage)[3], const bool cos_cage_free) +{ + bool (*test_fn)(BMFace *, void *user_data); + + if (flag & BMBVH_RESPECT_SELECT) { + test_fn = bm_face_is_select; + } + else if (flag & BMBVH_RESPECT_HIDDEN) { + test_fn = bm_face_is_not_hidden; + } + else { + test_fn = NULL; + } + + flag &= ~(BMBVH_RESPECT_SELECT | BMBVH_RESPECT_HIDDEN); + + return BKE_bmbvh_new_ex(bm, looptris, looptris_tot, flag, cos_cage, cos_cage_free, test_fn, NULL); +} + + void BKE_bmbvh_free(BMBVHTree *bmtree) { BLI_bvhtree_free(bmtree->tree); diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index e28152dbc1a..4859aa8f791 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -935,7 +935,7 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected if (pd->flag & PFIELD_DO_LOCATION) { madd_v3_v3fl(total_force, force, 1.0f/point->vel_to_sec); - if (ELEM3(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG, PFIELD_SMOKEFLOW)==0 && pd->f_flow != 0.0f) { + if (ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG, PFIELD_SMOKEFLOW)==0 && pd->f_flow != 0.0f) { madd_v3_v3fl(total_force, point->vel, -pd->f_flow * efd->falloff); } } diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index a8de9b69fbe..09c1dcf701d 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -276,7 +276,7 @@ int list_find_data_fcurves(ListBase *dst, ListBase *src, const char *dataPrefix, int matches = 0; /* sanity checks */ - if (ELEM4(NULL, dst, src, dataPrefix, dataName)) + if (ELEM(NULL, dst, src, dataPrefix, dataName)) return 0; else if ((dataPrefix[0] == 0) || (dataName[0] == 0)) return 0; @@ -522,17 +522,28 @@ bool calc_fcurve_bounds(FCurve *fcu, float *xmin, float *xmax, float *ymin, floa /* only loop over keyframes to find extents for values if needed */ if (ymin || ymax) { - BezTriple *bezt; + BezTriple *bezt, *prevbezt = NULL; - for (bezt = fcu->bezt, i = 0; i < fcu->totvert; bezt++, i++) { - if ((do_sel_only == false) || BEZSELECTED(bezt)) { + for (bezt = fcu->bezt, i = 0; i < fcu->totvert; prevbezt = bezt, bezt++, i++) { + if ((do_sel_only == false) || BEZSELECTED(bezt)) { + /* keyframe itself */ + yminv = min_ff(yminv, bezt->vec[1][1]); + ymaxv = max_ff(ymaxv, bezt->vec[1][1]); + if (include_handles) { - yminv = min_ffff(yminv, bezt->vec[1][1], bezt->vec[0][1], bezt->vec[2][1]); - ymaxv = max_ffff(ymaxv, bezt->vec[1][1], bezt->vec[0][1], bezt->vec[2][1]); - } - else { - yminv = min_ff(yminv, bezt->vec[1][1]); - ymaxv = max_ff(ymaxv, bezt->vec[1][1]); + /* left handle - only if applicable + * NOTE: for the very first keyframe, the left handle actually has no bearings on anything + */ + if (prevbezt && (prevbezt->ipo == BEZT_IPO_BEZ)) { + yminv = min_ff(yminv, bezt->vec[0][1]); + ymaxv = max_ff(ymaxv, bezt->vec[0][1]); + } + + /* right handle - only if applicable */ + if (bezt->ipo == BEZT_IPO_BEZ) { + yminv = min_ff(yminv, bezt->vec[2][1]); + ymaxv = max_ff(ymaxv, bezt->vec[2][1]); + } } foundvert = true; diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index c381084cfd2..e226e9d9797 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -506,7 +506,7 @@ void gpencil_layer_setactive(bGPdata *gpd, bGPDlayer *active) bGPDlayer *gpl; /* error checking */ - if (ELEM3(NULL, gpd, gpd->layers.first, active)) + if (ELEM(NULL, gpd, gpd->layers.first, active)) return; /* loop over layers deactivating all */ diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c index 2e201a0b8e8..1b7a03ec80e 100644 --- a/source/blender/blenkernel/intern/idcode.c +++ b/source/blender/blenkernel/intern/idcode.c @@ -73,6 +73,8 @@ static IDType idtypes[] = { { ID_NT, "NodeTree", "node_groups", IDTYPE_FLAGS_ISLINKABLE }, { ID_OB, "Object", "objects", IDTYPE_FLAGS_ISLINKABLE }, { ID_PA, "ParticleSettings", "particles", 0 }, + { ID_PAL, "Palettes", "palettes", IDTYPE_FLAGS_ISLINKABLE }, + { ID_PC, "PaintCurve", "paint_curves", IDTYPE_FLAGS_ISLINKABLE }, { ID_SCE, "Scene", "scenes", IDTYPE_FLAGS_ISLINKABLE }, { ID_SCR, "Screen", "screens", 0 }, { ID_SEQ, "Sequence", "sequences", 0 }, /* not actually ID data */ diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index 3188676fb6c..95bfd72c9df 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -64,7 +64,7 @@ static char idp_size_table[] = { /** \name IDP Array API * \{ */ -#define GETPROP(prop, i) (((IDProperty *)(prop)->data.pointer) + (i)) +#define GETPROP(prop, i) &(IDP_IDPArray(prop)[i]) /* --------- property array type -------------*/ diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index db5c212d1db..805c1250c5d 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -1257,7 +1257,7 @@ static bool do_add_image_extension(char *string, const char imtype, const ImageF extension = extension_test; } #endif - else if (ELEM5(imtype, R_IMF_IMTYPE_PNG, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_THEORA, R_IMF_IMTYPE_XVID)) { + else if (ELEM(imtype, R_IMF_IMTYPE_PNG, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_THEORA, R_IMF_IMTYPE_XVID)) { if (!BLI_testextensie(string, extension_test = ".png")) extension = extension_test; } @@ -1900,7 +1900,7 @@ int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf) ibuf->ftype = RADHDR; } #endif - else if (ELEM5(imtype, R_IMF_IMTYPE_PNG, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_THEORA, R_IMF_IMTYPE_XVID)) { + else if (ELEM(imtype, R_IMF_IMTYPE_PNG, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_THEORA, R_IMF_IMTYPE_XVID)) { ibuf->ftype = PNG; if (imtype == R_IMF_IMTYPE_PNG) { diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index 7385322ddeb..51cf26063c7 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -1308,8 +1308,8 @@ static void icu_to_fcurves(ID *id, ListBase *groups, ListBase *list, IpoCurve *i * - they were degrees/10 * - we need radians for RNA to do the right thing */ - if ( ((icu->blocktype == ID_OB) && ELEM3(icu->adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z)) || - ((icu->blocktype == ID_PO) && ELEM3(icu->adrcode, AC_EUL_X, AC_EUL_Y, AC_EUL_Z)) ) + if ( ((icu->blocktype == ID_OB) && ELEM(icu->adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z)) || + ((icu->blocktype == ID_PO) && ELEM(icu->adrcode, AC_EUL_X, AC_EUL_Y, AC_EUL_Z)) ) { const float fac = (float)M_PI / 18.0f; //10.0f * M_PI/180.0f; @@ -1341,7 +1341,7 @@ static void icu_to_fcurves(ID *id, ListBase *groups, ListBase *list, IpoCurve *i DriverVar *dvar = fcu->driver->variables.first; DriverTarget *dtar = &dvar->targets[0]; - if (ELEM3(dtar->transChan, DTAR_TRANSCHAN_ROTX, DTAR_TRANSCHAN_ROTY, DTAR_TRANSCHAN_ROTZ)) { + if (ELEM(dtar->transChan, DTAR_TRANSCHAN_ROTX, DTAR_TRANSCHAN_ROTY, DTAR_TRANSCHAN_ROTZ)) { const float fac = (float)M_PI / 18.0f; dst->vec[0][0] *= fac; @@ -1388,7 +1388,7 @@ static void ipo_to_animato(ID *id, Ipo *ipo, char actname[], char constname[], S IpoCurve *icu; /* sanity check */ - if (ELEM3(NULL, ipo, anim, drivers)) + if (ELEM(NULL, ipo, anim, drivers)) return; if (G.debug & G_DEBUG) printf("ipo_to_animato\n"); diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index df343459d2f..515287de336 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -104,6 +104,7 @@ #include "BKE_mask.h" #include "BKE_node.h" #include "BKE_object.h" +#include "BKE_paint.h" #include "BKE_particle.h" #include "BKE_packedFile.h" #include "BKE_speaker.h" @@ -515,6 +516,10 @@ ListBase *which_libbase(Main *mainlib, short type) return &(mainlib->mask); case ID_LS: return &(mainlib->linestyle); + case ID_PAL: + return &(mainlib->palettes); + case ID_PC: + return &(mainlib->paintcurves); } return NULL; } @@ -596,6 +601,8 @@ int set_listbasepointers(Main *main, ListBase **lb) lb[a++] = &(main->text); lb[a++] = &(main->sound); lb[a++] = &(main->group); + lb[a++] = &(main->palettes); + lb[a++] = &(main->paintcurves); lb[a++] = &(main->brush); lb[a++] = &(main->script); lb[a++] = &(main->particle); @@ -731,6 +738,12 @@ static ID *alloc_libblock_notest(short type) case ID_LS: id = MEM_callocN(sizeof(FreestyleLineStyle), "Freestyle Line Style"); break; + case ID_PAL: + id = MEM_callocN(sizeof(Palette), "Palette"); + break; + case ID_PC: + id = MEM_callocN(sizeof(PaintCurve), "Paint Curve"); + break; } return id; } @@ -1007,6 +1020,12 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, bool do_id_user) case ID_LS: BKE_linestyle_free((FreestyleLineStyle *)id); break; + case ID_PAL: + BKE_palette_free((Palette *)id); + break; + case ID_PC: + BKE_paint_curve_free((PaintCurve *)id); + break; } /* avoid notifying on removed data */ @@ -1131,14 +1150,17 @@ void BKE_main_unlock(struct Main *bmain) } /* ***************** ID ************************ */ - - -ID *BKE_libblock_find_name(const short type, const char *name) /* type: "OB" or "MA" etc */ +ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const char *name) { - ListBase *lb = which_libbase(G.main, type); + ListBase *lb = which_libbase(bmain, type); BLI_assert(lb != NULL); return BLI_findstring(lb, name, offsetof(ID, name) + 2); } +ID *BKE_libblock_find_name(const short type, const char *name) +{ + return BKE_libblock_find_name_ex(G.main, type, name); +} + void id_sort_by_name(ListBase *lb, ID *id) { diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index 4147750c356..1c40446c217 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -1212,7 +1212,7 @@ void BKE_mask_point_parent_matrix_get(MaskSplinePoint *point, float ctime, float } invert_m3_m3(mask_to_clip_matrix, mask_from_clip_matrix); - mul_serie_m3(parent_matrix, mask_to_clip_matrix, H, mask_from_clip_matrix, NULL, NULL, NULL, NULL, NULL); + mul_m3_series(parent_matrix, mask_from_clip_matrix, H, mask_to_clip_matrix); } } } diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 971db1997de..b4ab464838e 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -111,6 +111,9 @@ void BKE_material_free_ex(Material *ma, bool do_id_user) MEM_freeN(ma->nodetree); } + if (ma->texpaintslot) + MEM_freeN(ma->texpaintslot); + if (ma->gpumaterial.first) GPU_material_free(ma); } @@ -269,7 +272,9 @@ Material *localize_material(Material *ma) if (ma->ramp_col) man->ramp_col = MEM_dupallocN(ma->ramp_col); if (ma->ramp_spec) man->ramp_spec = MEM_dupallocN(ma->ramp_spec); - + + if (ma->texpaintslot) man->texpaintslot = MEM_dupallocN(man->texpaintslot); + man->preview = NULL; if (ma->nodetree) @@ -467,7 +472,7 @@ Material ***give_matarar(Object *ob) me = ob->data; return &(me->mat); } - else if (ELEM3(ob->type, OB_CURVE, OB_FONT, OB_SURF)) { + else if (ELEM(ob->type, OB_CURVE, OB_FONT, OB_SURF)) { cu = ob->data; return &(cu->mat); } @@ -488,7 +493,7 @@ short *give_totcolp(Object *ob) me = ob->data; return &(me->totcol); } - else if (ELEM3(ob->type, OB_CURVE, OB_FONT, OB_SURF)) { + else if (ELEM(ob->type, OB_CURVE, OB_FONT, OB_SURF)) { cu = ob->data; return &(cu->totcol); } @@ -1291,7 +1296,7 @@ bool object_remove_material_slot(Object *ob) } /* check indices from mesh */ - if (ELEM4(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) { + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) { material_data_index_remove_id((ID *)ob->data, actcol - 1); if (ob->curve_cache) { BKE_displist_free(&ob->curve_cache->disp); @@ -1301,6 +1306,114 @@ bool object_remove_material_slot(Object *ob) return true; } +void BKE_texpaint_slots_clear(struct Material *ma) +{ + + if (ma->texpaintslot) { + MEM_freeN(ma->texpaintslot); + ma->texpaintslot = NULL; + } + ma->tot_slots = 0; + ma->paint_active_slot = 0; + ma->paint_clone_slot = 0; +} + + +static bool get_mtex_slot_valid_texpaint(struct MTex *mtex) +{ + return (mtex && (mtex->texco == TEXCO_UV) && + mtex->tex && (mtex->tex->type == TEX_IMAGE) && + mtex->tex->ima); +} + +void BKE_texpaint_slot_refresh_cache(Material *ma, bool use_nodes) +{ + MTex **mtex; + short count = 0; + short index = 0, i; + + if (!ma) + return; + + if (ma->texpaintslot) { + MEM_freeN(ma->texpaintslot); + ma->texpaintslot = NULL; + } + + if (use_nodes) { + bNode *node, *active_node; + + if (!(ma->use_nodes && ma->nodetree)) + return; + + for (node = ma->nodetree->nodes.first; node; node = node->next) { + if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) + count++; + } + + ma->tot_slots = count; + + if (count == 0) { + ma->paint_active_slot = 0; + return; + } + ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots"); + + active_node = nodeGetActiveTexture(ma->nodetree); + + for (node = ma->nodetree->nodes.first; node; node = node->next) { + if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) { + if (active_node == node) + ma->paint_active_slot = index; + ma->texpaintslot[index++].ima = (Image *)node->id; + } + } + } + else { + for (mtex = ma->mtex, i = 0; i < MAX_MTEX; i++, mtex++) { + if (get_mtex_slot_valid_texpaint(*mtex)) { + count++; + } + } + + ma->tot_slots = count; + + if (count == 0) { + ma->paint_active_slot = 0; + return; + } + + ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots"); + + for (mtex = ma->mtex, i = 0; i < MAX_MTEX; i++, mtex++) { + if (get_mtex_slot_valid_texpaint(*mtex)) { + ma->texpaintslot[index].ima = (*mtex)->tex->ima; + ma->texpaintslot[index++].uvname = (*mtex)->uvname; + } + } + } + + if (ma->paint_active_slot >= count) { + ma->paint_active_slot = count - 1; + } + + if (ma->paint_clone_slot >= count) { + ma->paint_clone_slot = count - 1; + } + + return; +} + +void BKE_texpaint_slots_refresh_object(struct Object *ob, bool use_nodes) +{ + int i; + + for (i = 1; i < ob->totcol + 1; i++) { + Material *ma = give_current_material(ob, i); + BKE_texpaint_slot_refresh_cache(ma, use_nodes); + } +} + /* r_col = current value, col = new value, (fac == 0) is no change */ void ramp_blend(int type, float r_col[3], const float fac, const float col[3]) diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index 43b19f0c869..5a045606d15 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -491,10 +491,7 @@ void BKE_mball_properties_copy(Scene *scene, Object *active_object) BLI_split_name_num(basisname, &basisnr, active_object->id.name + 2, '.'); - /* XXX recursion check, see scene.c, just too simple code this BKE_scene_base_iter_next() */ - if (F_ERROR == BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL)) - return; - + BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL); while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &ob)) { if (ob->type == OB_MBALL) { if (ob != active_object) { @@ -537,23 +534,17 @@ Object *BKE_mball_basis_find(Scene *scene, Object *basis) BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.'); - /* XXX recursion check, see scene.c, just too simple code this BKE_scene_base_iter_next() */ - if (F_ERROR == BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL)) - return NULL; - + BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL); while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &ob)) { - if (ob->type == OB_MBALL) { + if ((ob->type == OB_MBALL) && !(base->flag & OB_FROMDUPLI)) { if (ob != bob) { BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); - /* object ob has to be in same "group" ... it means, that it has to have - * same base of its name */ + /* object ob has to be in same "group" ... it means, that it has to have same base of its name */ if (strcmp(obname, basisname) == 0) { if (obnr < basisnr) { - if (!(ob->flag & OB_FROMDUPLI)) { - basis = ob; - basisnr = obnr; - } + basis = ob; + basisnr = obnr; } } } @@ -2227,10 +2218,7 @@ static void mball_count(EvaluationContext *eval_ctx, PROCESS *process, Scene *sc BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.'); process->totelem = 0; - /* XXX recursion check, see scene.c, just too simple code this BKE_scene_base_iter_next() */ - if (F_ERROR == BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL)) - return; - + BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL); while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &ob)) { if (ob->type == OB_MBALL) { if (ob == bob) { diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 2bf33b97a70..66c383ef0d3 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -115,16 +115,16 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2 int i, i1 = 0, i2 = 0, tot, j; for (i = 0; i < c1->totlayer; i++) { - if (ELEM7(c1->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY, - CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) + if (ELEM(c1->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY, + CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) { i1++; } } for (i = 0; i < c2->totlayer; i++) { - if (ELEM7(c2->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY, - CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) + if (ELEM(c2->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY, + CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) { i2++; } @@ -135,16 +135,16 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2 l1 = c1->layers; l2 = c2->layers; tot = i1; - i1 = 0; i2 = 0; + i1 = 0; i2 = 0; for (i = 0; i < tot; i++) { - while (i1 < c1->totlayer && !ELEM7(l1->type, CD_MVERT, CD_MEDGE, CD_MPOLY, - CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) + while (i1 < c1->totlayer && !ELEM(l1->type, CD_MVERT, CD_MEDGE, CD_MPOLY, + CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) { i1++, l1++; } - while (i2 < c2->totlayer && !ELEM7(l2->type, CD_MVERT, CD_MEDGE, CD_MPOLY, - CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) + while (i2 < c2->totlayer && !ELEM(l2->type, CD_MVERT, CD_MEDGE, CD_MPOLY, + CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) { i2++, l2++; } @@ -2041,7 +2041,7 @@ int BKE_mesh_mselect_find(Mesh *me, int index, int type) { int i; - BLI_assert(ELEM3(type, ME_VSEL, ME_ESEL, ME_FSEL)); + BLI_assert(ELEM(type, ME_VSEL, ME_ESEL, ME_FSEL)); for (i = 0; i < me->totselect; i++) { if ((me->mselect[i].index == index) && @@ -2059,7 +2059,7 @@ int BKE_mesh_mselect_find(Mesh *me, int index, int type) */ int BKE_mesh_mselect_active_get(Mesh *me, int type) { - BLI_assert(ELEM3(type, ME_VSEL, ME_ESEL, ME_FSEL)); + BLI_assert(ELEM(type, ME_VSEL, ME_ESEL, ME_FSEL)); if (me->totselect) { if (me->mselect[me->totselect - 1].type == type) { diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index 83b6d6c61d6..d244dcc931f 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -731,7 +731,7 @@ void BKE_mesh_loop_tangents(Mesh *mesh, const char *uvmap, float (*r_looptangent } BKE_mesh_loop_tangents_ex(mesh->mvert, mesh->totvert, mesh->mloop, r_looptangents, - loopnors, loopuvs, mesh->totloop, mesh->mpoly, mesh->totpoly, reports); + loopnors, loopuvs, mesh->totloop, mesh->mpoly, mesh->totpoly, reports); } /** \} */ diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c index 65c576dd6a0..82065750791 100644 --- a/source/blender/blenkernel/intern/mesh_mapping.c +++ b/source/blender/blenkernel/intern/mesh_mapping.c @@ -442,7 +442,7 @@ int *BKE_mesh_calc_smoothgroups(const MEdge *medge, const int totedge, /* Find contiguous smooth groups already assigned, these are the values we can't reuse! */ for (; i--; p++) { int bit = poly_groups[*p]; - if (!ELEM3(bit, 0, poly_group_id, poly_group_id_overflowed) && + if (!ELEM(bit, 0, poly_group_id, poly_group_id_overflowed) && !(bit_poly_group_mask & bit)) { bit_poly_group_mask |= bit; diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c index e14bb9377da..dd2c6f42c4a 100644 --- a/source/blender/blenkernel/intern/mesh_validate.c +++ b/source/blender/blenkernel/intern/mesh_validate.c @@ -164,16 +164,20 @@ static int search_poly_cmp(const void *v1, const void *v2) { const SortPoly *sp1 = v1, *sp2 = v2; const int max_idx = sp1->numverts > sp2->numverts ? sp2->numverts : sp1->numverts; - int idx = 0; + int idx; /* Reject all invalid polys at end of list! */ if (sp1->invalid || sp2->invalid) - return sp1->invalid && sp2->invalid ? 0 : sp1->invalid ? 1 : -1; - /* Else, sort on first non-egal verts (remember verts of valid polys are sorted). */ - while (idx < max_idx && sp1->verts[idx] == sp2->verts[idx]) - idx++; - return sp1->verts[idx] > sp2->verts[idx] ? 1 : sp1->verts[idx] < sp2->verts[idx] ? -1 : - sp1->numverts > sp2->numverts ? 1 : sp1->numverts < sp2->numverts ? -1 : 0; + return sp1->invalid ? (sp2->invalid ? 0 : 1) : -1; + /* Else, sort on first non-equal verts (remember verts of valid polys are sorted). */ + for (idx = 0; idx < max_idx; idx++) { + const int v1 = sp1->verts[idx]; + const int v2 = sp2->verts[idx]; + if (v1 != v2) { + return (v1 > v2) ? 1 : -1; + } + } + return sp1->numverts > sp2->numverts ? 1 : sp1->numverts < sp2->numverts ? -1 : 0; } static int search_polyloop_cmp(const void *v1, const void *v2) diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index d0114d52a06..19e45142960 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -430,7 +430,7 @@ static float nlastrip_get_frame_actionclip(NlaStrip *strip, float cframe, short return (strip->end + (strip->actstart * scale - cframe)) / scale; } else { /* if (mode == NLATIME_CONVERT_EVAL) */ - if (IS_EQF(cframe, strip->end) && IS_EQF(strip->repeat, ((int)strip->repeat))) { + if (IS_EQF((float)cframe, strip->end) && IS_EQF(strip->repeat, floorf(strip->repeat))) { /* this case prevents the motion snapping back to the first frame at the end of the strip * by catching the case where repeats is a whole number, which means that the end of the strip * could also be interpreted as the end of the start of a repeat @@ -453,7 +453,7 @@ static float nlastrip_get_frame_actionclip(NlaStrip *strip, float cframe, short return strip->actstart + (cframe - strip->start) / scale; } else { /* if (mode == NLATIME_CONVERT_EVAL) */ - if (IS_EQF(cframe, strip->end) && IS_EQF(strip->repeat, ((int)strip->repeat))) { + if (IS_EQF(cframe, strip->end) && IS_EQF(strip->repeat, floorf(strip->repeat))) { /* this case prevents the motion snapping back to the first frame at the end of the strip * by catching the case where repeats is a whole number, which means that the end of the strip * could also be interpreted as the end of the start of a repeat @@ -1637,7 +1637,7 @@ bool BKE_nla_tweakmode_enter(AnimData *adt) } } - if (ELEM3(NULL, activeTrack, activeStrip, activeStrip->act)) { + if (ELEM(NULL, activeTrack, activeStrip, activeStrip->act)) { if (G.debug & G_DEBUG) { printf("NLA tweakmode enter - neither active requirement found\n"); printf("\tactiveTrack = %p, activeStrip = %p\n", (void *)activeTrack, (void *)activeStrip); @@ -1744,7 +1744,7 @@ static void UNUSED_FUNCTION(BKE_nla_bake) (Scene *scene, ID *UNUSED(id), AnimDat * 1) Scene and AnimData must be provided * 2) there must be tracks to merge... */ - if (ELEM3(NULL, scene, adt, adt->nla_tracks.first)) + if (ELEM(NULL, scene, adt, adt->nla_tracks.first)) return; /* if animdata currently has an action, 'push down' this onto the stack first */ diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 56a76a54955..0dee80e27cd 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -3406,6 +3406,7 @@ static void registerCompositNodes(void) register_node_type_cmp_inpaint(); register_node_type_cmp_despeckle(); register_node_type_cmp_defocus(); + register_node_type_cmp_sunbeams(); register_node_type_cmp_valtorgb(); register_node_type_cmp_rgbtobw(); diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 42128a9b364..98a197b9e02 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -246,7 +246,7 @@ void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src) ModifierData *md; BKE_object_free_modifiers(ob_dst); - if (!ELEM5(ob_dst->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { + if (!ELEM(ob_dst->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { /* only objects listed above can have modifiers and linking them to objects * which doesn't have modifiers stack is quite silly */ return; @@ -255,11 +255,11 @@ void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src) for (md = ob_src->modifiers.first; md; md = md->next) { ModifierData *nmd = NULL; - if (ELEM4(md->type, - eModifierType_Hook, - eModifierType_Softbody, - eModifierType_ParticleInstance, - eModifierType_Collision)) + if (ELEM(md->type, + eModifierType_Hook, + eModifierType_Softbody, + eModifierType_ParticleInstance, + eModifierType_Collision)) { continue; } @@ -296,7 +296,7 @@ void BKE_object_free_derived_caches(Object *ob) me->bb->flag |= BOUNDBOX_DIRTY; } } - else if (ELEM3(ob->type, OB_SURF, OB_CURVE, OB_FONT)) { + else if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) { Curve *cu = ob->data; if (cu->bb) { @@ -977,7 +977,7 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name) ob->empty_drawtype = OB_PLAINAXES; ob->empty_drawsize = 1.0; - if (ELEM3(type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { + if (ELEM(type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { ob->trackflag = OB_NEGZ; ob->upflag = OB_POSY; } @@ -1978,7 +1978,7 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4]) unit_m4(mat); cu = par->data; - if (ELEM3(NULL, par->curve_cache, par->curve_cache->path, par->curve_cache->path->data)) /* only happens on reload file, but violates depsgraph still... fix! */ + if (ELEM(NULL, par->curve_cache, par->curve_cache->path, par->curve_cache->path->data)) /* only happens on reload file, but violates depsgraph still... fix! */ BKE_displist_make_curveTypes(scene, par, 0); if (par->curve_cache->path == NULL) return; @@ -1994,17 +1994,20 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4]) * we divide the curvetime calculated in the previous step by the length of the path, to get a time * factor, which then gets clamped to lie within 0.0 - 1.0 range */ - if (IS_EQF(cu->pathlen, 0.0f) == 0) + if (cu->pathlen) { ctime = cu->ctime / cu->pathlen; - else + } + else { ctime = cu->ctime; + } CLAMP(ctime, 0.0f, 1.0f); } else { ctime = BKE_scene_frame_get(scene); - if (IS_EQF(cu->pathlen, 0.0f) == 0) + if (cu->pathlen) { ctime /= cu->pathlen; + } CLAMP(ctime, 0.0f, 1.0f); } @@ -2473,7 +2476,7 @@ BoundBox *BKE_object_boundbox_get(Object *ob) if (ob->type == OB_MESH) { bb = BKE_mesh_boundbox_get(ob); } - else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { + else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { bb = BKE_curve_boundbox_get(ob); } else if (ob->type == OB_MBALL) { diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index 707438bc673..0d82c6e89a1 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -754,14 +754,14 @@ static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Obj if (orco) { int j; - for (j = 0; j < mpoly->totloop; j++) { + for (j = 0; j < mp->totloop; j++) { madd_v3_v3fl(dob->orco, orco[loopstart[j].v], w); } } if (mloopuv) { int j; - for (j = 0; j < mpoly->totloop; j++) { + for (j = 0; j < mp->totloop; j++) { madd_v2_v2fl(dob->uv, mloopuv[mp->loopstart + j].uv, w); } } diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 8ff8ee39a7a..27fd3fc4908 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -45,8 +45,10 @@ #include "BLI_bitmap.h" #include "BLI_utildefines.h" #include "BLI_math_vector.h" +#include "BLI_listbase.h" #include "BKE_brush.h" +#include "BKE_main.h" #include "BKE_context.h" #include "BKE_crazyspace.h" #include "BKE_depsgraph.h" @@ -269,6 +271,105 @@ void BKE_paint_brush_set(Paint *p, Brush *br) } } +void BKE_paint_curve_free(PaintCurve *pc) +{ + if (pc->points) { + MEM_freeN(pc->points); + pc->points = NULL; + pc->tot_points = 0; + } +} + +PaintCurve *BKE_paint_curve_add(Main *bmain, const char *name) +{ + PaintCurve *pc; + + pc = BKE_libblock_alloc(bmain, ID_PC, name); + + return pc; +} + +Palette *BKE_paint_palette(Paint *p) +{ + return p ? p->palette : NULL; +} + +void BKE_paint_palette_set(Paint *p, Palette *palette) +{ + if (p) { + id_us_min((ID *)p->palette); + id_us_plus((ID *)palette); + p->palette = palette; + } +} + +void BKE_paint_curve_set(Brush *br, PaintCurve *pc) +{ + if (br) { + id_us_min((ID *)br->paint_curve); + id_us_plus((ID *)pc); + br->paint_curve = pc; + } +} + +/* remove colour from palette. Must be certain color is inside the palette! */ +void BKE_palette_color_remove(Palette *palette, PaletteColor *color) +{ + BLI_remlink(&palette->colors, color); + BLI_addhead(&palette->deleted, color); +} + +void BKE_palette_cleanup(Palette *palette) +{ + BLI_freelistN(&palette->deleted); +} + + +Palette *BKE_palette_add(Main *bmain, const char *name) +{ + Palette *palette; + + palette = BKE_libblock_alloc(bmain, ID_PAL, name); + + /* enable fake user by default */ + palette->id.flag |= LIB_FAKEUSER; + + return palette; +} + +void BKE_palette_free(Palette *palette) +{ + BLI_freelistN(&palette->colors); +} + +PaletteColor *BKE_palette_color_add(Palette *palette) +{ + PaletteColor *color = MEM_callocN(sizeof(*color), "Pallete Color"); + BLI_addtail(&palette->colors, color); + palette->active_color = BLI_countlist(&palette->colors) - 1; + return color; +} + +void BKE_palette_color_delete(struct Palette *palette) +{ + PaletteColor *color = BLI_findlink(&palette->colors, palette->active_color); + + if (color) { + if ((color == palette->colors.last) && (palette->colors.last != palette->colors.first)) + palette->active_color--; + + BLI_remlink(&palette->colors, color); + BLI_addhead(&palette->deleted, color); + } +} + + +bool BKE_palette_is_empty(const struct Palette *palette) +{ + return BLI_listbase_is_empty(&palette->colors); +} + + /* are we in vertex paint or weight pain face select mode? */ bool BKE_paint_select_face_test(Object *ob) { @@ -318,6 +419,7 @@ void BKE_paint_init(Paint *p, const char col[3]) void BKE_paint_free(Paint *paint) { id_us_min((ID *)paint->brush); + id_us_min((ID *)paint->palette); } /* called when copying scene settings, so even if 'src' and 'tar' are the same @@ -328,6 +430,7 @@ void BKE_paint_copy(Paint *src, Paint *tar) { tar->brush = src->brush; id_us_plus((ID *)tar->brush); + id_us_plus((ID *)tar->palette); } /* returns non-zero if any of the face's vertices @@ -378,7 +481,7 @@ float paint_grid_paint_mask(const GridPaintMask *gpm, unsigned level, return gpm->data[(y * factor) * gridsize + (x * factor)]; } -/* threshhold to move before updating the brush rotation */ +/* threshold to move before updating the brush rotation */ #define RAKE_THRESHHOLD 20 void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, const float mouse_pos[2]) diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 8161f9d8875..27d346f65b9 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -1657,11 +1657,14 @@ int psys_particle_dm_face_lookup(Object *ob, DerivedMesh *dm, int index, const f index_mp_to_orig = NULL; } + totface = dm->getNumTessFaces(dm); + if (!totface) { + return DMCACHE_NOTFOUND; + } + mpoly = dm->getPolyArray(dm); osface = dm->getTessFaceDataArray(dm, CD_ORIGSPACE); - totface = dm->getNumTessFaces(dm); - if (osface == NULL || index_mf_to_mpoly == NULL) { /* Assume we don't need osface data */ if (index < totface) { diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 5237eeda108..82818baaed0 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -117,7 +117,7 @@ static int particles_are_dynamic(ParticleSystem *psys) if (psys->part->type == PART_HAIR) return psys->flag & PSYS_HAIR_DYNAMICS; else - return ELEM3(psys->part->phystype, PART_PHYS_NEWTON, PART_PHYS_BOIDS, PART_PHYS_FLUID); + return ELEM(psys->part->phystype, PART_PHYS_NEWTON, PART_PHYS_BOIDS, PART_PHYS_FLUID); } float psys_get_current_display_percentage(ParticleSystem *psys) @@ -1079,7 +1079,7 @@ static int distribute_threads_init_data(ParticleThread *threads, Scene *scene, D float *element_weight=NULL,*element_sum=NULL,*jitter_offset=NULL, *vweight=NULL; float cur, maxweight=0.0, tweight, totweight, inv_totweight, co[3], nor[3], orco[3]; - if (ELEM3(NULL, ob, psys, psys->part)) + if (ELEM(NULL, ob, psys, psys->part)) return 0; part=psys->part; @@ -3153,7 +3153,7 @@ static void basic_rotate(ParticleSettings *part, ParticleData *pa, float dfra, f extrotfac = 0.0f; } - if ((part->flag & PART_ROT_DYN) && ELEM3(part->avemode, PART_AVE_VELOCITY, PART_AVE_HORIZONTAL, PART_AVE_VERTICAL)) { + if ((part->flag & PART_ROT_DYN) && ELEM(part->avemode, PART_AVE_VELOCITY, PART_AVE_HORIZONTAL, PART_AVE_VERTICAL)) { float angle; float len1 = len_v3(pa->prev_state.vel); float len2 = len_v3(pa->state.vel); @@ -4846,13 +4846,13 @@ void psys_changed_type(Object *ob, ParticleSystem *psys) psys->flag &= ~PSYS_KEYED; if (part->type == PART_HAIR) { - if (ELEM4(part->ren_as, PART_DRAW_NOT, PART_DRAW_PATH, PART_DRAW_OB, PART_DRAW_GR)==0) + if (ELEM(part->ren_as, PART_DRAW_NOT, PART_DRAW_PATH, PART_DRAW_OB, PART_DRAW_GR)==0) part->ren_as = PART_DRAW_PATH; if (part->distr == PART_DISTR_GRID) part->distr = PART_DISTR_JIT; - if (ELEM3(part->draw_as, PART_DRAW_NOT, PART_DRAW_REND, PART_DRAW_PATH)==0) + if (ELEM(part->draw_as, PART_DRAW_NOT, PART_DRAW_REND, PART_DRAW_PATH)==0) part->draw_as = PART_DRAW_REND; CLAMP(part->path_start, 0.0f, 100.0f); diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index e4e6105fe8c..ccedb6f6b71 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -50,6 +50,15 @@ #define STACK_FIXED_DEPTH 100 +/* Setting zero so we can catch bugs in OpenMP/PBVH. */ +#ifdef _OPENMP +# ifdef DEBUG +# define PBVH_OMP_LIMIT 0 +# else +# define PBVH_OMP_LIMIT 8 +# endif +#endif + typedef struct PBVHStack { PBVHNode *node; int revisiting; @@ -965,7 +974,7 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes, * can only update vertices marked with ME_VERT_PBVH_UPDATE. */ -#pragma omp parallel for private(n) schedule(static) +#pragma omp parallel for private(n) schedule(static) if (totnode > PBVH_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHNode *node = nodes[n]; @@ -1009,7 +1018,7 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes, } } -#pragma omp parallel for private(n) schedule(static) +#pragma omp parallel for private(n) schedule(static) if (totnode > PBVH_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHNode *node = nodes[n]; @@ -1046,7 +1055,7 @@ void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag) int n; /* update BB, redraw flag */ -#pragma omp parallel for private(n) schedule(static) +#pragma omp parallel for private(n) schedule(static) if (totnode > PBVH_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHNode *node = nodes[n]; diff --git a/source/blender/blenkernel/intern/report.c b/source/blender/blenkernel/intern/report.c index 90b5d8cf1a1..b2178fe69b3 100644 --- a/source/blender/blenkernel/intern/report.c +++ b/source/blender/blenkernel/intern/report.c @@ -284,7 +284,7 @@ Report *BKE_reports_last_displayable(ReportList *reports) Report *report; for (report = reports->list.last; report; report = report->prev) { - if (ELEM3(report->type, RPT_ERROR, RPT_WARNING, RPT_INFO)) + if (ELEM(report->type, RPT_ERROR, RPT_WARNING, RPT_INFO)) return report; } diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index 98bcdfabad3..3d61b0bdefb 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -395,7 +395,7 @@ static void rigidbody_validate_sim_shape(Object *ob, bool rebuild) } mul_v3_fl(size, 0.5f); - if (ELEM3(rbo->shape, RB_SHAPE_CAPSULE, RB_SHAPE_CYLINDER, RB_SHAPE_CONE)) { + if (ELEM(rbo->shape, RB_SHAPE_CAPSULE, RB_SHAPE_CYLINDER, RB_SHAPE_CONE)) { /* take radius as largest x/y dimension, and height as z-dimension */ radius = MAX2(size[0], size[1]); height = size[2]; @@ -477,7 +477,7 @@ void BKE_rigidbody_calc_volume(Object *ob, float *r_vol) // XXX: all dimensions are auto-determined now... later can add stored settings for this BKE_object_dimensions_get(ob, size); - if (ELEM3(rbo->shape, RB_SHAPE_CAPSULE, RB_SHAPE_CYLINDER, RB_SHAPE_CONE)) { + if (ELEM(rbo->shape, RB_SHAPE_CAPSULE, RB_SHAPE_CYLINDER, RB_SHAPE_CONE)) { /* take radius as largest x/y dimension, and height as z-dimension */ radius = MAX2(size[0], size[1]) * 0.5f; height = size[2]; @@ -720,7 +720,7 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b return; } - if (ELEM4(NULL, rbc->ob1, rbc->ob1->rigidbody_object, rbc->ob2, rbc->ob2->rigidbody_object)) { + if (ELEM(NULL, rbc->ob1, rbc->ob1->rigidbody_object, rbc->ob2, rbc->ob2->rigidbody_object)) { if (rbc->physics_constraint) { RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint); RB_constraint_delete(rbc->physics_constraint); diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index f8ce31f1b8a..a6e23edba56 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -39,6 +39,7 @@ #include "DNA_anim_types.h" #include "DNA_group_types.h" #include "DNA_linestyle_types.h" +#include "DNA_mesh_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" #include "DNA_rigidbody_types.h" @@ -46,6 +47,8 @@ #include "DNA_screen_types.h" #include "DNA_sequence_types.h" #include "DNA_space_types.h" +#include "DNA_view3d_types.h" +#include "DNA_windowmanager_types.h" #include "BLI_math.h" #include "BLI_blenlib.h" @@ -62,6 +65,7 @@ #include "BKE_action.h" #include "BKE_colortools.h" #include "BKE_depsgraph.h" +#include "BKE_editmesh.h" #include "BKE_fcurve.h" #include "BKE_freestyle.h" #include "BKE_global.h" @@ -86,6 +90,8 @@ #include "IMB_colormanagement.h" +#include "bmesh.h" + //XXX #include "BIF_previewrender.h" //XXX #include "BIF_editseq.h" @@ -510,6 +516,8 @@ Scene *BKE_scene_add(Main *bmain, const char *name) sce->r.border.ymin = 0.0f; sce->r.border.xmax = 1.0f; sce->r.border.ymax = 1.0f; + + sce->r.preview_start_resolution = 64; sce->toolsettings = MEM_callocN(sizeof(struct ToolSettings), "Tool Settings Struct"); sce->toolsettings->doublimit = 0.001; @@ -719,14 +727,14 @@ void BKE_scene_set_background(Main *bmain, Scene *scene) /* called from creator.c */ Scene *BKE_scene_set_name(Main *bmain, const char *name) { - Scene *sce = (Scene *)BKE_libblock_find_name(ID_SCE, name); + Scene *sce = (Scene *)BKE_libblock_find_name_ex(bmain, ID_SCE, name); if (sce) { BKE_scene_set_background(bmain, sce); - printf("Scene switch: '%s' in file: '%s'\n", name, G.main->name); + printf("Scene switch: '%s' in file: '%s'\n", name, bmain->name); return sce; } - printf("Can't find scene: '%s' in file: '%s'\n", name, G.main->name); + printf("Can't find scene: '%s' in file: '%s'\n", name, bmain->name); return NULL; } @@ -804,9 +812,7 @@ void BKE_scene_unlink(Main *bmain, Scene *sce, Scene *newsce) BKE_libblock_free(bmain, sce); } -/* used by metaballs - * doesn't return the original duplicated object, only dupli's - */ +/* Used by metaballs, return *all* objects (including duplis) existing in the scene (including scene's sets) */ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter, Scene **scene, int val, Base **base, Object **ob) { @@ -817,11 +823,12 @@ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter, iter->phase = F_START; iter->dupob = NULL; iter->duplilist = NULL; + iter->dupli_refob = NULL; } else { /* run_again is set when a duplilist has been ended */ while (run_again) { - run_again = 0; + run_again = false; /* the first base */ if (iter->phase == F_START) { @@ -879,34 +886,46 @@ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter, iter->dupob = iter->duplilist->first; - if (!iter->dupob) + if (!iter->dupob) { free_object_duplilist(iter->duplilist); + iter->duplilist = NULL; + } + iter->dupli_refob = NULL; } } } /* handle dupli's */ if (iter->dupob) { - - copy_m4_m4(iter->omat, iter->dupob->ob->obmat); - copy_m4_m4(iter->dupob->ob->obmat, iter->dupob->mat); - (*base)->flag |= OB_FROMDUPLI; *ob = iter->dupob->ob; iter->phase = F_DUPLI; - + + if (iter->dupli_refob != *ob) { + if (iter->dupli_refob) { + /* Restore previous object's real matrix. */ + copy_m4_m4(iter->dupli_refob->obmat, iter->omat); + } + /* Backup new object's real matrix. */ + iter->dupli_refob = *ob; + copy_m4_m4(iter->omat, iter->dupli_refob->obmat); + } + copy_m4_m4((*ob)->obmat, iter->dupob->mat); + iter->dupob = iter->dupob->next; } else if (iter->phase == F_DUPLI) { iter->phase = F_SCENE; (*base)->flag &= ~OB_FROMDUPLI; - for (iter->dupob = iter->duplilist->first; iter->dupob; iter->dupob = iter->dupob->next) { - copy_m4_m4(iter->dupob->ob->obmat, iter->omat); + if (iter->dupli_refob) { + /* Restore last object's real matrix. */ + copy_m4_m4(iter->dupli_refob->obmat, iter->omat); + iter->dupli_refob = NULL; } free_object_duplilist(iter->duplilist); iter->duplilist = NULL; - run_again = 1; + run_again = true; } } } @@ -1541,6 +1560,53 @@ static void scene_update_tagged_recursive(EvaluationContext *eval_ctx, Main *bma } +static bool check_rendered_viewport_visible(Main *bmain) +{ + wmWindowManager *wm = bmain->wm.first; + wmWindow *window; + for (window = wm->windows.first; window != NULL; window = window->next) { + bScreen *screen = window->screen; + ScrArea *area; + for (area = screen->areabase.first; area != NULL; area = area->next) { + View3D *v3d = area->spacedata.first; + if (area->spacetype != SPACE_VIEW3D) { + continue; + } + if (v3d->drawtype == OB_RENDER) { + return true; + } + } + } + return false; +} + +static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene) +{ + /* This is needed to prepare mesh to be used by the render + * engine from the viewport rendering. We do loading here + * so all the objects which shares the same mesh datablock + * are nicely tagged for update and updated. + * + * This makes it so viewport render engine doesn't need to + * call loading of the edit data for the mesh objects. + */ + + Object *obedit = scene->obedit; + if (obedit) { + Mesh *mesh = obedit->data; + /* TODO(sergey): Check object recalc flags as well? */ + if ((obedit->type == OB_MESH) && + (mesh->id.flag & (LIB_ID_RECALC | LIB_ID_RECALC_DATA))) + { + if (check_rendered_viewport_visible(bmain)) { + BMesh *bm = mesh->edit_btmesh->bm; + BM_mesh_bm_to_me(bm, mesh, false); + DAG_id_tag_update(&mesh->id, 0); + } + } + } +} + void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *scene) { Scene *sce_iter; @@ -1552,6 +1618,9 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) DAG_scene_relations_update(bmain, sce_iter); + /* flush editing data if needed */ + prepare_mesh_for_viewport_render(bmain, scene); + /* flush recalc flags to dependencies */ DAG_ids_flush_tagged(bmain); diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index 2b14b92217b..d2dc9da47f9 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -52,6 +52,11 @@ #include "RNA_access.h" +/* TODO(sergey): Could be considered a bad level call, but + * need this for gaussian table. + */ +#include "RE_pipeline.h" + static void slice_get_byte_buffers(const SeqRenderData *context, const ImBuf *ibuf1, const ImBuf *ibuf2, const ImBuf *ibuf3, const ImBuf *out, int start_line, unsigned char **rect1, unsigned char **rect2, unsigned char **rect3, unsigned char **rect_out) @@ -2579,6 +2584,295 @@ static void do_overdrop_effect(const SeqRenderData *context, Sequence *UNUSED(se } } +/*********************** Gaussian Blur *************************/ + +/* NOTE: This gaussian blur implementation accumulates values in the square + * kernel rather that doing X direction and then Y direction because of the + * lack of using multiple-staged filters. + * + * Once we can we'll implement a way to apply filter as multiple stages we + * can optimize hell of a lot in here. + */ + +static void init_gaussian_blur_effect(Sequence *seq) +{ + if (seq->effectdata) + MEM_freeN(seq->effectdata); + + seq->effectdata = MEM_callocN(sizeof(WipeVars), "wipevars"); +} + +static int num_inputs_gaussian_blur(void) +{ + return 1; +} + +static void free_gaussian_blur_effect(Sequence *seq) +{ + if (seq->effectdata) + MEM_freeN(seq->effectdata); + + seq->effectdata = NULL; +} + +static void copy_gaussian_blur_effect(Sequence *dst, Sequence *src) +{ + dst->effectdata = MEM_dupallocN(src->effectdata); +} + +static int early_out_gaussian_blur(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1)) +{ + GaussianBlurVars *data = seq->effectdata; + if (data->size_x == 0.0f && data->size_y == 0) { + return EARLY_USE_INPUT_1; + } + return EARLY_DO_EFFECT; +} + +/* TODO(sergey): De-duplicate with compositor. */ +static float *make_gaussian_blur_kernel(float rad, int size) +{ + float *gausstab, sum, val; + float fac; + int i, n; + + n = 2 * size + 1; + + gausstab = (float *)MEM_mallocN(sizeof(float) * n, __func__); + + sum = 0.0f; + fac = (rad > 0.0f ? 1.0f / rad : 0.0f); + for (i = -size; i <= size; i++) { + val = RE_filter_value(R_FILTER_GAUSS, (float)i * fac); + sum += val; + gausstab[i + size] = val; + } + + sum = 1.0f / sum; + for (i = 0; i < n; i++) + gausstab[i] *= sum; + + return gausstab; +} + +static void do_gaussian_blur_effect_byte(Sequence *seq, + int start_line, + int x, int y, + int frame_width, int frame_height, + unsigned char *rect, + unsigned char *out) +{ +#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4) + GaussianBlurVars *data = seq->effectdata; + const int size_x = (int) (data->size_x + 0.5f), + size_y = (int) (data->size_y + 0.5f); + int i, j; + + /* Make gaussian weight tabke. */ + float *gausstab_x, *gausstab_y; + gausstab_x = make_gaussian_blur_kernel(data->size_x, size_x); + if (data->size_x == data->size_y) { + gausstab_y = gausstab_x; + } + else { + gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y); + } + + for (i = 0; i < y; ++i) { + for (j = 0; j < x; ++j) { + int out_index = INDEX(j, i); + int current_x, current_y; + float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + float accum_weight = 0.0f; + for (current_y = i - size_y; + current_y <= i + size_y; + ++current_y) + { + if (current_y < -start_line || + current_y + start_line >= frame_height) + { + /* Out of bounds. */ + continue; + } + + for (current_x = j - size_x; + current_x <= j + size_x; + ++current_x) + { + float weight; + int index = INDEX(current_x, current_y + start_line); + if (current_x < 0 || current_x >= frame_width) { + /* Out of bounds. */ + continue; + } + BLI_assert(index >= 0); + BLI_assert(index < frame_width * frame_height * 4); + + if (size_x != 0 && size_y != 0) { + weight = gausstab_x[current_x - j + size_x] * + gausstab_y[current_y - i + size_y]; + } + else if (size_x == 0) { + weight = gausstab_y[current_y - i + size_y]; + } + else { + weight = gausstab_x[current_x - j + size_x]; + } + accum[0] += rect[index] * weight; + accum[1] += rect[index + 1] * weight; + accum[2] += rect[index + 2] * weight; + accum[3] += rect[index + 3] * weight; + accum_weight += weight; + } + } + out[out_index + 0] = accum[0] / accum_weight; + out[out_index + 1] = accum[1] / accum_weight; + out[out_index + 2] = accum[2] / accum_weight; + out[out_index + 3] = accum[3] / accum_weight; + } + } + + MEM_freeN(gausstab_x); + if (gausstab_x != gausstab_y) { + MEM_freeN(gausstab_y); + } +#undef INDEX +} + +static void do_gaussian_blur_effect_float(Sequence *seq, + int start_line, + int x, int y, + int frame_width, int frame_height, + float *rect, + float *out) +{ +#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4) + GaussianBlurVars *data = seq->effectdata; + const int size_x = (int) (data->size_x + 0.5f), + size_y = (int) (data->size_y + 0.5f); + int i, j; + + /* Make gaussian weight tabke. */ + float *gausstab_x, *gausstab_y; + gausstab_x = make_gaussian_blur_kernel(data->size_x, size_x); + if (data->size_x == data->size_y) { + gausstab_y = gausstab_x; + } + else { + gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y); + } + + for (i = 0; i < y; ++i) { + for (j = 0; j < x; ++j) { + int out_index = INDEX(j, i); + int current_x, current_y; + float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + float accum_weight = 0.0f; + for (current_y = i - size_y; + current_y <= i + size_y; + ++current_y) + { + float weight; + if (current_y < -start_line || + current_y + start_line >= frame_height) + { + /* Out of bounds. */ + continue; + } + + for (current_x = j - size_x; + current_x <= j + size_x; + ++current_x) + { + int index = INDEX(current_x, current_y + start_line); + if (current_x < 0 || current_x >= frame_width) { + /* Out of bounds. */ + continue; + } + + if (size_x != 0 && size_y != 0) { + weight = gausstab_x[current_x - j + size_x] * + gausstab_y[current_y - i + size_y]; + } + else if (size_x == 0) { + weight = gausstab_y[current_y - i + size_y]; + } + else { + weight = gausstab_x[current_x - j + size_x]; + } + madd_v4_v4fl(accum, &rect[index], weight); + accum_weight += weight; + } + } + mul_v4_v4fl(&out[out_index], accum, 1.0f / accum_weight); + } + } + + MEM_freeN(gausstab_x); + if (gausstab_x != gausstab_y) { + MEM_freeN(gausstab_y); + } +#undef INDEX +} + +static void do_gaussian_blur_effect(const SeqRenderData *context, + Sequence *seq, + float UNUSED(cfra), + float UNUSED(facf0), + float UNUSED(facf1), + ImBuf *ibuf1, + ImBuf *ibuf2, + ImBuf *UNUSED(ibuf3), + int start_line, + int total_lines, + ImBuf *out) +{ + if (out->rect_float) { + float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; + + slice_get_float_buffers(context, + ibuf1, ibuf2, + NULL, + out, + start_line, + &rect1, + &rect2, + NULL, + &rect_out); + + do_gaussian_blur_effect_float(seq, + start_line, + context->rectx, + total_lines, + context->rectx, + context->recty, + ibuf1->rect_float, + rect_out); + } + else { + unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; + + slice_get_byte_buffers(context, + ibuf1, ibuf2, + NULL, + out, + start_line, + &rect1, + &rect2, + NULL, + &rect_out); + + do_gaussian_blur_effect_byte(seq, + start_line, + context->rectx, + total_lines, + context->rectx, + context->recty, + (unsigned char *) ibuf1->rect, + rect_out); + } +} + /*********************** sequence effect factory *************************/ static void init_noop(Sequence *UNUSED(seq)) @@ -2767,6 +3061,15 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type) rval.early_out = early_out_adjustment; rval.execute = do_adjustment; break; + case SEQ_TYPE_GAUSSIAN_BLUR: + rval.multithreaded = true; + rval.init = init_gaussian_blur_effect; + rval.num_inputs = num_inputs_gaussian_blur; + rval.free = free_gaussian_blur_effect; + rval.copy = copy_gaussian_blur_effect; + rval.early_out = early_out_gaussian_blur; + rval.execute_slice = do_gaussian_blur_effect; + break; } return rval; diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index f5efe04951f..dedf5e8bd72 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -758,7 +758,7 @@ void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, const bool lock_r int prev_startdisp = 0, prev_enddisp = 0; /* note: don't rename the strip, will break animation curves */ - if (ELEM7(seq->type, + if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE, SEQ_TYPE_META, SEQ_TYPE_MOVIECLIP, SEQ_TYPE_MASK) == 0) { @@ -994,28 +994,29 @@ void BKE_sequence_base_unique_name_recursive(ListBase *seqbasep, Sequence *seq) static const char *give_seqname_by_type(int type) { switch (type) { - case SEQ_TYPE_META: return "Meta"; - case SEQ_TYPE_IMAGE: return "Image"; - case SEQ_TYPE_SCENE: return "Scene"; - case SEQ_TYPE_MOVIE: return "Movie"; - case SEQ_TYPE_MOVIECLIP: return "Clip"; - case SEQ_TYPE_MASK: return "Mask"; - case SEQ_TYPE_SOUND_RAM: return "Audio"; - case SEQ_TYPE_CROSS: return "Cross"; - case SEQ_TYPE_GAMCROSS: return "Gamma Cross"; - case SEQ_TYPE_ADD: return "Add"; - case SEQ_TYPE_SUB: return "Sub"; - case SEQ_TYPE_MUL: return "Mul"; - case SEQ_TYPE_ALPHAOVER: return "Alpha Over"; - case SEQ_TYPE_ALPHAUNDER: return "Alpha Under"; - case SEQ_TYPE_OVERDROP: return "Over Drop"; - case SEQ_TYPE_WIPE: return "Wipe"; - case SEQ_TYPE_GLOW: return "Glow"; - case SEQ_TYPE_TRANSFORM: return "Transform"; - case SEQ_TYPE_COLOR: return "Color"; - case SEQ_TYPE_MULTICAM: return "Multicam"; - case SEQ_TYPE_ADJUSTMENT: return "Adjustment"; - case SEQ_TYPE_SPEED: return "Speed"; + case SEQ_TYPE_META: return "Meta"; + case SEQ_TYPE_IMAGE: return "Image"; + case SEQ_TYPE_SCENE: return "Scene"; + case SEQ_TYPE_MOVIE: return "Movie"; + case SEQ_TYPE_MOVIECLIP: return "Clip"; + case SEQ_TYPE_MASK: return "Mask"; + case SEQ_TYPE_SOUND_RAM: return "Audio"; + case SEQ_TYPE_CROSS: return "Cross"; + case SEQ_TYPE_GAMCROSS: return "Gamma Cross"; + case SEQ_TYPE_ADD: return "Add"; + case SEQ_TYPE_SUB: return "Sub"; + case SEQ_TYPE_MUL: return "Mul"; + case SEQ_TYPE_ALPHAOVER: return "Alpha Over"; + case SEQ_TYPE_ALPHAUNDER: return "Alpha Under"; + case SEQ_TYPE_OVERDROP: return "Over Drop"; + case SEQ_TYPE_WIPE: return "Wipe"; + case SEQ_TYPE_GLOW: return "Glow"; + case SEQ_TYPE_TRANSFORM: return "Transform"; + case SEQ_TYPE_COLOR: return "Color"; + case SEQ_TYPE_MULTICAM: return "Multicam"; + case SEQ_TYPE_ADJUSTMENT: return "Adjustment"; + case SEQ_TYPE_SPEED: return "Speed"; + case SEQ_TYPE_GAUSSIAN_BLUR: return "Gaussian Blur"; default: return NULL; } @@ -2224,7 +2225,7 @@ static ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh, con init_data.out = out; IMB_processor_apply_threaded(out->y, sizeof(RenderEffectThread), &init_data, - render_effect_execute_init_handle, render_effect_execute_do_thread); + render_effect_execute_init_handle, render_effect_execute_do_thread); return out; } @@ -2808,7 +2809,7 @@ static ImBuf *seq_render_strip(const SeqRenderData *context, Sequence *seq, floa float nr = give_stripelem_index(seq, cfra); /* all effects are handled similarly with the exception of speed effect */ int type = (seq->type & SEQ_TYPE_EFFECT && seq->type != SEQ_TYPE_SPEED) ? SEQ_TYPE_EFFECT : seq->type; - bool is_preprocessed = !ELEM3(type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_SCENE); + bool is_preprocessed = !ELEM(type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_SCENE); ibuf = BKE_sequencer_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF); @@ -2875,7 +2876,7 @@ static bool seq_must_swap_input_in_blend_mode(Sequence *seq) /* bad hack, to fix crazy input ordering of * those two effects */ - if (ELEM3(seq->blend_mode, SEQ_TYPE_ALPHAOVER, SEQ_TYPE_ALPHAUNDER, SEQ_TYPE_OVERDROP)) { + if (ELEM(seq->blend_mode, SEQ_TYPE_ALPHAOVER, SEQ_TYPE_ALPHAUNDER, SEQ_TYPE_OVERDROP)) { swap_input = true; } @@ -2960,7 +2961,7 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ListBase *seq /* Some of the blend modes are unclear how to apply with only single input, * or some of them will just produce an empty result.. */ - if (ELEM3(seq->blend_mode, SEQ_BLEND_REPLACE, SEQ_TYPE_CROSS, SEQ_TYPE_ALPHAOVER)) { + if (ELEM(seq->blend_mode, SEQ_BLEND_REPLACE, SEQ_TYPE_CROSS, SEQ_TYPE_ALPHAOVER)) { int early_out; if (seq->blend_mode == SEQ_BLEND_REPLACE) { early_out = EARLY_NO_INPUT; @@ -3688,7 +3689,7 @@ Sequence *BKE_sequencer_foreground_frame_get(Scene *scene, int frame) if (seq->flag & SEQ_MUTE || seq->startdisp > frame || seq->enddisp <= frame) continue; /* only use elements you can see - not */ - if (ELEM5(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_META, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIE, SEQ_TYPE_COLOR)) { + if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_META, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIE, SEQ_TYPE_COLOR)) { if (seq->machine > best_machine) { best_seq = seq; best_machine = seq->machine; diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index e2cc7b84f95..d2a4d15a2c6 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -50,6 +50,7 @@ #include "BKE_lattice.h" #include "BKE_deform.h" +#include "BKE_mesh.h" /* for OMP limits. */ #include "BKE_subsurf.h" #include "BKE_editmesh.h" @@ -65,57 +66,6 @@ /* Util macros */ #define OUT_OF_MEMORY() ((void)printf("Shrinkwrap: Out of memory\n")) -/* get derived mesh */ -/* TODO is anyfunction that does this? returning the derivedFinal without we caring if its in edit mode or not? */ -DerivedMesh *object_get_derived_final(Object *ob, bool for_render) -{ - Mesh *me = ob->data; - BMEditMesh *em = me->edit_btmesh; - - if (for_render) { - /* TODO(sergey): use proper derived render here in the future. */ - return ob->derivedFinal; - } - - if (em) { - DerivedMesh *dm = em->derivedFinal; - return dm; - } - - return ob->derivedFinal; -} - -/* Space transform */ -void space_transform_from_matrixs(SpaceTransform *data, float local[4][4], float target[4][4]) -{ - float itarget[4][4]; - invert_m4_m4(itarget, target); - mul_m4_m4m4(data->local2target, itarget, local); - invert_m4_m4(data->target2local, data->local2target); -} - -void space_transform_apply(const SpaceTransform *data, float co[3]) -{ - mul_v3_m4v3(co, ((SpaceTransform *)data)->local2target, co); -} - -void space_transform_invert(const SpaceTransform *data, float co[3]) -{ - mul_v3_m4v3(co, ((SpaceTransform *)data)->target2local, co); -} - -static void space_transform_apply_normal(const SpaceTransform *data, float no[3]) -{ - mul_mat3_m4_v3(((SpaceTransform *)data)->local2target, no); - normalize_v3(no); /* TODO: could we just determine de scale value from the matrix? */ -} - -static void space_transform_invert_normal(const SpaceTransform *data, float no[3]) -{ - mul_mat3_m4_v3(((SpaceTransform *)data)->target2local, no); - normalize_v3(no); /* TODO: could we just determine de scale value from the matrix? */ -} - /* * Shrinkwrap to the nearest vertex * @@ -135,12 +85,12 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) OUT_OF_MEMORY(); return; } - + /* Setup nearest */ nearest.index = -1; nearest.dist_sq = FLT_MAX; #ifndef __APPLE__ -#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(treeData, calc) schedule(static) +#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(treeData, calc) schedule(static) if(calc->numVerts > BKE_MESH_OMP_LIMIT) #endif for (i = 0; i < calc->numVerts; ++i) { float *co = calc->vertexCos[i]; @@ -158,7 +108,7 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) else { copy_v3_v3(tmp_co, co); } - space_transform_apply(&calc->local2target, tmp_co); + BLI_space_transform_apply(&calc->local2target, tmp_co); /* Use local proximity heuristics (to reduce the nearest search) * @@ -184,7 +134,7 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) /* Convert the coordinates back to mesh coordinates */ copy_v3_v3(tmp_co, nearest.co); - space_transform_invert(&calc->local2target, tmp_co); + BLI_space_transform_invert(&calc->local2target, tmp_co); interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */ } @@ -223,11 +173,11 @@ bool BKE_shrinkwrap_project_normal( /* Apply space transform (TODO readjust dist) */ if (transf) { copy_v3_v3(tmp_co, vert); - space_transform_apply(transf, tmp_co); + BLI_space_transform_apply(transf, tmp_co); co = tmp_co; copy_v3_v3(tmp_no, dir); - space_transform_apply_normal(transf, tmp_no); + BLI_space_transform_apply_normal(transf, tmp_no); no = tmp_no; #ifdef USE_DIST_CORRECT @@ -246,7 +196,7 @@ bool BKE_shrinkwrap_project_normal( if (hit_tmp.index != -1) { /* invert the normal first so face culling works on rotated objects */ if (transf) { - space_transform_invert_normal(transf, hit_tmp.no); + BLI_space_transform_invert_normal(transf, hit_tmp.no); } if (options & (MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE | MOD_SHRINKWRAP_CULL_TARGET_BACKFACE)) { @@ -261,7 +211,7 @@ bool BKE_shrinkwrap_project_normal( if (transf) { /* Inverting space transform (TODO make coeherent with the initial dist readjust) */ - space_transform_invert(transf, hit_tmp.co); + BLI_space_transform_invert(transf, hit_tmp.co); #ifdef USE_DIST_CORRECT hit_tmp.dist = len_v3v3(vert, hit_tmp.co); #endif @@ -326,7 +276,7 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for auxMesh = object_get_derived_final(calc->smd->auxTarget, for_render); if (!auxMesh) return; - SPACE_TRANSFORM_SETUP(&local2aux, calc->ob, calc->smd->auxTarget); + BLI_SPACE_TRANSFORM_SETUP(&local2aux, calc->ob, calc->smd->auxTarget); } /* After sucessufuly build the trees, start projection vertexs */ @@ -335,7 +285,7 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for { #ifndef __APPLE__ -#pragma omp parallel for private(i, hit) schedule(static) +#pragma omp parallel for private(i, hit) schedule(static) if (calc->numVerts > BKE_MESH_OMP_LIMIT) #endif for (i = 0; i < calc->numVerts; ++i) { float *co = calc->vertexCos[i]; @@ -445,7 +395,7 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) /* Find the nearest vertex */ #ifndef __APPLE__ -#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(calc, treeData) schedule(static) +#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(calc, treeData) schedule(static) if(calc->numVerts > BKE_MESH_OMP_LIMIT) #endif for (i = 0; i < calc->numVerts; ++i) { float *co = calc->vertexCos[i]; @@ -460,7 +410,7 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) else { copy_v3_v3(tmp_co, co); } - space_transform_apply(&calc->local2target, tmp_co); + BLI_space_transform_apply(&calc->local2target, tmp_co); /* Use local proximity heuristics (to reduce the nearest search) * @@ -494,7 +444,7 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) } /* Convert the coordinates back to mesh coordinates */ - space_transform_invert(&calc->local2target, tmp_co); + BLI_space_transform_invert(&calc->local2target, tmp_co); interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */ } } @@ -537,7 +487,7 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM /* TODO there might be several "bugs" on non-uniform scales matrixs * because it will no longer be nearest surface, not sphere projection * because space has been deformed */ - SPACE_TRANSFORM_SETUP(&calc.local2target, ob, smd->target); + BLI_SPACE_TRANSFORM_SETUP(&calc.local2target, ob, smd->target); /* TODO: smd->keepDist is in global units.. must change to local */ calc.keepDist = smd->keepDist; diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 11dc9150d8f..79c348ac181 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -41,6 +41,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" @@ -2291,18 +2292,23 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, DMSetDrawOptionsTex drawParams, DMSetDrawOptions drawParamsMapped, DMCompareDrawOptions compareDrawOptions, - void *userData) + void *userData, DMDrawFlag flag) { CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; CCGSubSurf *ss = ccgdm->ss; CCGKey key; MCol *mcol = dm->getTessFaceDataArray(dm, CD_PREVIEW_MCOL); MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE); + MTFace *tf_stencil_base = NULL; + MTFace *tf_stencil = NULL; + MTFace *tf_base; short (*lnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL); DMFlagMat *faceFlags = ccgdm->faceFlags; DMDrawOption draw_option; int i, totface, gridSize = ccgSubSurf_getGridSize(ss); int gridFaces = gridSize - 1; + int gridOffset = 0; + int mat_nr_cache = -1; (void) compareDrawOptions; @@ -2316,6 +2322,12 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, mcol = dm->getTessFaceDataArray(dm, CD_TEXTURE_MCOL); totface = ccgSubSurf_getNumFaces(ss); + + if (flag & DM_DRAW_USE_TEXPAINT_UV) { + int stencil = CustomData_get_stencil_layer(&dm->faceData, CD_MTFACE); + tf_stencil_base = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, stencil); + } + for (i = 0; i < totface; i++) { CCGFace *f = ccgdm->faceMap[i].face; int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f); @@ -2334,6 +2346,18 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, mat_nr = 0; } + /* texture painting, handle the correct uv layer here */ + if (flag & DM_DRAW_USE_TEXPAINT_UV) { + if (mat_nr != mat_nr_cache) { + tf_base = DM_paint_uvlayer_active_get(dm, mat_nr); + + mat_nr_cache = mat_nr; + } + tf = tf_base + gridOffset; + tf_stencil = tf_stencil_base + gridOffset; + gridOffset += gridFaces * gridFaces * numVerts; + } + if (drawParams) draw_option = drawParams(tf, (mcol != NULL), mat_nr); else if (index != ORIGINDEX_NONE) @@ -2374,26 +2398,31 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, float *d_co = CCG_grid_elem_co(&key, faceGridData, x, y + 1); if (tf) glTexCoord2fv(tf->uv[1]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf_stencil->uv[1]); if (cp) glColor3ub(cp[7], cp[6], cp[5]); glNormal3sv(ln[0][1]); glVertex3fv(d_co); if (tf) glTexCoord2fv(tf->uv[2]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf_stencil->uv[2]); if (cp) glColor3ub(cp[11], cp[10], cp[9]); glNormal3sv(ln[0][2]); glVertex3fv(c_co); if (tf) glTexCoord2fv(tf->uv[3]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf_stencil->uv[3]); if (cp) glColor3ub(cp[15], cp[14], cp[13]); glNormal3sv(ln[0][3]); glVertex3fv(b_co); if (tf) glTexCoord2fv(tf->uv[0]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf_stencil->uv[0]); if (cp) glColor3ub(cp[3], cp[2], cp[1]); glNormal3sv(ln[0][0]); glVertex3fv(a_co); if (tf) tf++; + if (tf_stencil) tf_stencil++; if (cp) cp += 16; ln++; } @@ -2409,17 +2438,20 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, b = CCG_grid_elem(&key, faceGridData, x, y + 1); if (tf) glTexCoord2fv(tf->uv[0]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf_stencil->uv[0]); if (cp) glColor3ub(cp[3], cp[2], cp[1]); glNormal3fv(CCG_elem_no(&key, a)); glVertex3fv(CCG_elem_co(&key, a)); if (tf) glTexCoord2fv(tf->uv[1]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf_stencil->uv[1]); if (cp) glColor3ub(cp[7], cp[6], cp[5]); glNormal3fv(CCG_elem_no(&key, b)); glVertex3fv(CCG_elem_co(&key, b)); if (x != gridFaces - 1) { if (tf) tf++; + if (tf_stencil) tf_stencil++; if (cp) cp += 16; } } @@ -2428,16 +2460,19 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, b = CCG_grid_elem(&key, faceGridData, x, y + 1); if (tf) glTexCoord2fv(tf->uv[3]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf_stencil->uv[3]); if (cp) glColor3ub(cp[15], cp[14], cp[13]); glNormal3fv(CCG_elem_no(&key, a)); glVertex3fv(CCG_elem_co(&key, a)); if (tf) glTexCoord2fv(tf->uv[2]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf_stencil->uv[2]); if (cp) glColor3ub(cp[11], cp[10], cp[9]); glNormal3fv(CCG_elem_no(&key, b)); glVertex3fv(CCG_elem_co(&key, b)); if (tf) tf++; + if (tf_stencil) tf_stencil++; if (cp) cp += 16; glEnd(); @@ -2456,22 +2491,27 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, ccgDM_glNormalFast(a_co, b_co, c_co, d_co); if (tf) glTexCoord2fv(tf->uv[1]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf_stencil->uv[1]); if (cp) glColor3ub(cp[7], cp[6], cp[5]); glVertex3fv(d_co); if (tf) glTexCoord2fv(tf->uv[2]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf_stencil->uv[2]); if (cp) glColor3ub(cp[11], cp[10], cp[9]); glVertex3fv(c_co); if (tf) glTexCoord2fv(tf->uv[3]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf_stencil->uv[3]); if (cp) glColor3ub(cp[15], cp[14], cp[13]); glVertex3fv(b_co); if (tf) glTexCoord2fv(tf->uv[0]); + if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE1, tf_stencil->uv[0]); if (cp) glColor3ub(cp[3], cp[2], cp[1]); glVertex3fv(a_co); if (tf) tf++; + if (tf_stencil) tf_stencil++; if (cp) cp += 16; } } @@ -2484,17 +2524,17 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, static void ccgDM_drawFacesTex(DerivedMesh *dm, DMSetDrawOptionsTex setDrawOptions, DMCompareDrawOptions compareDrawOptions, - void *userData) + void *userData, DMDrawFlag flag) { - ccgDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData); + ccgDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData, flag); } static void ccgDM_drawMappedFacesTex(DerivedMesh *dm, DMSetDrawOptions setDrawOptions, DMCompareDrawOptions compareDrawOptions, - void *userData) + void *userData, DMDrawFlag flag) { - ccgDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData); + ccgDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData, flag); } static void ccgDM_drawUVEdges(DerivedMesh *dm) diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 90687ef9916..47b615c2573 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -2697,7 +2697,7 @@ void txt_indent(Text *text) /* hardcoded: TXT_TABSIZE = 4 spaces: */ int spaceslen = TXT_TABSIZE; - if (ELEM3(NULL, text, text->curl, text->sell)) { + if (ELEM(NULL, text, text->curl, text->sell)) { return; } @@ -2764,7 +2764,7 @@ void txt_unindent(Text *text) /* hardcoded: TXT_TABSIZE = 4 spaces: */ int spaceslen = TXT_TABSIZE; - if (ELEM3(NULL, text, text->curl, text->sell)) { + if (ELEM(NULL, text, text->curl, text->sell)) { return; } diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index bb956cb085c..77f62771360 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -145,12 +145,12 @@ void init_tex_mapping(TexMapping *texmap) if (texmap->type == TEXMAP_TYPE_TEXTURE) { /* to transform a texture, the inverse transform needs * to be applied to the texture coordinate */ - mul_serie_m4(texmap->mat, tmat, rmat, smat, 0, 0, 0, 0, 0); + mul_m4_series(texmap->mat, tmat, rmat, smat); invert_m4(texmap->mat); } else if (texmap->type == TEXMAP_TYPE_POINT) { /* forward transform */ - mul_serie_m4(texmap->mat, tmat, rmat, smat, 0, 0, 0, 0, 0); + mul_m4_series(texmap->mat, tmat, rmat, smat); } else if (texmap->type == TEXMAP_TYPE_VECTOR) { /* no translation for vectors */ @@ -474,7 +474,8 @@ void BKE_texture_free(Tex *tex) void default_tex(Tex *tex) { - tex->type = TEX_CLOUDS; + tex->type = TEX_IMAGE; + tex->ima = NULL; tex->stype = 0; tex->flag = TEX_CHECKER_ODD; tex->imaflag = TEX_INTERPOL | TEX_MIPMAP | TEX_USEALPHA; @@ -592,7 +593,7 @@ Tex *add_texture(Main *bmain, const char *name) void default_mtex(MTex *mtex) { - mtex->texco = TEXCO_ORCO; + mtex->texco = TEXCO_UV; mtex->mapto = MAP_COL; mtex->object = NULL; mtex->projx = PROJ_X; diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c index 9ede39fd666..eb224020977 100644 --- a/source/blender/blenkernel/intern/tracking_stabilize.c +++ b/source/blender/blenkernel/intern/tracking_stabilize.c @@ -439,6 +439,6 @@ void BKE_tracking_stabilization_data_to_mat4(int width, int height, float aspect rotate_m4(rotation_mat, 'Z', angle); /* rotation matrix */ /* compose transformation matrix */ - mul_serie_m4(mat, translation_mat, center_mat, aspect_mat, rotation_mat, inv_aspect_mat, - scale_mat, inv_center_mat, NULL); + mul_m4_series(mat, translation_mat, center_mat, aspect_mat, rotation_mat, inv_aspect_mat, + scale_mat, inv_center_mat); } diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c index a9f040b8650..aef44993912 100644 --- a/source/blender/blenkernel/intern/writeavi.c +++ b/source/blender/blenkernel/intern/writeavi.c @@ -110,7 +110,7 @@ bMovieHandle *BKE_movie_handle_get(const char imtype) } #endif #ifdef WITH_FFMPEG - if (ELEM4(imtype, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_XVID, R_IMF_IMTYPE_THEORA)) { + if (ELEM(imtype, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_XVID, R_IMF_IMTYPE_THEORA)) { mh.start_movie = BKE_ffmpeg_start; mh.append_movie = BKE_ffmpeg_append; mh.end_movie = BKE_ffmpeg_end; diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 00dfae9e72a..ef3c84f661d 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -30,13 +30,6 @@ #include <string.h> #include <stdio.h> -#if defined(_WIN32) && defined(DEBUG) && !defined(__MINGW32__) && !defined(__CYGWIN__) -/* This does not seem necessary or present on MSVC 8, but may be needed in earlier versions? */ -# if _MSC_VER < 1400 -# include <stdint.h> -# endif -#endif - #include <stdlib.h> #include <libavformat/avformat.h> diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h index 2d1e1d84882..b574447558c 100644 --- a/source/blender/blenlib/BLI_fileops.h +++ b/source/blender/blenlib/BLI_fileops.h @@ -62,7 +62,7 @@ int BLI_create_symlink(const char *path, const char *to); /* keep in sync with the definition of struct direntry in BLI_fileops_types.h */ #ifdef WIN32 -# if (defined(_MSC_VER) && (_MSC_VER >= 1500)) || defined(__MINGW64__) +# if defined(_MSC_VER) || defined(__MINGW64__) typedef struct _stat64 BLI_stat_t; # elif defined(__MINGW32__) typedef struct _stati64 BLI_stat_t; diff --git a/source/blender/blenlib/BLI_fileops_types.h b/source/blender/blenlib/BLI_fileops_types.h index 53c9fa16b70..0e6eab687ad 100644 --- a/source/blender/blenlib/BLI_fileops_types.h +++ b/source/blender/blenlib/BLI_fileops_types.h @@ -46,7 +46,7 @@ struct direntry { char *relname; char *path; #ifdef WIN32 /* keep in sync with the definition of BLI_stat_t in BLI_fileops.h */ -# if (defined(_MSC_VER) && (_MSC_VER >= 1500)) || defined(__MINGW64__) +# if defined(_MSC_VER) || defined(__MINGW64__) struct _stat64 s; # elif defined(__MINGW32__) struct _stati64 s; diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h index dc29a129dbf..313c4190a30 100644 --- a/source/blender/blenlib/BLI_ghash.h +++ b/source/blender/blenlib/BLI_ghash.h @@ -139,6 +139,9 @@ unsigned int BLI_ghashutil_uinthash(unsigned int key); unsigned int BLI_ghashutil_uinthash_v4(const unsigned int key[4]); #define BLI_ghashutil_inthash_v4_p \ ((GSetHashFP)BLI_ghashutil_uinthash_v4) +int BLI_ghashutil_uinthash_v4_cmp(const void *a, const void *b); +#define BLI_ghashutil_inthash_v4_cmp \ + BLI_ghashutil_uinthash_v4_cmp unsigned int BLI_ghashutil_inthash_p(const void *ptr); int BLI_ghashutil_intcmp(const void *a, const void *b); diff --git a/source/blender/blenlib/BLI_gsqueue.h b/source/blender/blenlib/BLI_gsqueue.h index d17897df665..4600d6f6325 100644 --- a/source/blender/blenlib/BLI_gsqueue.h +++ b/source/blender/blenlib/BLI_gsqueue.h @@ -30,8 +30,6 @@ /** \file BLI_gsqueue.h * \ingroup bli - * \brief A generic structure queue (a queue for fixed length - * (generally small) structures. */ typedef struct _GSQueue GSQueue; @@ -46,4 +44,3 @@ void BLI_gsqueue_pushback(GSQueue *gq, const void *item); void BLI_gsqueue_free(GSQueue *gq); #endif /* __BLI_GSQUEUE_H__ */ - diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h index 94f5303e705..0a6e2eae1ed 100644 --- a/source/blender/blenlib/BLI_listbase.h +++ b/source/blender/blenlib/BLI_listbase.h @@ -76,8 +76,8 @@ void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1); void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1, 2); void BLI_duplicatelist(struct ListBase *dst, const struct ListBase *src) ATTR_NONNULL(1, 2); void BLI_listbase_reverse(struct ListBase *lb) ATTR_NONNULL(1); -void BLI_rotatelist_first(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2); -void BLI_rotatelist_last(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2); +void BLI_listbase_rotate_first(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2); +void BLI_listbase_rotate_last(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2); /** * Utility functions to avoid first/last references inline all over. @@ -111,27 +111,27 @@ for ((lb_iter) = (lb).first, (indexvar) = BLI_countlist(lb); (lb_iter); (lb_iter * * \code{.c} * - * LISTBASE_CIRCULAR_FORWARD_BEGIN (listbase, item, item_init) { + * BLI_LISTBASE_CIRCULAR_FORWARD_BEGIN (listbase, item, item_init) { * ...operate on marker... * } - * LISTBASE_CIRCULAR_FORWARD_END (listbase, item, item_init); + * BLI_LISTBASE_CIRCULAR_FORWARD_END (listbase, item, item_init); * * \endcode */ -#define LISTBASE_CIRCULAR_FORWARD_BEGIN(lb, lb_iter, lb_init) \ +#define BLI_LISTBASE_CIRCULAR_FORWARD_BEGIN(lb, lb_iter, lb_init) \ if ((lb)->first && (lb_init || (lb_init = (lb)->first))) { \ lb_iter = lb_init; \ do { -#define LISTBASE_CIRCULAR_FORWARD_END(lb, lb_iter, lb_init) \ +#define BLI_LISTBASE_CIRCULAR_FORWARD_END(lb, lb_iter, lb_init) \ } while ((lb_iter = (lb_iter)->next ? (lb_iter)->next : (lb)->first), \ (lb_iter != lb_init)); \ } -#define LISTBASE_CIRCULAR_BACKWARD_BEGIN(lb, lb_iter, lb_init) \ +#define BLI_LISTBASE_CIRCULAR_BACKWARD_BEGIN(lb, lb_iter, lb_init) \ if ((lb)->last && (lb_init || (lb_init = (lb)->last))) { \ lb_iter = lb_init; \ do { -#define LISTBASE_CIRCULAR_BACKWARD_END(lb, lb_iter, lb_init) \ +#define BLI_LISTBASE_CIRCULAR_BACKWARD_END(lb, lb_iter, lb_init) \ } while ((lb_iter = (lb_iter)->prev ? (lb_iter)->prev : (lb)->last), \ (lb_iter != lb_init)); \ } diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h index 54e9349f1f8..b639df4da84 100644 --- a/source/blender/blenlib/BLI_math_base.h +++ b/source/blender/blenlib/BLI_math_base.h @@ -147,13 +147,7 @@ static const int NAN_INT = 0x7FC00000; #ifdef WIN32 # if defined(_MSC_VER) -# if (_MSC_VER < 1800) && !defined(isnan) -# define isnan(n) _isnan(n) -# endif # define finite(n) _finite(n) -# if (_MSC_VER < 1800) && !defined(hypot) -# define hypot(a, b) _hypot(a, b) -# endif # endif #endif @@ -163,7 +157,7 @@ static const int NAN_INT = 0x7FC00000; #ifndef CHECK_TYPE #ifdef __GNUC__ #define CHECK_TYPE(var, type) { \ - __typeof(var) *__tmp; \ + typeof(var) *__tmp; \ __tmp = (type *)NULL; \ (void)__tmp; \ } (void)0 @@ -241,11 +235,6 @@ MINLINE int mod_i(int i, int n); MINLINE unsigned int highest_order_bit_i(unsigned int n); MINLINE unsigned short highest_order_bit_s(unsigned short n); -#if defined(_MSC_VER) && (_MSC_VER < 1800) -extern double copysign(double x, double y); -extern double round(double x); -#endif - double double_round(double x, int ndigits); #ifdef BLI_MATH_GCC_WARN_PRAGMA diff --git a/source/blender/blenlib/BLI_math_color_blend.h b/source/blender/blenlib/BLI_math_color_blend.h index d7e9bf50eae..2535a31ccc4 100644 --- a/source/blender/blenlib/BLI_math_color_blend.h +++ b/source/blender/blenlib/BLI_math_color_blend.h @@ -49,6 +49,24 @@ MINLINE void blend_color_lighten_byte(unsigned char dst[4], const unsigned char MINLINE void blend_color_darken_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4]); MINLINE void blend_color_erase_alpha_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4]); MINLINE void blend_color_add_alpha_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4]); + +MINLINE void blend_color_overlay_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_hardlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_burn_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_linearburn_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_dodge_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_screen_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_softlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_pinlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_linearlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_vividlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_difference_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_exclusion_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_color_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_hue_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_saturation_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); +MINLINE void blend_color_luminosity_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]); + MINLINE void blend_color_interpolate_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4], float t); MINLINE void blend_color_mix_float(float dst[4], const float src1[4], const float src2[4]); @@ -59,6 +77,24 @@ MINLINE void blend_color_lighten_float(float dst[4], const float src1[4], const MINLINE void blend_color_darken_float(float dst[4], const float src1[4], const float src2[4]); MINLINE void blend_color_erase_alpha_float(float dst[4], const float src1[4], const float src2[4]); MINLINE void blend_color_add_alpha_float(float dst[4], const float src1[4], const float src2[4]); + +MINLINE void blend_color_overlay_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_hardlight_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_burn_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_linearburn_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_dodge_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_screen_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_softlight_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_pinlight_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_linearlight_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_vividlight_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_difference_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_exclusion_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_color_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_hue_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_saturation_float(float dst[4], const float src1[4], const float src2[2]); +MINLINE void blend_color_luminosity_float(float dst[4], const float src1[4], const float src2[2]); + MINLINE void blend_color_interpolate_float(float dst[4], const float src1[4], const float src2[4], float t); #if BLI_MATH_DO_INLINE diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index ed0777aceea..57cde5637d3 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -169,6 +169,8 @@ int isect_point_tri_v2(const float pt[2], const float v1[2], const float v2[2], bool isect_point_tri_v2_cw(const float pt[2], const float v1[2], const float v2[2], const float v3[2]); int isect_point_tri_v2_int(const int x1, const int y1, const int x2, const int y2, const int a, const int b); bool isect_point_tri_prism_v3(const float p[3], const float v1[3], const float v2[3], const float v3[3]); +bool isect_point_tri_v3(const float p[3], const float v1[3], const float v2[3], const float v3[3], + float r_vi[3]); /* axis-aligned bounding box */ bool isect_aabb_aabb_v3(const float min1[3], const float max1[3], const float min2[3], const float max2[3]); diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h index 49183934412..7bcaab1f939 100644 --- a/source/blender/blenlib/BLI_math_matrix.h +++ b/source/blender/blenlib/BLI_math_matrix.h @@ -34,6 +34,8 @@ extern "C" { #endif +#include "BLI_compiler_attrs.h" + /********************************* Init **************************************/ void zero_m3(float R[3][3]); @@ -67,12 +69,33 @@ void mul_m4_m4m3(float R[4][4], float A[4][4], float B[3][3]); void mul_m4_m4m4(float R[4][4], float A[4][4], float B[4][4]); void mul_m3_m3m4(float R[3][3], float A[4][4], float B[3][3]); -void mul_serie_m3(float R[3][3], - float M1[3][3], float M2[3][3], float M3[3][3], float M4[3][3], - float M5[3][3], float M6[3][3], float M7[3][3], float M8[3][3]); -void mul_serie_m4(float R[4][4], - float M1[4][4], float M2[4][4], float M3[4][4], float M4[4][4], - float M5[4][4], float M6[4][4], float M7[4][4], float M8[4][4]); +/* mul_m3_series */ +void _va_mul_m3_series_3(float R[3][3], float M1[3][3], float M2[3][3]) ATTR_NONNULL(); +void _va_mul_m3_series_4(float R[3][3], float M1[3][3], float M2[3][3], float M3[3][3]) ATTR_NONNULL(); +void _va_mul_m3_series_5(float R[3][3], float M1[3][3], float M2[3][3], float M3[3][3], float M4[3][3]) ATTR_NONNULL(); +void _va_mul_m3_series_6(float R[3][3], float M1[3][3], float M2[3][3], float M3[3][3], float M4[3][3], + float M5[3][3]) ATTR_NONNULL(); +void _va_mul_m3_series_7(float R[3][3], float M1[3][3], float M2[3][3], float M3[3][3], float M4[3][3], + float M5[3][3], float M6[3][3]) ATTR_NONNULL(); +void _va_mul_m3_series_8(float R[3][3], float M1[3][3], float M2[3][3], float M3[3][3], float M4[3][3], + float M5[3][3], float M6[3][3], float M7[3][3]) ATTR_NONNULL(); +void _va_mul_m3_series_9(float R[3][3], float M1[3][3], float M2[3][3], float M3[3][3], float M4[3][3], + float M5[3][3], float M6[3][3], float M7[3][3], float M8[3][3]) ATTR_NONNULL(); +/* mul_m4_series */ +void _va_mul_m4_series_3(float R[4][4], float M1[4][4], float M2[4][4]) ATTR_NONNULL(); +void _va_mul_m4_series_4(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4]) ATTR_NONNULL(); +void _va_mul_m4_series_5(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4], float M4[4][4]) ATTR_NONNULL(); +void _va_mul_m4_series_6(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4], float M4[4][4], + float M5[4][4]) ATTR_NONNULL(); +void _va_mul_m4_series_7(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4], float M4[4][4], + float M5[4][4], float M6[4][4]) ATTR_NONNULL(); +void _va_mul_m4_series_8(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4], float M4[4][4], + float M5[4][4], float M6[4][4], float M7[4][4]) ATTR_NONNULL(); +void _va_mul_m4_series_9(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4], float M4[4][4], + float M5[4][4], float M6[4][4], float M7[4][4], float M8[4][4]) ATTR_NONNULL(); + +#define mul_m3_series(...) VA_NARGS_CALL_OVERLOAD(_va_mul_m3_series_, __VA_ARGS__) +#define mul_m4_series(...) VA_NARGS_CALL_OVERLOAD(_va_mul_m4_series_, __VA_ARGS__) void mul_m4_v3(float M[4][4], float r[3]); void mul_v3_m4v3(float r[3], float M[4][4], const float v[3]); @@ -201,6 +224,22 @@ bool is_negative_m4(float mat[4][4]); bool is_zero_m3(float mat[3][3]); bool is_zero_m4(float mat[4][4]); +/* SpaceTransform helper */ +typedef struct SpaceTransform { + float local2target[4][4]; + float target2local[4][4]; + +} SpaceTransform; + +void BLI_space_transform_from_matrices(struct SpaceTransform *data, float local[4][4], float target[4][4]); +void BLI_space_transform_apply(const struct SpaceTransform *data, float co[3]); +void BLI_space_transform_invert(const struct SpaceTransform *data, float co[3]); +void BLI_space_transform_apply_normal(const struct SpaceTransform *data, float no[3]); +void BLI_space_transform_invert_normal(const struct SpaceTransform *data, float no[3]); + +#define BLI_SPACE_TRANSFORM_SETUP(data, local, target) \ + BLI_space_transform_from_matrices((data), (local)->obmat, (target)->obmat) + /*********************************** Other ***********************************/ void print_m3(const char *str, float M[3][3]); diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index 942097e1ed6..6885a5aa351 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -65,6 +65,7 @@ MINLINE void swap_v4_v4(float a[4], float b[4]); MINLINE void copy_v2_v2_char(char r[2], const char a[2]); MINLINE void copy_v3_v3_char(char r[3], const char a[3]); MINLINE void copy_v4_v4_char(char r[4], const char a[4]); + /* short */ MINLINE void copy_v2_v2_short(short r[2], const short a[2]); MINLINE void copy_v3_v3_short(short r[3], const short a[3]); @@ -231,6 +232,7 @@ MINLINE bool equals_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_R MINLINE bool compare_v2v2(const float a[2], const float b[2], const float limit) ATTR_WARN_UNUSED_RESULT; MINLINE bool compare_v3v3(const float a[3], const float b[3], const float limit) ATTR_WARN_UNUSED_RESULT; MINLINE bool compare_len_v3v3(const float a[3], const float b[3], const float limit) ATTR_WARN_UNUSED_RESULT; +MINLINE bool compare_len_squared_v3v3(const float a[3], const float b[3], const float limit) ATTR_WARN_UNUSED_RESULT; MINLINE bool compare_v4v4(const float a[4], const float b[4], const float limit) ATTR_WARN_UNUSED_RESULT; MINLINE bool equals_v4v4(const float a[4], const float b[4]) ATTR_WARN_UNUSED_RESULT; diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h index 244c308a05c..3d82480d050 100644 --- a/source/blender/blenlib/BLI_path_util.h +++ b/source/blender/blenlib/BLI_path_util.h @@ -111,6 +111,7 @@ const char *BLI_last_slash(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_R int BLI_add_slash(char *string) ATTR_NONNULL(); void BLI_del_slash(char *string) ATTR_NONNULL(); const char *BLI_first_slash(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; +void BLI_path_native_slash(char *path) ATTR_NONNULL(); void BLI_getlastdir(const char *dir, char *last, const size_t maxlen); bool BLI_testextensie(const char *str, const char *ext) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; @@ -128,9 +129,6 @@ int BLI_stringdec(const char *string, char *head, char *start, unsigned short *n void BLI_stringenc(char *string, const char *head, const char *tail, unsigned short numlen, int pic); int BLI_split_name_num(char *left, int *nr, const char *name, const char delim); -/* make sure path separators conform to system one */ -void BLI_clean(char *path) ATTR_NONNULL(); - /** * dir can be any input, like from buttons, and this function * converts it to a regular full path. diff --git a/source/blender/blenlib/BLI_stackdefines.h b/source/blender/blenlib/BLI_stackdefines.h index 24cb043cd43..da9bf5ea04c 100644 --- a/source/blender/blenlib/BLI_stackdefines.h +++ b/source/blender/blenlib/BLI_stackdefines.h @@ -36,7 +36,7 @@ # define _STACK_SWAP_TOTALLOC(stack_a, stack_b) SWAP(unsigned int, _##stack_a##_totalloc, _##stack_b##_totalloc) #else # define STACK_DECLARE(stack) unsigned int _##stack##_index -# define STACK_INIT(stack, tot) ((void)stack, (void)((_##stack##_index) = 0), (void)(tot)) +# define STACK_INIT(stack, tot) ((void)stack, (void)((_##stack##_index) = 0), (void)(0 ? tot : 0)) # define _STACK_SIZETEST(stack, off) (void)(stack), (void)(off) # define _STACK_SWAP_TOTALLOC(stack_a, stack_b) (void)(stack_a), (void)(stack_b) #endif @@ -57,9 +57,12 @@ #define STACK_PEEK_PTR(stack) (BLI_assert(_##stack##_index), &((stack)[_##stack##_index - 1])) /** remove any item from the stack, take care, re-orders */ #define STACK_REMOVE(stack, i) \ - _STACK_BOUNDSTEST(stack, i); \ - if (--_##stack##_index != i) { \ - stack[i] = stack[_##stack##_index]; \ + { \ + const unsigned int _i = i; \ + _STACK_BOUNDSTEST(stack, _i); \ + if (--_##stack##_index != _i) { \ + stack[_i] = stack[_##stack##_index]; \ + } \ } (void)0 #ifdef __GNUC__ #define STACK_SWAP(stack_a, stack_b) { \ diff --git a/source/blender/blenlib/BLI_sys_types.h b/source/blender/blenlib/BLI_sys_types.h index fcbed1daf66..c9cf33f2f69 100644 --- a/source/blender/blenlib/BLI_sys_types.h +++ b/source/blender/blenlib/BLI_sys_types.h @@ -47,127 +47,7 @@ extern "C" { #endif -/* MSVC 2010 and 2012 (>=1600) have stdint.h so we should use this for consistency */ -#if defined(_WIN32) && defined(_MSC_VER) && _MSC_VER <= 1500 - -/* The __intXX are built-in types of the visual compiler! So we don't - * need to include anything else here. */ - - -typedef signed __int8 int8_t; -typedef signed __int16 int16_t; -typedef signed __int32 int32_t; -typedef signed __int64 int64_t; - -typedef unsigned __int8 uint8_t; -typedef unsigned __int16 uint16_t; -typedef unsigned __int32 uint32_t; -typedef unsigned __int64 uint64_t; - -// 7.18.2 Limits of specified-width integer types - -#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 - -// 7.18.2.1 Limits of exact-width integer types -#define INT8_MIN ((int8_t)_I8_MIN) -#define INT8_MAX _I8_MAX -#define INT16_MIN ((int16_t)_I16_MIN) -#define INT16_MAX _I16_MAX -#define INT32_MIN ((int32_t)_I32_MIN) -#define INT32_MAX _I32_MAX -#define INT64_MIN ((int64_t)_I64_MIN) -#define INT64_MAX _I64_MAX -#define UINT8_MAX _UI8_MAX -#define UINT16_MAX _UI16_MAX -#define UINT32_MAX _UI32_MAX -#define UINT64_MAX _UI64_MAX - -// 7.18.2.2 Limits of minimum-width integer types -#define INT_LEAST8_MIN INT8_MIN -#define INT_LEAST8_MAX INT8_MAX -#define INT_LEAST16_MIN INT16_MIN -#define INT_LEAST16_MAX INT16_MAX -#define INT_LEAST32_MIN INT32_MIN -#define INT_LEAST32_MAX INT32_MAX -#define INT_LEAST64_MIN INT64_MIN -#define INT_LEAST64_MAX INT64_MAX -#define UINT_LEAST8_MAX UINT8_MAX -#define UINT_LEAST16_MAX UINT16_MAX -#define UINT_LEAST32_MAX UINT32_MAX -#define UINT_LEAST64_MAX UINT64_MAX - -// 7.18.2.3 Limits of fastest minimum-width integer types -#define INT_FAST8_MIN INT8_MIN -#define INT_FAST8_MAX INT8_MAX -#define INT_FAST16_MIN INT16_MIN -#define INT_FAST16_MAX INT16_MAX -#define INT_FAST32_MIN INT32_MIN -#define INT_FAST32_MAX INT32_MAX -#define INT_FAST64_MIN INT64_MIN -#define INT_FAST64_MAX INT64_MAX -#define UINT_FAST8_MAX UINT8_MAX -#define UINT_FAST16_MAX UINT16_MAX -#define UINT_FAST32_MAX UINT32_MAX -#define UINT_FAST64_MAX UINT64_MAX - -// 7.18.2.4 Limits of integer types capable of holding object pointers -#ifdef _WIN64 // [ -# define INTPTR_MIN INT64_MIN -# define INTPTR_MAX INT64_MAX -# define UINTPTR_MAX UINT64_MAX -#else // _WIN64 ][ -# define INTPTR_MIN INT32_MIN -# define INTPTR_MAX INT32_MAX -# define UINTPTR_MAX UINT32_MAX -#endif // _WIN64 ] - -// 7.18.2.5 Limits of greatest-width integer types -#define INTMAX_MIN INT64_MIN -#define INTMAX_MAX INT64_MAX -#define UINTMAX_MAX UINT64_MAX - -// 7.18.3 Limits of other integer types - -#ifdef _WIN64 // [ -# define PTRDIFF_MIN _I64_MIN -# define PTRDIFF_MAX _I64_MAX -#else // _WIN64 ][ -# define PTRDIFF_MIN _I32_MIN -# define PTRDIFF_MAX _I32_MAX -#endif // _WIN64 ] - -#define SIG_ATOMIC_MIN INT_MIN -#define SIG_ATOMIC_MAX INT_MAX - -#ifndef SIZE_MAX // [ -# ifdef _WIN64 // [ -# define SIZE_MAX _UI64_MAX -# else // _WIN64 ][ -# define SIZE_MAX _UI32_MAX -# endif // _WIN64 ] -#endif // SIZE_MAX ] - -#endif // __STDC_LIMIT_MACROS ] - -#ifndef _INTPTR_T_DEFINED -#ifdef _WIN64 -typedef __int64 intptr_t; -#else -typedef long intptr_t; -#endif -#define _INTPTR_T_DEFINED -#endif - -#ifndef _UINTPTR_T_DEFINED -#ifdef _WIN64 -typedef unsigned __int64 uintptr_t; -#else -typedef unsigned long uintptr_t; -#endif -#define _UINTPTR_T_DEFINED -#endif - -#elif defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD_kernel__) || defined(__GNU__) +#if defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD_kernel__) || defined(__GNU__) /* Linux-i386, Linux-Alpha, Linux-ppc */ #include <stdint.h> @@ -186,7 +66,7 @@ typedef uint64_t u_int64_t; #include <inttypes.h> /* MinGW and MSVC >= 2010 */ -#elif defined(FREE_WINDOWS) || (defined(_MSC_VER) && _MSC_VER >= 1600) +#elif defined(FREE_WINDOWS) || defined(_MSC_VER) #include <stdint.h> #else diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h index b6bdf26d5b6..683b3c4c438 100644 --- a/source/blender/blenlib/BLI_utildefines.h +++ b/source/blender/blenlib/BLI_utildefines.h @@ -40,6 +40,25 @@ #include <stdio.h> #endif + +/* varargs macros (keep first so others can use) */ +/* --- internal helpers --- */ +#define _VA_NARGS_GLUE(x, y) x y +#define _VA_NARGS_RETURN_COUNT(\ + _1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, _9_, _10_, _11_, _12_, _13_, _14_, _15_, _16_, \ + _17_, _18_, _19_, _20_, _21_, _22_, _23_, _24_, _25_, _26_, _27_, _28_, _29_, _30_, _31_, _32_, \ + count, ...) count +#define _VA_NARGS_EXPAND(args) _VA_NARGS_RETURN_COUNT args +#define _VA_NARGS_COUNT_MAX32(...) _VA_NARGS_EXPAND((__VA_ARGS__, \ + 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, \ + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) +#define _VA_NARGS_OVERLOAD_MACRO2(name, count) name##count +#define _VA_NARGS_OVERLOAD_MACRO1(name, count) _VA_NARGS_OVERLOAD_MACRO2(name, count) +#define _VA_NARGS_OVERLOAD_MACRO(name, count) _VA_NARGS_OVERLOAD_MACRO1(name, count) +/* --- expose for re-use --- */ +#define VA_NARGS_CALL_OVERLOAD(name, ...) \ + _VA_NARGS_GLUE(_VA_NARGS_OVERLOAD_MACRO(name, _VA_NARGS_COUNT_MAX32(__VA_ARGS__)), (__VA_ARGS__)) + /* useful for finding bad use of min/max */ #if 0 /* gcc only */ @@ -137,20 +156,20 @@ * ... the compiler optimizes away the temp var */ #ifdef __GNUC__ #define CHECK_TYPE(var, type) { \ - __typeof(var) *__tmp; \ + typeof(var) *__tmp; \ __tmp = (type *)NULL; \ (void)__tmp; \ } (void)0 #define CHECK_TYPE_PAIR(var_a, var_b) { \ - __typeof(var_a) *__tmp; \ - __tmp = (__typeof(var_b) *)NULL; \ + typeof(var_a) *__tmp; \ + __tmp = (typeof(var_b) *)NULL; \ (void)__tmp; \ } (void)0 #define CHECK_TYPE_PAIR_INLINE(var_a, var_b) ((void)({ \ - __typeof(var_a) *__tmp; \ - __tmp = (__typeof(var_b) *)NULL; \ + typeof(var_a) *__tmp; \ + __tmp = (typeof(var_b) *)NULL; \ (void)__tmp; \ })) @@ -161,8 +180,19 @@ #endif /* can be used in simple macros */ -#define CHECK_TYPE_INLINE(val, type) \ - ((void)(((type)0) != (val))) +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) +# define CHECK_TYPE_INLINE(val, type) \ + (void)((void)(((type)0) != (0 ? (val) : ((type)0))), \ + _Generic((val), type: 0, const type: 0)) +#else +# define CHECK_TYPE_INLINE(val, type) \ + ((void)(((type)0) != (0 ? (val) : ((type)0)))) +#endif + +#define CHECK_TYPE_NONCONST(var) { \ + void *non_const = 0 ? (var) : NULL; \ + (void)non_const; \ +} (void)0 #define SWAP(type, a, b) { \ type sw_ap; \ @@ -182,17 +212,42 @@ (b) = (tval); \ } (void)0 -/* ELEM#(a, ...): is the first arg equal any of the others */ -#define ELEM(a, b, c) ((a) == (b) || (a) == (c)) -#define ELEM3(a, b, c, d) (ELEM(a, b, c) || (a) == (d) ) -#define ELEM4(a, b, c, d, e) (ELEM(a, b, c) || ELEM(a, d, e) ) -#define ELEM5(a, b, c, d, e, f) (ELEM(a, b, c) || ELEM3(a, d, e, f) ) -#define ELEM6(a, b, c, d, e, f, g) (ELEM(a, b, c) || ELEM4(a, d, e, f, g) ) -#define ELEM7(a, b, c, d, e, f, g, h) (ELEM3(a, b, c, d) || ELEM4(a, e, f, g, h) ) -#define ELEM8(a, b, c, d, e, f, g, h, i) (ELEM4(a, b, c, d, e) || ELEM4(a, f, g, h, i) ) -#define ELEM9(a, b, c, d, e, f, g, h, i, j) (ELEM4(a, b, c, d, e) || ELEM5(a, f, g, h, i, j) ) -#define ELEM10(a, b, c, d, e, f, g, h, i, j, k) (ELEM4(a, b, c, d, e) || ELEM6(a, f, g, h, i, j, k) ) -#define ELEM11(a, b, c, d, e, f, g, h, i, j, k, l) (ELEM4(a, b, c, d, e) || ELEM7(a, f, g, h, i, j, k, l) ) +/* ELEM#(v, ...): is the first arg equal any others? */ +/* internal helpers*/ +#define _VA_ELEM3(v, a, b) \ + (((v) == (a)) || ((v) == (b))) +#define _VA_ELEM4(v, a, b, c) \ + (_VA_ELEM3(v, a, b) || ((v) == (c))) +#define _VA_ELEM5(v, a, b, c, d) \ + (_VA_ELEM4(v, a, b, c) || ((v) == (d))) +#define _VA_ELEM6(v, a, b, c, d, e) \ + (_VA_ELEM5(v, a, b, c, d) || ((v) == (e))) +#define _VA_ELEM7(v, a, b, c, d, e, f) \ + (_VA_ELEM6(v, a, b, c, d, e) || ((v) == (f))) +#define _VA_ELEM8(v, a, b, c, d, e, f, g) \ + (_VA_ELEM7(v, a, b, c, d, e, f) || ((v) == (g))) +#define _VA_ELEM9(v, a, b, c, d, e, f, g, h) \ + (_VA_ELEM8(v, a, b, c, d, e, f, g) || ((v) == (h))) +#define _VA_ELEM10(v, a, b, c, d, e, f, g, h, i) \ + (_VA_ELEM9(v, a, b, c, d, e, f, g, h) || ((v) == (i))) +#define _VA_ELEM11(v, a, b, c, d, e, f, g, h, i, j) \ + (_VA_ELEM10(v, a, b, c, d, e, f, g, h, i) || ((v) == (j))) +#define _VA_ELEM12(v, a, b, c, d, e, f, g, h, i, j, k) \ + (_VA_ELEM11(v, a, b, c, d, e, f, g, h, i, j) || ((v) == (k))) +#define _VA_ELEM13(v, a, b, c, d, e, f, g, h, i, j, k, l) \ + (_VA_ELEM12(v, a, b, c, d, e, f, g, h, i, j, k) || ((v) == (l))) +#define _VA_ELEM14(v, a, b, c, d, e, f, g, h, i, j, k, l, m) \ + (_VA_ELEM13(v, a, b, c, d, e, f, g, h, i, j, k, l) || ((v) == (m))) +#define _VA_ELEM15(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n) \ + (_VA_ELEM14(v, a, b, c, d, e, f, g, h, i, j, k, l, m) || ((v) == (n))) +#define _VA_ELEM16(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) \ + (_VA_ELEM15(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n) || ((v) == (o))) +#define _VA_ELEM17(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \ + (_VA_ELEM16(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) || ((v) == (p))) + +/* reusable ELEM macro */ +#define ELEM(...) VA_NARGS_CALL_OVERLOAD(_VA_ELEM, __VA_ARGS__) + /* shift around elements */ #define SHIFT3(type, a, b, c) { \ @@ -324,13 +379,13 @@ #define IN_RANGE_INCL(a, b, c) ((b < c) ? ((b <= a && a <= c) ? 1 : 0) : ((c <= a && a <= b) ? 1 : 0)) /* unpack vector for args */ -#define UNPACK2(a) ((a)[0]), ((a)[1]) -#define UNPACK3(a) ((a)[0]), ((a)[1]), ((a)[2]) -#define UNPACK4(a) ((a)[0]), ((a)[1]), ((a)[2]), ((a)[3]) -/* op may be '&' or '*' */ -#define UNPACK2OP(op, a) op((a)[0]), op((a)[1]) -#define UNPACK3OP(op, a) op((a)[0]), op((a)[1]), op((a)[2]) -#define UNPACK4OP(op, a) op((a)[0]), op((a)[1]), op((a)[2]), op((a)[3]) +#define UNPACK2(a) ((a)[0]), ((a)[1]) +#define UNPACK3(a) UNPACK2(a), ((a)[2]) +#define UNPACK4(a) UNPACK3(a), ((a)[3]) +/* pre may be '&', '*' or func, post may be '->member' */ +#define UNPACK2_EX(pre, a, post) (pre((a)[0])post), (pre((a)[1])post) +#define UNPACK3_EX(pre, a, post) UNPACK2_EX(pre, a, post), (pre((a)[2])post) +#define UNPACK4_EX(pre, a, post) UNPACK3_EX(pre, a, post), (pre((a)[3])post) /* array helpers */ #define ARRAY_LAST_ITEM(arr_start, arr_dtype, tot) \ @@ -363,8 +418,7 @@ /* memcpy, skipping the first part of a struct, * ensures 'struct_dst' isn't const and that the offset can be computed at compile time */ #define MEMCPY_STRUCT_OFS(struct_dst, struct_src, member) { \ - void *_not_const = struct_dst; \ - (void)_not_const; \ + CHECK_TYPE_NONCONST(struct_dst); \ ((void)(struct_dst == struct_src), \ memcpy((char *)(struct_dst) + OFFSETOF_STRUCT(struct_dst, member), \ (char *)(struct_src) + OFFSETOF_STRUCT(struct_dst, member), \ diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c index d24c180dae6..b209e6803f8 100644 --- a/source/blender/blenlib/intern/BLI_ghash.c +++ b/source/blender/blenlib/intern/BLI_ghash.c @@ -570,12 +570,12 @@ void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh) ghi->curEntry = NULL; ghi->curBucket = UINT_MAX; /* wraps to zero */ if (gh->nentries) { - while (!ghi->curEntry) { + do { ghi->curBucket++; if (UNLIKELY(ghi->curBucket == ghi->gh->nbuckets)) break; ghi->curEntry = ghi->gh->buckets[ghi->curBucket]; - } + } while (!ghi->curEntry); } } @@ -704,6 +704,11 @@ unsigned int BLI_ghashutil_uinthash_v4(const unsigned int key[4]) return hash; } +int BLI_ghashutil_uinthash_v4_cmp(const void *a, const void *b) +{ + return memcmp(a, b, sizeof(unsigned int[4])); +} + unsigned int BLI_ghashutil_uinthash(unsigned int key) { key += ~(key << 16); diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index e4f9df5c27e..17ab55e58f4 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -45,6 +45,17 @@ #define MAX_TREETYPE 32 +/* Setting zero so we can catch bugs in OpenMP/KDOPBVH. + * TODO(sergey): Deduplicate the limits with PBVH from BKE. + */ +#ifdef _OPENMP +# ifdef DEBUG +# define KDOPBVH_OMP_LIMIT 0 +# else +# define KDOPBVH_OMP_LIMIT 1024 +# endif +#endif + typedef unsigned char axis_t; typedef struct BVHNode { @@ -749,7 +760,8 @@ static void non_recursive_bvh_div_nodes(BVHTree *tree, BVHNode *branches_array, int j; /* Loop all branches on this level */ -#pragma omp parallel for private(j) schedule(static) + +#pragma omp parallel for private(j) schedule(static) if (num_leafs > KDOPBVH_OMP_LIMIT) for (j = i; j < end_j; j++) { int k; const int parent_level_index = j - i; @@ -1102,7 +1114,7 @@ BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, unsigned int data[j]->stop_axis = min_axis(tree1->stop_axis, tree2->stop_axis); } -#pragma omp parallel for private(j) schedule(static) +#pragma omp parallel for private(j) schedule(static) if (tree1->totleaf > KDOPBVH_OMP_LIMIT) for (j = 0; j < MIN2(tree1->tree_type, tree1->nodes[tree1->totleaf]->totnode); j++) { traverse(data[j], tree1->nodes[tree1->totleaf]->children[j], tree2->nodes[tree2->totleaf]); } diff --git a/source/blender/blenlib/intern/BLI_linklist.c b/source/blender/blenlib/intern/BLI_linklist.c index 66fcfd21fbb..a0b61e7945c 100644 --- a/source/blender/blenlib/intern/BLI_linklist.c +++ b/source/blender/blenlib/intern/BLI_linklist.c @@ -38,17 +38,12 @@ int BLI_linklist_length(LinkNode *list) { - if (0) { - return list ? (1 + BLI_linklist_length(list->next)) : 0; - } - else { - int len; + int len; - for (len = 0; list; list = list->next) - len++; - - return len; - } + for (len = 0; list; list = list->next) + len++; + + return len; } int BLI_linklist_index(LinkNode *list, void *ptr) diff --git a/source/blender/blenlib/intern/edgehash.c b/source/blender/blenlib/intern/edgehash.c index 27c5457370b..f6e4aec9624 100644 --- a/source/blender/blenlib/intern/edgehash.c +++ b/source/blender/blenlib/intern/edgehash.c @@ -463,14 +463,14 @@ void BLI_edgehashIterator_init(EdgeHashIterator *ehi, EdgeHash *eh) ehi->curEntry = NULL; ehi->curBucket = UINT_MAX; /* wraps to zero */ if (eh->nentries) { - while (!ehi->curEntry) { + do { ehi->curBucket++; if (UNLIKELY(ehi->curBucket == ehi->eh->nbuckets)) { break; } ehi->curEntry = ehi->eh->buckets[ehi->curBucket]; - } + } while (!ehi->curEntry); } } diff --git a/source/blender/blenlib/intern/gsqueue.c b/source/blender/blenlib/intern/gsqueue.c index 67703c3f033..94d18ce3c77 100644 --- a/source/blender/blenlib/intern/gsqueue.c +++ b/source/blender/blenlib/intern/gsqueue.c @@ -27,6 +27,12 @@ /** \file blender/blenlib/intern/gsqueue.c * \ingroup bli + * + * \brief A generic structure queue + * (a queue for fixed length generally small) structures. + * + * \note Only use this if you need (first-in-first-out), + * otherwise #BLI_stack is more efficient (first-in-last-out). */ #include <string.h> diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c index b0c24899bd1..abf15d57cf7 100644 --- a/source/blender/blenlib/intern/listbase.c +++ b/source/blender/blenlib/intern/listbase.c @@ -354,7 +354,7 @@ int BLI_countlist(const ListBase *listbase) } /** - * Returns the nth element of \a listbase, numbering from 1. + * Returns the nth element of \a listbase, numbering from 0. */ void *BLI_findlink(const ListBase *listbase, int number) { @@ -372,7 +372,7 @@ void *BLI_findlink(const ListBase *listbase, int number) } /** - * Returns the nth-last element of \a listbase, numbering from 1. + * Returns the nth-last element of \a listbase, numbering from 0. */ void *BLI_rfindlink(const ListBase *listbase, int number) { @@ -390,7 +390,7 @@ void *BLI_rfindlink(const ListBase *listbase, int number) } /** - * Returns the position of \a vlink within \a listbase, numbering from 1, or -1 if not found. + * Returns the position of \a vlink within \a listbase, numbering from 0, or -1 if not found. */ int BLI_findindex(const ListBase *listbase, const void *vlink) { @@ -599,7 +599,7 @@ void BLI_listbase_reverse(ListBase *lb) /** * \param vlink Link to make first. */ -void BLI_rotatelist_first(ListBase *lb, void *vlink) +void BLI_listbase_rotate_first(ListBase *lb, void *vlink) { /* make circular */ ((Link *)lb->first)->prev = lb->last; @@ -615,7 +615,7 @@ void BLI_rotatelist_first(ListBase *lb, void *vlink) /** * \param vlink Link to make last. */ -void BLI_rotatelist_last(ListBase *lb, void *vlink) +void BLI_listbase_rotate_last(ListBase *lb, void *vlink) { /* make circular */ ((Link *)lb->first)->prev = lb->last; diff --git a/source/blender/blenlib/intern/math_color.c b/source/blender/blenlib/intern/math_color.c index 57a48bb5fa8..828a84da6e1 100644 --- a/source/blender/blenlib/intern/math_color.c +++ b/source/blender/blenlib/intern/math_color.c @@ -37,112 +37,38 @@ void hsv_to_rgb(float h, float s, float v, float *r, float *g, float *b) { - if (s != 0.0f) { - float i, f, p; - h = (h - floorf(h)) * 6.0f; - - i = floorf(h); - f = h - i; - - /* avoid computing q/t when not needed */ - p = (v * (1.0f - s)); -#define q (v * (1.0f - (s * f))) -#define t (v * (1.0f - (s * (1.0f - f)))) - - /* faster to compare floats then int conversion */ - if (i < 1.0f) { - *r = v; - *g = t; - *b = p; - } - else if (i < 2.0f) { - *r = q; - *g = v; - *b = p; - } - else if (i < 3.0f) { - *r = p; - *g = v; - *b = t; - } - else if (i < 4.0f) { - *r = p; - *g = q; - *b = v; - } - else if (i < 5.0f) { - *r = t; - *g = p; - *b = v; - } - else { - *r = v; - *g = p; - *b = q; - } + float nr, ng, nb; -#undef q -#undef t + nr = fabsf(h * 6.0f - 3.0f) - 1.0f; + ng = 2.0f - fabsf(h * 6.0f - 2.0f); + nb = 2.0f - fabsf(h * 6.0f - 4.0f); - } - else { - *r = v; - *g = v; - *b = v; - } + CLAMP(nr, 0.0f, 1.0f); + CLAMP(nb, 0.0f, 1.0f); + CLAMP(ng, 0.0f, 1.0f); + + *r = ((nr - 1.0f) * s + 1.0f) * v; + *g = ((ng - 1.0f) * s + 1.0f) * v; + *b = ((nb - 1.0f) * s + 1.0f) * v; } -/* HSL to rgb conversion from https://en.wikipedia.org/wiki/HSL_and_HSV */ void hsl_to_rgb(float h, float s, float l, float *r, float *g, float *b) { - float i, f, c; - h = (h - floorf(h)) * 6.0f; - c = (l > 0.5f) ? (2.0f * (1.0f - l) * s) : (2.0f * l * s); - i = floorf(h); - f = h - i; + float nr, ng, nb, chroma; -#define x2 (c * f) -#define x1 (c * (1.0f - f)) + nr = fabsf(h * 6.0f - 3.0f) - 1.0f; + ng = 2.0f - fabsf(h * 6.0f - 2.0f); + nb = 2.0f - fabsf(h * 6.0f - 4.0f); - /* faster to compare floats then int conversion */ - if (i < 1.0f) { - *r = c; - *g = x2; - *b = 0; - } - else if (i < 2.0f) { - *r = x1; - *g = c; - *b = 0; - } - else if (i < 3.0f) { - *r = 0; - *g = c; - *b = x2; - } - else if (i < 4.0f) { - *r = 0; - *g = x1; - *b = c; - } - else if (i < 5.0f) { - *r = x2; - *g = 0; - *b = c; - } - else { - *r = c; - *g = 0; - *b = x1; - } + CLAMP(nr, 0.0f, 1.0f); + CLAMP(nb, 0.0f, 1.0f); + CLAMP(ng, 0.0f, 1.0f); -#undef x1 -#undef x2 + chroma = (1.0f - fabsf(2.0f * l - 1.0f)) * s; - f = l - 0.5f * c; - *r += f; - *g += f; - *b += f; + *r = (nr - 0.5f) * chroma + l; + *g = (ng - 0.5f) * chroma + l; + *b = (nb - 0.5f) * chroma + l; } /* convenience function for now */ @@ -187,7 +113,7 @@ void yuv_to_rgb(float y, float u, float v, float *lr, float *lg, float *lb) void rgb_to_ycc(float r, float g, float b, float *ly, float *lcb, float *lcr, int colorspace) { float sr, sg, sb; - float y = 128.f, cr = 128.f, cb = 128.f; + float y = 128.0f, cr = 128.0f, cb = 128.0f; sr = 255.0f * r; sg = 255.0f * g; @@ -226,7 +152,7 @@ void rgb_to_ycc(float r, float g, float b, float *ly, float *lcb, float *lcr, in /* FIXME comment above must be wrong because BLI_YCC_ITU_BT601 y 16.0 cr 16.0 -> r -0.7009 */ void ycc_to_rgb(float y, float cb, float cr, float *lr, float *lg, float *lb, int colorspace) { - float r = 128.f, g = 128.f, b = 128.f; + float r = 128.0f, g = 128.0f, b = 128.0f; switch (colorspace) { case BLI_YCC_ITU_BT601: @@ -284,57 +210,26 @@ void hex_to_rgb(char *hexcol, float *r, float *g, float *b) void rgb_to_hsv(float r, float g, float b, float *lh, float *ls, float *lv) { - float h, s, v; - float cmax, cmin; - - cmax = r; - cmin = r; - cmax = (g > cmax ? g : cmax); - cmin = (g < cmin ? g : cmin); - cmax = (b > cmax ? b : cmax); - cmin = (b < cmin ? b : cmin); - - v = cmax; /* value */ - if (cmax != 0.0f) { - float cdelta; - - cdelta = cmax - cmin; - s = cdelta / cmax; - - if (s != 0.0f) { - float rc, gc, bc; - - rc = (cmax - r) / cdelta; - gc = (cmax - g) / cdelta; - bc = (cmax - b) / cdelta; - - if (r == cmax) { - h = bc - gc; - if (h < 0.0f) { - h += 6.0f; - } - } - else if (g == cmax) { - h = 2.0f + rc - bc; - } - else { - h = 4.0f + gc - rc; - } - - h *= (1.0f / 6.0f); - } - else { - h = 0.0f; - } + float k = 0.0f; + float chroma; + float min_gb; + + if (g < b) { + SWAP(float, g, b); + k = -1.0f; } - else { - h = 0.0f; - s = 0.0f; + min_gb = b; + if (r < g) { + SWAP(float, r, g); + k = -2.0f / 6.0f - k; + min_gb = min_ff(g, b); } - *lh = h; - *ls = s; - *lv = v; + chroma = r - min_gb; + + *lh = fabsf(k + (g - b) / (6.0f * chroma + 1e-20f)); + *ls = chroma / (r + 1e-20f); + *lv = r; } /* convenience function for now */ @@ -374,8 +269,8 @@ void rgb_to_hsl(float r, float g, float b, float *lh, float *ls, float *ll) void rgb_to_hsl_compat(float r, float g, float b, float *lh, float *ls, float *ll) { - float orig_s = *ls; - float orig_h = *lh; + const float orig_s = *ls; + const float orig_h = *lh; rgb_to_hsl(r, g, b, lh, ls, ll); @@ -407,8 +302,8 @@ void rgb_to_hsl_v(const float rgb[3], float r_hsl[3]) void rgb_to_hsv_compat(float r, float g, float b, float *lh, float *ls, float *lv) { - float orig_h = *lh; - float orig_s = *ls; + const float orig_h = *lh; + const float orig_s = *ls; rgb_to_hsv(r, g, b, lh, ls, lv); @@ -703,11 +598,12 @@ static float index_to_float(const unsigned short i) void BLI_init_srgb_conversion(void) { - static int initialized = 0; + static bool initialized = false; unsigned int i, b; - if (initialized) return; - initialized = 1; + if (initialized) + return; + initialized = true; /* Fill in the lookup table to convert floats to bytes: */ for (i = 0; i < 0x10000; i++) { @@ -762,13 +658,13 @@ static float xyz_to_lab_component(float v) void xyz_to_lab(float x, float y, float z, float *l, float *a, float *b) { - float xr = x / 95.047f; - float yr = y / 100.0f; - float zr = z / 108.883f; + const float xr = x / 95.047f; + const float yr = y / 100.0f; + const float zr = z / 108.883f; - float fx = xyz_to_lab_component(xr); - float fy = xyz_to_lab_component(yr); - float fz = xyz_to_lab_component(zr); + const float fx = xyz_to_lab_component(xr); + const float fy = xyz_to_lab_component(yr); + const float fz = xyz_to_lab_component(zr); *l = 116.0f * fy - 16.0f; *a = 500.0f * (fx - fy); diff --git a/source/blender/blenlib/intern/math_color_blend_inline.c b/source/blender/blenlib/intern/math_color_blend_inline.c index 4810fe757fa..2522fe5f6c9 100644 --- a/source/blender/blenlib/intern/math_color_blend_inline.c +++ b/source/blender/blenlib/intern/math_color_blend_inline.c @@ -30,11 +30,16 @@ #include "BLI_math_base.h" #include "BLI_math_color.h" #include "BLI_math_color_blend.h" +#include "BLI_math_vector.h" #include "BLI_utildefines.h" #ifndef __MATH_COLOR_BLEND_INLINE_C__ #define __MATH_COLOR_BLEND_INLINE_C__ +/* don't add any saturation to a completly black and white image */ +#define EPS_SATURATION 0.0005f +#define EPS_ALPHA 0.0005f + /***************************** Color Blending ******************************** * * - byte colors are assumed to be straight alpha @@ -67,10 +72,7 @@ MINLINE void blend_color_mix_byte(unsigned char dst[4], const unsigned char src1 } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4_char((char *)dst, (char *)src1); } } @@ -92,10 +94,7 @@ MINLINE void blend_color_add_byte(unsigned char dst[4], const unsigned char src1 } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4_char((char *)dst, (char *)src1); } } @@ -117,10 +116,7 @@ MINLINE void blend_color_sub_byte(unsigned char dst[4], const unsigned char src1 } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4_char((char *)dst, (char *)src1); } } @@ -143,10 +139,7 @@ MINLINE void blend_color_mul_byte(unsigned char dst[4], const unsigned char src1 } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4_char((char *)dst, (char *)src1); } } @@ -169,10 +162,7 @@ MINLINE void blend_color_lighten_byte(unsigned char dst[4], const unsigned char } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4_char((char *)dst, (char *)src1); } } @@ -195,10 +185,7 @@ MINLINE void blend_color_darken_byte(unsigned char dst[4], const unsigned char s } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4_char((char *)dst, (char *)src1); } } @@ -215,10 +202,7 @@ MINLINE void blend_color_erase_alpha_byte(unsigned char dst[4], const unsigned c } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4_char((char *)dst, (char *)src1); } } @@ -235,11 +219,391 @@ MINLINE void blend_color_add_alpha_byte(unsigned char dst[4], const unsigned cha } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + +MINLINE void blend_color_overlay_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = (int)src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + int i = 3; + + while (i--) { + int temp; + + if (src1[i] > 127) { + temp = 255 - ((255 - 2 * (src1[i] - 127)) * (255 - src2[i]) / 255); + } + else { + temp = (2 * src1[i] * src2[i]) >> 8; + } + dst[i] = (unsigned char)min_ii((temp * fac + src1[i] * mfac) / 255, 255); + } + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + + +MINLINE void blend_color_hardlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = (int)src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + int i = 3; + + while (i--) { + int temp; + + if (src2[i] > 127) { + temp = 255 - ((255 - 2 * (src2[i] - 127)) * (255 - src1[i]) / 255); + } + else { + temp = (2 * src2[i] * src1[i]) >> 8; + } + dst[i] = (unsigned char)min_ii((temp * fac + src1[i] * mfac) / 255, 255); + } + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + + +MINLINE void blend_color_burn_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + int i = 3; + + while (i--) { + const int temp = (src2[i] == 0) ? 0 : max_ii(255 - ((255 - src1[i]) * 255) / src2[i], 0); + dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255); + } + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + + +MINLINE void blend_color_linearburn_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + int i = 3; + + while (i--) { + const int temp = max_ii(src1[i] + src2[i] - 255, 0); + dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255); + } + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + + +MINLINE void blend_color_dodge_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + int i = 3; + + while (i--) { + const int temp = (src2[i] == 255) ? 255 : min_ii((src1[i] * 255) / (255 - src2[i]), 255); + dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255); + } + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + +MINLINE void blend_color_screen_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + int i = 3; + + while (i--) { + const int temp = max_ii(255 - (((255 - src1[i]) * (255 - src2[i])) / 255), 0); + dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255); + } + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + + +MINLINE void blend_color_softlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + int i = 3; + + while (i--) { + int temp; + + if (src1[i] < 127) { + temp = ((2 * ((src2[i] / 2) + 64)) * src1[i]) / 255; + } + else { + temp = 255 - (2 * (255 - ((src2[i] / 2) + 64)) * (255 - src1[i]) / 255); + } + dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255); + } + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + + +MINLINE void blend_color_pinlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + int i = 3; + + while (i--) { + int temp; + + if (src2[i] > 127) { + temp = max_ii(2 * (src2[i] - 127), src1[i]); + } + else { + temp = min_ii(2 * src2[i], src1[i]); + } + dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255); + } + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + + +MINLINE void blend_color_linearlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + int i = 3; + + while (i--) { + int temp; + + if (src2[i] > 127) { + temp = min_ii(src1[i] + 2 * (src2[i] - 127), 255); + } + else { + temp = max_ii(src1[i] + 2 * src2[i] - 255, 0); + } + dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255); + } + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + + +MINLINE void blend_color_vividlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + int i = 3; + + while (i--) { + int temp; + + if (src2[i] == 255) { + temp = 255; + } + else if (src2[i] == 0) { + temp = 0; + } + else if (src2[i] > 127) { + temp = min_ii(((src1[i]) * 255) / (2 * (255 - src2[i])), 255); + } + else { + temp = max_ii(255 - ((255 - src1[i]) * 255 / (2 * src2[i])), 0); + } + dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255); + } + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + + + +MINLINE void blend_color_difference_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + int i = 3; + + while (i--) { + const int temp = abs(src1[i] - src2[i]); + dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255); + } + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + + +MINLINE void blend_color_exclusion_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + int i = 3; + + while (i--) { + const int temp = 127 - ((2 * (src1[i] - 127) * (src2[i] - 127)) / 255); + dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255); + } + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + +MINLINE void blend_color_color_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + float h1, s1, v1; + float h2, s2, v2; + float r, g, b; + rgb_to_hsv(src1[0] / 255.0f, src1[1] / 255.0f, src1[2] / 255.0f, &h1, &s1, &v1); + rgb_to_hsv(src2[0] / 255.0f, src2[1] / 255.0f, src2[2] / 255.0f, &h2, &s2, &v2); + + + h1 = h2; + s1 = s2; + + hsv_to_rgb(h1, s1, v1, &r, &g, &b); + + dst[0] = (unsigned char)(((int)(r * 255.0f) * fac + src1[0] * mfac) / 255); + dst[1] = (unsigned char)(((int)(g * 255.0f) * fac + src1[1] * mfac) / 255); + dst[2] = (unsigned char)(((int)(b * 255.0f) * fac + src1[2] * mfac) / 255); + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + +MINLINE void blend_color_hue_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + float h1, s1, v1; + float h2, s2, v2; + float r, g, b; + rgb_to_hsv(src1[0] / 255.0f, src1[1] / 255.0f, src1[2] / 255.0f, &h1, &s1, &v1); + rgb_to_hsv(src2[0] / 255.0f, src2[1] / 255.0f, src2[2] / 255.0f, &h2, &s2, &v2); + + + h1 = h2; + + hsv_to_rgb(h1, s1, v1, &r, &g, &b); + + dst[0] = (unsigned char)(((int)(r * 255.0f) * fac + src1[0] * mfac) / 255); + dst[1] = (unsigned char)(((int)(g * 255.0f) * fac + src1[1] * mfac) / 255); + dst[2] = (unsigned char)(((int)(b * 255.0f) * fac + src1[2] * mfac) / 255); + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } + +} + +MINLINE void blend_color_saturation_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + float h1, s1, v1; + float h2, s2, v2; + float r, g, b; + rgb_to_hsv(src1[0] / 255.0f, src1[1] / 255.0f, src1[2] / 255.0f, &h1, &s1, &v1); + rgb_to_hsv(src2[0] / 255.0f, src2[1] / 255.0f, src2[2] / 255.0f, &h2, &s2, &v2); + + if (s1 > EPS_SATURATION) { + s1 = s2; + } + + hsv_to_rgb(h1, s1, v1, &r, &g, &b); + + dst[0] = (unsigned char)(((int)(r * 255.0f) * fac + src1[0] * mfac) / 255); + dst[1] = (unsigned char)(((int)(g * 255.0f) * fac + src1[1] * mfac) / 255); + dst[2] = (unsigned char)(((int)(b * 255.0f) * fac + src1[2] * mfac) / 255); + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); + } +} + +MINLINE void blend_color_luminosity_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]) +{ + const int fac = src2[3]; + if (fac != 0) { + const int mfac = 255 - fac; + float h1, s1, v1; + float h2, s2, v2; + float r, g, b; + rgb_to_hsv(src1[0] / 255.0f, src1[1] / 255.0f, src1[2] / 255.0f, &h1, &s1, &v1); + rgb_to_hsv(src2[0] / 255.0f, src2[1] / 255.0f, src2[2] / 255.0f, &h2, &s2, &v2); + + v1 = v2; + + hsv_to_rgb(h1, s1, v1, &r, &g, &b); + + dst[0] = (unsigned char)(((int)(r * 255.0f) * fac + src1[0] * mfac) / 255); + dst[1] = (unsigned char)(((int)(g * 255.0f) * fac + src1[1] * mfac) / 255); + dst[2] = (unsigned char)(((int)(b * 255.0f) * fac + src1[2] * mfac) / 255); + + } + else { + /* no op */ + copy_v4_v4_char((char *)dst, (char *)src1); } + } MINLINE void blend_color_interpolate_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4], float ft) @@ -257,10 +621,7 @@ MINLINE void blend_color_interpolate_byte(unsigned char dst[4], const unsigned c dst[3] = (unsigned char)divide_round_i(tmp, 255); } else { - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4_char((char *)dst, (char *)src1); } } @@ -280,10 +641,7 @@ MINLINE void blend_color_mix_float(float dst[4], const float src1[4], const floa } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4(dst, src1); } } @@ -298,10 +656,7 @@ MINLINE void blend_color_add_float(float dst[4], const float src1[4], const floa } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4(dst, src1); } } @@ -316,10 +671,7 @@ MINLINE void blend_color_sub_float(float dst[4], const float src1[4], const floa } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4(dst, src1); } } @@ -337,10 +689,7 @@ MINLINE void blend_color_mul_float(float dst[4], const float src1[4], const floa } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4(dst, src1); } } @@ -360,10 +709,7 @@ MINLINE void blend_color_lighten_float(float dst[4], const float src1[4], const } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4(dst, src1); } } @@ -383,10 +729,7 @@ MINLINE void blend_color_darken_float(float dst[4], const float src1[4], const f } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4(dst, src1); } } @@ -397,8 +740,9 @@ MINLINE void blend_color_erase_alpha_float(float dst[4], const float src1[4], co float alpha = max_ff(src1[3] - src2[3], 0.0f); float map_alpha; - if (alpha <= 0.0005f) + if (alpha <= EPS_ALPHA) { alpha = 0.0f; + } map_alpha = alpha / src1[3]; @@ -409,10 +753,7 @@ MINLINE void blend_color_erase_alpha_float(float dst[4], const float src1[4], co } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4(dst, src1); } } @@ -423,8 +764,9 @@ MINLINE void blend_color_add_alpha_float(float dst[4], const float src1[4], cons float alpha = min_ff(src1[3] + src2[3], 1.0f); float map_alpha; - if (alpha >= 1.0f - 0.0005f) + if (alpha >= 1.0f - EPS_ALPHA) { alpha = 1.0f; + } map_alpha = (src1[3] > 0.0f) ? alpha / src1[3] : 1.0f; @@ -435,17 +777,390 @@ MINLINE void blend_color_add_alpha_float(float dst[4], const float src1[4], cons } else { /* no op */ - dst[0] = src1[0]; - dst[1] = src1[1]; - dst[2] = src1[2]; - dst[3] = src1[3]; + copy_v4_v4(dst, src1); + } +} + +MINLINE void blend_color_overlay_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + int i = 3; + + while (i--) { + float temp; + + if (src1[i] > 0.5f) { + temp = 1.0f - (1.0f - 2.0f * (src1[i] - 0.5f)) * (1.0f - src2[i]); + } + else { + temp = 2.0f * src1[i] * src2[i]; + } + dst[i] = min_ff(temp * fac + src1[i] * mfac, 1.0f); + } + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + + +MINLINE void blend_color_hardlight_float(float dst[4], const float src1[4], const float src2[2]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + int i = 3; + + while (i--) { + float temp; + + if (src2[i] > 0.5f) { + temp = 1.0f - ((1.0f - 2.0f * (src2[i] - 0.5f)) * (1.0f - src1[i])); + } + else { + temp = 2.0f * src2[i] * src1[i]; + } + dst[i] = min_ff((temp * fac + src1[i] * mfac) / 1.0f, 1.0f); + } + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + +MINLINE void blend_color_burn_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + int i = 3; + + while (i--) { + const float temp = (src2[i] == 0.0f) ? 0.0f : max_ff(1.0f - ((1.0f - src1[i]) / src2[i]), 0.0f); + dst[i] = (temp * fac + src1[i] * mfac); + } + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + +MINLINE void blend_color_linearburn_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + int i = 3; + + while (i--) { + const float temp = max_ff(src1[i] + src2[i] - 1.0f, 0.0f); + dst[i] = (temp * fac + src1[i] * mfac); + } + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + + +MINLINE void blend_color_dodge_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + int i = 3; + + while (i--) { + const float temp = (src2[i] >= 1.0f) ? 1.0f : min_ff(src1[i] / (1.0f - src2[i]), 1.0f); + dst[i] = (temp * fac + src1[i] * mfac); + } + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + +MINLINE void blend_color_screen_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + int i = 3; + + while (i--) { + const float temp = max_ff(1.0f - ((1.0f - src1[i]) * (1.0f - src2[i])), 0.0f); + dst[i] = (temp * fac + src1[i] * mfac); + } + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + +MINLINE void blend_color_softlight_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + int i = 3; + + while (i--) { + float temp; + + if (src1[i] < 0.5f) { + temp = (src2[i] + 0.5f) * src1[i]; + } + else { + temp = 1.0f - ((1.0f - (src2[i] + 0.5f)) * (1.0f - src1[i])); + } + dst[i] = (temp * fac + src1[i] * mfac); + } + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + +MINLINE void blend_color_pinlight_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + int i = 3; + + while (i--) { + float temp; + + if (src2[i] > 0.5f) { + temp = max_ff(2.0f * (src2[i] - 0.5f), src1[i]); + } + else { + temp = min_ff(2.0f * src2[i], src1[i]); + } + dst[i] = (temp * fac + src1[i] * mfac); + } + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + + +MINLINE void blend_color_linearlight_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + int i = 3; + + while (i--) { + float temp; + + if (src2[i] > 0.5f) { + temp = min_ff(src1[i] + 2.0f * (src2[i] - 0.5f), 1.0f); + } + else { + temp = max_ff(src1[i] + 2.0f * src2[i] - 1.0f, 0.0f); + } + dst[i] = (temp * fac + src1[i] * mfac); + } + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + + +MINLINE void blend_color_vividlight_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + int i = 3; + + while (i--) { + float temp; + + if (src2[i] == 1.0f) { + temp = 1.0f; + } + else if (src2[i] == 0.0f) { + temp = 0.0f; + } + else if (src2[i] > 0.5f) { + temp = min_ff(((src1[i]) * 1.0f) / (2.0f * (1.0f - src2[i])), 1.0f); + } + else { + temp = max_ff(1.0f - ((1.0f - src1[i]) * 1.0f / (2.0f * src2[i])), 0.0f); + } + dst[i] = (temp * fac + src1[i] * mfac); + } + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + +MINLINE void blend_color_difference_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + int i = 3; + + while (i--) { + dst[i] = (fabsf(src1[i] - src2[i]) * fac + src1[i] * mfac); + } + } + else { + /* no op */ + copy_v4_v4(dst, src1); } } + +MINLINE void blend_color_exclusion_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + int i = 3; + + while (i--) { + const float temp = 0.5f - ((2 * (src1[i] - 0.5f) * (src2[i] - 0.5f))); + dst[i] = (temp * fac + src1[i] * mfac); + } + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } + +} + +MINLINE void blend_color_color_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + float h1, s1, v1; + float h2, s2, v2; + float r, g, b; + + rgb_to_hsv(src1[0], src1[1], src1[2], &h1, &s1, &v1); + rgb_to_hsv(src2[0], src2[1], src2[2], &h2, &s2, &v2); + + h1 = h2; + s1 = s2; + + hsv_to_rgb(h1, s1, v1, &r, &g, &b); + + dst[0] = (r * fac + src1[0] * mfac); + dst[1] = (g * fac + src1[1] * mfac); + dst[2] = (b * fac + src1[2] * mfac); + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + + +MINLINE void blend_color_hue_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + float h1, s1, v1; + float h2, s2, v2; + float r, g, b; + + rgb_to_hsv(src1[0], src1[1], src1[2], &h1, &s1, &v1); + rgb_to_hsv(src2[0], src2[1], src2[2], &h2, &s2, &v2); + + h1 = h2; + + hsv_to_rgb(h1, s1, v1, &r, &g, &b); + + dst[0] = (r * fac + src1[0] * mfac); + dst[1] = (g * fac + src1[1] * mfac); + dst[2] = (b * fac + src1[2] * mfac); + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + +MINLINE void blend_color_saturation_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + float h1, s1, v1; + float h2, s2, v2; + float r, g, b; + + rgb_to_hsv(src1[0], src1[1], src1[2], &h1, &s1, &v1); + rgb_to_hsv(src2[0], src2[1], src2[2], &h2, &s2, &v2); + + if (s1 > EPS_SATURATION) { + s1 = s2; + } + hsv_to_rgb(h1, s1, v1, &r, &g, &b); + + dst[0] = (r * fac + src1[0] * mfac); + dst[1] = (g * fac + src1[1] * mfac); + dst[2] = (b * fac + src1[2] * mfac); + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + +MINLINE void blend_color_luminosity_float(float dst[3], const float src1[3], const float src2[3]) +{ + const float fac = src2[3]; + if (fac != 0.0f && fac < 1.0f) { + const float mfac = 1.0f - fac; + float h1, s1, v1; + float h2, s2, v2; + float r, g, b; + + rgb_to_hsv(src1[0], src1[1], src1[2], &h1, &s1, &v1); + rgb_to_hsv(src2[0], src2[1], src2[2], &h2, &s2, &v2); + + v1 = v2; + hsv_to_rgb(h1, s1, v1, &r, &g, &b); + + dst[0] = (r * fac + src1[0] * mfac); + dst[1] = (g * fac + src1[1] * mfac); + dst[2] = (b * fac + src1[2] * mfac); + } + else { + /* no op */ + copy_v4_v4(dst, src1); + } +} + + MINLINE void blend_color_interpolate_float(float dst[4], const float src1[4], const float src2[4], float t) { /* interpolation, colors are premultiplied so it goes fine */ - float mt = 1.0f - t; + const float mt = 1.0f - t; dst[0] = mt * src1[0] + t * src2[0]; dst[1] = mt * src1[1] + t * src2[1]; @@ -453,4 +1168,7 @@ MINLINE void blend_color_interpolate_float(float dst[4], const float src1[4], co dst[3] = mt * src1[3] + t * src2[3]; } +#undef EPS_SATURATION +#undef EPS_ALPHA + #endif /* __MATH_COLOR_BLEND_INLINE_C__ */ diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c index bb2201541d9..9233749d5df 100644 --- a/source/blender/blenlib/intern/math_color_inline.c +++ b/source/blender/blenlib/intern/math_color_inline.c @@ -255,11 +255,11 @@ MINLINE float rgb_to_luma_y(const float rgb[3]) MINLINE int compare_rgb_uchar(const unsigned char col_a[3], const unsigned char col_b[3], const int limit) { - int r = (int)col_a[0] - (int)col_b[0]; + const int r = (int)col_a[0] - (int)col_b[0]; if (ABS(r) < limit) { - int g = (int)col_a[1] - (int)col_b[1]; + const int g = (int)col_a[1] - (int)col_b[1]; if (ABS(g) < limit) { - int b = (int)col_a[2] - (int)col_b[2]; + const int b = (int)col_a[2] - (int)col_b[2]; if (ABS(b) < limit) { return 1; } @@ -280,7 +280,7 @@ MINLINE void premul_to_straight_v4_v4(float straight[4], const float premul[4]) straight[3] = premul[3]; } else { - float alpha_inv = 1.0f / premul[3]; + const float alpha_inv = 1.0f / premul[3]; straight[0] = premul[0] * alpha_inv; straight[1] = premul[1] * alpha_inv; straight[2] = premul[2] * alpha_inv; @@ -295,7 +295,7 @@ MINLINE void premul_to_straight_v4(float color[4]) MINLINE void straight_to_premul_v4_v4(float premul[4], const float straight[4]) { - float alpha = straight[3]; + const float alpha = straight[3]; premul[0] = straight[0] * alpha; premul[1] = straight[1] * alpha; premul[2] = straight[2] * alpha; @@ -309,8 +309,8 @@ MINLINE void straight_to_premul_v4(float color[4]) MINLINE void straight_uchar_to_premul_float(float result[4], const unsigned char color[4]) { - float alpha = color[3] * (1.0f / 255.0f); - float fac = alpha * (1.0f / 255.0f); + const float alpha = color[3] * (1.0f / 255.0f); + const float fac = alpha * (1.0f / 255.0f); result[0] = color[0] * fac; result[1] = color[1] * fac; @@ -327,7 +327,7 @@ MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float c result[3] = FTOCHAR(color[3]); } else { - float alpha_inv = 1.0f / color[3]; + const float alpha_inv = 1.0f / color[3]; /* hopefully this would be optimized */ result[0] = FTOCHAR(color[0] * alpha_inv); diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index efb881cde1b..54e3545a3f1 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -568,7 +568,7 @@ int isect_seg_seg_v2_point(const float v1[2], const float v2[2], const float v3[ { float a1, a2, b1, b2, c1, c2, d; float u, v; - const float eps = 0.000001f; + const float eps = 1e-6f; const float eps_sq = eps * eps; a1 = v2[0] - v1[0]; @@ -1278,13 +1278,13 @@ bool isect_plane_plane_v3(float r_isect_co[3], float r_isect_no[3], static bool getLowestRoot(const float a, const float b, const float c, const float maxR, float *root) { /* Check if a solution exists */ - float determinant = b * b - 4.0f * a * c; + const float determinant = b * b - 4.0f * a * c; /* If determinant is negative it means no solutions. */ if (determinant >= 0.0f) { /* calculate the two roots: (if determinant == 0 then * x1==x2 but lets disregard that slight optimization) */ - float sqrtD = sqrtf(determinant); + const float sqrtD = sqrtf(determinant); float r1 = (-b - sqrtD) / (2.0f * a); float r2 = (-b + sqrtD) / (2.0f * a); @@ -1295,18 +1295,18 @@ static bool getLowestRoot(const float a, const float b, const float c, const flo /* Get lowest root: */ if (r1 > 0.0f && r1 < maxR) { *root = r1; - return 1; + return true; } /* It is possible that we want x2 - this can happen */ /* if x1 < 0 */ if (r2 > 0.0f && r2 < maxR) { *root = r2; - return 1; + return true; } } /* No (valid) solutions */ - return 0; + return false; } bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const float radius, @@ -1335,7 +1335,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl if (fabsf(nordotv) < 0.000001f) { if (fabsf(a) >= radius) { - return 0; + return false; } } else { @@ -1377,7 +1377,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl //(((unsigned int)z)& ~(((unsigned int)x)|((unsigned int)y))) & 0x80000000) { *r_lambda = t0; copy_v3_v3(ipoint, point); - return 1; + return true; } } @@ -1394,7 +1394,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl if (getLowestRoot(a, b, c, *r_lambda, r_lambda)) { copy_v3_v3(ipoint, v0); - found_by_sweep = 1; + found_by_sweep = true; } /*v1*/ @@ -1404,7 +1404,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl if (getLowestRoot(a, b, c, *r_lambda, r_lambda)) { copy_v3_v3(ipoint, v1); - found_by_sweep = 1; + found_by_sweep = true; } /*v2*/ @@ -1414,7 +1414,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl if (getLowestRoot(a, b, c, *r_lambda, r_lambda)) { copy_v3_v3(ipoint, v2); - found_by_sweep = 1; + found_by_sweep = true; } /*---test edges---*/ @@ -1440,7 +1440,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl copy_v3_v3(ipoint, e1); mul_v3_fl(ipoint, e); add_v3_v3(ipoint, v0); - found_by_sweep = 1; + found_by_sweep = true; } } @@ -1462,7 +1462,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl copy_v3_v3(ipoint, e2); mul_v3_fl(ipoint, e); add_v3_v3(ipoint, v0); - found_by_sweep = 1; + found_by_sweep = true; } } @@ -1489,7 +1489,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl copy_v3_v3(ipoint, e3); mul_v3_fl(ipoint, e); add_v3_v3(ipoint, v1); - found_by_sweep = 1; + found_by_sweep = true; } } @@ -1508,10 +1508,10 @@ bool isect_axial_line_tri_v3(const int axis, const float p1[3], const float p2[3 return isect_line_tri_v3(p1, p2, v0, v1, v2, lambda); /* first a simple bounding box test */ - if (min_fff(v0[a1], v1[a1], v2[a1]) > p1[a1]) return 0; - if (min_fff(v0[a2], v1[a2], v2[a2]) > p1[a2]) return 0; - if (max_fff(v0[a1], v1[a1], v2[a1]) < p1[a1]) return 0; - if (max_fff(v0[a2], v1[a2], v2[a2]) < p1[a2]) return 0; + if (min_fff(v0[a1], v1[a1], v2[a1]) > p1[a1]) return false; + if (min_fff(v0[a2], v1[a2], v2[a2]) > p1[a2]) return false; + if (max_fff(v0[a1], v1[a1], v2[a1]) < p1[a1]) return false; + if (max_fff(v0[a2], v1[a2], v2[a2]) < p1[a2]) return false; /* then a full intersection test */ #endif @@ -1521,7 +1521,7 @@ bool isect_axial_line_tri_v3(const int axis, const float p1[3], const float p2[3 sub_v3_v3v3(p, v0, p1); f = (e2[a1] * e1[a2] - e2[a2] * e1[a1]); - if ((f > -0.000001f) && (f < 0.000001f)) return 0; + if ((f > -0.000001f) && (f < 0.000001f)) return false; v = (p[a2] * e1[a1] - p[a1] * e1[a2]) / f; if ((v < 0.0f) || (v > 1.0f)) return 0; @@ -1529,7 +1529,7 @@ bool isect_axial_line_tri_v3(const int axis, const float p1[3], const float p2[3 f = e1[a1]; if ((f > -0.000001f) && (f < 0.000001f)) { f = e1[a2]; - if ((f > -0.000001f) && (f < 0.000001f)) return 0; + if ((f > -0.000001f) && (f < 0.000001f)) return false; u = (-p[a2] - v * e2[a2]) / f; } else @@ -1539,9 +1539,9 @@ bool isect_axial_line_tri_v3(const int axis, const float p1[3], const float p2[3 *r_lambda = (p[a0] + u * e1[a0] + v * e2[a0]) / (p2[a0] - p1[a0]); - if ((*r_lambda < 0.0f) || (*r_lambda > 1.0f)) return 0; + if ((*r_lambda < 0.0f) || (*r_lambda > 1.0f)) return false; - return 1; + return true; } /** @@ -1616,9 +1616,9 @@ int isect_line_line_v3(const float v1[3], const float v2[3], const float v3[3], } } -/* Intersection point strictly between the two lines - * 0 when no intersection is found - * */ +/** Intersection point strictly between the two lines + * \return false when no intersection is found + */ bool isect_line_line_strict_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3], float vi[3], float *r_lambda) @@ -1635,7 +1635,7 @@ bool isect_line_line_strict_v3(const float v1[3], const float v2[3], d = dot_v3v3(dir1, dir2); if (d == 1.0f || d == -1.0f || d == 0) { /* colinear or one vector is zero-length*/ - return 0; + return false; } cross_v3_v3v3(ab, a, b); @@ -1644,7 +1644,7 @@ bool isect_line_line_strict_v3(const float v1[3], const float v2[3], /* test zero length line */ if (UNLIKELY(div == 0.0f)) { - return 0; + return false; } /* test if the two lines are coplanar */ else if (d > -0.000001f && d < 0.000001f) { @@ -1663,14 +1663,14 @@ bool isect_line_line_strict_v3(const float v1[3], const float v2[3], if (r_lambda) *r_lambda = f1; - return 1; /* intersection found */ + return true; /* intersection found */ } else { - return 0; + return false; } } else { - return 0; + return false; } } @@ -1688,9 +1688,9 @@ void isect_ray_aabb_initialize(IsectRayAABBData *data, const float ray_start[3], data->ray_inv_dir[1] = 1.0f / ray_direction[1]; data->ray_inv_dir[2] = 1.0f / ray_direction[2]; - data->sign[0] = data->ray_inv_dir[0] < 0; - data->sign[1] = data->ray_inv_dir[1] < 0; - data->sign[2] = data->ray_inv_dir[2] < 0; + data->sign[0] = data->ray_inv_dir[0] < 0.0f; + data->sign[1] = data->ray_inv_dir[1] < 0.0f; + data->sign[2] = data->ray_inv_dir[2] < 0.0f; } /* Adapted from http://www.gamedev.net/community/forums/topic.asp?topic_id=459973 */ @@ -1808,8 +1808,9 @@ float line_plane_factor_v3(const float plane_co[3], const float plane_no[3], return (dot != 0.0f) ? -dot_v3v3(plane_no, h) / dot : 0.0f; } -/* ensure the distance between these points is no greater then 'dist' - * if it is, scale then both into the center */ +/** Ensure the distance between these points is no greater then 'dist'. + * If it is, scale then both into the center. + */ void limit_dist_v3(float v1[3], float v2[3], const float dist) { const float dist_old = len_v3v3(v1, v2); @@ -1874,8 +1875,7 @@ static bool point_in_slice(const float p[3], const float v1[3], const float l1[3 sub_v3_v3v3(rp, p, v1); h = dot_v3v3(q, rp) / dot_v3v3(q, q); - if (h < 0.0f || h > 1.0f) return 0; - return 1; + return (h < 0.0f || h > 1.0f) ? false : true; } #if 0 @@ -1904,10 +1904,43 @@ static int point_in_slice_m(float p[3], float origin[3], float normal[3], float bool isect_point_tri_prism_v3(const float p[3], const float v1[3], const float v2[3], const float v3[3]) { - if (!point_in_slice(p, v1, v2, v3)) return 0; - if (!point_in_slice(p, v2, v3, v1)) return 0; - if (!point_in_slice(p, v3, v1, v2)) return 0; - return 1; + if (!point_in_slice(p, v1, v2, v3)) return false; + if (!point_in_slice(p, v2, v3, v1)) return false; + if (!point_in_slice(p, v3, v1, v2)) return false; + return true; +} + +/** + * \param r_vi 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. + */ +bool isect_point_tri_v3(const float p[3], const float v1[3], const float v2[3], const float v3[3], + float r_vi[3]) +{ + if (isect_point_tri_prism_v3(p, v1, v2, v3)) { + float no[3], n1[3], n2[3]; + + /* Could use normal_tri_v3, but doesn't have to be unit-length */ + sub_v3_v3v3(n1, v1, v2); + sub_v3_v3v3(n2, v2, v3); + cross_v3_v3v3(no, n1, n2); + + if (LIKELY(len_squared_v3(no) != 0.0f)) { + float plane[4]; + plane_from_point_normal_v3(plane, v1, no); + closest_to_plane_v3(r_vi, plane, p); + } + else { + /* degenerate */ + copy_v3_v3(r_vi, p); + } + + return true; + } + else { + return false; + } } bool clip_segment_v3_plane(float p1[3], float p2[3], const float plane[4]) @@ -1918,7 +1951,7 @@ bool clip_segment_v3_plane(float p1[3], float p2[3], const float plane[4]) div = dot_v3v3(dp, plane); if (div == 0.0f) /* parallel */ - return 1; + return true; t = -plane_point_side_v3(plane, p1) / div; @@ -1927,34 +1960,34 @@ bool clip_segment_v3_plane(float p1[3], float p2[3], const float plane[4]) if (t >= 1.0f) { zero_v3(p1); zero_v3(p2); - return 0; + return false; } /* intersect plane */ if (t > 0.0f) { madd_v3_v3v3fl(pc, p1, dp, t); copy_v3_v3(p1, pc); - return 1; + return true; } - return 1; + return true; } else { /* behind plane, completely clipped */ if (t <= 0.0f) { zero_v3(p1); zero_v3(p2); - return 0; + return false; } /* intersect plane */ if (t < 1.0f) { madd_v3_v3v3fl(pc, p1, dp, t); copy_v3_v3(p2, pc); - return 1; + return true; } - return 1; + return true; } } @@ -2183,12 +2216,12 @@ static bool barycentric_weights(const float v1[3], const float v2[3], const floa if (fabsf(wtot) > FLT_EPSILON) { mul_v3_fl(w, 1.0f / wtot); - return 0; + return false; } else { /* zero area triangle */ copy_v3_fl(w, 1.0f / 3.0f); - return 1; + return true; } } @@ -2239,8 +2272,9 @@ void interp_weights_face_v3(float w[4], const float v1[3], const float v2[3], co } } } - else + else { barycentric_weights(v1, v2, v3, co, n, w); + } } } @@ -2266,11 +2300,11 @@ int barycentric_inside_triangle_v2(const float w[3]) /* returns 0 for degenerated triangles */ bool barycentric_coords_v2(const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3]) { - float x = co[0], y = co[1]; - float x1 = v1[0], y1 = v1[1]; - float x2 = v2[0], y2 = v2[1]; - float x3 = v3[0], y3 = v3[1]; - float det = (y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3); + const float x = co[0], y = co[1]; + const float x1 = v1[0], y1 = v1[1]; + const float x2 = v2[0], y2 = v2[1]; + const float x3 = v3[0], y3 = v3[1]; + const float det = (y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3); if (fabsf(det) > FLT_EPSILON) { w[0] = ((y2 - y3) * (x - x3) + (x3 - x2) * (y - y3)) / det; @@ -2319,8 +2353,9 @@ void barycentric_weights_v2_persp(const float v1[4], const float v2[4], const fl if (wtot != 0.0f) { mul_v3_fl(w, 1.0f / wtot); } - else /* dummy values for zero area face */ + else { /* dummy values for zero area face */ w[0] = w[1] = w[2] = 1.0f / 3.0f; + } } /* same as #barycentric_weights_v2 but works with a quad, @@ -2355,8 +2390,7 @@ void barycentric_weights_v2_quad(const float v1[2], const float v2[2], const flo if (UNLIKELY(lens[0] < FLT_EPSILON)) { w[0] = 1.0f; w[1] = w[2] = w[3] = 0.0f; } else if (UNLIKELY(lens[1] < FLT_EPSILON)) { w[1] = 1.0f; w[0] = w[2] = w[3] = 0.0f; } else if (UNLIKELY(lens[2] < FLT_EPSILON)) { w[2] = 1.0f; w[0] = w[1] = w[3] = 0.0f; } - else if (UNLIKELY(lens[3] < FLT_EPSILON)) { w[3] = 1.0f; w[0] = w[1] = w[2] = 0.0f; - } + else if (UNLIKELY(lens[3] < FLT_EPSILON)) { w[3] = 1.0f; w[0] = w[1] = w[2] = 0.0f; } else { float wtot, area; @@ -2563,7 +2597,7 @@ static float mean_value_half_tan_v2(const float v1[2], const float v2[2], const void interp_weights_poly_v3(float *w, float v[][3], const int n, const float co[3]) { - const float eps = 0.00001f; /* take care, low values cause [#36105] */ + const float eps = 1e-5f; /* take care, low values cause [#36105] */ const float eps_sq = eps * eps; const float *v_curr, *v_next; float ht_prev, ht; /* half tangents */ @@ -2632,7 +2666,7 @@ void interp_weights_poly_v3(float *w, float v[][3], const int n, const float co[ void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[2]) { - const float eps = 0.00001f; /* take care, low values cause [#36105] */ + const float eps = 1e-5f; /* take care, low values cause [#36105] */ const float eps_sq = eps * eps; const float *v_curr, *v_next; float ht_prev, ht; /* half tangents */ @@ -2702,8 +2736,8 @@ void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[ void interp_cubic_v3(float x[3], float v[3], const float x1[3], const float v1[3], const float x2[3], const float v2[3], const float t) { float a[3], b[3]; - float t2 = t * t; - float t3 = t2 * t; + const float t2 = t * t; + const float t3 = t2 * t; /* cubic interpolation */ a[0] = v1[0] + v2[0] + 2 * (x1[0] - x2[0]); @@ -2928,11 +2962,9 @@ void orthographic_m4(float matrix[4][4], const float left, const float right, co void perspective_m4(float mat[4][4], const float left, const float right, const float bottom, const float top, const float nearClip, const float farClip) { - float Xdelta, Ydelta, Zdelta; - - Xdelta = right - left; - Ydelta = top - bottom; - Zdelta = farClip - nearClip; + const float Xdelta = right - left; + const float Ydelta = top - bottom; + const float Zdelta = farClip - nearClip; if (Xdelta == 0.0f || Ydelta == 0.0f || Zdelta == 0.0f) { return; @@ -2946,7 +2978,7 @@ void perspective_m4(float mat[4][4], const float left, const float right, const mat[3][2] = (-2.0f * nearClip * farClip) / Zdelta; mat[0][1] = mat[0][2] = mat[0][3] = mat[1][0] = mat[1][2] = mat[1][3] = - mat[3][0] = mat[3][1] = mat[3][3] = 0.0; + mat[3][0] = mat[3][1] = mat[3][3] = 0.0f; } @@ -2995,7 +3027,6 @@ static void i_multmatrix(float icand[4][4], float Vm[4][4]) void polarview_m4(float Vm[4][4], float dist, float azimuth, float incidence, float twist) { - unit_m4(Vm); translate_m4(Vm, 0.0, 0.0, -dist); @@ -3017,16 +3048,16 @@ void lookat_m4(float mat[4][4], float vx, float vy, float vz, float px, float py dx = px - vx; dy = py - vy; dz = pz - vz; - hyp = dx * dx + dz * dz; /* hyp squared */ + hyp = dx * dx + dz * dz; /* hyp squared */ hyp1 = sqrtf(dy * dy + hyp); - hyp = sqrtf(hyp); /* the real hyp */ + hyp = sqrtf(hyp); /* the real hyp */ - if (hyp1 != 0.0f) { /* rotate X */ + if (hyp1 != 0.0f) { /* rotate X */ sine = -dy / hyp1; cosine = hyp / hyp1; } else { - sine = 0; + sine = 0.0f; cosine = 1.0f; } mat1[1][1] = cosine; @@ -3036,16 +3067,16 @@ void lookat_m4(float mat[4][4], float vx, float vy, float vz, float px, float py i_multmatrix(mat1, mat); - mat1[1][1] = mat1[2][2] = 1.0f; /* be careful here to reinit */ - mat1[1][2] = mat1[2][1] = 0.0; /* those modified by the last */ + mat1[1][1] = mat1[2][2] = 1.0f; /* be careful here to reinit */ + mat1[1][2] = mat1[2][1] = 0.0f; /* those modified by the last */ - /* paragraph */ - if (hyp != 0.0f) { /* rotate Y */ + /* paragraph */ + if (hyp != 0.0f) { /* rotate Y */ sine = dx / hyp; cosine = -dz / hyp; } else { - sine = 0; + sine = 0.0f; cosine = 1.0f; } mat1[0][0] = cosine; @@ -3226,10 +3257,10 @@ void accumulate_vertex_normals_poly(float **vertnos, const float polyno[3], void tangent_from_uv(float uv1[2], float uv2[2], float uv3[3], float co1[3], float co2[3], float co3[3], float n[3], float tang[3]) { - float s1 = uv2[0] - uv1[0]; - float s2 = uv3[0] - uv1[0]; - float t1 = uv2[1] - uv1[1]; - float t2 = uv3[1] - uv1[1]; + const float s1 = uv2[0] - uv1[0]; + const float s2 = uv3[0] - uv1[0]; + const float t1 = uv2[1] - uv1[1]; + const float t2 = uv3[1] - uv1[1]; float det = (s1 * t2 - s2 * t1); if (det != 0.0f) { /* otherwise 'tang' becomes nan */ @@ -3254,7 +3285,7 @@ void tangent_from_uv(float uv1[2], float uv2[2], float uv3[3], float co1[3], flo } } else { - tang[0] = tang[1] = tang[2] = 0.0; + tang[0] = tang[1] = tang[2] = 0.0f; } } @@ -3287,7 +3318,8 @@ void vcloud_estimate_transform(int list_size, float (*pos)[3], float *weight, fl float lloc[3], float rloc[3], float lrot[3][3], float lscale[3][3]) { float accu_com[3] = {0.0f, 0.0f, 0.0f}, accu_rcom[3] = {0.0f, 0.0f, 0.0f}; - float accu_weight = 0.0f, accu_rweight = 0.0f, eps = 0.000001f; + float accu_weight = 0.0f, accu_rweight = 0.0f; + const float eps = 1e-6f; int a; /* first set up a nice default response */ @@ -3381,7 +3413,7 @@ void vcloud_estimate_transform(int list_size, float (*pos)[3], float *weight, fl /* this is pretty much Polardecompose 'inline' the algo based on Higham's thesis */ /* without the far case ... but seems to work here pretty neat */ - odet = 0.f; + odet = 0.0f; ndet = determinant_m3_array(q); while ((odet - ndet) * (odet - ndet) > eps && i < imax) { invert_m3_m3(qi, q); @@ -3422,9 +3454,8 @@ bool form_factor_visible_quad(const float p[3], const float n[3], float q0[3], float q1[3], float q2[3], float q3[3]) { static const float epsilon = 1e-6f; - float c, sd[3]; - - c = dot_v3v3(n, p); + float sd[3]; + const float c = dot_v3v3(n, p); /* signed distances from the vertices to the plane. */ sd[0] = dot_v3v3(n, v0) - c; @@ -3435,16 +3466,16 @@ bool form_factor_visible_quad(const float p[3], const float n[3], if (fabsf(sd[1]) < epsilon) sd[1] = 0.0f; if (fabsf(sd[2]) < epsilon) sd[2] = 0.0f; - if (sd[0] > 0) { - if (sd[1] > 0) { - if (sd[2] > 0) { + if (sd[0] > 0.0f) { + if (sd[1] > 0.0f) { + if (sd[2] > 0.0f) { /* +++ */ copy_v3_v3(q0, v0); copy_v3_v3(q1, v1); copy_v3_v3(q2, v2); copy_v3_v3(q3, q2); } - else if (sd[2] < 0) { + else if (sd[2] < 0.0f) { /* ++- */ copy_v3_v3(q0, v0); copy_v3_v3(q1, v1); @@ -3459,15 +3490,15 @@ bool form_factor_visible_quad(const float p[3], const float n[3], copy_v3_v3(q3, q2); } } - else if (sd[1] < 0) { - if (sd[2] > 0) { + else if (sd[1] < 0.0f) { + if (sd[2] > 0.0f) { /* +-+ */ copy_v3_v3(q0, v0); vec_add_dir(q1, v0, v1, (sd[0] / (sd[0] - sd[1]))); vec_add_dir(q2, v1, v2, (sd[1] / (sd[1] - sd[2]))); copy_v3_v3(q3, v2); } - else if (sd[2] < 0) { + else if (sd[2] < 0.0f) { /* +-- */ copy_v3_v3(q0, v0); vec_add_dir(q1, v0, v1, (sd[0] / (sd[0] - sd[1]))); @@ -3483,14 +3514,14 @@ bool form_factor_visible_quad(const float p[3], const float n[3], } } else { - if (sd[2] > 0) { + if (sd[2] > 0.0f) { /* +0+ */ copy_v3_v3(q0, v0); copy_v3_v3(q1, v1); copy_v3_v3(q2, v2); copy_v3_v3(q3, q2); } - else if (sd[2] < 0) { + else if (sd[2] < 0.0f) { /* +0- */ copy_v3_v3(q0, v0); copy_v3_v3(q1, v1); @@ -3506,16 +3537,16 @@ bool form_factor_visible_quad(const float p[3], const float n[3], } } } - else if (sd[0] < 0) { - if (sd[1] > 0) { - if (sd[2] > 0) { + else if (sd[0] < 0.0f) { + if (sd[1] > 0.0f) { + if (sd[2] > 0.0f) { /* -++ */ vec_add_dir(q0, v0, v1, (sd[0] / (sd[0] - sd[1]))); copy_v3_v3(q1, v1); copy_v3_v3(q2, v2); vec_add_dir(q3, v0, v2, (sd[0] / (sd[0] - sd[2]))); } - else if (sd[2] < 0) { + else if (sd[2] < 0.0f) { /* -+- */ vec_add_dir(q0, v0, v1, (sd[0] / (sd[0] - sd[1]))); copy_v3_v3(q1, v1); @@ -3530,15 +3561,15 @@ bool form_factor_visible_quad(const float p[3], const float n[3], copy_v3_v3(q3, q2); } } - else if (sd[1] < 0) { - if (sd[2] > 0) { + else if (sd[1] < 0.0f) { + if (sd[2] > 0.0f) { /* --+ */ vec_add_dir(q0, v0, v2, (sd[0] / (sd[0] - sd[2]))); vec_add_dir(q1, v1, v2, (sd[1] / (sd[1] - sd[2]))); copy_v3_v3(q2, v2); copy_v3_v3(q3, q2); } - else if (sd[2] < 0) { + else if (sd[2] < 0.0f) { /* --- */ return false; } @@ -3548,14 +3579,14 @@ bool form_factor_visible_quad(const float p[3], const float n[3], } } else { - if (sd[2] > 0) { + if (sd[2] > 0.0f) { /* -0+ */ vec_add_dir(q0, v0, v2, (sd[0] / (sd[0] - sd[2]))); copy_v3_v3(q1, v1); copy_v3_v3(q2, v2); copy_v3_v3(q3, q2); } - else if (sd[2] < 0) { + else if (sd[2] < 0.0f) { /* -0- */ return false; } @@ -3566,15 +3597,15 @@ bool form_factor_visible_quad(const float p[3], const float n[3], } } else { - if (sd[1] > 0) { - if (sd[2] > 0) { + if (sd[1] > 0.0f) { + if (sd[2] > 0.0f) { /* 0++ */ copy_v3_v3(q0, v0); copy_v3_v3(q1, v1); copy_v3_v3(q2, v2); copy_v3_v3(q3, q2); } - else if (sd[2] < 0) { + else if (sd[2] < 0.0f) { /* 0+- */ copy_v3_v3(q0, v0); copy_v3_v3(q1, v1); @@ -3589,15 +3620,15 @@ bool form_factor_visible_quad(const float p[3], const float n[3], copy_v3_v3(q3, q2); } } - else if (sd[1] < 0) { - if (sd[2] > 0) { + else if (sd[1] < 0.0f) { + if (sd[2] > 0.0f) { /* 0-+ */ copy_v3_v3(q0, v0); vec_add_dir(q1, v1, v2, (sd[1] / (sd[1] - sd[2]))); copy_v3_v3(q2, v2); copy_v3_v3(q3, q2); } - else if (sd[2] < 0) { + else if (sd[2] < 0.0f) { /* 0-- */ return false; } @@ -3607,14 +3638,14 @@ bool form_factor_visible_quad(const float p[3], const float n[3], } } else { - if (sd[2] > 0) { + if (sd[2] > 0.0f) { /* 00+ */ copy_v3_v3(q0, v0); copy_v3_v3(q1, v1); copy_v3_v3(q2, v2); copy_v3_v3(q3, q2); } - else if (sd[2] < 0) { + else if (sd[2] < 0.0f) { /* 00- */ return false; } @@ -3769,7 +3800,7 @@ static void ff_normalize(float n[3]) d = dot_v3v3(n, n); - if (d > 1.0e-35F) { + if (d > 1.0e-35f) { d = 1.0f / sqrtf(d); n[0] *= d; diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index 7fc30e3112b..152b31754bb 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -47,19 +47,19 @@ void zero_m4(float m[4][4]) void unit_m3(float m[3][3]) { - m[0][0] = m[1][1] = m[2][2] = 1.0; - m[0][1] = m[0][2] = 0.0; - m[1][0] = m[1][2] = 0.0; - m[2][0] = m[2][1] = 0.0; + m[0][0] = m[1][1] = m[2][2] = 1.0f; + m[0][1] = m[0][2] = 0.0f; + m[1][0] = m[1][2] = 0.0f; + m[2][0] = m[2][1] = 0.0f; } void unit_m4(float m[4][4]) { - m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0; - m[0][1] = m[0][2] = m[0][3] = 0.0; - m[1][0] = m[1][2] = m[1][3] = 0.0; - m[2][0] = m[2][1] = m[2][3] = 0.0; - m[3][0] = m[3][1] = m[3][2] = 0.0; + m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0f; + m[0][1] = m[0][2] = m[0][3] = 0.0f; + m[1][0] = m[1][2] = m[1][3] = 0.0f; + m[2][0] = m[2][1] = m[2][3] = 0.0f; + m[3][0] = m[3][1] = m[3][2] = 0.0f; } void copy_m3_m3(float m1[3][3], float m2[3][3]) @@ -103,14 +103,14 @@ void copy_m4_m3(float m1[4][4], float m2[3][3]) /* no clear */ m1[2][2] = m2[2][2]; /* Reevan's Bugfix */ - m1[0][3] = 0.0F; - m1[1][3] = 0.0F; - m1[2][3] = 0.0F; + m1[0][3] = 0.0f; + m1[1][3] = 0.0f; + m1[2][3] = 0.0f; - m1[3][0] = 0.0F; - m1[3][1] = 0.0F; - m1[3][2] = 0.0F; - m1[3][3] = 1.0F; + m1[3][0] = 0.0f; + m1[3][1] = 0.0f; + m1[3][2] = 0.0f; + m1[3][3] = 1.0f; } @@ -274,71 +274,148 @@ void mul_m4_m3m4(float m1[4][4], float m3_[3][3], float m2_[4][4]) m1[2][2] = m2[2][0] * m3[0][2] + m2[2][1] * m3[1][2] + m2[2][2] * m3[2][2]; } -void mul_serie_m3(float answ[3][3], - float m1[3][3], float m2[3][3], float m3[3][3], - float m4[3][3], float m5[3][3], float m6[3][3], - float m7[3][3], float m8[3][3]) -{ - float temp[3][3]; - - if (m1 == NULL || m2 == NULL) return; - - mul_m3_m3m3(answ, m2, m1); - if (m3) { - mul_m3_m3m3(temp, m3, answ); - if (m4) { - mul_m3_m3m3(answ, m4, temp); - if (m5) { - mul_m3_m3m3(temp, m5, answ); - if (m6) { - mul_m3_m3m3(answ, m6, temp); - if (m7) { - mul_m3_m3m3(temp, m7, answ); - if (m8) { - mul_m3_m3m3(answ, m8, temp); - } - else copy_m3_m3(answ, temp); - } - } - else copy_m3_m3(answ, temp); - } - } - else copy_m3_m3(answ, temp); - } -} -void mul_serie_m4(float answ[4][4], float m1[4][4], - float m2[4][4], float m3[4][4], float m4[4][4], - float m5[4][4], float m6[4][4], float m7[4][4], - float m8[4][4]) -{ - float temp[4][4]; - - if (m1 == NULL || m2 == NULL) return; - - mul_m4_m4m4(answ, m1, m2); - if (m3) { - mul_m4_m4m4(temp, answ, m3); - if (m4) { - mul_m4_m4m4(answ, temp, m4); - if (m5) { - mul_m4_m4m4(temp, answ, m5); - if (m6) { - mul_m4_m4m4(answ, temp, m6); - if (m7) { - mul_m4_m4m4(temp, answ, m7); - if (m8) { - mul_m4_m4m4(answ, temp, m8); - } - else copy_m4_m4(answ, temp); - } - } - else copy_m4_m4(answ, temp); - } - } - else copy_m4_m4(answ, temp); - } -} +/** \name Macro helpers for: mul_m3_series + * \{ */ +void _va_mul_m3_series_3( + float r[3][3], + float m1[3][3], float m2[3][3]) +{ + mul_m3_m3m3(r, m1, m2); +} +void _va_mul_m3_series_4( + float r[3][3], + float m1[3][3], float m2[3][3], float m3[3][3]) +{ + mul_m3_m3m3(r, m1, m2); + mul_m3_m3m3(r, r, m3); +} +void _va_mul_m3_series_5( + float r[3][3], + float m1[3][3], float m2[3][3], float m3[3][3], float m4[3][3]) +{ + mul_m3_m3m3(r, m1, m2); + mul_m3_m3m3(r, r, m3); + mul_m3_m3m3(r, r, m4); +} +void _va_mul_m3_series_6( + float r[3][3], + float m1[3][3], float m2[3][3], float m3[3][3], float m4[3][3], + float m5[3][3]) +{ + mul_m3_m3m3(r, m1, m2); + mul_m3_m3m3(r, r, m3); + mul_m3_m3m3(r, r, m4); + mul_m3_m3m3(r, r, m5); +} +void _va_mul_m3_series_7( + float r[3][3], + float m1[3][3], float m2[3][3], float m3[3][3], float m4[3][3], + float m5[3][3], float m6[3][3]) +{ + mul_m3_m3m3(r, m1, m2); + mul_m3_m3m3(r, r, m3); + mul_m3_m3m3(r, r, m4); + mul_m3_m3m3(r, r, m5); + mul_m3_m3m3(r, r, m6); +} +void _va_mul_m3_series_8( + float r[3][3], + float m1[3][3], float m2[3][3], float m3[3][3], float m4[3][3], + float m5[3][3], float m6[3][3], float m7[3][3]) +{ + mul_m3_m3m3(r, m1, m2); + mul_m3_m3m3(r, r, m3); + mul_m3_m3m3(r, r, m4); + mul_m3_m3m3(r, r, m5); + mul_m3_m3m3(r, r, m6); + mul_m3_m3m3(r, r, m7); +} +void _va_mul_m3_series_9( + float r[3][3], + float m1[3][3], float m2[3][3], float m3[3][3], float m4[3][3], + float m5[3][3], float m6[3][3], float m7[3][3], float m8[3][3]) +{ + mul_m3_m3m3(r, m1, m2); + mul_m3_m3m3(r, r, m3); + mul_m3_m3m3(r, r, m4); + mul_m3_m3m3(r, r, m5); + mul_m3_m3m3(r, r, m6); + mul_m3_m3m3(r, r, m7); + mul_m3_m3m3(r, r, m8); +} +/** \} */ + +/** \name Macro helpers for: mul_m4_series + * \{ */ +void _va_mul_m4_series_3( + float r[4][4], + float m1[4][4], float m2[4][4]) +{ + mul_m4_m4m4(r, m1, m2); +} +void _va_mul_m4_series_4( + float r[4][4], + float m1[4][4], float m2[4][4], float m3[4][4]) +{ + mul_m4_m4m4(r, m1, m2); + mul_m4_m4m4(r, r, m3); +} +void _va_mul_m4_series_5( + float r[4][4], + float m1[4][4], float m2[4][4], float m3[4][4], float m4[4][4]) +{ + mul_m4_m4m4(r, m1, m2); + mul_m4_m4m4(r, r, m3); + mul_m4_m4m4(r, r, m4); +} +void _va_mul_m4_series_6( + float r[4][4], + float m1[4][4], float m2[4][4], float m3[4][4], float m4[4][4], + float m5[4][4]) +{ + mul_m4_m4m4(r, m1, m2); + mul_m4_m4m4(r, r, m3); + mul_m4_m4m4(r, r, m4); + mul_m4_m4m4(r, r, m5); +} +void _va_mul_m4_series_7( + float r[4][4], + float m1[4][4], float m2[4][4], float m3[4][4], float m4[4][4], + float m5[4][4], float m6[4][4]) +{ + mul_m4_m4m4(r, m1, m2); + mul_m4_m4m4(r, r, m3); + mul_m4_m4m4(r, r, m4); + mul_m4_m4m4(r, r, m5); + mul_m4_m4m4(r, r, m6); +} +void _va_mul_m4_series_8( + float r[4][4], + float m1[4][4], float m2[4][4], float m3[4][4], float m4[4][4], + float m5[4][4], float m6[4][4], float m7[4][4]) +{ + mul_m4_m4m4(r, m1, m2); + mul_m4_m4m4(r, r, m3); + mul_m4_m4m4(r, r, m4); + mul_m4_m4m4(r, r, m5); + mul_m4_m4m4(r, r, m6); + mul_m4_m4m4(r, r, m7); +} +void _va_mul_m4_series_9( + float r[4][4], + float m1[4][4], float m2[4][4], float m3[4][4], float m4[4][4], + float m5[4][4], float m6[4][4], float m7[4][4], float m8[4][4]) +{ + mul_m4_m4m4(r, m1, m2); + mul_m4_m4m4(r, r, m3); + mul_m4_m4m4(r, r, m4); + mul_m4_m4m4(r, r, m5); + mul_m4_m4m4(r, r, m6); + mul_m4_m4m4(r, r, m7); + mul_m4_m4m4(r, r, m8); +} +/** \} */ void mul_v2_m3v2(float r[2], float m[3][3], float v[2]) { @@ -360,10 +437,9 @@ void mul_m3_v2(float m[3][3], float r[2]) void mul_m4_v3(float mat[4][4], float vec[3]) { - float x, y; + const float x = vec[0]; + const float y = vec[1]; - x = vec[0]; - y = vec[1]; vec[0] = x * mat[0][0] + y * mat[1][0] + mat[2][0] * vec[2] + mat[3][0]; vec[1] = x * mat[0][1] + y * mat[1][1] + mat[2][1] * vec[2] + mat[3][1]; vec[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2] + mat[3][2]; @@ -371,10 +447,9 @@ void mul_m4_v3(float mat[4][4], float vec[3]) void mul_v3_m4v3(float r[3], float mat[4][4], const float vec[3]) { - float x, y; + const float x = vec[0]; + const float y = vec[1]; - x = vec[0]; - y = vec[1]; r[0] = x * mat[0][0] + y * mat[1][0] + mat[2][0] * vec[2] + mat[3][0]; r[1] = x * mat[0][1] + y * mat[1][1] + mat[2][1] * vec[2] + mat[3][1]; r[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2] + mat[3][2]; @@ -382,18 +457,16 @@ void mul_v3_m4v3(float r[3], float mat[4][4], const float vec[3]) void mul_v2_m4v3(float r[2], float mat[4][4], const float vec[3]) { - float x; + const float x = vec[0]; - x = vec[0]; r[0] = x * mat[0][0] + vec[1] * mat[1][0] + mat[2][0] * vec[2] + mat[3][0]; r[1] = x * mat[0][1] + vec[1] * mat[1][1] + mat[2][1] * vec[2] + mat[3][1]; } void mul_v2_m2v2(float r[2], float mat[2][2], const float vec[2]) { - float x; + const float x = vec[0]; - x = vec[0]; r[0] = mat[0][0] * x + mat[1][0] * vec[1]; r[1] = mat[0][1] * x + mat[1][1] * vec[1]; } @@ -406,10 +479,9 @@ void mul_m2v2(float mat[2][2], float vec[2]) /* same as mul_m4_v3() but doesnt apply translation component */ void mul_mat3_m4_v3(float mat[4][4], float vec[3]) { - float x, y; + const float x = vec[0]; + const float y = vec[1]; - x = vec[0]; - y = vec[1]; vec[0] = x * mat[0][0] + y * mat[1][0] + mat[2][0] * vec[2]; vec[1] = x * mat[0][1] + y * mat[1][1] + mat[2][1] * vec[2]; vec[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2]; @@ -436,11 +508,9 @@ void mul_v2_project_m4_v3(float r[2], float mat[4][4], const float vec[3]) void mul_v4_m4v4(float r[4], float mat[4][4], const float v[4]) { - float x, y, z; - - x = v[0]; - y = v[1]; - z = v[2]; + const float x = v[0]; + const float y = v[1]; + const float z = v[2]; r[0] = x * mat[0][0] + y * mat[1][0] + z * mat[2][0] + mat[3][0] * v[3]; r[1] = x * mat[0][1] + y * mat[1][1] + z * mat[2][1] + mat[3][1] * v[3]; @@ -455,11 +525,9 @@ void mul_m4_v4(float mat[4][4], float r[4]) void mul_v4d_m4v4d(double r[4], float mat[4][4], double v[4]) { - double x, y, z; - - x = v[0]; - y = v[1]; - z = v[2]; + const double x = v[0]; + const double y = v[1]; + const double z = v[2]; r[0] = x * (double)mat[0][0] + y * (double)mat[1][0] + z * (double)mat[2][0] + (double)mat[3][0] * v[3]; r[1] = x * (double)mat[0][1] + y * (double)mat[1][1] + z * (double)mat[2][1] + (double)mat[3][1] * v[3]; @@ -499,10 +567,9 @@ void mul_m3_v3(float M[3][3], float r[3]) void mul_transposed_m3_v3(float mat[3][3], float vec[3]) { - float x, y; + const float x = vec[0]; + const float y = vec[1]; - x = vec[0]; - y = vec[1]; vec[0] = x * mat[0][0] + y * mat[0][1] + mat[0][2] * vec[2]; vec[1] = x * mat[1][0] + y * mat[1][1] + mat[1][2] * vec[2]; vec[2] = x * mat[2][0] + y * mat[2][1] + mat[2][2] * vec[2]; @@ -510,10 +577,9 @@ void mul_transposed_m3_v3(float mat[3][3], float vec[3]) void mul_transposed_mat3_m4_v3(float mat[4][4], float vec[3]) { - float x, y; + const float x = vec[0]; + const float y = vec[1]; - x = vec[0]; - y = vec[1]; vec[0] = x * mat[0][0] + y * mat[0][1] + mat[0][2] * vec[2]; vec[1] = x * mat[1][0] + y * mat[1][1] + mat[1][2] * vec[2]; vec[2] = x * mat[2][0] + y * mat[2][1] + mat[2][2] * vec[2]; @@ -566,10 +632,9 @@ void negate_m4(float m[4][4]) void mul_m3_v3_double(float mat[3][3], double vec[3]) { - double x, y; + const double x = vec[0]; + const double y = vec[1]; - x = vec[0]; - y = vec[1]; vec[0] = x * (double)mat[0][0] + y * (double)mat[1][0] + (double)mat[2][0] * vec[2]; vec[1] = x * (double)mat[0][1] + y * (double)mat[1][1] + (double)mat[2][1] * vec[2]; vec[2] = x * (double)mat[0][2] + y * (double)mat[1][2] + (double)mat[2][2] * vec[2]; @@ -621,11 +686,9 @@ float determinant_m3_array(float m[3][3]) bool invert_m3_ex(float m[3][3], const float epsilon) { float tmp[3][3]; - bool success; + const bool success = invert_m3_m3_ex(tmp, m, epsilon); - success = invert_m3_m3_ex(tmp, m, epsilon); copy_m3_m3(m, tmp); - return success; } @@ -659,11 +722,9 @@ bool invert_m3_m3_ex(float m1[3][3], float m2[3][3], const float epsilon) bool invert_m3(float m[3][3]) { float tmp[3][3]; - bool success; + const bool success = invert_m3_m3(tmp, m); - success = invert_m3_m3(tmp, m); copy_m3_m3(m, tmp); - return success; } @@ -696,11 +757,9 @@ bool invert_m3_m3(float m1[3][3], float m2[3][3]) bool invert_m4(float m[4][4]) { float tmp[4][4]; - bool success; + const bool success = invert_m4_m4(tmp, m); - success = invert_m4_m4(tmp, m); copy_m4_m4(m, tmp); - return success; } @@ -2115,7 +2174,7 @@ void pseudoinverse_m4_m4(float Ainv[4][4], float A[4][4], float epsilon) transpose_m4(V); - mul_serie_m4(Ainv, U, Wm, V, NULL, NULL, NULL, NULL, NULL); + mul_m4_series(Ainv, U, Wm, V); } void pseudoinverse_m3_m3(float Ainv[3][3], float A[3][3], float epsilon) @@ -2156,3 +2215,51 @@ void invert_m4_m4_safe(float Ainv[4][4], float A[4][4]) } } } + +/** + * SpaceTransform struct encapsulates all needed data to convert between two coordinate spaces + * (where conversion can be represented by a matrix multiplication). + * + * A SpaceTransform is initialized using: + * BLI_SPACE_TRANSFORM_SETUP(&data, ob1, ob2) + * + * After that the following calls can be used: + * BLI_space_transform_apply(&data, co); // converts a coordinate in ob1 space to the corresponding ob2 space + * BLI_space_transform_invert(&data, co); // converts a coordinate in ob2 space to the corresponding ob1 space + * + * Same concept as BLI_space_transform_apply and BLI_space_transform_invert, but no is normalized after conversion + * (and not translated at all!): + * BLI_space_transform_apply_normal(&data, no); + * BLI_space_transform_invert_normal(&data, no); + * + */ + +void BLI_space_transform_from_matrices(SpaceTransform *data, float local[4][4], float target[4][4]) +{ + float itarget[4][4]; + invert_m4_m4(itarget, target); + mul_m4_m4m4(data->local2target, itarget, local); + invert_m4_m4(data->target2local, data->local2target); +} + +void BLI_space_transform_apply(const SpaceTransform *data, float co[3]) +{ + mul_v3_m4v3(co, ((SpaceTransform *)data)->local2target, co); +} + +void BLI_space_transform_invert(const SpaceTransform *data, float co[3]) +{ + mul_v3_m4v3(co, ((SpaceTransform *)data)->target2local, co); +} + +void BLI_space_transform_apply_normal(const SpaceTransform *data, float no[3]) +{ + mul_mat3_m4_v3(((SpaceTransform *)data)->local2target, no); + normalize_v3(no); +} + +void BLI_space_transform_invert_normal(const SpaceTransform *data, float no[3]) +{ + mul_mat3_m4_v3(((SpaceTransform *)data)->target2local, no); + normalize_v3(no); +} diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c index dce2e9d54e3..141f9201689 100644 --- a/source/blender/blenlib/intern/math_rotation.c +++ b/source/blender/blenlib/intern/math_rotation.c @@ -139,7 +139,7 @@ float dot_qtqt(const float q1[4], const float q2[4]) void invert_qt(float q[4]) { - float f = dot_qtqt(q, q); + const float f = dot_qtqt(q, q); if (f == 0.0f) return; @@ -380,9 +380,8 @@ void mat3_to_quat_is_ok(float q[4], float wmat[3][3]) float normalize_qt(float q[4]) { - float len; + const float len = sqrtf(dot_qtqt(q, q)); - len = sqrtf(dot_qtqt(q, q)); if (len != 0.0f) { mul_qt_fl(q, 1.0f / len); } @@ -520,7 +519,7 @@ float angle_qtqt(const float q1[4], const float q2[4]) void vec_to_quat(float q[4], const float vec[3], short axis, const short upflag) { - const float eps = 0.0001f; + const float eps = 1e-4f; float nor[3], tvec[3]; float angle, si, co, len; @@ -669,7 +668,7 @@ void QuatInterpolW(float *result, float quat1[4], float quat2[4], float t) */ void interp_dot_slerp(const float t, const float cosom, float r_w[2]) { - const float eps = 0.0001f; + const float eps = 1e-4f; BLI_assert(IN_RANGE_INCL(cosom, -1.0001f, 1.0001f)); @@ -783,9 +782,8 @@ void tri_to_quat_ex(float quat[4], const float v1[3], const float v2[3], const f float tri_to_quat(float quat[4], const float v1[3], const float v2[3], const float v3[3]) { float vec[3]; - float len; + const float len = normal_tri_v3(vec, v1, v2, v3); - len = normal_tri_v3(vec, v1, v2, v3); tri_to_quat_ex(quat, v1, v2, v3, vec); return len; } @@ -1606,7 +1604,7 @@ void mat4_to_dquat(DualQuat *dq, float basemat[4][4], float mat[4][4]) mul_m4_m4m4(S, baseRinv, baseRS); /* set scaling part */ - mul_serie_m4(dq->scale, basemat, S, baseinv, NULL, NULL, NULL, NULL, NULL); + mul_m4_series(dq->scale, basemat, S, baseinv); dq->scale_weight = 1.0f; } else { @@ -1658,7 +1656,7 @@ void add_weighted_dq_dq(DualQuat *dqsum, const DualQuat *dq, float weight) /* make sure we interpolate quats in the right direction */ if (dot_qtqt(dq->quat, dqsum->quat) < 0) { - flipped = 1; + flipped = true; weight = -weight; } @@ -1689,7 +1687,7 @@ void add_weighted_dq_dq(DualQuat *dqsum, const DualQuat *dq, float weight) void normalize_dq(DualQuat *dq, float totweight) { - float scale = 1.0f / totweight; + const float scale = 1.0f / totweight; mul_qt_fl(dq->quat, scale); mul_qt_fl(dq->trans, scale); diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c index 15b88fe0c7f..6b37b0d5d32 100644 --- a/source/blender/blenlib/intern/math_vector.c +++ b/source/blender/blenlib/intern/math_vector.c @@ -35,7 +35,7 @@ void interp_v2_v2v2(float target[2], const float a[2], const float b[2], const float t) { - float s = 1.0f - t; + const float s = 1.0f - t; target[0] = s * a[0] + t * b[0]; target[1] = s * a[1] + t * b[1]; @@ -51,7 +51,7 @@ void interp_v2_v2v2v2(float p[2], const float v1[2], const float v2[2], const fl void interp_v3_v3v3(float target[3], const float a[3], const float b[3], const float t) { - float s = 1.0f - t; + const float s = 1.0f - t; target[0] = s * a[0] + t * b[0]; target[1] = s * a[1] + t * b[1]; @@ -60,7 +60,7 @@ void interp_v3_v3v3(float target[3], const float a[3], const float b[3], const f void interp_v4_v4v4(float target[4], const float a[4], const float b[4], const float t) { - float s = 1.0f - t; + const float s = 1.0f - t; target[0] = s * a[0] + t * b[0]; target[1] = s * a[1] + t * b[1]; @@ -119,8 +119,7 @@ bool interp_v2_v2v2_slerp(float target[2], const float a[2], const float b[2], c } /** - * Same as #interp_v3_v3v3_slerp buy uses fallback values - * for opposite vectors. + * Same as #interp_v3_v3v3_slerp but uses fallback values for opposite vectors. */ void interp_v3_v3v3_slerp_safe(float target[3], const float a[3], const float b[3], const float t) { @@ -208,7 +207,7 @@ void interp_v3_v3v3v3_uv(float p[3], const float v1[3], const float v2[3], const void interp_v3_v3v3_uchar(char unsigned target[3], const unsigned char a[3], const unsigned char b[3], const float t) { - float s = 1.0f - t; + const float s = 1.0f - t; target[0] = (char)floorf(s * a[0] + t * b[0]); target[1] = (char)floorf(s * a[1] + t * b[1]); @@ -221,7 +220,7 @@ void interp_v3_v3v3_char(char target[3], const char a[3], const char b[3], const void interp_v4_v4v4_uchar(char unsigned target[4], const unsigned char a[4], const unsigned char b[4], const float t) { - float s = 1.0f - t; + const float s = 1.0f - t; target[0] = (char)floorf(s * a[0] + t * b[0]); target[1] = (char)floorf(s * a[1] + t * b[1]); @@ -550,8 +549,7 @@ void angle_poly_v3(float *angles, const float *verts[3], int len) /* Project v1 on v2 */ void project_v2_v2v2(float c[2], const float v1[2], const float v2[2]) { - float mul; - mul = dot_v2v2(v1, v2) / dot_v2v2(v2, v2); + const float mul = dot_v2v2(v1, v2) / dot_v2v2(v2, v2); c[0] = mul * v2[0]; c[1] = mul * v2[1]; @@ -560,8 +558,7 @@ void project_v2_v2v2(float c[2], const float v1[2], const float v2[2]) /* Project v1 on v2 */ void project_v3_v3v3(float c[3], const float v1[3], const float v2[3]) { - float mul; - mul = dot_v3v3(v1, v2) / dot_v3v3(v2, v2); + const float mul = dot_v3v3(v1, v2) / dot_v3v3(v2, v2); c[0] = mul * v2[0]; c[1] = mul * v2[1]; @@ -837,7 +834,7 @@ double len_squared_vn(const float *array, const int size) float normalize_vn_vn(float *array_tar, const float *array_src, const int size) { - double d = len_squared_vn(array_src, size); + const double d = len_squared_vn(array_src, size); float d_sqrt; if (d > 1.0e-35) { d_sqrt = (float)sqrt(d); diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c index 135050f4a3f..0a990e0d63d 100644 --- a/source/blender/blenlib/intern/math_vector_inline.c +++ b/source/blender/blenlib/intern/math_vector_inline.c @@ -850,17 +850,17 @@ MINLINE void normal_float_to_short_v3(short out[3], const float in[3]) MINLINE bool is_zero_v2(const float v[2]) { - return (v[0] == 0 && v[1] == 0); + return (v[0] == 0.0f && v[1] == 0.0f); } MINLINE bool is_zero_v3(const float v[3]) { - return (v[0] == 0 && v[1] == 0 && v[2] == 0); + return (v[0] == 0.0f && v[1] == 0.0f && v[2] == 0.0f); } MINLINE bool is_zero_v4(const float v[4]) { - return (v[0] == 0 && v[1] == 0 && v[2] == 0 && v[3] == 0); + return (v[0] == 0.0f && v[1] == 0.0f && v[2] == 0.0f && v[3] == 0.0f); } MINLINE bool is_finite_v2(const float v[2]) @@ -880,7 +880,7 @@ MINLINE bool is_finite_v4(const float v[4]) MINLINE bool is_one_v3(const float v[3]) { - return (v[0] == 1 && v[1] == 1 && v[2] == 1); + return (v[0] == 1.0f && v[1] == 1.0f && v[2] == 1.0f); } diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 0b89ec1f0d0..a7fa443cfc4 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -1175,7 +1175,13 @@ static bool get_path_local(char *targetpath, const char *folder_name, const char } /* try EXECUTABLE_DIR/2.5x/folder_name - new default directory for local blender installed files */ +#ifdef __APPLE__ + static char osx_resourses[FILE_MAX]; /* due new codesign situation in OSX > 10.9.5 we must move the blender_version dir with contents to Resources */ + sprintf(osx_resourses, "%s../Resources", bprogdir); + return test_path(targetpath, osx_resourses, blender_version_decimal(ver), relfolder); +#else return test_path(targetpath, bprogdir, blender_version_decimal(ver), relfolder); +#endif } /** @@ -1415,7 +1421,7 @@ const char *BLI_get_folder_create(int folder_id, const char *subfolder) const char *path; /* only for user folders */ - if (!ELEM4(folder_id, BLENDER_USER_DATAFILES, BLENDER_USER_CONFIG, BLENDER_USER_SCRIPTS, BLENDER_USER_AUTOSAVE)) + if (!ELEM(folder_id, BLENDER_USER_DATAFILES, BLENDER_USER_CONFIG, BLENDER_USER_SCRIPTS, BLENDER_USER_AUTOSAVE)) return NULL; path = BLI_get_folder(folder_id, subfolder); @@ -1515,21 +1521,6 @@ void BLI_setenv_if_new(const char *env, const char *val) BLI_setenv(env, val); } - -/** - * Changes to the path separators to the native ones for this OS. - */ -void BLI_clean(char *path) -{ -#ifdef WIN32 - if (path && BLI_strnlen(path, 3) > 2) { - BLI_char_switch(path + 2, '/', '\\'); - } -#else - BLI_char_switch(path + BLI_path_unc_prefix_len(path), '\\', '/'); -#endif -} - /** * Change every \a from in \a string into \a to. The * result will be in \a string @@ -1681,7 +1672,7 @@ void BLI_make_file_string(const char *relabase, char *string, const char *dir, c strcat(string, file); /* Push all slashes to the system preferred direction */ - BLI_clean(string); + BLI_path_native_slash(string); } static bool testextensie_ex(const char *str, const size_t str_len, @@ -1783,7 +1774,7 @@ bool BLI_replace_extension(char *path, size_t maxlen, const char *ext) ssize_t a; for (a = path_len - 1; a >= 0; a--) { - if (ELEM3(path[a], '.', '/', '\\')) { + if (ELEM(path[a], '.', '/', '\\')) { break; } } @@ -2146,6 +2137,20 @@ void BLI_del_slash(char *string) } /** + * Changes to the path separators to the native ones for this OS. + */ +void BLI_path_native_slash(char *path) +{ +#ifdef WIN32 + if (path && BLI_strnlen(path, 3) > 2) { + BLI_char_switch(path + 2, '/', '\\'); + } +#else + BLI_char_switch(path + BLI_path_unc_prefix_len(path), '\\', '/'); +#endif +} + +/** * Tries appending each of the semicolon-separated extensions in the PATHEXT * environment variable (Windows-only) onto *name in turn until such a file is found. * Returns success/failure. diff --git a/source/blender/blenlib/intern/polyfill2d.c b/source/blender/blenlib/intern/polyfill2d.c index 71cda92842a..dd829e5d80a 100644 --- a/source/blender/blenlib/intern/polyfill2d.c +++ b/source/blender/blenlib/intern/polyfill2d.c @@ -387,7 +387,7 @@ static bool kdtree2d_isect_tri_recursive( (span_tri_v2_sign(tri_coords[1], tri_coords[2], co) != CONCAVE) && (span_tri_v2_sign(tri_coords[2], tri_coords[0], co) != CONCAVE)) { - if (!ELEM3(node->index, tri_index[0], tri_index[1], tri_index[2])) { + if (!ELEM(node->index, tri_index[0], tri_index[1], tri_index[2])) { return true; } } diff --git a/source/blender/blenlib/intern/rand.c b/source/blender/blenlib/intern/rand.c index 410f98897ce..3dff0b31091 100644 --- a/source/blender/blenlib/intern/rand.c +++ b/source/blender/blenlib/intern/rand.c @@ -95,15 +95,20 @@ void BLI_rng_srandom(RNG *rng, unsigned int seed) BLI_rng_seed(rng, seed + hash[seed & 255]); } -int BLI_rng_get_int(RNG *rng) +BLI_INLINE void rng_step(RNG *rng) { rng->X = (MULTIPLIER * rng->X + ADDEND) & MASK; +} + +int BLI_rng_get_int(RNG *rng) +{ + rng_step(rng); return (int) (rng->X >> 17); } unsigned int BLI_rng_get_uint(RNG *rng) { - rng->X = (MULTIPLIER * rng->X + ADDEND) & MASK; + rng_step(rng); return (unsigned int) (rng->X >> 17); } @@ -167,10 +172,9 @@ void BLI_rng_shuffle_array(RNG *rng, void *data, unsigned int elem_size_i, unsig void BLI_rng_skip(RNG *rng, int n) { - int i; - - for (i = 0; i < n; i++) - BLI_rng_get_int(rng); + while (n--) { + rng_step(rng); + } } /***/ diff --git a/source/blender/blenlib/intern/scanfill.c b/source/blender/blenlib/intern/scanfill.c index 05e4984d9a3..3d3dfeef302 100644 --- a/source/blender/blenlib/intern/scanfill.c +++ b/source/blender/blenlib/intern/scanfill.c @@ -865,6 +865,9 @@ unsigned int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const /* Newell's Method */ /* Similar code used elsewhere, but this checks for double ups * which historically this function supports so better not change */ + + /* warning: this only gives stable direction with single polygons, + * ideally we'd calcualte connectivity and calculate each polys normal, see T41047 */ const float *v_prev; zero_v3(n); diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c index 453b0cc939f..f3ecc799e1e 100644 --- a/source/blender/blenlib/intern/storage.c +++ b/source/blender/blenlib/intern/storage.c @@ -515,7 +515,7 @@ int BLI_stat(const char *path, BLI_stat_t *buffer) int BLI_wstat(const wchar_t *path, BLI_stat_t *buffer) { -#if (defined(_MSC_VER) && (_MSC_VER >= 1500)) || defined(__MINGW64__) +#if defined(_MSC_VER) || defined(__MINGW64__) return _wstat64(path, buffer); #elif defined(__MINGW32__) return _wstati64(path, buffer); diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c index aa705aaf63e..eeafc1a9e8f 100644 --- a/source/blender/blenlib/intern/string.c +++ b/source/blender/blenlib/intern/string.c @@ -648,7 +648,7 @@ int BLI_str_rstrip_float_zero(char *str, const char pad) * \param str_array_len The length of the array, or -1 for a NULL-terminated array. * \return The index of str in str_array or -1. */ -int BLI_str_index_in_array_n(const char *str, const char **str_array, const int str_array_len) +int BLI_str_index_in_array_n(const char *__restrict str, const char **__restrict str_array, const int str_array_len) { int index; const char **str_iter = str_array; @@ -668,7 +668,7 @@ int BLI_str_index_in_array_n(const char *str, const char **str_array, const int * \param str_array Array of strings, (must be NULL-terminated). * \return The index of str in str_array or -1. */ -int BLI_str_index_in_array(const char *str, const char **str_array) +int BLI_str_index_in_array(const char *__restrict str, const char **__restrict str_array) { int index; const char **str_iter = str_array; diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index 4fb983c119b..4b7b9cecb17 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -275,7 +275,8 @@ void BLO_main_expander(void (*expand_doit_func)(void *, struct Main *, void *)); */ void BLO_expand_main(void *fdhandle, struct Main *mainvar); -/* Update defaults in startup.blend, without having to save and embed it */ +/* Update defaults in startup.blend & userprefs.blend, without having to save and embed it */ +void BLO_update_defaults_userpref_blend(void); void BLO_update_defaults_startup_blend(struct Main *mainvar); #ifdef __cplusplus diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index eb10aae8adb..7a21c190966 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -434,8 +434,7 @@ void blo_join_main(ListBase *mainlist) while ((tojoin = mainl->next)) { add_main_to_main(mainl, tojoin); BLI_remlink(mainlist, tojoin); - MEM_freeN(tojoin->eval_ctx); - MEM_freeN(tojoin); + BKE_main_free(tojoin); } } @@ -1824,6 +1823,7 @@ static void lib_link_brush(FileData *fd, Main *main) brush->mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mtex.tex); brush->mask_mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mask_mtex.tex); brush->clone.image = newlibadr_us(fd, brush->id.lib, brush->clone.image); + brush->paint_curve = newlibadr_us(fd, brush->id.lib, brush->paint_curve); } } } @@ -1834,6 +1834,8 @@ static void direct_link_brush(FileData *fd, Brush *brush) /* fallof curve */ brush->curve = newdataadr(fd, brush->curve); + brush->gradient = newdataadr(fd, brush->gradient); + if (brush->curve) direct_link_curvemapping(fd, brush->curve); else @@ -1843,6 +1845,43 @@ static void direct_link_brush(FileData *fd, Brush *brush) brush->icon_imbuf = NULL; } +/* ************ READ Palette *************** */ +static void lib_link_palette(FileData *UNUSED(fd), Main *main) +{ + Palette *palette; + + /* only link ID pointers */ + for (palette = main->palettes.first; palette; palette = palette->id.next) { + if (palette->id.flag & LIB_NEED_LINK) { + palette->id.flag -= LIB_NEED_LINK; + } + } +} + +static void direct_link_palette(FileData *fd, Palette *palette) +{ + /* palette itself has been read */ + link_list(fd, &palette->colors); +} + +static void lib_link_paint_curve(FileData *UNUSED(fd), Main *main) +{ + PaintCurve *pc; + + /* only link ID pointers */ + for (pc = main->paintcurves.first; pc; pc = pc->id.next) { + if (pc->id.flag & LIB_NEED_LINK) { + pc->id.flag -= LIB_NEED_LINK; + } + } +} + +static void direct_link_paint_curve(FileData *fd, PaintCurve *pc) +{ + pc->points = newdataadr(fd, pc->points); +} + + static void direct_link_script(FileData *UNUSED(fd), Script *script) { script->id.us = 1; @@ -2664,9 +2703,9 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree) } } else if (ntree->type==NTREE_COMPOSIT) { - if (ELEM4(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT)) + if (ELEM(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT)) direct_link_curvemapping(fd, node->storage); - else if (ELEM3(node->type, CMP_NODE_IMAGE, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) + else if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) ((ImageUser *)node->storage)->ok = 1; } else if ( ntree->type==NTREE_TEXTURE) { @@ -3564,7 +3603,8 @@ static void direct_link_material(FileData *fd, Material *ma) for (a = 0; a < MAX_MTEX; a++) { ma->mtex[a] = newdataadr(fd, ma->mtex[a]); } - + ma->texpaintslot = NULL; + ma->ramp_col = newdataadr(fd, ma->ramp_col); ma->ramp_spec = newdataadr(fd, ma->ramp_spec); @@ -5107,6 +5147,7 @@ static void link_paint(FileData *fd, Scene *sce, Paint *p) { if (p) { p->brush = newlibadr_us(fd, sce->id.lib, p->brush); + p->palette = newlibadr_us(fd, sce->id.lib, p->palette); p->paint_cursor = NULL; } } @@ -5155,6 +5196,10 @@ static void lib_link_scene(FileData *fd, Main *main) sce->toolsettings->sculpt->gravity_object = newlibadr_us(fd, sce->id.lib, sce->toolsettings->sculpt->gravity_object); + if (sce->toolsettings->imapaint.stencil) + sce->toolsettings->imapaint.stencil = + newlibadr_us(fd, sce->id.lib, sce->toolsettings->imapaint.stencil); + sce->toolsettings->skgen_template = newlibadr(fd, sce->id.lib, sce->toolsettings->skgen_template); for (base = sce->base.first; base; base = next) { @@ -5403,7 +5448,7 @@ static void direct_link_scene(FileData *fd, Scene *sce) if (seq->strip && seq->strip->done==0) { seq->strip->done = true; - if (ELEM4(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) { + if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) { seq->strip->stripdata = newdataadr(fd, seq->strip->stripdata); } else { @@ -7186,6 +7231,8 @@ static const char *dataname(short id_code) case ID_NT: return "Data from NT"; case ID_BR: return "Data from BR"; case ID_PA: return "Data from PA"; + case ID_PAL: return "Data from PAL"; + case ID_PC: return "Data from PCRV"; case ID_GD: return "Data from GD"; case ID_WM: return "Data from WM"; case ID_MC: return "Data from MC"; @@ -7371,6 +7418,12 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID case ID_LS: direct_link_linestyle(fd, (FreestyleLineStyle *)id); break; + case ID_PAL: + direct_link_palette(fd, (Palette *)id); + break; + case ID_PC: + direct_link_paint_curve(fd, (PaintCurve *)id); + break; } oldnewmap_free_unused(fd->datamap); @@ -7559,6 +7612,8 @@ static void lib_link_all(FileData *fd, Main *main) lib_link_vfont(fd, main); lib_link_nodetree(fd, main); /* has to be done after scene/materials, this will verify group nodes */ lib_link_brush(fd, main); + lib_link_palette(fd, main); + lib_link_paint_curve(fd, main); lib_link_particlesettings(fd, main); lib_link_movieclip(fd, main); lib_link_mask(fd, main); @@ -8098,6 +8153,7 @@ static void expand_brush(FileData *fd, Main *mainvar, Brush *brush) expand_doit(fd, mainvar, brush->mtex.tex); expand_doit(fd, mainvar, brush->mask_mtex.tex); expand_doit(fd, mainvar, brush->clone.image); + expand_doit(fd, mainvar, brush->paint_curve); } static void expand_material(FileData *fd, Main *mainvar, Material *ma) diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c index 3890e07bb65..7c6b6ec7249 100644 --- a/source/blender/blenloader/intern/versioning_260.c +++ b/source/blender/blenloader/intern/versioning_260.c @@ -2454,9 +2454,9 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) if (sl->spacetype == SPACE_OUTLINER) { SpaceOops *so = (SpaceOops *)sl; - if (!ELEM11(so->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_SELECTED, SO_ACTIVE, - SO_SAME_TYPE, SO_GROUPS, SO_LIBRARIES, SO_SEQUENCE, SO_DATABLOCKS, - SO_USERDEF)) + if (!ELEM(so->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_SELECTED, SO_ACTIVE, + SO_SAME_TYPE, SO_GROUPS, SO_LIBRARIES, SO_SEQUENCE, SO_DATABLOCKS, + SO_USERDEF)) { so->outlinevis = SO_ALL_SCENES; } diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 12603ba71ef..01ca8d2d51d 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -34,6 +34,7 @@ /* allow readfile to use deprecated functionality */ #define DNA_DEPRECATED_ALLOW +#include "DNA_brush_types.h" #include "DNA_constraint_types.h" #include "DNA_sdna_types.h" #include "DNA_space_types.h" @@ -320,6 +321,13 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) mat->line_col[3] = mat->alpha; } } + + if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "int", "preview_start_resolution")) { + Scene *scene; + for (scene = main->scene.first; scene; scene = scene->id.next) { + scene->r.preview_start_resolution = 64; + } + } } if (!MAIN_VERSION_ATLEAST(main, 271, 2)) { @@ -345,6 +353,14 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } + if (!MAIN_VERSION_ATLEAST(main, 271, 3)) { + Brush *br; + + for (br = main->brush.first; br; br = br->id.next) { + br->fill_threshold = 0.2f; + } + } + if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "int", "preview_start_resolution")) { Scene *scene; for (scene = main->scene.first; scene; scene = scene->id.next) { diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index fdedd3f4edd..02f9c1fde17 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -28,6 +28,7 @@ #include "BLI_utildefines.h" #include "BLI_math.h" +#include "DNA_brush_types.h" #include "DNA_freestyle_types.h" #include "DNA_linestyle_types.h" #include "DNA_scene_types.h" @@ -36,14 +37,34 @@ #include "DNA_userdef_types.h" #include "DNA_mesh_types.h" #include "DNA_material_types.h" +#include "DNA_object_types.h" +#include "BKE_brush.h" +#include "BKE_library.h" #include "BKE_main.h" #include "BLO_readfile.h" -/* Update defaults in startup.blend, without having to save and embed the file. + +/** + * Override values in in-memory startup.blend, avoids resaving for small changes. + */ +void BLO_update_defaults_userpref_blend(void) +{ + /* defaults from T37518 */ + + U.uiflag |= USER_ZBUF_CURSOR; + U.uiflag |= USER_QUIT_PROMPT; + U.uiflag |= USER_CONTINUOUS_MOUSE; + + U.versions = 1; + U.savetime = 2; +} + +/** + * Update defaults in startup.blend, without having to save and embed the file. * This function can be emptied each time the startup.blend is updated. */ -void BLO_update_defaults_startup_blend(Main *main) +void BLO_update_defaults_startup_blend(Main *bmain) { Scene *scene; SceneRenderLayer *srl; @@ -51,7 +72,7 @@ void BLO_update_defaults_startup_blend(Main *main) Mesh *me; Material *mat; - for (scene = main->scene.first; scene; scene = scene->id.next) { + for (scene = bmain->scene.first; scene; scene = scene->id.next) { scene->r.im_format.planes = R_IMF_PLANES_RGBA; scene->r.im_format.compress = 15; @@ -59,9 +80,20 @@ void BLO_update_defaults_startup_blend(Main *main) srl->freestyleConfig.sphere_radius = 0.1f; srl->pass_alpha_threshold = 0.5f; } + + if (scene->toolsettings) { + ToolSettings *ts = scene->toolsettings; + + if (ts->sculpt) { + Sculpt *sculpt = ts->sculpt; + sculpt->paint.symmetry_flags |= PAINT_SYMM_X; + sculpt->flags |= SCULPT_DYNTOPO_COLLAPSE; + sculpt->detail_size = 12; + } + } } - for (linestyle = main->linestyle.first; linestyle; linestyle = linestyle->id.next) { + for (linestyle = bmain->linestyle.first; linestyle; linestyle = linestyle->id.next) { linestyle->flag = LS_SAME_OBJECT | LS_NO_SORTING | LS_TEXTURE; linestyle->sort_key = LS_SORT_KEY_DISTANCE_FROM_CAMERA; linestyle->integration_type = LS_INTEGRATION_MEAN; @@ -71,7 +103,7 @@ void BLO_update_defaults_startup_blend(Main *main) { bScreen *screen; - for (screen = main->screen.first; screen; screen = screen->id.next) { + for (screen = bmain->screen.first; screen; screen = screen->id.next) { ScrArea *area; for (area = screen->areabase.first; area; area = area->next) { SpaceLink *space_link; @@ -85,13 +117,27 @@ void BLO_update_defaults_startup_blend(Main *main) } } - for (me = main->mesh.first; me; me = me->id.next) { + for (me = bmain->mesh.first; me; me = me->id.next) { me->smoothresh = DEG2RADF(180.0f); + me->flag &= ~ME_TWOSIDED; } - for (mat = main->mat.first; mat; mat = mat->id.next) { + for (mat = bmain->mat.first; mat; mat = mat->id.next) { mat->line_col[0] = mat->line_col[1] = mat->line_col[2] = 0.0f; mat->line_col[3] = 1.0f; } + + { + Brush *br; + br = BKE_brush_add(bmain, "Fill"); + br->imagepaint_tool = PAINT_TOOL_FILL; + br->ob_mode = OB_MODE_TEXTURE_PAINT; + + br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Mask"); + if (br) { + br->imagepaint_tool = PAINT_TOOL_MASK; + br->ob_mode |= OB_MODE_TEXTURE_PAINT; + } + } } diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index 572c6d0a02d..557cc147f19 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -473,7 +473,7 @@ static void do_version_ntree_242_2(bNodeTree *ntree) if (ntree->type == NTREE_COMPOSIT) { for (node = ntree->nodes.first; node; node = node->next) { - if (ELEM3(node->type, CMP_NODE_IMAGE, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { + if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { /* only image had storage */ if (node->storage) { NodeImageAnim *nia = node->storage; @@ -2232,7 +2232,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) } if (sce->r.mode & R_PANORAMA) { - /* all these checks to ensure saved files with svn version keep working... */ + /* all these checks to ensure saved files between released versions keep working... */ if (sce->r.xsch < sce->r.ysch) { Object *obc = blo_do_versions_newlibadr(fd, lib, sce->camera); if (obc && obc->type == OB_CAMERA) { diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index de10e6fcfbf..82670d2d2b4 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -769,7 +769,7 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree) writedata(wd, DATA, strlen(nss->bytecode)+1, nss->bytecode); writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage); } - else if (ntree->type==NTREE_COMPOSIT && ELEM4(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT)) + else if (ntree->type==NTREE_COMPOSIT && ELEM(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT)) write_curvemapping(wd, node->storage); else if (ntree->type==NTREE_TEXTURE && (node->type==TEX_NODE_CURVE_RGB || node->type==TEX_NODE_CURVE_TIME) ) write_curvemapping(wd, node->storage); @@ -2363,6 +2363,9 @@ static void write_scenes(WriteData *wd, ListBase *scebase) case SEQ_TYPE_TRANSFORM: writestruct(wd, DATA, "TransformVars", 1, seq->effectdata); break; + case SEQ_TYPE_GAUSSIAN_BLUR: + writestruct(wd, DATA, "GaussianBlurVars", 1, seq->effectdata); + break; } } @@ -3028,6 +3031,38 @@ static void write_brushes(WriteData *wd, ListBase *idbase) if (brush->curve) write_curvemapping(wd, brush->curve); + if (brush->curve) + writestruct(wd, DATA, "ColorBand", 1, brush->gradient); + } + } +} + +static void write_palettes(WriteData *wd, ListBase *idbase) +{ + Palette *palette; + + for (palette = idbase->first; palette; palette = palette->id.next) { + if (palette->id.us > 0 || wd->current) { + PaletteColor *color; + writestruct(wd, ID_PAL, "Palette", 1, palette); + if (palette->id.properties) IDP_WriteProperty(palette->id.properties, wd); + + for (color = palette->colors.first; color; color= color->next) + writestruct(wd, DATA, "PaletteColor", 1, color); + } + } +} + +static void write_paintcurves(WriteData *wd, ListBase *idbase) +{ + PaintCurve *pc; + + for (pc = idbase->first; pc; pc = pc->id.next) { + if (pc->id.us > 0 || wd->current) { + writestruct(wd, ID_PC, "PaintCurve", 1, pc); + + writestruct(wd, DATA, "PaintCurvePoint", pc->tot_points, pc->points); + if (pc->id.properties) IDP_WriteProperty(pc->id.properties, wd); } } } @@ -3503,6 +3538,8 @@ static int write_file_handle(Main *mainvar, int handle, MemFile *compare, MemFil write_particlesettings(wd, &mainvar->particle); write_nodetrees(wd, &mainvar->nodetree); write_brushes (wd, &mainvar->brush); + write_palettes (wd, &mainvar->palettes); + write_paintcurves (wd, &mainvar->paintcurves); write_scripts (wd, &mainvar->script); write_gpencils (wd, &mainvar->gpencil); write_linestyles(wd, &mainvar->linestyle); diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h index 01745396cd1..39359b97a4e 100644 --- a/source/blender/bmesh/bmesh_class.h +++ b/source/blender/bmesh/bmesh_class.h @@ -285,8 +285,8 @@ extern void bpy_bm_generic_invalidate(struct BPy_BMGeneric *self); typedef bool (*BMElemFilterFunc)(BMElem *, void *user_data); /* defines */ -#define BM_ELEM_CD_SET_INT(ele, offset, f) \ - { assert(offset != -1); *((int *)((char *)(ele)->head.data + (offset))) = (f); } (void)0 +#define BM_ELEM_CD_SET_INT(ele, offset, f) { CHECK_TYPE_NONCONST(ele); \ + assert(offset != -1); *((int *)((char *)(ele)->head.data + (offset))) = (f); } (void)0 #define BM_ELEM_CD_GET_INT(ele, offset) \ (assert(offset != -1), *((int *)((char *)(ele)->head.data + (offset)))) @@ -294,8 +294,8 @@ typedef bool (*BMElemFilterFunc)(BMElem *, void *user_data); #define BM_ELEM_CD_GET_VOID_P(ele, offset) \ (assert(offset != -1), (void *)((char *)(ele)->head.data + (offset))) -#define BM_ELEM_CD_SET_FLOAT(ele, offset, f) \ - { assert(offset != -1); *((float *)((char *)(ele)->head.data + (offset))) = (f); } (void)0 +#define BM_ELEM_CD_SET_FLOAT(ele, offset, f) { CHECK_TYPE_NONCONST(ele); \ + assert(offset != -1); *((float *)((char *)(ele)->head.data + (offset))) = (f); } (void)0 #define BM_ELEM_CD_GET_FLOAT(ele, offset) \ (assert(offset != -1), *((float *)((char *)(ele)->head.data + (offset)))) diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index 18575b42d94..6f886ed5b37 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -1732,8 +1732,7 @@ BMEdge *bmesh_jekv(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, l_kill = l_kill->radial_next; } for (i = 0; i < radlen; i++) { - bm->totloop--; - BLI_mempool_free(bm->lpool, loops[i]); + bm_kill_only_loop(bm, loops[i]); } } #ifndef NDEBUG diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.c b/source/blender/bmesh/intern/bmesh_edgeloop.c index f01e1197bb7..e83a1d5b00a 100644 --- a/source/blender/bmesh/intern/bmesh_edgeloop.c +++ b/source/blender/bmesh/intern/bmesh_edgeloop.c @@ -682,12 +682,12 @@ void BM_edgeloop_expand(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store, int el_sto LinkData *node_curr_init = node_curr; LinkData *node_curr_copy; int i = 0; - LISTBASE_CIRCULAR_FORWARD_BEGIN (&el_store->verts, node_curr, node_curr_init) { + BLI_LISTBASE_CIRCULAR_FORWARD_BEGIN (&el_store->verts, node_curr, node_curr_init) { if (i++ < step) { break; } } - LISTBASE_CIRCULAR_FORWARD_END (&el_store->verts, node_curr, node_curr_init); + BLI_LISTBASE_CIRCULAR_FORWARD_END (&el_store->verts, node_curr, node_curr_init); node_curr_copy = MEM_dupallocN(node_curr); BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy); diff --git a/source/blender/bmesh/intern/bmesh_iterators_inline.h b/source/blender/bmesh/intern/bmesh_iterators_inline.h index 6a0eb0e0a30..b9733d4702f 100644 --- a/source/blender/bmesh/intern/bmesh_iterators_inline.h +++ b/source/blender/bmesh/intern/bmesh_iterators_inline.h @@ -80,60 +80,70 @@ BLI_INLINE bool BM_iter_init(BMIter *iter, BMesh *bm, const char itype, void *da break; case BM_EDGES_OF_VERT: BLI_assert(data != NULL); + BLI_assert(((BMElem *)data)->head.htype == BM_VERT); iter->begin = (BMIter__begin_cb)bmiter__edge_of_vert_begin; iter->step = (BMIter__step_cb)bmiter__edge_of_vert_step; iter->data.edge_of_vert.vdata = (BMVert *)data; break; case BM_FACES_OF_VERT: BLI_assert(data != NULL); + BLI_assert(((BMElem *)data)->head.htype == BM_VERT); iter->begin = (BMIter__begin_cb)bmiter__face_of_vert_begin; iter->step = (BMIter__step_cb)bmiter__face_of_vert_step; iter->data.face_of_vert.vdata = (BMVert *)data; break; case BM_LOOPS_OF_VERT: BLI_assert(data != NULL); + BLI_assert(((BMElem *)data)->head.htype == BM_VERT); iter->begin = (BMIter__begin_cb)bmiter__loop_of_vert_begin; iter->step = (BMIter__step_cb)bmiter__loop_of_vert_step; iter->data.loop_of_vert.vdata = (BMVert *)data; break; case BM_VERTS_OF_EDGE: BLI_assert(data != NULL); + BLI_assert(((BMElem *)data)->head.htype == BM_EDGE); iter->begin = (BMIter__begin_cb)bmiter__vert_of_edge_begin; iter->step = (BMIter__step_cb)bmiter__vert_of_edge_step; iter->data.vert_of_edge.edata = (BMEdge *)data; break; case BM_FACES_OF_EDGE: BLI_assert(data != NULL); + BLI_assert(((BMElem *)data)->head.htype == BM_EDGE); iter->begin = (BMIter__begin_cb)bmiter__face_of_edge_begin; iter->step = (BMIter__step_cb)bmiter__face_of_edge_step; iter->data.face_of_edge.edata = (BMEdge *)data; break; case BM_VERTS_OF_FACE: BLI_assert(data != NULL); + BLI_assert(((BMElem *)data)->head.htype == BM_FACE); iter->begin = (BMIter__begin_cb)bmiter__vert_of_face_begin; iter->step = (BMIter__step_cb)bmiter__vert_of_face_step; iter->data.vert_of_face.pdata = (BMFace *)data; break; case BM_EDGES_OF_FACE: BLI_assert(data != NULL); + BLI_assert(((BMElem *)data)->head.htype == BM_FACE); iter->begin = (BMIter__begin_cb)bmiter__edge_of_face_begin; iter->step = (BMIter__step_cb)bmiter__edge_of_face_step; iter->data.edge_of_face.pdata = (BMFace *)data; break; case BM_LOOPS_OF_FACE: BLI_assert(data != NULL); + BLI_assert(((BMElem *)data)->head.htype == BM_FACE); iter->begin = (BMIter__begin_cb)bmiter__loop_of_face_begin; iter->step = (BMIter__step_cb)bmiter__loop_of_face_step; iter->data.loop_of_face.pdata = (BMFace *)data; break; case BM_LOOPS_OF_LOOP: BLI_assert(data != NULL); + BLI_assert(((BMElem *)data)->head.htype == BM_LOOP); iter->begin = (BMIter__begin_cb)bmiter__loop_of_loop_begin; iter->step = (BMIter__step_cb)bmiter__loop_of_loop_step; iter->data.loop_of_loop.ldata = (BMLoop *)data; break; case BM_LOOPS_OF_EDGE: BLI_assert(data != NULL); + BLI_assert(((BMElem *)data)->head.htype == BM_EDGE); iter->begin = (BMIter__begin_cb)bmiter__loop_of_edge_begin; iter->step = (BMIter__step_cb)bmiter__loop_of_edge_step; iter->data.loop_of_edge.edata = (BMEdge *)data; diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c index a9e6dad7fd0..26a224c7c71 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.c +++ b/source/blender/bmesh/intern/bmesh_mesh.c @@ -802,7 +802,7 @@ void BM_mesh_elem_index_ensure(BMesh *bm, const char htype) } /* skip if we only need to operate on one element */ -#pragma omp parallel sections if ((!ELEM5(htype_needed, BM_VERT, BM_EDGE, BM_FACE, BM_LOOP, BM_FACE | BM_LOOP)) && \ +#pragma omp parallel sections if ((!ELEM(htype_needed, BM_VERT, BM_EDGE, BM_FACE, BM_LOOP, BM_FACE | BM_LOOP)) && \ (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT)) { #pragma omp section @@ -1056,7 +1056,7 @@ void BM_mesh_elem_table_ensure(BMesh *bm, const char htype) } /* skip if we only need to operate on one element */ -#pragma omp parallel sections if ((!ELEM3(htype_needed, BM_VERT, BM_EDGE, BM_FACE)) && \ +#pragma omp parallel sections if ((!ELEM(htype_needed, BM_VERT, BM_EDGE, BM_FACE)) && \ (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT)) { #pragma omp section @@ -1181,7 +1181,11 @@ int BM_mesh_elem_count(BMesh *bm, const char htype) * * WARNING: Be careful if you keep pointers to affected BM elements, or arrays, when using this func! */ -void BM_mesh_remap(BMesh *bm, unsigned int *vert_idx, unsigned int *edge_idx, unsigned int *face_idx) +void BM_mesh_remap( + BMesh *bm, + const unsigned int *vert_idx, + const unsigned int *edge_idx, + const unsigned int *face_idx) { /* Mapping old to new pointers. */ GHash *vptr_map = NULL, *eptr_map = NULL, *fptr_map = NULL; @@ -1194,18 +1198,23 @@ void BM_mesh_remap(BMesh *bm, unsigned int *vert_idx, unsigned int *edge_idx, un if (!(vert_idx || edge_idx || face_idx)) return; + BM_mesh_elem_table_ensure( + bm, + (vert_idx ? BM_VERT : 0) | + (edge_idx ? BM_EDGE : 0) | + (face_idx ? BM_FACE : 0)); + /* Remap Verts */ if (vert_idx) { BMVert **verts_pool, *verts_copy, **vep; int i, totvert = bm->totvert; - unsigned int *new_idx = NULL; + const unsigned int *new_idx; /* Init the old-to-new vert pointers mapping */ vptr_map = BLI_ghash_ptr_new_ex("BM_mesh_remap vert pointers mapping", bm->totvert); /* Make a copy of all vertices. */ - verts_pool = MEM_callocN(sizeof(BMVert *) * totvert, "BM_mesh_remap verts pool"); - BM_iter_as_array(bm, BM_VERTS_OF_MESH, NULL, (void **)verts_pool, totvert); + verts_pool = bm->vtable; verts_copy = MEM_mallocN(sizeof(BMVert) * totvert, "BM_mesh_remap verts copy"); for (i = totvert, ve = verts_copy + totvert - 1, vep = verts_pool + totvert - 1; i--; ve--, vep--) { *ve = **vep; @@ -1223,8 +1232,8 @@ void BM_mesh_remap(BMesh *bm, unsigned int *vert_idx, unsigned int *edge_idx, un BLI_ghash_insert(vptr_map, (void *)*vep, (void *)new_vep); } bm->elem_index_dirty |= BM_VERT; + bm->elem_table_dirty |= BM_VERT; - MEM_freeN(verts_pool); MEM_freeN(verts_copy); } @@ -1232,14 +1241,13 @@ void BM_mesh_remap(BMesh *bm, unsigned int *vert_idx, unsigned int *edge_idx, un if (edge_idx) { BMEdge **edges_pool, *edges_copy, **edp; int i, totedge = bm->totedge; - unsigned int *new_idx = NULL; + const unsigned int *new_idx; /* Init the old-to-new vert pointers mapping */ eptr_map = BLI_ghash_ptr_new_ex("BM_mesh_remap edge pointers mapping", bm->totedge); /* Make a copy of all vertices. */ - edges_pool = MEM_callocN(sizeof(BMEdge *) * totedge, "BM_mesh_remap edges pool"); - BM_iter_as_array(bm, BM_EDGES_OF_MESH, NULL, (void **)edges_pool, totedge); + edges_pool = bm->etable; edges_copy = MEM_mallocN(sizeof(BMEdge) * totedge, "BM_mesh_remap edges copy"); for (i = totedge, ed = edges_copy + totedge - 1, edp = edges_pool + totedge - 1; i--; ed--, edp--) { *ed = **edp; @@ -1256,8 +1264,8 @@ void BM_mesh_remap(BMesh *bm, unsigned int *vert_idx, unsigned int *edge_idx, un /* printf("mapping edge from %d to %d (%p/%p to %p)\n", i, *new_idx, *edp, edges_pool[i], new_edp);*/ } bm->elem_index_dirty |= BM_EDGE; + bm->elem_table_dirty |= BM_EDGE; - MEM_freeN(edges_pool); MEM_freeN(edges_copy); } @@ -1265,14 +1273,13 @@ void BM_mesh_remap(BMesh *bm, unsigned int *vert_idx, unsigned int *edge_idx, un if (face_idx) { BMFace **faces_pool, *faces_copy, **fap; int i, totface = bm->totface; - unsigned int *new_idx = NULL; + const unsigned int *new_idx; /* Init the old-to-new vert pointers mapping */ fptr_map = BLI_ghash_ptr_new_ex("BM_mesh_remap face pointers mapping", bm->totface); /* Make a copy of all vertices. */ - faces_pool = MEM_callocN(sizeof(BMFace *) * totface, "BM_mesh_remap faces pool"); - BM_iter_as_array(bm, BM_FACES_OF_MESH, NULL, (void **)faces_pool, totface); + faces_pool = bm->ftable; faces_copy = MEM_mallocN(sizeof(BMFace) * totface, "BM_mesh_remap faces copy"); for (i = totface, fa = faces_copy + totface - 1, fap = faces_pool + totface - 1; i--; fa--, fap--) { *fa = **fap; @@ -1289,8 +1296,8 @@ void BM_mesh_remap(BMesh *bm, unsigned int *vert_idx, unsigned int *edge_idx, un } bm->elem_index_dirty |= BM_FACE | BM_LOOP; + bm->elem_table_dirty |= BM_FACE; - MEM_freeN(faces_pool); MEM_freeN(faces_copy); } diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h index 3923c2515a3..da181df4eed 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.h +++ b/source/blender/bmesh/intern/bmesh_mesh.h @@ -69,7 +69,11 @@ BMFace *BM_face_at_index_find(BMesh *bm, const int index); int BM_mesh_elem_count(BMesh *bm, const char htype); -void BM_mesh_remap(BMesh *bm, unsigned int *vert_idx, unsigned int *edge_idx, unsigned int *face_idx); +void BM_mesh_remap( + BMesh *bm, + const unsigned int *vert_idx, + const unsigned int *edge_idx, + const unsigned int *face_idx); typedef struct BMAllocTemplate { int totvert, totedge, totloop, totface; diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index b9da7618df8..7dc46cf0678 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -956,6 +956,7 @@ static BMOpDefine bmo_dissolve_verts_def = { /* slots_in */ {{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, {"use_face_split", BMO_OP_SLOT_BOOL}, + {"use_boundary_tear", BMO_OP_SLOT_BOOL}, {{'\0'}}, }, {{{'\0'}}}, /* no output */ diff --git a/source/blender/bmesh/intern/bmesh_walkers.c b/source/blender/bmesh/intern/bmesh_walkers.c index 8f74e98e762..6a5efbe70ac 100644 --- a/source/blender/bmesh/intern/bmesh_walkers.c +++ b/source/blender/bmesh/intern/bmesh_walkers.c @@ -47,7 +47,7 @@ * * basic design pattern: the walker step function goes through it's * list of possible choices for recursion, and recurses (by pushing a new state) - * using the first non-visited one. this choise is the flagged as visited using + * using the first non-visited one. This choice is the flagged as visited using * the ghash. each step may push multiple new states onto the worklist at once. * * - Walkers use tool flags, not header flags. diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c index 9e9cd0d66e2..e4417477e76 100644 --- a/source/blender/bmesh/operators/bmo_bridge.c +++ b/source/blender/bmesh/operators/bmo_bridge.c @@ -119,7 +119,7 @@ static void bm_bridge_best_rotation(struct BMEdgeLoopStore *el_store_a, struct B } if (el_b_best) { - BLI_rotatelist_first(lb_b, el_b_best); + BLI_listbase_rotate_first(lb_b, el_b_best); } } @@ -272,7 +272,7 @@ static void bridge_loop_pair(BMesh *bm, const int len_b = BM_edgeloop_length_get(el_store_b); ListBase *lb_b = BM_edgeloop_verts_get(el_store_b); LinkData *el_b = BLI_rfindlink(lb_b, mod_i(twist_offset, len_b)); - BLI_rotatelist_first(lb_b, el_b); + BLI_listbase_rotate_first(lb_b, el_b); } } diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c index b497ab2f693..426e20939ca 100644 --- a/source/blender/bmesh/operators/bmo_connect_pair.c +++ b/source/blender/bmesh/operators/bmo_connect_pair.c @@ -134,7 +134,7 @@ static void state_calc_co_pair(const PathContext *pc, static bool state_link_find(PathLinkState *state, BMElem *ele) { PathLink *link = state->link_last; - BLI_assert(ELEM3(ele->head.htype, BM_VERT, BM_EDGE, BM_FACE)); + BLI_assert(ELEM(ele->head.htype, BM_VERT, BM_EDGE, BM_FACE)); if (link) { do { if (link->ele == ele) { diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c index 209ca30ddc3..877cd16d9d2 100644 --- a/source/blender/bmesh/operators/bmo_dissolve.c +++ b/source/blender/bmesh/operators/bmo_dissolve.c @@ -51,6 +51,7 @@ #define VERT_MARK_PAIR 4 #define VERT_TAG 2 #define VERT_ISGC 8 +#define VERT_MARK_TEAR 16 @@ -85,7 +86,7 @@ static bool UNUSED_FUNCTION(check_hole_in_region) (BMesh *bm, BMFace *f) return true; } -static void bm_face_split(BMesh *bm, const short oflag) +static void bm_face_split(BMesh *bm, const short oflag, bool use_edge_delete) { BMIter iter; BMVert *v; @@ -104,6 +105,12 @@ static void bm_face_split(BMesh *bm, const short oflag) } } } + /* remove surrounding edges & faces */ + if (use_edge_delete) { + while (v->e) { + BM_edge_kill(bm, v->e); + } + } } } } @@ -268,7 +275,7 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op) } } - bm_face_split(bm, VERT_TAG); + bm_face_split(bm, VERT_TAG, false); } if (use_verts) { @@ -345,13 +352,29 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op) BMFace *act_face = bm->act_face; const bool use_face_split = BMO_slot_bool_get(op->slots_in, "use_face_split"); + const bool use_boundary_tear = BMO_slot_bool_get(op->slots_in, "use_boundary_tear"); BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { BMO_elem_flag_enable(bm, v, VERT_MARK | VERT_ISGC); } if (use_face_split) { - bm_face_split(bm, VERT_MARK); + bm_face_split(bm, VERT_MARK, false); + } + + if (use_boundary_tear) { + BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { + if (!BM_vert_is_edge_pair(v)) { + BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { + if (BM_edge_is_boundary(e)) { + BMO_elem_flag_enable(bm, v, VERT_MARK_TEAR); + break; + } + } + } + } + + bm_face_split(bm, VERT_MARK_TEAR, true); } BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c index e13a9df4474..8bb4722ea07 100644 --- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c +++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c @@ -920,13 +920,13 @@ static void bm_edgering_pair_order(BMesh *bm, } BLI_assert(node != NULL); - BLI_rotatelist_first(lb_b, node); + BLI_listbase_rotate_first(lb_b, node); /* now check we are winding the same way */ if (bm_edgering_pair_order_is_flipped(bm, el_store_a, el_store_b)) { BM_edgeloop_flip(bm, el_store_b); /* re-ensure the first node */ - BLI_rotatelist_first(lb_b, node); + BLI_listbase_rotate_first(lb_b, node); } /* sanity checks that we are aligned & winding now */ diff --git a/source/blender/bmesh/operators/bmo_utils.c b/source/blender/bmesh/operators/bmo_utils.c index 600386893dd..d2d1c0854de 100644 --- a/source/blender/bmesh/operators/bmo_utils.c +++ b/source/blender/bmesh/operators/bmo_utils.c @@ -63,7 +63,7 @@ void bmo_transform_exec(BMesh *UNUSED(bm), BMOperator *op) if (!is_zero_m4(mat_space)) { invert_m4_m4(imat_space, mat_space); - mul_serie_m4(mat, imat_space, mat, mat_space, NULL, NULL, NULL, NULL, NULL); + mul_m4_series(mat, imat_space, mat, mat_space); } BMO_ITER (v, &iter, op->slots_in, "verts", BM_VERT) { diff --git a/source/blender/bmesh/tools/bmesh_beautify.c b/source/blender/bmesh/tools/bmesh_beautify.c index 90d26a775d3..6639e767e77 100644 --- a/source/blender/bmesh/tools/bmesh_beautify.c +++ b/source/blender/bmesh/tools/bmesh_beautify.c @@ -67,6 +67,7 @@ static unsigned int erot_gsetutil_hash(const void *ptr) return BLI_ghashutil_inthash_v4(&e_state->v1); } #endif +#if 0 static int erot_gsetutil_cmp(const void *a, const void *b) { const EdRotState *e_state_a = (const EdRotState *)a; @@ -81,10 +82,10 @@ static int erot_gsetutil_cmp(const void *a, const void *b) else if (e_state_a->f2 > e_state_b->f2) return 1; else return 0; } - +#endif static GSet *erot_gset_new(void) { - return BLI_gset_new(BLI_ghashutil_inthash_v4_p, erot_gsetutil_cmp, __func__); + return BLI_gset_new(BLI_ghashutil_inthash_v4_p, BLI_ghashutil_inthash_v4_cmp, __func__); } /* ensure v0 is smaller */ @@ -142,10 +143,10 @@ static float bm_edge_calc_rotate_beauty__area( float axis_mat[3][3]; // printf("%p %p %p %p - %p %p\n", v1, v2, v3, v4, e->l->f, e->l->radial_next->f); - BLI_assert((ELEM3(v1, v2, v3, v4) == false) && - (ELEM3(v2, v1, v3, v4) == false) && - (ELEM3(v3, v1, v2, v4) == false) && - (ELEM3(v4, v1, v2, v3) == false)); + BLI_assert((ELEM(v1, v2, v3, v4) == false) && + (ELEM(v2, v1, v3, v4) == false) && + (ELEM(v3, v1, v2, v4) == false) && + (ELEM(v4, v1, v2, v3) == false)); is_zero_a = (normal_tri_v3(no_a, v2, v3, v4) <= FLT_EPSILON); is_zero_b = (normal_tri_v3(no_b, v2, v4, v1) <= FLT_EPSILON); diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index bd7378f30e9..aedc551b5a6 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -1631,7 +1631,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) * corresponding ones that changed on the other end. * The graph is dynamic in the sense that having an offset that * doesn't meet the user spec can be added as the search proceeds. - * We want this search to be deterministic (not dependendent + * We want this search to be deterministic (not dependent * on order of processing through hash table), so as to avoid * flicker to to different decisions made if search is different * while dragging the offset number in the UI. So look for the @@ -3387,7 +3387,7 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme) VMesh *vm1, *vm2; EdgeHalf *e1, *e2; BMEdge *bme1, *bme2; - BMFace *f1, *f2, *f, *newf; + BMFace *f1, *f2, *f; int k, nseg, i1, i2, odd, mid; int mat_nr = bp->mat_nr; @@ -3428,7 +3428,7 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme) vm2 = bv2->vmesh; if (nseg == 1) { - newf = bev_create_quad_straddle(bm, bmv1, bmv2, bmv3, bmv4, f1, f2, mat_nr, e1->is_seam); + bev_create_quad_straddle(bm, bmv1, bmv2, bmv3, bmv4, f1, f2, mat_nr, e1->is_seam); } else { bmv1i = bmv1; diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c index 4b6209fc4eb..ef1783cc693 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c +++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c @@ -414,10 +414,10 @@ static void bm_decim_triangulate_end(BMesh *bm) BM_vert_in_edge(e, l_b->next->v) ? l_b->prev->v : l_b->next->v, }; - BLI_assert(ELEM3(vquad[0], vquad[1], vquad[2], vquad[3]) == false); - BLI_assert(ELEM3(vquad[1], vquad[0], vquad[2], vquad[3]) == false); - BLI_assert(ELEM3(vquad[2], vquad[1], vquad[0], vquad[3]) == false); - BLI_assert(ELEM3(vquad[3], vquad[1], vquad[2], vquad[0]) == false); + BLI_assert(ELEM(vquad[0], vquad[1], vquad[2], vquad[3]) == false); + BLI_assert(ELEM(vquad[1], vquad[0], vquad[2], vquad[3]) == false); + BLI_assert(ELEM(vquad[2], vquad[1], vquad[0], vquad[3]) == false); + BLI_assert(ELEM(vquad[3], vquad[1], vquad[2], vquad[0]) == false); if (is_quad_convex_v3(vquad[0]->co, vquad[1]->co, vquad[2]->co, vquad[3]->co)) { /* highly unlikely to fail, but prevents possible double-ups */ diff --git a/source/blender/bmesh/tools/bmesh_edgenet.c b/source/blender/bmesh/tools/bmesh_edgenet.c index a08aa6184b5..1328b81b746 100644 --- a/source/blender/bmesh/tools/bmesh_edgenet.c +++ b/source/blender/bmesh/tools/bmesh_edgenet.c @@ -393,8 +393,8 @@ static LinkNode *bm_edgenet_path_calc_best( if (path == NULL) { return NULL; } - else if (path_cost <= 1) { - /* any face that takes 1-2 iterations to find we consider valid */ + else if (path_cost < 1) { + /* any face that takes 1 iteration to find we consider valid */ return path; } else { @@ -465,7 +465,6 @@ void BM_mesh_edgenet(BMesh *bm, if (use_edge_tag == false) { BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - BM_elem_flag_enable(e, BM_ELEM_TAG); BM_elem_flag_set(e, BM_ELEM_TAG, bm_edge_step_ok(e)); } } diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp index d27795b0ab2..6e2d337a32e 100644 --- a/source/blender/collada/AnimationImporter.cpp +++ b/source/blender/collada/AnimationImporter.cpp @@ -804,7 +804,7 @@ void AnimationImporter::apply_matrix_curves(Object *ob, std::vector<FCurve *>& a // evaluate_joint_world_transform_at_frame(temp, NULL, node, fra); // calc special matrix - mul_serie_m4(mat, irest, temp, irest_dae, rest, NULL, NULL, NULL, NULL); + mul_m4_series(mat, irest, temp, irest_dae, rest); } else { copy_m4_m4(mat, matfra); @@ -1210,7 +1210,7 @@ void AnimationImporter::add_bone_animation_sampled(Object *ob, std::vector<FCurv // evaluate_joint_world_transform_at_frame(temp, NULL, node, fra); // calc special matrix - mul_serie_m4(mat, irest, temp, irest_dae, rest, NULL, NULL, NULL, NULL); + mul_m4_series(mat, irest, temp, irest_dae, rest); float rot[4], loc[3], scale[3]; @@ -1545,7 +1545,7 @@ Object *AnimationImporter::translate_animation_OLD(COLLADAFW::Node *node, // evaluate_joint_world_transform_at_frame(temp, NULL, node, fra); // calc special matrix - mul_serie_m4(mat, irest, temp, irest_dae, rest, NULL, NULL, NULL, NULL); + mul_m4_series(mat, irest, temp, irest_dae, rest); } else { copy_m4_m4(mat, matfra); diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index bbbbbf211c6..97d300e77f5 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -805,10 +805,14 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia // DIFFUSE // color if (ef->getDiffuse().isColor()) { + /* too high intensity can create artefacts (fireflies) + So here we take care that intensity is set to 0.8 wherever possible + */ col = ef->getDiffuse().getColor(); - ma->r = col.getRed(); - ma->g = col.getGreen(); - ma->b = col.getBlue(); + ma->ref = max_ffff(col.getRed(), col.getGreen(), col.getBlue(), 0.8); + ma->r = col.getRed() / ma->ref; + ma->g = col.getGreen() / ma->ref; + ma->b = col.getBlue() / ma->ref; } // texture else if (ef->getDiffuse().isTexture()) { diff --git a/source/blender/collada/TransformWriter.cpp b/source/blender/collada/TransformWriter.cpp index c3665a33ca4..595787b44ac 100644 --- a/source/blender/collada/TransformWriter.cpp +++ b/source/blender/collada/TransformWriter.cpp @@ -77,7 +77,7 @@ void TransformWriter::add_node_transform_ob(COLLADASW::Node& node, Object *ob, B BKE_object_to_mat4(ob, C); copy_v3_v3(ob->size, scale); - mul_serie_m4(tmat, ob->parent->obmat, ob->parentinv, C, NULL, NULL, NULL, NULL, NULL); + mul_m4_series(tmat, ob->parent->obmat, ob->parentinv, C); // calculate local mat diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt index a19433436f1..4bcdd4d9e34 100644 --- a/source/blender/compositor/CMakeLists.txt +++ b/source/blender/compositor/CMakeLists.txt @@ -39,7 +39,7 @@ set(INC ../nodes/intern ../render/extern/include ../render/intern/include - ../../../intern/opencl + ../../../extern/clew/include ../../../intern/guardedalloc ) @@ -175,6 +175,11 @@ set(SRC nodes/COM_GlareNode.cpp nodes/COM_GlareNode.h + nodes/COM_SunBeamsNode.cpp + nodes/COM_SunBeamsNode.h + operations/COM_SunBeamsOperation.cpp + operations/COM_SunBeamsOperation.h + nodes/COM_CornerPinNode.cpp nodes/COM_CornerPinNode.h nodes/COM_PlaneTrackDeformNode.cpp @@ -535,4 +540,6 @@ list(APPEND INC data_to_c(${CMAKE_CURRENT_SOURCE_DIR}/operations/COM_OpenCLKernels.cl ${CMAKE_CURRENT_BINARY_DIR}/operations/COM_OpenCLKernels.cl.h SRC) +add_definitions(-DCL_USE_DEPRECATED_OPENCL_1_1_APIS) + blender_add_lib(bf_compositor "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/compositor/COM_compositor.h b/source/blender/compositor/COM_compositor.h index 2cf2c690d3e..9b22444cf7f 100644 --- a/source/blender/compositor/COM_compositor.h +++ b/source/blender/compositor/COM_compositor.h @@ -208,7 +208,7 @@ extern "C" { * * @see ExecutionGroup.execute Execute a complete ExecutionGroup. Halts until finished or breaked by user * @see ExecutionGroup.scheduleChunkWhenPossible Tries to schedule a single chunk, - * checks if all input data is available. Can trigger dependant chunks to be calculated + * checks if all input data is available. Can trigger dependent chunks to be calculated * @see ExecutionGroup.scheduleAreaWhenPossible Tries to schedule an area. This can be multiple chunks * (is called from [@ref ExecutionGroup.scheduleChunkWhenPossible]) * @see ExecutionGroup.scheduleChunk Schedule a chunk on the WorkScheduler diff --git a/source/blender/compositor/SConscript b/source/blender/compositor/SConscript index 073b100e156..eab40873f64 100644 --- a/source/blender/compositor/SConscript +++ b/source/blender/compositor/SConscript @@ -26,7 +26,7 @@ # ***** END GPL LICENSE BLOCK ***** Import ('env') -defs = ['GLEW_STATIC'] +defs = ['GLEW_STATIC', 'CL_USE_DEPRECATED_OPENCL_1_1_APIS'] sources_intern = env.Glob('intern/*.cpp') sources_nodes = env.Glob('nodes/*.cpp') @@ -37,7 +37,7 @@ incs = [ 'intern', 'nodes', 'operations', - '#/intern/opencl', + '#/extern/clew/include', '../blenkernel', '../blenlib', '../imbuf', diff --git a/source/blender/compositor/intern/COM_Converter.cpp b/source/blender/compositor/intern/COM_Converter.cpp index 9251e161839..99f66bcb5b4 100644 --- a/source/blender/compositor/intern/COM_Converter.cpp +++ b/source/blender/compositor/intern/COM_Converter.cpp @@ -99,6 +99,7 @@ extern "C" { #include "COM_SetValueOperation.h" #include "COM_SplitViewerNode.h" #include "COM_Stabilize2dNode.h" +#include "COM_SunBeamsNode.h" #include "COM_SwitchNode.h" #include "COM_TextureNode.h" #include "COM_TimeNode.h" @@ -394,6 +395,9 @@ Node *Converter::convert(bNode *b_node) case CMP_NODE_CORNERPIN: node = new CornerPinNode(b_node); break; + case CMP_NODE_SUNBEAMS: + node = new SunBeamsNode(b_node); + break; } return node; } diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h index b2b8f03c476..d9c16615fb6 100644 --- a/source/blender/compositor/intern/COM_NodeOperation.h +++ b/source/blender/compositor/intern/COM_NodeOperation.h @@ -38,7 +38,7 @@ extern "C" { #include "COM_MemoryProxy.h" #include "COM_SocketReader.h" -#include "OCL_opencl.h" +#include "clew.h" using std::list; using std::min; diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.cpp b/source/blender/compositor/intern/COM_OpenCLDevice.cpp index 2cfc10cff29..c5b663d2aef 100644 --- a/source/blender/compositor/intern/COM_OpenCLDevice.cpp +++ b/source/blender/compositor/intern/COM_OpenCLDevice.cpp @@ -103,7 +103,7 @@ void OpenCLDevice::COM_clAttachMemoryBufferOffsetToKernelParameter(cl_kernel ker if (offsetIndex != -1) { cl_int error; rcti *rect = memoryBuffer->getRect(); - cl_int2 offset = {rect->xmin, rect->ymin}; + cl_int2 offset = {{rect->xmin, rect->ymin}}; error = clSetKernelArg(kernel, offsetIndex, sizeof(cl_int2), &offset); if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); } @@ -114,7 +114,7 @@ void OpenCLDevice::COM_clAttachSizeToKernelParameter(cl_kernel kernel, int offse { if (offsetIndex != -1) { cl_int error; - cl_int2 offset = {(cl_int)operation->getWidth(), (cl_int)operation->getHeight()}; + cl_int2 offset = {{(cl_int)operation->getWidth(), (cl_int)operation->getHeight()}}; error = clSetKernelArg(kernel, offsetIndex, sizeof(cl_int2), &offset); if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); } @@ -154,7 +154,7 @@ void OpenCLDevice::COM_clEnqueueRange(cl_kernel kernel, MemoryBuffer *outputMemo bool breaked = false; for (offsety = 0; offsety < height && (!breaked); offsety += localSize) { - offset[1] = offsety; + offset.y = offsety; if (offsety + localSize < height) { size[1] = localSize; } @@ -169,7 +169,7 @@ void OpenCLDevice::COM_clEnqueueRange(cl_kernel kernel, MemoryBuffer *outputMemo else { size[0] = width - offsetx; } - offset[0] = offsetx; + offset.x = offsetx; error = clSetKernelArg(kernel, offsetIndex, sizeof(cl_int2), &offset); if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); } diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.h b/source/blender/compositor/intern/COM_OpenCLDevice.h index 50cc6f25f70..94df2f2b44c 100644 --- a/source/blender/compositor/intern/COM_OpenCLDevice.h +++ b/source/blender/compositor/intern/COM_OpenCLDevice.h @@ -26,7 +26,7 @@ class OpenCLDevice; #define _COM_OpenCLDevice_h #include "COM_Device.h" -#include "OCL_opencl.h" +#include "clew.h" #include "COM_WorkScheduler.h" #include "COM_ReadBufferOperation.h" diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cpp b/source/blender/compositor/intern/COM_WorkScheduler.cpp index d60f9cb7f10..e1016731c7f 100644 --- a/source/blender/compositor/intern/COM_WorkScheduler.cpp +++ b/source/blender/compositor/intern/COM_WorkScheduler.cpp @@ -28,7 +28,7 @@ #include "COM_CPUDevice.h" #include "COM_OpenCLDevice.h" #include "COM_OpenCLKernels.cl.h" -#include "OCL_opencl.h" +#include "clew.h" #include "COM_WriteBufferOperation.h" #include "MEM_guardedalloc.h" @@ -274,7 +274,7 @@ bool WorkScheduler::hasGPUDevices() #endif } -static void clContextError(const char *errinfo, const void *private_info, size_t cb, void *user_data) +static void CL_CALLBACK clContextError(const char *errinfo, const void *private_info, size_t cb, void *user_data) { printf("OPENCL error: %s\n", errinfo); } @@ -326,7 +326,7 @@ void WorkScheduler::initialize(bool use_opencl, int num_cpu_threads) g_context = NULL; g_program = NULL; - if (!OCL_init()) /* this will check for errors and skip if already initialized */ + if (clewInit() != CLEW_SUCCESS) /* this will check for errors and skip if already initialized */ return; if (clCreateContextFromType) { diff --git a/source/blender/compositor/intern/COM_compositor.cpp b/source/blender/compositor/intern/COM_compositor.cpp index 99655c67a3f..ec9ef6c7e68 100644 --- a/source/blender/compositor/intern/COM_compositor.cpp +++ b/source/blender/compositor/intern/COM_compositor.cpp @@ -32,7 +32,7 @@ extern "C" { #include "COM_compositor.h" #include "COM_ExecutionSystem.h" #include "COM_WorkScheduler.h" -#include "OCL_opencl.h" +#include "clew.h" #include "COM_MovieDistortionOperation.h" static ThreadMutex s_compositorMutex; diff --git a/source/blender/compositor/nodes/COM_SunBeamsNode.cpp b/source/blender/compositor/nodes/COM_SunBeamsNode.cpp new file mode 100644 index 00000000000..ed14acabf36 --- /dev/null +++ b/source/blender/compositor/nodes/COM_SunBeamsNode.cpp @@ -0,0 +1,42 @@ +/* + * Copyright 2014, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Lukas Toenne + */ + +#include "COM_SunBeamsNode.h" +#include "COM_SunBeamsOperation.h" + +SunBeamsNode::SunBeamsNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void SunBeamsNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const +{ + NodeInput *inputSocket = this->getInputSocket(0); + NodeOutput *outputSocket = this->getOutputSocket(0); + NodeSunBeams *data = (NodeSunBeams *)getbNode()->storage; + + SunBeamsOperation *operation = new SunBeamsOperation(); + operation->setData(*data); + converter.addOperation(operation); + + converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); + converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_SunBeamsNode.h b/source/blender/compositor/nodes/COM_SunBeamsNode.h new file mode 100644 index 00000000000..4024eb276bc --- /dev/null +++ b/source/blender/compositor/nodes/COM_SunBeamsNode.h @@ -0,0 +1,37 @@ +/* + * Copyright 2014, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Lukas Toenne + */ + +#ifndef _COM_SunBeamsNode_h_ +#define _COM_SunBeamsNode_h_ + +#include "COM_Node.h" + +/** + * @brief SunBeamsNode + * @ingroup Node + */ +class SunBeamsNode : public Node { +public: + SunBeamsNode(bNode *editorNode); + void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; +}; + +#endif diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp index 0cea2a7183f..67f52934b13 100644 --- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp @@ -109,8 +109,8 @@ void DirectionalBlurOperation::executeOpenCL(OpenCLDevice *device, cl_kernel directionalBlurKernel = device->COM_clCreateKernel("directionalBlurKernel", NULL); cl_int iterations = pow(2.0f, this->m_data->iter); - cl_float2 ltxy = {this->m_tx, this->m_ty}; - cl_float2 centerpix = {this->m_center_x_pix, this->m_center_y_pix}; + cl_float2 ltxy = {{this->m_tx, this->m_ty}}; + cl_float2 centerpix = {{this->m_center_x_pix, this->m_center_y_pix}}; cl_float lsc = this->m_sc; cl_float lrot = this->m_rot; diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.cpp b/source/blender/compositor/operations/COM_MathBaseOperation.cpp index cbc60b5091d..32a1e77b9a7 100644 --- a/source/blender/compositor/operations/COM_MathBaseOperation.cpp +++ b/source/blender/compositor/operations/COM_MathBaseOperation.cpp @@ -335,12 +335,11 @@ void MathModuloOperation::executePixelSampled(float output[4], float x, float y, void MathAbsoluteOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler) { - float inputValue1[4]; + float inputValue1[4]; - this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); + this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); - output[0] = fabs(inputValue1[0]); + output[0] = fabs(inputValue1[0]); - clampIfNeeded(output); + clampIfNeeded(output); } - diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.h b/source/blender/compositor/operations/COM_MathBaseOperation.h index 05d2bb054d3..32cd19f1fb9 100644 --- a/source/blender/compositor/operations/COM_MathBaseOperation.h +++ b/source/blender/compositor/operations/COM_MathBaseOperation.h @@ -165,8 +165,8 @@ public: class MathAbsoluteOperation : public MathBaseOperation { public: - MathAbsoluteOperation() : MathBaseOperation() {} - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + MathAbsoluteOperation() : MathBaseOperation() {} + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); }; #endif diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp new file mode 100644 index 00000000000..97f9f7b5eea --- /dev/null +++ b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp @@ -0,0 +1,303 @@ +/* + * Copyright 2014, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Lukas Toenne + */ + +#include "MEM_guardedalloc.h" + +#include "COM_SunBeamsOperation.h" + +SunBeamsOperation::SunBeamsOperation() : NodeOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + this->setResolutionInputSocketIndex(0); + + this->setComplex(true); +} + +void SunBeamsOperation::initExecution() +{ + /* convert to pixels */ + this->m_source_px[0] = this->m_data.source[0] * this->getWidth(); + this->m_source_px[1] = this->m_data.source[1] * this->getHeight(); + this->m_ray_length_px = this->m_data.ray_length * max(this->getWidth(), this->getHeight()); +} + +/** + * Defines a line accumulator for a specific sector, + * given by the four matrix entries that rotate from buffer space into the sector + * + * (x,y) is used to designate buffer space coordinates + * (u,v) is used to designate sector space coordinates + * + * For a target point (x,y) the sector should be chosen such that + * ``u >= v >= 0`` + * This removes the need to handle all sorts of special cases. + */ +template <int fxx, int fxy, int fyx, int fyy> +struct BufferLineAccumulator { + + /* utility functions implementing the matrix transform to/from sector space */ + + static inline void buffer_to_sector(int x, int y, int &u, int &v) + { + u = x * fxx + y * fyx; + v = x * fxy + y * fyy; + } + + static inline void buffer_to_sector(float x, float y, float &u, float &v) + { + u = x * fxx + y * fyx; + v = x * fxy + y * fyy; + } + + static inline void sector_to_buffer(int u, int v, int &x, int &y) + { + x = u * fxx + v * fxy; + y = u * fyx + v * fyy; + } + + static inline void sector_to_buffer(float u, float v, float &x, float &y) + { + x = u * fxx + v * fxy; + y = u * fyx + v * fyy; + } + + /** + * Set up the initial buffer pointer and calculate necessary variables for looping. + * + * Note that sector space is centered around the "source" point while the loop starts + * at dist_min from the target pt. This way the loop can be canceled as soon as it runs + * out of the buffer rect, because no pixels further along the line can contribute. + * + * \param x, y Start location in the buffer + * \param num Total steps in the loop + * \param v, dv Vertical offset in sector space, for line offset perpendicular to the loop axis + */ + static float *init_buffer_iterator(MemoryBuffer *input, const float source[2], const float pt_ofs[2], + float dist_min, float dist_max, + int &x, int &y, int &num, float &v, float &dv) + { + float pu, pv; + buffer_to_sector(pt_ofs[0], pt_ofs[1], pu, pv); + + /* line angle */ + float tan_phi = pv / pu; + float cos_phi = 1.0f / sqrtf(tan_phi * tan_phi + 1.0f); + + float umin = pu - cos_phi * dist_min; + float umax = pu - cos_phi * dist_max; + v = umin * tan_phi; + dv = tan_phi; + + sector_to_buffer(umin, v, x, y); + x += source[0]; + y += source[1]; + + num = (int)ceilf(umin) - max_ii((int)floorf(umax), 1); + + float *iter = input->getBuffer() + COM_NUMBER_OF_CHANNELS * (x + input->getWidth() * y); + return iter; + } + + /** + * Perform the actual accumulation along a ray segment from source to pt. + * Only pixels withing dist_min..dist_max contribute. + * + * The loop runs backwards(!) over the primary sector space axis u, i.e. increasing distance to pt. + * After each step it decrements v by dv < 1, adding a buffer shift when necessary. + */ + static void eval(MemoryBuffer *input, float output[4], const float pt_ofs[2], const float source[2], + float dist_min, float dist_max) + { + rcti rect = *input->getRect(); + int buffer_width = input->getWidth(); + int x, y, num; + float v, dv; + + /* initialise the iteration variables */ + float *buffer = init_buffer_iterator(input, source, pt_ofs, dist_min, dist_max, x, y, num, v, dv); + + float falloff_factor = num > 1 ? 1.0f / (float)(num - 1) : 0.0f; + + int tot = 0; + + /* v_local keeps track of when to decrement v (see below) */ + float v_local = v - floorf(v); + + for (int i = 0; i < num; i++) { + /* range check, abort when running beyond the image border */ + if (x < rect.xmin || x >= rect.xmax || y < rect.ymin || y >= rect.ymax) + break; + + float f = 1.0f - (float)i * falloff_factor; + madd_v4_v4fl(output, buffer, buffer[3] * f * f); + /* TODO implement proper filtering here, see + * http://en.wikipedia.org/wiki/Lanczos_resampling + * http://en.wikipedia.org/wiki/Sinc_function + * + * using lanczos with x = distance from the line segment, + * normalized to a == 0.5f, could give a good result + * + * for now just count samples and divide equally at the end ... + */ + tot++; + + /* decrement u */ + x -= fxx; + y -= fyx; + buffer -= (fxx + fyx * buffer_width) * COM_NUMBER_OF_CHANNELS; + + /* decrement v (in steps of dv < 1) */ + v_local -= dv; + if (v_local < 0.0f) { + v_local += 1.0f; + + x -= fxy; + y -= fyy; + buffer -= (fxy + fyy * buffer_width) * COM_NUMBER_OF_CHANNELS; + } + } + + /* normalize */ + if (num > 0) { + mul_v4_fl(output, 1.0f / (float)num); + } + } +}; + +/** + * Dispatch function which selects an appropriate accumulator based on the sector of the target point, + * relative to the source. + * + * The BufferLineAccumulator defines the actual loop over the buffer, with an efficient inner loop + * due to using compile time constants instead of a local matrix variable defining the sector space. + */ +static void accumulate_line(MemoryBuffer *input, float output[4], const float co[2], const float source[2], + float dist_min, float dist_max) +{ + /* coordinates relative to source */ + float pt_ofs[2] = {co[0] - source[0], co[1] - source[1]}; + + /* The source sectors are defined like so: + * + * \ 3 | 2 / + * \ | / + * 4 \ | / 1 + * \|/ + * ----------- + * /|\ + * 5 / | \ 8 + * / | \ + * / 6 | 7 \ + * + * The template arguments encode the transformation into "sector space", + * by means of rotation/mirroring matrix elements. + */ + + if (fabsf(pt_ofs[1]) > fabsf(pt_ofs[0])) { + if (pt_ofs[0] > 0.0f) { + if (pt_ofs[1] > 0.0f) { + /* 2 */ + BufferLineAccumulator<0, 1, 1, 0>::eval(input, output, pt_ofs, source, dist_min, dist_max); + } + else { + /* 7 */ + BufferLineAccumulator<0, 1, -1, 0>::eval(input, output, pt_ofs, source, dist_min, dist_max); + } + } + else { + if (pt_ofs[1] > 0.0f) { + /* 3 */ + BufferLineAccumulator<0, -1, 1, 0>::eval(input, output, pt_ofs, source, dist_min, dist_max); + } + else { + /* 6 */ + BufferLineAccumulator<0, -1, -1, 0>::eval(input, output, pt_ofs, source, dist_min, dist_max); + } + } + } + else { + if (pt_ofs[0] > 0.0f) { + if (pt_ofs[1] > 0.0f) { + /* 1 */ + BufferLineAccumulator< 1, 0, 0, 1>::eval(input, output, pt_ofs, source, dist_min, dist_max); + } + else { + /* 8 */ + BufferLineAccumulator< 1, 0, 0, -1>::eval(input, output, pt_ofs, source, dist_min, dist_max); + } + } + else { + if (pt_ofs[1] > 0.0f) { + /* 4 */ + BufferLineAccumulator<-1, 0, 0, 1>::eval(input, output, pt_ofs, source, dist_min, dist_max); + } + else { + /* 5 */ + BufferLineAccumulator<-1, 0, 0, -1>::eval(input, output, pt_ofs, source, dist_min, dist_max); + } + } + } +} + +void *SunBeamsOperation::initializeTileData(rcti *rect) +{ + void *buffer = getInputOperation(0)->initializeTileData(NULL); + return buffer; +} + +void SunBeamsOperation::executePixel(float output[4], int x, int y, void *data) +{ + const float co[2] = {(float)x, (float)y}; + + accumulate_line((MemoryBuffer *)data, output, co, this->m_source_px, 0.0f, this->m_ray_length_px); +} + +static void calc_ray_shift(rcti *rect, float x, float y, const float source[2], float ray_length) +{ + float co[2] = {x, y}; + float dir[2], dist; + + /* move (x,y) vector toward the source by ray_length distance */ + sub_v2_v2v2(dir, co, source); + dist = normalize_v2(dir); + mul_v2_fl(dir, min_ff(dist, ray_length)); + sub_v2_v2(co, dir); + + int ico[2] = {(int)co[0], (int)co[1]}; + BLI_rcti_do_minmax_v(rect, ico); +} + +bool SunBeamsOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) +{ + /* Enlarges the rect by moving each corner toward the source. + * This is the maximum distance that pixels can influence each other + * and gives a rect that contains all possible accumulated pixels. + */ + rcti rect = *input; + calc_ray_shift(&rect, input->xmin, input->ymin, this->m_source_px, this->m_ray_length_px); + calc_ray_shift(&rect, input->xmin, input->ymax, this->m_source_px, this->m_ray_length_px); + calc_ray_shift(&rect, input->xmax, input->ymin, this->m_source_px, this->m_ray_length_px); + calc_ray_shift(&rect, input->xmax, input->ymax, this->m_source_px, this->m_ray_length_px); + + return NodeOperation::determineDependingAreaOfInterest(&rect, readOperation, output); +} + diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.h b/source/blender/compositor/operations/COM_SunBeamsOperation.h new file mode 100644 index 00000000000..ef80a31fe40 --- /dev/null +++ b/source/blender/compositor/operations/COM_SunBeamsOperation.h @@ -0,0 +1,48 @@ +/* + * Copyright 2014, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Lukas Toenne + */ + +#ifndef _COM_SunBeamsOperation_h +#define _COM_SunBeamsOperation_h + +#include "COM_NodeOperation.h" + +class SunBeamsOperation : public NodeOperation { +public: + SunBeamsOperation(); + + void executePixel(float output[4], int x, int y, void *data); + + void initExecution(); + + void *initializeTileData(rcti *rect); + + bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output); + + void setData(const NodeSunBeams &data) { m_data = data; } + +private: + NodeSunBeams m_data; + + float m_source_px[2]; + float m_ray_length_px; +}; + +#endif diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 3530857266d..7d8e278f0cf 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -3846,7 +3846,7 @@ void ANIM_channel_draw_widgets(bContext *C, bAnimContext *ac, bAnimListElem *ale short offset; /* sanity checks - don't draw anything */ - if (ELEM3(NULL, acf, ale, block)) + if (ELEM(NULL, acf, ale, block)) return; /* get initial offset */ diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 9997cc07c19..b6ab0407711 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -605,7 +605,7 @@ static int animedit_poll_channels_active(bContext *C) if (ELEM(NULL, sa, CTX_wm_region(C))) return 0; /* animation editor test */ - if (ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0) + if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0) return 0; return 1; @@ -622,7 +622,7 @@ static int animedit_poll_channels_nla_tweakmode_off(bContext *C) if (ELEM(NULL, sa, CTX_wm_region(C))) return 0; /* animation editor test */ - if (ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0) + if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0) return 0; /* NLA TweakMode test */ @@ -901,10 +901,10 @@ static void rearrange_animchannels_filter_visible(ListBase *anim_data_visible, b { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale, *ale_next; - int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); + int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); /* get all visible channels */ - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* now, only keep the ones that are of the types we are interested in */ for (ale = anim_data.first; ale; ale = ale_next) { @@ -2257,7 +2257,7 @@ static int animchannels_find_poll(bContext *C) return 0; /* animation editor with dopesheet */ - return ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA); + return ELEM(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA); } /* find_invoke() - Get initial channels */ @@ -2802,7 +2802,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index, /* deselect all other channels */ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR); - if (pchan) ED_pose_deselectall(ob, 0); + if (pchan) ED_pose_de_selectall(ob, SEL_DESELECT, false); /* only select channels in group and group itself */ for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next) @@ -2812,7 +2812,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index, else { /* select group by itself */ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR); - if (pchan) ED_pose_deselectall(ob, 0); + if (pchan) ED_pose_de_selectall(ob, SEL_DESELECT, false); agrp->flag |= AGRP_SELECTED; } diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c index 640349199be..f3b47b168e9 100644 --- a/source/blender/editors/animation/anim_deps.c +++ b/source/blender/editors/animation/anim_deps.c @@ -193,7 +193,7 @@ static void animchan_sync_fcurve(bAnimContext *ac, bAnimListElem *ale, FCurve ** /* major priority is selection status, so refer to the checks done in anim_filter.c * skip_fcurve_selected_data() for reference about what's going on here... */ - if (ELEM3(NULL, fcu, fcu->rna_path, owner_id)) + if (ELEM(NULL, fcu, fcu->rna_path, owner_id)) return; if (GS(owner_id->name) == ID_OB) { diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c index d3e6d8f474f..57df6d32f03 100644 --- a/source/blender/editors/animation/anim_ipo_utils.c +++ b/source/blender/editors/animation/anim_ipo_utils.c @@ -63,7 +63,7 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu) /* sanity checks */ if (name == NULL) return icon; - else if (ELEM3(NULL, id, fcu, fcu->rna_path)) { + else if (ELEM(NULL, id, fcu, fcu->rna_path)) { if (fcu == NULL) strcpy(name, IFACE_("<invalid>")); else if (fcu->rna_path == NULL) diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index e519fc8bfef..a133bc49a69 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -204,7 +204,7 @@ void ED_markers_get_minmax(ListBase *markers, short sel, float *first, float *la /* sanity check */ //printf("markers = %p - %p, %p\n", markers, markers->first, markers->last); - if (ELEM3(NULL, markers, markers->first, markers->last)) { + if (ELEM(NULL, markers, markers->first, markers->last)) { *first = 0.0f; *last = 0.0f; return; @@ -1012,14 +1012,14 @@ static void select_timeline_marker_frame(ListBase *markers, int frame, bool exte } } - LISTBASE_CIRCULAR_FORWARD_BEGIN (markers, marker, marker_first) { + BLI_LISTBASE_CIRCULAR_FORWARD_BEGIN (markers, marker, marker_first) { /* this way a not-extend select will allways give 1 selected marker */ if (marker->frame == frame) { marker->flag ^= SELECT; break; } } - LISTBASE_CIRCULAR_FORWARD_END (markers, marker, marker_first); + BLI_LISTBASE_CIRCULAR_FORWARD_END (markers, marker, marker_first); } static int ed_marker_select(bContext *C, const wmEvent *event, bool extend, bool camera) diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 88429aa3867..620bd52e527 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -72,7 +72,7 @@ static int change_frame_poll(bContext *C) * this shouldn't show up in 3D editor (or others without 2D timeline view) via search */ if (sa) { - if (ELEM5(sa->spacetype, SPACE_TIME, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) { + if (ELEM(sa->spacetype, SPACE_TIME, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) { return true; } else if (sa->spacetype == SPACE_IPO) { diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index ee5039488bd..83593faff22 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -670,8 +670,8 @@ static short snap_bezier_horizontal(KeyframeEditData *UNUSED(ked), BezTriple *be if (bezt->f2 & SELECT) { bezt->vec[0][1] = bezt->vec[2][1] = bezt->vec[1][1]; - if (ELEM3(bezt->h1, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) bezt->h1 = HD_ALIGN; - if (ELEM3(bezt->h2, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) bezt->h2 = HD_ALIGN; + if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) bezt->h1 = HD_ALIGN; + if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) bezt->h2 = HD_ALIGN; } return 0; } @@ -810,9 +810,9 @@ KeyframeEditFunc ANIM_editkeyframes_mirror(short type) */ #define ENSURE_HANDLES_MATCH(bezt) \ if (bezt->h1 != bezt->h2) { \ - if (ELEM3(bezt->h1, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) \ + if (ELEM(bezt->h1, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) \ bezt->h1 = HD_FREE; \ - if (ELEM3(bezt->h2, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) \ + if (ELEM(bezt->h2, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) \ bezt->h2 = HD_FREE; \ } (void)0 diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 878c9193b23..a68751e9294 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -652,7 +652,7 @@ static bool visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop) const char *identifier = NULL; /* validate data */ - if (ELEM3(NULL, ptr, ptr->data, prop)) + if (ELEM(NULL, ptr, ptr->data, prop)) return 0; /* get first constraint and determine type of keyframe constraints to check for @@ -1042,7 +1042,7 @@ short insert_keyframe(ReportList *reports, ID *id, bAction *act, const char grou /* for Loc/Rot/Scale and also Color F-Curves, the color of the F-Curve in the Graph Editor, * is determined by the array index for the F-Curve */ - if (ELEM5(RNA_property_subtype(prop), PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) { + if (ELEM(RNA_property_subtype(prop), PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) { fcu->color_mode = FCURVE_COLOR_AUTO_RGB; } } diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt index ca2dc1b66e2..9aa17f1e503 100644 --- a/source/blender/editors/armature/CMakeLists.txt +++ b/source/blender/editors/armature/CMakeLists.txt @@ -26,6 +26,7 @@ set(INC ../../makesdna ../../makesrna ../../windowmanager + ../../gpu ../../../../intern/guardedalloc ) diff --git a/source/blender/editors/armature/SConscript b/source/blender/editors/armature/SConscript index b3c1ea2dbe9..c68045c9398 100644 --- a/source/blender/editors/armature/SConscript +++ b/source/blender/editors/armature/SConscript @@ -39,6 +39,7 @@ incs = [ '../../blenlib', '../../makesdna', '../../makesrna', + '../../gpu', '../../windowmanager', ] incs = ' '.join(incs) diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index f71cfd52175..1e4d9bac246 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -1343,7 +1343,9 @@ static int armature_reveal_exec(bContext *C, wmOperator *UNUSED(op)) for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (arm->layer & ebone->layer) { if (ebone->flag & BONE_HIDDEN_A) { - ebone->flag |= (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); + if (!(ebone->flag & BONE_UNSELECTABLE)) { + ebone->flag |= (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); + } ebone->flag &= ~BONE_HIDDEN_A; } } diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index 9c3c93e4850..12d13b05ee1 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -160,7 +160,7 @@ void *get_nearest_bone(bContext *C, short findunsel, int x, int y) rect.ymin = rect.ymax = y; glInitNames(); - hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect); + hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true); if (hits > 0) return get_bone_from_selectbuffer(vc.scene, vc.scene->basact, buffer, hits, findunsel); @@ -295,13 +295,13 @@ static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2], rect.ymin = mval[1] - 5; rect.ymax = mval[1] + 5; - hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect); + hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, true); if (hits == 0) { rect.xmin = mval[0] - 12; rect.xmax = mval[0] + 12; rect.ymin = mval[1] - 12; rect.ymax = mval[1] + 12; - hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect); + hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, true); } /* See if there are any selected bones in this group */ if (hits > 0) { diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c index e898e600e9b..57ae03ccebe 100644 --- a/source/blender/editors/armature/armature_skinning.c +++ b/source/blender/editors/armature/armature_skinning.c @@ -200,10 +200,22 @@ static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], i float distance; int i, iflip, j; bool use_topology = (mesh->editflag & ME_EDIT_MIRROR_TOPO) != 0; + bool use_mask = false; + + if ((ob->mode & OB_MODE_WEIGHT_PAINT) && + (mesh->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL))) + { + use_mask = true; + } /* for each vertex in the mesh */ for (i = 0; i < mesh->totvert; i++) { - iflip = (dgroupflip) ? mesh_get_x_mirror_vert(ob, i, use_topology) : 0; + + if (use_mask && !(mesh->mvert[i].flag & SELECT)) { + continue; + } + + iflip = (dgroupflip) ? mesh_get_x_mirror_vert(ob, i, use_topology) : -1; /* for each skinnable bone */ for (j = 0; j < numbones; ++j) { @@ -224,7 +236,7 @@ static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], i ED_vgroup_vert_remove(ob, dgroup, i); /* do same for mirror */ - if (dgroupflip && dgroupflip[j] && iflip >= 0) { + if (dgroupflip && dgroupflip[j] && iflip != -1) { if (distance != 0.0f) ED_vgroup_vert_add(ob, dgroupflip[j], iflip, distance, WEIGHT_REPLACE); diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index 475ffd23617..ba105325b97 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -53,6 +53,8 @@ #include "WM_api.h" #include "WM_types.h" +#include "GPU_select.h" + typedef int (*GestureDetectFct)(bContext *, SK_Gesture *, SK_Sketch *); typedef void (*GestureApplyFct)(bContext *, SK_Gesture *, SK_Sketch *); @@ -493,7 +495,7 @@ static void sk_drawStroke(SK_Stroke *stk, int id, float color[3], int start, int gluQuadricNormals(quad, GLU_SMOOTH); if (id != -1) { - glLoadName(id); + GPU_select_load_id(id); for (i = 0; i < stk->nb_points; i++) { glPushMatrix(); @@ -1969,7 +1971,7 @@ static int sk_selectStroke(bContext *C, SK_Sketch *sketch, const int mval[2], in rect.ymin = mval[1] - 5; rect.ymax = mval[1] + 5; - hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect); + hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true); if (hits > 0) { int besthitresult = -1; @@ -2032,7 +2034,7 @@ static void sk_drawSketch(Scene *scene, View3D *UNUSED(v3d), SK_Sketch *sketch, sk_drawStroke(stk, id, NULL, -1, -1); } - glLoadName(-1); + GPU_select_load_id(-1); } else { float selected_rgb[3] = {1, 0, 0}; diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index 56e7bde0081..49650fcadbf 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -635,8 +635,8 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; MVert *mvert = me->mvert; - bool use_vert_sel = false; - bool use_face_sel = false; + bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; + bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; *err_str = NULL; @@ -652,9 +652,8 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, return; /* count triangles and create mask */ - if (ob->mode == OB_MODE_WEIGHT_PAINT && - ((use_face_sel = ((me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0)) || - (use_vert_sel = ((me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0)))) + if (ob->mode & OB_MODE_WEIGHT_PAINT && + (use_face_sel || use_vert_sel)) { mask = MEM_callocN(sizeof(int) * me->totvert, "heat_bone_weighting mask"); diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index 890bf6649b9..da68108285f 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -1074,7 +1074,9 @@ static int show_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr)) if (arm->layer & bone->layer) { if (bone->flag & BONE_HIDDEN_P) { bone->flag &= ~BONE_HIDDEN_P; - bone->flag |= BONE_SELECTED; + if (!(bone->flag & BONE_UNSELECTABLE)) { + bone->flag |= BONE_SELECTED; + } } } diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c index 6762ffc17b2..0609fcc29e8 100644 --- a/source/blender/editors/armature/pose_lib.c +++ b/source/blender/editors/armature/pose_lib.c @@ -307,7 +307,7 @@ static int poselib_sanitize_exec(bContext *C, wmOperator *op) /* check if any pose matches this */ /* TODO: don't go looking through the list like this every time... */ for (marker = act->markers.first; marker; marker = marker->next) { - if (IS_EQ(marker->frame, (double)ak->cfra)) { + if (IS_EQ((double)marker->frame, (double)ak->cfra)) { marker->flag = -1; break; } @@ -1417,7 +1417,7 @@ static void poselib_preview_init_data(bContext *C, wmOperator *op) pld->marker = (pld->act) ? BLI_findlink(&pld->act->markers, pose_index) : NULL; /* check if valid poselib */ - if (ELEM3(NULL, pld->ob, pld->pose, pld->arm)) { + if (ELEM(NULL, pld->ob, pld->pose, pld->arm)) { BKE_report(op->reports, RPT_ERROR, "Pose lib is only for armatures in pose mode"); pld->state = PL_PREVIEW_ERROR; return; diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index aa741ef9aaf..76284ba44de 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -69,6 +69,29 @@ /* ***************** Pose Select Utilities ********************* */ +/* Note: SEL_TOGGLE is assumed to have already been handled! */ +static void pose_do_bone_select(bPoseChannel *pchan, const int select_mode) +{ + /* select pchan only if selectable, but deselect works always */ + switch (select_mode) { + case SEL_SELECT: + if (!(pchan->bone->flag & BONE_UNSELECTABLE)) + pchan->bone->flag |= BONE_SELECTED; + break; + case SEL_DESELECT: + pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + break; + case SEL_INVERT: + if (pchan->bone->flag & BONE_SELECTED) { + pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + } + else if (!(pchan->bone->flag & BONE_UNSELECTABLE)) { + pchan->bone->flag |= BONE_SELECTED; + } + break; + } +} + /* Utility method for changing the selection status of a bone */ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select) { @@ -76,7 +99,7 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select) /* sanity checks */ // XXX: actually, we can probably still get away with no object - at most we have no updates - if (ELEM4(NULL, ob, ob->pose, pchan, pchan->bone)) + if (ELEM(NULL, ob, ob->pose, pchan, pchan->bone)) return; arm = ob->data; @@ -139,7 +162,7 @@ int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, shor } if (!extend && !deselect && !toggle) { - ED_pose_deselectall(ob, 0); + ED_pose_de_selectall(ob, SEL_DESELECT, true); nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); arm->act_bone = nearBone; } @@ -191,16 +214,12 @@ int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, shor return nearBone != NULL; } -/* test==0: deselect all - * test==1: swap select (apply to all the opposite of current situation) - * test==2: only clear active tag - * test==3: swap select (no test / inverse selection status of all independently) - */ -void ED_pose_deselectall(Object *ob, int test) +/* 'select_mode' is usual SEL_SELECT/SEL_DESELECT/SEL_TOGGLE/SEL_INVERT. + * When true, 'ignore_visibility' makes this func also affect invisible bones (hidden or on hidden layers). */ +void ED_pose_de_selectall(Object *ob, int select_mode, const bool ignore_visibility) { bArmature *arm = ob->data; bPoseChannel *pchan; - int selectmode = 0; /* we call this from outliner too */ if (ob->pose == NULL) { @@ -208,31 +227,23 @@ void ED_pose_deselectall(Object *ob, int test) } /* Determine if we're selecting or deselecting */ - if (test == 1) { + if (select_mode == SEL_TOGGLE) { + select_mode = SEL_SELECT; for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - if (PBONE_VISIBLE(arm, pchan->bone)) { - if (pchan->bone->flag & BONE_SELECTED) + if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) { + if (pchan->bone->flag & BONE_SELECTED) { + select_mode = SEL_DESELECT; break; + } } } - - if (pchan == NULL) - selectmode = 1; } - else if (test == 2) - selectmode = 2; - /* Set the flags accordingly */ + /* Set the flags accordingly */ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { /* ignore the pchan if it isn't visible or if its selection cannot be changed */ - if ((pchan->bone->layer & arm->layer) && !(pchan->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) { - if (test == 3) { - pchan->bone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } - else { - if (selectmode == 0) pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - else if (selectmode == 1) pchan->bone->flag |= BONE_SELECTED; - } + if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) { + pose_do_bone_select(pchan, select_mode); } } } @@ -353,24 +364,7 @@ static int pose_de_select_all_exec(bContext *C, wmOperator *op) /* Set the flags */ CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) { - /* select pchan only if selectable, but deselect works always */ - switch (action) { - case SEL_SELECT: - if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) - pchan->bone->flag |= BONE_SELECTED; - break; - case SEL_DESELECT: - pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - break; - case SEL_INVERT: - if (pchan->bone->flag & BONE_SELECTED) { - pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } - else if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) { - pchan->bone->flag |= BONE_SELECTED; - } - break; - } + pose_do_bone_select(pchan, action); } CTX_DATA_END; @@ -644,7 +638,7 @@ static bool pose_select_same_group(bContext *C, Object *ob, bool extend) bool changed = false, tagged = false; /* sanity checks */ - if (ELEM3(NULL, ob, pose, arm)) + if (ELEM(NULL, ob, pose, arm)) return 0; /* count the number of groups */ @@ -701,7 +695,7 @@ static bool pose_select_same_layer(bContext *C, Object *ob, bool extend) bool changed = false; int layers = 0; - if (ELEM3(NULL, ob, pose, arm)) + if (ELEM(NULL, ob, pose, arm)) return 0; /* figure out what bones are selected */ @@ -761,7 +755,7 @@ static bool pose_select_same_keyingset(bContext *C, ReportList *reports, Object return false; } - if (ELEM3(NULL, ob, pose, arm)) + if (ELEM(NULL, ob, pose, arm)) return false; /* if not extending selection, deselect all selected first */ diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index 375cbb0fe2b..5f9f24d23a4 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -134,7 +134,7 @@ static int pose_slide_init(bContext *C, wmOperator *op, short mode) pso->nextFrame = RNA_int_get(op->ptr, "next_frame"); /* check the settings from the context */ - if (ELEM4(NULL, pso->ob, pso->arm, pso->ob->adt, pso->ob->adt->action)) + if (ELEM(NULL, pso->ob, pso->arm, pso->ob->adt, pso->ob->adt->action)) return 0; else act = pso->ob->adt->action; diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 11c8b11e31d..b0371b8dd6c 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -7019,7 +7019,7 @@ static int match_texture_space_poll(bContext *C) { Object *object = CTX_data_active_object(C); - return object && ELEM3(object->type, OB_CURVE, OB_SURF, OB_FONT); + return object && ELEM(object->type, OB_CURVE, OB_SURF, OB_FONT); } static int match_texture_space_exec(bContext *C, wmOperator *UNUSED(op)) diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt index 3fc6e2e6f0d..2a84ca7f297 100644 --- a/source/blender/editors/datafiles/CMakeLists.txt +++ b/source/blender/editors/datafiles/CMakeLists.txt @@ -93,6 +93,8 @@ if(WITH_BLENDER) data_to_c_simple(../../../../release/datafiles/brushicons/soften.png SRC) data_to_c_simple(../../../../release/datafiles/brushicons/subtract.png SRC) data_to_c_simple(../../../../release/datafiles/brushicons/texdraw.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/texfill.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/texmask.png SRC) data_to_c_simple(../../../../release/datafiles/brushicons/thumb.png SRC) data_to_c_simple(../../../../release/datafiles/brushicons/twist.png SRC) data_to_c_simple(../../../../release/datafiles/brushicons/vertexdraw.png SRC) diff --git a/source/blender/editors/datafiles/SConscript b/source/blender/editors/datafiles/SConscript index 47819d0e33c..6bc8f21e384 100644 --- a/source/blender/editors/datafiles/SConscript +++ b/source/blender/editors/datafiles/SConscript @@ -77,6 +77,8 @@ sources.extend(( os.path.join(env['DATA_SOURCES'], "soften.png.c"), os.path.join(env['DATA_SOURCES'], "subtract.png.c"), os.path.join(env['DATA_SOURCES'], "texdraw.png.c"), + os.path.join(env['DATA_SOURCES'], "texfill.png.c"), + os.path.join(env['DATA_SOURCES'], "texmask.png.c"), os.path.join(env['DATA_SOURCES'], "thumb.png.c"), os.path.join(env['DATA_SOURCES'], "twist.png.c"), os.path.join(env['DATA_SOURCES'], "vertexdraw.png.c"), diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index b725f5c773a..6e17be04623 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -1412,7 +1412,7 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG rctf subrect, *subrect_ptr = NULL; /* error checking */ - if (ELEM3(NULL, gpd, gpl, gpf)) + if (ELEM(NULL, gpd, gpl, gpf)) return; /* only convert if there are any strokes on this layer's frame to convert */ diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 4910396ac6f..afecdd91599 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -1861,7 +1861,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) /* we don't pass on key events, GP is used with key-modifiers - prevents Dkey to insert drivers */ if (ISKEYBOARD(event->type)) { - if (ELEM4(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY)) { + if (ELEM(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY)) { /* allow some keys - for frame changing: [#33412] */ } else { @@ -1874,7 +1874,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) /* exit painting mode (and/or end current stroke) * NOTE: cannot do RIGHTMOUSE (as is standard for canceling) as that would break polyline [#32647] */ - if (ELEM4(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY)) { + if (ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY)) { /* exit() ends the current stroke before cleaning up */ /* printf("\t\tGP - end of paint op + end of stroke\n"); */ p->status = GP_STATUS_DONE; @@ -1949,7 +1949,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) } /* eraser size */ else if ((p->paintmode == GP_PAINTMODE_ERASER) && - ELEM4(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, PADPLUSKEY, PADMINUS)) + ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, PADPLUSKEY, PADMINUS)) { /* just resize the brush (local version) * TODO: fix the hardcoded size jumps (set to make a visible difference) and hardcoded keys diff --git a/source/blender/editors/include/BIF_gl.h b/source/blender/editors/include/BIF_gl.h index 477a7c0ce17..9fa603966b6 100644 --- a/source/blender/editors/include/BIF_gl.h +++ b/source/blender/editors/include/BIF_gl.h @@ -58,8 +58,24 @@ * */ void cpack(unsigned int x); -#define glMultMatrixf(x) glMultMatrixf( (float *)(x)) -#define glLoadMatrixf(x) glLoadMatrixf( (float *)(x)) + +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) +# define glMultMatrixf(x) \ + glMultMatrixf(_Generic((x), \ + float *: (float *)(x), \ + float (*)[4]: (float *)(x), \ + const float *: (float *)(x), \ + const float (*)[4]: (float *)(x)) \ +) +# define glLoadMatrixf(x) \ + glLoadMatrixf(_Generic((x), \ + float *: (float *)(x), \ + float (*)[4]: (float *)(x)) \ +) +#else +# define glMultMatrixf(x) glMultMatrixf((float *)(x)) +# define glLoadMatrixf(x) glLoadMatrixf((float *)(x)) +#endif #define GLA_PIXEL_OFS 0.375f diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 7579f6cba65..f6a1b493fac 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -174,7 +174,7 @@ void ED_armature_ebone_selectflag_disable(EditBone *ebone, int flag); /* poseobject.c */ void ED_armature_exit_posemode(struct bContext *C, struct Base *base); void ED_armature_enter_posemode(struct bContext *C, struct Base *base); -void ED_pose_deselectall(struct Object *ob, int test); +void ED_pose_de_selectall(struct Object *ob, int select_mode, const bool ignore_visibility); void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select); void ED_pose_recalculate_paths(struct Scene *scene, struct Object *ob); struct Object *ED_pose_object_from_context(struct bContext *C); diff --git a/source/blender/editors/include/ED_datafiles.h b/source/blender/editors/include/ED_datafiles.h index 9022a1481aa..661ab58b98c 100644 --- a/source/blender/editors/include/ED_datafiles.h +++ b/source/blender/editors/include/ED_datafiles.h @@ -150,6 +150,12 @@ extern char datatoc_subtract_png[]; extern int datatoc_texdraw_png_size; extern char datatoc_texdraw_png[]; +extern int datatoc_texfill_png_size; +extern char datatoc_texfill_png[]; + +extern int datatoc_texmask_png_size; +extern char datatoc_texmask_png[]; + extern int datatoc_thumb_png_size; extern char datatoc_thumb_png[]; diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h index b15a83809f5..db13c628ade 100644 --- a/source/blender/editors/include/ED_image.h +++ b/source/blender/editors/include/ED_image.h @@ -69,8 +69,11 @@ void ED_image_point_pos__reverse(struct SpaceImage *sima, struct ARegion *ar, co bool ED_space_image_show_render(struct SpaceImage *sima); bool ED_space_image_show_paint(struct SpaceImage *sima); bool ED_space_image_show_uvedit(struct SpaceImage *sima, struct Object *obedit); +bool ED_space_image_show_texpaint(struct SpaceImage *sima, struct Object *ob); bool ED_space_image_show_uvshadow(struct SpaceImage *sima, struct Object *obedit); +bool ED_space_image_paint_curve(const struct bContext *C); + bool ED_space_image_check_show_maskedit(struct Scene *scene, struct SpaceImage *sima); int ED_space_image_maskedit_poll(struct bContext *C); int ED_space_image_maskedit_mask_poll(struct bContext *C); diff --git a/source/blender/editors/include/ED_paint.h b/source/blender/editors/include/ED_paint.h index d7e84d8f50d..decd79fcc7b 100644 --- a/source/blender/editors/include/ED_paint.h +++ b/source/blender/editors/include/ED_paint.h @@ -28,9 +28,11 @@ struct bContext; struct RegionView3D; struct wmKeyConfig; +struct wmOperator; /* paint_ops.c */ void ED_operatortypes_paint(void); +void ED_operatormacros_paint(void); void ED_keymap_paint(struct wmKeyConfig *keyconf); /* paint_undo.c */ @@ -41,6 +43,7 @@ enum { typedef void (*UndoRestoreCb)(struct bContext *C, struct ListBase *lb); typedef void (*UndoFreeCb)(struct ListBase *lb); +typedef bool (*UndoCleanupCb)(struct bContext *C, struct ListBase *lb); int ED_undo_paint_step(struct bContext *C, int type, int step, const char *name); void ED_undo_paint_step_num(struct bContext *C, int type, int num); @@ -48,7 +51,7 @@ const char *ED_undo_paint_get_name(struct bContext *C, int type, int nr, int *ac void ED_undo_paint_free(void); int ED_undo_paint_valid(int type, const char *name); bool ED_undo_paint_empty(int type); -void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free); +void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup); void ED_undo_paint_push_end(int type); /* paint_image.c */ @@ -57,5 +60,6 @@ void ED_image_undo_restore(struct bContext *C, struct ListBase *lb); void ED_image_undo_free(struct ListBase *lb); void ED_imapaint_clear_partial_redraw(void); void ED_imapaint_dirty_region(struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h); +void ED_imapaint_bucket_fill(struct bContext *C, float color[3], struct wmOperator *op); #endif /* __ED_PAINT_H__ */ diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index 41ff9b88da9..daa6864b5aa 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -98,6 +98,7 @@ enum TfmMode { #define CTX_NDOF (1 << 5) #define CTX_MOVIECLIP (1 << 6) #define CTX_MASK (1 << 7) +#define CTX_PAINT_CURVE (1 << 8) /* Standalone call to get the transformation center corresponding to the current situation * returns 1 if successful, 0 otherwise (usually means there's no selection) diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index 04eb829979f..4b82fa40c6a 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -54,7 +54,7 @@ void ED_uvedit_assign_image(struct Main *bmain, struct Scene *scene, struct Obje bool ED_uvedit_minmax(struct Scene *scene, struct Image *ima, struct Object *obedit, float min[2], float max[2]); bool ED_object_get_active_image(struct Object *ob, int mat_nr, - struct Image **r_ima, struct ImageUser **r_iuser, struct bNode **r_node); + struct Image **r_ima, struct ImageUser **r_iuser, struct bNode **r_node, struct bNodeTree **r_ntree); void ED_object_assign_active_image(struct Main *bmain, struct Object *ob, int mat_nr, struct Image *ima); bool ED_uvedit_test(struct Object *obedit); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 76839747076..dceede7a540 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -56,6 +56,7 @@ struct bContext; struct bPoseChannel; struct bScreen; struct bglMats; +struct rctf; struct rcti; struct wmOperator; struct wmOperatorType; @@ -84,6 +85,7 @@ typedef struct ViewDepths { float *ED_view3d_cursor3d_get(struct Scene *scene, struct View3D *v3d); void ED_view3d_cursor3d_position(struct bContext *C, float fp[3], const int mval[2]); +void ED_view3d_cursor3d_update(struct bContext *C, const int mval[2]); struct Camera *ED_view3d_camera_data_get(struct View3D *v3d, struct RegionView3D *rv3d); @@ -269,7 +271,7 @@ bool ED_view3d_autodist_depth_seg(struct ARegion *ar, const int mval_sta[2], con /* select */ #define MAXPICKBUF 10000 -short view3d_opengl_select(struct ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input); +short view3d_opengl_select(struct ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const struct rcti *input, bool do_nearest); /* view3d_select.c */ float ED_view3d_select_dist_px(void); @@ -364,6 +366,6 @@ void ED_view3d_operator_properties_viewmat_get(struct wmOperator *op, int *winx, #endif /* render */ -void ED_view3d_shade_update(struct Main *bmain, struct View3D *v3d, struct ScrArea *sa); +void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View3D *v3d, struct ScrArea *sa); #endif /* __ED_VIEW3D_H__ */ diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index 904c14f0573..f1b544f269b 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -978,6 +978,8 @@ DEF_ICON(BRUSH_SNAKE_HOOK) DEF_ICON(BRUSH_SOFTEN) DEF_ICON(BRUSH_SUBTRACT) DEF_ICON(BRUSH_TEXDRAW) +DEF_ICON(BRUSH_TEXFILL) +DEF_ICON(BRUSH_TEXMASK) DEF_ICON(BRUSH_THUMB) DEF_ICON(BRUSH_ROTATE) DEF_ICON(BRUSH_VERTEXDRAW) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 1565583b574..d7b4f753810 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -75,6 +75,9 @@ struct ImBuf; struct bNodeTree; struct bNode; struct bNodeSocket; +struct wmDropBox; +struct wmDrag; +struct wmEvent; typedef struct uiBut uiBut; typedef struct uiBlock uiBlock; @@ -175,6 +178,7 @@ enum { UI_BUT_DRAG_MULTI = (1 << 25), /* edit this button as well as the active button (not just dragging) */ UI_BUT_SCA_LINK_GREY = (1 << 26), /* used to flag if sca links shoud be grey out */ UI_BUT_HAS_SEP_CHAR = (1 << 27), /* but->str contains UI_SEP_CHAR, used for key shortcuts */ + UI_OPTION_TOOLTIPS = (1 << 28), /* force show tooltips when holding option/alt if U's USER_TOOLTIPS is off */ }; #define UI_PANEL_WIDTH 340 @@ -288,6 +292,9 @@ typedef enum { #define UI_GRAD_V_ALT 9 #define UI_GRAD_L_ALT 10 +#define UI_PALETTE_COLOR 20 +#define UI_PALETTE_COLOR_ACTIVE 1 + /* Drawing * * Functions to draw various shapes, taking theme settings into account. @@ -437,6 +444,7 @@ void uiButSetDragValue(uiBut *but); void uiButSetDragImage(uiBut *but, const char *path, int icon, struct ImBuf *ima, float scale); bool UI_but_active_drop_name(struct bContext *C); +bool UI_but_active_drop_color(struct bContext *C); void uiButSetFlag(uiBut *but, int flag); void uiButClearFlag(uiBut *but, int flag); @@ -708,7 +716,6 @@ void UI_remove_popup_handlers_all(struct bContext *C, struct ListBase *handlers) void UI_init(void); void UI_init_userdef(void); -void UI_init_userdef_factory(void); void UI_reinit_font(void); void UI_exit(void); @@ -847,6 +854,7 @@ void uiTemplateVectorscope(uiLayout *layout, struct PointerRNA *ptr, const char void uiTemplateCurveMapping(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int type, int levels, int brush, int neg_slope); void uiTemplateColorPicker(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int value_slider, int lock, int lock_luminosity, int cubic); +void uiTemplatePalette(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int color); void uiTemplateLayers(uiLayout *layout, struct PointerRNA *ptr, const char *propname, PointerRNA *used_ptr, const char *used_propname, int active_layer); void uiTemplateGameStates(uiLayout *layout, struct PointerRNA *ptr, const char *propname, @@ -916,7 +924,14 @@ void uiItemMenuEnumO(uiLayout *layout, struct bContext *C, const char *opname, c void uiItemMenuEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name, int icon); /* UI Operators */ +typedef struct uiDragColorHandle { + float color[3]; + bool gamma_corrected; +} uiDragColorHandle; + void UI_buttons_operatortypes(void); +void UI_drop_color_copy(struct wmDrag *drag, struct wmDropBox *drop); +int UI_drop_color_poll(struct bContext *C, struct wmDrag *drag, const struct wmEvent *event); /* Helpers for Operators */ uiBut *uiContextActiveButton(const struct bContext *C); diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index 2e78940a813..da365355e95 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -237,6 +237,9 @@ enum { TH_STITCH_PREVIEW_UNSTITCHABLE, TH_STITCH_PREVIEW_ACTIVE, + TH_PAINT_CURVE_HANDLE, + TH_PAINT_CURVE_PIVOT, + TH_UV_SHADOW, TH_UV_OTHERS, diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index c857150782e..0a45ffc4c13 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -830,7 +830,7 @@ static void ui_menu_block_set_keyaccels(uiBlock *block) * fun first pass on all buttons so first word chars always get first priority */ for (but = block->buttons.first; but; but = but->next) { - if (!ELEM5(but->type, BUT, BUTM, MENU, BLOCK, PULLDOWN) || (but->flag & UI_HIDDEN)) { + if (!ELEM(but->type, BUT, BUTM, MENU, BLOCK, PULLDOWN) || (but->flag & UI_HIDDEN)) { /* pass */ } else if (but->menu_key == '\0') { @@ -1320,7 +1320,7 @@ int ui_is_but_push_ex(uiBut *but, double *value) int is_push = 0; if (but->bit) { - const bool state = ELEM3(but->type, TOGN, ICONTOGN, OPTIONN) ? false : true; + const bool state = ELEM(but->type, TOGN, ICONTOGN, OPTIONN) ? false : true; int lvalue; UI_GET_BUT_VALUE_INIT(but, *value); lvalue = (int)*value; @@ -1630,7 +1630,7 @@ bool ui_is_but_float(const uiBut *but) bool ui_is_but_bool(const uiBut *but) { - if (ELEM4(but->type, TOG, TOGN, ICONTOG, ICONTOGN)) + if (ELEM(but->type, TOG, TOGN, ICONTOG, ICONTOGN)) return true; if (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_BOOLEAN) @@ -1843,7 +1843,7 @@ void ui_set_but_val(uiBut *but, double value) int ui_get_but_string_max_length(uiBut *but) { - if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) + if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) return but->hardmax; else return UI_MAX_DRAW_STR; @@ -1958,7 +1958,7 @@ static float ui_get_but_step_unit(uiBut *but, float step_default) */ void ui_get_but_string_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision) { - if (but->rnaprop && ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { + if (but->rnaprop && ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { PropertyType type; const char *buf = NULL; int buf_len; @@ -2095,7 +2095,7 @@ bool ui_set_but_string_eval_num(bContext *C, uiBut *but, const char *str, double bool ui_set_but_string(bContext *C, uiBut *but, const char *str) { - if (but->rnaprop && ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { + if (but->rnaprop && ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { if (RNA_property_editable(&but->rnapoin, but->rnaprop)) { PropertyType type; @@ -2747,7 +2747,7 @@ void uiBlockEndAlign(uiBlock *block) bool ui_but_can_align(uiBut *but) { - return !ELEM5(but->type, LABEL, OPTION, OPTIONN, SEPR, SEPRLINE); + return !ELEM(but->type, LABEL, OPTION, OPTIONN, SEPR, SEPRLINE); } static void ui_block_do_align_but(uiBut *first, short nr) @@ -3029,7 +3029,7 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str, } if ((block->flag & UI_BLOCK_LOOP) || - ELEM8(but->type, MENU, TEX, LABEL, BLOCK, BUTM, SEARCH_MENU, PROGRESSBAR, SEARCH_MENU_UNLINK)) + ELEM(but->type, MENU, TEX, LABEL, BLOCK, BUTM, SEARCH_MENU, PROGRESSBAR, SEARCH_MENU_UNLINK)) { but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT); } @@ -3048,7 +3048,7 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str, } /* keep track of UI_interface.h */ - if (ELEM11(but->type, BLOCK, BUT, LABEL, PULLDOWN, ROUNDBOX, LISTBOX, BUTM, SCROLL, SEPR, SEPRLINE, GRIP)) {} + if (ELEM(but->type, BLOCK, BUT, LABEL, PULLDOWN, ROUNDBOX, LISTBOX, BUTM, SCROLL, SEPR, SEPRLINE, GRIP)) {} else if (but->type >= SEARCH_MENU) {} else but->flag |= UI_BUT_UNDO; @@ -3213,12 +3213,12 @@ static uiBut *ui_def_but_rna(uiBlock *block, int type, int retval, const char *s int icon = 0; uiMenuCreateFunc func = NULL; - if (ELEM3(type, COLOR, HSVCIRCLE, HSVCUBE)) { + if (ELEM(type, COLOR, HSVCIRCLE, HSVCUBE)) { BLI_assert(index == -1); } /* use rna values if parameters are not specified */ - if ((proptype == PROP_ENUM) && ELEM3(type, MENU, ROW, LISTROW)) { + if ((proptype == PROP_ENUM) && ELEM(type, MENU, ROW, LISTROW)) { /* MENU is handled a little differently here */ EnumPropertyItem *item; int value; @@ -3811,9 +3811,6 @@ void uiBlockFlipOrder(uiBlock *block) but->rect.ymax = centy - (but->rect.ymax - centy); SWAP(float, but->rect.ymin, but->rect.ymax); } - - /* also flip order in block itself, for example for arrowkey */ - BLI_listbase_reverse(&block->buttons); } @@ -4339,7 +4336,7 @@ void uiButGetStrInfo(bContext *C, uiBut *but, ...) } tmp = BLI_strdup(_tmp); } - else if (ELEM3(type, BUT_GET_RNAENUM_IDENTIFIER, BUT_GET_RNAENUM_LABEL, BUT_GET_RNAENUM_TIP)) { + else if (ELEM(type, BUT_GET_RNAENUM_IDENTIFIER, BUT_GET_RNAENUM_LABEL, BUT_GET_RNAENUM_TIP)) { PointerRNA *ptr = NULL; PropertyRNA *prop = NULL; int value = 0; @@ -4429,11 +4426,6 @@ void UI_init_userdef(void) uiStyleInit(); } -void UI_init_userdef_factory(void) -{ - init_userdef_factory(); -} - void UI_reinit_font(void) { uiStyleInit(); diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index f821aab8c4d..15b8494cb34 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -695,11 +695,11 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), } /* RGB / YCC (3 channels) */ - else if (ELEM4(scopes->wavefrm_mode, - SCOPES_WAVEFRM_RGB, - SCOPES_WAVEFRM_YCC_601, - SCOPES_WAVEFRM_YCC_709, - SCOPES_WAVEFRM_YCC_JPEG)) + else if (ELEM(scopes->wavefrm_mode, + SCOPES_WAVEFRM_RGB, + SCOPES_WAVEFRM_YCC_601, + SCOPES_WAVEFRM_YCC_709, + SCOPES_WAVEFRM_YCC_JPEG)) { int rgb = (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB); diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index d37660a0611..68148d30136 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -38,6 +38,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_brush_types.h" #include "DNA_sensor_types.h" #include "DNA_controller_types.h" #include "DNA_actuator_types.h" @@ -60,6 +61,7 @@ #include "PIL_time.h" #include "BKE_blender.h" +#include "BKE_brush.h" #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_idprop.h" @@ -383,16 +385,16 @@ void ui_pan_to_scroll(const wmEvent *event, int *type, int *val) } } -static bool ui_but_editable(uiBut *but) +bool ui_but_is_editable(const uiBut *but) { - return ELEM6(but->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX, PROGRESSBAR); + return !ELEM(but->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX, PROGRESSBAR); } static uiBut *ui_but_prev(uiBut *but) { while (but->prev) { but = but->prev; - if (!ui_but_editable(but)) return but; + if (ui_but_is_editable(but)) return but; } return NULL; } @@ -401,7 +403,7 @@ static uiBut *ui_but_next(uiBut *but) { while (but->next) { but = but->next; - if (!ui_but_editable(but)) return but; + if (ui_but_is_editable(but)) return but; } return NULL; } @@ -412,7 +414,7 @@ static uiBut *ui_but_first(uiBlock *block) but = block->buttons.first; while (but) { - if (!ui_but_editable(but)) return but; + if (ui_but_is_editable(but)) return but; but = but->next; } return NULL; @@ -424,7 +426,7 @@ static uiBut *ui_but_last(uiBlock *block) but = block->buttons.last; while (but) { - if (!ui_but_editable(but)) return but; + if (ui_but_is_editable(but)) return but; but = but->prev; } return NULL; @@ -433,7 +435,7 @@ static uiBut *ui_but_last(uiBlock *block) static bool ui_is_a_warp_but(uiBut *but) { if (U.uiflag & USER_CONTINUOUS_MOUSE) { - if (ELEM6(but->type, NUM, NUMSLI, HSVCIRCLE, TRACKPREVIEW, HSVCUBE, BUT_CURVE)) { + if (ELEM(but->type, NUM, NUMSLI, HSVCIRCLE, TRACKPREVIEW, HSVCUBE, BUT_CURVE)) { return true; } } @@ -463,7 +465,7 @@ bool ui_is_but_utf8(const uiBut *but) { if (but->rnaprop) { const int subtype = RNA_property_subtype(but->rnaprop); - return !(ELEM4(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME, PROP_BYTESTRING)); + return !(ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME, PROP_BYTESTRING)); } else { return !(but->flag & UI_BUT_NO_UTF8); @@ -717,7 +719,7 @@ static void ui_apply_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data) if (value == 0.0) push = 1; else push = 0; - if (ELEM3(but->type, TOGN, ICONTOGN, OPTIONN)) push = !push; + if (ELEM(but->type, TOGN, ICONTOGN, OPTIONN)) push = !push; ui_set_but_val(but, (double)push); if (but->type == ICONTOG || but->type == ICONTOGN) ui_check_but(but); } @@ -1189,7 +1191,7 @@ static bool ui_but_mouse_inside_icon(uiBut *but, ARegion *ar, const wmEvent *eve BLI_rcti_rctf_copy(&rect, &but->rect); - if (but->imb) { + if (but->imb || but->type == COLOR) { /* use button size itself */ } else if (but->drawflag & UI_BUT_ICON_LEFT) { @@ -1242,10 +1244,42 @@ static bool ui_but_start_drag(bContext *C, uiBut *but, uiHandleButtonData *data, } else #endif - { + if (but->type == COLOR) { + bool valid = false; + uiDragColorHandle *drag_info = MEM_callocN(sizeof(*drag_info), __func__); + + /* TODO support more button pointer types */ + if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) { + RNA_property_float_get_array(&but->rnapoin, but->rnaprop, drag_info->color); + drag_info->gamma_corrected = true; + valid = true; + } + else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) { + RNA_property_float_get_array(&but->rnapoin, but->rnaprop, drag_info->color); + drag_info->gamma_corrected = false; + valid = true; + } + else if (but->pointype == UI_BUT_POIN_FLOAT) { + copy_v3_v3(drag_info->color, (float *)but->poin); + valid = true; + } + else if (but->pointype == UI_BUT_POIN_CHAR) { + rgb_uchar_to_float(drag_info->color, (unsigned char *)but->poin); + valid = true; + } + + if (valid) { + WM_event_start_drag(C, ICON_COLOR, WM_DRAG_COLOR, drag_info, 0.0, WM_DRAG_FREE_DATA); + } + else { + MEM_freeN(drag_info); + return false; + } + } + else { wmDrag *drag; - drag = WM_event_start_drag(C, but->icon, but->dragtype, but->dragpoin, ui_get_but_val(but)); + drag = WM_event_start_drag(C, but->icon, but->dragtype, but->dragpoin, ui_get_but_val(but), WM_DRAG_NOP); if (but->imb) WM_event_drag_image(drag, but->imb, but->imb_scale, BLI_rctf_size_x(&but->rect), BLI_rctf_size_y(&but->rect)); } @@ -1655,7 +1689,7 @@ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleB for (wmd = drags->first; wmd; wmd = wmd->next) { if (wmd->type == WM_DRAG_ID) { /* align these types with UI_but_active_drop_name */ - if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { + if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { ID *id = (ID *)wmd->poin; button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); @@ -1802,7 +1836,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, } /* text/string and ID data */ - else if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { + else if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { uiHandleButtonData *active_data = but->active; if (but->poin == NULL && but->rnapoin.data == NULL) { @@ -2009,7 +2043,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con BLI_strncpy(origstr, but->editstr, data->maxlen); - if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { + if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { if (but->flag & UI_HAS_ICON) { startx += UI_DPI_ICON_SIZE / aspect; } @@ -2461,11 +2495,11 @@ static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa uiBut *but; /* label and roundbox can overlap real buttons (backdrops...) */ - if (ELEM5(actbut->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX)) + if (ELEM(actbut->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX)) return; for (but = actbut->next; but; but = but->next) { - if (ELEM5(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) { + if (ELEM(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) { if (!(but->flag & UI_BUT_DISABLED)) { data->postbut = but; data->posttype = BUTTON_ACTIVATE_TEXT_EDITING; @@ -2474,7 +2508,7 @@ static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa } } for (but = block->buttons.first; but != actbut; but = but->next) { - if (ELEM5(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) { + if (ELEM(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) { if (!(but->flag & UI_BUT_DISABLED)) { data->postbut = but; data->posttype = BUTTON_ACTIVATE_TEXT_EDITING; @@ -2489,11 +2523,11 @@ static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa uiBut *but; /* label and roundbox can overlap real buttons (backdrops...) */ - if (ELEM5(actbut->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX)) + if (ELEM(actbut->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX)) return; for (but = actbut->prev; but; but = but->prev) { - if (ELEM5(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) { + if (ELEM(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) { if (!(but->flag & UI_BUT_DISABLED)) { data->postbut = but; data->posttype = BUTTON_ACTIVATE_TEXT_EDITING; @@ -2502,7 +2536,7 @@ static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa } } for (but = block->buttons.last; but != actbut; but = but->prev) { - if (ELEM5(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) { + if (ELEM(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) { if (!(but->flag & UI_BUT_DISABLED)) { data->postbut = but; data->posttype = BUTTON_ACTIVATE_TEXT_EDITING; @@ -2803,7 +2837,7 @@ static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data) data->coba = (ColorBand *)but->poin; but->editcoba = data->coba; } - else if (ELEM4(but->type, BUT_NORMAL, HSVCUBE, HSVCIRCLE, COLOR)) { + else if (ELEM(but->type, BUT_NORMAL, HSVCUBE, HSVCIRCLE, COLOR)) { ui_get_but_vectorf(but, data->origvec); copy_v3_v3(data->vec, data->origvec); but->editvec = data->vec; @@ -2990,7 +3024,7 @@ static int ui_do_but_BUT(bContext *C, uiBut *but, uiHandleButtonData *data, cons static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { - if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { + if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { but->drawstr[0] = 0; but->modifier_key = 0; button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT); @@ -3053,7 +3087,7 @@ static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { - if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { + if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT); return WM_UI_HANDLER_BREAK; } @@ -3078,7 +3112,7 @@ static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, c static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { - if (ELEM4(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS) { + if (ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS) { if (ELEM(event->type, PADENTER, RETKEY) && (!ui_is_but_utf8(but))) { /* pass - allow filesel, enter to execute */ } @@ -3106,7 +3140,7 @@ static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButton static int ui_do_but_SEARCH_UNLINK(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) { /* unlink icon is on right */ - if (ELEM4(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS && + if (ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS && ui_is_but_search_unlink_visible(but)) { ARegion *ar = data->region; @@ -3156,7 +3190,7 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons } #endif if (data->state == BUTTON_STATE_HIGHLIGHT) { - if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { + if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { #if 0 /* UNUSED */ data->togdual = event->ctrl; data->togonly = !event->shift; @@ -3194,7 +3228,7 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con } #endif - if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { + if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { int ret = WM_UI_HANDLER_BREAK; /* XXX (a bit ugly) Special case handling for filebrowser drag button */ if (but->dragpoin && but->imb && ui_but_mouse_inside_icon(but, data->region, event)) { @@ -3243,7 +3277,7 @@ static float ui_numedit_apply_snapf(uiBut *but, float tempf, float softmin, floa if (bUnit_IsValid(unit->system, unit_type)) { fac = (float)bUnit_BaseScalar(unit->system, unit_type); - if (ELEM3(unit_type, B_UNIT_LENGTH, B_UNIT_AREA, B_UNIT_VOLUME)) { + if (ELEM(unit_type, B_UNIT_LENGTH, B_UNIT_AREA, B_UNIT_VOLUME)) { fac /= unit->scale_length; } } @@ -3478,7 +3512,7 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton click = 1; } else if (event->val == KM_PRESS) { - if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->ctrl) { + if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->ctrl) { button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); retval = WM_UI_HANDLER_BREAK; } @@ -3767,7 +3801,7 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton click = 2; } else if (event->val == KM_PRESS) { - if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->ctrl) { + if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->ctrl) { button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); retval = WM_UI_HANDLER_BREAK; } @@ -4024,7 +4058,7 @@ static int ui_do_but_LISTROW(bContext *C, uiBut *but, uiHandleButtonData *data, /* hack to pass on ctrl+click and double click to overlapping text * editing field for editing list item names */ - if ((ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS && event->ctrl) || + if ((ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS && event->ctrl) || (event->type == LEFTMOUSE && event->val == KM_DBL_CLICK)) { uiBut *labelbut = ui_but_list_row_text_activate(C, but, data, event, BUTTON_ACTIVATE_TEXT_EDITING); @@ -4053,7 +4087,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co } } #ifdef USE_DRAG_TOGGLE - if (event->type == LEFTMOUSE && ui_is_but_drag_toggle(but)) { + if (event->type == LEFTMOUSE && event->val == KM_PRESS && (ui_is_but_drag_toggle(but))) { button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG); data->dragstartx = event->x; data->dragstarty = event->y; @@ -4061,7 +4095,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co } #endif /* regular open menu */ - if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { + if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { button_activate_state(C, but, BUTTON_STATE_MENU_OPEN); return WM_UI_HANDLER_BREAK; } @@ -4206,11 +4240,29 @@ static bool ui_numedit_but_NORMAL(uiBut *but, uiHandleButtonData *data, static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { - if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { + /* first handle click on icondrag type button */ + if (event->type == LEFTMOUSE && but->dragpoin && event->val == KM_PRESS) { + if (ui_but_mouse_inside_icon(but, data->region, event)) { + button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG); + data->dragstartx = event->x; + data->dragstarty = event->y; + return WM_UI_HANDLER_BREAK; + } + } +#ifdef USE_DRAG_TOGGLE + if (event->type == LEFTMOUSE && event->val == KM_PRESS) { + button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG); + data->dragstartx = event->x; + data->dragstarty = event->y; + return WM_UI_HANDLER_BREAK; + } +#endif + /* regular open menu */ + if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { button_activate_state(C, but, BUTTON_STATE_MENU_OPEN); return WM_UI_HANDLER_BREAK; } - else if (ELEM3(event->type, MOUSEPAN, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) { + else if (ELEM(event->type, MOUSEPAN, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) { float *hsv = ui_block_hsv_get(but->block); float col[3]; @@ -4233,6 +4285,81 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co ui_apply_button(C, but->block, but, data, true); return WM_UI_HANDLER_BREAK; } + else if ((int)(but->a1) == UI_PALETTE_COLOR && + event->type == DELKEY && event->val == KM_PRESS) + { + Scene *scene = CTX_data_scene(C); + Paint *paint = BKE_paint_get_active(scene); + Palette *palette = BKE_paint_palette(paint); + PaletteColor *color = but->rnapoin.data; + + BKE_palette_color_remove(palette, color); + + button_activate_state(C, but, BUTTON_STATE_EXIT); + return WM_UI_HANDLER_BREAK; + } + } + else if (data->state == BUTTON_STATE_WAIT_DRAG) { + + /* this function also ends state */ + if (ui_but_start_drag(C, but, data, event)) { + return WM_UI_HANDLER_BREAK; + } + + /* outside icon quit, not needed if drag activated */ + if (0 == ui_but_mouse_inside_icon(but, data->region, event)) { + button_activate_state(C, but, BUTTON_STATE_EXIT); + data->cancel = true; + return WM_UI_HANDLER_BREAK; + } + + if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { + if ((int)(but->a1) == UI_PALETTE_COLOR) { + Palette *palette = but->rnapoin.id.data; + PaletteColor *color = but->rnapoin.data; + palette->active_color = BLI_findindex(&palette->colors, color); + + if (!event->ctrl) { + float color[3]; + Scene *scene = CTX_data_scene(C); + Paint *paint = BKE_paint_get_active(scene); + Brush *brush = BKE_paint_brush(paint); + + if (brush->flag & BRUSH_USE_GRADIENT) { + float *target = &brush->gradient->data[brush->gradient->cur].r; + + if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) { + RNA_property_float_get_array(&but->rnapoin, but->rnaprop, target); + ui_block_to_scene_linear_v3(but->block, target); + } + else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) { + RNA_property_float_get_array(&but->rnapoin, but->rnaprop, target); + } + } + else { + if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) { + RNA_property_float_get_array(&but->rnapoin, but->rnaprop, color); + BKE_brush_color_set(scene, brush, color); + } + else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) { + RNA_property_float_get_array(&but->rnapoin, but->rnaprop, color); + ui_block_to_display_space_v3(but->block, color); + BKE_brush_color_set(scene, brush, color); + } + } + + button_activate_state(C, but, BUTTON_STATE_EXIT); + } + else { + button_activate_state(C, but, BUTTON_STATE_MENU_OPEN); + } + } + else { + button_activate_state(C, but, BUTTON_STATE_MENU_OPEN); + } + return WM_UI_HANDLER_BREAK; + } + } return WM_UI_HANDLER_CONTINUE; @@ -4412,7 +4539,7 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data, } if (snap != SNAP_OFF) { - if (ELEM3((int)but->a1, UI_GRAD_HV, UI_GRAD_HS, UI_GRAD_H)) { + if (ELEM((int)but->a1, UI_GRAD_HV, UI_GRAD_HS, UI_GRAD_H)) { ui_color_snap_hue(snap, &hsv[0]); } } @@ -4489,7 +4616,7 @@ static void ui_ndofedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data, } if (snap != SNAP_OFF) { - if (ELEM3((int)but->a1, UI_GRAD_HV, UI_GRAD_HS, UI_GRAD_H)) { + if (ELEM((int)but->a1, UI_GRAD_HV, UI_GRAD_HS, UI_GRAD_H)) { ui_color_snap_hue(snap, &hsv[0]); } } @@ -6012,7 +6139,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * } /* handle drivers */ else if ((event->type == DKEY) && - !ELEM3(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) && + !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) && (event->val == KM_PRESS)) { if (event->alt) @@ -6026,7 +6153,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * } /* handle keyingsets */ else if ((event->type == KKEY) && - !ELEM3(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) && + !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) && (event->val == KM_PRESS)) { if (event->alt) @@ -6250,7 +6377,7 @@ static bool ui_but_contains_pt(uiBut *but, float mx, float my) return BLI_rctf_isect_pt(&but->rect, mx, my); } -static uiBut *ui_but_find_activated(ARegion *ar) +uiBut *ui_but_find_activated(ARegion *ar) { uiBlock *block; uiBut *but; @@ -6298,13 +6425,27 @@ bool UI_but_active_drop_name(bContext *C) uiBut *but = ui_but_find_activated(ar); if (but) { - if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) + if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) return 1; } return 0; } +bool UI_but_active_drop_color(bContext *C) +{ + ARegion *ar = CTX_wm_region(C); + + if (ar) { + uiBut *but = ui_but_find_activated(ar); + + if (but && but->type == COLOR) + return true; + } + + return false; +} + static void ui_blocks_set_tooltips(ARegion *ar, const bool enable) { uiBlock *block; @@ -6378,7 +6519,7 @@ static bool ui_is_but_interactive(const uiBut *but, const bool labeledit) /* note, LABEL is included for highlights, this allows drags */ if ((but->type == LABEL) && but->dragpoin == NULL) return false; - if (ELEM4(but->type, ROUNDBOX, SEPR, SEPRLINE, LISTBOX)) + if (ELEM(but->type, ROUNDBOX, SEPR, SEPRLINE, LISTBOX)) return false; if (but->flag & UI_HIDDEN) return false; @@ -6471,9 +6612,13 @@ static uiBut *ui_list_find_mouse_over(ARegion *ar, int x, int y) static bool button_modal_state(uiHandleButtonState state) { - return ELEM6(state, BUTTON_STATE_WAIT_RELEASE, BUTTON_STATE_WAIT_KEY_EVENT, - BUTTON_STATE_NUM_EDITING, BUTTON_STATE_TEXT_EDITING, - BUTTON_STATE_TEXT_SELECTING, BUTTON_STATE_MENU_OPEN); + return ELEM(state, + BUTTON_STATE_WAIT_RELEASE, + BUTTON_STATE_WAIT_KEY_EVENT, + BUTTON_STATE_NUM_EDITING, + BUTTON_STATE_TEXT_EDITING, + BUTTON_STATE_TEXT_SELECTING, + BUTTON_STATE_MENU_OPEN); } static void button_timers_tooltip_remove(bContext *C, uiBut *but) @@ -6511,7 +6656,7 @@ static void button_tooltip_timer_reset(bContext *C, uiBut *but) data->tooltiptimer = NULL; } - if (U.flag & USER_TOOLTIPS) + if ((U.flag & USER_TOOLTIPS) || (but->flag & UI_OPTION_TOOLTIPS)) if (!but->block->tooltipdisabled) if (!wm->drags.first) data->tooltiptimer = WM_event_add_timer(data->wm, data->window, TIMER, BUTTON_TOOLTIP_DELAY); @@ -6664,7 +6809,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA copy_v2_fl(data->ungrab_mval, FLT_MAX); #endif - if (ELEM3(but->type, BUT_CURVE, SEARCH_MENU, SEARCH_MENU_UNLINK)) { + if (ELEM(but->type, BUT_CURVE, SEARCH_MENU, SEARCH_MENU_UNLINK)) { /* XXX curve is temp */ } else { @@ -7023,6 +7168,11 @@ static int ui_handle_button_over(bContext *C, const wmEvent *event, ARegion *ar) if (event->type == MOUSEMOVE) { but = ui_but_find_mouse_over(ar, event); if (but) { + if (event->alt) + /* display tooltips if holding alt on mouseover when tooltips are off in prefs */ + but->flag |= UI_OPTION_TOOLTIPS; + else + but->flag &= ~UI_OPTION_TOOLTIPS; button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER); } } @@ -7054,6 +7204,17 @@ void ui_button_activate_do(bContext *C, ARegion *ar, uiBut *but) ui_do_button(C, but->block, but, &event); } +/** + * Simulate moving the mouse over a button (or navigating to it with arrow keys). + * + * exported so menus can start with a highlighted button, + * even if the mouse isnt over it + */ +void ui_button_activate_over(bContext *C, ARegion *ar, uiBut *but) +{ + button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER); +} + void ui_button_execute_begin(struct bContext *UNUSED(C), struct ARegion *ar, uiBut *but, void **active_back) { /* note: ideally we would not have to change 'but->active' however @@ -7116,12 +7277,20 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but) retval = WM_UI_HANDLER_CONTINUE; break; case MOUSEMOVE: - /* verify if we are still over the button, if not exit */ - if (!ui_mouse_inside_button(ar, but, event->x, event->y)) { - data->cancel = true; - button_activate_state(C, but, BUTTON_STATE_EXIT); + { + uiBut *but_other = ui_but_find_mouse_over(ar, event); + bool exit = false; + + if (!ui_block_is_menu(block) && + !ui_mouse_inside_button(ar, but, event->x, event->y)) + { + exit = true; + } + else if (but_other && ui_but_is_editable(but_other) && (but_other != but)) { + exit = true; } - else if (ui_but_find_mouse_over(ar, event) != but) { + + if (exit) { data->cancel = true; button_activate_state(C, but, BUTTON_STATE_EXIT); } @@ -7132,6 +7301,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but) } break; + } case TIMER: { /* handle tooltip timer */ @@ -7715,6 +7885,22 @@ static int ui_handle_menu_button(bContext *C, const wmEvent *event, uiPopupBlock int retval; if (but) { + /* Its possible there is an active menu item NOT under the mouse, + * in this case ignore mouse clicks outside the button (but Enter etc is accepted) */ + if (event->val == KM_RELEASE) { + /* pass, needed so we can exit active menu-items when click-dragging out of them */ + } + else if (!ui_mouse_inside_region(but->active->region, event->x, event->y)) { + /* pass, needed to click-exit outside of non-flaoting menus */ + } + else if ((event->type != MOUSEMOVE) && ISMOUSE(event->type)) { + if (!ui_mouse_inside_button(but->active->region, but, event->x, event->y)) { + but = NULL; + } + } + } + + if (but) { ScrArea *ctx_area = CTX_wm_area(C); ARegion *ctx_region = CTX_wm_region(C); @@ -7764,6 +7950,7 @@ static int ui_handle_menu_event( if (menu->is_grab) { if (event->type == LEFTMOUSE) { menu->is_grab = false; + retval = WM_UI_HANDLER_BREAK; } else { if (event->type == MOUSEMOVE) { @@ -7968,7 +8155,7 @@ static int ui_handle_menu_event( for (but = block->buttons.first; but; but = but->next) { bool doit = false; - if (!ELEM3(but->type, LABEL, SEPR, SEPRLINE)) + if (!ELEM(but->type, LABEL, SEPR, SEPRLINE)) count++; /* exception for rna layer buts */ @@ -8079,7 +8266,7 @@ static int ui_handle_menu_event( if (inside == 0) { uiSafetyRct *saferct = block->saferct.first; - if (ELEM3(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE) && + if (ELEM(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE) && ELEM(event->val, KM_PRESS, KM_DBL_CLICK)) { if ((is_parent_menu == false) && (U.uiflag & USER_MENUOPENAUTO) == 0) { @@ -8121,9 +8308,14 @@ static int ui_handle_menu_event( else if ((event->type == LEFTMOUSE) && (event->val == KM_PRESS) && (inside && is_floating && inside_title)) { - if (!ui_but_find_activated(ar)) { + if (!but || !ui_mouse_inside_button(ar, but, event->x, event->y)) { + if (but) { + button_timers_tooltip_remove(C, but); + } + menu->is_grab = true; copy_v2_v2_int(menu->grab_xy_prev, &event->x); + retval = WM_UI_HANDLER_BREAK; } } #endif @@ -8458,15 +8650,15 @@ static int ui_handler_popup(bContext *C, const wmEvent *event, void *userdata) /* free if done, does not free handle itself */ if (menu->menuretval) { + wmWindow *win = CTX_wm_window(C); /* copy values, we have to free first (closes region) */ uiPopupBlockHandle temp = *menu; ui_popup_block_free(C, menu); - UI_remove_popup_handlers(&CTX_wm_window(C)->modalhandlers, menu); + UI_remove_popup_handlers(&win->modalhandlers, menu); #ifdef USE_DRAG_TOGGLE { - wmWindow *win = CTX_wm_window(C); WM_event_free_ui_handler_all(C, &win->modalhandlers, ui_handler_region_drag_toggle, ui_handler_region_drag_toggle_remove); } diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 546b2b85af5..51dd9166e46 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -508,6 +508,8 @@ static void init_brush_icons(void) INIT_BRUSH_ICON(ICON_BRUSH_SOFTEN, soften); INIT_BRUSH_ICON(ICON_BRUSH_SUBTRACT, subtract); INIT_BRUSH_ICON(ICON_BRUSH_TEXDRAW, texdraw); + INIT_BRUSH_ICON(ICON_BRUSH_TEXFILL, texfill); + INIT_BRUSH_ICON(ICON_BRUSH_TEXMASK, texmask); INIT_BRUSH_ICON(ICON_BRUSH_THUMB, thumb); INIT_BRUSH_ICON(ICON_BRUSH_ROTATE, twist); INIT_BRUSH_ICON(ICON_BRUSH_VERTEXDRAW, vertexdraw); diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index cd3b6390184..7d03aaea6b3 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -186,6 +186,7 @@ struct uiBut { * (type == LABEL), Use (a1 == 1.0f) to use a2 as a blending factor (wow, this is imaginative!). * (type == SCROLL) Use as scroll size. * (type == SEARCH_MENU) Use as number or rows. + * (type == COLOR) Use as indication of color palette */ float a1; @@ -193,6 +194,7 @@ struct uiBut { * (type == NUM), Use to store RNA 'precision' value, for dragging and click-step. * (type == LABEL), If (a1 == 1.0f) use a2 as a blending factor. * (type == SEARCH_MENU) Use as number or columns. + * (type == COLOR) Use as indication of active palette color */ float a2; @@ -550,12 +552,16 @@ void ui_draw_but_NODESOCKET(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol PointerRNA *ui_handle_afterfunc_add_operator(struct wmOperatorType *ot, int opcontext, bool create_props); extern void ui_pan_to_scroll(const struct wmEvent *event, int *type, int *val); extern void ui_button_activate_do(struct bContext *C, struct ARegion *ar, uiBut *but); +extern void ui_button_activate_over(struct bContext *C, struct ARegion *ar, uiBut *but); extern void ui_button_execute_begin(struct bContext *C, struct ARegion *ar, uiBut *but, void **active_back); extern void ui_button_execute_end(struct bContext *C, struct ARegion *ar, uiBut *but, void *active_back); extern void ui_button_active_free(const struct bContext *C, uiBut *but); extern bool ui_button_is_active(struct ARegion *ar) ATTR_WARN_UNUSED_RESULT; extern int ui_button_open_menu_direction(uiBut *but); extern void ui_button_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiBut *but, const bool restore); +extern uiBut *ui_but_find_activated(struct ARegion *ar); +bool ui_but_is_editable(const uiBut *but); + void ui_button_clipboard_free(void); void ui_panel_menu(struct bContext *C, ARegion *ar, Panel *pa); uiBut *ui_but_find_old(uiBlock *block_old, const uiBut *but_new); @@ -589,7 +595,6 @@ int ui_id_icon_get(struct bContext *C, struct ID *id, const bool big); /* resources.c */ void init_userdef_do_versions(void); -void init_userdef_factory(void); void ui_theme_init_default(void); void ui_style_init_default(void); void ui_resources_init(void); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 789c10d6693..645eb607031 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -1181,7 +1181,7 @@ void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index if (flag & UI_ITEM_R_ICON_ONLY) { /* pass */ } - else if (ELEM4(type, PROP_INT, PROP_FLOAT, PROP_STRING, PROP_POINTER)) { + else if (ELEM(type, PROP_INT, PROP_FLOAT, PROP_STRING, PROP_POINTER)) { name = ui_item_name_add_colon(name, namestr); } else if (type == PROP_BOOLEAN && is_array && index == RNA_NO_INDEX) { @@ -1323,9 +1323,9 @@ void uiItemEnumR_string(uiLayout *layout, struct PointerRNA *ptr, const char *pr for (a = 0; item[a].identifier; a++) { if (item[a].value == ivalue) { - const char *item_name = CTX_IFACE_(RNA_property_translation_context(prop), item[a].name); + const char *item_name = name ? name : CTX_IFACE_(RNA_property_translation_context(prop), item[a].name); - uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, ivalue, 0, item_name ? item_name : name, icon ? icon : item[a].icon); + uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, ivalue, 0, item_name, icon ? icon : item[a].icon); break; } } @@ -1559,7 +1559,7 @@ void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propna } type = RNA_property_type(prop); - if (!ELEM3(type, PROP_POINTER, PROP_STRING, PROP_ENUM)) { + if (!ELEM(type, PROP_POINTER, PROP_STRING, PROP_ENUM)) { RNA_warning("Property %s must be a pointer, string or enum", propname); return; } diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 877a993e0ac..458aca444cb 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -35,6 +35,7 @@ #include "DNA_text_types.h" /* for UI_OT_reports_to_text */ #include "BLI_blenlib.h" +#include "BLI_math_color.h" #include "BLF_api.h" #include "BLF_translation.h" @@ -44,6 +45,7 @@ #include "BKE_global.h" #include "BKE_text.h" /* for UI_OT_reports_to_text */ #include "BKE_report.h" +#include "BKE_paint.h" #include "RNA_access.h" #include "RNA_define.h" @@ -55,6 +57,8 @@ #include "WM_api.h" #include "WM_types.h" +#include "ED_paint.h" + /* only for UI_OT_editsource */ #include "ED_screen.h" #include "BKE_main.h" @@ -258,28 +262,43 @@ static void UI_OT_unset_property_button(wmOperatorType *ot) /* Copy To Selected Operator ------------------------ */ -static bool copy_to_selected_list(bContext *C, PointerRNA *ptr, ListBase *lb, bool *use_path) +static bool copy_to_selected_list( + bContext *C, PointerRNA *ptr, PropertyRNA *prop, + ListBase *r_lb, bool *r_use_path_from_id, char **r_path) { - *use_path = false; + *r_use_path_from_id = false; + *r_path = NULL; - if (RNA_struct_is_a(ptr->type, &RNA_EditBone)) - *lb = CTX_data_collection_get(C, "selected_editable_bones"); - else if (RNA_struct_is_a(ptr->type, &RNA_PoseBone)) - *lb = CTX_data_collection_get(C, "selected_pose_bones"); - else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) - *lb = CTX_data_collection_get(C, "selected_editable_sequences"); - else { + if (RNA_struct_is_a(ptr->type, &RNA_EditBone)) { + *r_lb = CTX_data_collection_get(C, "selected_editable_bones"); + } + else if (RNA_struct_is_a(ptr->type, &RNA_PoseBone)) { + *r_lb = CTX_data_collection_get(C, "selected_pose_bones"); + } + else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) { + *r_lb = CTX_data_collection_get(C, "selected_editable_sequences"); + } + else if (ptr->id.data) { ID *id = ptr->id.data; - if (id && GS(id->name) == ID_OB) { - *lb = CTX_data_collection_get(C, "selected_editable_objects"); - *use_path = true; + if (GS(id->name) == ID_OB) { + *r_lb = CTX_data_collection_get(C, "selected_editable_objects"); + *r_use_path_from_id = true; + *r_path = RNA_path_from_ID_to_property(ptr, prop); } - else { - return false; + else if (GS(id->name) == ID_SCE) { + /* Sequencer's ID is scene :/ */ + /* Try to recursively find an RNA_Sequence ancestor, to handle situations like T41062... */ + if ((*r_path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Sequence)) != NULL) { + *r_lb = CTX_data_collection_get(C, "selected_editable_sequences"); + } } + return (*r_path != NULL); } - + else { + return false; + } + return true; } @@ -303,47 +322,54 @@ static bool copy_to_selected_button(bContext *C, bool all, bool poll) /* if there is a valid property that is editable... */ if (ptr.data && prop) { char *path = NULL; - bool use_path; + bool use_path_from_id; CollectionPointerLink *link; ListBase lb; - if (!copy_to_selected_list(C, &ptr, &lb, &use_path)) + if (!copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path)) return success; - if (!use_path || (path = RNA_path_from_ID_to_property(&ptr, prop))) { - for (link = lb.first; link; link = link->next) { - if (link->ptr.data != ptr.data) { - if (use_path) { - lprop = NULL; - RNA_id_pointer_create(link->ptr.id.data, &idptr); - RNA_path_resolve_property(&idptr, path, &lptr, &lprop); - } - else { - lptr = link->ptr; - lprop = prop; - } + for (link = lb.first; link; link = link->next) { + if (link->ptr.data != ptr.data) { + if (use_path_from_id) { + /* Path relative to ID. */ + lprop = NULL; + RNA_id_pointer_create(link->ptr.id.data, &idptr); + RNA_path_resolve_property(&idptr, path, &lptr, &lprop); + } + else if (path) { + /* Path relative to elements from list. */ + lprop = NULL; + RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop); + } + else { + lptr = link->ptr; + lprop = prop; + } + + if (lptr.data == ptr.data) { + /* lptr might not be the same as link->ptr! */ + continue; + } - if (lprop == prop) { - if (RNA_property_editable(&lptr, lprop)) { - if (poll) { + if (lprop == prop) { + if (RNA_property_editable(&lptr, lprop)) { + if (poll) { + success = true; + break; + } + else { + if (RNA_property_copy(&lptr, &ptr, prop, (all) ? -1 : index)) { + RNA_property_update(C, &lptr, prop); success = true; - break; - } - else { - if (RNA_property_copy(&lptr, &ptr, prop, (all) ? -1 : index)) { - RNA_property_update(C, &lptr, prop); - success = true; - } } } } } } - - if (path) - MEM_freeN(path); } + MEM_SAFE_FREE(path); BLI_freelistN(&lb); } @@ -810,6 +836,91 @@ static void UI_OT_reloadtranslation(wmOperatorType *ot) ot->exec = reloadtranslation_exec; } +int UI_drop_color_poll(struct bContext *C, wmDrag *drag, const wmEvent *UNUSED(event)) +{ + /* should only return true for regions that include buttons, for now + * return true always */ + if (drag->type == WM_DRAG_COLOR) { + SpaceImage *sima = CTX_wm_space_image(C); + ARegion *ar = CTX_wm_region(C); + + if (UI_but_active_drop_color(C)) + return 1; + + if (sima && (sima->mode == SI_MODE_PAINT) && + sima->image && (ar && ar->regiontype == RGN_TYPE_WINDOW)) + { + return 1; + } + } + + return 0; +} + +void UI_drop_color_copy(wmDrag *drag, wmDropBox *drop) +{ + uiDragColorHandle *drag_info = (uiDragColorHandle *)drag->poin; + + RNA_float_set_array(drop->ptr, "color", drag_info->color); + RNA_boolean_set(drop->ptr, "gamma", drag_info->gamma_corrected); +} + +static int drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + ARegion *ar = CTX_wm_region(C); + uiBut *but = NULL; + float color[3]; + bool gamma; + + RNA_float_get_array(op->ptr, "color", color); + gamma = RNA_boolean_get(op->ptr, "gamma"); + + /* find button under mouse, check if it has RNA color property and + * if it does copy the data */ + but = ui_but_find_activated(ar); + + if (but && but->type == COLOR && but->rnaprop) { + if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) { + if (!gamma) + ui_block_to_display_space_v3(but->block, color); + RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color); + RNA_property_update(C, &but->rnapoin, but->rnaprop); + } + else if (RNA_property_subtype(but->rnaprop) == PROP_COLOR) { + if (gamma) + ui_block_to_scene_linear_v3(but->block, color); + RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color); + RNA_property_update(C, &but->rnapoin, but->rnaprop); + } + } + else { + if (gamma) { + srgb_to_linearrgb_v3_v3(color, color); + } + + ED_imapaint_bucket_fill(C, color, op); + } + + ED_region_tag_redraw(ar); + + return OPERATOR_FINISHED; +} + + +static void UI_OT_drop_color(wmOperatorType *ot) +{ + ot->name = "Drop Color"; + ot->idname = "UI_OT_drop_color"; + ot->description = "Drop colors to buttons"; + + ot->invoke = drop_color_invoke; + + RNA_def_float_color(ot->srna, "color", 3, NULL, 0.0, FLT_MAX, "Color", "Source color", 0.0, 1.0); + RNA_def_boolean(ot->srna, "gamma", 0, "Gamma Corrected", "The source color is gamma corrected "); +} + + + /* ********************************************************* */ /* Registration */ @@ -821,7 +932,7 @@ void UI_buttons_operatortypes(void) WM_operatortype_append(UI_OT_unset_property_button); WM_operatortype_append(UI_OT_copy_to_selected_button); WM_operatortype_append(UI_OT_reports_to_textblock); /* XXX: temp? */ - + WM_operatortype_append(UI_OT_drop_color); #ifdef WITH_PYTHON WM_operatortype_append(UI_OT_editsource); WM_operatortype_append(UI_OT_edittranslation_init); diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 2ccb3740777..d0909e9413c 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -120,7 +120,7 @@ static int panel_aligned(ScrArea *sa, ARegion *ar) return BUT_VERTICAL; else if (sa->spacetype == SPACE_IMAGE && ar->regiontype == RGN_TYPE_PREVIEW) return BUT_VERTICAL; - else if (ELEM3(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS)) + else if (ELEM(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS)) return BUT_VERTICAL; return 0; @@ -462,31 +462,41 @@ static void ui_draw_panel_scalewidget(const rcti *rect) fdrawline(xmin + dx, ymin + 1, xmax, ymax - dy + 1); glDisable(GL_BLEND); } - static void ui_draw_panel_dragwidget(const rctf *rect) { - float xmin, xmax, dx; - float ymin, ymax, dy; - - xmin = rect->xmin; - xmax = rect->xmax; - ymin = rect->ymin; - ymax = rect->ymax; - - dx = (xmax - xmin) / 3.0f; - dy = (ymax - ymin) / 3.0f; - - glEnable(GL_BLEND); - glColor4ub(255, 255, 255, 50); - fdrawline(xmin, ymax, xmax, ymin); - fdrawline(xmin + dx, ymax, xmax, ymin + dy); - fdrawline(xmin + 2 * dx, ymax, xmax, ymin + 2 * dy); - - glColor4ub(0, 0, 0, 50); - fdrawline(xmin, ymax + 1, xmax, ymin + 1); - fdrawline(xmin + dx, ymax + 1, xmax, ymin + dy + 1); - fdrawline(xmin + 2 * dx, ymax + 1, xmax, ymin + 2 * dy + 1); - glDisable(GL_BLEND); + unsigned char col_back[3], col_high[3], col_dark[3]; + const int col_tint = 84; + + const int px = (int)U.pixelsize; + const int px_zoom = max_ii(iroundf(BLI_rctf_size_y(rect) / 22.0f), 1); + + const int box_margin = max_ii(iroundf((float)(px_zoom * 2.0f)), px); + const int box_size = max_ii(iroundf((BLI_rctf_size_y(rect) / 8.0f) - px), px); + + const int x_min = rect->xmin; + const int y_min = rect->ymin; + const int y_ofs = max_ii(iroundf(BLI_rctf_size_y(rect) / 3.0f), px); + const int x_ofs = y_ofs; + int i_x, i_y; + + + UI_GetThemeColor3ubv(UI_GetThemeValue(TH_PANEL_SHOW_HEADER) ? TH_PANEL_HEADER : TH_PANEL_BACK, col_back); + UI_GetColorPtrShade3ubv(col_back, col_high, col_tint); + UI_GetColorPtrShade3ubv(col_back, col_dark, -col_tint); + + + /* draw multiple boxes */ + for (i_x = 0; i_x < 4; i_x++) { + for (i_y = 0; i_y < 2; i_y++) { + const int x_co = (x_min + x_ofs) + (i_x * (box_size + box_margin)); + const int y_co = (y_min + y_ofs) + (i_y * (box_size + box_margin)); + + glColor3ubv(col_dark); + glRectf(x_co - box_size, y_co - px_zoom, x_co, (y_co + box_size) - px_zoom); + glColor3ubv(col_high); + glRectf(x_co - box_size, y_co, x_co, y_co + box_size); + } + } } @@ -1131,7 +1141,7 @@ static void ui_handle_panel_header(const bContext *C, uiBlock *block, int mx, in button = 1; else if (event == AKEY) button = 1; - else if (ELEM3(event, 0, RETKEY, LEFTMOUSE) && shift) { + else if (ELEM(event, 0, RETKEY, LEFTMOUSE) && shift) { block->panel->flag ^= PNL_PIN; button = 2; } @@ -1716,7 +1726,7 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar) /* XXX hardcoded key warning */ if ((inside || inside_header) && event->val == KM_PRESS) { - if (event->type == AKEY && !ELEM4(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift, event->alt)) { + if (event->type == AKEY && !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift, event->alt)) { if (pa->flag & PNL_CLOSEDY) { if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my)) diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index c32f0de937e..3629c72ce49 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -392,7 +392,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) data->totline++; } - if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { + if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { /* better not show the value of a password */ if ((but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PASSWORD)) == 0) { /* full string */ @@ -1872,7 +1872,7 @@ static void ui_update_block_buts_rgb(uiBlock *block, const float rgb[3], bool is if (rgb_gamma[2] > 1.0f) rgb_gamma[2] = modf(rgb_gamma[2], &intpart); rgb_float_to_uchar(rgb_gamma_uchar, rgb_gamma); - BLI_snprintf(col, sizeof(col), "%02X%02X%02X", UNPACK3OP((unsigned int), rgb_gamma_uchar)); + BLI_snprintf(col, sizeof(col), "%02X%02X%02X", UNPACK3_EX((unsigned int), rgb_gamma_uchar, )); strcpy(bt->poin, col); } @@ -2160,7 +2160,7 @@ static void uiBlockPicker(uiBlock *block, float rgba[4], PointerRNA *ptr, Proper } rgb_float_to_uchar(rgb_gamma_uchar, rgb_gamma); - BLI_snprintf(hexcol, sizeof(hexcol), "%02X%02X%02X", UNPACK3OP((unsigned int), rgb_gamma_uchar)); + BLI_snprintf(hexcol, sizeof(hexcol), "%02X%02X%02X", UNPACK3_EX((unsigned int), rgb_gamma_uchar, )); yco = -3.0f * UI_UNIT_Y; bt = uiDefBut(block, TEX, 0, IFACE_("Hex: "), 0, yco, butwidth, UI_UNIT_Y, hexcol, 0, 8, 0, 0, TIP_("Hex triplet for color (#RRGGBB)")); @@ -2408,6 +2408,7 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi uiBlockSetFlag(block, UI_BLOCK_MOVEMOUSE_QUIT); if (pup->popup) { + uiBut *but_activate = NULL; uiBlockSetFlag(block, UI_BLOCK_LOOP | UI_BLOCK_REDRAW | UI_BLOCK_NUMSELECT); uiBlockSetDirection(block, direction); @@ -2421,6 +2422,10 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi * block to be under the mouse */ offset[0] = -(bt->rect.xmin + 0.8f * BLI_rctf_size_x(&bt->rect)); offset[1] = -(bt->rect.ymin + 0.5f * UI_UNIT_Y); + + if (ui_but_is_editable(bt)) { + but_activate = bt; + } } else { /* position mouse at 0.8*width of the button and below the tile @@ -2430,6 +2435,20 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi offset[0] = min_ii(offset[0], -(bt->rect.xmin + 0.8f * BLI_rctf_size_x(&bt->rect))); offset[1] = 2.1 * UI_UNIT_Y; + + for (bt = block->buttons.first; bt; bt = bt->next) { + if (ui_but_is_editable(bt)) { + but_activate = bt; + break; + } + } + } + + /* in rare cases this is needed since moving the popup + * to be within the window bounds may move it away from the mouse, + * This ensures we set an item to be active. */ + if (but_activate) { + ui_button_activate_over(C, handle->region, but_activate); } block->minbounds = minwidth; diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 1c5d3ecfd2e..cb5f5331c2e 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -36,6 +36,7 @@ #include "DNA_scene_types.h" #include "DNA_object_types.h" #include "DNA_object_force.h" +#include "DNA_brush_types.h" #include "BLI_utildefines.h" #include "BLI_string.h" @@ -60,6 +61,7 @@ #include "BKE_object.h" #include "BKE_packedFile.h" #include "BKE_particle.h" +#include "BKE_paint.h" #include "BKE_report.h" #include "BKE_sca.h" #include "BKE_screen.h" @@ -349,6 +351,8 @@ static const char *template_id_browse_tip(StructRNA *type) case ID_BR: return N_("Browse Brush to be linked"); case ID_PA: return N_("Browse Particle Settings to be linked"); case ID_GD: return N_("Browse Grease Pencil Data to be linked"); + case ID_PAL: return N_("Browse Palette Data to be linked"); + case ID_PC: return N_("Browse Paint Curve Data to be linked"); } } return N_("Browse ID data to be linked"); @@ -489,7 +493,7 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str if (user_alert) uiButSetFlag(but, UI_BUT_REDALERT); - if (id->lib == NULL && !(ELEM5(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB))) { + if (id->lib == NULL && !(ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB))) { uiDefButR(block, TOG, 0, "F", 0, 0, UI_UNIT_X, UI_UNIT_Y, &idptr, "use_fake_user", -1, 0, 0, -1, -1, NULL); } } @@ -808,7 +812,7 @@ static int modifier_can_delete(ModifierData *md) static int modifier_is_simulation(ModifierData *md) { /* Physic Tab */ - if (ELEM7(md->type, eModifierType_Cloth, eModifierType_Collision, eModifierType_Fluidsim, eModifierType_Smoke, + if (ELEM(md->type, eModifierType_Cloth, eModifierType_Collision, eModifierType_Fluidsim, eModifierType_Smoke, eModifierType_Softbody, eModifierType_Surface, eModifierType_DynamicPaint)) { return 1; @@ -906,9 +910,9 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob, uiBlockSetEmboss(block, UI_EMBOSS); } } /* tessellation point for curve-typed objects */ - else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { + else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { /* some modifiers could work with pre-tessellated curves only */ - if (ELEM3(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) { + if (ELEM(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) { /* add disabled pre-tessellated button, so users could have * message for this modifiers */ but = uiDefIconButBitI(block, TOG, eModifierMode_ApplyOnSpline, 0, ICON_SURFACE_DATA, 0, 0, @@ -979,7 +983,7 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob, uiBlockClearButLock(block); uiBlockSetButLock(block, ob && ob->id.lib, ERROR_LIBDATA_MESSAGE); - if (!ELEM5(md->type, eModifierType_Fluidsim, eModifierType_Softbody, eModifierType_ParticleSystem, + if (!ELEM(md->type, eModifierType_Fluidsim, eModifierType_Softbody, eModifierType_ParticleSystem, eModifierType_Cloth, eModifierType_Smoke)) { uiItemO(row, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Copy"), ICON_NONE, @@ -1298,7 +1302,7 @@ void uiTemplatePreview(uiLayout *layout, bContext *C, ID *id, int show_buttons, char _preview_id[UI_MAX_NAME_STR]; - if (id && !ELEM5(GS(id->name), ID_MA, ID_TE, ID_WO, ID_LA, ID_LS)) { + if (id && !ELEM(GS(id->name), ID_MA, ID_TE, ID_WO, ID_LA, ID_LS)) { RNA_warning("Expected ID of type material, texture, lamp, world or line style"); return; } @@ -2363,6 +2367,61 @@ void uiTemplateColorPicker(uiLayout *layout, PointerRNA *ptr, const char *propna } } +void uiTemplatePalette(uiLayout *layout, PointerRNA *ptr, const char *propname, int UNUSED(colors)) +{ + PropertyRNA *prop = RNA_struct_find_property(ptr, propname); + PointerRNA cptr; + Palette *palette; + PaletteColor *color; + uiBlock *block; + uiLayout *col; + int row_cols = 0, col_id = 0; + int cols_per_row = MAX2(uiLayoutGetWidth(layout) / UI_UNIT_X, 1); + + if (!prop) { + RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname); + return; + } + + cptr = RNA_property_pointer_get(ptr, prop); + if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Palette)) + return; + + block = uiLayoutGetBlock(layout); + + palette = cptr.data; + + /* first delete any pending colors */ + BKE_palette_cleanup(palette); + + color = palette->colors.first; + + col = uiLayoutColumn(layout, true); + uiLayoutRow(col, true); + uiDefIconButO(block, BUT, "PALETTE_OT_color_add", WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL); + uiDefIconButO(block, BUT, "PALETTE_OT_color_delete", WM_OP_INVOKE_DEFAULT, ICON_ZOOMOUT, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL); + + col = uiLayoutColumn(layout, true); + uiLayoutRow(col, true); + + for (; color; color = color->next) { + PointerRNA ptr; + + if (row_cols >= cols_per_row) { + uiLayoutRow(col, true); + row_cols = 0; + } + + RNA_pointer_create(&palette->id, &RNA_PaletteColor, color, &ptr); + uiDefButR(block, COLOR, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, &ptr, "color", -1, 0.0, 1.0, + UI_PALETTE_COLOR, (col_id == palette->active_color) ? UI_PALETTE_COLOR_ACTIVE : 0.0, ""); + + row_cols++; + col_id++; + } +} + + /********************* Layer Buttons Template ************************/ static void handle_layer_buttons(bContext *C, void *arg1, void *arg2) @@ -3543,7 +3602,7 @@ void uiTemplateColormanagedViewSettings(uiLayout *layout, bContext *UNUSED(C), P col = uiLayoutColumn(layout, false); row = uiLayoutRow(col, false); - uiItemR(row, &view_transform_ptr, "view_transform", UI_ITEM_R_EXPAND, IFACE_("View"), ICON_NONE); + uiItemR(row, &view_transform_ptr, "view_transform", 0, IFACE_("View"), ICON_NONE); col = uiLayoutColumn(layout, false); uiItemR(col, &view_transform_ptr, "exposure", 0, NULL, ICON_NONE); diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index 744ed7e5b72..008ea84b607 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -151,7 +151,7 @@ int uiDefAutoButsRNA(uiLayout *layout, PointerRNA *ptr, const char *name; int tot = 0; - assert(ELEM3(label_align, '\0', 'H', 'V')); + assert(ELEM(label_align, '\0', 'H', 'V')); RNA_STRUCT_BEGIN (ptr, prop) { diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 6ea0a55729d..23f185befb9 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -33,6 +33,7 @@ #include <string.h> #include <assert.h> +#include "DNA_brush_types.h" #include "DNA_screen_types.h" #include "DNA_userdef_types.h" @@ -848,7 +849,7 @@ static void widget_draw_icon(const uiBut *but, BIFIconID icon, float alpha, cons height = ICON_DEFAULT_HEIGHT / aspect; /* calculate blend color */ - if (ELEM4(but->type, TOG, ROW, TOGN, LISTROW)) { + if (ELEM(but->type, TOG, ROW, TOGN, LISTROW)) { if (but->flag & UI_SELECT) {} else if (but->flag & UI_ACTIVE) {} else alpha = 0.5f; @@ -2825,6 +2826,17 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat widgetbase_draw(&wtb, wcol); + if (but->a1 == UI_PALETTE_COLOR && but->a2 == UI_PALETTE_COLOR_ACTIVE) { + float width = rect->xmax - rect->xmin; + float height = rect->ymax - rect->ymin; + + glColor4ubv((unsigned char *)wcol->outline); + glBegin(GL_TRIANGLES); + glVertex2f(rect->xmin + 0.1f * width, rect->ymin + 0.9f * height); + glVertex2f(rect->xmin + 0.1f * width, rect->ymin + 0.5f * height); + glVertex2f(rect->xmin + 0.5f * width, rect->ymin + 0.9f * height); + glEnd(); + } } static void widget_normal(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign)) diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 372ced0a6fd..dbb0235f40f 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -36,11 +36,10 @@ #include "MEM_guardedalloc.h" #include "DNA_curve_types.h" -#include "DNA_userdef_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" +#include "DNA_userdef_types.h" #include "DNA_windowmanager_types.h" -#include "DNA_mesh_types.h" /* init_userdef_factory */ #include "BLI_blenlib.h" #include "BLI_utildefines.h" @@ -51,7 +50,6 @@ #include "BKE_main.h" #include "BKE_texture.h" - #include "BIF_gl.h" #include "UI_interface.h" @@ -537,6 +535,13 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo cp = ts->preview_stitch_active; break; + case TH_PAINT_CURVE_HANDLE: + cp = ts->paint_curve_handle; + break; + case TH_PAINT_CURVE_PIVOT: + cp = ts->paint_curve_pivot; + break; + case TH_UV_OTHERS: cp = ts->uv_others; break; @@ -774,6 +779,8 @@ static void ui_theme_space_init_handles_color(ThemeSpace *theme_space) rgba_char_args_set(theme_space->handle_sel_auto, 0xf0, 0xff, 0x40, 255); rgba_char_args_set(theme_space->handle_sel_vect, 0x40, 0xc0, 0x30, 255); rgba_char_args_set(theme_space->handle_sel_align, 0xf0, 0x90, 0xa0, 255); + rgba_char_args_set(theme_space->handle_vertex, 0x00, 0x00, 0x00, 0xff); + rgba_char_args_set(theme_space->handle_vertex_select, 0xff, 0xff, 0, 0xff); rgba_char_args_set(theme_space->act_spline, 0xdb, 0x25, 0x12, 255); } @@ -871,6 +878,8 @@ void ui_theme_init_default(void) rgba_char_args_set(btheme->tv3d.title, 0, 0, 0, 255); rgba_char_args_set(btheme->tv3d.freestyle_edge_mark, 0x7f, 0xff, 0x7f, 255); rgba_char_args_set(btheme->tv3d.freestyle_face_mark, 0x7f, 0xff, 0x7f, 51); + rgba_char_args_set_fl(btheme->tv3d.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f); + rgba_char_args_set_fl(btheme->tv3d.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f); btheme->tv3d.facedot_size = 4; @@ -1129,8 +1138,6 @@ void ui_theme_init_default(void) rgba_char_args_set(btheme->tclip.path_after, 0x00, 0x00, 0xff, 255); rgba_char_args_set(btheme->tclip.grid, 0x5e, 0x5e, 0x5e, 255); rgba_char_args_set(btheme->tclip.cframe, 0x60, 0xc0, 0x40, 255); - rgba_char_args_set(btheme->tclip.handle_vertex, 0x00, 0x00, 0x00, 0xff); - rgba_char_args_set(btheme->tclip.handle_vertex_select, 0xff, 0xff, 0, 0xff); rgba_char_args_set(btheme->tclip.list, 0x66, 0x66, 0x66, 0xff); rgba_char_args_set(btheme->tclip.strip, 0x0c, 0x0a, 0x0a, 0x80); rgba_char_args_set(btheme->tclip.strip_select, 0xff, 0x8c, 0x00, 0xff); @@ -2427,6 +2434,16 @@ void init_userdef_do_versions(void) } } + if (U.versionfile < 272 || (U.versionfile == 272 && U.subversionfile < 2)) { + bTheme *btheme; + for (btheme = U.themes.first; btheme; btheme = btheme->next) { + rgba_char_args_set_fl(btheme->tv3d.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f); + rgba_char_args_set_fl(btheme->tv3d.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f); + rgba_char_args_set_fl(btheme->tima.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f); + rgba_char_args_set_fl(btheme->tima.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f); + } + } + { bTheme *btheme; for (btheme = U.themes.first; btheme; btheme = btheme->next) { @@ -2449,25 +2466,3 @@ void init_userdef_do_versions(void) // XXX reset_autosave(); } - -/** - * Override values in in-memory startup.blend, avoids resaving for small changes. - */ -void init_userdef_factory(void) -{ - /* defaults from T37518 */ - - U.uiflag |= USER_ZBUF_CURSOR; - U.uiflag |= USER_QUIT_PROMPT; - U.uiflag |= USER_CONTINUOUS_MOUSE; - - U.versions = 1; - U.savetime = 2; - - { - Mesh *me; - for (me = G.main->mesh.first; me; me = me->id.next) { - me->flag &= ~ME_TWOSIDED; - } - } -} diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index 4d2ea0e64f4..a4130540b1b 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -250,7 +250,7 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr) row = uiLayoutRow(box, false); split = uiLayoutSplit(row, 0.6f, UI_LAYOUT_ALIGN_RIGHT); - uiItemL(split, IFACE_("Transformation Type"), ICON_NONE); + uiItemL(split, IFACE_("Transformation Type"), ICON_NONE); uiItemR(split, imfptr, "export_transformation_type_selection", 0, "", ICON_NONE); row = uiLayoutRow(box, false); diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c index cc26d6079a9..553c1faa36a 100644 --- a/source/blender/editors/mesh/editmesh_knife_project.c +++ b/source/blender/editors/mesh/editmesh_knife_project.c @@ -65,7 +65,7 @@ static LinkNode *knifeproject_poly_from_object(ARegion *ar, Scene *scene, Object dm = ob->derivedFinal ? ob->derivedFinal : mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); dm_needsFree = false; } - else if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { + else if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { dm = CDDM_from_curve(ob); dm_needsFree = true; } diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 23828098940..9cdfb43ae15 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -2807,6 +2807,13 @@ static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op) BMEdge *e; BMIter iter; + const bool use_wire = RNA_boolean_get(op->ptr, "use_wire"); + const bool use_boundary = RNA_boolean_get(op->ptr, "use_boundary"); + const bool use_multi_face = RNA_boolean_get(op->ptr, "use_multi_face"); + const bool use_non_contiguous = RNA_boolean_get(op->ptr, "use_non_contiguous"); + const bool use_verts = RNA_boolean_get(op->ptr, "use_verts"); + + if (!RNA_boolean_get(op->ptr, "extend")) EDBM_flag_disable_all(em, BM_ELEM_SELECT); @@ -2819,15 +2826,30 @@ static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { - if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN) && !BM_vert_is_manifold(v)) { - BM_vert_select_set(em->bm, v, true); + if (use_verts) { + BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { + if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { + if (!BM_vert_is_manifold(v)) { + BM_vert_select_set(em->bm, v, true); + } + } } } - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && !BM_edge_is_manifold(e)) { - BM_edge_select_set(em->bm, e, true); + if (use_wire || use_boundary || use_multi_face || use_non_contiguous) { + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + if ((use_wire && BM_edge_is_wire(e)) || + (use_boundary && BM_edge_is_boundary(e)) || + (use_non_contiguous && (BM_edge_is_manifold(e) && !BM_edge_is_contiguous(e))) || + (use_multi_face && (BM_edge_face_count(e) > 2))) + { + /* check we never select perfect edge (in test above) */ + BLI_assert(!(BM_edge_is_manifold(e) && BM_edge_is_contiguous(e))); + + BM_edge_select_set(em->bm, e, true); + } + } } } @@ -2854,6 +2876,18 @@ void MESH_OT_select_non_manifold(wmOperatorType *ot) /* props */ RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend the selection"); + /* edges */ + RNA_def_boolean(ot->srna, "use_wire", true, "Wire", + "Wire edges"); + RNA_def_boolean(ot->srna, "use_boundary", true, "Boundaries", + "Boundary edges"); + RNA_def_boolean(ot->srna, "use_multi_face", true, + "Multiple Faces", "Edges shared by 3+ faces"); + RNA_def_boolean(ot->srna, "use_non_contiguous", true, "Non Contiguous", + "Edges between faces pointing in alternate directions"); + /* verts */ + RNA_def_boolean(ot->srna, "use_verts", true, "Vertices", + "Vertices connecting multiple face regions"); } static int edbm_select_random_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 27145cc7649..ddf7650deaf 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -3052,7 +3052,7 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op) float (*screen_vert_coords)[2], (*sco)[2], (*mouse_path)[2]; /* edit-object needed for matrix, and ar->regiondata for projections to work */ - if (ELEM3(NULL, obedit, ar, ar->regiondata)) + if (ELEM(NULL, obedit, ar, ar->regiondata)) return OPERATOR_CANCELLED; if (bm->totvertsel < 2) { @@ -3675,7 +3675,7 @@ static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span } /* set this vertex first */ - BLI_rotatelist_first(verts, v_act_link); + BLI_listbase_rotate_first(verts, v_act_link); BM_edgeloop_edges_get(el_store, edges); @@ -4107,6 +4107,11 @@ static void edbm_dissolve_prop__use_face_split(wmOperatorType *ot) RNA_def_boolean(ot->srna, "use_face_split", 0, "Face Split", "Split off face corners to maintain surrounding geometry"); } +static void edbm_dissolve_prop__use_boundary_tear(wmOperatorType *ot) +{ + RNA_def_boolean(ot->srna, "use_boundary_tear", 0, "Tear Boundary", + "Split off face corners instead of merging faces"); +} static int edbm_dissolve_verts_exec(bContext *C, wmOperator *op) { @@ -4114,9 +4119,14 @@ static int edbm_dissolve_verts_exec(bContext *C, wmOperator *op) BMEditMesh *em = BKE_editmesh_from_object(obedit); const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split"); + const bool use_boundary_tear = RNA_boolean_get(op->ptr, "use_boundary_tear"); - if (!EDBM_op_callf(em, op, "dissolve_verts verts=%hv use_face_split=%b", BM_ELEM_SELECT, use_face_split)) + if (!EDBM_op_callf(em, op, + "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b", + BM_ELEM_SELECT, use_face_split, use_boundary_tear)) + { return OPERATOR_CANCELLED; + } EDBM_update_generic(em, true, true); @@ -4138,6 +4148,7 @@ void MESH_OT_dissolve_verts(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; edbm_dissolve_prop__use_face_split(ot); + edbm_dissolve_prop__use_boundary_tear(ot); } static int edbm_dissolve_edges_exec(bContext *C, wmOperator *op) @@ -4249,6 +4260,7 @@ void MESH_OT_dissolve_mode(wmOperatorType *ot) edbm_dissolve_prop__use_verts(ot); edbm_dissolve_prop__use_face_split(ot); + edbm_dissolve_prop__use_boundary_tear(ot); } static int edbm_dissolve_limited_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c index 36c7bb404da..feac7f6ece3 100644 --- a/source/blender/editors/metaball/mball_edit.c +++ b/source/blender/editors/metaball/mball_edit.c @@ -594,7 +594,7 @@ bool mouse_mball(bContext *C, const int mval[2], bool extend, bool deselect, boo rect.ymin = mval[1] - 12; rect.ymax = mval[1] + 12; - hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect); + hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true); /* does startelem exist? */ ml = mb->editelems->first; diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 99dd8b75609..34b4ca2c0f1 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1470,7 +1470,7 @@ static void convert_ensure_curve_cache(Main *bmain, Scene *scene, Object *ob) /* Force creation. This is normally not needed but on operator * redo we might end up with an object which isn't evaluated yet. */ - if (ELEM3(ob->type, OB_SURF, OB_CURVE, OB_FONT)) { + if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) { BKE_displist_make_curveTypes(scene, ob, false); } else if (ob->type == OB_MBALL) { @@ -2274,7 +2274,7 @@ static int join_poll(bContext *C) if (!ob || ob->id.lib) return 0; - if (ELEM4(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE)) + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE)) return ED_operator_screenactive(C); else return 0; diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index 94574e81b81..2402ecb498d 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -770,7 +770,7 @@ static int objects_bake_render_modal(bContext *C, wmOperator *UNUSED(op), const static bool is_multires_bake(Scene *scene) { - if (ELEM4(scene->r.bake_mode, RE_BAKE_NORMALS, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_AO)) + if (ELEM(scene->r.bake_mode, RE_BAKE_NORMALS, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_AO)) return scene->r.bake_flag & R_BAKE_MULTIRES; return 0; diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index f57ab220471..e21f56538aa 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -51,6 +51,7 @@ #include "BKE_image.h" #include "BKE_library.h" #include "BKE_main.h" +#include "BKE_node.h" #include "BKE_report.h" #include "BKE_modifier.h" #include "BKE_mesh.h" @@ -177,7 +178,7 @@ static bool write_internal_bake_pixels( void *lock; bool is_float; char *mask_buffer = NULL; - const int num_pixels = width * height; + const size_t num_pixels = (size_t)width * (size_t)height; ibuf = BKE_image_acquire_ibuf(image, NULL, &lock); @@ -310,7 +311,7 @@ static bool write_external_bake_pixels( /* margins */ if (margin > 0) { char *mask_buffer = NULL; - const int num_pixels = width * height; + const size_t num_pixels = (size_t)width * (size_t)height; mask_buffer = MEM_callocN(sizeof(char) * num_pixels, "Bake Mask"); RE_bake_mask_fill(pixel_array, num_pixels, mask_buffer); @@ -335,14 +336,14 @@ static bool write_external_bake_pixels( static bool is_noncolor_pass(ScenePassType pass_type) { - return ELEM7(pass_type, - SCE_PASS_Z, - SCE_PASS_NORMAL, - SCE_PASS_VECTOR, - SCE_PASS_INDEXOB, - SCE_PASS_UV, - SCE_PASS_RAYHITS, - SCE_PASS_INDEXMA); + return ELEM(pass_type, + SCE_PASS_Z, + SCE_PASS_NORMAL, + SCE_PASS_VECTOR, + SCE_PASS_INDEXOB, + SCE_PASS_UV, + SCE_PASS_RAYHITS, + SCE_PASS_INDEXMA); } /* if all is good tag image and return true */ @@ -367,10 +368,22 @@ static bool bake_object_check(Object *ob, ReportList *reports) } for (i = 0; i < ob->totcol; i++) { - ED_object_get_active_image(ob, i + 1, &image, NULL, NULL); + bNodeTree *ntree = NULL; + bNode *node = NULL; + ED_object_get_active_image(ob, i + 1, &image, NULL, &node, &ntree); if (image) { - ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, &lock); + ImBuf *ibuf; + + if (node) { + if (BKE_node_is_connected_to_output(ntree, node)) { + BKE_reportf(reports, RPT_ERROR, + "Circular dependency for image \"%s\" from object \"%s\"", + image->id.name + 2, ob->id.name + 2); + } + } + + ibuf = BKE_image_acquire_ibuf(image, NULL, &lock); if (ibuf) { BKE_image_release_ibuf(image, ibuf, lock); @@ -429,7 +442,7 @@ static bool bake_objects_check(Main *bmain, Object *ob, ListBase *selected_objec if (ob_iter == ob) continue; - if (ELEM5(ob_iter->type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL) == false) { + if (ELEM(ob_iter->type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL) == false) { BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not a mesh or can't be converted to a mesh (Curve, Text, Surface or Metaball)", ob_iter->id.name + 2); return false; } @@ -477,7 +490,7 @@ static void build_image_lookup(Main *bmain, Object *ob, BakeImages *bake_images) for (i = 0; i < tot_mat; i++) { Image *image; - ED_object_get_active_image(ob, i + 1, &image, NULL, NULL); + ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL); if ((image->id.flag & LIB_DOIT)) { for (j = 0; j < i; j++) { @@ -501,10 +514,10 @@ static void build_image_lookup(Main *bmain, Object *ob, BakeImages *bake_images) /* * returns the total number of pixels */ -static int initialize_internal_images(BakeImages *bake_images, ReportList *reports) +static size_t initialize_internal_images(BakeImages *bake_images, ReportList *reports) { int i; - int tot_size = 0; + size_t tot_size = 0; for (i = 0; i < bake_images->size; i++) { ImBuf *ibuf; @@ -518,7 +531,7 @@ static int initialize_internal_images(BakeImages *bake_images, ReportList *repor bk_image->height = ibuf->y; bk_image->offset = tot_size; - tot_size += ibuf->x * ibuf->y; + tot_size += (size_t)ibuf->x * (size_t)ibuf->y; } else { BKE_image_release_ibuf(bk_image->image, ibuf, lock); @@ -563,7 +576,7 @@ static int bake( BakeImages bake_images = {NULL}; - int num_pixels; + size_t num_pixels; int tot_materials; int i; @@ -620,7 +633,7 @@ static int bake( else { /* when saving extenally always use the size specified in the UI */ - num_pixels = width * height * bake_images.size; + num_pixels = (size_t)width * (size_t)height * bake_images.size; for (i = 0; i < bake_images.size; i++) { bake_images.data[i].width = width; @@ -1067,7 +1080,6 @@ static int bake_exec(bContext *C, wmOperator *op) /* setup new render */ RE_test_break_cb(re, NULL, bake_break); - RE_progress_cb(re, NULL, bake_progress_update); if (!bake_objects_check(bkr.main, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.is_selected_to_active)) return OPERATOR_CANCELLED; diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 85e4bbce8dc..92ed84b7f5e 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -485,7 +485,7 @@ static void test_constraints(Object *owner, bPoseChannel *pchan) } /* target checks for specific constraints */ - if (ELEM3(curcon->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_SPLINEIK)) { + if (ELEM(curcon->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_SPLINEIK)) { if (ct->tar) { if (ct->tar->type != OB_CURVE) { ct->tar = NULL; diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index a6ab4bafcaf..2f499cbc4eb 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -139,7 +139,9 @@ static int object_hide_view_clear_exec(bContext *C, wmOperator *UNUSED(op)) /* XXX need a context loop to handle such cases */ for (base = FIRSTBASE; base; base = base->next) { if ((base->lay & v3d->lay) && base->object->restrictflag & OB_RESTRICT_VIEW) { - base->flag |= SELECT; + if (!(base->object->restrictflag & OB_RESTRICT_SELECT)) { + base->flag |= SELECT; + } base->object->flag = base->flag; base->object->restrictflag &= ~OB_RESTRICT_VIEW; changed = true; @@ -344,6 +346,11 @@ static bool ED_object_editmode_load_ex(Object *obedit, const bool freedata) if (freedata) free_editMball(obedit); } + /* Tag update so no access to freed data referenced from + * derived cache will happen. + */ + DAG_id_tag_update((ID *)obedit->data, 0); + return true; } @@ -430,7 +437,7 @@ void ED_object_editmode_enter(bContext *C, int flag) base = scene->basact; } - if (ELEM3(NULL, base, base->object, base->object->data)) return; + if (ELEM(NULL, base, base->object, base->object->data)) return; ob = base->object; @@ -559,7 +566,7 @@ static int editmode_toggle_poll(bContext *C) if ((ob->restrictflag & OB_RESTRICT_VIEW) && !(ob->mode & OB_MODE_EDIT)) return 0; - return (ELEM7(ob->type, OB_MESH, OB_ARMATURE, OB_FONT, OB_MBALL, OB_LATTICE, OB_SURF, OB_CURVE)); + return OB_TYPE_SUPPORT_EDITMODE(ob->type); } void OBJECT_OT_editmode_toggle(wmOperatorType *ot) @@ -730,7 +737,7 @@ static void copy_texture_space(Object *to, Object *ob) texflag = ((Mesh *)ob->data)->texflag; poin2 = ((Mesh *)ob->data)->loc; } - else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { + else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { texflag = ((Curve *)ob->data)->texflag; poin2 = ((Curve *)ob->data)->loc; } @@ -745,7 +752,7 @@ static void copy_texture_space(Object *to, Object *ob) ((Mesh *)to->data)->texflag = texflag; poin1 = ((Mesh *)to->data)->loc; } - else if (ELEM3(to->type, OB_CURVE, OB_SURF, OB_FONT)) { + else if (ELEM(to->type, OB_CURVE, OB_SURF, OB_FONT)) { ((Curve *)to->data)->texflag = texflag; poin1 = ((Curve *)to->data)->loc; } @@ -1082,7 +1089,7 @@ void ED_object_check_force_modifiers(Main *bmain, Scene *scene, Object *object) /* add/remove modifier as needed */ if (!md) { if (pd && (pd->shape == PFIELD_SHAPE_SURFACE) && ELEM(pd->forcefield, PFIELD_GUIDE, PFIELD_TEXTURE) == 0) - if (ELEM4(object->type, OB_MESH, OB_SURF, OB_FONT, OB_CURVE)) + if (ELEM(object->type, OB_MESH, OB_SURF, OB_FONT, OB_CURVE)) ED_object_modifier_add(NULL, bmain, scene, object, NULL, eModifierType_Surface); } else { @@ -1423,7 +1430,7 @@ static void UNUSED_FUNCTION(image_aspect) (Scene *scene, View3D *v3d) BKE_mesh_texspace_get(ob->data, NULL, NULL, size); space = size[0] / size[1]; } - else if (ELEM3(ob->type, OB_CURVE, OB_FONT, OB_SURF)) { + else if (ELEM(ob->type, OB_CURVE, OB_FONT, OB_SURF)) { float size[3]; BKE_curve_texspace_get(ob->data, NULL, NULL, size); space = size[0] / size[1]; @@ -1470,7 +1477,7 @@ static EnumPropertyItem *object_mode_set_itemsf(bContext *C, PointerRNA *UNUSED( if ((input->value == OB_MODE_EDIT && OB_TYPE_SUPPORT_EDITMODE(ob->type)) || (input->value == OB_MODE_POSE && (ob->type == OB_ARMATURE)) || (input->value == OB_MODE_PARTICLE_EDIT && use_mode_particle_edit) || - (ELEM4(input->value, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, + (ELEM(input->value, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT) && (ob->type == OB_MESH)) || (input->value == OB_MODE_OBJECT)) { diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c index 47b5f1605e7..20e2e22cdf8 100644 --- a/source/blender/editors/object/object_group.c +++ b/source/blender/editors/object/object_group.c @@ -563,3 +563,67 @@ void OBJECT_OT_group_remove(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +static int group_unlink_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Group *group = CTX_data_pointer_get_type(C, "group", &RNA_Group).data; + + if (!group) + return OPERATOR_CANCELLED; + + BKE_group_unlink(group); + + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_group_unlink(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Unlink Group"; + ot->idname = "OBJECT_OT_group_unlink"; + ot->description = "Unlink the group from all objects"; + + /* api callbacks */ + ot->exec = group_unlink_exec; + ot->poll = ED_operator_objectmode; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static int select_grouped_exec(bContext *C, wmOperator *UNUSED(op)) /* Select objects in the same group as the active */ +{ + Group *group = CTX_data_pointer_get_type(C, "group", &RNA_Group).data; + + if (!group) + return OPERATOR_CANCELLED; + + CTX_DATA_BEGIN (C, Base *, base, visible_bases) + { + if (!(base->flag & SELECT) && BKE_group_object_exists(group, base->object)) { + ED_base_object_select(base, BA_SELECT); + } + } + CTX_DATA_END; + + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_grouped_select(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Grouped"; + ot->idname = "OBJECT_OT_grouped_select"; + ot->description = "Select all objects in group"; + + /* api callbacks */ + ot->exec = select_grouped_exec; + ot->poll = ED_operator_objectmode; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c index afff367b939..9f9a647c9f1 100644 --- a/source/blender/editors/object/object_hook.c +++ b/source/blender/editors/object/object_hook.c @@ -528,8 +528,7 @@ static int add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob invert_m4_m4(ob->imat, ob->obmat); /* apparently this call goes from right to left... */ - mul_serie_m4(hmd->parentinv, pose_mat, ob->imat, obedit->obmat, - NULL, NULL, NULL, NULL, NULL); + mul_m4_series(hmd->parentinv, pose_mat, ob->imat, obedit->obmat); DAG_relations_tag_update(bmain); diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index fd6b9a1bad0..b8824420018 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -251,6 +251,8 @@ void OBJECT_OT_shape_key_move(struct wmOperatorType *ot); void OBJECT_OT_group_add(struct wmOperatorType *ot); void OBJECT_OT_group_link(struct wmOperatorType *ot); void OBJECT_OT_group_remove(struct wmOperatorType *ot); +void OBJECT_OT_group_unlink(struct wmOperatorType *ot); +void OBJECT_OT_grouped_select(struct wmOperatorType *ot); /* object_bake.c */ void OBJECT_OT_bake_image(wmOperatorType *ot); diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 1249beb4517..b05840b5823 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -98,7 +98,7 @@ ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *sc ModifierTypeInfo *mti = modifierType_getInfo(type); /* only geometry objects should be able to get modifiers [#25291] */ - if (!ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { + if (!ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { BKE_reportf(reports, RPT_WARNING, "Modifiers cannot be added to object '%s'", ob->id.name + 2); return NULL; } @@ -1876,7 +1876,7 @@ static int meshdeform_bind_exec(bContext *C, wmOperator *op) else if (ob->type == OB_MBALL) { BKE_displist_make_mball(CTX_data_main(C)->eval_ctx, scene, ob); } - else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { + else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { BKE_displist_make_curveTypes(scene, ob, 0); } diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index a8f07747d3a..45f981016dc 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -229,6 +229,8 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_group_add); WM_operatortype_append(OBJECT_OT_group_link); WM_operatortype_append(OBJECT_OT_group_remove); + WM_operatortype_append(OBJECT_OT_group_unlink); + WM_operatortype_append(OBJECT_OT_grouped_select); WM_operatortype_append(OBJECT_OT_hook_add_selob); WM_operatortype_append(OBJECT_OT_hook_add_newob); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 3059d84a085..f6d1df4e8d4 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -444,7 +444,7 @@ EnumPropertyItem prop_clear_parent_types[] = { /* Helper for ED_object_parent_clear() - Remove deform-modifiers associated with parent */ static void object_remove_parent_deform_modifiers(Object *ob, const Object *par) { - if (ELEM3(par->type, OB_ARMATURE, OB_LATTICE, OB_CURVE)) { + if (ELEM(par->type, OB_ARMATURE, OB_LATTICE, OB_CURVE)) { ModifierData *md, *mdn; /* assume that we only need to remove the first instance of matching deform modifier here */ @@ -593,7 +593,7 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object int partype, bool xmirror, bool keep_transform, const int vert_par[3]) { bPoseChannel *pchan = NULL; - int pararm = ELEM4(partype, PAR_ARMATURE, PAR_ARMATURE_NAME, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO); + int pararm = ELEM(partype, PAR_ARMATURE, PAR_ARMATURE_NAME, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO); DAG_id_tag_update(&par->id, OB_RECALC_OB); @@ -678,7 +678,7 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object * assuming that the parent is selected too... */ // XXX currently this should only happen for meshes, curves, surfaces, and lattices - this stuff isn't available for metas yet - if (ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { ModifierData *md; switch (partype) { @@ -1128,7 +1128,7 @@ static int object_track_clear_exec(bContext *C, wmOperator *op) /* also remove all tracking constraints */ for (con = ob->constraints.last; con; con = pcon) { pcon = con->prev; - if (ELEM3(con->type, CONSTRAINT_TYPE_TRACKTO, CONSTRAINT_TYPE_LOCKTRACK, CONSTRAINT_TYPE_DAMPTRACK)) + if (ELEM(con->type, CONSTRAINT_TYPE_TRACKTO, CONSTRAINT_TYPE_LOCKTRACK, CONSTRAINT_TYPE_DAMPTRACK)) BKE_constraint_remove(&ob->constraints, con); } @@ -1192,7 +1192,7 @@ static int track_set_exec(bContext *C, wmOperator *op) DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); /* Lamp, Camera and Speaker track differently by default */ - if (ELEM3(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { + if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { data->trackflag = TRACK_nZ; } } @@ -1213,7 +1213,7 @@ static int track_set_exec(bContext *C, wmOperator *op) DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); /* Lamp, Camera and Speaker track differently by default */ - if (ELEM3(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { + if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { data->reserved1 = TRACK_nZ; data->reserved2 = UP_Y; } @@ -1235,7 +1235,7 @@ static int track_set_exec(bContext *C, wmOperator *op) DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); /* Lamp, Camera and Speaker track differently by default */ - if (ELEM3(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { + if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) { data->trackflag = TRACK_nZ; data->lockflag = LOCK_Y; } diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c index be050917f5a..d741991ce7f 100644 --- a/source/blender/editors/object/object_shapekey.c +++ b/source/blender/editors/object/object_shapekey.c @@ -494,9 +494,9 @@ static int shape_key_move_poll(bContext *C) Object *ob = ED_object_context(C); ID *data = (ob) ? ob->data : NULL; Key *key = BKE_key_from_object(ob); - return (ob && !ob->id.lib && data && !data->lib && ob->mode != OB_MODE_EDIT && key && key->totkey); -} + return (ob && !ob->id.lib && data && !data->lib && ob->mode != OB_MODE_EDIT && key && key->totkey > 1); +} static EnumPropertyItem slot_move[] = { { -2, "TOP", 0, "Top of the list", "" }, @@ -510,17 +510,15 @@ static int shape_key_move_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); - int type = RNA_enum_get(op->ptr, "type"); - int act_index = ob->shapenr - 1; - int new_index = act_index; Key *key = BKE_key_from_object(ob); KeyBlock *kb = BKE_keyblock_from_object(ob); + const int type = RNA_enum_get(op->ptr, "type"); + const int totkey = key->totkey; + const int act_index = ob->shapenr - 1; + int new_index; - if (type >= -1 && type <= 1) { - new_index = act_index + type; - } - else if (type == 2) { - new_index = key->totkey - 1; + if (type == 2) { + new_index = totkey - 1; } else if (type == -2) { if (act_index == 1 || act_index == 0) @@ -528,6 +526,9 @@ static int shape_key_move_exec(bContext *C, wmOperator *op) else new_index = 1; } + else { + new_index = (totkey + act_index + type) % totkey; + } BKE_keyblock_move(ob, kb, new_index); diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index 6e59f9f4aea..e2ebe583ecf 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -385,7 +385,7 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l /* first check if we can execute */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { - if (ELEM6(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF)) { + if (ELEM(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF)) { ID *obdata = ob->data; if (ID_REAL_USERS(obdata) > 1) { BKE_reportf(reports, RPT_ERROR, @@ -784,7 +784,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) } if (ctx_ob_act) { - BLI_rotatelist_first(&ctx_data_list, (LinkData *)ctx_ob_act); + BLI_listbase_rotate_first(&ctx_data_list, (LinkData *)ctx_ob_act); } for (tob = bmain->object.first; tob; tob = tob->id.next) { diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c index 94d8d78de1a..8a034fdd8b5 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.c @@ -45,6 +45,7 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_depsgraph.h" #include "BKE_DerivedMesh.h" #include "BKE_icons.h" #include "BKE_main.h" @@ -165,6 +166,7 @@ void ED_render_engine_changed(Main *bmain) bScreen *sc; ScrArea *sa; Scene *scene; + Material *ma; for (sc = bmain->screen.first; sc; sc = sc->id.next) for (sa = sc->areabase.first; sa; sa = sa->next) @@ -174,6 +176,14 @@ void ED_render_engine_changed(Main *bmain) for (scene = bmain->scene.first; scene; scene = scene->id.next) ED_render_id_flush_update(bmain, &scene->id); + + /* reset texture painting */ + for (ma = bmain->mat.first; ma; ma = ma->id.next) { + if (ma->texpaintslot) { + BKE_texpaint_slots_clear(ma); + DAG_id_tag_update(&ma->id, 0); + } + } } /***************************** Updates *********************************** diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index d1375b1b8ab..11e7174ea98 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -931,11 +931,11 @@ static bool region_is_overlap(wmWindow *win, ScrArea *sa, ARegion *ar) if (U.uiflag2 & USER_REGION_OVERLAP) { if (WM_is_draw_triple(win)) { if (ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_SEQ)) { - if (ELEM3(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS)) + if (ELEM(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS)) return 1; } else if (sa->spacetype == SPACE_IMAGE) { - if (ELEM4(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS, RGN_TYPE_PREVIEW)) + if (ELEM(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS, RGN_TYPE_PREVIEW)) return 1; } } diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index f76f76aacaa..5beab9fcc14 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -378,7 +378,7 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge) if (split == 0) return NULL; /* note regarding (fac > 0.5f) checks below. - * notmally it shouldn't matter which is used since the copy should match the original + * normally it shouldn't matter which is used since the copy should match the original * however with viewport rendering and python console this isn't the case. - campbell */ if (dir == 'h') { diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 2ddda19fb28..7c7574b3af3 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -201,7 +201,7 @@ int ED_operator_animview_active(bContext *C) { if (ED_operator_areaactive(C)) { SpaceLink *sl = (SpaceLink *)CTX_wm_space_data(C); - if (sl && (ELEM5(sl->spacetype, SPACE_SEQ, SPACE_ACTION, SPACE_NLA, SPACE_IPO, SPACE_TIME))) + if (sl && (ELEM(sl->spacetype, SPACE_SEQ, SPACE_ACTION, SPACE_NLA, SPACE_IPO, SPACE_TIME))) return true; } @@ -3220,6 +3220,16 @@ static int match_region_with_redraws(int spacetype, int regiontype, int redraws) } } + else if (regiontype == RGN_TYPE_CHANNELS) { + switch (spacetype) { + case SPACE_IPO: + case SPACE_ACTION: + case SPACE_NLA: + if (redraws & TIME_ALL_ANIM_WIN) + return 1; + break; + } + } else if (regiontype == RGN_TYPE_UI) { if (spacetype == SPACE_CLIP) { /* Track Preview button is on Properties Editor in SpaceClip, @@ -4154,7 +4164,8 @@ void ED_keymap_screen(wmKeyConfig *keyconf) /* dropbox for entire window */ lb = WM_dropboxmap_find("Window", 0, 0); WM_dropbox_add(lb, "WM_OT_open_mainfile", open_file_drop_poll, open_file_drop_copy); - + WM_dropbox_add(lb, "UI_OT_drop_color", UI_drop_color_poll, UI_drop_color_copy); + keymap_modal_set(keyconf); } diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index 79ce4f879b7..18db57c9f21 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -40,6 +40,7 @@ set(INC_SYS set(SRC paint_cursor.c + paint_curve.c paint_hide.c paint_image.c paint_image_2d.c diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index b1e4696cd02..7b9ede38b39 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -44,6 +44,7 @@ #include "BKE_brush.h" #include "BKE_context.h" +#include "BKE_curve.h" #include "BKE_image.h" #include "BKE_node.h" #include "BKE_paint.h" @@ -58,6 +59,8 @@ #include "ED_view3d.h" +#include "UI_resources.h" + #include "paint_intern.h" /* still needed for sculpt_stroke_get_location, should be * removed eventually (TODO) */ @@ -756,7 +759,7 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush, ViewContext *vc, int x, int y, float zoom, PaintMode mode) { /* color means that primary brush texture is colured and secondary is used for alpha/mask control */ - bool col = ELEM3(mode, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D, PAINT_VERTEX) ? true : false; + bool col = ELEM(mode, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D, PAINT_VERTEX) ? true : false; OverlayControlFlags flags = BKE_paint_get_overlay_flags(); /* save lots of GL state * TODO: check on whether all of these are needed? */ @@ -791,6 +794,138 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush, glPopAttrib(); } + +BLI_INLINE void draw_tri_point(float *co, float width, bool selected) +{ + float w = width / 2.0f; + if (selected) + UI_ThemeColor4(TH_VERTEX_SELECT); + else + UI_ThemeColor4(TH_PAINT_CURVE_PIVOT); + + glLineWidth(3.0); + + glBegin(GL_LINE_LOOP); + glVertex2f(co[0], co[1] + w); + glVertex2f(co[0] - w, co[1] - w); + glVertex2f(co[0] + w, co[1] - w); + glEnd(); + + glColor4f(1.0, 1.0, 1.0, 0.5); + glLineWidth(1.0); + + glBegin(GL_LINE_LOOP); + glVertex2f(co[0], co[1] + w); + glVertex2f(co[0] - w, co[1] - w); + glVertex2f(co[0] + w, co[1] - w); + glEnd(); +} + +BLI_INLINE void draw_rect_point(float *co, float width, bool selected) +{ + float w = width / 2.0f; + if (selected) + UI_ThemeColor4(TH_VERTEX_SELECT); + else + UI_ThemeColor4(TH_PAINT_CURVE_HANDLE); + glLineWidth(3.0); + + glBegin(GL_LINE_LOOP); + glVertex2f(co[0] + w, co[1] + w); + glVertex2f(co[0] - w, co[1] + w); + glVertex2f(co[0] - w, co[1] - w); + glVertex2f(co[0] + w, co[1] - w); + glEnd(); + + glColor4f(1.0, 1.0, 1.0, 0.5); + glLineWidth(1.0); + + glBegin(GL_LINE_LOOP); + glVertex2f(co[0] + w, co[1] + w); + glVertex2f(co[0] - w, co[1] + w); + glVertex2f(co[0] - w, co[1] - w); + glVertex2f(co[0] + w, co[1] - w); + glEnd(); +} + + +BLI_INLINE void draw_bezier_handle_lines(BezTriple *bez) +{ + short line1[] = {0, 1}; + short line2[] = {1, 2}; + + glVertexPointer(2, GL_FLOAT, 3 * sizeof(float), bez->vec); + glColor4f(0.0, 0.0, 0.0, 0.5); + glLineWidth(3.0); + glDrawArrays(GL_LINE_STRIP, 0, 3); + + glLineWidth(1.0); + if (bez->f1 || bez->f2) + UI_ThemeColor4(TH_VERTEX_SELECT); + else + glColor4f(1.0, 1.0, 1.0, 0.5); + glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, line1); + if (bez->f3 || bez->f2) + UI_ThemeColor4(TH_VERTEX_SELECT); + else + glColor4f(1.0, 1.0, 1.0, 0.5); + glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, line2); +} + +static void paint_draw_curve_cursor(Brush *brush) +{ + if (brush->paint_curve && brush->paint_curve->points) { + int i; + PaintCurve *pc = brush->paint_curve; + PaintCurvePoint *cp = pc->points; + + glEnable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); + glEnableClientState(GL_VERTEX_ARRAY); + + /* draw the bezier handles and the curve segment between the current and next point */ + for (i = 0; i < pc->tot_points - 1; i++, cp++) { + int j; + PaintCurvePoint *cp_next = cp + 1; + float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2]; + /* use color coding to distinguish handles vs curve segments */ + draw_bezier_handle_lines(&cp->bez); + draw_tri_point(&cp->bez.vec[1][0], 10.0, cp->bez.f2); + draw_rect_point(&cp->bez.vec[0][0], 8.0, cp->bez.f1 || cp->bez.f2); + draw_rect_point(&cp->bez.vec[2][0], 8.0, cp->bez.f3 || cp->bez.f2); + + for (j = 0; j < 2; j++) + BKE_curve_forward_diff_bezier( + cp->bez.vec[1][j], + cp->bez.vec[2][j], + cp_next->bez.vec[0][j], + cp_next->bez.vec[1][j], + data + j, PAINT_CURVE_NUM_SEGMENTS, sizeof(float[2])); + + glVertexPointer(2, GL_FLOAT, 0, data); + glLineWidth(3.0); + glColor4f(0.0, 0.0, 0.0, 0.5); + glDrawArrays(GL_LINE_STRIP, 0, PAINT_CURVE_NUM_SEGMENTS + 1); + + glLineWidth(1.0); + glColor4f(0.9, 0.9, 1.0, 0.5); + glDrawArrays(GL_LINE_STRIP, 0, PAINT_CURVE_NUM_SEGMENTS + 1); + } + + /* draw last line segment */ + draw_bezier_handle_lines(&cp->bez); + draw_tri_point(&cp->bez.vec[1][0], 10.0, cp->bez.f2); + draw_rect_point(&cp->bez.vec[0][0], 8.0, cp->bez.f1 || cp->bez.f2); + draw_rect_point(&cp->bez.vec[2][0], 8.0, cp->bez.f3 || cp->bez.f2); + + glLineWidth(1.0); + + glDisable(GL_BLEND); + glDisable(GL_LINE_SMOOTH); + glDisableClientState(GL_VERTEX_ARRAY); + } +} + /* Special actions taken when paint cursor goes over mesh */ /* TODO: sculpt only for now */ static void paint_cursor_on_hit(UnifiedPaintSettings *ups, Brush *brush, ViewContext *vc, @@ -848,6 +983,12 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) zoomx = max_ff(zoomx, zoomy); mode = BKE_paintmode_get_active_from_context(C); + /* skip everything and draw brush here */ + if (brush->flag & BRUSH_CURVE) { + paint_draw_curve_cursor(brush); + return; + } + /* set various defaults */ translation[0] = x; translation[1] = y; @@ -857,8 +998,11 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) /* don't calculate rake angles while a stroke is active because the rake variables are global and * we may get interference with the stroke itself. For line strokes, such interference is visible */ - if (!ups->stroke_active && (brush->flag & BRUSH_RAKE)) - paint_calculate_rake_rotation(ups, translation); + if (!ups->stroke_active) { + if (brush->flag & BRUSH_RAKE) + /* here, translation contains the mouse coordinates. */ + paint_calculate_rake_rotation(ups, translation); + } /* draw overlay */ paint_draw_alpha_overlay(ups, brush, &vc, x, y, zoomx, mode); @@ -878,9 +1022,9 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) /* check if brush is subtracting, use different color then */ /* TODO: no way currently to know state of pen flip or * invert key modifier without starting a stroke */ - if ((!(brush->flag & BRUSH_INVERTED) ^ + if ((!(ups->draw_inverted) ^ !(brush->flag & BRUSH_DIR_IN)) && - ELEM5(brush->sculpt_tool, SCULPT_TOOL_DRAW, + ELEM(brush->sculpt_tool, SCULPT_TOOL_DRAW, SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY, SCULPT_TOOL_PINCH, SCULPT_TOOL_CREASE)) { @@ -890,12 +1034,12 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) /* only do if brush is over the mesh */ if (hit) paint_cursor_on_hit(ups, brush, &vc, location); + } - if (ups->draw_anchored) { - final_radius = ups->anchored_size; - translation[0] = ups->anchored_initial_mouse[0]; - translation[1] = ups->anchored_initial_mouse[1]; - } + if (ups->draw_anchored) { + final_radius = ups->anchored_size; + translation[0] = ups->anchored_initial_mouse[0]; + translation[1] = ups->anchored_initial_mouse[1]; } /* make lines pretty */ diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c new file mode 100644 index 00000000000..217c88c87ea --- /dev/null +++ b/source/blender/editors/sculpt_paint/paint_curve.c @@ -0,0 +1,801 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/sculpt_paint/paint_curve.c + * \ingroup edsculpt + */ + +#include <string.h> +#include <limits.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_brush_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_view3d_types.h" + +#include "BKE_context.h" +#include "BKE_main.h" +#include "BKE_paint.h" + +#include "BLI_math_vector.h" +#include "BLI_string.h" + +#include "ED_paint.h" +#include "ED_view3d.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "UI_view2d.h" + +#include "paint_intern.h" + +#define PAINT_CURVE_SELECT_THRESHOLD 40.0f +#define PAINT_CURVE_POINT_SELECT(pcp, i) (*(&pcp->bez.f1 + i) = SELECT) + + +int paint_curve_poll(bContext *C) +{ + Object *ob = CTX_data_active_object(C); + Paint *p; + RegionView3D *rv3d = CTX_wm_region_view3d(C); + SpaceImage *sima; + + if (rv3d && !(ob && ((ob->mode & OB_MODE_ALL_PAINT) != 0))) + return false; + + sima = CTX_wm_space_image(C); + + if (sima && sima->mode != SI_MODE_PAINT) + return false; + + p = BKE_paint_get_active_from_context(C); + + if (p && p->brush && (p->brush->flag & BRUSH_CURVE)) { + return true; + } + + return false; +} + +/* Paint Curve Undo*/ + +typedef struct UndoCurve { + struct UndoImageTile *next, *prev; + + PaintCurvePoint *points; /* points of curve */ + int tot_points; + int active_point; + + char idname[MAX_ID_NAME]; /* name instead of pointer*/ +} UndoCurve; + +static void paintcurve_undo_restore(bContext *C, ListBase *lb) +{ + Paint *p = BKE_paint_get_active_from_context(C); + UndoCurve *uc; + PaintCurve *pc = NULL; + + if (p->brush) { + pc = p->brush->paint_curve; + } + + if (!pc) + return; + + uc = (UndoCurve *)lb->first; + + if (strncmp(uc->idname, pc->id.name, BLI_strnlen(uc->idname, sizeof(uc->idname))) == 0) { + SWAP(PaintCurvePoint *, pc->points, uc->points); + SWAP(int, pc->tot_points, uc->tot_points); + SWAP(int, pc->add_index, uc->active_point); + } +} + +static void paintcurve_undo_delete(ListBase *lb) +{ + UndoCurve *uc; + uc = (UndoCurve *)lb->first; + + if (uc->points) + MEM_freeN(uc->points); + uc->points = NULL; +} + + +static void paintcurve_undo_begin(bContext *C, wmOperator *op, PaintCurve *pc) +{ + PaintMode mode = BKE_paintmode_get_active_from_context(C); + ListBase *lb = NULL; + int undo_stack_id; + UndoCurve *uc; + + switch (mode) { + case PAINT_TEXTURE_2D: + case PAINT_TEXTURE_PROJECTIVE: + undo_stack_id = UNDO_PAINT_IMAGE; + break; + + case PAINT_SCULPT: + undo_stack_id = UNDO_PAINT_MESH; + break; + + default: + /* do nothing, undo is handled by global */ + return; + } + + + ED_undo_paint_push_begin(undo_stack_id, op->type->name, + paintcurve_undo_restore, paintcurve_undo_delete, NULL); + lb = undo_paint_push_get_list(undo_stack_id); + + uc = MEM_callocN(sizeof(*uc), "Undo_curve"); + + lb->first = uc; + + BLI_strncpy(uc->idname, pc->id.name, sizeof(uc->idname)); + uc->tot_points = pc->tot_points; + uc->active_point = pc->add_index; + uc->points = MEM_dupallocN(pc->points); + + undo_paint_push_count_alloc(undo_stack_id, sizeof(*uc) + sizeof(*pc->points) * pc->tot_points); + + ED_undo_paint_push_end(undo_stack_id); +} +#define SEL_F1 (1 << 0) +#define SEL_F2 (1 << 1) +#define SEL_F3 (1 << 2) + +/* returns 0, 1, or 2 in point according to handle 1, pivot or handle 2 */ +static PaintCurvePoint *paintcurve_point_get_closest(PaintCurve *pc, const float pos[2], bool ignore_pivot, const float threshold, char *point) +{ + PaintCurvePoint *pcp, *closest = NULL; + int i; + float dist, closest_dist = FLT_MAX; + + for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) { + dist = len_manhattan_v2v2(pos, pcp->bez.vec[0]); + if (dist < threshold) { + if (dist < closest_dist) { + closest = pcp; + closest_dist = dist; + if (point) + *point = SEL_F1; + } + } + if (!ignore_pivot) { + dist = len_manhattan_v2v2(pos, pcp->bez.vec[1]); + if (dist < threshold) { + if (dist < closest_dist) { + closest = pcp; + closest_dist = dist; + if (point) + *point = SEL_F2; + } + } + } + dist = len_manhattan_v2v2(pos, pcp->bez.vec[2]); + if (dist < threshold) { + if (dist < closest_dist) { + closest = pcp; + closest_dist = dist; + if (point) + *point = SEL_F3; + } + } + } + + return closest; +} + +static int paintcurve_point_co_index(char sel) +{ + char i = 0; + while (sel != 1) { + sel >>= 1; + i++; + } + return i; +} + +/******************* Operators *********************************/ + +static int paintcurve_new_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Paint *p = BKE_paint_get_active_from_context(C); + Main *bmain = CTX_data_main(C); + + if (p && p->brush) { + p->brush->paint_curve = BKE_paint_curve_add(bmain, "PaintCurve"); + } + + return OPERATOR_FINISHED; +} + +void PAINTCURVE_OT_new(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add New Paint Curve"; + ot->description = "Add new paint curve"; + ot->idname = "PAINTCURVE_OT_new"; + + /* api callbacks */ + ot->exec = paintcurve_new_exec; + ot->poll = paint_curve_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static void paintcurve_point_add(bContext *C, wmOperator *op, const int loc[2]) +{ + Paint *p = BKE_paint_get_active_from_context(C); + Brush *br = p->brush; + Main *bmain = CTX_data_main(C); + PaintCurve *pc; + PaintCurvePoint *pcp; + wmWindow *window = CTX_wm_window(C); + ARegion *ar = CTX_wm_region(C); + float vec[3] = {loc[0], loc[1], 0.0}; + int add_index; + int i; + + pc = br->paint_curve; + if (!pc) { + br->paint_curve = pc = BKE_paint_curve_add(bmain, "PaintCurve"); + } + + paintcurve_undo_begin(C, op, pc); + + pcp = MEM_mallocN((pc->tot_points + 1) * sizeof(PaintCurvePoint), "PaintCurvePoint"); + add_index = pc->add_index; + + if (pc->points) { + if (add_index > 0) + memcpy(pcp, pc->points, add_index * sizeof(PaintCurvePoint)); + if (add_index < pc->tot_points) + memcpy(pcp + add_index + 1, pc->points + add_index, (pc->tot_points - add_index) * sizeof(PaintCurvePoint)); + + MEM_freeN(pc->points); + } + pc->points = pcp; + pc->tot_points++; + + /* initialize new point */ + memset(&pcp[add_index], 0, sizeof(PaintCurvePoint)); + copy_v3_v3(pcp[add_index].bez.vec[0], vec); + copy_v3_v3(pcp[add_index].bez.vec[1], vec); + copy_v3_v3(pcp[add_index].bez.vec[2], vec); + + /* last step, clear selection from all bezier handles expect the next */ + for (i = 0; i < pc->tot_points; i++) { + pcp[i].bez.f1 = pcp[i].bez.f2 = pcp[i].bez.f3 = 0; + } + pcp[add_index].bez.f3 = SELECT; + pcp[add_index].bez.h2 = HD_ALIGN; + + pc->add_index = add_index + 1; + + WM_paint_cursor_tag_redraw(window, ar); +} + + +static int paintcurve_add_point_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + int loc[2] = {event->mval[0], event->mval[1]}; + paintcurve_point_add(C, op, loc); + RNA_int_set_array(op->ptr, "location", loc); + return OPERATOR_FINISHED; +} + +static int paintcurve_add_point_exec(bContext *C, wmOperator *op) +{ + int loc[2]; + + if (RNA_struct_property_is_set(op->ptr, "location")) { + RNA_int_get_array(op->ptr, "location", loc); + paintcurve_point_add(C, op, loc); + return OPERATOR_FINISHED; + } + + return OPERATOR_CANCELLED; +} + +void PAINTCURVE_OT_add_point(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add New Paint Curve Point"; + ot->description = "Add new paint curve point"; + ot->idname = "PAINTCURVE_OT_add_point"; + + /* api callbacks */ + ot->invoke = paintcurve_add_point_invoke; + ot->exec = paintcurve_add_point_exec; + ot->poll = paint_curve_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER; + + /* properties */ + RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, SHRT_MAX, + "Location", "Location of vertex in area space", 0, SHRT_MAX); +} + +static int paintcurve_delete_point_exec(bContext *C, wmOperator *op) +{ + Paint *p = BKE_paint_get_active_from_context(C); + Brush *br = p->brush; + PaintCurve *pc; + PaintCurvePoint *pcp; + wmWindow *window = CTX_wm_window(C); + ARegion *ar = CTX_wm_region(C); + int i; + int tot_del = 0; + pc = br->paint_curve; + + if (!pc || pc->tot_points == 0) { + return OPERATOR_CANCELLED; + } + + paintcurve_undo_begin(C, op, pc); + +#define DELETE_TAG 2 + + for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) { + if ((pcp->bez.f1 & SELECT) || (pcp->bez.f2 & SELECT) || (pcp->bez.f3 & SELECT)) { + pcp->bez.f2 |= DELETE_TAG; + tot_del++; + } + } + + if (tot_del > 0) { + int j = 0; + int new_tot = pc->tot_points - tot_del; + PaintCurvePoint *points_new = NULL; + if (new_tot > 0) + points_new = MEM_mallocN(new_tot * sizeof(PaintCurvePoint), "PaintCurvePoint"); + + for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) { + if (!(pcp->bez.f2 & DELETE_TAG)) { + points_new[j] = pc->points[i]; + + if ((i + 1) == pc->add_index) { + pc->add_index = j + 1; + } + j++; + } + else if ((i + 1) == pc->add_index) { + /* prefer previous point */ + pc->add_index = j; + } + } + MEM_freeN(pc->points); + + pc->points = points_new; + pc->tot_points = new_tot; + } + +#undef DELETE_TAG + + WM_paint_cursor_tag_redraw(window, ar); + + return OPERATOR_FINISHED; +} + + +void PAINTCURVE_OT_delete_point(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add New Paint Curve Point"; + ot->description = "Add new paint curve point"; + ot->idname = "PAINTCURVE_OT_delete_point"; + + /* api callbacks */ + ot->exec = paintcurve_delete_point_exec; + ot->poll = paint_curve_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; +} + + +static bool paintcurve_point_select(bContext *C, wmOperator *op, const int loc[2], bool toggle, bool extend) +{ + wmWindow *window = CTX_wm_window(C); + ARegion *ar = CTX_wm_region(C); + Paint *p = BKE_paint_get_active_from_context(C); + Brush *br = p->brush; + PaintCurve *pc; + PaintCurvePoint *pcp; + int i; + const float loc_fl[2] = {UNPACK2(loc)}; + + pc = br->paint_curve; + + if (!pc) + return false; + + paintcurve_undo_begin(C, op, pc); + + pcp = pc->points; + + if (toggle) { + char select = 0; + bool selected = false; + + for (i = 0; i < pc->tot_points; i++) { + if (pcp[i].bez.f1 || pcp[i].bez.f2 || pcp[i].bez.f3) { + selected = true; + break; + } + } + + if (!selected) { + select = SELECT; + } + + for (i = 0; i < pc->tot_points; i++) { + pc->points[i].bez.f1 = pc->points[i].bez.f2 = pc->points[i].bez.f3 = select; + } + } + else { + PaintCurvePoint *pcp; + char selflag; + + pcp = paintcurve_point_get_closest(pc, loc_fl, false, PAINT_CURVE_SELECT_THRESHOLD, &selflag); + + if (pcp) { + pc->add_index = (pcp - pc->points) + 1; + + if (selflag == SEL_F2) { + if (extend) + pcp->bez.f2 ^= SELECT; + else + pcp->bez.f2 |= SELECT; + } + else if (selflag == SEL_F1) { + if (extend) + pcp->bez.f1 ^= SELECT; + else + pcp->bez.f1 |= SELECT; + } + else if (selflag == SEL_F3) { + if (extend) + pcp->bez.f3 ^= SELECT; + else + pcp->bez.f3 |= SELECT; + } + } + + /* clear selection for unselected points if not extending and if a point has been selected */ + if (!extend && pcp) { + for (i = 0; i < pc->tot_points; i++) { + pc->points[i].bez.f1 = pc->points[i].bez.f2 = pc->points[i].bez.f3 = 0; + + if ((pc->points + i) == pcp) { + char index = paintcurve_point_co_index(selflag); + PAINT_CURVE_POINT_SELECT(pcp, index); + } + } + } + + if (!pcp) + return false; + } + + WM_paint_cursor_tag_redraw(window, ar); + + return true; +} + + +static int paintcurve_select_point_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + int loc[2] = {UNPACK2(event->mval)}; + bool toggle = RNA_boolean_get(op->ptr, "toggle"); + bool extend = RNA_boolean_get(op->ptr, "extend"); + if (paintcurve_point_select(C, op, loc, toggle, extend)) { + RNA_int_set_array(op->ptr, "location", loc); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +static int paintcurve_select_point_exec(bContext *C, wmOperator *op) +{ + int loc[2]; + + if (RNA_struct_property_is_set(op->ptr, "location")) { + bool toggle = RNA_boolean_get(op->ptr, "toggle"); + bool extend = RNA_boolean_get(op->ptr, "extend"); + RNA_int_get_array(op->ptr, "location", loc); + if (paintcurve_point_select(C, op, loc, toggle, extend)) + return OPERATOR_FINISHED; + } + + return OPERATOR_CANCELLED; +} + +void PAINTCURVE_OT_select(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Select Paint Curve Point"; + ot->description = "Select a paint curve point"; + ot->idname = "PAINTCURVE_OT_select"; + + /* api callbacks */ + ot->invoke = paintcurve_select_point_invoke; + ot->exec = paintcurve_select_point_exec; + ot->poll = paint_curve_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER; + + /* properties */ + RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, SHRT_MAX, + "Location", "Location of vertex in area space", 0, SHRT_MAX); + prop = RNA_def_boolean(ot->srna, "toggle", false, "Toggle", "(De)select all"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); +} + +typedef struct PointSlideData { + PaintCurvePoint *pcp; + char select; + int initial_loc[2]; + float point_initial_loc[3][2]; + int event; + bool align; +} PointSlideData; + +static int paintcurve_slide_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + Paint *p = BKE_paint_get_active_from_context(C); + const float loc_fl[2] = {UNPACK2(event->mval)}; + char select; + int i; + bool do_select = RNA_boolean_get(op->ptr, "select"); + bool align = RNA_boolean_get(op->ptr, "align"); + Brush *br = p->brush; + PaintCurve *pc = br->paint_curve; + PaintCurvePoint *pcp; + + if (!pc) + return OPERATOR_PASS_THROUGH; + + if (do_select) { + pcp = paintcurve_point_get_closest(pc, loc_fl, align, PAINT_CURVE_SELECT_THRESHOLD, &select); + } + else { + pcp = NULL; + /* just find first selected point */ + for (i = 0; i < pc->tot_points; i++) { + if (pc->points[i].bez.f1 || pc->points[i].bez.f2 || pc->points[i].bez.f3) { + pcp = &pc->points[i]; + select = SEL_F3; + break; + } + } + } + + + if (pcp) { + ARegion *ar = CTX_wm_region(C); + wmWindow *window = CTX_wm_window(C); + PointSlideData *psd = MEM_mallocN(sizeof(PointSlideData), "PointSlideData"); + copy_v2_v2_int(psd->initial_loc, event->mval); + psd->event = event->type; + psd->pcp = pcp; + psd->select = paintcurve_point_co_index(select); + for (i = 0; i < 3; i++) { + copy_v2_v2(psd->point_initial_loc[i], pcp->bez.vec[i]); + } + psd->align = align; + op->customdata = psd; + + if (do_select) + paintcurve_undo_begin(C, op, pc); + + /* first, clear all selection from points */ + for (i = 0; i < pc->tot_points; i++) + pc->points[i].bez.f1 = pc->points[i].bez.f3 = pc->points[i].bez.f2 = 0; + + /* only select the active point */ + PAINT_CURVE_POINT_SELECT(pcp, psd->select); + pc->add_index = (pcp - pc->points) + 1; + + WM_event_add_modal_handler(C, op); + WM_paint_cursor_tag_redraw(window, ar); + return OPERATOR_RUNNING_MODAL; + } + + return OPERATOR_PASS_THROUGH; +} + +static int paintcurve_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + PointSlideData *psd = op->customdata; + + if (event->type == psd->event && event->val == KM_RELEASE) { + MEM_freeN(psd); + return OPERATOR_FINISHED; + } + + switch (event->type) { + case MOUSEMOVE: + { + ARegion *ar = CTX_wm_region(C); + wmWindow *window = CTX_wm_window(C); + float diff[2] = {event->mval[0] - psd->initial_loc[0], + event->mval[1] - psd->initial_loc[1]}; + if (psd->select == 1) { + int i; + for (i = 0; i < 3; i++) + add_v2_v2v2(psd->pcp->bez.vec[i], diff, psd->point_initial_loc[i]); + } + else { + add_v2_v2(diff, psd->point_initial_loc[psd->select]); + copy_v2_v2(psd->pcp->bez.vec[psd->select], diff); + + if (psd->align) { + char opposite = (psd->select == 0) ? 2 : 0; + sub_v2_v2v2(diff, psd->pcp->bez.vec[1], psd->pcp->bez.vec[psd->select]); + add_v2_v2v2(psd->pcp->bez.vec[opposite], psd->pcp->bez.vec[1], diff); + } + } + WM_paint_cursor_tag_redraw(window, ar); + break; + } + default: + break; + } + + return OPERATOR_RUNNING_MODAL; +} + + +void PAINTCURVE_OT_slide(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Slide Paint Curve Point"; + ot->description = "Select and slide paint curve point"; + ot->idname = "PAINTCURVE_OT_slide"; + + /* api callbacks */ + ot->invoke = paintcurve_slide_invoke; + ot->modal = paintcurve_slide_modal; + ot->poll = paint_curve_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "align", false, "Align Handles", "Aligns opposite point handle during transform"); + RNA_def_boolean(ot->srna, "select", true, "Select", "Attempt to select a point handle before transform"); +} + +static int paintcurve_draw_exec(bContext *C, wmOperator *UNUSED(op)) +{ + PaintMode mode = BKE_paintmode_get_active_from_context(C); + const char *name; + + switch (mode) { + case PAINT_TEXTURE_2D: + case PAINT_TEXTURE_PROJECTIVE: + name = "PAINT_OT_image_paint"; + break; + case PAINT_WEIGHT: + name = "PAINT_OT_weight_paint"; + break; + case PAINT_VERTEX: + name = "PAINT_OT_vertex_paint"; + break; + case PAINT_SCULPT: + name = "SCULPT_OT_brush_stroke"; + break; + default: + return OPERATOR_PASS_THROUGH; + } + + return WM_operator_name_call(C, name, WM_OP_INVOKE_DEFAULT, NULL); +} + +void PAINTCURVE_OT_draw(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Draw Curve"; + ot->description = "Draw curve"; + ot->idname = "PAINTCURVE_OT_draw"; + + /* api callbacks */ + ot->exec = paintcurve_draw_exec; + ot->poll = paint_curve_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO; +} + +static int paintcurve_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + op->customdata = SET_INT_IN_POINTER(event->type); + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; +} + +static int paintcurve_cursor_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + if (event->type == GET_INT_FROM_POINTER(op->customdata) && event->val == KM_RELEASE) + return OPERATOR_FINISHED; + + if (event->type == MOUSEMOVE) { + PaintMode mode = BKE_paintmode_get_active_from_context(C); + + switch (mode) { + case PAINT_TEXTURE_2D: + { + ARegion *ar = CTX_wm_region(C); + SpaceImage *sima = CTX_wm_space_image(C); + float location[2]; + + if (!sima) + return OPERATOR_CANCELLED; + + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]); + copy_v2_v2(sima->cursor, location); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL); + break; + } + default: + ED_view3d_cursor3d_update(C, event->mval); + break; + } + } + + return OPERATOR_RUNNING_MODAL; +} + +void PAINTCURVE_OT_cursor(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Place Cursor"; + ot->description = "Place cursor"; + ot->idname = "PAINTCURVE_OT_cursor"; + + /* api callbacks */ + ot->invoke = paintcurve_cursor_invoke; + ot->modal = paintcurve_cursor_modal; + ot->poll = paint_curve_poll; + + /* flags */ + ot->flag = 0; +} diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 34232c51ff7..f1a2a8156d8 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -43,6 +43,7 @@ #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_threads.h" #include "PIL_time.h" @@ -59,15 +60,21 @@ #include "BKE_brush.h" #include "BKE_image.h" #include "BKE_main.h" +#include "BKE_material.h" #include "BKE_mesh.h" #include "BKE_node.h" #include "BKE_paint.h" +#include "BKE_report.h" +#include "BKE_scene.h" +#include "BKE_texture.h" +#include "BKE_colortools.h" #include "BKE_editmesh.h" #include "UI_view2d.h" #include "ED_image.h" +#include "ED_mesh.h" #include "ED_object.h" #include "ED_paint.h" #include "ED_screen.h" @@ -82,6 +89,9 @@ #include "GPU_draw.h" +#include "BIF_gl.h" +#include "BIF_glutil.h" + #include "IMB_colormanagement.h" #include "paint_intern.h" @@ -102,14 +112,27 @@ typedef struct UndoImageTile { int x, y; + Image *ima; short source, use_float; char gen_type; + bool valid; } UndoImageTile; /* this is a static resource for non-globality, * Maybe it should be exposed as part of the * paint operation, but for now just give a public interface */ static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0}; +static SpinLock undolock; + +void image_undo_init_locks(void) +{ + BLI_spin_init(&undolock); +} + +void image_undo_end_locks(void) +{ + BLI_spin_end(&undolock); +} ImagePaintPartialRedraw *get_imapaintpartial(void) { @@ -122,26 +145,53 @@ void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr) } /* UNDO */ +typedef enum { + COPY = 0, + RESTORE = 1, + RESTORE_COPY = 2 +} CopyMode; -static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int restore) +static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, CopyMode mode) { - /* copy or swap contents of tile->rect and region in ibuf->rect */ - IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE, - tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE); + if (mode == COPY) { + /* copy or swap contents of tile->rect and region in ibuf->rect */ + IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE, + tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE); - if (ibuf->rect_float) { - SWAP(float *, tmpibuf->rect_float, tile->rect.fp); + if (ibuf->rect_float) { + SWAP(float *, tmpibuf->rect_float, tile->rect.fp); + } + else { + SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint); + } } else { - SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint); - } - - if (restore) + if (mode == RESTORE_COPY) + IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE, + tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE); + /* swap to the tmpbuf for easy copying */ + if (ibuf->rect_float) { + SWAP(float *, tmpibuf->rect_float, tile->rect.fp); + } + else { + SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint); + } + IMB_rectcpy(ibuf, tmpibuf, tile->x * IMAPAINT_TILE_SIZE, tile->y * IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE); + + if (mode == RESTORE) { + if (ibuf->rect_float) { + SWAP(float *, tmpibuf->rect_float, tile->rect.fp); + } + else { + SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint); + } + } + } } -void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask) +void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate) { ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); UndoImageTile *tile; @@ -160,6 +210,8 @@ void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsi *mask = tile->mask; } + if (validate) + tile->valid = true; return tile->rect.pt; } @@ -170,7 +222,7 @@ void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsi return NULL; } -void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile) +void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **mask, bool **valid, bool proj) { ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); UndoImageTile *tile; @@ -179,10 +231,14 @@ void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, void *data; /* check if tile is already pushed */ - data = image_undo_find_tile(ima, ibuf, x_tile, y_tile, NULL); - if (data) - return data; - + + /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */ + if (!proj) { + data = image_undo_find_tile(ima, ibuf, x_tile, y_tile, mask, true); + if (data) + return data; + } + if (*tmpibuf == NULL) *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect); @@ -191,6 +247,11 @@ void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, tile->x = x_tile; tile->y = y_tile; + /* add mask explicitly here */ + if (mask) + *mask = tile->mask = MEM_callocN(sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE, + "UndoImageTile.mask"); + allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4; allocsize *= (ibuf->rect_float) ? sizeof(float) : sizeof(char); tile->rect.pt = MEM_mapallocN(allocsize, "UndeImageTile.rect"); @@ -200,12 +261,23 @@ void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, tile->gen_type = ima->gen_type; tile->source = ima->source; tile->use_float = use_float; + tile->valid = true; + tile->ima = ima; - undo_copy_tile(tile, *tmpibuf, ibuf, 0); - undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize); + if (valid) + *valid = &tile->valid; + + undo_copy_tile(tile, *tmpibuf, ibuf, COPY); + + if (proj) + BLI_spin_lock(&undolock); + undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize); BLI_addtail(lb, tile); - + + if (proj) + BLI_spin_unlock(&undolock); + return tile->rect.pt; } @@ -222,6 +294,33 @@ void image_undo_remove_masks(void) } } +static void image_undo_restore_runtime(ListBase *lb) +{ + ImBuf *ibuf, *tmpibuf; + UndoImageTile *tile; + + tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, + IB_rectfloat | IB_rect); + + for (tile = lb->first; tile; tile = tile->next) { + Image *ima = tile->ima; + ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL); + + undo_copy_tile(tile, tmpibuf, ibuf, RESTORE); + + GPU_free_image(ima); /* force OpenGL reload (maybe partial update will operate better?) */ + if (ibuf->rect_float) + ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */ + if (ibuf->mipmap[0]) + ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */ + ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; + + BKE_image_release_ibuf(ima, ibuf, NULL); + } + + IMB_freeImBuf(tmpibuf); +} + void ED_image_undo_restore(bContext *C, ListBase *lb) { Main *bmain = CTX_data_main(C); @@ -273,7 +372,7 @@ void ED_image_undo_restore(bContext *C, ListBase *lb) continue; } - undo_copy_tile(tile, tmpibuf, ibuf, 1); + undo_copy_tile(tile, tmpibuf, ibuf, RESTORE_COPY); GPU_free_image(ima); /* force OpenGL reload */ if (ibuf->rect_float) @@ -282,6 +381,8 @@ void ED_image_undo_restore(bContext *C, ListBase *lb) ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; + DAG_id_tag_update(&ima->id, 0); + BKE_image_release_ibuf(ima, ibuf, NULL); } @@ -296,6 +397,42 @@ void ED_image_undo_free(ListBase *lb) MEM_freeN(tile->rect.pt); } +static void image_undo_end(void) +{ + ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); + UndoImageTile *tile; + int deallocsize = 0; + int allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4; + + /* first dispose of invalid tiles (may happen due to drag dot for instance) */ + for (tile = lb->first; tile;) { + if (!tile->valid) { + UndoImageTile *tmp_tile = tile->next; + deallocsize += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char)); + MEM_freeN(tile->rect.pt); + BLI_freelinkN (lb, tile); + tile = tmp_tile; + } + else { + tile = tile->next; + } + } + + /* don't forget to remove the size of deallocated tiles */ + undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, -deallocsize); + + ED_undo_paint_push_end(UNDO_PAINT_IMAGE); +} + +static void image_undo_invalidate(void) +{ + UndoImageTile *tile; + ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); + + for (tile = lb->first; tile; tile = tile->next) + tile->valid = false; +} + /* Imagepaint Partial Redraw & Dirty Region */ void ED_imapaint_clear_partial_redraw(void) @@ -344,7 +481,7 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int for (ty = tiley; ty <= tileh; ty++) for (tx = tilex; tx <= tilew; tx++) - image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty); + image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false); ibuf->userflags |= IB_BITMAPDIRTY; @@ -373,6 +510,70 @@ void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short te } } +/* paint blur kernels */ +BlurKernel *paint_new_blur_kernel(Brush *br) +{ + int i, j; + BlurKernel *kernel = MEM_mallocN(sizeof(BlurKernel), "blur kernel"); + int pixel_len = br->blur_kernel_radius; + BlurKernelType type = br->blur_mode; + + kernel->side = pixel_len * 2 + 1; + kernel->side_squared = kernel->side * kernel->side; + kernel->wdata = MEM_mallocN(sizeof(float) * kernel->side_squared, "blur kernel data"); + kernel->pixel_len = pixel_len; + + switch (type) { + case KERNEL_BOX: + for (i = 0; i < kernel->side_squared; i++) + kernel->wdata[i] = 1.0; + break; + + case KERNEL_GAUSSIAN: + { + float standard_dev = pixel_len / 3.0; /* at standard deviation of 3.0 kernel is at about zero */ + int i_term = pixel_len + 1; + + /* make the necessary adjustment to the value for use in the normal distribution formula */ + standard_dev = standard_dev * standard_dev * 2; + + kernel->wdata[pixel_len + pixel_len * kernel->side] = 1.0; + /* fill in all four quadrants at once */ + for (i = 0; i < i_term; i++) { + for (j = 0; j < pixel_len; j++) { + float idist = pixel_len - i; + float jdist = pixel_len - j; + + float value = exp((idist * idist + jdist * jdist) / standard_dev); + + kernel->wdata[i + j * kernel->side] = + kernel->wdata[(kernel->side - j - 1) + i * kernel->side] = + kernel->wdata[(kernel->side - i - 1) + (kernel->side - j - 1) * kernel->side] = + kernel->wdata[j + (kernel->side - i - 1) * kernel->side] = + value; + } + } + + break; + } + + default: + printf("unidentified kernel type, aborting\n"); + MEM_freeN(kernel->wdata); + MEM_freeN(kernel); + return NULL; + break; + } + + return kernel; +} + +void paint_delete_blur_kernel(BlurKernel *kernel) +{ + if (kernel->wdata) + MEM_freeN(kernel->wdata); +} + /************************ image paint poll ************************/ static Brush *image_paint_brush(bContext *C) @@ -432,11 +633,57 @@ typedef struct PaintOperation { void *custom_paint; float prevmouse[2]; + float startmouse[2]; double starttime; + void *cursor; ViewContext vc; } PaintOperation; +bool paint_use_opacity_masking(Brush *brush) +{ + return (brush->flag & BRUSH_AIRBRUSH) || + (brush->flag & BRUSH_DRAG_DOT) || + (brush->flag & BRUSH_ANCHORED) || + (brush->imagepaint_tool == PAINT_TOOL_SMEAR) || + (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) || + (brush->imagepaint_tool == PAINT_TOOL_FILL) || + (brush->flag & BRUSH_USE_GRADIENT) || + (brush->mtex.tex && !ELEM(brush->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_3D)) ? + false : true; +} + +void paint_brush_color_get(struct Scene *scene, struct Brush *br, bool color_correction, bool invert, float distance, + float pressure, float color[3], struct ColorManagedDisplay *display) +{ + if (invert) + copy_v3_v3(color, BKE_brush_secondary_color_get(scene, br)); + else { + if (br->flag & BRUSH_USE_GRADIENT) { + switch (br->gradient_stroke_mode) { + case BRUSH_GRADIENT_PRESSURE: + do_colorband(br->gradient, pressure, color); + break; + case BRUSH_GRADIENT_SPACING_REPEAT: + { + float coord = fmod(distance / br->gradient_spacing, 1.0); + do_colorband(br->gradient, coord, color); + break; + } + case BRUSH_GRADIENT_SPACING_CLAMP: + { + do_colorband(br->gradient, distance / br->gradient_spacing, color); + break; + } + } + } + else + copy_v3_v3(color, BKE_brush_color_get(scene, br)); + } + if (color_correction) + IMB_colormanagement_display_to_scene_linear_v3(color, display); +} + void paint_brush_init_tex(Brush *brush) { /* init mtex nodes */ @@ -462,26 +709,54 @@ void paint_brush_exit_tex(Brush *brush) } } +static void gradient_draw_line(bContext *UNUSED(C), int x, int y, void *customdata) +{ + PaintOperation *pop = (PaintOperation *)customdata; + + if (pop) { + glEnable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); + + glLineWidth(4.0); + glColor4ub(0, 0, 0, 255); + sdrawline(x, y, pop->startmouse[0], pop->startmouse[1]); + glLineWidth(2.0); + glColor4ub(255, 255, 255, 255); + sdrawline(x, y, pop->startmouse[0], pop->startmouse[1]); + glLineWidth(1.0); + + glDisable(GL_BLEND); + glDisable(GL_LINE_SMOOTH); + } +} + -static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, float mouse[2]) +static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const float mouse[2]) { Scene *scene = CTX_data_scene(C); ToolSettings *settings = scene->toolsettings; PaintOperation *pop = MEM_callocN(sizeof(PaintOperation), "PaintOperation"); /* caller frees */ + Brush *brush = BKE_paint_brush(&settings->imapaint.paint); int mode = RNA_enum_get(op->ptr, "mode"); view3d_set_viewcontext(C, &pop->vc); - pop->prevmouse[0] = mouse[0]; - pop->prevmouse[1] = mouse[1]; + copy_v2_v2(pop->prevmouse, mouse); + copy_v2_v2(pop->startmouse, mouse); + + if ((brush->imagepaint_tool == PAINT_TOOL_FILL) && (brush->flag & BRUSH_USE_GRADIENT)) { + pop->cursor = WM_paint_cursor_activate(CTX_wm_manager(C), image_paint_poll, gradient_draw_line, pop); + } /* initialize from context */ if (CTX_wm_region_view3d(C)) { + Object *ob = OBACT; + paint_proj_mesh_data_ensure(C, ob, op); pop->mode = PAINT_MODE_3D_PROJECT; - pop->custom_paint = paint_proj_new_stroke(C, OBACT, pop->prevmouse, mode); + pop->custom_paint = paint_proj_new_stroke(C, ob, mouse, mode); } else { pop->mode = PAINT_MODE_2D; - pop->custom_paint = paint_2d_new_stroke(C, op); + pop->custom_paint = paint_2d_new_stroke(C, op, mode); } if (!pop->custom_paint) { @@ -491,52 +766,69 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, float mou settings->imapaint.flag |= IMAGEPAINT_DRAWING; ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name, - ED_image_undo_restore, ED_image_undo_free); - - { - UnifiedPaintSettings *ups = &settings->unified_paint_settings; - ups->stroke_active = true; - } + ED_image_undo_restore, ED_image_undo_free, NULL); return pop; } +/* restore painting image to previous state. Used for anchored and drag-dot style brushes*/ +static void paint_stroke_restore(void) +{ + ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE); + image_undo_restore_runtime(lb); + image_undo_invalidate(); +} + static void paint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr) { PaintOperation *pop = paint_stroke_mode_data(stroke); Scene *scene = CTX_data_scene(C); - Brush *brush = BKE_paint_brush(&scene->toolsettings->imapaint.paint); + ToolSettings *toolsettings = CTX_data_tool_settings(C); + UnifiedPaintSettings *ups = &toolsettings->unified_paint_settings; + Brush *brush = BKE_paint_brush(&toolsettings->imapaint.paint); + + float alphafac = (brush->flag & BRUSH_ACCUMULATE) ? ups->overlap_factor : 1.0f; /* initial brush values. Maybe it should be considered moving these to stroke system */ - float startsize = (float)BKE_brush_size_get(scene, brush); float startalpha = BKE_brush_alpha_get(scene, brush); float mouse[2]; float pressure; + float size; + float distance = paint_stroke_distance_get(stroke); int eraser; RNA_float_get_array(itemptr, "mouse", mouse); pressure = RNA_float_get(itemptr, "pressure"); eraser = RNA_boolean_get(itemptr, "pen_flip"); + size = max_ff(1.0f, RNA_float_get(itemptr, "size")); + + /* stroking with fill tool only acts on stroke end */ + if (brush->imagepaint_tool == PAINT_TOOL_FILL) { + copy_v2_v2(pop->prevmouse, mouse); + return; + } if (BKE_brush_use_alpha_pressure(scene, brush)) - BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * pressure)); - if (BKE_brush_use_size_pressure(scene, brush)) - BKE_brush_size_set(scene, brush, (int)max_ff(1.0f, startsize * pressure)); + BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * pressure * alphafac)); + else + BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * alphafac)); + + if ((brush->flag & BRUSH_DRAG_DOT) || (brush->flag & BRUSH_ANCHORED)) { + paint_stroke_restore(); + } if (pop->mode == PAINT_MODE_3D_PROJECT) { - paint_proj_stroke(C, pop->custom_paint, pop->prevmouse, mouse); + paint_proj_stroke(C, pop->custom_paint, pop->prevmouse, mouse, pressure, distance, size); } else { - paint_2d_stroke(pop->custom_paint, pop->prevmouse, mouse, eraser); + paint_2d_stroke(pop->custom_paint, pop->prevmouse, mouse, eraser, pressure, distance, size); } - pop->prevmouse[0] = mouse[0]; - pop->prevmouse[1] = mouse[1]; + copy_v2_v2(pop->prevmouse, mouse); /* restore brush values */ BKE_brush_alpha_set(scene, brush, startalpha); - BKE_brush_size_set(scene, brush, startsize); } static void paint_stroke_redraw(const bContext *C, struct PaintStroke *stroke, bool final) @@ -554,11 +846,39 @@ static void paint_stroke_redraw(const bContext *C, struct PaintStroke *stroke, b static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke) { Scene *scene = CTX_data_scene(C); - ToolSettings *settings = scene->toolsettings; + ToolSettings *toolsettings = scene->toolsettings; PaintOperation *pop = paint_stroke_mode_data(stroke); + Brush *brush = BKE_paint_brush(&toolsettings->imapaint.paint); - settings->imapaint.flag &= ~IMAGEPAINT_DRAWING; + toolsettings->imapaint.flag &= ~IMAGEPAINT_DRAWING; + if (brush->imagepaint_tool == PAINT_TOOL_FILL) { + if (brush->flag & BRUSH_USE_GRADIENT) { + if (pop->mode == PAINT_MODE_2D) { + paint_2d_gradient_fill(C, brush, pop->startmouse, pop->prevmouse, pop->custom_paint); + } + else { + paint_proj_stroke(C, pop->custom_paint, pop->startmouse, pop->prevmouse, 1.0, 0.0, BKE_brush_size_get(scene, brush)); + /* two redraws, one for GPU update, one for notification */ + paint_proj_redraw(C, pop->custom_paint, false); + paint_proj_redraw(C, pop->custom_paint, true); + } + } + else { + if (pop->mode == PAINT_MODE_2D) { + float color[3]; + + srgb_to_linearrgb_v3_v3(color, BKE_brush_color_get(scene, brush)); + paint_2d_bucket_fill(C, color, brush, pop->prevmouse, pop->custom_paint); + } + else { + paint_proj_stroke(C, pop->custom_paint, pop->startmouse, pop->prevmouse, 1.0, 0.0, BKE_brush_size_get(scene, brush)); + /* two redraws, one for GPU update, one for notification */ + paint_proj_redraw(C, pop->custom_paint, false); + paint_proj_redraw(C, pop->custom_paint, true); + } + } + } if (pop->mode == PAINT_MODE_3D_PROJECT) { paint_proj_stroke_done(pop->custom_paint); } @@ -566,7 +886,11 @@ static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke) paint_2d_stroke_done(pop->custom_paint); } - ED_undo_paint_push_end(UNDO_PAINT_IMAGE); + if (pop->cursor) { + WM_paint_cursor_end(CTX_wm_manager(C), pop->cursor); + } + + image_undo_end(); /* duplicate warning, see texpaint_init */ #if 0 @@ -576,43 +900,41 @@ static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke) BKE_reportf(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted: %s", pop->s.warnpackedfile); #endif MEM_freeN(pop); - - { - UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; - ups->stroke_active = false; - } -} - -static bool paint_stroke_test_start(bContext *UNUSED(C), wmOperator *UNUSED(op), const float UNUSED(mouse[2])) -{ - return true; } - -static int paint_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static bool paint_stroke_test_start(bContext *C, wmOperator *op, const float mouse[2]) { PaintOperation *pop; - float mouse[2]; - int retval; /* TODO Should avoid putting this here. Instead, last position should be requested * from stroke system. */ - mouse[0] = event->mval[0]; - mouse[1] = event->mval[1]; if (!(pop = texture_paint_init(C, op, mouse))) { - return OPERATOR_CANCELLED; + return false; } - op->customdata = paint_stroke_new(C, NULL, paint_stroke_test_start, + paint_stroke_set_mode_data(op->customdata, pop); + + return true; +} + + +static int paint_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + int retval; + + op->customdata = paint_stroke_new(C, op, NULL, paint_stroke_test_start, paint_stroke_update_step, paint_stroke_redraw, paint_stroke_done, event->type); - paint_stroke_set_mode_data(op->customdata, pop); + + if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) { + paint_stroke_data_free(op); + return OPERATOR_FINISHED; + } /* add modal handler */ WM_event_add_modal_handler(C, op); - retval = op->type->modal(C, op, event); OPERATOR_RETVAL_CHECK(retval); BLI_assert(retval == OPERATOR_RUNNING_MODAL); @@ -637,12 +959,10 @@ static int paint_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - op->customdata = paint_stroke_new(C, NULL, paint_stroke_test_start, + op->customdata = paint_stroke_new(C, op, NULL, paint_stroke_test_start, paint_stroke_update_step, paint_stroke_redraw, paint_stroke_done, 0); - paint_stroke_set_mode_data(op->customdata, pop); - /* frees op->customdata */ paint_stroke_exec(C, op); @@ -686,9 +1006,9 @@ int get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy) if (!rv3d) { SpaceImage *sima = CTX_wm_space_image(C); - ARegion *ar = CTX_wm_region(C); if (sima->mode == SI_MODE_PAINT) { + ARegion *ar = CTX_wm_region(C); ED_space_image_get_zoom(sima, ar, zoomx, zoomy); return 1; @@ -847,17 +1167,39 @@ void PAINT_OT_grab_clone(wmOperatorType *ot) typedef struct { bool show_cursor; short event_type; -} SampleColorData; + float initcolor[3]; + bool sample_palette; +} SampleColorData; + + +static void sample_color_update_header(SampleColorData *data, bContext *C) +{ +#define HEADER_LENGTH 150 + char msg[HEADER_LENGTH]; + ScrArea *sa = CTX_wm_area(C); + + if (sa) { + BLI_snprintf(msg, HEADER_LENGTH, + "Sample color for %s", + !data->sample_palette ? + "Brush. Use Left Click to sample for palette instead" : + "Palette. Use Left Click to sample more colors"); + ED_area_headerprint(sa, msg); + } + +#undef HEADER_LENGTH +} static int sample_color_exec(bContext *C, wmOperator *op) { Paint *paint = BKE_paint_get_active_from_context(C); Brush *brush = BKE_paint_brush(paint); + PaintMode mode = BKE_paintmode_get_active_from_context(C); ARegion *ar = CTX_wm_region(C); wmWindow *win = CTX_wm_window(C); bool show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0); int location[2]; - + bool use_palette; paint->flags &= ~PAINT_SHOW_BRUSH; /* force redraw without cursor */ @@ -865,7 +1207,9 @@ static int sample_color_exec(bContext *C, wmOperator *op) WM_redraw_windows(C); RNA_int_get_array(op->ptr, "location", location); - paint_sample_color(C, ar, location[0], location[1]); + use_palette = RNA_boolean_get(op->ptr, "palette"); + + paint_sample_color(C, ar, location[0], location[1], mode == PAINT_TEXTURE_PROJECTIVE, use_palette); if (show_cursor) { paint->flags |= PAINT_SHOW_BRUSH; @@ -878,7 +1222,9 @@ static int sample_color_exec(bContext *C, wmOperator *op) static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event) { + Scene *scene = CTX_data_scene(C); Paint *paint = BKE_paint_get_active_from_context(C); + PaintMode mode = BKE_paintmode_get_active_from_context(C); Brush *brush = BKE_paint_brush(paint); SampleColorData *data = MEM_mallocN(sizeof(SampleColorData), "sample color custom data"); ARegion *ar = CTX_wm_region(C); @@ -886,18 +1232,24 @@ static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event data->event_type = event->type; data->show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0); + copy_v3_v3(data->initcolor, BKE_brush_color_get(scene, brush)); + data->sample_palette = false; op->customdata = data; paint->flags &= ~PAINT_SHOW_BRUSH; + sample_color_update_header(data, C); + + WM_event_add_modal_handler(C, op); + /* force redraw without cursor */ WM_paint_cursor_tag_redraw(win, ar); WM_redraw_windows(C); RNA_int_set_array(op->ptr, "location", event->mval); - paint_sample_color(C, ar, event->mval[0], event->mval[1]); + + paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == PAINT_TEXTURE_PROJECTIVE, false); WM_cursor_modal_set(win, BC_EYEDROPPER_CURSOR); - WM_event_add_modal_handler(C, op); WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush); return OPERATOR_RUNNING_MODAL; @@ -905,17 +1257,27 @@ static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event) { + Scene *scene = CTX_data_scene(C); SampleColorData *data = op->customdata; Paint *paint = BKE_paint_get_active_from_context(C); Brush *brush = BKE_paint_brush(paint); + PaintMode mode = BKE_paintmode_get_active_from_context(C); if ((event->type == data->event_type) && (event->val == KM_RELEASE)) { + ScrArea *sa = CTX_wm_area(C); + if (data->show_cursor) { paint->flags |= PAINT_SHOW_BRUSH; } + if (data->sample_palette) { + BKE_brush_color_set(scene, brush, data->initcolor); + RNA_boolean_set(op->ptr, "palette", true); + } WM_cursor_modal_restore(CTX_wm_window(C)); MEM_freeN(data); + ED_area_headerprint(sa, NULL); + return OPERATOR_FINISHED; } @@ -924,10 +1286,22 @@ static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); RNA_int_set_array(op->ptr, "location", event->mval); - paint_sample_color(C, ar, event->mval[0], event->mval[1]); + paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == PAINT_TEXTURE_PROJECTIVE, false); WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush); break; } + + case LEFTMOUSE: + if (event->val == KM_PRESS) { + ARegion *ar = CTX_wm_region(C); + RNA_int_set_array(op->ptr, "location", event->mval); + paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == PAINT_TEXTURE_PROJECTIVE, true); + if (!data->sample_palette) { + data->sample_palette = true; + sample_color_update_header(data, C); + } + } + break; } return OPERATOR_RUNNING_MODAL; @@ -956,6 +1330,7 @@ void PAINT_OT_sample_color(wmOperatorType *ot) /* properties */ RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "Cursor location in region coordinates", 0, 16384); + RNA_def_boolean(ot->srna, "palette", 0, "Palette", "Add color to palette"); } /******************** texture paint toggle operator ********************/ @@ -973,13 +1348,78 @@ static int texture_paint_toggle_poll(bContext *C) return 1; } + +/* Make sure that active object has a material, and assign UVs and image layers if they do not exist */ +void paint_proj_mesh_data_ensure(bContext *C, Object *ob, wmOperator *op) +{ + Mesh *me; + int layernum; + bool add_material = false; + ImagePaintSettings *imapaint = &(CTX_data_tool_settings(C)->imapaint); + Brush *br = BKE_paint_brush(&imapaint->paint); + + /* no material, add one */ + if (ob->totcol == 0) { + add_material = true; + } + else { + /* there may be material slots but they may be empty, check */ + bool has_material = false; + int i; + + for (i = 1; i < ob->totcol + 1; i++) { + Material *ma = give_current_material(ob, i); + if (ma) { + has_material = true; + if (!ma->texpaintslot) { + proj_paint_add_slot(C, ma, NULL); + } + } + } + + if (!has_material) + add_material = true; + } + + if (add_material) { + Material *ma = BKE_material_add(CTX_data_main(C), "Material"); + /* no material found, just assign to first slot */ + assign_material(ob, ma, 1, BKE_MAT_ASSIGN_USERPREF); + proj_paint_add_slot(C, ma, NULL); + } + + me = BKE_mesh_from_object(ob); + layernum = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY); + + if (layernum == 0) { + BKE_reportf(op->reports, RPT_WARNING, "Object did not have UV map, manual unwrap recommended"); + + ED_mesh_uv_texture_add(me, "UVMap", true); + } + + /* Make sure we have a stencil to paint on! */ + if (br->imagepaint_tool == PAINT_TOOL_MASK) { + imapaint->flag |= IMAGEPAINT_PROJECT_LAYER_STENCIL; + + if (imapaint->stencil == NULL) { + int width; + int height; + Main *bmain = CTX_data_main(C); + float color[4] = {0.0, 0.0, 0.0, 1.0}; + + width = 1024; + height = 1024; + imapaint->stencil = BKE_image_add_generated(bmain, width, height, "Stencil", 32, false, IMA_GENTYPE_BLANK, color); + } + } +} + static int texture_paint_toggle_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); const int mode_flag = OB_MODE_TEXTURE_PAINT; const bool is_mode_set = (ob->mode & mode_flag) != 0; - Mesh *me; if (!is_mode_set) { if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { @@ -987,8 +1427,6 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op) } } - me = BKE_mesh_from_object(ob); - if (ob->mode & mode_flag) { ob->mode &= ~mode_flag; @@ -999,11 +1437,36 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op) toggle_paint_cursor(C, 0); } else { - ob->mode |= mode_flag; + bScreen *sc; + Main *bmain = CTX_data_main(C); + Material *ma; + + bool use_nodes = BKE_scene_use_new_shading_nodes(scene); + /* This has to stay here to regenerate the texture paint + * cache in case we are loading a file */ + BKE_texpaint_slots_refresh_object(ob, use_nodes); + + paint_proj_mesh_data_ensure(C, ob, op); + + /* set the current material active paint slot on image editor */ + ma = give_current_material(ob, ob->actcol); + + if (ma->tot_slots > 0) { + for (sc = bmain->screen.first; sc; sc = sc->id.next) { + ScrArea *sa; + for (sa = sc->areabase.first; sa; sa = sa->next) { + SpaceLink *sl; + for (sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_IMAGE) { + SpaceImage *sima = (SpaceImage *)sl; + ED_space_image_set(sima, scene, scene->obedit, ma->texpaintslot[ma->paint_active_slot].ima); + } + } + } + } + } - if (me->mtface == NULL) - me->mtface = CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DEFAULT, - NULL, me->totface); + ob->mode |= mode_flag; BKE_paint_init(&scene->toolsettings->imapaint.paint, PAINT_CURSOR_TEXTURE_PAINT); @@ -1035,6 +1498,60 @@ void PAINT_OT_texture_paint_toggle(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +static int brush_colors_flip_exec(bContext *C, wmOperator *UNUSED(op)) +{ + UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; + Brush *br = image_paint_brush(C); + if (ups->flag & UNIFIED_PAINT_COLOR) { + swap_v3_v3(ups->rgb, ups->secondary_rgb); + } + else if (br) { + swap_v3_v3(br->rgb, br->secondary_rgb); + } + WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, br); + + return OPERATOR_FINISHED; +} + +static int brush_colors_flip_poll(bContext *C) +{ + if (image_paint_poll(C)) { + Brush *br = image_paint_brush(C); + if (br->imagepaint_tool == PAINT_TOOL_DRAW) + return 1; + } + + return 0; +} + +void PAINT_OT_brush_colors_flip(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Brush Colors Flip"; + ot->idname = "PAINT_OT_brush_colors_flip"; + ot->description = "Toggle foreground and background brush colors"; + + /* api callbacks */ + ot->exec = brush_colors_flip_exec; + ot->poll = brush_colors_flip_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + + +void ED_imapaint_bucket_fill(struct bContext *C, float color[3], wmOperator *op) +{ + ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name, + ED_image_undo_restore, ED_image_undo_free, NULL); + + paint_2d_bucket_fill(C, color, NULL, NULL, NULL); + + ED_undo_paint_push_end(UNDO_PAINT_IMAGE); +} + + static int texture_paint_poll(bContext *C) { if (texture_paint_toggle_poll(C)) diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index 4f67fc9cc87..1f66910eaa2 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -40,11 +40,18 @@ #include "BLI_math.h" +#include "BLI_rect.h" +#include "BLI_math_color_blend.h" +#include "BLI_stack.h" +#include "BLI_bitmap.h" + #include "BKE_context.h" +#include "BKE_depsgraph.h" #include "BKE_brush.h" #include "BKE_image.h" #include "BKE_paint.h" #include "BKE_report.h" +#include "BKE_texture.h" #include "ED_paint.h" #include "ED_screen.h" @@ -69,24 +76,25 @@ /* Defines and Structs */ typedef struct BrushPainterCache { - int size; /* size override, if 0 uses 2*BKE_brush_size_get(brush) */ - bool use_float; /* need float imbuf? */ bool use_color_correction; /* use color correction for float */ - bool use_masking; /* use masking? */ + bool invert; bool is_texbrush; bool is_maskbrush; - int lastsize; - float lastalpha; - float lastjitter; + int lastdiameter; float last_tex_rotation; float last_mask_rotation; + float last_pressure; ImBuf *ibuf; ImBuf *texibuf; - unsigned short *mask; + unsigned short *curve_mask; + unsigned short *tex_mask; + unsigned short *tex_mask_old; + unsigned int tex_mask_old_w; + unsigned int tex_mask_old_h; } BrushPainterCache; typedef struct BrushPainter { @@ -136,43 +144,42 @@ typedef struct ImagePaintState { int do_facesel; bool need_redraw; + + BlurKernel *blurkernel; } ImagePaintState; -static BrushPainter *brush_painter_2d_new(Scene *scene, Brush *brush) +static BrushPainter *brush_painter_2d_new(Scene *scene, Brush *brush, bool invert) { BrushPainter *painter = MEM_callocN(sizeof(BrushPainter), "BrushPainter"); painter->brush = brush; painter->scene = scene; painter->firsttouch = 1; - painter->cache.lastsize = -1; /* force ibuf create in refresh */ + painter->cache.lastdiameter = -1; /* force ibuf create in refresh */ + painter->cache.invert = invert; return painter; } -static void brush_painter_2d_require_imbuf(BrushPainter *painter, bool use_float, bool use_color_correction, bool use_masking) +static void brush_painter_2d_require_imbuf(BrushPainter *painter, bool use_float, bool use_color_correction) { Brush *brush = painter->brush; if ((painter->cache.use_float != use_float)) { if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf); - if (painter->cache.mask) MEM_freeN(painter->cache.mask); + if (painter->cache.curve_mask) MEM_freeN(painter->cache.curve_mask); + if (painter->cache.tex_mask) MEM_freeN(painter->cache.tex_mask); + if (painter->cache.tex_mask_old) MEM_freeN(painter->cache.tex_mask_old); painter->cache.ibuf = NULL; - painter->cache.mask = NULL; - painter->cache.lastsize = -1; /* force ibuf create in refresh */ - } - - if (painter->cache.use_float != use_float) { - if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf); - painter->cache.texibuf = NULL; - painter->cache.lastsize = -1; /* force ibuf create in refresh */ + painter->cache.curve_mask = NULL; + painter->cache.tex_mask = NULL; + painter->cache.lastdiameter = -1; /* force ibuf create in refresh */ } painter->cache.use_float = use_float; painter->cache.use_color_correction = use_float && use_color_correction; - painter->cache.use_masking = use_masking; painter->cache.is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ? true : false; painter->cache.is_maskbrush = (brush->mask_mtex.tex) ? true : false; } @@ -181,7 +188,9 @@ static void brush_painter_2d_free(BrushPainter *painter) { if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf); if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf); - if (painter->cache.mask) MEM_freeN(painter->cache.mask); + if (painter->cache.curve_mask) MEM_freeN(painter->cache.curve_mask); + if (painter->cache.tex_mask) MEM_freeN(painter->cache.tex_mask); + if (painter->cache.tex_mask_old) MEM_freeN(painter->cache.tex_mask_old); MEM_freeN(painter); } @@ -192,41 +201,177 @@ static void brush_imbuf_tex_co(rctf *mapping, int x, int y, float texco[3]) texco[2] = 0.0f; } -/* create a mask with the falloff strength and optionally brush alpha */ -static unsigned short *brush_painter_mask_new(BrushPainter *painter, int size) +/* create a mask with the mask texture */ +static unsigned short *brush_painter_mask_ibuf_new(BrushPainter *painter, int size) { Scene *scene = painter->scene; Brush *brush = painter->brush; - bool use_masking = painter->cache.use_masking; - - float alpha = (use_masking) ? 1.0f : BKE_brush_alpha_get(scene, brush); - int radius = BKE_brush_size_get(scene, brush); - int xoff = -size * 0.5f + 0.5f; - int yoff = -size * 0.5f + 0.5f; + rctf mask_mapping = painter->mask_mapping; + struct ImagePool *pool = painter->pool; + float texco[3]; unsigned short *mask, *m; - int x, y; + int x, y, thread = 0; - mask = MEM_callocN(sizeof(unsigned short) * size * size, "brush_painter_mask"); + mask = MEM_mallocN(sizeof(unsigned short) * size * size, "brush_painter_mask"); m = mask; for (y = 0; y < size; y++) { for (x = 0; x < size; x++, m++) { + float res; + brush_imbuf_tex_co(&mask_mapping, x, y, texco); + res = BKE_brush_sample_masktex(scene, brush, texco, thread, pool); + *m = (unsigned short)(65535.0f * res); + } + } + + return mask; +} + +/* update rectangular section of the brush image */ +static void brush_painter_mask_imbuf_update( + BrushPainter *painter, unsigned short *tex_mask_old, + int origx, int origy, int w, int h, int xt, int yt, int diameter) +{ + Scene *scene = painter->scene; + Brush *brush = painter->brush; + rctf tex_mapping = painter->mask_mapping; + struct ImagePool *pool = painter->pool; + unsigned short res; + + bool use_texture_old = (tex_mask_old != NULL); + + int x, y, thread = 0; + + unsigned short *tex_mask = painter->cache.tex_mask; + unsigned short *tex_mask_cur = painter->cache.tex_mask_old; + + /* fill pixels */ + for (y = origy; y < h; y++) { + for (x = origx; x < w; x++) { + /* sample texture */ + float texco[3]; + + /* handle byte pixel */ + unsigned short *b = tex_mask + (y * diameter + x); + unsigned short *t = tex_mask_cur + (y * diameter + x); + + if (!use_texture_old) { + brush_imbuf_tex_co(&tex_mapping, x, y, texco); + res = (unsigned short)(65535.0f * BKE_brush_sample_masktex(scene, brush, texco, thread, pool)); + } + + /* read from old texture buffer */ + if (use_texture_old) { + res = *(tex_mask_old + ((y - origy + yt) * painter->cache.tex_mask_old_w + (x - origx + xt))); + } + + /* write to new texture mask */ + *t = res; + /* write to mask image buffer */ + *b = res; + } + } +} + + +/** + * Update the brush mask image by trying to reuse the cached texture result. + * This can be considerably faster for brushes that change size due to pressure or + * textures that stick to the surface where only part of the pixels are new + */ +static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter, const float pos[2], int diameter) +{ + BrushPainterCache *cache = &painter->cache; + unsigned short *tex_mask_old; + int destx, desty, srcx, srcy, w, h, x1, y1, x2, y2; + + /* create brush image buffer if it didn't exist yet */ + if (!cache->tex_mask) + cache->tex_mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask"); + + /* create new texture image buffer with coordinates relative to old */ + tex_mask_old = cache->tex_mask_old; + cache->tex_mask_old = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask"); + + if (tex_mask_old) { + ImBuf maskibuf; + ImBuf maskibuf_old; + maskibuf.x = maskibuf.y = diameter; + maskibuf_old.x = cache->tex_mask_old_w; + maskibuf_old.y = cache->tex_mask_old_h; + + srcx = srcy = 0; + w = cache->tex_mask_old_w; + h = cache->tex_mask_old_h; + destx = (int)painter->lastpaintpos[0] - (int)pos[0] + (diameter / 2 - w / 2); + desty = (int)painter->lastpaintpos[1] - (int)pos[1] + (diameter / 2 - h / 2); + + /* hack, use temporary rects so that clipping works */ + IMB_rectclip(&maskibuf, &maskibuf_old, &destx, &desty, &srcx, &srcy, &w, &h); + } + else { + srcx = srcy = 0; + destx = desty = 0; + w = h = 0; + } + + x1 = min_ii(destx, diameter); + y1 = min_ii(desty, diameter); + x2 = min_ii(destx + w, diameter); + y2 = min_ii(desty + h, diameter); + + /* blend existing texture in new position */ + if ((x1 < x2) && (y1 < y2)) + brush_painter_mask_imbuf_update(painter, tex_mask_old, x1, y1, x2, y2, srcx, srcy, diameter); + + if (tex_mask_old) + MEM_freeN(tex_mask_old); + + /* sample texture in new areas */ + if ((0 < x1) && (0 < diameter)) + brush_painter_mask_imbuf_update(painter, NULL, 0, 0, x1, diameter, 0, 0, diameter); + if ((x2 < diameter) && (0 < diameter)) + brush_painter_mask_imbuf_update(painter, NULL, x2, 0, diameter, diameter, 0, 0, diameter); + if ((x1 < x2) && (0 < y1)) + brush_painter_mask_imbuf_update(painter, NULL, x1, 0, x2, y1, 0, 0, diameter); + if ((x1 < x2) && (y2 < diameter)) + brush_painter_mask_imbuf_update(painter, NULL, x1, y2, x2, diameter, 0, 0, diameter); + + /* through with sampling, now update sizes */ + cache->tex_mask_old_w = diameter; + cache->tex_mask_old_h = diameter; +} + +/* create a mask with the falloff strength */ +static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter, int diameter, float radius) +{ + Brush *brush = painter->brush; + + int xoff = -diameter * 0.5f + 0.5f; + int yoff = -diameter * 0.5f + 0.5f; + + unsigned short *mask, *m; + int x, y; + + mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask"); + m = mask; + + for (y = 0; y < diameter; y++) { + for (x = 0; x < diameter; x++, m++) { float xy[2] = {x + xoff, y + yoff}; float len = len_v2(xy); - float strength = alpha; - - strength *= BKE_brush_curve_strength_clamp(brush, len, radius); - *m = (unsigned short)(65535.0f * strength); + *m = (unsigned short)(65535.0f * BKE_brush_curve_strength_clamp(brush, len, radius)); } } return mask; } + /* create imbuf with brush color */ -static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size) +static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size, float pressure, float distance) { Scene *scene = painter->scene; Brush *brush = painter->brush; @@ -235,19 +380,11 @@ static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size) struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device); rctf tex_mapping = painter->tex_mapping; - rctf mask_mapping = painter->mask_mapping; struct ImagePool *pool = painter->pool; - bool use_masking = painter->cache.use_masking; bool use_color_correction = painter->cache.use_color_correction; bool use_float = painter->cache.use_float; bool is_texbrush = painter->cache.is_texbrush; - bool is_maskbrush = painter->cache.is_maskbrush; - - float alpha = (use_masking) ? 1.0f : BKE_brush_alpha_get(scene, brush); - int radius = BKE_brush_size_get(scene, brush); - int xoff = -size * 0.5f + 0.5f; - int yoff = -size * 0.5f + 0.5f; int x, y, thread = 0; float brush_rgb[3]; @@ -257,11 +394,7 @@ static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size) /* get brush color */ if (brush->imagepaint_tool == PAINT_TOOL_DRAW) { - copy_v3_v3(brush_rgb, brush->rgb); - - if (use_color_correction) { - IMB_colormanagement_display_to_scene_linear_v3(brush_rgb, display); - } + paint_brush_color_get(scene, brush, use_color_correction, painter->cache.invert, distance, pressure, brush_rgb, display); } else { brush_rgb[0] = 1.0f; @@ -289,19 +422,6 @@ static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size) rgba[3] = 1.0f; } - if (is_maskbrush) { - brush_imbuf_tex_co(&mask_mapping, x, y, texco); - rgba[3] *= BKE_brush_sample_masktex(scene, brush, texco, thread, pool); - } - - /* when not using masking, multiply in falloff and strength */ - if (!use_masking) { - float xy[2] = {x + xoff, y + yoff}; - float len = len_v2(xy); - - rgba[3] *= alpha * BKE_brush_curve_strength_clamp(brush, len, radius); - } - if (use_float) { /* write to float pixel */ float *dstf = ibuf->rect_float + (y * size + x) * 4; @@ -332,14 +452,11 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf, struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device); rctf tex_mapping = painter->tex_mapping; - rctf mask_mapping = painter->mask_mapping; struct ImagePool *pool = painter->pool; - bool use_masking = painter->cache.use_masking; bool use_color_correction = painter->cache.use_color_correction; bool use_float = painter->cache.use_float; bool is_texbrush = painter->cache.is_texbrush; - bool is_maskbrush = painter->cache.is_maskbrush; bool use_texture_old = (oldtexibuf != NULL); int x, y, thread = 0; @@ -347,15 +464,10 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf, ImBuf *ibuf = painter->cache.ibuf; ImBuf *texibuf = painter->cache.texibuf; - unsigned short *mask = painter->cache.mask; /* get brush color */ if (brush->imagepaint_tool == PAINT_TOOL_DRAW) { - copy_v3_v3(brush_rgb, brush->rgb); - - if (use_color_correction) { - IMB_colormanagement_display_to_scene_linear_v3(brush_rgb, display); - } + paint_brush_color_get(scene, brush, use_color_correction, painter->cache.invert, 0.0, 1.0, brush_rgb, display); } else { brush_rgb[0] = 1.0f; @@ -363,7 +475,7 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf, brush_rgb[2] = 1.0f; } - /* fill pixes */ + /* fill pixels */ for (y = origy; y < h; y++) { for (x = origx; x < w; x++) { /* sample texture and multiply with brush color */ @@ -383,11 +495,6 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf, copy_v3_v3(rgba, brush_rgb); rgba[3] = 1.0f; } - - if (is_maskbrush) { - brush_imbuf_tex_co(&mask_mapping, x, y, texco); - rgba[3] *= BKE_brush_sample_masktex(scene, brush, texco, thread, pool); - } } if (use_float) { @@ -404,12 +511,6 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf, /* write to new texture buffer */ copy_v4_v4(tf, rgba); - /* if not using masking, multiply in the mask now */ - if (!use_masking) { - unsigned short *m = mask + (y * ibuf->x + x); - rgba[3] *= *m * (1.0f / 65535.0f); - } - /* output premultiplied float image, mf was already premultiplied */ mul_v3_v3fl(bf, rgba, rgba[3]); bf[3] = rgba[3]; @@ -438,12 +539,6 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf, t[2] = crgba[2]; t[3] = crgba[3]; - /* if not using masking, multiply in the mask now */ - if (!use_masking) { - unsigned short *m = mask + (y * ibuf->x + x); - crgba[3] = (crgba[3] * (*m)) / 65535; - } - /* write to brush image buffer */ b[0] = crgba[0]; b[1] = crgba[1]; @@ -457,14 +552,11 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf, /* update the brush image by trying to reuse the cached texture result. this * can be considerably faster for brushes that change size due to pressure or * textures that stick to the surface where only part of the pixels are new */ -static void brush_painter_imbuf_partial_update(BrushPainter *painter, const float pos[2]) +static void brush_painter_imbuf_partial_update(BrushPainter *painter, const float pos[2], int diameter) { - const Scene *scene = painter->scene; - Brush *brush = painter->brush; BrushPainterCache *cache = &painter->cache; ImBuf *oldtexibuf, *ibuf; int imbflag, destx, desty, srcx, srcy, w, h, x1, y1, x2, y2; - int diameter = 2 * BKE_brush_size_get(scene, brush); /* create brush image buffer if it didn't exist yet */ imbflag = (cache->use_float) ? IB_rectfloat : IB_rect; @@ -478,10 +570,10 @@ static void brush_painter_imbuf_partial_update(BrushPainter *painter, const floa if (oldtexibuf) { srcx = srcy = 0; - destx = (int)painter->lastpaintpos[0] - (int)pos[0]; - desty = (int)painter->lastpaintpos[1] - (int)pos[1]; w = oldtexibuf->x; h = oldtexibuf->y; + destx = (int)painter->lastpaintpos[0] - (int)pos[0] + (diameter / 2 - w / 2); + desty = (int)painter->lastpaintpos[1] - (int)pos[1] + (diameter / 2 - h / 2); IMB_rectclip(cache->texibuf, oldtexibuf, &destx, &desty, &srcx, &srcy, &w, &h); } @@ -514,7 +606,7 @@ static void brush_painter_imbuf_partial_update(BrushPainter *painter, const floa brush_painter_imbuf_update(painter, NULL, x1, y2, x2, ibuf->y, 0, 0); } -static void brush_painter_2d_tex_mapping(ImagePaintState *s, int size, const float startpos[2], const float pos[2], const float mouse[2], int mapmode, rctf *mapping) +static void brush_painter_2d_tex_mapping(ImagePaintState *s, int diameter, const float startpos[2], const float pos[2], const float mouse[2], int mapmode, rctf *mapping) { float invw = 1.0f / (float)s->canvas->x; float invh = 1.0f / (float)s->canvas->y; @@ -522,19 +614,19 @@ static void brush_painter_2d_tex_mapping(ImagePaintState *s, int size, const flo int ipos[2]; /* find start coordinate of brush in canvas */ - ipos[0] = (int)floorf((pos[0] - size / 2) + 1.0f); - ipos[1] = (int)floorf((pos[1] - size / 2) + 1.0f); + ipos[0] = (int)floorf((pos[0] - diameter / 2) + 1.0f); + ipos[1] = (int)floorf((pos[1] - diameter / 2) + 1.0f); if (mapmode == MTEX_MAP_MODE_STENCIL) { /* map from view coordinates of brush to region coordinates */ UI_view2d_view_to_region(s->v2d, ipos[0] * invw, ipos[1] * invh, &xmin, &ymin); - UI_view2d_view_to_region(s->v2d, (ipos[0] + size) * invw, (ipos[1] + size) * invh, &xmax, &ymax); + UI_view2d_view_to_region(s->v2d, (ipos[0] + diameter) * invw, (ipos[1] + diameter) * invh, &xmax, &ymax); /* output mapping from brush ibuf x/y to region coordinates */ mapping->xmin = xmin; mapping->ymin = ymin; - mapping->xmax = (xmax - xmin) / (float)size; - mapping->ymax = (ymax - ymin) / (float)size; + mapping->xmax = (xmax - xmin) / (float)diameter; + mapping->ymax = (ymax - ymin) / (float)diameter; } else if (mapmode == MTEX_MAP_MODE_3D) { /* 3D mapping, just mapping to canvas 0..1 */ @@ -545,104 +637,126 @@ static void brush_painter_2d_tex_mapping(ImagePaintState *s, int size, const flo } else if (ELEM(mapmode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_RANDOM)) { /* view mapping */ - mapping->xmin = mouse[0] - size * 0.5f + 0.5f; - mapping->ymin = mouse[1] - size * 0.5f + 0.5f; + mapping->xmin = mouse[0] - diameter * 0.5f + 0.5f; + mapping->ymin = mouse[1] - diameter * 0.5f + 0.5f; mapping->xmax = 1.0f; mapping->ymax = 1.0f; } else /* if (mapmode == MTEX_MAP_MODE_TILED) */ { - mapping->xmin = -size * 0.5f + 0.5f + (int)pos[0] - (int)startpos[0]; - mapping->ymin = -size * 0.5f + 0.5f + (int)pos[1] - (int)startpos[1]; + mapping->xmin = (int)(-diameter * 0.5) + (int)pos[0] - (int)startpos[0]; + mapping->ymin = (int)(-diameter * 0.5) + (int)pos[1] - (int)startpos[1]; mapping->xmax = 1.0f; mapping->ymax = 1.0f; } } -static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *painter, const float pos[2], const float mouse[2]) +static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *painter, const float pos[2], const float mouse[2], float pressure, float distance, float size) { const Scene *scene = painter->scene; UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; Brush *brush = painter->brush; BrushPainterCache *cache = &painter->cache; - const int diameter = 2 * BKE_brush_size_get(scene, brush); - const int size = (cache->size) ? cache->size : diameter; - const float alpha = BKE_brush_alpha_get(scene, brush); - const bool use_masking = painter->cache.use_masking; + const int diameter = 2 * size; bool do_random = false; bool do_partial_update = false; - bool do_view = false; + bool update_color = (brush->flag & BRUSH_USE_GRADIENT) && + ((ELEM(brush->gradient_stroke_mode, + BRUSH_GRADIENT_SPACING_REPEAT, + BRUSH_GRADIENT_SPACING_CLAMP)) || + (cache->last_pressure != pressure)); float tex_rotation = -brush->mtex.rot; float mask_rotation = -brush->mask_mtex.rot; + painter->pool = BKE_image_pool_new(); + /* determine how can update based on textures used */ if (painter->cache.is_texbrush) { if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) { - do_view = true; tex_rotation += ups->brush_rotation; } else if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) do_random = true; - else + else if (!((brush->flag & BRUSH_ANCHORED) || update_color)) do_partial_update = true; - brush_painter_2d_tex_mapping(s, size, painter->startpaintpos, pos, mouse, + brush_painter_2d_tex_mapping(s, diameter, painter->startpaintpos, pos, mouse, brush->mtex.brush_map_mode, &painter->tex_mapping); } if (painter->cache.is_maskbrush) { + bool renew_maxmask = false; + bool do_partial_update_mask = false; + /* invalidate case for all mapping modes */ if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) { - do_view = true; mask_rotation += ups->brush_rotation; } - else if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) - do_random = true; - else - do_partial_update = true; + else if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) { + renew_maxmask = true; + } + else if (!(brush->flag & BRUSH_ANCHORED)) { + do_partial_update_mask = true; + renew_maxmask = true; + } + /* explicilty disable partial update even if it has been enabled above */ + if (brush->mask_pressure) { + do_partial_update_mask = false; + renew_maxmask = true; + } - brush_painter_2d_tex_mapping(s, size, painter->startpaintpos, pos, mouse, - brush->mask_mtex.brush_map_mode, &painter->mask_mapping); + if ((diameter != cache->lastdiameter) || + (mask_rotation != cache->last_mask_rotation) || + renew_maxmask) + { + if (cache->tex_mask) { + MEM_freeN(cache->tex_mask); + cache->tex_mask = NULL; + } + + brush_painter_2d_tex_mapping(s, diameter, painter->startpaintpos, pos, mouse, + brush->mask_mtex.brush_map_mode, &painter->mask_mapping); + + if (do_partial_update_mask) + brush_painter_mask_imbuf_partial_update(painter, pos, diameter); + else + cache->tex_mask = brush_painter_mask_ibuf_new(painter, diameter); + cache->last_mask_rotation = mask_rotation; + } } - if (do_view || do_random) - do_partial_update = false; + /* curve mask can only change if the size changes */ + if (diameter != cache->lastdiameter) { + if (cache->curve_mask) { + MEM_freeN(cache->curve_mask); + cache->curve_mask = NULL; + } - painter->pool = BKE_image_pool_new(); + cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size); + } /* detect if we need to recreate image brush buffer */ - if (diameter != cache->lastsize || - alpha != cache->lastalpha || - brush->jitter != cache->lastjitter || - tex_rotation != cache->last_tex_rotation || - mask_rotation != cache->last_mask_rotation || - do_random) + if ((diameter != cache->lastdiameter) || + (tex_rotation != cache->last_tex_rotation) || + do_random || + update_color) { if (cache->ibuf) { IMB_freeImBuf(cache->ibuf); cache->ibuf = NULL; } - if (cache->mask) { - MEM_freeN(cache->mask); - cache->mask = NULL; - } if (do_partial_update) { - /* do partial update of texture + recreate mask */ - cache->mask = brush_painter_mask_new(painter, size); - brush_painter_imbuf_partial_update(painter, pos); + /* do partial update of texture */ + brush_painter_imbuf_partial_update(painter, pos, diameter); } else { - /* create brush and mask from scratch */ - if (use_masking) - cache->mask = brush_painter_mask_new(painter, size); - cache->ibuf = brush_painter_imbuf_new(painter, size); + /* create brush from scratch */ + cache->ibuf = brush_painter_imbuf_new(painter, diameter, pressure, distance); } - cache->lastsize = diameter; - cache->lastalpha = alpha; - cache->lastjitter = brush->jitter; + cache->lastdiameter = diameter; cache->last_tex_rotation = tex_rotation; - cache->last_mask_rotation = mask_rotation; + cache->last_pressure = pressure; } else if (do_partial_update) { /* do only partial update of texture */ @@ -650,7 +764,7 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *pai int dy = (int)painter->lastpaintpos[1] - (int)pos[1]; if ((dx != 0) || (dy != 0)) { - brush_painter_imbuf_partial_update(painter, pos); + brush_painter_imbuf_partial_update(painter, pos, diameter); } } @@ -703,7 +817,7 @@ static void paint_2d_ibuf_rgb_set(ImBuf *ibuf, int x, int y, const bool is_torus } } -static int paint_2d_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, float *outrgb, short torus) +static float paint_2d_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, float *outrgb, short torus, float w) { float inrgb[4]; @@ -716,16 +830,23 @@ static int paint_2d_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, flo paint_2d_ibuf_rgb_get(ibuf, x, y, 0, inrgb); } + mul_v4_fl(inrgb, w); add_v4_v4(outrgb, inrgb); - return 1; + return w; } -static void paint_2d_lift_soften(ImBuf *ibuf, ImBuf *ibufb, int *pos, const bool is_torus) +static void paint_2d_lift_soften(ImagePaintState *s, ImBuf *ibuf, ImBuf *ibufb, int *pos, const short is_torus) { - int x, y, count, xi, yi, xo, yo; + bool sharpen = (s->painter->cache.invert ^ ((s->brush->flag & BRUSH_DIR_IN) != 0)); + float threshold = s->brush->sharp_threshold; + int x, y, xi, yi, xo, yo, xk, yk; + float count; int out_off[2], in_off[2], dim[2]; + int diff_pos[2]; float outrgb[4]; + float rgba[4]; + BlurKernel *kernel = s->blurkernel; dim[0] = ibufb->x; dim[1] = ibufb->y; @@ -741,28 +862,52 @@ static void paint_2d_lift_soften(ImBuf *ibuf, ImBuf *ibufb, int *pos, const bool return; } + /* find offset inside mask buffers to sample them */ + sub_v2_v2v2_int(diff_pos, out_off, in_off); + for (y = 0; y < dim[1]; y++) { for (x = 0; x < dim[0]; x++) { /* get input pixel */ xi = in_off[0] + x; yi = in_off[1] + y; - count = 1; - paint_2d_ibuf_rgb_get(ibuf, xi, yi, is_torus, outrgb); + count = 0.0; + paint_2d_ibuf_rgb_get(ibuf, xi, yi, is_torus, rgba); + zero_v4(outrgb); - count += paint_2d_ibuf_add_if(ibuf, xi - 1, yi - 1, outrgb, is_torus); - count += paint_2d_ibuf_add_if(ibuf, xi - 1, yi, outrgb, is_torus); - count += paint_2d_ibuf_add_if(ibuf, xi - 1, yi + 1, outrgb, is_torus); + for (yk = 0; yk < kernel->side; yk++) { + for (xk = 0; xk < kernel->side; xk++) { + count += paint_2d_ibuf_add_if(ibuf, xi + xk - kernel->pixel_len, + yi + yk - kernel->pixel_len, outrgb, is_torus, + kernel->wdata[xk + yk * kernel->side]); + } + } - count += paint_2d_ibuf_add_if(ibuf, xi, yi - 1, outrgb, is_torus); - count += paint_2d_ibuf_add_if(ibuf, xi, yi + 1, outrgb, is_torus); + if (count > 0.0f) { + mul_v4_fl(outrgb, 1.0f / (float)count); - count += paint_2d_ibuf_add_if(ibuf, xi + 1, yi - 1, outrgb, is_torus); - count += paint_2d_ibuf_add_if(ibuf, xi + 1, yi, outrgb, is_torus); - count += paint_2d_ibuf_add_if(ibuf, xi + 1, yi + 1, outrgb, is_torus); + if (sharpen) { + /* subtract blurred image from normal image gives high pass filter */ + sub_v3_v3v3(outrgb, rgba, outrgb); - mul_v4_fl(outrgb, 1.0f / (float)count); + /* now rgba_ub contains the edge result, but this should be converted to luminance to avoid + * colored speckles appearing in final image, and also to check for threshold */ + outrgb[0] = outrgb[1] = outrgb[2] = rgb_to_grayscale(outrgb); + if (fabsf(outrgb[0]) > threshold) { + float mask = BKE_brush_alpha_get(s->scene, s->brush); + float alpha = rgba[3]; + rgba[3] = outrgb[3] = mask; + /* add to enhance edges */ + blend_color_add_float(outrgb, rgba, outrgb); + outrgb[3] = alpha; + } + else + copy_v4_v4(outrgb, rgba); + } + } + else + copy_v4_v4(outrgb, rgba); /* write into brush buffer */ xo = out_off[0] + x; yo = out_off[1] + y; @@ -830,10 +975,10 @@ static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos) tot = paint_2d_torus_split_region(region, ibufb, ibuf); for (a = 0; a < tot; a++) - IMB_rectblend(ibufb, ibufb, ibuf, NULL, NULL, 0, region[a].destx, region[a].desty, + IMB_rectblend(ibufb, ibufb, ibuf, NULL, NULL, NULL, 0, region[a].destx, region[a].desty, region[a].destx, region[a].desty, region[a].srcx, region[a].srcy, - region[a].width, region[a].height, IMB_BLEND_COPY_RGB); + region[a].width, region[a].height, IMB_BLEND_COPY_RGB, false); } static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos) @@ -844,10 +989,10 @@ static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos) ImBuf *clonebuf = IMB_allocImBuf(w, h, ibufb->planes, ibufb->flags); IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h); - IMB_rectblend(clonebuf, clonebuf, ibufb, NULL, NULL, 0, destx, desty, destx, desty, destx, desty, w, h, - IMB_BLEND_COPY_ALPHA); - IMB_rectblend(clonebuf, clonebuf, ibuf, NULL, NULL, 0, destx, desty, destx, desty, srcx, srcy, w, h, - IMB_BLEND_COPY_RGB); + IMB_rectblend(clonebuf, clonebuf, ibufb, NULL, NULL, NULL, 0, destx, desty, destx, desty, destx, desty, w, h, + IMB_BLEND_COPY_ALPHA, false); + IMB_rectblend(clonebuf, clonebuf, ibuf, NULL, NULL, NULL, 0, destx, desty, destx, desty, srcx, srcy, w, h, + IMB_BLEND_COPY_RGB, false); return clonebuf; } @@ -858,17 +1003,16 @@ static void paint_2d_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[ ipos[1] = (int)floorf((pos[1] - ibufb->y / 2) + 1.0f); } -static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *maskb, const float lastpos[2], const float pos[2]) +static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsigned short *texmaskb, const float lastpos[2], const float pos[2]) { ImagePaintState *s = ((ImagePaintState *)state); - ImBuf *clonebuf = NULL, *frombuf, *tmpbuf = NULL; + ImBuf *clonebuf = NULL, *frombuf; ImagePaintRegion region[4]; short torus = s->brush->flag & BRUSH_TORUS; short blend = s->blend; const float *offset = s->brush->clone.offset; float liftpos[2]; - float brush_alpha = BKE_brush_alpha_get(s->scene, s->brush); - unsigned short mask_max = (unsigned short)(brush_alpha * 65535.0f); + float mask_max = BKE_brush_alpha_get(s->scene, s->brush); int bpos[2], blastpos[2], bliftpos[2]; int a, tot; @@ -876,7 +1020,7 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *maskb, const f /* lift from canvas */ if (s->tool == PAINT_TOOL_SOFTEN) { - paint_2d_lift_soften(s->canvas, ibufb, bpos, torus); + paint_2d_lift_soften(s, s->canvas, ibufb, bpos, torus); } else if (s->tool == PAINT_TOOL_SMEAR) { if (lastpos[0] == pos[0] && lastpos[1] == pos[1]) @@ -903,9 +1047,6 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *maskb, const f paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y); tot = 1; } - - if (s->do_masking) - tmpbuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0); /* blend into canvas */ for (a = 0; a < tot; a++) { @@ -916,11 +1057,14 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *maskb, const f if (s->do_masking) { /* masking, find original pixels tiles from undo buffer to composite over */ int tilex, tiley, tilew, tileh, tx, ty; + ImBuf *tmpbuf; imapaint_region_tiles(s->canvas, region[a].destx, region[a].desty, region[a].width, region[a].height, &tilex, &tiley, &tilew, &tileh); - + + tmpbuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0); + for (ty = tiley; ty <= tileh; ty++) { for (tx = tilex; tx <= tilew; tx++) { /* retrieve original pixels + mask from undo buffer */ @@ -929,31 +1073,32 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *maskb, const f int origy = region[a].desty - ty * IMAPAINT_TILE_SIZE; if (s->canvas->rect_float) - tmpbuf->rect_float = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask); + tmpbuf->rect_float = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false); else - tmpbuf->rect = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask); + tmpbuf->rect = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false); IMB_rectblend(s->canvas, tmpbuf, frombuf, mask, - maskb, mask_max, + curveb, texmaskb, mask_max, region[a].destx, region[a].desty, origx, origy, region[a].srcx, region[a].srcy, - region[a].width, region[a].height, blend); + region[a].width, region[a].height, blend, ((s->brush->flag & BRUSH_ACCUMULATE) != 0)); } } + + IMB_freeImBuf(tmpbuf); } else { /* no masking, composite brush directly onto canvas */ - IMB_rectblend(s->canvas, s->canvas, frombuf, NULL, NULL, 0, + IMB_rectblend(s->canvas, s->canvas, frombuf, NULL, curveb, texmaskb, mask_max, region[a].destx, region[a].desty, region[a].destx, region[a].desty, region[a].srcx, region[a].srcy, - region[a].width, region[a].height, blend); + region[a].width, region[a].height, blend, false); } } if (clonebuf) IMB_freeImBuf(clonebuf); - if (tmpbuf) IMB_freeImBuf(tmpbuf); return 1; } @@ -1003,10 +1148,7 @@ static int paint_2d_canvas_set(ImagePaintState *s, Image *ima) } /* set masking */ - s->do_masking = (s->brush->flag & BRUSH_AIRBRUSH || - (s->brush->imagepaint_tool == PAINT_TOOL_SMEAR) || - (s->brush->mtex.tex && !ELEM3(s->brush->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_3D))) - ? false : true; + s->do_masking = paint_use_opacity_masking(s->brush); return 1; } @@ -1016,11 +1158,15 @@ static void paint_2d_canvas_free(ImagePaintState *s) BKE_image_release_ibuf(s->image, s->canvas, NULL); BKE_image_release_ibuf(s->brush->clone.image, s->clonecanvas, NULL); - if (s->do_masking) - image_undo_remove_masks(); + if (s->blurkernel) { + paint_delete_blur_kernel(s->blurkernel); + MEM_freeN(s->blurkernel); + } + + image_undo_remove_masks(); } -void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], int eraser) +void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], int eraser, float pressure, float distance, float size) { float newuv[2], olduv[2]; ImagePaintState *s = ps; @@ -1063,17 +1209,17 @@ void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], in /* OCIO_TODO: float buffers are now always linear, so always use color correction * this should probably be changed when texture painting color space is supported */ - brush_painter_2d_require_imbuf(painter, (ibuf->rect_float != NULL), !is_data, s->do_masking); + brush_painter_2d_require_imbuf(painter, (ibuf->rect_float != NULL), !is_data); - brush_painter_2d_refresh_cache(s, painter, newuv, mval); + brush_painter_2d_refresh_cache(s, painter, newuv, mval, pressure, distance, size); - if (paint_2d_op(s, painter->cache.ibuf, painter->cache.mask, olduv, newuv)) + if (paint_2d_op(s, painter->cache.ibuf, painter->cache.curve_mask, painter->cache.tex_mask, olduv, newuv)) s->need_redraw = true; BKE_image_release_ibuf(s->image, ibuf, NULL); } -void *paint_2d_new_stroke(bContext *C, wmOperator *op) +void *paint_2d_new_stroke(bContext *C, wmOperator *op, int mode) { Scene *scene = CTX_data_scene(C); ToolSettings *settings = scene->toolsettings; @@ -1102,10 +1248,14 @@ void *paint_2d_new_stroke(bContext *C, wmOperator *op) return NULL; } + if (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) { + s->blurkernel = paint_new_blur_kernel(brush); + } + paint_brush_init_tex(s->brush); /* create painter */ - s->painter = brush_painter_2d_new(scene, s->brush); + s->painter = brush_painter_2d_new(scene, s->brush, mode == BRUSH_STROKE_INVERT); return s; } @@ -1134,6 +1284,7 @@ void paint_2d_redraw(const bContext *C, void *ps, bool final) /* compositor listener deals with updating */ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, s->image); + DAG_id_tag_update(&s->image->id, 0); } else { if (!s->sima || !s->sima->lock) @@ -1153,3 +1304,334 @@ void paint_2d_stroke_done(void *ps) MEM_freeN(s); } + +static void paint_2d_fill_add_pixel_byte( + const int x_px, const int y_px, ImBuf *ibuf, BLI_Stack *stack, BLI_bitmap *touched, + const float color[4], float threshold_sq) +{ + int coordinate; + + if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0) + return; + + coordinate = y_px * ibuf->x + x_px; + + if (!BLI_BITMAP_TEST(touched, coordinate)) { + float color_f[4]; + unsigned char *color_b = (unsigned char *)(ibuf->rect + coordinate); + rgba_uchar_to_float(color_f, color_b); + + if (compare_len_squared_v3v3(color_f, color, threshold_sq)) { + BLI_stack_push(stack, &coordinate); + } + BLI_BITMAP_SET(touched, coordinate, true); + } +} + +static void paint_2d_fill_add_pixel_float( + const int x_px, const int y_px, ImBuf *ibuf, BLI_Stack *stack, BLI_bitmap *touched, + const float color[4], float threshold_sq) +{ + int coordinate; + + if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0) + return; + + coordinate = y_px * ibuf->x + x_px; + + if (!BLI_BITMAP_TEST(touched, coordinate)) { + if (compare_len_squared_v3v3(ibuf->rect_float + 4 * coordinate, color, threshold_sq)) { + BLI_stack_push(stack, &coordinate); + } + BLI_BITMAP_SET(touched, coordinate, true); + } +} + +/* this function expects linear space color values */ +void paint_2d_bucket_fill( + const bContext *C, const float color[3], Brush *br, + const float mouse_init[2], + void *ps) +{ + SpaceImage *sima = CTX_wm_space_image(C); + Image *ima = sima->image; + + ImagePaintState *s = ps; + + ImBuf *ibuf; + int x_px, y_px; + unsigned int color_b; + float color_f[4]; + float strength = br ? br->alpha : 1.0f; + + bool do_float; + + if (!ima) + return; + + ibuf = BKE_image_acquire_ibuf(ima, &sima->iuser, NULL); + + if (!ibuf) + return; + + do_float = (ibuf->rect_float != NULL); + /* first check if our image is float. If it is not we should correct the color to + * be in gamma space. strictly speaking this is not correct, but blender does not paint + * byte images in linear space */ + if (!do_float) { + linearrgb_to_srgb_uchar3((unsigned char *)&color_b, color); + *(((char *)&color_b) + 3) = strength * 255; + } + else { + copy_v3_v3(color_f, color); + color_f[3] = strength; + } + + if (!mouse_init || !br) { + /* first case, no image UV, fill the whole image */ + ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y); + + if (do_float) { + for (x_px = 0; x_px < ibuf->x; x_px++) { + for (y_px = 0; y_px < ibuf->y; y_px++) { + blend_color_mix_float(ibuf->rect_float + 4 * (y_px * ibuf->x + x_px), + ibuf->rect_float + 4 * (y_px * ibuf->x + x_px), color_f); + } + } + } + else { + for (x_px = 0; x_px < ibuf->x; x_px++) { + for (y_px = 0; y_px < ibuf->y; y_px++) { + blend_color_mix_byte((unsigned char *)(ibuf->rect + y_px * ibuf->x + x_px), + (unsigned char *)(ibuf->rect + y_px * ibuf->x + x_px), (unsigned char *)&color_b); + } + } + } + } + else { + /* second case, start sweeping the neighboring pixels, looking for pixels whose + * value is within the brush fill threshold from the fill color */ + BLI_Stack *stack; + BLI_bitmap *touched; + int coordinate; + int width = ibuf->x; + float image_init[2]; + int minx = ibuf->x, miny = ibuf->y, maxx = 0, maxy = 0; + float pixel_color[4]; + float threshold_sq = br->fill_threshold * br->fill_threshold; + + UI_view2d_region_to_view(s->v2d, mouse_init[0], mouse_init[1], &image_init[0], &image_init[1]); + + x_px = image_init[0] * ibuf->x; + y_px = image_init[1] * ibuf->y; + + if (x_px >= ibuf->x || x_px < 0 || y_px > ibuf->y || y_px < 0) { + BKE_image_release_ibuf(ima, ibuf, NULL); + return; + } + + /* change image invalidation method later */ + ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y); + + stack = BLI_stack_new(sizeof(int), __func__); + touched = BLI_BITMAP_NEW(ibuf->x * ibuf->y, "bucket_fill_bitmap"); + + coordinate = (y_px * ibuf->x + x_px); + + if (do_float) { + copy_v4_v4(pixel_color, ibuf->rect_float + 4 * coordinate); + } + else { + int pixel_color_b = *(ibuf->rect + coordinate); + rgba_uchar_to_float(pixel_color, (unsigned char *)&pixel_color_b); + } + + BLI_stack_push(stack, &coordinate); + BLI_BITMAP_SET(touched, coordinate, true); + + if (do_float) { + while (!BLI_stack_is_empty(stack)) { + BLI_stack_pop(stack, &coordinate); + + IMB_blend_color_float(ibuf->rect_float + 4 * (coordinate), + ibuf->rect_float + 4 * (coordinate), + color_f, br->blend); + + /* reconstruct the coordinates here */ + x_px = coordinate % width; + y_px = coordinate / width; + + paint_2d_fill_add_pixel_float(x_px - 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_float(x_px - 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_float(x_px - 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_float(x_px, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_float(x_px, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_float(x_px + 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_float(x_px + 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_float(x_px + 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq); + + if (x_px > maxx) + maxx = x_px; + if (x_px < minx) + minx = x_px; + if (y_px > maxy) + maxy = y_px; + if (x_px > miny) + miny = y_px; + } + } + else { + while (!BLI_stack_is_empty(stack)) { + BLI_stack_pop(stack, &coordinate); + + IMB_blend_color_byte((unsigned char *)(ibuf->rect + coordinate), + (unsigned char *)(ibuf->rect + coordinate), + (unsigned char *)&color_b, br->blend); + + /* reconstruct the coordinates here */ + x_px = coordinate % width; + y_px = coordinate / width; + + paint_2d_fill_add_pixel_byte(x_px - 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_byte(x_px - 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_byte(x_px - 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_byte(x_px, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_byte(x_px, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_byte(x_px + 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_byte(x_px + 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq); + paint_2d_fill_add_pixel_byte(x_px + 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq); + + if (x_px > maxx) + maxx = x_px; + if (x_px < minx) + minx = x_px; + if (y_px > maxy) + maxy = y_px; + if (x_px > miny) + miny = y_px; + } + } + + MEM_freeN(touched); + BLI_stack_free(stack); + } + + imapaint_image_update(sima, ima, ibuf, false); + ED_imapaint_clear_partial_redraw(); + + BKE_image_release_ibuf(ima, ibuf, NULL); + + WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima); +} + +void paint_2d_gradient_fill( + const bContext *C, Brush *br, + const float mouse_init[2], const float mouse_final[2], + void *ps) +{ + SpaceImage *sima = CTX_wm_space_image(C); + Image *ima = sima->image; + ImagePaintState *s = ps; + + ImBuf *ibuf; + int x_px, y_px; + unsigned int color_b; + float color_f[4]; + float image_init[2], image_final[2]; + float tangent[2]; + float line_len_sq_inv, line_len; + + bool do_float; + + if (!ima) + return; + + ibuf = BKE_image_acquire_ibuf(ima, &sima->iuser, NULL); + + if (!ibuf) + return; + + UI_view2d_region_to_view(s->v2d, mouse_final[0], mouse_final[1], &image_final[0], &image_final[1]); + UI_view2d_region_to_view(s->v2d, mouse_init[0], mouse_init[1], &image_init[0], &image_init[1]); + + image_final[0] *= ibuf->x; + image_final[1] *= ibuf->y; + + image_init[0] *= ibuf->x; + image_init[1] *= ibuf->y; + + /* some math to get needed gradient variables */ + sub_v2_v2v2(tangent, image_final, image_init); + line_len = len_squared_v2(tangent); + line_len_sq_inv = 1.0f / line_len; + line_len = sqrt(line_len); + + do_float = (ibuf->rect_float != NULL); + + /* this will be substituted by something else when selection is available */ + ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y); + + if (do_float) { + for (x_px = 0; x_px < ibuf->x; x_px++) { + for (y_px = 0; y_px < ibuf->y; y_px++) { + float f; + float p[2] = {x_px - image_init[0], y_px - image_init[1]}; + + switch (br->gradient_fill_mode) { + case BRUSH_GRADIENT_LINEAR: + { + f = dot_v2v2(p, tangent) * line_len_sq_inv; + break; + } + case BRUSH_GRADIENT_RADIAL: + { + f = len_v2(p) / line_len; + break; + } + } + do_colorband(br->gradient, f, color_f); + /* convert to premultiplied */ + mul_v3_fl(color_f, color_f[3]); + color_f[3] *= br->alpha; + IMB_blend_color_float(ibuf->rect_float + 4 * (y_px * ibuf->x + x_px), + ibuf->rect_float + 4 * (y_px * ibuf->x + x_px), + color_f, br->blend); + } + } + } + else { + for (x_px = 0; x_px < ibuf->x; x_px++) { + for (y_px = 0; y_px < ibuf->y; y_px++) { + float f; + float p[2] = {x_px - image_init[0], y_px - image_init[1]}; + + switch (br->gradient_fill_mode) { + case BRUSH_GRADIENT_LINEAR: + { + f = dot_v2v2(p, tangent) * line_len_sq_inv; + break; + } + case BRUSH_GRADIENT_RADIAL: + { + f = len_v2(p) / line_len; + break; + } + } + + do_colorband(br->gradient, f, color_f); + rgba_float_to_uchar((unsigned char *)&color_b, color_f); + ((unsigned char *)&color_b)[3] *= br->alpha; + IMB_blend_color_byte((unsigned char *)(ibuf->rect + y_px * ibuf->x + x_px), + (unsigned char *)(ibuf->rect + y_px * ibuf->x + x_px), + (unsigned char *)&color_b, br->blend); + } + } + } + + imapaint_image_update(sima, ima, ibuf, false); + ED_imapaint_clear_partial_redraw(); + + BKE_image_release_ibuf(ima, ibuf, NULL); + + WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima); +} diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 399b5044a05..e10c97ea9f0 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -48,30 +48,39 @@ #include "BLI_threads.h" #include "BLI_utildefines.h" +#include "BLF_translation.h" + #include "PIL_time.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" #include "DNA_brush_types.h" +#include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" #include "BKE_camera.h" +#include "BKE_colortools.h" #include "BKE_context.h" +#include "BKE_depsgraph.h" #include "BKE_DerivedMesh.h" #include "BKE_idprop.h" #include "BKE_brush.h" #include "BKE_image.h" #include "BKE_library.h" #include "BKE_main.h" +#include "BKE_material.h" +#include "BKE_mesh.h" #include "BKE_mesh_mapping.h" #include "BKE_paint.h" #include "BKE_report.h" #include "BKE_scene.h" +#include "BKE_texture.h" #include "UI_view2d.h" +#include "UI_interface.h" #include "ED_paint.h" #include "ED_screen.h" @@ -141,6 +150,7 @@ BLI_INLINE unsigned char f_to_char(const float val) #define PROJ_SRC_VIEW 1 #define PROJ_SRC_IMAGE_CAM 2 #define PROJ_SRC_IMAGE_VIEW 3 +#define PROJ_SRC_VIEW_FILL 4 #define PROJ_VIEW_DATA_ID "view_data" #define PROJ_VIEW_DATA_SIZE (4 * 4 + 4 * 4 + 3) /* viewmat + winmat + clipsta + clipend + is_ortho */ @@ -162,6 +172,9 @@ BLI_INLINE unsigned char f_to_char(const float val) /* vert flags */ #define PROJ_VERT_CULL 1 +/* to avoid locking in tile initialization */ +#define TILE_PENDING SET_INT_IN_POINTER(-1) + /* This is mainly a convenience struct used so we can keep an array of images we use * Thir imbufs, etc, in 1 array, When using threads this array is copied for each thread * because 'partRedrawRect' and 'touch' values would not be thread safe */ @@ -169,7 +182,10 @@ typedef struct ProjPaintImage { Image *ima; ImBuf *ibuf; ImagePaintPartialRedraw *partRedrawRect; - void **undoRect; /* only used to build undo tiles after painting */ + volatile void **undoRect; /* only used to build undo tiles during painting */ + unsigned short **maskRect; /* the mask accumulation must happen on canvas, not on space screen bucket. + * Here we store the mask rectangle */ + bool **valid; /* store flag to enforce validation of undo rectangle */ int touch; } ProjPaintImage; @@ -181,9 +197,14 @@ typedef struct ProjPaintState { Scene *scene; int source; /* PROJ_SRC_**** */ + /* the paint color. It can change depending of inverted mode or not */ + float paint_color[3]; + float paint_color_linear[3]; + Brush *brush; short tool, blend, mode; int orig_brush_size; + float brush_size; Object *ob; /* end similarities with ImagePaintState */ @@ -194,10 +215,13 @@ typedef struct ProjPaintState { MVert *dm_mvert; MFace *dm_mface; - MTFace *dm_mtface; - MTFace *dm_mtface_clone; /* other UV map, use for cloning between layers */ + MTFace **dm_mtface; + MTFace **dm_mtface_clone; /* other UV map, use for cloning between layers */ MTFace *dm_mtface_stencil; + Image *stencil_ima; + float stencil_value; + /* projection painting only */ MemArena *arena_mt[BLENDER_MAX_THREADS]; /* for multithreading, the first item is sometimes used for non threaded cases too */ LinkNode **bucketRect; /* screen sized 2D array, each pixel has a linked list of ProjPixel's */ @@ -231,6 +255,7 @@ typedef struct ProjPaintState { bool do_layer_clone; bool do_layer_stencil; bool do_layer_stencil_inv; + bool do_stencil_brush; bool do_occlude; /* Use raytraced occlusion? - ortherwise will paint right through to the back*/ bool do_backfacecull; /* ignore faces with normals pointing away, skips a lot of raycasts if your normals are correctly flipped */ @@ -245,7 +270,6 @@ typedef struct ProjPaintState { bool do_masking; /* use masking during painting. Some operations such as airbrush may disable */ bool is_texbrush; /* only to avoid running */ bool is_maskbrush; /* mask brush is applied before masking */ - bool is_maskbrush_tiled; /* mask brush is applied after masking */ #ifndef PROJ_DEBUG_NOSEAMBLEED float seam_bleed_px; #endif @@ -269,6 +293,10 @@ typedef struct ProjPaintState { /* redraw */ bool need_redraw; + + BlurKernel *blurkernel; + + SpinLock *tile_lock; } ProjPaintState; typedef union pixelPointer { @@ -290,14 +318,16 @@ typedef struct ProjPixel { * Store the max mask value to avoid painting over an area with a lower opacity * with an advantage that we can avoid touching the pixel at all, if the * new mask value is lower then mask_accum */ - unsigned short mask_accum; + unsigned short *mask_accum; /* for various reasons we may want to mask out painting onto this pixel */ unsigned short mask; short x_px, y_px; + /* horrible hack, store tile valid flag pointer here to re-validate tiles used for anchored and drag-dot strokes */ + bool *valid; - PixelStore origColor; + PixelPointer origColor; PixelStore newColor; PixelPointer pixel; @@ -310,33 +340,44 @@ typedef struct ProjPixelClone { PixelStore clonepx; } ProjPixelClone; -/* blur, store surrounding colors */ -#define PROJ_PIXEL_SOFTEN_TOT 4 -/* blur picking offset (in screenspace) */ -#define PROJ_PIXEL_SOFTEN_OFS_PX 1.0f +/* undo tile pushing */ +typedef struct { + SpinLock *lock; + bool masked; + unsigned short tile_width; + ImBuf **tmpibuf; + ProjPaintImage *pjima; +} TileInfo; -static const float proj_pixel_soften_v2[PROJ_PIXEL_SOFTEN_TOT][2] = { - {-PROJ_PIXEL_SOFTEN_OFS_PX, 0.0f}, - { 0.0f, -PROJ_PIXEL_SOFTEN_OFS_PX}, - { 0.0f, PROJ_PIXEL_SOFTEN_OFS_PX}, - { PROJ_PIXEL_SOFTEN_OFS_PX, 0.0f}, -}; /* Finish projection painting structs */ -static Image *project_paint_face_image(const ProjPaintState *ps, MTFace *dm_mtface, int face_index) +static TexPaintSlot *project_paint_face_paint_slot(const ProjPaintState *ps, int face_index) { - Image *ima; + MFace *mf = ps->dm_mface + face_index; + Material *ma = ps->dm->mat[mf->mat_nr]; + return ma->texpaintslot + ma->paint_active_slot; +} - if (ps->do_new_shading_nodes) { /* cached BKE_scene_use_new_shading_nodes result */ - MFace *mf = ps->dm_mface + face_index; - ED_object_get_active_image(ps->ob, mf->mat_nr + 1, &ima, NULL, NULL); +static Image *project_paint_face_paint_image(const ProjPaintState *ps, int face_index) +{ + if (ps->do_stencil_brush) { + return ps->stencil_ima; } else { - ima = dm_mtface[face_index].tpage; + MFace *mf = ps->dm_mface + face_index; + Material *ma = ps->dm->mat[mf->mat_nr]; + TexPaintSlot *slot = ma->texpaintslot + ma->paint_active_slot; + return slot ? slot->ima : NULL; } +} + - return ima; +static TexPaintSlot *project_paint_face_clone_slot(const ProjPaintState *ps, int face_index) +{ + MFace *mf = ps->dm_mface + face_index; + Material *ma = ps->dm->mat[mf->mat_nr]; + return &ma->texpaintslot[ma->paint_clone_slot]; } /* fast projection bucket array lookup, use the safe version for bound checking */ @@ -477,8 +518,8 @@ static int project_paint_PickFace(const ProjPaintState *ps, const float pt[2], f static void uvco_to_wrapped_pxco(const float uv[2], int ibuf_x, int ibuf_y, float *x, float *y) { /* use */ - *x = (float)fmodf(uv[0], 1.0f); - *y = (float)fmodf(uv[1], 1.0f); + *x = fmodf(uv[0], 1.0f); + *y = fmodf(uv[1], 1.0f); if (*x < 0.0f) *x += 1.0f; if (*y < 0.0f) *y += 1.0f; @@ -505,7 +546,7 @@ static bool project_paint_PickColor(const ProjPaintState *ps, const float pt[2], if (face_index == -1) return 0; - tf = ps->dm_mtface + face_index; + tf = *(ps->dm_mtface + face_index); if (side == 0) { interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[1], tf->uv[2], w); @@ -514,8 +555,9 @@ static bool project_paint_PickColor(const ProjPaintState *ps, const float pt[2], interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[2], tf->uv[3], w); } - ima = project_paint_face_image(ps, ps->dm_mtface, face_index); + ima = project_paint_face_paint_image(ps, face_index); ibuf = BKE_image_get_first_ibuf(ima); /* we must have got the imbuf before getting here */ + if (!ibuf) return 0; if (interp) { float x, y; @@ -762,11 +804,11 @@ static int line_isect_x(const float p1[2], const float p2[2], const float x_leve static bool cmp_uv(const float vec2a[2], const float vec2b[2]) { /* if the UV's are not between 0.0 and 1.0 */ - float xa = (float)fmodf(vec2a[0], 1.0f); - float ya = (float)fmodf(vec2a[1], 1.0f); + float xa = fmodf(vec2a[0], 1.0f); + float ya = fmodf(vec2a[1], 1.0f); - float xb = (float)fmodf(vec2b[0], 1.0f); - float yb = (float)fmodf(vec2b[1], 1.0f); + float xb = fmodf(vec2b[0], 1.0f); + float yb = fmodf(vec2b[1], 1.0f); if (xa < 0.0f) xa += 1.0f; if (ya < 0.0f) ya += 1.0f; @@ -843,7 +885,7 @@ static bool pixel_bounds_array(float (*uv)[2], rcti *bounds_px, const int ibuf_x static void project_face_winding_init(const ProjPaintState *ps, const int face_index) { /* detect the winding of faces in uv space */ - MTFace *tf = ps->dm_mtface + face_index; + MTFace *tf = ps->dm_mtface[face_index]; float winding = cross_tri_v2(tf->uv[0], tf->uv[1], tf->uv[2]); if (ps->dm_mface[face_index].v4) @@ -868,7 +910,7 @@ static bool check_seam(const ProjPaintState *ps, MFace *mf; MTFace *tf; const MFace *orig_mf = ps->dm_mface + orig_face; - const MTFace *orig_tf = ps->dm_mtface + orig_face; + const MTFace *orig_tf = ps->dm_mtface[orig_face]; /* vert indices from face vert order indices */ i1 = (*(&orig_mf->v1 + orig_i1_fidx)); @@ -890,13 +932,13 @@ static bool check_seam(const ProjPaintState *ps, /* Only need to check if 'i2_fidx' is valid because we know i1_fidx is the same vert on both faces */ if (i2_fidx != -1) { - Image *tpage = project_paint_face_image(ps, ps->dm_mtface, face_index); - Image *orig_tpage = project_paint_face_image(ps, ps->dm_mtface, orig_face); + Image *tpage = project_paint_face_paint_image(ps, face_index); + Image *orig_tpage = project_paint_face_paint_image(ps, orig_face); BLI_assert(i1_fidx != -1); /* This IS an adjacent face!, now lets check if the UVs are ok */ - tf = ps->dm_mtface + face_index; + tf = ps->dm_mtface[face_index]; /* set up the other face */ *other_face = face_index; @@ -909,7 +951,7 @@ static bool check_seam(const ProjPaintState *ps, /* first test if they have the same image */ if ((orig_tpage == tpage) && cmp_uv(orig_tf->uv[orig_i1_fidx], tf->uv[i1_fidx]) && - cmp_uv(orig_tf->uv[orig_i2_fidx], tf->uv[i2_fidx]) ) + cmp_uv(orig_tf->uv[orig_i2_fidx], tf->uv[i2_fidx])) { /* if faces don't have the same winding in uv space, * they are on the same side so edge is boundary */ @@ -1168,7 +1210,7 @@ static float project_paint_uvpixel_mask( if (ps->do_layer_stencil) { /* another UV maps image is masking this one's */ ImBuf *ibuf_other; - Image *other_tpage = project_paint_face_image(ps, ps->dm_mtface_stencil, face_index); + Image *other_tpage = ps->stencil_ima; const MTFace *tf_other = ps->dm_mtface_stencil + face_index; if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) { @@ -1296,24 +1338,70 @@ static int project_paint_pixel_sizeof(const short tool) } } +static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty) +{ + ProjPaintImage *pjIma = tinf->pjima; + int tile_index = tx + ty * tinf->tile_width; + bool generate_tile = false; + + /* double check lock to avoid locking */ + if (UNLIKELY(!pjIma->undoRect[tile_index])) { + if (tinf->lock) + BLI_spin_lock(tinf->lock); + if (LIKELY(!pjIma->undoRect[tile_index])) { + pjIma->undoRect[tile_index] = TILE_PENDING; + generate_tile = true; + } + if (tinf->lock) + BLI_spin_unlock(tinf->lock); + } + + + if (generate_tile) { + volatile void *undorect; + if (tinf->masked) { + undorect = image_undo_push_tile(pjIma->ima, pjIma->ibuf, tinf->tmpibuf, tx, ty, &pjIma->maskRect[tile_index], &pjIma->valid[tile_index], true); + } + else { + undorect = image_undo_push_tile(pjIma->ima, pjIma->ibuf, tinf->tmpibuf, tx, ty, NULL, &pjIma->valid[tile_index], true); + } + + pjIma->ibuf->userflags |= IB_BITMAPDIRTY; + /* tile ready, publish */ + if (tinf->lock) + BLI_spin_lock(tinf->lock); + pjIma->undoRect[tile_index] = undorect; + if (tinf->lock) + BLI_spin_unlock(tinf->lock); + + } + + return tile_index; +} /* run this function when we know a bucket's, face's pixel can be initialized, * return the ProjPixel which is added to 'ps->bucketRect[bucket_index]' */ static ProjPixel *project_paint_uvpixel_init( const ProjPaintState *ps, MemArena *arena, - const ImBuf *ibuf, + const TileInfo *tinf, int x_px, int y_px, const float mask, const int face_index, - const int image_index, const float pixelScreenCo[4], const float world_spaceCo[3], const int side, const float w[3]) { ProjPixel *projPixel; - + int x_tile, y_tile; + int x_round, y_round; + int tile_offset; + /* volatile is important here to ensure pending check is not optimized away by compiler*/ + volatile int tile_index; + + ProjPaintImage *projima = tinf->pjima; + ImBuf *ibuf = projima->ibuf; /* wrap pixel location */ x_px = mod_i(x_px, ibuf->x); @@ -1321,19 +1409,36 @@ static ProjPixel *project_paint_uvpixel_init( BLI_assert(ps->pixel_sizeof == project_paint_pixel_sizeof(ps->tool)); projPixel = (ProjPixel *)BLI_memarena_alloc(arena, ps->pixel_sizeof); + + /* calculate the undo tile offset of the pixel, used to store the original + * pixel color and accumulated mask if any */ + x_tile = x_px >> IMAPAINT_TILE_BITS; + y_tile = y_px >> IMAPAINT_TILE_BITS; + + x_round = x_tile * IMAPAINT_TILE_SIZE; + y_round = y_tile * IMAPAINT_TILE_SIZE; //memset(projPixel, 0, size); + tile_offset = (x_px - x_round) + (y_px - y_round) * IMAPAINT_TILE_SIZE; + tile_index = project_paint_undo_subtiles(tinf, x_tile, y_tile); + + /* other thread may be initializing the tile so wait here */ + while (projima->undoRect[tile_index] == TILE_PENDING) + ; + + BLI_assert(tile_index < (IMAPAINT_TILE_NUMBER(ibuf->x) * IMAPAINT_TILE_NUMBER(ibuf->y))); + BLI_assert(tile_offset < (IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE)); + + projPixel->valid = projima->valid[tile_index]; + if (ibuf->rect_float) { projPixel->pixel.f_pt = ibuf->rect_float + ((x_px + y_px * ibuf->x) * 4); - projPixel->origColor.f[0] = projPixel->pixel.f_pt[0]; - projPixel->origColor.f[1] = projPixel->pixel.f_pt[1]; - projPixel->origColor.f[2] = projPixel->pixel.f_pt[2]; - projPixel->origColor.f[3] = projPixel->pixel.f_pt[3]; + projPixel->origColor.f_pt = (float *)projima->undoRect[tile_index] + 4 * tile_offset; zero_v4(projPixel->newColor.f); } else { - projPixel->pixel.ch_pt = ((unsigned char *)ibuf->rect + ((x_px + y_px * ibuf->x) * 4)); - projPixel->origColor.uint = *projPixel->pixel.uint_pt; + projPixel->pixel.ch_pt = (unsigned char *)(ibuf->rect + (x_px + y_px * ibuf->x)); + projPixel->origColor.uint_pt = (unsigned int *)projima->undoRect[tile_index] + tile_offset; projPixel->newColor.uint = 0; } @@ -1348,7 +1453,10 @@ static ProjPixel *project_paint_uvpixel_init( projPixel->y_px = y_px; projPixel->mask = (unsigned short)(mask * 65535); - projPixel->mask_accum = 0; + if (ps->do_masking) + projPixel->mask_accum = projima->maskRect[tile_index] + tile_offset; + else + projPixel->mask_accum = NULL; /* which bounding box cell are we in?, needed for undo */ projPixel->bb_cell_index = ((int)(((float)x_px / (float)ibuf->x) * PROJ_BOUNDBOX_DIV)) + @@ -1358,8 +1466,8 @@ static ProjPixel *project_paint_uvpixel_init( if (ps->tool == PAINT_TOOL_CLONE) { if (ps->dm_mtface_clone) { ImBuf *ibuf_other; - Image *other_tpage = project_paint_face_image(ps, ps->dm_mtface_clone, face_index); - const MTFace *tf_other = ps->dm_mtface_clone + face_index; + Image *other_tpage = project_paint_face_clone_slot(ps, face_index)->ima; + const MTFace *tf_other = ps->dm_mtface_clone[face_index]; if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) { /* BKE_image_acquire_ibuf - TODO - this may be slow */ @@ -1423,7 +1531,8 @@ static ProjPixel *project_paint_uvpixel_init( if (ibuf->rect_float) projPixel->pixel.f_pt[0] = 0; else projPixel->pixel.ch_pt[0] = 0; #endif - projPixel->image_index = image_index; + /* pointer arithmetics */ + projPixel->image_index = projima - ps->projImages; return projPixel; } @@ -2131,15 +2240,24 @@ static bool IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot /* One of the most important function for projection painting, since it selects the pixels to be added into each bucket. * initialize pixels from this face where it intersects with the bucket_index, optionally initialize pixels for removing seams */ -static void project_paint_face_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const int face_index, const int image_index, rctf *bucket_bounds, const ImBuf *ibuf, const short clamp_u, const short clamp_v) +static void project_paint_face_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const int face_index, const int image_index, rctf *bucket_bounds, ImBuf *ibuf, ImBuf **tmpibuf, const short clamp_u, const short clamp_v) { /* Projection vars, to get the 3D locations into screen space */ MemArena *arena = ps->arena_mt[thread_index]; LinkNode **bucketPixelNodes = ps->bucketRect + bucket_index; LinkNode *bucketFaceNodes = ps->bucketFaces[bucket_index]; + bool threaded = (ps->thread_tot > 1); + + TileInfo tinf = { + ps->tile_lock, + ps->do_masking, + IMAPAINT_TILE_NUMBER(ibuf->x), + tmpibuf, + ps->projImages + image_index + }; const MFace *mf = ps->dm_mface + face_index; - const MTFace *tf = ps->dm_mtface + face_index; + const MTFace *tf = ps->dm_mtface[face_index]; /* UV/pixel seeking data */ int x; /* Image X-Pixel */ @@ -2183,8 +2301,8 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i /* Use tf_uv_pxoffset instead of tf->uv so we can offset the UV half a pixel * this is done so we can avoid offsetting all the pixels by 0.5 which causes * problems when wrapping negative coords */ - xhalfpx = (0.5f + (PROJ_GEOM_TOLERANCE * (1.0f / 3.0f))) / ibuf_xf; - yhalfpx = (0.5f + (PROJ_GEOM_TOLERANCE * (1.0f / 4.0f))) / ibuf_yf; + xhalfpx = (0.5f + (PROJ_PIXEL_TOLERANCE * (1.0f / 3.0f))) / ibuf_xf; + yhalfpx = (0.5f + (PROJ_PIXEL_TOLERANCE * (1.0f / 4.0f))) / ibuf_yf; /* Note about (PROJ_GEOM_TOLERANCE/x) above... * Needed to add this offset since UV coords are often quads aligned to pixels. @@ -2258,6 +2376,10 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i CLAMP(bounds_px.ymax, 0, ibuf->y); } + /* + project_paint_undo_tiles_init(&bounds_px, ps->projImages + image_index, tmpibuf, + tile_width, threaded, ps->do_masking); + */ /* clip face and */ has_isect = 0; @@ -2300,8 +2422,8 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i if (mask > 0.0f) { BLI_linklist_prepend_arena( bucketPixelNodes, - project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index, - image_index, pixelScreenCo, wco, side, w), + project_paint_uvpixel_init(ps, arena, &tinf, x, y, mask, face_index, + pixelScreenCo, wco, side, w), arena ); } @@ -2333,7 +2455,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i if (ps->seam_bleed_px > 0.0f) { int face_seam_flag; - if (ps->thread_tot > 1) + if (threaded) BLI_lock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */ face_seam_flag = ps->faceSeamFlags[face_index]; @@ -2351,7 +2473,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i if ((face_seam_flag & (PROJ_FACE_SEAM1 | PROJ_FACE_SEAM2 | PROJ_FACE_SEAM3 | PROJ_FACE_SEAM4)) == 0) { - if (ps->thread_tot > 1) + if (threaded) BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */ } @@ -2376,7 +2498,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i uv_image_outset(tf_uv_pxoffset, outset_uv, ps->seam_bleed_px, ibuf->x, ibuf->y, mf->v4 != 0); /* ps->faceSeamUVs cant be modified when threading, now this is done we can unlock */ - if (ps->thread_tot > 1) + if (threaded) BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */ vCoSS[0] = ps->screenCoords[mf->v1]; @@ -2520,7 +2642,8 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i if (mask > 0.0f) { BLI_linklist_prepend_arena( bucketPixelNodes, - project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index, image_index, pixelScreenCo, wco, side, w), + project_paint_uvpixel_init(ps, arena, &tinf, x, y, mask, face_index, + pixelScreenCo, wco, side, w), arena ); } @@ -2589,6 +2712,7 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index ImBuf *ibuf = NULL; Image *tpage_last = NULL, *tpage; Image *ima = NULL; + ImBuf *tmpibuf = NULL; if (ps->image_tot == 1) { /* Simple loop, no context switching */ @@ -2596,7 +2720,7 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index ima = ps->projImages[0].ima; for (node = ps->bucketFaces[bucket_index]; node; node = node->next) { - project_paint_face_init(ps, thread_index, bucket_index, GET_INT_FROM_POINTER(node->link), 0, bucket_bounds, ibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V); + project_paint_face_init(ps, thread_index, bucket_index, GET_INT_FROM_POINTER(node->link), 0, bucket_bounds, ibuf, &tmpibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V); } } else { @@ -2606,7 +2730,7 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index face_index = GET_INT_FROM_POINTER(node->link); /* Image context switching */ - tpage = project_paint_face_image(ps, ps->dm_mtface, face_index); + tpage = project_paint_face_paint_image(ps, face_index); if (tpage_last != tpage) { tpage_last = tpage; @@ -2620,10 +2744,13 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index } /* context switching done */ - project_paint_face_init(ps, thread_index, bucket_index, face_index, image_index, bucket_bounds, ibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V); + project_paint_face_init(ps, thread_index, bucket_index, face_index, image_index, bucket_bounds, ibuf, &tmpibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V); } } + if (tmpibuf) + IMB_freeImBuf(tmpibuf); + ps->bucketFlags[bucket_index] |= PROJ_BUCKET_INIT; } @@ -2771,11 +2898,17 @@ static void project_paint_begin(ProjPaintState *ps) ProjPaintImage *projIma; Image *tpage_last = NULL, *tpage; + TexPaintSlot *slot_last = NULL, *slot = NULL; + TexPaintSlot *slot_last_clone = NULL, *slot_clone; /* Face vars */ MPoly *mpoly_orig; MFace *mf; - MTFace *tf; + MTFace **tf; + MTFace *tf_base; + + MTFace **tf_clone; + MTFace *tf_clone_base; int a, i; /* generic looping vars */ int image_index = -1, face_index; @@ -2830,13 +2963,15 @@ static void project_paint_begin(ProjPaintState *ps) return; } - ps->dm_mvert = ps->dm->getVertArray(ps->dm); - ps->dm_mface = ps->dm->getTessFaceArray(ps->dm); - ps->dm_mtface = ps->dm->getTessFaceDataArray(ps->dm, CD_MTFACE); + DM_update_materials(ps->dm, ps->ob); ps->dm_totvert = ps->dm->getNumVerts(ps->dm); ps->dm_totface = ps->dm->getNumTessFaces(ps->dm); + ps->dm_mvert = ps->dm->getVertArray(ps->dm); + ps->dm_mface = ps->dm->getTessFaceArray(ps->dm); + ps->dm_mtface = MEM_mallocN(ps->dm_totface * sizeof(MTFace *), "proj_paint_mtfaces"); + if (ps->do_face_sel) { index_mf_to_mpoly = ps->dm->getTessFaceDataArray(ps->dm, CD_ORIGINDEX); index_mp_to_orig = ps->dm->getPolyDataArray(ps->dm, CD_ORIGINDEX); @@ -2852,32 +2987,23 @@ static void project_paint_begin(ProjPaintState *ps) } /* use clone mtface? */ - - - /* Note, use the original mesh for getting the clone and mask layer index - * this avoids re-generating the derived mesh just to get the new index */ if (ps->do_layer_clone) { - //int layer_num = CustomData_get_clone_layer(&ps->dm->faceData, CD_MTFACE); - int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->data)->pdata, CD_MTEXPOLY); - if (layer_num != -1) - ps->dm_mtface_clone = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num); - - if (ps->dm_mtface_clone == NULL || ps->dm_mtface_clone == ps->dm_mtface) { - ps->do_layer_clone = false; - ps->dm_mtface_clone = NULL; - } + ps->dm_mtface_clone = MEM_mallocN(ps->dm_totface * sizeof(MTFace *), "proj_paint_mtfaces"); } - if (ps->do_layer_stencil) { + if (ps->do_layer_stencil || ps->do_stencil_brush) { //int layer_num = CustomData_get_stencil_layer(&ps->dm->faceData, CD_MTFACE); int layer_num = CustomData_get_stencil_layer(&((Mesh *)ps->ob->data)->pdata, CD_MTEXPOLY); if (layer_num != -1) ps->dm_mtface_stencil = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num); - if (ps->dm_mtface_stencil == NULL || ps->dm_mtface_stencil == ps->dm_mtface) { - ps->do_layer_stencil = false; - ps->dm_mtface_stencil = NULL; + if (ps->dm_mtface_stencil == NULL) { + /* get active instead */ + ps->dm_mtface_stencil = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE); } + + if (ps->do_stencil_brush) + tf_base = ps->dm_mtface_stencil; } /* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */ @@ -3092,6 +3218,13 @@ static void project_paint_begin(ProjPaintState *ps) if (reset_threads) ps->thread_tot = 1; + if (ps->thread_tot > 1) { + ps->tile_lock = MEM_mallocN(sizeof(SpinLock), "projpaint_tile_lock"); + BLI_spin_init(ps->tile_lock); + } + + image_undo_init_locks(); + for (a = 0; a < ps->thread_tot; a++) { ps->arena_mt[a] = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "project paint arena"); } @@ -3153,7 +3286,48 @@ static void project_paint_begin(ProjPaintState *ps) is_face_sel = true; } - if (is_face_sel && (tpage = project_paint_face_image(ps, ps->dm_mtface, face_index))) { + if (!ps->do_stencil_brush) { + slot = project_paint_face_paint_slot(ps, face_index); + /* all faces should have a valid slot, reassert here */ + if (slot == NULL) { + tf_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE); + } + else { + if (slot != slot_last) { + if (!slot->uvname || !(tf_base = CustomData_get_layer_named(&ps->dm->faceData, CD_MTFACE, slot->uvname))) + tf_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE); + slot_last = slot; + } + + /* don't allow using the same inage for painting and stencilling */ + if (slot->ima == ps->stencil_ima) + continue; + } + } + + *tf = tf_base + face_index; + + if (ps->do_layer_clone) { + slot_clone = project_paint_face_clone_slot(ps, face_index); + /* all faces should have a valid slot, reassert here */ + if (ELEM(slot_clone, NULL, slot)) + continue; + + tf_clone = ps->dm_mtface_clone + face_index; + + if (slot_clone != slot_last_clone) { + if (!slot->uvname || !(tf_clone_base = CustomData_get_layer_named(&ps->dm->faceData, CD_MTFACE, slot_clone->uvname))) + tf_clone_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE); + slot_last_clone = slot_clone; + } + + *tf_clone = tf_clone_base + face_index; + } + + /* tfbase here should be non-null! */ + BLI_assert (tf_base != NULL); + + if (is_face_sel && ((slot && (tpage = slot->ima)) || (tpage = project_paint_face_paint_image(ps, face_index)))) { const float *v1coSS, *v2coSS, *v3coSS, *v4coSS = NULL; v1coSS = ps->screenCoords[mf->v1]; @@ -3251,10 +3425,19 @@ static void project_paint_begin(ProjPaintState *ps) projIma = ps->projImages = (ProjPaintImage *)BLI_memarena_alloc(arena, sizeof(ProjPaintImage) * ps->image_tot); for (node = image_LinkList, i = 0; node; node = node->next, i++, projIma++) { + int size; projIma->ima = node->link; projIma->touch = 0; projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, NULL, NULL); - projIma->partRedrawRect = BLI_memarena_calloc(arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); + size = sizeof(void **) * IMAPAINT_TILE_NUMBER(projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(projIma->ibuf->y); + projIma->partRedrawRect = BLI_memarena_alloc(arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); + memset(projIma->partRedrawRect, 0, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); + projIma->undoRect = (volatile void **) BLI_memarena_alloc(arena, size); + memset(projIma->undoRect, 0, size); + projIma->maskRect = (unsigned short **) BLI_memarena_alloc(arena, size); + memset(projIma->maskRect, 0, size); + projIma->valid = (bool **) BLI_memarena_alloc(arena, size); + memset(projIma->valid, 0, size); } /* we have built the array, discard the linked list */ @@ -3281,95 +3464,12 @@ static void project_paint_end(ProjPaintState *ps) int a; ProjPaintImage *projIma; - /* build undo data from original pixel colors */ - if (U.uiflag & USER_GLOBALUNDO) { - ProjPixel *projPixel; - ImBuf *tmpibuf = NULL, *tmpibuf_float = NULL; - LinkNode *pixel_node; - void *tilerect; - MemArena *arena = ps->arena_mt[0]; /* threaded arena re-used for non threaded case */ - - int bucket_tot = (ps->buckets_x * ps->buckets_y); /* we could get an X/Y but easier to loop through all possible buckets */ - int bucket_index; - int tile_index; - int x_round, y_round; - int x_tile, y_tile; - int is_float = -1; - - /* context */ - ProjPaintImage *last_projIma; - int last_image_index = -1; - int last_tile_width = 0; - - for (a = 0, last_projIma = ps->projImages; a < ps->image_tot; a++, last_projIma++) { - int size = sizeof(void **) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->y); - last_projIma->undoRect = (void **) BLI_memarena_calloc(arena, size); - last_projIma->ibuf->userflags |= IB_BITMAPDIRTY; - } - - for (bucket_index = 0; bucket_index < bucket_tot; bucket_index++) { - /* loop through all pixels */ - for (pixel_node = ps->bucketRect[bucket_index]; pixel_node; pixel_node = pixel_node->next) { - - /* ok we have a pixel, was it modified? */ - projPixel = (ProjPixel *)pixel_node->link; - - if (last_image_index != projPixel->image_index) { - /* set the context */ - last_image_index = projPixel->image_index; - last_projIma = ps->projImages + last_image_index; - last_tile_width = IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x); - is_float = last_projIma->ibuf->rect_float ? 1 : 0; - } - - - if ((is_float == 0 && projPixel->origColor.uint != *projPixel->pixel.uint_pt) || - (is_float == 1 && - (projPixel->origColor.f[0] != projPixel->pixel.f_pt[0] || - projPixel->origColor.f[1] != projPixel->pixel.f_pt[1] || - projPixel->origColor.f[2] != projPixel->pixel.f_pt[2] || - projPixel->origColor.f[3] != projPixel->pixel.f_pt[3])) - ) - { - - x_tile = projPixel->x_px >> IMAPAINT_TILE_BITS; - y_tile = projPixel->y_px >> IMAPAINT_TILE_BITS; - - x_round = x_tile * IMAPAINT_TILE_SIZE; - y_round = y_tile * IMAPAINT_TILE_SIZE; - - tile_index = x_tile + y_tile * last_tile_width; - - if (last_projIma->undoRect[tile_index] == NULL) { - /* add the undo tile from the modified image, then write the original colors back into it */ - tilerect = last_projIma->undoRect[tile_index] = image_undo_push_tile(last_projIma->ima, last_projIma->ibuf, is_float ? (&tmpibuf_float) : (&tmpibuf), x_tile, y_tile); - } - else { - tilerect = last_projIma->undoRect[tile_index]; - } - - /* This is a BIT ODD, but overwrite the undo tiles image info with this pixels original color - * because allocating the tiles along the way slows down painting */ - - if (is_float) { - float *rgba_fp = (float *)tilerect + (((projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE)) * 4; - copy_v4_v4(rgba_fp, projPixel->origColor.f); - } - else { - ((unsigned int *)tilerect)[(projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE] = projPixel->origColor.uint; - } - } - } - } - - if (tmpibuf) IMB_freeImBuf(tmpibuf); - if (tmpibuf_float) IMB_freeImBuf(tmpibuf_float); - } - /* done calculating undo data */ + image_undo_remove_masks(); /* dereference used image buffers */ for (a = 0, projIma = ps->projImages; a < ps->image_tot; a++, projIma++) { BKE_image_release_ibuf(projIma->ima, projIma->ibuf, NULL); + DAG_id_tag_update(&projIma->ima->id, 0); } BKE_image_release_ibuf(ps->reproject_image, ps->reproject_ibuf, NULL); @@ -3378,6 +3478,14 @@ static void project_paint_end(ProjPaintState *ps) MEM_freeN(ps->bucketRect); MEM_freeN(ps->bucketFaces); MEM_freeN(ps->bucketFlags); + MEM_freeN(ps->dm_mtface); + if (ps->do_layer_clone) + MEM_freeN(ps->dm_mtface_clone); + if (ps->thread_tot > 1) { + BLI_spin_end(ps->tile_lock); + MEM_freeN((void *)ps->tile_lock); + } + image_undo_end_locks(); #ifndef PROJ_DEBUG_NOSEAMBLEED if (ps->seam_bleed_px > 0.0f) { @@ -3388,6 +3496,11 @@ static void project_paint_end(ProjPaintState *ps) } #endif + if (ps->blurkernel) { + paint_delete_blur_kernel(ps->blurkernel); + MEM_freeN(ps->blurkernel); + } + if (ps->vertFlags) MEM_freeN(ps->vertFlags); for (a = 0; a < ps->thread_tot; a++) { @@ -3480,7 +3593,7 @@ static bool project_bucket_iter_init(ProjPaintState *ps, const float mval_f[2]) { if (ps->source == PROJ_SRC_VIEW) { float min_brush[2], max_brush[2]; - const float radius = (float)BKE_brush_size_get(ps->scene, ps->brush); + const float radius = ps->brush_size; /* so we don't have a bucket bounds that is way too small to paint into */ // if (radius < 1.0f) radius = 1.0f; // this doesn't work yet :/ @@ -3518,7 +3631,7 @@ static bool project_bucket_iter_init(ProjPaintState *ps, const float mval_f[2]) static bool project_bucket_iter_next(ProjPaintState *ps, int *bucket_index, rctf *bucket_bounds, const float mval[2]) { - const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush); + const int diameter = 2 * ps->brush_size; if (ps->thread_tot > 1) BLI_lock_thread(LOCK_CUSTOM1); @@ -3580,7 +3693,7 @@ static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, floa clone_rgba[3] = (unsigned char)(clone_pt[3] * mask); if (ps->do_masking) { - IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch, clone_rgba, ps->blend); + IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, clone_rgba, ps->blend); } else { IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, clone_rgba, ps->blend); @@ -3598,7 +3711,7 @@ static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, fl mul_v4_v4fl(clone_rgba, clone_pt, mask); if (ps->do_masking) { - IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f, clone_rgba, ps->blend); + IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, clone_rgba, ps->blend); } else { IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, clone_rgba, ps->blend); @@ -3636,42 +3749,58 @@ static void do_projectpaint_smear_f(ProjPaintState *ps, ProjPixel *projPixel, fl BLI_linklist_prepend_arena(smearPixels_f, (void *)projPixel, smearArena); } -/* do_projectpaint_soften for float & byte - */ -static float inv_pow2(float f) -{ - f = 1.0f - f; - f = f * f; - return 1.0f - f; -} - static void do_projectpaint_soften_f(ProjPaintState *ps, ProjPixel *projPixel, float mask, MemArena *softenArena, LinkNode **softenPixels) { - unsigned int accum_tot = 0; - unsigned int i; - + float accum_tot = 0.0; + int xk, yk; + BlurKernel *kernel = ps->blurkernel; float *rgba = projPixel->newColor.f; - /* sigh, mask values tend to need to be a _lot_ stronger with blur */ - mask = inv_pow2(mask); - /* rather then painting, accumulate surrounding colors */ zero_v4(rgba); - for (i = 0; i < PROJ_PIXEL_SOFTEN_TOT; i++) { - float co_ofs[2]; - float rgba_tmp[4]; - sub_v2_v2v2(co_ofs, projPixel->projCoSS, proj_pixel_soften_v2[i]); - if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, true)) { - add_v4_v4(rgba, rgba_tmp); - accum_tot++; + for (yk = 0; yk < kernel->side; yk++) { + for (xk = 0; xk < kernel->side; xk++) { + float rgba_tmp[4]; + float co_ofs[2] = {xk - kernel->pixel_len, yk - kernel->pixel_len}; + + add_v2_v2(co_ofs, projPixel->projCoSS); + + if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, true)) { + float weight = kernel->wdata[xk + yk * kernel->side]; + mul_v4_fl(rgba_tmp, weight); + add_v4_v4(rgba, rgba_tmp); + accum_tot += weight; + } } } if (LIKELY(accum_tot != 0)) { mul_v4_fl(rgba, 1.0f / (float)accum_tot); - blend_color_interpolate_float(rgba, rgba, projPixel->pixel.f_pt, mask); + + if (ps->mode == BRUSH_STROKE_INVERT) { + /* subtract blurred image from normal image gives high pass filter */ + sub_v3_v3v3(rgba, projPixel->pixel.f_pt, rgba); + + /* now rgba_ub contains the edge result, but this should be converted to luminance to avoid + * colored speckles appearing in final image, and also to check for threshold */ + rgba[0] = rgba[1] = rgba[2] = rgb_to_grayscale(rgba); + if (fabsf(rgba[0]) > ps->brush->sharp_threshold) { + float alpha = projPixel->pixel.f_pt[3]; + projPixel->pixel.f_pt[3] = rgba[3] = mask; + + /* add to enhance edges */ + blend_color_add_float(rgba, projPixel->pixel.f_pt, rgba); + projPixel->pixel.f_pt[3] = alpha; + } + else + return; + } + else { + blend_color_interpolate_float(rgba, rgba, projPixel->pixel.f_pt, mask); + } + BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena); } } @@ -3679,24 +3808,27 @@ static void do_projectpaint_soften_f(ProjPaintState *ps, ProjPixel *projPixel, f static void do_projectpaint_soften(ProjPaintState *ps, ProjPixel *projPixel, float mask, MemArena *softenArena, LinkNode **softenPixels) { - unsigned int accum_tot = 0; - unsigned int i; - + float accum_tot = 0; + int xk, yk; + BlurKernel *kernel = ps->blurkernel; float rgba[4]; /* convert to byte after */ - /* sigh, mask values tend to need to be a _lot_ stronger with blur */ - mask = inv_pow2(mask); - /* rather then painting, accumulate surrounding colors */ zero_v4(rgba); - for (i = 0; i < PROJ_PIXEL_SOFTEN_TOT; i++) { - float co_ofs[2]; - float rgba_tmp[4]; - sub_v2_v2v2(co_ofs, projPixel->projCoSS, proj_pixel_soften_v2[i]); - if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, true)) { - add_v4_v4(rgba, rgba_tmp); - accum_tot++; + for (yk = 0; yk < kernel->side; yk++) { + for (xk = 0; xk < kernel->side; xk++) { + float rgba_tmp[4]; + float co_ofs[2] = {xk - kernel->pixel_len, yk - kernel->pixel_len}; + + add_v2_v2(co_ofs, projPixel->projCoSS); + + if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, true)) { + float weight = kernel->wdata[xk + yk * kernel->side]; + mul_v4_fl(rgba_tmp, weight); + add_v4_v4(rgba, rgba_tmp); + accum_tot += weight; + } } } @@ -3704,9 +3836,34 @@ static void do_projectpaint_soften(ProjPaintState *ps, ProjPixel *projPixel, flo unsigned char *rgba_ub = projPixel->newColor.ch; mul_v4_fl(rgba, 1.0f / (float)accum_tot); - premul_float_to_straight_uchar(rgba_ub, rgba); - blend_color_interpolate_byte(rgba_ub, rgba_ub, projPixel->pixel.ch_pt, mask); + if (ps->mode == BRUSH_STROKE_INVERT) { + float rgba_pixel[4]; + + straight_uchar_to_premul_float(rgba_pixel, projPixel->pixel.ch_pt); + + /* subtract blurred image from normal image gives high pass filter */ + sub_v3_v3v3(rgba, rgba_pixel, rgba); + /* now rgba_ub contains the edge result, but this should be converted to luminance to avoid + * colored speckles appearing in final image, and also to check for threshold */ + rgba[0] = rgba[1] = rgba[2] = rgb_to_grayscale(rgba); + if (fabsf(rgba[0]) > ps->brush->sharp_threshold) { + float alpha = rgba_pixel[3]; + rgba[3] = rgba_pixel[3] = mask; + + /* add to enhance edges */ + blend_color_add_float(rgba, rgba_pixel, rgba); + + rgba[3] = alpha; + premul_float_to_straight_uchar(rgba_ub, rgba); + } + else + return; + } + else { + premul_float_to_straight_uchar(rgba_ub, rgba); + blend_color_interpolate_byte(rgba_ub, rgba_ub, projPixel->pixel.ch_pt, mask); + } BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena); } } @@ -3716,7 +3873,7 @@ static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, const float rgb[3]; unsigned char rgba_ub[4]; - copy_v3_v3(rgb, ps->brush->rgb); + copy_v3_v3(rgb, ps->paint_color); if (ps->is_texbrush) { mul_v3_v3(rgb, texrgb); @@ -3728,7 +3885,7 @@ static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, const rgba_ub[3] = f_to_char(mask); if (ps->do_masking) { - IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch, rgba_ub, ps->blend); + IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, rgba_ub, ps->blend); } else { IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, rgba_ub, ps->blend); @@ -3739,7 +3896,7 @@ static void do_projectpaint_draw_f(ProjPaintState *ps, ProjPixel *projPixel, con { float rgba[4]; - srgb_to_linearrgb_v3_v3(rgba, ps->brush->rgb); + copy_v3_v3(rgba, ps->paint_color_linear); if (ps->is_texbrush) mul_v3_v3(rgba, texrgb); @@ -3748,13 +3905,42 @@ static void do_projectpaint_draw_f(ProjPaintState *ps, ProjPixel *projPixel, con rgba[3] = mask; if (ps->do_masking) { - IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f, rgba, ps->blend); + IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, rgba, ps->blend); + } + else { + IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, rgba, ps->blend); + } +} + +static void do_projectpaint_mask(ProjPaintState *ps, ProjPixel *projPixel, float mask) +{ + unsigned char rgba_ub[4]; + rgba_ub[0] = rgba_ub[1] = rgba_ub[2] = ps->stencil_value * 255.0f; + rgba_ub[3] = f_to_char(mask); + + if (ps->do_masking) { + IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, rgba_ub, ps->blend); + } + else { + IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, rgba_ub, ps->blend); + } +} + +static void do_projectpaint_mask_f(ProjPaintState *ps, ProjPixel *projPixel, float mask) +{ + float rgba[4]; + rgba[0] = rgba[1] = rgba[2] = ps->stencil_value; + rgba[3] = mask; + + if (ps->do_masking) { + IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, rgba, ps->blend); } else { IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, rgba, ps->blend); } } + /* run this for single and multithreaded painting */ static void *do_projectpaint_thread(void *ph_v) { @@ -3788,7 +3974,7 @@ static void *do_projectpaint_thread(void *ph_v) float co[2]; unsigned short mask_short; const float brush_alpha = BKE_brush_alpha_get(ps->scene, brush); - const float brush_radius = (float)BKE_brush_size_get(ps->scene, brush); + const float brush_radius = ps->brush_size; const float brush_radius_sq = brush_radius * brush_radius; /* avoid a square root with every dist comparison */ short lock_alpha = ELEM(brush->blend, IMB_BLEND_ERASE_ALPHA, IMB_BLEND_ADD_ALPHA) ? 0 : brush->flag & BRUSH_LOCK_ALPHA; @@ -3838,32 +4024,102 @@ static void *do_projectpaint_thread(void *ph_v) } /* end copy */ - if (is_floatbuf) { - /* re-project buffer is assumed byte - TODO, allow float */ - bicubic_interpolation_color(ps->reproject_ibuf, projPixel->newColor.ch, NULL, - projPixel->projCoSS[0], projPixel->projCoSS[1]); - if (projPixel->newColor.ch[3]) { - float newColor_f[4]; - float mask = ((float)projPixel->mask) * (1.0f / 65535.0f); + /* fill tools */ + if (ps->source == PROJ_SRC_VIEW_FILL) { + if (brush->flag & BRUSH_USE_GRADIENT) { + /* these could probably be cached instead of being done per pixel */ + float tangent[2]; + float line_len_sq_inv, line_len; + float f; + float color_f[4]; + float p[2] = {projPixel->projCoSS[0] - lastpos[0], projPixel->projCoSS[1] - lastpos[1]}; + + sub_v2_v2v2(tangent, pos, lastpos); + line_len = len_squared_v2(tangent); + line_len_sq_inv = 1.0f / line_len; + line_len = sqrt(line_len); + + switch (brush->gradient_fill_mode) { + case BRUSH_GRADIENT_LINEAR: + { + f = dot_v2v2(p, tangent) * line_len_sq_inv; + break; + } + case BRUSH_GRADIENT_RADIAL: + { + f = len_v2(p) / line_len; + break; + } + } + do_colorband(brush->gradient, f, color_f); + color_f[3] *= ((float)projPixel->mask) * (1.0f / 65535.0f) * brush->alpha; + + if (is_floatbuf) { + /* convert to premultipied */ + mul_v3_fl(color_f, color_f[3]); + IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, + color_f, ps->blend); + } + else { + rgba_float_to_uchar(projPixel->newColor.ch, color_f); + IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, + projPixel->newColor.ch, ps->blend); + } + } + else { + if (is_floatbuf) { + float newColor_f[4]; + newColor_f[3] = ((float)projPixel->mask) * (1.0f / 65535.0f) * brush->alpha; + copy_v3_v3(newColor_f, ps->paint_color_linear); - straight_uchar_to_premul_float(newColor_f, projPixel->newColor.ch); - IMB_colormanagement_colorspace_to_scene_linear_v4(newColor_f, true, ps->reproject_ibuf->rect_colorspace); - mul_v4_v4fl(newColor_f, newColor_f, mask); + IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, + newColor_f, ps->blend); + } + else { + float mask = ((float)projPixel->mask) * (1.0f / 65535.0f); + projPixel->newColor.ch[3] = mask * 255 * brush->alpha; - blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f, - newColor_f); + rgb_float_to_uchar(projPixel->newColor.ch, ps->paint_color); + IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, + projPixel->newColor.ch, ps->blend); + } } + + last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index; + last_partial_redraw_cell->x1 = min_ii(last_partial_redraw_cell->x1, (int)projPixel->x_px); + last_partial_redraw_cell->y1 = min_ii(last_partial_redraw_cell->y1, (int)projPixel->y_px); + + last_partial_redraw_cell->x2 = max_ii(last_partial_redraw_cell->x2, (int)projPixel->x_px + 1); + last_partial_redraw_cell->y2 = max_ii(last_partial_redraw_cell->y2, (int)projPixel->y_px + 1); } else { - /* re-project buffer is assumed byte - TODO, allow float */ - bicubic_interpolation_color(ps->reproject_ibuf, projPixel->newColor.ch, NULL, - projPixel->projCoSS[0], projPixel->projCoSS[1]); - if (projPixel->newColor.ch[3]) { - float mask = ((float)projPixel->mask) * (1.0f / 65535.0f); - projPixel->newColor.ch[3] *= mask; - - blend_color_mix_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch, - projPixel->newColor.ch); + if (is_floatbuf) { + /* re-project buffer is assumed byte - TODO, allow float */ + bicubic_interpolation_color(ps->reproject_ibuf, projPixel->newColor.ch, NULL, + projPixel->projCoSS[0], projPixel->projCoSS[1]); + if (projPixel->newColor.ch[3]) { + float newColor_f[4]; + float mask = ((float)projPixel->mask) * (1.0f / 65535.0f); + + straight_uchar_to_premul_float(newColor_f, projPixel->newColor.ch); + IMB_colormanagement_colorspace_to_scene_linear_v4(newColor_f, true, ps->reproject_ibuf->rect_colorspace); + mul_v4_v4fl(newColor_f, newColor_f, mask); + + blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, + newColor_f); + } + } + else { + /* re-project buffer is assumed byte - TODO, allow float */ + bicubic_interpolation_color(ps->reproject_ibuf, projPixel->newColor.ch, NULL, + projPixel->projCoSS[0], projPixel->projCoSS[1]); + if (projPixel->newColor.ch[3]) { + float mask = ((float)projPixel->mask) * (1.0f / 65535.0f); + projPixel->newColor.ch[3] *= mask; + + blend_color_mix_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, + projPixel->newColor.ch); + } } } } @@ -3885,7 +4141,7 @@ static void *do_projectpaint_thread(void *ph_v) if (falloff > 0.0f) { float texrgb[3]; - float mask = falloff; + float mask; if (ps->do_masking) { /* masking to keep brush contribution to a pixel limited. note we do not do @@ -3894,20 +4150,24 @@ static void *do_projectpaint_thread(void *ph_v) * * Instead we use a formula that adds up but approaches brush_alpha slowly * and never exceeds it, which gives nice smooth results. */ - float mask_accum = projPixel->mask_accum; + float mask_accum = *projPixel->mask_accum; + float max_mask = brush_alpha * falloff * 65535.0f; if (ps->is_maskbrush) { float texmask = BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool); - CLAMP(texmask, 0.0f, 1.0f); - mask = mask_accum + (brush_alpha * texmask * 65535.0f - mask_accum) * mask; - } - else { - mask = mask_accum + (brush_alpha * 65535.0f - mask_accum) * mask; + max_mask *= texmask; } + + if (brush->flag & BRUSH_ACCUMULATE) + mask = mask_accum + max_mask; + else + mask = mask_accum + (max_mask - mask_accum * falloff); + + mask = min_ff(mask, 65535.0f); mask_short = (unsigned short)mask; - if (mask_short > projPixel->mask_accum) { - projPixel->mask_accum = mask_short; + if (mask_short > *projPixel->mask_accum) { + *projPixel->mask_accum = mask_short; mask = mask_short * (1.0f / 65535.0f); } else { @@ -3916,7 +4176,7 @@ static void *do_projectpaint_thread(void *ph_v) } } else { - mask *= brush_alpha; + mask = brush_alpha * falloff; if (ps->is_maskbrush) { float texmask = BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool); CLAMP(texmask, 0.0f, 1.0f); @@ -3945,10 +4205,6 @@ static void *do_projectpaint_thread(void *ph_v) mask *= texrgba[3]; } - if (ps->is_maskbrush_tiled) { - mask *= BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool); - } - /* extra mask for normal, layer stencil, .. */ mask *= ((float)projPixel->mask) * (1.0f / 65535.0f); @@ -3964,6 +4220,9 @@ static void *do_projectpaint_thread(void *ph_v) } /* end copy */ + /* validate undo tile, since we will modify t*/ + *projPixel->valid = true; + last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index; last_partial_redraw_cell->x1 = min_ii(last_partial_redraw_cell->x1, (int)projPixel->x_px); last_partial_redraw_cell->y1 = min_ii(last_partial_redraw_cell->y1, (int)projPixel->y_px); @@ -3987,6 +4246,10 @@ static void *do_projectpaint_thread(void *ph_v) if (is_floatbuf) do_projectpaint_soften_f(ps, projPixel, mask, softenArena, &softenPixels_f); else do_projectpaint_soften(ps, projPixel, mask, softenArena, &softenPixels); break; + case PAINT_TOOL_MASK: + if (is_floatbuf) do_projectpaint_mask_f(ps, projPixel, mask); + else do_projectpaint_mask(ps, projPixel, mask); + break; default: if (is_floatbuf) do_projectpaint_draw_f(ps, projPixel, texrgb, mask); else do_projectpaint_draw(ps, projPixel, texrgb, mask); @@ -3995,8 +4258,8 @@ static void *do_projectpaint_thread(void *ph_v) } if (lock_alpha) { - if (is_floatbuf) projPixel->pixel.f_pt[3] = projPixel->origColor.f[3]; - else projPixel->pixel.ch_pt[3] = projPixel->origColor.ch[3]; + if (is_floatbuf) projPixel->pixel.f_pt[3] = projPixel->origColor.f_pt[3]; + else projPixel->pixel.ch_pt[3] = projPixel->origColor.ch_pt[3]; } /* done painting */ @@ -4114,14 +4377,17 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po } -void paint_proj_stroke(bContext *C, void *pps, const float prev_pos[2], const float pos[2]) +void paint_proj_stroke(const bContext *C, void *pps, const float prev_pos[2], const float pos[2], float pressure, float distance, float size) { ProjPaintState *ps = pps; + Brush *brush = ps->brush; + Scene *scene = ps->scene; int a; + ps->brush_size = size; + /* clone gets special treatment here to avoid going through image initialization */ if (ps->tool == PAINT_TOOL_CLONE && ps->mode == BRUSH_STROKE_INVERT) { - Scene *scene = ps->scene; View3D *v3d = ps->v3d; float *cursor = ED_view3d_cursor3d_get(scene, v3d); int mval_i[2] = {(int)pos[0], (int)pos[1]}; @@ -4136,6 +4402,25 @@ void paint_proj_stroke(bContext *C, void *pps, const float prev_pos[2], const fl return; } + /* handle gradient and inverted stroke color here */ + if (ps->tool == PAINT_TOOL_DRAW) { + paint_brush_color_get(scene, brush, false, ps->mode == BRUSH_STROKE_INVERT, distance, pressure, ps->paint_color, NULL); + srgb_to_linearrgb_v3_v3(ps->paint_color_linear, ps->paint_color); + } + else if (ps->tool == PAINT_TOOL_FILL) { + copy_v3_v3(ps->paint_color, BKE_brush_color_get(scene, brush)); + srgb_to_linearrgb_v3_v3(ps->paint_color_linear, ps->paint_color); + } + else if (ps->tool == PAINT_TOOL_MASK) { + ps->stencil_value = brush->weight; + + if ((ps->mode == BRUSH_STROKE_INVERT) ^ + ((scene->toolsettings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) != 0)) + { + ps->stencil_value = 1.0f - ps->stencil_value; + } + } + /* continue adding to existing partial redraw rects until redraw */ if (!ps->need_redraw) { for (a = 0; a < ps->image_tot; a++) @@ -4160,30 +4445,24 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int Brush *brush = ps->brush; ps->tool = brush->imagepaint_tool; ps->blend = brush->blend; + /* only check for inversion for the soften tool, elsewhere, a resident brush inversion flag can cause issues */ + if (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) { + ps->mode = ((ps->mode == BRUSH_STROKE_INVERT) ^ ((brush->flag & BRUSH_DIR_IN) != 0) ? + BRUSH_STROKE_INVERT : BRUSH_STROKE_NORMAL); + + ps->blurkernel = paint_new_blur_kernel(brush); + } /* disable for 3d mapping also because painting on mirrored mesh can create "stripes" */ - ps->do_masking = (brush->flag & BRUSH_AIRBRUSH || - (brush->imagepaint_tool == PAINT_TOOL_SMEAR) || - (brush->mtex.tex && !ELEM3(brush->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_3D))) - ? false : true; + ps->do_masking = paint_use_opacity_masking(brush); ps->is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ? true : false; - ps->is_maskbrush = false; - ps->is_maskbrush_tiled = false; - if (brush->mask_mtex.tex) { - if (ELEM(brush->mask_mtex.brush_map_mode, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_TILED)) { - ps->is_maskbrush_tiled = true; - } - else { - ps->is_maskbrush = true; - } - } + ps->is_maskbrush = (brush->mask_mtex.tex) ? true : false; } else { /* brush may be NULL*/ ps->do_masking = false; ps->is_texbrush = false; ps->is_maskbrush = false; - ps->is_maskbrush_tiled = false; } /* sizeof(ProjPixel), since we alloc this a _lot_ */ @@ -4198,6 +4477,7 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int ps->scene = scene; ps->ob = ob; /* allow override of active object */ + ps->stencil_ima = settings->imapaint.stencil; /* setup projection painting data */ ps->do_backfacecull = (settings->imapaint.flag & IMAGEPAINT_PROJECT_BACKFACE) ? 0 : 1; ps->do_occlude = (settings->imapaint.flag & IMAGEPAINT_PROJECT_XRAY) ? 0 : 1; @@ -4207,8 +4487,11 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int if (ps->tool == PAINT_TOOL_CLONE) ps->do_layer_clone = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) ? 1 : 0; - ps->do_layer_stencil = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL) ? 1 : 0; - ps->do_layer_stencil_inv = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) ? 1 : 0; + ps->do_stencil_brush = ps->brush->imagepaint_tool == PAINT_TOOL_MASK; + /* deactivate stenciling for the stencil brush :) */ + ps->do_layer_stencil = ((settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL) && + !(ps->do_stencil_brush) && ps->stencil_ima); + ps->do_layer_stencil_inv = ((settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) != 0); #ifndef PROJ_DEBUG_NOSEAMBLEED @@ -4236,6 +4519,7 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int mode) { ProjPaintState *ps = MEM_callocN(sizeof(ProjPaintState), "ProjectionPaintState"); + project_state_init(C, ob, ps, mode); if (ps->tool == PAINT_TOOL_CLONE && mode == BRUSH_STROKE_INVERT) { @@ -4268,6 +4552,10 @@ void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int m paint_proj_begin_clone(ps, mouse); + /* special full screen draw mode for fill tool */ + if (ps->tool == PAINT_TOOL_FILL) + ps->source = PROJ_SRC_VIEW_FILL; + return ps; } @@ -4316,8 +4604,11 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op) int orig_brush_size; IDProperty *idgroup; IDProperty *view_data = NULL; + Object *ob = OBACT; + + paint_proj_mesh_data_ensure(C, ob, op); - project_state_init(C, OBACT, &ps, BRUSH_STROKE_NORMAL); + project_state_init(C, ob, &ps, BRUSH_STROKE_NORMAL); if (ps.ob == NULL || ps.ob->type != OB_MESH) { BKE_report(op->reports, RPT_ERROR, "No active mesh object"); @@ -4365,7 +4656,6 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op) /* override */ ps.is_texbrush = false; ps.is_maskbrush = false; - ps.is_maskbrush_tiled = false; ps.do_masking = false; orig_brush_size = BKE_brush_size_get(scene, ps.brush); BKE_brush_size_set(scene, ps.brush, 32); /* cover the whole image */ @@ -4375,7 +4665,7 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op) scene->toolsettings->imapaint.flag |= IMAGEPAINT_DRAWING; ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name, - ED_image_undo_restore, ED_image_undo_free); + ED_image_undo_restore, ED_image_undo_free, NULL); /* allocate and initialize spatial data structures */ project_paint_begin(&ps); @@ -4508,3 +4798,162 @@ void PAINT_OT_image_from_view(wmOperatorType *ot) RNA_def_string_file_name(ot->srna, "filepath", NULL, FILE_MAX, "File Path", "Name of the file"); } + +/* Add layer operator */ + +static EnumPropertyItem layer_type_items[] = { + {MAP_COL, "DIFFUSE_COLOR", 0, "Diffuse Color", ""}, + {MAP_REF, "DIFFUSE_INTENSITY", 0, "Diffuse Intensity", ""}, + {MAP_ALPHA, "ALPHA", 0, "Alpha", ""}, + {MAP_TRANSLU, "TRANSLUCENCY", 0, "Translucency", ""}, + {MAP_COLSPEC, "SPECULAR_COLOR", 0, "Specular Color", ""}, + {MAP_SPEC, "SPECULAR_INTENSITY", 0, "Specular Intensity", ""}, + {MAP_HAR, "SPECULAR_HARDNESS", 0, "Specular Hardness", ""}, + {MAP_AMB, "AMBIENT", 0, "Ambient", ""}, + {MAP_EMIT, "EMMIT", 0, "Emmit", ""}, + {MAP_COLMIR, "MIRROR_COLOR", 0, "Mirror Color", ""}, + {MAP_RAYMIRR, "RAYMIRROR", 0, "Ray Mirror", ""}, + {MAP_NORM, "NORMAL", 0, "Normal", ""}, + {MAP_WARP, "WARP", 0, "Warp", ""}, + {MAP_DISPLACE, "DISPLACE", 0, "Displace", ""}, + {0, NULL, 0, NULL, NULL} +}; + +bool proj_paint_add_slot(bContext *C, Material *ma, wmOperator *op) +{ + Object *ob = CTX_data_active_object(C); + Scene *scene = CTX_data_scene(C); + bool use_nodes = BKE_scene_use_new_shading_nodes(scene); + + if (!ob) + return false; + + if (!ma) + ma = give_current_material(ob, ob->actcol); + + if (ma) { + + if (use_nodes) { + /* not supported for now */ + } + else { + MTex *mtex = add_mtex_id(&ma->id, -1); + + /* successful creation of mtex layer, now create set */ + if (mtex) { + Main *bmain = CTX_data_main(C); + Image *ima; + int type = MAP_COL; + + if (op) + type = RNA_enum_get(op->ptr, "type"); + + mtex->tex = add_texture(bmain, DATA_(layer_type_items[type].name)); + mtex->mapto = type; + + if (mtex->tex) { + float color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + char imagename[MAX_ID_NAME - 2] = "Material Diffuse Color"; + int width = 1024; + int height = 1024; + bool use_float = false; + short gen_type = IMA_GENTYPE_BLANK; + bool alpha = false; + + if (op) { + width = RNA_int_get(op->ptr, "width"); + height = RNA_int_get(op->ptr, "height"); + use_float = RNA_boolean_get(op->ptr, "float"); + gen_type = RNA_enum_get(op->ptr, "generated_type"); + RNA_float_get_array(op->ptr, "color", color); + alpha = RNA_boolean_get(op->ptr, "alpha"); + RNA_string_get(op->ptr, "name", imagename); + } + + if (!use_float) { + /* crappy workaround because we only upload straight color to OpenGL and that makes + * painting result on viewport too opaque */ + color[3] = 1.0; + } + + ima = mtex->tex->ima = BKE_image_add_generated(bmain, width, height, imagename, alpha ? 32 : 24, use_float, + gen_type, color); + + BKE_texpaint_slot_refresh_cache(ma, false); + BKE_image_signal(ima, NULL, IMA_SIGNAL_USER_NEW_IMAGE); + WM_event_add_notifier(C, NC_TEXTURE | NA_ADDED, mtex->tex); + WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima); + ED_area_tag_redraw(CTX_wm_area(C)); + } + + WM_event_add_notifier(C, NC_TEXTURE, CTX_data_scene(C)); + return true; + } + } + } + + return false; +} + +static int texture_paint_add_texture_paint_slot_exec(bContext *C, wmOperator *op) +{ + return proj_paint_add_slot(C, NULL, op); +} + + +static int texture_paint_add_texture_paint_slot_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + char imagename[MAX_ID_NAME - 2]; + Object *ob = CTX_data_active_object(C); + Material *ma = give_current_material(ob, ob->actcol); + int type = RNA_enum_get(op->ptr, "type"); + + type = RNA_enum_from_value(layer_type_items, type); + + /* get the name of the texture layer type */ + BLI_assert(type != -1); + + /* take the second letter to avoid the ID identifier */ + BLI_snprintf(imagename, FILE_MAX, "%s %s", &ma->id.name[2], layer_type_items[type].name); + + RNA_string_set(op->ptr, "name", imagename); + return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, 5 * UI_UNIT_Y); +} + +#define IMA_DEF_NAME N_("Untitled") + + +void PAINT_OT_add_texture_paint_slot(wmOperatorType *ot) +{ + PropertyRNA *prop; + static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + + /* identifiers */ + ot->name = "Add Texture Paint Slot"; + ot->description = "Add a texture paint slot"; + ot->idname = "PAINT_OT_add_texture_paint_slot"; + + /* api callbacks */ + ot->invoke = texture_paint_add_texture_paint_slot_invoke; + ot->exec = texture_paint_add_texture_paint_slot_exec; + ot->poll = ED_operator_region_view3d_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_enum(ot->srna, "type", layer_type_items, 0, "Type", "Merge method to use"); + RNA_def_property_flag(prop, PROP_HIDDEN); + RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image datablock name"); + prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384); + RNA_def_property_subtype(prop, PROP_PIXEL); + prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384); + RNA_def_property_subtype(prop, PROP_PIXEL); + prop = RNA_def_float_color(ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f); + RNA_def_property_subtype(prop, PROP_COLOR_GAMMA); + RNA_def_property_float_array_default(prop, default_color); + RNA_def_boolean(ot->srna, "alpha", 1, "Alpha", "Create an image with an alpha channel"); + RNA_def_enum(ot->srna, "generated_type", image_generated_type_items, IMA_GENTYPE_BLANK, + "Generated Type", "Fill the image with a grid for UV map testing"); + RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth"); +} diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index b20c1756d75..fb4bedb6906 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -38,7 +38,9 @@ struct bglMats; struct Brush; struct ImagePool; struct ColorSpace; +struct ColorManagedDisplay; struct ListBase; +struct Material; struct Mesh; struct MTex; struct Object; @@ -65,7 +67,7 @@ typedef void (*StrokeUpdateStep)(struct bContext *C, struct PaintStroke *stroke, typedef void (*StrokeRedraw)(const struct bContext *C, struct PaintStroke *stroke, bool final); typedef void (*StrokeDone)(const struct bContext *C, struct PaintStroke *stroke); -struct PaintStroke *paint_stroke_new(struct bContext *C, +struct PaintStroke *paint_stroke_new(struct bContext *C, struct wmOperator *op, StrokeGetLocation get_location, StrokeTestStart test_start, StrokeUpdateStep update_step, StrokeRedraw redraw, StrokeDone done, int event_type); @@ -84,6 +86,7 @@ int paint_stroke_exec(struct bContext *C, struct wmOperator *op); void paint_stroke_cancel(struct bContext *C, struct wmOperator *op); struct ViewContext *paint_stroke_view_context(struct PaintStroke *stroke); void *paint_stroke_mode_data(struct PaintStroke *stroke); +float paint_stroke_distance_get(struct PaintStroke *stroke); void paint_stroke_set_mode_data(struct PaintStroke *stroke, void *mode_data); int paint_poll(struct bContext *C); void paint_cursor_start(struct bContext *C, int (*poll)(struct bContext *C)); @@ -117,7 +120,7 @@ void PAINT_OT_weight_gradient(struct wmOperatorType *ot); void PAINT_OT_vertex_paint_toggle(struct wmOperatorType *ot); void PAINT_OT_vertex_paint(struct wmOperatorType *ot); -unsigned int vpaint_get_current_col(struct VPaint *vp); +unsigned int vpaint_get_current_col(struct Scene *scene, struct VPaint *vp); /* paint_vertex_proj.c */ @@ -144,32 +147,42 @@ typedef struct ImagePaintPartialRedraw { #define IMAPAINT_TILE_NUMBER(size) (((size) + IMAPAINT_TILE_SIZE - 1) >> IMAPAINT_TILE_BITS) int image_texture_paint_poll(struct bContext *C); -void *image_undo_find_tile(struct Image *ima, struct ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask); -void *image_undo_push_tile(struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile); +void *image_undo_find_tile(struct Image *ima, struct ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate); +void *image_undo_push_tile(struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **, bool **valid, bool proj); void image_undo_remove_masks(void); +void image_undo_init_locks(void); +void image_undo_end_locks(void); + void imapaint_image_update(struct SpaceImage *sima, struct Image *image, struct ImBuf *ibuf, short texpaint); struct ImagePaintPartialRedraw *get_imapaintpartial(void); void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr); void imapaint_region_tiles(struct ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th); int get_imapaint_zoom(struct bContext *C, float *zoomx, float *zoomy); -void *paint_2d_new_stroke(struct bContext *, struct wmOperator *); +void *paint_2d_new_stroke(struct bContext *, struct wmOperator *, int mode); void paint_2d_redraw(const bContext *C, void *ps, bool final); void paint_2d_stroke_done(void *ps); -void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], int eraser); +void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], int eraser, float pressure, float distance, float size); +void paint_2d_bucket_fill(const struct bContext *C, const float color[3], struct Brush *br, const float mouse_init[2], void *ps); +void paint_2d_gradient_fill (const struct bContext *C, struct Brush *br, const float mouse_init[2], const float mouse_final[2], void *ps); void *paint_proj_new_stroke(struct bContext *C, struct Object *ob, const float mouse[2], int mode); -void paint_proj_stroke(struct bContext *C, void *ps, const float prevmval_i[2], const float mval_i[2]); -void paint_proj_redraw(const bContext *C, void *pps, bool final); +void paint_proj_stroke(const struct bContext *C, void *ps, const float prevmval_i[2], const float mval_i[2], float pressure, float distance, float size); +void paint_proj_redraw(const struct bContext *C, void *pps, bool final); void paint_proj_stroke_done(void *ps); +void paint_proj_mesh_data_ensure(bContext *C, struct Object *ob, struct wmOperator *op); +bool proj_paint_add_slot(bContext *C, struct Material *ma, struct wmOperator *op); + +void paint_brush_color_get(struct Scene *scene, struct Brush *br, bool color_correction, bool invert, float distance, float pressure, float color[3], struct ColorManagedDisplay *display); +bool paint_use_opacity_masking(struct Brush *brush); void paint_brush_init_tex(struct Brush *brush); void paint_brush_exit_tex(struct Brush *brush); void PAINT_OT_grab_clone(struct wmOperatorType *ot); void PAINT_OT_sample_color(struct wmOperatorType *ot); +void PAINT_OT_brush_colors_flip(struct wmOperatorType *ot); void PAINT_OT_texture_paint_toggle(struct wmOperatorType *ot); void PAINT_OT_project_image(struct wmOperatorType *ot); void PAINT_OT_image_from_view(struct wmOperatorType *ot); - -/* new texture painting */ +void PAINT_OT_add_texture_paint_slot(struct wmOperatorType *ot); void PAINT_OT_image_paint(struct wmOperatorType *ot); /* uv sculpting */ @@ -202,7 +215,7 @@ float paint_calc_object_space_radius(struct ViewContext *vc, const float center[ float paint_get_tex_pixel(struct MTex *mtex, float u, float v, struct ImagePool *pool, int thread); void paint_get_tex_pixel_col(struct MTex *mtex, float u, float v, float rgba[4], struct ImagePool *pool, int thread, bool convert, struct ColorSpace *colorspace); -void paint_sample_color(const struct bContext *C, struct ARegion *ar, int x, int y); +void paint_sample_color(bContext *C, struct ARegion *ar, int x, int y, bool texpaint_proj, bool palette); void BRUSH_OT_curve_preset(struct wmOperatorType *ot); void PAINT_OT_face_select_linked(struct wmOperatorType *ot); @@ -213,8 +226,10 @@ void PAINT_OT_face_select_reveal(struct wmOperatorType *ot); void PAINT_OT_vert_select_all(struct wmOperatorType *ot); void PAINT_OT_vert_select_ungrouped(struct wmOperatorType *ot); + int vert_paint_poll(struct bContext *C); int mask_paint_poll(struct bContext *C); +int paint_curve_poll(struct bContext *C); int facemask_paint_poll(struct bContext *C); void flip_v3_v3(float out[3], const float in[3], const char symm); @@ -229,7 +244,6 @@ typedef enum BrushStrokeMode { /* paint_undo.c */ struct ListBase *undo_paint_push_get_list(int type); void undo_paint_push_count_alloc(int type, int size); -bool sculpt_undo_cleanup(struct bContext *C, struct ListBase *lb); /* paint_hide.c */ @@ -258,4 +272,29 @@ typedef enum { void PAINT_OT_mask_flood_fill(struct wmOperatorType *ot); void PAINT_OT_mask_lasso_gesture(struct wmOperatorType *ot); +/* paint_curve.c */ +void PAINTCURVE_OT_new(struct wmOperatorType *ot); +void PAINTCURVE_OT_add_point(struct wmOperatorType *ot); +void PAINTCURVE_OT_delete_point(struct wmOperatorType *ot); +void PAINTCURVE_OT_select(struct wmOperatorType *ot); +void PAINTCURVE_OT_slide(struct wmOperatorType *ot); +void PAINTCURVE_OT_draw(struct wmOperatorType *ot); +void PAINTCURVE_OT_cursor(struct wmOperatorType *ot); + +/* image painting blur kernel */ +typedef struct { + float *wdata; /* actual kernel */ + int side; /* kernel side */ + int side_squared; /* data side */ + int pixel_len; /* pixels around center that kernel is wide */ +} BlurKernel; + +enum BlurKernelType; +/* can be extended to other blur kernels later */ +BlurKernel *paint_new_blur_kernel(struct Brush *br); +void paint_delete_blur_kernel(BlurKernel *); + +/* paint curve defines */ +#define PAINT_CURVE_NUM_SEGMENTS 40 + #endif /* __PAINT_INTERN_H__ */ diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index b3f81f379f3..8faa4cfaf33 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -115,7 +115,7 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op) sculpt_undo_push_begin("Mask flood fill"); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (i = 0; i < totnode; i++) { PBVHVertexIter vi; @@ -236,7 +236,7 @@ int ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *r BKE_pbvh_search_gather(pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (i = 0; i < totnode; i++) { PBVHVertexIter vi; bool any_masked = false; @@ -385,7 +385,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) /* gather nodes inside lasso's enclosing rectangle (should greatly help with bigger meshes) */ BKE_pbvh_search_gather(pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (i = 0; i < totnode; i++) { PBVHVertexIter vi; bool any_masked = false; diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index 9021581d47f..3605ce5f280 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -149,11 +149,112 @@ static void BRUSH_OT_scale_size(wmOperatorType *ot) RNA_def_float(ot->srna, "scalar", 1, 0, 2, "Scalar", "Factor to scale brush size by", 0, 2); } +/* Palette operators */ + +static int palette_new_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Paint *paint = BKE_paint_get_active_from_context(C); + Main *bmain = CTX_data_main(C); + Palette *palette; + + palette = BKE_palette_add(bmain, "Palette"); + + BKE_paint_palette_set(paint, palette); + + return OPERATOR_FINISHED; +} + +static void PALETTE_OT_new(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add New Palette"; + ot->description = "Add new palette"; + ot->idname = "PALETTE_OT_new"; + + /* api callbacks */ + ot->exec = palette_new_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static int palette_poll(bContext *C) +{ + Paint *paint = BKE_paint_get_active_from_context(C); + + if (paint && paint->palette != NULL) + return true; + + return false; +} + +static int palette_color_add_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Scene *scene = CTX_data_scene(C); + Paint *paint = BKE_paint_get_active_from_context(C); + Brush *brush = paint->brush; + PaintMode mode = BKE_paintmode_get_active_from_context(C); + Palette *palette = paint->palette; + PaletteColor *color = BKE_palette_color_add(palette); + + if (ELEM(mode, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D, PAINT_VERTEX)) { + copy_v3_v3(color->rgb, BKE_brush_color_get(scene, brush)); + color->value = 0.0; + } + else if (mode == PAINT_WEIGHT) { + zero_v3(color->rgb); + color->value = brush->weight; + } + + return OPERATOR_FINISHED; +} + +static void PALETTE_OT_color_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "New Palette Color"; + ot->description = "Add new color to active palette"; + ot->idname = "PALETTE_OT_color_add"; + + /* api callbacks */ + ot->exec = palette_color_add_exec; + ot->poll = palette_poll; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + + +static int palette_color_delete_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Paint *paint = BKE_paint_get_active_from_context(C); + Palette *palette = paint->palette; + + BKE_palette_color_delete(palette); + + return OPERATOR_FINISHED; +} + +static void PALETTE_OT_color_delete(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Delete Palette Color"; + ot->description = "Remove active color from palette"; + ot->idname = "PALETTE_OT_color_delete"; + + /* api callbacks */ + ot->exec = palette_color_delete_exec; + ot->poll = palette_poll; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + + + static int vertex_color_set_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); Object *obact = CTX_data_active_object(C); - unsigned int paintcol = vpaint_get_current_col(scene->toolsettings->vpaint); + unsigned int paintcol = vpaint_get_current_col(scene, scene->toolsettings->vpaint); if (ED_vpaint_fill(obact, paintcol)) { ED_region_tag_redraw(CTX_wm_region(C)); // XXX - should redraw all 3D views @@ -332,6 +433,7 @@ static int brush_generic_tool_set(Main *bmain, Paint *paint, const int tool, if (brush) { BKE_paint_brush_set(paint, brush); BKE_paint_invalidate_overlay_all(); + WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush); return OPERATOR_FINISHED; } @@ -928,8 +1030,37 @@ static void ed_keymap_stencil(wmKeyMap *keymap) /**************************** registration **********************************/ +void ED_operatormacros_paint(void) +{ + wmOperatorType *ot; + wmOperatorTypeMacro *otmacro; + + ot = WM_operatortype_append_macro("PAINTCURVE_OT_add_point_slide", "Add Curve Point and Slide", + "Add new curve point and slide it", OPTYPE_UNDO); + ot->description = "Add new curve point and slide it"; + WM_operatortype_macro_define(ot, "PAINTCURVE_OT_add_point"); + otmacro = WM_operatortype_macro_define(ot, "PAINTCURVE_OT_slide"); + RNA_boolean_set(otmacro->ptr, "align", true); + RNA_boolean_set(otmacro->ptr, "select", false); +} + + void ED_operatortypes_paint(void) { + /* palette */ + WM_operatortype_append(PALETTE_OT_new); + WM_operatortype_append(PALETTE_OT_color_add); + WM_operatortype_append(PALETTE_OT_color_delete); + + /* paint curve */ + WM_operatortype_append(PAINTCURVE_OT_new); + WM_operatortype_append(PAINTCURVE_OT_add_point); + WM_operatortype_append(PAINTCURVE_OT_delete_point); + WM_operatortype_append(PAINTCURVE_OT_select); + WM_operatortype_append(PAINTCURVE_OT_slide); + WM_operatortype_append(PAINTCURVE_OT_draw); + WM_operatortype_append(PAINTCURVE_OT_cursor); + /* brush */ WM_operatortype_append(BRUSH_OT_add); WM_operatortype_append(BRUSH_OT_scale_size); @@ -950,6 +1081,8 @@ void ED_operatortypes_paint(void) WM_operatortype_append(PAINT_OT_grab_clone); WM_operatortype_append(PAINT_OT_project_image); WM_operatortype_append(PAINT_OT_image_from_view); + WM_operatortype_append(PAINT_OT_brush_colors_flip); + WM_operatortype_append(PAINT_OT_add_texture_paint_slot); /* weight */ WM_operatortype_append(PAINT_OT_weight_paint_toggle); @@ -1119,12 +1252,44 @@ static void paint_partial_visibility_keys(wmKeyMap *keymap) RNA_enum_set(kmi->ptr, "area", PARTIALVIS_ALL); } + +static void paint_keymap_curve(wmKeyMap *keymap) +{ + wmKeyMapItem *kmi; + + WM_keymap_add_item(keymap, "PAINTCURVE_OT_add_point_slide", ACTIONMOUSE, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "PAINTCURVE_OT_select", SELECTMOUSE, KM_PRESS, 0, 0); + kmi = WM_keymap_add_item(keymap, "PAINTCURVE_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "extend", true); + WM_keymap_add_item(keymap, "PAINTCURVE_OT_slide", ACTIONMOUSE, KM_PRESS, 0, 0); + kmi = WM_keymap_add_item(keymap, "PAINTCURVE_OT_slide", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "align", true); + kmi = WM_keymap_add_item(keymap, "PAINTCURVE_OT_select", AKEY, KM_PRESS, 0, 0); + RNA_boolean_set(kmi->ptr, "toggle", true); + + WM_keymap_add_item(keymap, "PAINTCURVE_OT_cursor", ACTIONMOUSE, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "PAINTCURVE_OT_delete_point", XKEY, KM_PRESS, 0, 0); + + WM_keymap_add_item(keymap, "PAINTCURVE_OT_draw", RETKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "PAINTCURVE_OT_draw", PADENTER, KM_PRESS, 0, 0); + + WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", GKEY, KM_PRESS, 0, 0); + kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", EVT_TWEAK_S, KM_ANY, 0, 0); + WM_keymap_add_item(keymap, "TRANSFORM_OT_rotate", RKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "TRANSFORM_OT_resize", SKEY, KM_PRESS, 0, 0); +} + void ED_keymap_paint(wmKeyConfig *keyconf) { wmKeyMap *keymap; wmKeyMapItem *kmi; int i; + keymap = WM_keymap_find(keyconf, "Paint Curve", 0, 0); + keymap->poll = paint_curve_poll; + + paint_keymap_curve(keymap); + /* Sculpt mode */ keymap = WM_keymap_find(keyconf, "Sculpt", 0, 0); keymap->poll = sculpt_mode_poll; @@ -1191,7 +1356,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf) RNA_boolean_set(kmi->ptr, "create_missing", 1); /* */ - kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", AKEY, KM_PRESS, 0, 0); + kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", EKEY, KM_PRESS, 0, 0); RNA_string_set(kmi->ptr, "data_path", "tool_settings.sculpt.brush.stroke_method"); kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", SKEY, KM_PRESS, KM_SHIFT, 0); @@ -1225,7 +1390,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf) kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", RKEY, KM_PRESS, 0, 0); RNA_string_set(kmi->ptr, "data_path", "tool_settings.vertex_paint.brush.texture_angle_source_random"); - kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", AKEY, KM_PRESS, 0, 0); + kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", EKEY, KM_PRESS, 0, 0); RNA_string_set(kmi->ptr, "data_path", "tool_settings.vertex_paint.brush.stroke_method"); /* Weight Paint mode */ @@ -1250,7 +1415,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf) ed_keymap_stencil(keymap); - kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", AKEY, KM_PRESS, 0, 0); + kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", EKEY, KM_PRESS, 0, 0); RNA_string_set(kmi->ptr, "data_path", "tool_settings.vertex_paint.brush.stroke_method"); kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", MKEY, KM_PRESS, 0, 0); /* face mask toggle */ @@ -1283,6 +1448,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf) RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_image_paint", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "mode", BRUSH_STROKE_NORMAL); RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_image_paint", LEFTMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "mode", BRUSH_STROKE_INVERT); + WM_keymap_add_item(keymap, "PAINT_OT_brush_colors_flip", XKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "PAINT_OT_grab_clone", RIGHTMOUSE, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "PAINT_OT_sample_color", SKEY, KM_PRESS, 0, 0); @@ -1301,7 +1467,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf) kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", RKEY, KM_PRESS, 0, 0); RNA_string_set(kmi->ptr, "data_path", "tool_settings.image_paint.brush.texture_angle_source_random"); - kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", AKEY, KM_PRESS, 0, 0); + kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", EKEY, KM_PRESS, 0, 0); RNA_string_set(kmi->ptr, "data_path", "tool_settings.image_paint.brush.stroke_method"); /* face-mask mode */ diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 5133f51a6fd..47a772af9e4 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -36,16 +36,19 @@ #include "BLI_math.h" #include "BLI_utildefines.h" #include "BLI_rand.h" +#include "BLI_listbase.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_brush_types.h" +#include "DNA_curve_types.h" #include "RNA_access.h" #include "BKE_context.h" #include "BKE_paint.h" #include "BKE_brush.h" +#include "BKE_curve.h" #include "BKE_colortools.h" #include "BKE_image.h" @@ -72,7 +75,7 @@ typedef struct PaintSample { typedef struct PaintStroke { void *mode_data; - void *smooth_stroke_cursor; + void *stroke_cursor; wmTimer *timer; /* Cached values */ @@ -81,6 +84,9 @@ typedef struct PaintStroke { Brush *brush; UnifiedPaintSettings *ups; + /* used for lines and curves */ + ListBase line; + /* Paint stroke can use up to PAINT_MAX_INPUT_SAMPLES prior inputs * to smooth the stroke */ PaintSample samples[PAINT_MAX_INPUT_SAMPLES]; @@ -88,6 +94,8 @@ typedef struct PaintStroke { int cur_sample; float last_mouse_position[2]; + /* space distance covered so far */ + float stroke_distance; /* Set whether any stroke step has yet occurred * e.g. in sculpt mode, stroke doesn't start until cursor @@ -116,18 +124,17 @@ typedef struct PaintStroke { StrokeDone done; } PaintStroke; -/*** Cursor ***/ -static void paint_draw_smooth_stroke(bContext *C, int x, int y, void *customdata) +/*** Cursors ***/ +static void paint_draw_smooth_cursor(bContext *C, int x, int y, void *customdata) { Paint *paint = BKE_paint_get_active_from_context(C); Brush *brush = BKE_paint_brush(paint); PaintStroke *stroke = customdata; - if (stroke && brush && (brush->flag & BRUSH_SMOOTH_STROKE)) { - glColor4ubv(paint->paint_cursor_col); + if (stroke && brush) { glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); - + glColor4ubv(paint->paint_cursor_col); sdrawline(x, y, (int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1]); glDisable(GL_BLEND); @@ -135,12 +142,39 @@ static void paint_draw_smooth_stroke(bContext *C, int x, int y, void *customdata } } +static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata) +{ + Paint *paint = BKE_paint_get_active_from_context(C); + PaintStroke *stroke = customdata; + + glEnable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); + + glEnable(GL_LINE_STIPPLE); + glLineStipple(3, 0xAAAA); + + glColor4ub(0, 0, 0, paint->paint_cursor_col[3]); + glLineWidth(3.0); + sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1], + x, y); + + glColor4ub(255, 255, 255, paint->paint_cursor_col[3]); + glLineWidth(1.0); + sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1], + x, y); + + glDisable(GL_LINE_STIPPLE); + + glDisable(GL_BLEND); + glDisable(GL_LINE_SMOOTH); +} + static bool paint_tool_require_location(Brush *brush, PaintMode mode) { switch (mode) { case PAINT_SCULPT: - if (ELEM4(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, - SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB)) + if (ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, + SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB)) { return false; } @@ -155,13 +189,18 @@ static bool paint_tool_require_location(Brush *brush, PaintMode mode) } /* Initialize the stroke cache variants from operator properties */ -static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode, - struct PaintStroke *stroke, - const float mouse[2], float pressure) +static bool paint_brush_update(bContext *C, + Brush *brush, + PaintMode mode, + struct PaintStroke *stroke, + const float mouse_init[2], + float mouse[2], float pressure, + float location[3]) { Scene *scene = CTX_data_scene(C); - UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; - + UnifiedPaintSettings *ups = stroke->ups; + bool location_sampled = false; + bool location_success = false; /* XXX: Use pressure value from first brush step for brushes which don't * support strokes (grab, thumb). They depends on initial state and * brush coord/pressure/etc. @@ -222,14 +261,14 @@ static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode, else { copy_v2_v2(ups->tex_mouse, mouse); } - } - /* take care of mask texture, if any */ - if (brush->mask_mtex.tex) { - if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) - BKE_brush_randomize_texture_coordinates(ups, true); - else { - copy_v2_v2(ups->mask_tex_mouse, mouse); + /* take care of mask texture, if any */ + if (brush->mask_mtex.tex) { + if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) + BKE_brush_randomize_texture_coordinates(ups, true); + else { + copy_v2_v2(ups->mask_tex_mouse, mouse); + } } } @@ -246,14 +285,14 @@ static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode, ups->brush_rotation = atan2(dx, dy) + M_PI; if (brush->flag & BRUSH_EDGE_TO_EDGE) { - float out[3]; - halfway[0] = dx * 0.5f + stroke->initial_mouse[0]; halfway[1] = dy * 0.5f + stroke->initial_mouse[1]; if (stroke->get_location) { - if (stroke->get_location(C, out, halfway)) { + if (stroke->get_location(C, location, halfway)) { hit = true; + location_sampled = true; + location_success = true; } else if (!paint_tool_require_location(brush, mode)) { hit = true; @@ -266,17 +305,43 @@ static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode, if (hit) { copy_v2_v2(ups->anchored_initial_mouse, halfway); copy_v2_v2(ups->tex_mouse, halfway); + copy_v2_v2(ups->mask_tex_mouse, halfway); + copy_v2_v2(mouse, halfway); ups->anchored_size /= 2.0f; ups->pixel_radius /= 2.0f; + stroke->stroke_distance = ups->pixel_radius; } - else + else { copy_v2_v2(ups->anchored_initial_mouse, stroke->initial_mouse); - + copy_v2_v2(mouse, stroke->initial_mouse); + stroke->stroke_distance = ups->pixel_radius; + } + ups->pixel_radius /= stroke->zoom_2d; ups->draw_anchored = true; } else if (brush->flag & BRUSH_RAKE) { - paint_calculate_rake_rotation(ups, mouse); + /* here we are using the initial mouse coordinate because we do not want the rake + * result to depend on jittering */ + if (!stroke->brush_init) + copy_v2_v2(ups->last_rake, mouse_init); + else + paint_calculate_rake_rotation(ups, mouse_init); } + + if (!location_sampled) { + if (stroke->get_location) { + if (stroke->get_location(C, location, mouse)) + location_success = true; + else if (!paint_tool_require_location(brush, mode)) + location_success = true; + } + else { + zero_v3(location); + location_success = true; + } + } + + return location_success; } @@ -284,12 +349,11 @@ static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode, static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float mouse_in[2], float pressure) { Scene *scene = CTX_data_scene(C); - wmWindow *window = CTX_wm_window(C); - ARegion *ar = CTX_wm_region(C); Paint *paint = BKE_paint_get_active_from_context(C); PaintMode mode = BKE_paintmode_get_active_from_context(C); Brush *brush = BKE_paint_brush(paint); PaintStroke *stroke = op->customdata; + UnifiedPaintSettings *ups = stroke->ups; float mouse_out[2]; PointerRNA itemptr; float location[3]; @@ -315,8 +379,6 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float copy_v2_v2(stroke->last_mouse_position, mouse_in); stroke->last_pressure = pressure; - paint_brush_update(C, brush, mode, stroke, mouse_in, pressure); - { float delta[2]; float factor = stroke->zoom_2d; @@ -336,22 +398,13 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float } } - /* TODO: can remove the if statement once all modes have this */ - if (stroke->get_location) { - if (!stroke->get_location(C, location, mouse_out)) { - if (paint_tool_require_location(brush, mode)) { - if (ar && (paint->flags & PAINT_SHOW_BRUSH)) - WM_paint_cursor_tag_redraw(window, ar); - return; - } - } + if (!paint_brush_update(C, brush, mode, stroke, mouse_in, mouse_out, pressure, location)) { + return; } - else - zero_v3(location); /* Add to stroke */ RNA_collection_add(op->ptr, "stroke", &itemptr); - + RNA_float_set(&itemptr, "size", ups->pixel_radius); RNA_float_set_array(&itemptr, "location", location); RNA_float_set_array(&itemptr, "mouse", mouse_out); RNA_boolean_set(&itemptr, "pen_flip", stroke->pen_flip); @@ -362,20 +415,12 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float /* don't record this for now, it takes up a lot of memory when doing long * strokes with small brush size, and operators have register disabled */ RNA_collection_clear(op->ptr, "stroke"); - - /* always redraw region if brush is shown */ - if (ar && (paint->flags & PAINT_SHOW_BRUSH)) - WM_paint_cursor_tag_redraw(window, ar); } /* Returns zero if no sculpt changes should be made, non-zero otherwise */ static int paint_smooth_stroke(PaintStroke *stroke, float output[2], float *outpressure, const PaintSample *sample, PaintMode mode) { - output[0] = sample->mouse[0]; - output[1] = sample->mouse[1]; - *outpressure = sample->pressure; - if (paint_supports_smooth_stroke(stroke->brush, mode)) { float radius = stroke->brush->smooth_stroke_radius * stroke->zoom_2d; float u = stroke->brush->smooth_stroke_factor, v = 1.0f - u; @@ -391,6 +436,11 @@ static int paint_smooth_stroke(PaintStroke *stroke, float output[2], float *outp output[1] = sample->mouse[1] * v + stroke->last_mouse_position[1] * u; *outpressure = sample->pressure * v + stroke->last_pressure * u; } + else { + output[0] = sample->mouse[0]; + output[1] = sample->mouse[1]; + *outpressure = sample->pressure; + } return 1; } @@ -413,6 +463,55 @@ static float paint_space_stroke_spacing(const Scene *scene, PaintStroke *stroke, return max_ff(1.0, size_clamp * spacing / 50.0f); } + + +static float paint_stroke_overlapped_curve(Brush *br, float x, float spacing) +{ + int i; + const int n = 100 / spacing; + const float h = spacing / 50.0f; + const float x0 = x - 1; + + float sum; + + sum = 0; + for (i = 0; i < n; i++) { + float xx; + + xx = fabs(x0 + i * h); + + if (xx < 1.0f) + sum += BKE_brush_curve_strength(br, xx, 1); + } + + return sum; +} + +static float paint_stroke_integrate_overlap(Brush *br, float factor) +{ + int i; + int m; + float g; + float max; + + float spacing = br->spacing * factor; + + if (!(br->flag & BRUSH_SPACE_ATTEN && (br->spacing < 100))) + return 1.0; + + m = 10; + g = 1.0f / m; + max = 0; + for (i = 0; i < m; i++) { + float overlap = paint_stroke_overlapped_curve(br, i * g, spacing); + + if (overlap > max) + max = overlap; + } + + return 1.0f / max; +} + static float paint_space_stroke_spacing_variable(const Scene *scene, PaintStroke *stroke, float pressure, float dpressure, float length) { if (BKE_brush_use_size_pressure(scene, stroke->brush)) { @@ -444,40 +543,42 @@ static int paint_space_stroke(bContext *C, wmOperator *op, const float final_mou { const Scene *scene = CTX_data_scene(C); PaintStroke *stroke = op->customdata; - PaintMode mode = BKE_paintmode_get_active_from_context(C); + UnifiedPaintSettings *ups = stroke->ups; int cnt = 0; - if (paint_space_stroke_enabled(stroke->brush, mode)) { - float pressure, dpressure; - float mouse[2], dmouse[2]; - float length; + float pressure, dpressure; + float mouse[2], dmouse[2]; + float length; + float no_pressure_spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f); - sub_v2_v2v2(dmouse, final_mouse, stroke->last_mouse_position); + sub_v2_v2v2(dmouse, final_mouse, stroke->last_mouse_position); - pressure = stroke->last_pressure; - dpressure = final_pressure - stroke->last_pressure; + pressure = stroke->last_pressure; + dpressure = final_pressure - stroke->last_pressure; - length = normalize_v2(dmouse); + length = normalize_v2(dmouse); - while (length > 0.0f) { - float spacing = paint_space_stroke_spacing_variable(scene, stroke, pressure, dpressure, length); - - if (length >= spacing) { - mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing; - mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing; - pressure = stroke->last_pressure + (spacing / length) * dpressure; + while (length > 0.0f) { + float spacing = paint_space_stroke_spacing_variable(scene, stroke, pressure, dpressure, length); - paint_brush_stroke_add_step(C, op, mouse, pressure); + if (length >= spacing) { + mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing; + mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing; + pressure = stroke->last_pressure + (spacing / length) * dpressure; - length -= spacing; - pressure = stroke->last_pressure; - dpressure = final_pressure - stroke->last_pressure; + ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush, spacing / no_pressure_spacing); - cnt++; - } - else { - break; - } + stroke->stroke_distance += spacing / stroke->zoom_2d; + paint_brush_stroke_add_step(C, op, mouse, pressure); + + length -= spacing; + pressure = stroke->last_pressure; + dpressure = final_pressure - stroke->last_pressure; + + cnt++; + } + else { + break; } } @@ -487,6 +588,7 @@ static int paint_space_stroke(bContext *C, wmOperator *op, const float final_mou /**** Public API ****/ PaintStroke *paint_stroke_new(bContext *C, + wmOperator *op, StrokeGetLocation get_location, StrokeTestStart test_start, StrokeUpdateStep update_step, @@ -497,6 +599,7 @@ PaintStroke *paint_stroke_new(bContext *C, ToolSettings *toolsettings = CTX_data_tool_settings(C); UnifiedPaintSettings *ups = &toolsettings->unified_paint_settings; Brush *br = stroke->brush = BKE_paint_brush(BKE_paint_get_active_from_context(C)); + float zoomx, zoomy; view3d_set_viewcontext(C, &stroke->vc); if (stroke->vc.v3d) @@ -510,6 +613,18 @@ PaintStroke *paint_stroke_new(bContext *C, stroke->event_type = event_type; /* for modal, return event */ stroke->ups = ups; + get_imapaint_zoom(C, &zoomx, &zoomy); + stroke->zoom_2d = max_ff(zoomx, zoomy); + + if ((br->flag & BRUSH_CURVE) && + RNA_struct_property_is_set(op->ptr, "mode")) + { + RNA_enum_set(op->ptr, "mode", BRUSH_STROKE_NORMAL); + } + /* initialize here */ + ups->overlap_factor = 1.0; + ups->stroke_active = true; + /* initialize here to avoid initialization conflict with threaded strokes */ curvemapping_initialize(br->curve); @@ -521,8 +636,7 @@ PaintStroke *paint_stroke_new(bContext *C, void paint_stroke_data_free(struct wmOperator *op) { BKE_paint_set_overlay_override(0); - MEM_freeN(op->customdata); - op->customdata = NULL; + MEM_SAFE_FREE(op->customdata); } static void stroke_done(struct bContext *C, struct wmOperator *op) @@ -552,8 +666,10 @@ static void stroke_done(struct bContext *C, struct wmOperator *op) stroke->timer); } - if (stroke->smooth_stroke_cursor) - WM_paint_cursor_end(CTX_wm_manager(C), stroke->smooth_stroke_cursor); + if (stroke->stroke_cursor) + WM_paint_cursor_end(CTX_wm_manager(C), stroke->stroke_cursor); + + BLI_freelistN(&stroke->line); paint_stroke_data_free(op); } @@ -566,7 +682,7 @@ bool paint_space_stroke_enabled(Brush *br, PaintMode mode) static bool sculpt_is_grab_tool(Brush *br) { - return ELEM4(br->sculpt_tool, + return ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE, @@ -584,6 +700,16 @@ bool paint_supports_dynamic_size(Brush *br, PaintMode mode) if (sculpt_is_grab_tool(br)) return false; break; + + case PAINT_TEXTURE_2D: /* fall through */ + case PAINT_TEXTURE_PROJECTIVE: + if ((br->imagepaint_tool == PAINT_TOOL_FILL) && + (br->flag & BRUSH_USE_GRADIENT)) + { + return false; + } + break; + default: break; } @@ -593,8 +719,7 @@ bool paint_supports_dynamic_size(Brush *br, PaintMode mode) bool paint_supports_smooth_stroke(Brush *br, PaintMode mode) { if (!(br->flag & BRUSH_SMOOTH_STROKE) || - (br->flag & BRUSH_ANCHORED) || - (br->flag & BRUSH_DRAG_DOT)) + (br->flag & (BRUSH_ANCHORED | BRUSH_DRAG_DOT | BRUSH_LINE))) { return false; } @@ -613,7 +738,7 @@ bool paint_supports_smooth_stroke(Brush *br, PaintMode mode) bool paint_supports_texture(PaintMode mode) { /* ommit: PAINT_WEIGHT, PAINT_SCULPT_UV, PAINT_INVALID */ - return ELEM4(mode, PAINT_SCULPT, PAINT_VERTEX, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D); + return ELEM(mode, PAINT_SCULPT, PAINT_VERTEX, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D); } /* return true if the brush size can change during paint (normally used for pressure) */ @@ -701,28 +826,141 @@ static void paint_stroke_sample_average(const PaintStroke *stroke, /*printf("avg=(%f, %f), num=%d\n", average->mouse[0], average->mouse[1], stroke->num_samples);*/ } +/** + * Slightly different version of spacing for line/curve strokes, + * makes sure the dabs stay on the line path. + */ +static void paint_line_strokes_spacing( + bContext *C, wmOperator *op, PaintStroke *stroke, float spacing, float *length_residue, + const float old_pos[2], const float new_pos[2]) +{ + UnifiedPaintSettings *ups = stroke->ups; + + float mouse[2], dmouse[2]; + float length; + + sub_v2_v2v2(dmouse, new_pos, old_pos); + copy_v2_v2(stroke->last_mouse_position, old_pos); + + length = normalize_v2(dmouse); + + BLI_assert(length >= 0.0f); + + if (length == 0.0f) + return; + + while (length > 0.0f) { + float spacing_final = spacing - *length_residue; + length += *length_residue; + *length_residue = 0.0; + + if (length >= spacing) { + mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing_final; + mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing_final; + + ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush, 1.0); + + stroke->stroke_distance += spacing / stroke->zoom_2d; + paint_brush_stroke_add_step(C, op, mouse, 1.0); + + length -= spacing; + spacing_final = spacing; + } + else { + break; + } + } + + *length_residue = length; +} + + +static void paint_stroke_line_end(bContext *C, wmOperator *op, PaintStroke *stroke, float mouse[2]) +{ + Brush *br = stroke->brush; + if (stroke->stroke_started && (br->flag & BRUSH_LINE)) { + stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0); + + paint_brush_stroke_add_step(C, op, stroke->last_mouse_position, 1.0); + paint_space_stroke(C, op, mouse, 1.0); + } +} + +static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *stroke) +{ + Brush *br = stroke->brush; + if (br->flag & BRUSH_CURVE) { + const Scene *scene = CTX_data_scene(C); + const float spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f); + PaintCurve *pc = br->paint_curve; + PaintCurvePoint *pcp; + float length_residue = 0.0f; + int i; + + if (!pc) + return true; + + pcp = pc->points; + stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0); + + for (i = 0; i < pc->tot_points - 1; i++, pcp++) { + int j; + float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2]; + PaintCurvePoint *pcp_next = pcp + 1; + + for (j = 0; j < 2; j++) + BKE_curve_forward_diff_bezier( + pcp->bez.vec[1][j], + pcp->bez.vec[2][j], + pcp_next->bez.vec[0][j], + pcp_next->bez.vec[1][j], + data + j, PAINT_CURVE_NUM_SEGMENTS, sizeof(float[2])); + + + for (j = 0; j < PAINT_CURVE_NUM_SEGMENTS; j++) { + if (!stroke->stroke_started) { + stroke->last_pressure = 1.0; + copy_v2_v2(stroke->last_mouse_position, data + 2 * j); + stroke->stroke_started = stroke->test_start(C, op, stroke->last_mouse_position); + + if (stroke->stroke_started) { + paint_brush_stroke_add_step(C, op, data + 2 * j, 1.0); + paint_line_strokes_spacing(C, op, stroke, spacing, &length_residue, data + 2 * j, data + 2 * (j + 1)); + } + } + else { + paint_line_strokes_spacing(C, op, stroke, spacing, &length_residue, data + 2 * j, data + 2 * (j + 1)); + } + } + } + + stroke_done(C, op); + return true; + } + + return false; +} + + int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) { Paint *p = BKE_paint_get_active_from_context(C); PaintMode mode = BKE_paintmode_get_active_from_context(C); PaintStroke *stroke = op->customdata; + Brush *br = stroke->brush; PaintSample sample_average; float mouse[2]; bool first_dab = false; bool first_modal = false; - float zoomx, zoomy; bool redraw = false; float pressure; - /* see if tablet affects event */ - pressure = WM_event_tablet_data(event, &stroke->pen_flip, NULL); + /* see if tablet affects event. Line, anchored and drag dot strokes do not support pressure */ + pressure = (br->flag & (BRUSH_LINE | BRUSH_ANCHORED | BRUSH_DRAG_DOT)) ? 1.0f : WM_event_tablet_data(event, &stroke->pen_flip, NULL); paint_stroke_add_sample(p, stroke, event->mval[0], event->mval[1], pressure); paint_stroke_sample_average(stroke, &sample_average); - get_imapaint_zoom(C, &zoomx, &zoomy); - stroke->zoom_2d = max_ff(zoomx, zoomy); - /* let NDOF motion pass through to the 3D view so we can paint and rotate simultaneously! * this isn't perfect... even when an extra MOUSEMOVE is spoofed, the stroke discards it * since the 2D deltas are zero -- code in this file needs to be updated to use the @@ -732,8 +970,12 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) /* one time initialization */ if (!stroke->stroke_init) { - stroke->smooth_stroke_cursor = - WM_paint_cursor_activate(CTX_wm_manager(C), paint_poll, paint_draw_smooth_stroke, stroke); + if (paint_stroke_curve_end(C, op, stroke)) + return OPERATOR_FINISHED; + + if (paint_supports_smooth_stroke(br, mode)) + stroke->stroke_cursor = + WM_paint_cursor_activate(CTX_wm_manager(C), paint_poll, paint_draw_smooth_cursor, stroke); stroke->stroke_init = true; first_modal = true; @@ -747,9 +989,14 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) BLI_assert((stroke->stroke_started & ~1) == 0); /* 0/1 */ if (stroke->stroke_started) { - if (stroke->brush->flag & BRUSH_AIRBRUSH) + if (br->flag & BRUSH_AIRBRUSH) stroke->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, stroke->brush->rate); + if (br->flag & BRUSH_LINE) { + stroke->stroke_cursor = + WM_paint_cursor_activate(CTX_wm_manager(C), paint_poll, paint_draw_line_cursor, stroke); + } + first_dab = true; } } @@ -765,20 +1012,42 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_CANCELLED; } - if (event->type == stroke->event_type && event->val == KM_RELEASE && !first_modal) { + if (event->type == stroke->event_type && !first_modal) { + if (event->val == KM_RELEASE) { + paint_stroke_line_end (C, op, stroke, sample_average.mouse); + stroke_done(C, op); + return OPERATOR_FINISHED; + } + } + else if (ELEM(event->type, RETKEY, SPACEKEY)) { + paint_stroke_line_end(C, op, stroke, sample_average.mouse); stroke_done(C, op); return OPERATOR_FINISHED; } - else if (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) || - (event->type == TIMER && (event->customdata == stroke->timer)) ) + else if ((br->flag & BRUSH_LINE) && stroke->stroke_started && + (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)))) + { + if (br->flag & BRUSH_RAKE) { + copy_v2_v2(stroke->ups->last_rake, stroke->last_mouse_position); + paint_calculate_rake_rotation(stroke->ups, sample_average.mouse); + } + } + else if (first_modal || + /* regular dabs */ + (!(br->flag & (BRUSH_AIRBRUSH)) && (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))) || + /* airbrush */ + ((br->flag & BRUSH_AIRBRUSH) && event->type == TIMER && event->customdata == stroke->timer)) { if (paint_smooth_stroke(stroke, mouse, &pressure, &sample_average, mode)) { if (stroke->stroke_started) { - if (paint_space_stroke_enabled(stroke->brush, mode)) { + if (paint_space_stroke_enabled(br, mode)) { if (paint_space_stroke(C, op, mouse, pressure)) redraw = true; } else { + float dmouse[2]; + sub_v2_v2v2(dmouse, mouse, stroke->last_mouse_position); + stroke->stroke_distance += len_v2(dmouse); paint_brush_stroke_add_step(C, op, mouse, pressure); redraw = true; } @@ -789,19 +1058,27 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) /* we want the stroke to have the first daub at the start location * instead of waiting till we have moved the space distance */ if (first_dab && - paint_space_stroke_enabled(stroke->brush, mode) && - !(stroke->brush->flag & BRUSH_ANCHORED) && - !(stroke->brush->flag & BRUSH_SMOOTH_STROKE)) + paint_space_stroke_enabled(br, mode) && + !(br->flag & BRUSH_SMOOTH_STROKE)) { - paint_brush_stroke_add_step(C, op, mouse, pressure); + stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0); + paint_brush_stroke_add_step(C, op, sample_average.mouse, sample_average.pressure); redraw = true; } /* do updates for redraw. if event is inbetween mousemove there are more * coming, so postpone potentially slow redraw updates until all are done */ - if (event->type != INBETWEEN_MOUSEMOVE) + if (event->type != INBETWEEN_MOUSEMOVE) { + wmWindow *window = CTX_wm_window(C); + ARegion *ar = CTX_wm_region(C); + + /* At the very least, invalidate the cursor */ + if (ar && (p->flags & PAINT_SHOW_BRUSH)) + WM_paint_cursor_tag_redraw(window, ar); + if (redraw && stroke->redraw) stroke->redraw(C, stroke, false); + } return OPERATOR_RUNNING_MODAL; } @@ -843,6 +1120,11 @@ void *paint_stroke_mode_data(struct PaintStroke *stroke) return stroke->mode_data; } +float paint_stroke_distance_get(struct PaintStroke *stroke) +{ + return stroke->stroke_distance; +} + void paint_stroke_set_mode_data(PaintStroke *stroke, void *mode_data) { stroke->mode_data = mode_data; @@ -856,6 +1138,6 @@ int paint_poll(bContext *C) ARegion *ar = CTX_wm_region(C); return p && ob && BKE_paint_brush(p) && - (sa && sa->spacetype == SPACE_VIEW3D) && + (sa && ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) && (ar && ar->regiontype == RGN_TYPE_WINDOW); } diff --git a/source/blender/editors/sculpt_paint/paint_undo.c b/source/blender/editors/sculpt_paint/paint_undo.c index c5c747dbab4..20e3155c01d 100644 --- a/source/blender/editors/sculpt_paint/paint_undo.c +++ b/source/blender/editors/sculpt_paint/paint_undo.c @@ -51,19 +51,17 @@ typedef struct UndoElem { UndoRestoreCb restore; UndoFreeCb free; + UndoCleanupCb cleanup; } UndoElem; -typedef bool (*UndoCleanupCb)(struct bContext *C, ListBase *lb); - typedef struct UndoStack { int type; ListBase elems; UndoElem *current; - UndoCleanupCb cleanup; } UndoStack; -static UndoStack ImageUndoStack = {UNDO_PAINT_IMAGE, {NULL, NULL}, NULL, NULL}; -static UndoStack MeshUndoStack = {UNDO_PAINT_MESH, {NULL, NULL}, NULL, sculpt_undo_cleanup}; +static UndoStack ImageUndoStack = {UNDO_PAINT_IMAGE, {NULL, NULL}, NULL}; +static UndoStack MeshUndoStack = {UNDO_PAINT_MESH, {NULL, NULL}, NULL}; /* Generic */ @@ -81,7 +79,7 @@ static void undo_elem_free(UndoStack *UNUSED(stack), UndoElem *uel) } } -static void undo_stack_push_begin(UndoStack *stack, const char *name, UndoRestoreCb restore, UndoFreeCb free) +static void undo_stack_push_begin(UndoStack *stack, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup) { UndoElem *uel; int nr; @@ -101,6 +99,7 @@ static void undo_stack_push_begin(UndoStack *stack, const char *name, UndoRestor stack->current = uel = MEM_callocN(sizeof(UndoElem), "undo file"); uel->restore = restore; uel->free = free; + uel->cleanup = cleanup; BLI_addtail(&stack->elems, uel); /* name can be a dynamic string */ @@ -179,25 +178,24 @@ static void undo_stack_cleanup(UndoStack *stack, bContext *C) UndoElem *uel = stack->elems.first; bool stack_reset = false; - if (stack->cleanup) { - while (uel) { - if (stack->cleanup(C, &uel->elems)) { - UndoElem *uel_tmp = uel->next; - if (stack->current == uel) { - stack->current = NULL; - stack_reset = true; - } - undo_elem_free(stack, uel); - BLI_freelinkN(&stack->elems, uel); - uel = uel_tmp; + while (uel) { + if (uel->cleanup && uel->cleanup(C, &uel->elems)) { + UndoElem *uel_tmp = uel->next; + if (stack->current == uel) { + stack->current = NULL; + stack_reset = true; } - else - uel = uel->next; - } - if (stack_reset) { - stack->current = stack->elems.last; + undo_elem_free(stack, uel); + BLI_freelinkN(&stack->elems, uel); + uel = uel_tmp; } + else + uel = uel->next; + } + if (stack_reset) { + stack->current = stack->elems.last; } + } static int undo_stack_step(bContext *C, UndoStack *stack, int step, const char *name) @@ -255,23 +253,25 @@ static void undo_stack_free(UndoStack *stack) /* Exported Functions */ -void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free) +void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup) { if (type == UNDO_PAINT_IMAGE) - undo_stack_push_begin(&ImageUndoStack, name, restore, free); + undo_stack_push_begin(&ImageUndoStack, name, restore, free, cleanup); else if (type == UNDO_PAINT_MESH) - undo_stack_push_begin(&MeshUndoStack, name, restore, free); + undo_stack_push_begin(&MeshUndoStack, name, restore, free, cleanup); } ListBase *undo_paint_push_get_list(int type) { if (type == UNDO_PAINT_IMAGE) { - if (ImageUndoStack.current) + if (ImageUndoStack.current) { return &ImageUndoStack.current->elems; + } } else if (type == UNDO_PAINT_MESH) { - if (MeshUndoStack.current) + if (MeshUndoStack.current) { return &MeshUndoStack.current->elems; + } } return NULL; diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 25308f6595e..0d463172f99 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -35,23 +35,28 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" +#include "DNA_material_types.h" #include "DNA_scene_types.h" #include "DNA_brush_types.h" #include "BLI_math.h" +#include "BLI_math_color.h" #include "BLI_utildefines.h" #include "BLI_listbase.h" #include "BLI_rect.h" #include "BLF_translation.h" +#include "BKE_scene.h" #include "BKE_brush.h" #include "BKE_context.h" #include "BKE_DerivedMesh.h" +#include "BKE_material.h" #include "BKE_image.h" #include "BKE_paint.h" #include "BKE_report.h" +#include "BKE_image.h" #include "RNA_access.h" #include "RNA_define.h" @@ -67,6 +72,10 @@ #include "ED_view3d.h" #include "ED_screen.h" +#include "ED_uvedit.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" #include "BLI_sys_types.h" #include "ED_mesh.h" /* for face mask functions */ @@ -205,6 +214,175 @@ void paint_get_tex_pixel_col(MTex *mtex, float u, float v, float rgba[4], struct CLAMP(rgba[3], 0.0f, 1.0f); } +/* 3D Paint */ + +static void imapaint_project(float matrix[4][4], const float co[3], float pco[4]) +{ + copy_v3_v3(pco, co); + pco[3] = 1.0f; + + mul_m4_v4(matrix, pco); +} + +static void imapaint_tri_weights(float matrix[4][4], GLint view[4], + const float v1[3], const float v2[3], const float v3[3], + const float co[2], float w[3]) +{ + float pv1[4], pv2[4], pv3[4], h[3], divw; + float wmat[3][3], invwmat[3][3]; + + /* compute barycentric coordinates */ + + /* project the verts */ + imapaint_project(matrix, v1, pv1); + imapaint_project(matrix, v2, pv2); + imapaint_project(matrix, v3, pv3); + + /* do inverse view mapping, see gluProject man page */ + h[0] = (co[0] - view[0]) * 2.0f / view[2] - 1.0f; + h[1] = (co[1] - view[1]) * 2.0f / view[3] - 1.0f; + h[2] = 1.0f; + + /* solve for (w1,w2,w3)/perspdiv in: + * h * perspdiv = Project * Model * (w1 * v1 + w2 * v2 + w3 * v3) */ + + wmat[0][0] = pv1[0]; wmat[1][0] = pv2[0]; wmat[2][0] = pv3[0]; + wmat[0][1] = pv1[1]; wmat[1][1] = pv2[1]; wmat[2][1] = pv3[1]; + wmat[0][2] = pv1[3]; wmat[1][2] = pv2[3]; wmat[2][2] = pv3[3]; + + invert_m3_m3(invwmat, wmat); + mul_m3_v3(invwmat, h); + + copy_v3_v3(w, h); + + /* w is still divided by perspdiv, make it sum to one */ + divw = w[0] + w[1] + w[2]; + if (divw != 0.0f) { + mul_v3_fl(w, 1.0f / divw); + } +} + +/* compute uv coordinates of mouse in face */ +static void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, const int xy[2], float uv[2]) +{ + DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); + MTFace *tf_base, *tf; + Material *ma; + TexPaintSlot *slot; + int numfaces = dm->getNumTessFaces(dm), a, findex; + float p[2], w[3], absw, minabsw; + MFace mf; + MVert mv[4]; + float matrix[4][4], proj[4][4]; + GLint view[4]; + + /* compute barycentric coordinates */ + + /* double lookup */ + const int *index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX); + const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX); + if (index_mf_to_mpoly == NULL) { + index_mp_to_orig = NULL; + } + + /* get the needed opengl matrices */ + glGetIntegerv(GL_VIEWPORT, view); + glGetFloatv(GL_MODELVIEW_MATRIX, (float *)matrix); + glGetFloatv(GL_PROJECTION_MATRIX, (float *)proj); + view[0] = view[1] = 0; + mul_m4_m4m4(matrix, matrix, ob->obmat); + mul_m4_m4m4(matrix, proj, matrix); + + minabsw = 1e10; + uv[0] = uv[1] = 0.0; + + /* test all faces in the derivedmesh with the original index of the picked face */ + for (a = 0; a < numfaces; a++) { + findex = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a) : a; + + if (findex == faceindex) { + dm->getTessFace(dm, a, &mf); + + ma = dm->mat[mf.mat_nr]; + slot = &ma->texpaintslot[ma->paint_active_slot]; + + dm->getVert(dm, mf.v1, &mv[0]); + dm->getVert(dm, mf.v2, &mv[1]); + dm->getVert(dm, mf.v3, &mv[2]); + if (mf.v4) + dm->getVert(dm, mf.v4, &mv[3]); + + if (!slot->uvname || !(tf_base = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, slot->uvname))) + tf_base = CustomData_get_layer(&dm->faceData, CD_MTFACE); + + tf = &tf_base[a]; + + p[0] = xy[0]; + p[1] = xy[1]; + + if (mf.v4) { + /* the triangle with the largest absolute values is the one + * with the most negative weights */ + imapaint_tri_weights(matrix, view, mv[0].co, mv[1].co, mv[3].co, p, w); + absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]); + if (absw < minabsw) { + uv[0] = tf->uv[0][0] * w[0] + tf->uv[1][0] * w[1] + tf->uv[3][0] * w[2]; + uv[1] = tf->uv[0][1] * w[0] + tf->uv[1][1] * w[1] + tf->uv[3][1] * w[2]; + minabsw = absw; + } + + imapaint_tri_weights(matrix, view, mv[1].co, mv[2].co, mv[3].co, p, w); + absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]); + if (absw < minabsw) { + uv[0] = tf->uv[1][0] * w[0] + tf->uv[2][0] * w[1] + tf->uv[3][0] * w[2]; + uv[1] = tf->uv[1][1] * w[0] + tf->uv[2][1] * w[1] + tf->uv[3][1] * w[2]; + minabsw = absw; + } + } + else { + imapaint_tri_weights(matrix, view, mv[0].co, mv[1].co, mv[2].co, p, w); + absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]); + if (absw < minabsw) { + uv[0] = tf->uv[0][0] * w[0] + tf->uv[1][0] * w[1] + tf->uv[2][0] * w[2]; + uv[1] = tf->uv[0][1] * w[0] + tf->uv[1][1] * w[1] + tf->uv[2][1] * w[2]; + minabsw = absw; + } + } + } + } + + dm->release(dm); +} + +/* returns 0 if not found, otherwise 1 */ +static int imapaint_pick_face(ViewContext *vc, const int mval[2], unsigned int *r_index, unsigned int totface) +{ + if (totface == 0) + return 0; + + /* sample only on the exact position */ + *r_index = view3d_sample_backbuf(vc, mval[0], mval[1]); + + if ((*r_index) == 0 || (*r_index) > (unsigned int)totface) { + return 0; + } + + (*r_index)--; + + return 1; +} + + +static Image *imapaint_face_image(DerivedMesh *dm, int face_index) +{ + Image *ima; + MFace *mf = dm->getTessFaceArray(dm) + face_index; + Material *ma = dm->mat[mf->mat_nr]; + ima = ma->texpaintslot[ma->paint_active_slot].ima; + + return ima; +} + /* Uses symm to selectively flip any axis of a coordinate. */ void flip_v3_v3(float out[3], const float in[3], const char symm) { @@ -223,25 +401,123 @@ void flip_v3_v3(float out[3], const float in[3], const char symm) } /* used for both 3d view and image window */ -void paint_sample_color(const bContext *C, ARegion *ar, int x, int y) /* frontbuf */ +void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_proj, bool use_palette) { + Scene *scene = CTX_data_scene(C); + Paint *paint = BKE_paint_get_active_from_context(C); + Palette *palette = BKE_paint_palette(paint); + PaletteColor *color; Brush *br = BKE_paint_brush(BKE_paint_get_active_from_context(C)); unsigned int col; - const char *cp; + const unsigned char *cp; CLAMP(x, 0, ar->winx); CLAMP(y, 0, ar->winy); - glReadBuffer(GL_FRONT); - glReadPixels(x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col); - glReadBuffer(GL_BACK); + if (use_palette) { + if (!palette) { + palette = BKE_palette_add(CTX_data_main(C), "Palette"); + BKE_paint_palette_set(paint, palette); + } + + color = BKE_palette_color_add(palette); + } + + + if (CTX_wm_view3d(C) && texpaint_proj) { + /* first try getting a colour directly from the mesh faces if possible */ + Object *ob = OBACT; + bool sample_success = false; + + if (ob) { + DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); + + ViewContext vc; + const int mval[2] = {x, y}; + unsigned int faceindex; + unsigned int totface = dm->getNumTessFaces(dm); + MTFace *dm_mtface = dm->getTessFaceDataArray(dm, CD_MTFACE); + + DM_update_materials(dm, ob); + + if (dm_mtface) { + view3d_set_viewcontext(C, &vc); + + view3d_operator_needs_opengl(C); + + if (imapaint_pick_face(&vc, mval, &faceindex, totface)) { + Image *image = imapaint_face_image(dm, faceindex); + + ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL); + if (ibuf && ibuf->rect) { + float uv[2]; + float u, v; + imapaint_pick_uv(scene, ob, faceindex, mval, uv); + sample_success = true; + + u = fmodf(uv[0], 1.0f); + v = fmodf(uv[1], 1.0f); + + if (u < 0.0f) u += 1.0f; + if (v < 0.0f) v += 1.0f; + + u = u * ibuf->x - 0.5f; + v = v * ibuf->y - 0.5f; + + if (ibuf->rect_float) { + float rgba_f[4]; + bilinear_interpolation_color_wrap(ibuf, NULL, rgba_f, u, v); + straight_to_premul_v4(rgba_f); + if (use_palette) { + linearrgb_to_srgb_v3_v3(color->rgb, rgba_f); + } + else { + linearrgb_to_srgb_v3_v3(rgba_f, rgba_f); + BKE_brush_color_set(scene, br, rgba_f); + } + } + else { + unsigned char rgba[4]; + bilinear_interpolation_color_wrap(ibuf, rgba, NULL, u, v); + if (use_palette) { + rgb_uchar_to_float(color->rgb, rgba); + } + else { + float rgba_f[3]; + rgb_uchar_to_float(rgba_f, rgba); + BKE_brush_color_set(scene, br, rgba_f); + } + } + } + + BKE_image_release_ibuf(image, ibuf, NULL); + } + } + dm->release(dm); + } - cp = (char *)&col; + if (!sample_success) { + glReadBuffer(GL_FRONT); + glReadPixels(x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col); + glReadBuffer(GL_BACK); + } + else + return; + } + else { + glReadBuffer(GL_FRONT); + glReadPixels(x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col); + glReadBuffer(GL_BACK); + } + cp = (unsigned char *)&col; - if (br) { - br->rgb[0] = cp[0] / 255.0f; - br->rgb[1] = cp[1] / 255.0f; - br->rgb[2] = cp[2] / 255.0f; + if (use_palette) { + rgb_uchar_to_float(color->rgb, cp); + } + else { + float rgba_f[3]; + rgb_uchar_to_float(rgba_f, cp); + BKE_brush_color_set(scene, br, rgba_f); } } diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 969c5a09a82..2929a96db29 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -197,11 +197,11 @@ static int *get_indexarray(Mesh *me) return MEM_mallocN(sizeof(int) * (me->totpoly + 1), "vertexpaint"); } -unsigned int vpaint_get_current_col(VPaint *vp) +unsigned int vpaint_get_current_col(Scene *scene, VPaint *vp) { Brush *brush = BKE_paint_brush(&vp->paint); unsigned char col[4]; - rgb_float_to_uchar(col, brush->rgb); + rgb_float_to_uchar(col, BKE_brush_color_get(scene, brush)); col[3] = 255; /* alpha isn't used, could even be removed to speedup paint a little */ return *(unsigned int *)col; } @@ -2547,14 +2547,17 @@ static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) { int retval; - op->customdata = paint_stroke_new(C, NULL, wpaint_stroke_test_start, + op->customdata = paint_stroke_new(C, op, NULL, wpaint_stroke_test_start, wpaint_stroke_update_step, NULL, wpaint_stroke_done, event->type); + if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) { + paint_stroke_data_free(op); + return OPERATOR_FINISHED; + } /* add modal handler */ WM_event_add_modal_handler(C, op); - retval = op->type->modal(C, op, event); OPERATOR_RETVAL_CHECK(retval); BLI_assert(retval == OPERATOR_RUNNING_MODAL); @@ -2563,7 +2566,7 @@ static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) static int wpaint_exec(bContext *C, wmOperator *op) { - op->customdata = paint_stroke_new(C, NULL, wpaint_stroke_test_start, + op->customdata = paint_stroke_new(C, op, NULL, wpaint_stroke_test_start, wpaint_stroke_update_step, NULL, wpaint_stroke_done, 0); @@ -2778,7 +2781,8 @@ static void vpaint_build_poly_facemap(struct VPaintData *vd, Mesh *me) static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const float UNUSED(mouse[2])) { - ToolSettings *ts = CTX_data_tool_settings(C); + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; struct PaintStroke *stroke = op->customdata; VPaint *vp = ts->vpaint; Brush *brush = BKE_paint_brush(&vp->paint); @@ -2810,7 +2814,7 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f vpd->vp_handle = ED_vpaint_proj_handle_create(vpd->vc.scene, ob, &vpd->vertexcosnos); vpd->indexar = get_indexarray(me); - vpd->paintcol = vpaint_get_current_col(vp); + vpd->paintcol = vpaint_get_current_col(scene, vp); vpd->is_texbrush = !(brush->vertexpaint_tool == PAINT_BLEND_BLUR) && brush->mtex.tex; @@ -3062,14 +3066,18 @@ static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) { int retval; - op->customdata = paint_stroke_new(C, NULL, vpaint_stroke_test_start, + op->customdata = paint_stroke_new(C, op, NULL, vpaint_stroke_test_start, vpaint_stroke_update_step, NULL, vpaint_stroke_done, event->type); + if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) { + paint_stroke_data_free(op); + return OPERATOR_FINISHED; + } + /* add modal handler */ WM_event_add_modal_handler(C, op); - retval = op->type->modal(C, op, event); OPERATOR_RETVAL_CHECK(retval); BLI_assert(retval == OPERATOR_RUNNING_MODAL); @@ -3078,7 +3086,7 @@ static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event) static int vpaint_exec(bContext *C, wmOperator *op) { - op->customdata = paint_stroke_new(C, NULL, vpaint_stroke_test_start, + op->customdata = paint_stroke_new(C, op, NULL, vpaint_stroke_test_start, vpaint_stroke_update_step, NULL, vpaint_stroke_done, 0); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 12223effcf5..261da79e35c 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -359,19 +359,19 @@ static int sculpt_stroke_dynamic_topology(const SculptSession *ss, !(brush->flag & BRUSH_ANCHORED) && !(brush->flag & BRUSH_DRAG_DOT) && - (!ELEM6(brush->sculpt_tool, - /* These brushes, as currently coded, cannot - * support dynamic topology */ - SCULPT_TOOL_GRAB, - SCULPT_TOOL_ROTATE, - SCULPT_TOOL_THUMB, - SCULPT_TOOL_LAYER, + (!ELEM(brush->sculpt_tool, + /* These brushes, as currently coded, cannot + * support dynamic topology */ + SCULPT_TOOL_GRAB, + SCULPT_TOOL_ROTATE, + SCULPT_TOOL_THUMB, + SCULPT_TOOL_LAYER, - /* These brushes could handle dynamic topology, - * but user feedback indicates it's better not - * to */ - SCULPT_TOOL_SMOOTH, - SCULPT_TOOL_MASK))); + /* These brushes could handle dynamic topology, + * but user feedback indicates it's better not + * to */ + SCULPT_TOOL_SMOOTH, + SCULPT_TOOL_MASK))); } /*** paint mesh ***/ @@ -396,7 +396,7 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob) * entries might be inserted by sculpt_undo_push_node() into the * GHash used internally by BM_log_original_vert_co() by a * different thread. [#33787] */ -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP && !ss->bm) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && !ss->bm && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { SculptUndoNode *unode; SculptUndoType type = (brush->sculpt_tool == SCULPT_TOOL_MASK ? @@ -663,47 +663,6 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float loca /* ===== Sculpting ===== * */ - -static float overlapped_curve(Brush *br, float x) -{ - int i; - const int n = 100 / br->spacing; - const float h = br->spacing / 50.0f; - const float x0 = x - 1; - - float sum; - - sum = 0; - for (i = 0; i < n; i++) { - float xx; - - xx = fabsf(x0 + i * h); - - if (xx < 1.0f) - sum += BKE_brush_curve_strength(br, xx, 1); - } - - return sum; -} - -static float integrate_overlap(Brush *br) -{ - int i; - int m = 10; - float g = 1.0f / m; - float max; - - max = 0; - for (i = 0; i < m; i++) { - float overlap = overlapped_curve(br, i * g); - - if (overlap > max) - max = overlap; - } - - return max; -} - static void flip_v3(float v[3], const char symm) { flip_v3_v3(v, v, symm); @@ -776,7 +735,7 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache) /* Return modified brush strength. Includes the direction of the brush, positive * values pull vertices, negative values push. Uses tablet pressure and a * special multiplier found experimentally to scale the strength factor. */ -static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather) +static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather, UnifiedPaintSettings *ups) { const Scene *scene = cache->vc->scene; Brush *brush = BKE_paint_brush(&sd->paint); @@ -788,13 +747,10 @@ static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather) float pressure = BKE_brush_use_alpha_pressure(scene, brush) ? cache->pressure : 1; float pen_flip = cache->pen_flip ? -1 : 1; float invert = cache->invert ? -1 : 1; - float accum = integrate_overlap(brush); + float overlap = ups->overlap_factor; /* spacing is integer percentage of radius, divide by 50 to get * normalized diameter */ - float overlap = (brush->flag & BRUSH_SPACE_ATTEN && - brush->flag & BRUSH_SPACE && - !(brush->flag & BRUSH_ANCHORED) && - (brush->spacing < 100)) ? 1.0f / accum : 1; + float flip = dir * invert * pen_flip; switch (brush->sculpt_tool) { @@ -1040,7 +996,7 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod zero_v3(an); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -1236,14 +1192,14 @@ static int brush_needs_sculpt_normal(const Brush *brush) SCULPT_TOOL_SNAKE_HOOK) && (brush->normal_weight > 0)) || - ELEM7(brush->sculpt_tool, - SCULPT_TOOL_BLOB, - SCULPT_TOOL_CREASE, - SCULPT_TOOL_DRAW, - SCULPT_TOOL_LAYER, - SCULPT_TOOL_NUDGE, - SCULPT_TOOL_ROTATE, - SCULPT_TOOL_THUMB) || + ELEM(brush->sculpt_tool, + SCULPT_TOOL_BLOB, + SCULPT_TOOL_CREASE, + SCULPT_TOOL_DRAW, + SCULPT_TOOL_LAYER, + SCULPT_TOOL_NUDGE, + SCULPT_TOOL_ROTATE, + SCULPT_TOOL_THUMB) || (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA)); } @@ -1646,7 +1602,7 @@ static void smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, for (iteration = 0; iteration <= count; ++iteration) { float strength = (iteration != count) ? 1.0f : last; -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { switch (type) { case PBVH_GRIDS: @@ -1682,7 +1638,7 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot int n; /* threaded loop over nodes */ -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -1735,7 +1691,7 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) mul_v3_fl(offset, bstrength); /* threaded loop over nodes */ -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -1790,7 +1746,7 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod if (brush->sculpt_tool == SCULPT_TOOL_BLOB) flippedbstrength *= -1.0f; /* threaded loop over nodes */ -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -1833,7 +1789,7 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode float bstrength = ss->cache->bstrength; int n; -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -1880,7 +1836,7 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) add_v3_v3(grab_delta, ss->cache->sculpt_normal_symm); } -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -1928,7 +1884,7 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta); cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -1976,7 +1932,7 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to add_v3_v3(grab_delta, ss->cache->sculpt_normal_symm); } -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -2016,7 +1972,7 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta); cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -2059,7 +2015,7 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod static const int flip[8] = { 1, -1, -1, 1, -1, 1, 1, -1 }; float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass]; -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -2112,7 +2068,7 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode mul_v3_v3v3(offset, ss->cache->scale, ss->cache->sculpt_normal_symm); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -2175,7 +2131,7 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno float bstrength = ss->cache->bstrength; int n; -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -2220,7 +2176,7 @@ static void calc_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int to zero_v3(fc); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -2327,7 +2283,7 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob, /* for flatten center */ zero_v3(fc); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -2579,7 +2535,7 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno mul_v3_fl(temp, displace); add_v3_v3(fc, temp); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -2651,7 +2607,7 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) /* add_v3_v3v3(p, ss->cache->location, an); */ -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -2752,7 +2708,7 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t mul_m4_m4m4(tmat, mat, scale); invert_m4_m4(mat, tmat); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -2816,7 +2772,7 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) mul_v3_fl(temp, displace); add_v3_v3(fc, temp); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -2880,7 +2836,7 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod mul_v3_fl(temp, displace); add_v3_v3(fc, temp); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -2934,7 +2890,7 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl mul_v3_fl(offset, bstrength); /* threaded loop over nodes */ -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; @@ -3030,11 +2986,11 @@ static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush) radius = ss->cache->radius * 1.25f; data.radius_squared = radius * radius; - data.original = ELEM4(brush->sculpt_tool, - SCULPT_TOOL_GRAB, - SCULPT_TOOL_ROTATE, - SCULPT_TOOL_THUMB, - SCULPT_TOOL_LAYER) ? true : ss->cache->original; + data.original = ELEM(brush->sculpt_tool, + SCULPT_TOOL_GRAB, + SCULPT_TOOL_ROTATE, + SCULPT_TOOL_THUMB, + SCULPT_TOOL_LAYER) ? true : ss->cache->original; BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode); @@ -3092,18 +3048,18 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush) data.ss = ss; data.sd = sd; data.radius_squared = ss->cache->radius_squared; - data.original = ELEM4(brush->sculpt_tool, - SCULPT_TOOL_GRAB, - SCULPT_TOOL_ROTATE, - SCULPT_TOOL_THUMB, - SCULPT_TOOL_LAYER) ? true : ss->cache->original; + data.original = ELEM(brush->sculpt_tool, + SCULPT_TOOL_GRAB, + SCULPT_TOOL_ROTATE, + SCULPT_TOOL_THUMB, + SCULPT_TOOL_LAYER) ? true : ss->cache->original; BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode); /* Only act if some verts are inside the brush area */ if (totnode) { float location[3]; -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { sculpt_undo_push_node(ob, nodes[n], brush->sculpt_tool == SCULPT_TOOL_MASK ? @@ -3233,10 +3189,10 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob) ss->cache->supports_gravity) { /* these brushes start from original coordinates */ - const bool use_orco = ELEM3(brush->sculpt_tool, SCULPT_TOOL_GRAB, - SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB); + const bool use_orco = ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB, + SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; PBVHProxyNode *proxies; @@ -3329,7 +3285,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob) BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; @@ -3377,7 +3333,7 @@ static void calc_brushdata_symm(Sculpt *sd, StrokeCache *cache, const char symm, /* XXX This reduces the length of the grab delta if it approaches the line of symmetry * XXX However, a different approach appears to be needed */ #if 0 - if (sd->flags & SCULPT_SYMMETRY_FEATHER) { + if (sd->paint.symmetry_flags & SCULPT_SYMMETRY_FEATHER) { float frac = 1.0f / max_overlap_count(sd); float reduce = (feather - frac) / (1 - frac); @@ -3437,7 +3393,7 @@ static void sculpt_fix_noise_tear(Sculpt *sd, Object *ob) } static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob, - BrushActionFunc action) + BrushActionFunc action, UnifiedPaintSettings *ups) { Brush *brush = BKE_paint_brush(&sd->paint); SculptSession *ss = ob->sculpt; @@ -3447,7 +3403,7 @@ static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob, float feather = calc_symmetry_feather(sd, ss->cache); - cache->bstrength = brush_strength(sd, cache, feather); + cache->bstrength = brush_strength(sd, cache, feather, ups); cache->symmetry = symm; /* symm is a bit combination of XYZ - 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */ @@ -3733,8 +3689,8 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio /* not very nice, but with current events system implementation * we can't handle brush appearance inversion hotkey separately (sergey) */ - if (cache->invert) brush->flag |= BRUSH_INVERTED; - else brush->flag &= ~BRUSH_INVERTED; + if (cache->invert) ups->draw_inverted = true; + else ups->draw_inverted = false; /* Alt-Smooth */ if (cache->alt_smooth) { @@ -3780,7 +3736,7 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio mul_m3_v3(mat, viewDir); normalize_v3_v3(cache->true_view_normal, viewDir); - cache->supports_gravity = (!ELEM3(brush->sculpt_tool, SCULPT_TOOL_MASK, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_SIMPLIFY) && + cache->supports_gravity = (!ELEM(brush->sculpt_tool, SCULPT_TOOL_MASK, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_SIMPLIFY) && (sd->gravity_factor > 0.0f)); /* get gravity vector in world space */ if (cache->supports_gravity) { @@ -3838,10 +3794,10 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio cache->original = 1; } - if (ELEM9(brush->sculpt_tool, - SCULPT_TOOL_DRAW, SCULPT_TOOL_CREASE, SCULPT_TOOL_BLOB, - SCULPT_TOOL_LAYER, SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY, - SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_ROTATE, SCULPT_TOOL_FLATTEN)) + if (ELEM(brush->sculpt_tool, + SCULPT_TOOL_DRAW, SCULPT_TOOL_CREASE, SCULPT_TOOL_BLOB, + SCULPT_TOOL_LAYER, SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY, + SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_ROTATE, SCULPT_TOOL_FLATTEN)) { if (!(brush->flag & BRUSH_ACCUMULATE)) { cache->original = 1; @@ -3868,10 +3824,10 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru }; int tool = brush->sculpt_tool; - if (ELEM5(tool, - SCULPT_TOOL_GRAB, SCULPT_TOOL_NUDGE, - SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_SNAKE_HOOK, - SCULPT_TOOL_THUMB)) + if (ELEM(tool, + SCULPT_TOOL_GRAB, SCULPT_TOOL_NUDGE, + SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_SNAKE_HOOK, + SCULPT_TOOL_THUMB)) { float grab_location[3], imat[4][4], delta[3], loc[3]; @@ -3992,16 +3948,9 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, cache->radius_squared = cache->radius * cache->radius; if (brush->flag & BRUSH_ANCHORED) { + /* true location has been calculated as part of the stroke system already here */ if (brush->flag & BRUSH_EDGE_TO_EDGE) { - float halfway[2]; - float out[3]; - halfway[0] = 0.5f * (cache->mouse[0] + cache->initial_mouse[0]); - halfway[1] = 0.5f * (cache->mouse[1] + cache->initial_mouse[1]); - - if (sculpt_stroke_get_location(C, out, halfway)) { - copy_v3_v3(cache->anchored_location, out); - copy_v3_v3(cache->true_location, cache->anchored_location); - } + RNA_float_get_array(ptr, "location", cache->true_location); } cache->radius = paint_calc_object_space_radius(cache->vc, @@ -4393,10 +4342,10 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *UNUSED(st } if (sculpt_stroke_dynamic_topology(ss, brush)) { - do_symmetrical_brush_actions(sd, ob, sculpt_topology_update); + do_symmetrical_brush_actions(sd, ob, sculpt_topology_update, ups); } - do_symmetrical_brush_actions(sd, ob, do_brush_action); + do_symmetrical_brush_actions(sd, ob, do_brush_action, ups); sculpt_combine_proxies(sd, ob); @@ -4446,8 +4395,9 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str /* Finished */ if (ss->cache) { + UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; Brush *brush = BKE_paint_brush(&sd->paint); - brush->flag &= ~BRUSH_INVERTED; + ups->draw_inverted = false; sculpt_stroke_modifiers_check(C, ob); @@ -4506,7 +4456,7 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent if (!sculpt_brush_stroke_init(C, op)) return OPERATOR_CANCELLED; - stroke = paint_stroke_new(C, sculpt_stroke_get_location, + stroke = paint_stroke_new(C, op, sculpt_stroke_get_location, sculpt_stroke_test_start, sculpt_stroke_update_step, NULL, sculpt_stroke_done, event->type); @@ -4521,10 +4471,13 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent return OPERATOR_PASS_THROUGH; } + if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) { + paint_stroke_data_free(op); + return OPERATOR_FINISHED; + } /* add modal handler */ WM_event_add_modal_handler(C, op); - retval = op->type->modal(C, op, event); OPERATOR_RETVAL_CHECK(retval); BLI_assert(retval == OPERATOR_RUNNING_MODAL); @@ -4536,7 +4489,7 @@ static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op) if (!sculpt_brush_stroke_init(C, op)) return OPERATOR_CANCELLED; - op->customdata = paint_stroke_new(C, sculpt_stroke_get_location, sculpt_stroke_test_start, + op->customdata = paint_stroke_new(C, op, sculpt_stroke_get_location, sculpt_stroke_test_start, sculpt_stroke_update_step, NULL, sculpt_stroke_done, 0); /* frees op->customdata */ @@ -4856,7 +4809,7 @@ static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, co bool modifiers = false; for (i = 0; i < CD_NUMTYPES; i++) { - if (!ELEM7(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX) && + if (!ELEM(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX) && (CustomData_has_layer(&me->vdata, i) || CustomData_has_layer(&me->edata, i) || CustomData_has_layer(&me->fdata, i))) @@ -5062,11 +5015,11 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) ts->sculpt->paint.flags |= PAINT_SHOW_BRUSH; /* Make sure at least dyntopo subdivision is enabled */ - ts->sculpt->flags |= SCULPT_DYNTOPO_SUBDIVIDE; + ts->sculpt->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE; } if (!ts->sculpt->detail_size) { - ts->sculpt->detail_size = 30; + ts->sculpt->detail_size = 12; } if (ts->sculpt->constant_detail == 0.0f) diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index cd79f525d82..a61f571fdf6 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -130,4 +130,11 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3]); void sculpt_update_object_bounding_box(struct Object *ob); +/* Setting zero so we can catch bugs in OpenMP/sculpt. */ +#ifdef DEBUG +# define SCULPT_OMP_LIMIT 0 +#else +# define SCULPT_OMP_LIMIT 4 +#endif + #endif diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 0d49049c78e..91f80a4fc40 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -291,7 +291,7 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C, BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); -#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) +#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT) for (i = 0; i < totnode; i++) { BKE_pbvh_node_mark_redraw(nodes[i]); } @@ -543,7 +543,7 @@ static void sculpt_undo_free(ListBase *lb) } } -bool sculpt_undo_cleanup(bContext *C, ListBase *lb) +static bool sculpt_undo_cleanup(bContext *C, ListBase *lb) { Object *ob = CTX_data_active_object(C); SculptUndoNode *unode; @@ -551,10 +551,8 @@ bool sculpt_undo_cleanup(bContext *C, ListBase *lb) unode = lb->first; if (unode && strcmp(unode->idname, ob->id.name) != 0) { - for (unode = lb->first; unode; unode = unode->next) { - if (unode->bm_entry) - BM_log_cleanup_entry(unode->bm_entry); - } + if (unode->bm_entry) + BM_log_cleanup_entry(unode->bm_entry); return true; } @@ -881,7 +879,7 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, void sculpt_undo_push_begin(const char *name) { ED_undo_paint_push_begin(UNDO_PAINT_MESH, name, - sculpt_undo_restore, sculpt_undo_free); + sculpt_undo_restore, sculpt_undo_free, sculpt_undo_cleanup); } void sculpt_undo_push_end(void) diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c index 797a881ce79..292d6236bab 100644 --- a/source/blender/editors/sculpt_paint/sculpt_uv.c +++ b/source/blender/editors/sculpt_paint/sculpt_uv.c @@ -239,12 +239,14 @@ void ED_space_image_uv_sculpt_update(wmWindowManager *wm, ToolSettings *settings BKE_paint_init(&settings->uvsculpt->paint, PAINT_CURSOR_SCULPT); - WM_paint_cursor_activate(wm, uv_sculpt_brush_poll, - brush_drawcursor_uvsculpt, NULL); + settings->uvsculpt->paint.paint_cursor = WM_paint_cursor_activate(wm, uv_sculpt_brush_poll, + brush_drawcursor_uvsculpt, NULL); } else { - if (settings->uvsculpt) - settings->uvsculpt->paint.flags &= ~PAINT_SHOW_BRUSH; + if (settings->uvsculpt) { + WM_paint_cursor_end(wm, settings->uvsculpt->paint.paint_cursor); + settings->uvsculpt->paint.paint_cursor = NULL; + } } } diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c index b2e55085579..335949e8495 100644 --- a/source/blender/editors/space_action/action_draw.c +++ b/source/blender/editors/space_action/action_draw.c @@ -219,7 +219,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) if (acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT)) sel = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT); - if (ELEM3(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY)) { + if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY)) { switch (ale->type) { case ANIMTYPE_SUMMARY: { diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index cf18cffefb6..ddfca98a119 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -1086,8 +1086,9 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_ View2D *v2d = &ac->ar->v2d; bDopeSheet *ads = NULL; int channel_index; - short found = 0; - float selx = 0.0f; + bool found = false; + float frame = 0.0f; /* frame of keyframe under mouse - NLA corrections not applied/included */ + float selx = 0.0f; /* frame of keyframe under mouse */ float x, y; rctf rectf; @@ -1179,7 +1180,8 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_ * requiring to map each frame once again... */ selx = BKE_nla_tweakedit_remap(adt, ak->cfra, NLATIME_CONVERT_UNMAP); - found = 1; + frame = ak->cfra; + found = true; break; } else if (ak->cfra < rectf.xmin) @@ -1258,8 +1260,11 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_ if (found) { /* apply selection to keyframes */ if (column) { - /* select all keyframes in the same frame as the one we hit on the active channel */ - actkeys_mselect_column(ac, select_mode, selx); + /* select all keyframes in the same frame as the one we hit on the active channel + * [T41077]: "frame" not "selx" here (i.e. no NLA corrections yet) as the code here + * does that itself again as it needs to work on multiple datablocks + */ + actkeys_mselect_column(ac, select_mode, frame); } else if (same_channel) { /* select all keyframes in the active channel */ diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index 7a74a58c69d..b171e7a5f88 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -144,6 +144,7 @@ void ED_spacetypes_init(void) ED_operatormacros_curve(); ED_operatormacros_mask(); ED_operatormacros_sequencer(); + ED_operatormacros_paint(); /* register dropboxes (can use macros) */ spacetypes = BKE_spacetypes_list(); diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 8917704b731..524a42ba388 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -200,7 +200,7 @@ static int buttons_context_path_data(ButsContextPath *path, int type) /* if we already have a data, we're done */ if (RNA_struct_is_a(ptr->type, &RNA_Mesh) && (type == -1 || type == OB_MESH)) return 1; - else if (RNA_struct_is_a(ptr->type, &RNA_Curve) && (type == -1 || ELEM3(type, OB_CURVE, OB_SURF, OB_FONT))) return 1; + else if (RNA_struct_is_a(ptr->type, &RNA_Curve) && (type == -1 || ELEM(type, OB_CURVE, OB_SURF, OB_FONT))) return 1; else if (RNA_struct_is_a(ptr->type, &RNA_Armature) && (type == -1 || type == OB_ARMATURE)) return 1; else if (RNA_struct_is_a(ptr->type, &RNA_MetaBall) && (type == -1 || type == OB_MBALL)) return 1; else if (RNA_struct_is_a(ptr->type, &RNA_Lattice) && (type == -1 || type == OB_LATTICE)) return 1; @@ -230,7 +230,7 @@ static int buttons_context_path_modifier(ButsContextPath *path) if (buttons_context_path_object(path)) { ob = path->ptr[path->len - 1].data; - if (ob && ELEM5(ob->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF, OB_LATTICE)) + if (ob && ELEM(ob->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF, OB_LATTICE)) return 1; } @@ -638,7 +638,7 @@ static int buttons_shading_context(const bContext *C, int mainb) { Object *ob = CTX_data_active_object(C); - if (ELEM3(mainb, BCONTEXT_MATERIAL, BCONTEXT_WORLD, BCONTEXT_TEXTURE)) + if (ELEM(mainb, BCONTEXT_MATERIAL, BCONTEXT_WORLD, BCONTEXT_TEXTURE)) return 1; if (mainb == BCONTEXT_DATA && ob && ELEM(ob->type, OB_LAMP, OB_CAMERA)) return 1; @@ -1120,7 +1120,7 @@ void buttons_context_draw(const bContext *C, uiLayout *layout) name = RNA_struct_name_get_alloc(ptr, namebuf, sizeof(namebuf), NULL); if (name) { - if (!ELEM3(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_SCENE, BCONTEXT_RENDER_LAYER) && ptr->type == &RNA_Scene) + if (!ELEM(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_SCENE, BCONTEXT_RENDER_LAYER) && ptr->type == &RNA_Scene) uiItemLDrag(row, ptr, "", icon); /* save some space */ else uiItemLDrag(row, ptr, name, icon); diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index 1c3bad9757d..8c6bf67c9a8 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -358,7 +358,7 @@ static void buttons_area_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier * case NC_ANIMATION: switch (wmn->data) { case ND_KEYFRAME: - if (ELEM3(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED)) + if (ELEM(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED)) ED_area_tag_redraw(sa); break; } diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index 9a939bdc2ca..b5c08e7a08a 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -1728,7 +1728,7 @@ void clip_draw_main(const bContext *C, SpaceClip *sc, ARegion *ar) smat[1][1] = 1.0f / height; invert_m4_m4(ismat, smat); - mul_serie_m4(sc->unistabmat, smat, sc->stabmat, ismat, NULL, NULL, NULL, NULL, NULL); + mul_m4_series(sc->unistabmat, smat, sc->stabmat, ismat); } } else if ((sc->flag & SC_MUTE_FOOTAGE) == 0) { diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index d3be25050c8..a6fbb0c399d 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -846,7 +846,7 @@ static int clip_context(const bContext *C, const char *member, bContextDataResul static int clip_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) { if (drag->type == WM_DRAG_PATH) - if (ELEM4(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE, ICON_FILE_BLANK)) /* rule might not work? */ + if (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE, ICON_FILE_BLANK)) /* rule might not work? */ return true; return false; diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c index ce14471f608..abbffcd8546 100644 --- a/source/blender/editors/space_clip/tracking_ops.c +++ b/source/blender/editors/space_clip/tracking_ops.c @@ -2277,7 +2277,7 @@ static void set_axis(Scene *scene, Object *ob, MovieClip *clip, MovieTrackingOb copy_v3_v3(lmat[3], obmat[3]); invert_m4_m4(ilmat, lmat); - mul_serie_m4(mat, lmat, mat, ilmat, obmat, NULL, NULL, NULL, NULL); + mul_m4_series(mat, lmat, mat, ilmat, obmat); } else { mul_m4_m4m4(mat, obmat, mat); @@ -2996,7 +2996,7 @@ void CLIP_OT_detect_features(wmOperatorType *ot) /* properties */ RNA_def_enum(ot->srna, "placement", placement_items, 0, "Placement", "Placement for detected features"); RNA_def_int(ot->srna, "margin", 16, 0, INT_MAX, "Margin", "Only features further than margin pixels from the image edges are considered", 0, 300); - RNA_def_float(ot->srna, "threshold", 1.0f, 0.0001f, FLT_MAX, "Threshold", "Threshold level to consider feature good enough for tracking", 0.0001f, FLT_MAX); + RNA_def_float(ot->srna, "threshold", 0.5f, 0.0001f, FLT_MAX, "Threshold", "Threshold level to consider feature good enough for tracking", 0.0001f, FLT_MAX); RNA_def_int(ot->srna, "min_distance", 120, 0, INT_MAX, "Distance", "Minimal distance accepted between two features", 0, 300); } diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 3a493c0338c..d5be04cff20 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -422,7 +422,7 @@ static void file_keymap(struct wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, 0, 0); kmi = WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "extend", true); - kmi = WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, KM_ALT, 0); + kmi = WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, KM_CTRL | KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "extend", true); RNA_boolean_set(kmi->ptr, "fill", true); diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 1f1aac8c456..c8298927f7d 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -1707,7 +1707,7 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op) */ if (strstr(fcu->rna_path, "rotation_euler") == NULL) continue; - else if (ELEM3(fcu->array_index, 0, 1, 2) == 0) { + else if (ELEM(fcu->array_index, 0, 1, 2) == 0) { BKE_reportf(op->reports, RPT_WARNING, "Euler Rotation F-Curve has invalid index (ID='%s', Path='%s', Index=%d)", (ale->id) ? ale->id->name : TIP_("<No ID>"), fcu->rna_path, fcu->array_index); @@ -1750,7 +1750,7 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op) /* sanity check: ensure that there are enough F-Curves to work on in this group */ /* TODO: also enforce assumption that there be a full set of keyframes at each position by ensuring that totvert counts are same? */ - if (ELEM3(NULL, euf->fcurves[0], euf->fcurves[1], euf->fcurves[2])) { + if (ELEM(NULL, euf->fcurves[0], euf->fcurves[1], euf->fcurves[2])) { /* report which components are missing */ BKE_reportf(op->reports, RPT_WARNING, "Missing %s%s%s component(s) of euler rotation for ID='%s' and RNA-Path='%s'", diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 3675282654f..7e90008d8d2 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -843,14 +843,14 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, int color_man uiItemR(sub, imfptr, "color_mode", UI_ITEM_R_EXPAND, IFACE_("Color"), ICON_NONE); /* only display depth setting if multiple depths can be used */ - if ((ELEM7(depth_ok, - R_IMF_CHAN_DEPTH_1, - R_IMF_CHAN_DEPTH_8, - R_IMF_CHAN_DEPTH_10, - R_IMF_CHAN_DEPTH_12, - R_IMF_CHAN_DEPTH_16, - R_IMF_CHAN_DEPTH_24, - R_IMF_CHAN_DEPTH_32)) == 0) + if ((ELEM(depth_ok, + R_IMF_CHAN_DEPTH_1, + R_IMF_CHAN_DEPTH_8, + R_IMF_CHAN_DEPTH_10, + R_IMF_CHAN_DEPTH_12, + R_IMF_CHAN_DEPTH_16, + R_IMF_CHAN_DEPTH_24, + R_IMF_CHAN_DEPTH_32)) == 0) { row = uiLayoutRow(col, false); diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c index a2f7d9e7d6c..24b1c54dd9f 100644 --- a/source/blender/editors/space_image/image_edit.c +++ b/source/blender/editors/space_image/image_edit.c @@ -28,6 +28,7 @@ * \ingroup spimage */ +#include "DNA_brush_types.h" #include "DNA_mask_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -297,44 +298,51 @@ bool ED_space_image_show_render(SpaceImage *sima) bool ED_space_image_show_paint(SpaceImage *sima) { if (ED_space_image_show_render(sima)) - return 0; + return false; return (sima->mode == SI_MODE_PAINT); } +bool ED_space_image_show_texpaint(SpaceImage *sima, Object *ob) +{ + return (ob && ob->type == OB_MESH && + ob->mode == OB_MODE_TEXTURE_PAINT && + !(sima->flag & SI_NO_DRAW_TEXPAINT)); +} + bool ED_space_image_show_uvedit(SpaceImage *sima, Object *obedit) { if (sima && (ED_space_image_show_render(sima) || ED_space_image_show_paint(sima))) - return 0; + return false; if (obedit && obedit->type == OB_MESH) { struct BMEditMesh *em = BKE_editmesh_from_object(obedit); - int ret; + bool ret; ret = EDBM_mtexpoly_check(em); return ret; } - return 0; + return false; } bool ED_space_image_show_uvshadow(SpaceImage *sima, Object *obedit) { if (ED_space_image_show_render(sima)) - return 0; + return false; if (ED_space_image_show_paint(sima)) if (obedit && obedit->type == OB_MESH) { struct BMEditMesh *em = BKE_editmesh_from_object(obedit); - int ret; + bool ret; ret = EDBM_mtexpoly_check(em); - return ret; + return ret && !(sima->flag & SI_NO_DRAW_TEXPAINT); } - return 0; + return false; } /* matches clip function */ @@ -361,6 +369,21 @@ int ED_space_image_maskedit_poll(bContext *C) return false; } +bool ED_space_image_paint_curve(const bContext *C) +{ + SpaceImage *sima = CTX_wm_space_image(C); + + if (sima && sima->mode == SI_MODE_PAINT) { + Brush *br = CTX_data_tool_settings(C)->imapaint.paint.brush; + + if (br && (br->flag & BRUSH_CURVE)) + return true; + } + + return false; +} + + int ED_space_image_maskedit_mask_poll(bContext *C) { if (ED_space_image_maskedit_poll(C)) { diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 4ae05d8f64f..66bd346ae69 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1383,7 +1383,7 @@ static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima, /* sanitize all settings */ /* unlikely but just in case */ - if (ELEM3(simopts->im_format.planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB, R_IMF_PLANES_RGBA) == 0) { + if (ELEM(simopts->im_format.planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB, R_IMF_PLANES_RGBA) == 0) { simopts->im_format.planes = R_IMF_PLANES_RGBA; } @@ -1904,6 +1904,7 @@ static int image_new_exec(bContext *C, wmOperator *op) char *name = _name; float color[4]; int width, height, floatbuf, gen_type, alpha; + bool stencil; /* retrieve state */ sima = CTX_wm_space_image(C); @@ -1923,7 +1924,8 @@ static int image_new_exec(bContext *C, wmOperator *op) gen_type = RNA_enum_get(op->ptr, "generated_type"); RNA_float_get_array(op->ptr, "color", color); alpha = RNA_boolean_get(op->ptr, "alpha"); - + stencil = RNA_boolean_get(op->ptr, "texstencil"); + if (!alpha) color[3] = 1.0f; @@ -1955,6 +1957,13 @@ static int image_new_exec(bContext *C, wmOperator *op) tex->ima = ima; ED_area_tag_redraw(CTX_wm_area(C)); } + else if (stencil) { + ImagePaintSettings *imapaint = &(CTX_data_tool_settings(C)->imapaint); + + if (imapaint->stencil) + id_us_min(&imapaint->stencil->id); + imapaint->stencil = ima; + } } BKE_image_signal(ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_USER_NEW_IMAGE); @@ -2003,6 +2012,9 @@ void IMAGE_OT_new(wmOperatorType *ot) RNA_def_enum(ot->srna, "generated_type", image_generated_type_items, IMA_GENTYPE_BLANK, "Generated Type", "Fill the image with a grid for UV map testing"); RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth"); + prop = RNA_def_boolean(ot->srna, "texstencil", 0, "Stencil", "Set Image as stencil"); + RNA_def_property_flag(prop, PROP_HIDDEN); + } #undef IMA_DEF_NAME @@ -2037,7 +2049,7 @@ static int image_invert_exec(bContext *C, wmOperator *op) if (support_undo) { ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name, - ED_image_undo_restore, ED_image_undo_free); + ED_image_undo_restore, ED_image_undo_free, NULL); /* not strictly needed, because we only imapaint_dirty_region to invalidate all tiles * but better do this right in case someone copies this for a tool that uses partial redraw better */ ED_imapaint_clear_partial_redraw(); diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 0fb93ad27ee..375a0ddeac3 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -349,7 +349,7 @@ static void image_keymap(struct wmKeyConfig *keyconf) static int image_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) { if (drag->type == WM_DRAG_PATH) - if (ELEM3(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_BLANK)) /* rule might not work? */ + if (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_BLANK)) /* rule might not work? */ return 1; return 0; } @@ -633,6 +633,12 @@ static void image_main_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); /* image paint polls for mode */ + keymap = WM_keymap_find(wm->defaultconf, "Curve", 0, 0); + WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); + + keymap = WM_keymap_find(wm->defaultconf, "Paint Curve", 0, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); + keymap = WM_keymap_find(wm->defaultconf, "Image Paint", 0, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); @@ -657,6 +663,7 @@ static void image_main_area_draw(const bContext *C, ARegion *ar) Object *obact = CTX_data_active_object(C); Object *obedit = CTX_data_edit_object(C); Mask *mask = NULL; + bool curve = false; Scene *scene = CTX_data_scene(C); View2D *v2d = &ar->v2d; //View2DScrollers *scrollers; @@ -702,6 +709,9 @@ static void image_main_area_draw(const bContext *C, ARegion *ar) else if (sima->mode == SI_MODE_MASK) { mask = ED_space_image_get_mask(sima); } + else if (ED_space_image_paint_curve(C)) { + curve = true; + } ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW); @@ -753,6 +763,11 @@ static void image_main_area_draw(const bContext *C, ARegion *ar) draw_image_cursor(ar, sima->cursor); UI_view2d_view_restore(C); } + else if (curve) { + UI_view2d_view_ortho(v2d); + draw_image_cursor(ar, sima->cursor); + UI_view2d_view_restore(C); + } draw_image_cache(C, ar); diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index 9f3fc53482a..dd152022762 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -1832,7 +1832,7 @@ static void draw_actuator_motion(uiLayout *layout, PointerRNA *ptr) uiItemR(row, ptr, "offset_rotation", 0, NULL, ICON_NONE); uiItemR(split, ptr, "use_local_rotation", UI_ITEM_R_TOGGLE, NULL, ICON_NONE); - if (ELEM3(physics_type, OB_BODY_TYPE_DYNAMIC, OB_BODY_TYPE_RIGID, OB_BODY_TYPE_SOFT)) { + if (ELEM(physics_type, OB_BODY_TYPE_DYNAMIC, OB_BODY_TYPE_RIGID, OB_BODY_TYPE_SOFT)) { uiItemL(layout, IFACE_("Dynamic Object Settings:"), ICON_NONE); split = uiLayoutSplit(layout, 0.9, false); row = uiLayoutRow(split, false); diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index ef23fc24194..6fa9290c732 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -2307,6 +2307,12 @@ static void node_composit_buts_cornerpin(uiLayout *UNUSED(layout), bContext *UNU { } +static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "source", UI_ITEM_R_EXPAND, "", ICON_NONE); + uiItemR(layout, ptr, "ray_length", UI_ITEM_R_SLIDER, NULL, ICON_NONE); +} + /* only once called */ static void node_composit_set_butfunc(bNodeType *ntype) { @@ -2531,6 +2537,9 @@ static void node_composit_set_butfunc(bNodeType *ntype) case CMP_NODE_CORNERPIN: ntype->draw_buttons = node_composit_buts_cornerpin; break; + case CMP_NODE_SUNBEAMS: + ntype->draw_buttons = node_composit_buts_sunbeams; + break; } } diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 1c41ce9d86d..8422df35063 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -640,10 +640,10 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node) /* tree specific activate calls */ if (ntree->type == NTREE_SHADER) { /* when we select a material, active texture is cleared, for buttons */ - if (node->id && ELEM3(GS(node->id->name), ID_MA, ID_LA, ID_WO)) + if (node->id && ELEM(GS(node->id->name), ID_MA, ID_LA, ID_WO)) nodeClearActiveID(ntree, ID_TE); - if (ELEM4(node->type, SH_NODE_OUTPUT, SH_NODE_OUTPUT_MATERIAL, + if (ELEM(node->type, SH_NODE_OUTPUT, SH_NODE_OUTPUT_MATERIAL, SH_NODE_OUTPUT_WORLD, SH_NODE_OUTPUT_LAMP)) { bNode *tnode; diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 1f728b380d6..7eb90953df4 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -638,7 +638,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar uiButSetFlag(bt, UI_BUT_DRAG_LOCK); layflag++; /* is lay_xor */ - if (ELEM8(passflag, SCE_PASS_SPEC, SCE_PASS_SHADOW, SCE_PASS_AO, SCE_PASS_REFLECT, SCE_PASS_REFRACT, + if (ELEM(passflag, SCE_PASS_SPEC, SCE_PASS_SHADOW, SCE_PASS_AO, SCE_PASS_REFLECT, SCE_PASS_REFRACT, SCE_PASS_INDIRECT, SCE_PASS_EMIT, SCE_PASS_ENVIRONMENT)) { bt = uiDefIconButBitI(block, TOG, passflag, 0, (*layflag & passflag) ? ICON_DOT : ICON_BLANK1, diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 17e1e032bbf..ef621407abd 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -215,15 +215,15 @@ void OUTLINER_OT_item_openclose(wmOperatorType *ot) static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem, ReportList *reports) { /* can't rename rna datablocks entries or listbases */ - if (ELEM4(tselem->type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, TSE_ID_BASE)) { + if (ELEM(tselem->type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, TSE_ID_BASE)) { /* do nothing */; } - else if (ELEM10(tselem->type, TSE_ANIM_DATA, TSE_NLA, TSE_DEFGROUP_BASE, TSE_CONSTRAINT_BASE, TSE_MODIFIER_BASE, - TSE_DRIVER_BASE, TSE_POSE_BASE, TSE_POSEGRP_BASE, TSE_R_LAYER_BASE, TSE_R_PASS)) + else if (ELEM(tselem->type, TSE_ANIM_DATA, TSE_NLA, TSE_DEFGROUP_BASE, TSE_CONSTRAINT_BASE, TSE_MODIFIER_BASE, + TSE_DRIVER_BASE, TSE_POSE_BASE, TSE_POSEGRP_BASE, TSE_R_LAYER_BASE, TSE_R_PASS)) { BKE_report(reports, RPT_WARNING, "Cannot edit builtin name"); } - else if (ELEM3(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) { + else if (ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) { BKE_report(reports, RPT_WARNING, "Cannot edit sequence name"); } else if (tselem->id->lib) { @@ -1654,7 +1654,7 @@ static int outliner_parenting_poll(bContext *C) SpaceOops *soops = CTX_wm_space_outliner(C); if (soops) { - return ELEM4(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS); + return ELEM(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS); } return false; diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index d7521edd57a..6f5bf712d55 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -948,7 +948,7 @@ static bool do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, Sp WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } - else if (ELEM5(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) { + else if (ELEM(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) { WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL); } else { // rest of types diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index d1e9b3d34b7..d09ed1a100e 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -1339,7 +1339,7 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S else if (datalevel == TSE_DRIVER_BASE) { /* do nothing... no special ops needed yet */ } - else if (ELEM3(datalevel, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS)) { + else if (ELEM(datalevel, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS)) { /*WM_operator_name_call(C, "OUTLINER_OT_renderdata_operation", WM_OP_INVOKE_REGION_WIN, NULL)*/ } else { diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 520cd9a544d..5801dd126e3 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -821,7 +821,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i TreeStoreElem *tselem; ID *id = idv; - if (ELEM3(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { + if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { id = ((PointerRNA *)idv)->id.data; if (!id) id = ((PointerRNA *)idv)->data; } @@ -847,10 +847,10 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i te->parent = parent; te->index = index; // for data arays - if (ELEM3(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) { + if (ELEM(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) { /* pass */ } - else if (ELEM3(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { + else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { /* pass */ } else if (type == TSE_ANIM_DATA) { @@ -985,7 +985,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i te->directdata = seq; te->name = seq->strip->stripdata->name; } - else if (ELEM3(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { + else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { PointerRNA pptr, propptr, *ptr = (PointerRNA *)idv; PropertyRNA *prop, *iterprop; PropertyType proptype; @@ -1062,7 +1062,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i else if (tot) te->flag |= TE_LAZY_CLOSED; } - else if (ELEM3(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) { + else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) { tot = RNA_property_array_length(ptr, prop); if (TSELEM_OPEN(tselem, soops)) { diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index 41c5b00b381..504d9628d98 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -143,7 +143,7 @@ static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent * UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); - if (!ELEM4(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS)) { + if (!ELEM(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS)) { return false; } @@ -156,7 +156,7 @@ static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent * switch (te->idcode) { case ID_SCE: - return (ELEM3(tselem->type, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS)); + return (ELEM(tselem->type, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS)); case ID_OB: return (ELEM(tselem->type, TSE_MODIFIER_BASE, TSE_CONSTRAINT_BASE)); /* Other codes to ignore? */ diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 4ad5ed8bb80..dab51f752b4 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -142,19 +142,21 @@ static void get_seq_color3ubv(Scene *curscene, Sequence *seq, unsigned char col[ case SEQ_TYPE_GLOW: case SEQ_TYPE_MULTICAM: case SEQ_TYPE_ADJUSTMENT: + case SEQ_TYPE_GAUSSIAN_BLUR: UI_GetThemeColor3ubv(TH_SEQ_EFFECT, col); /* slightly offset hue to distinguish different effects */ - if (seq->type == SEQ_TYPE_ADD) rgb_byte_set_hue_float_offset(col, 0.04); - else if (seq->type == SEQ_TYPE_SUB) rgb_byte_set_hue_float_offset(col, 0.08); - else if (seq->type == SEQ_TYPE_MUL) rgb_byte_set_hue_float_offset(col, 0.12); - else if (seq->type == SEQ_TYPE_ALPHAOVER) rgb_byte_set_hue_float_offset(col, 0.16); - else if (seq->type == SEQ_TYPE_ALPHAUNDER) rgb_byte_set_hue_float_offset(col, 0.20); - else if (seq->type == SEQ_TYPE_OVERDROP) rgb_byte_set_hue_float_offset(col, 0.24); - else if (seq->type == SEQ_TYPE_GLOW) rgb_byte_set_hue_float_offset(col, 0.28); - else if (seq->type == SEQ_TYPE_TRANSFORM) rgb_byte_set_hue_float_offset(col, 0.36); - else if (seq->type == SEQ_TYPE_MULTICAM) rgb_byte_set_hue_float_offset(col, 0.32); - else if (seq->type == SEQ_TYPE_ADJUSTMENT) rgb_byte_set_hue_float_offset(col, 0.40); + if (seq->type == SEQ_TYPE_ADD) rgb_byte_set_hue_float_offset(col, 0.04); + else if (seq->type == SEQ_TYPE_SUB) rgb_byte_set_hue_float_offset(col, 0.08); + else if (seq->type == SEQ_TYPE_MUL) rgb_byte_set_hue_float_offset(col, 0.12); + else if (seq->type == SEQ_TYPE_ALPHAOVER) rgb_byte_set_hue_float_offset(col, 0.16); + else if (seq->type == SEQ_TYPE_ALPHAUNDER) rgb_byte_set_hue_float_offset(col, 0.20); + else if (seq->type == SEQ_TYPE_OVERDROP) rgb_byte_set_hue_float_offset(col, 0.24); + else if (seq->type == SEQ_TYPE_GLOW) rgb_byte_set_hue_float_offset(col, 0.28); + else if (seq->type == SEQ_TYPE_TRANSFORM) rgb_byte_set_hue_float_offset(col, 0.36); + else if (seq->type == SEQ_TYPE_MULTICAM) rgb_byte_set_hue_float_offset(col, 0.32); + else if (seq->type == SEQ_TYPE_ADJUSTMENT) rgb_byte_set_hue_float_offset(col, 0.40); + else if (seq->type == SEQ_TYPE_GAUSSIAN_BLUR) rgb_byte_set_hue_float_offset(col, 0.42); break; case SEQ_TYPE_COLOR: diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 3c17b2986ff..dcf13dbf43f 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -86,6 +86,7 @@ EnumPropertyItem sequencer_prop_effect_types[] = { {SEQ_TYPE_SPEED, "SPEED", 0, "Speed", "Color effect strip type"}, {SEQ_TYPE_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""}, {SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""}, + {SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""}, {0, NULL, 0, NULL, NULL} }; @@ -1918,9 +1919,12 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op) strip_new = seq_new->strip; strip_new->us = 1; - /* new stripdata */ - se_new = strip_new->stripdata; + /* new stripdata (only one element now!) */ + /* Note this assume all elements (images) have the same dimension, since we only copy the name here. */ + se_new = MEM_reallocN(strip_new->stripdata, sizeof(*se_new)); BLI_strncpy(se_new->name, se->name, sizeof(se_new->name)); + strip_new->stripdata = se_new; + BKE_sequence_calc(scene, seq_new); if (step > 1) { diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c index 9826ef10902..8e49d5649f3 100644 --- a/source/blender/editors/space_sequencer/sequencer_select.c +++ b/source/blender/editors/space_sequencer/sequencer_select.c @@ -912,7 +912,7 @@ static EnumPropertyItem sequencer_prop_select_grouped_types[] = { #define SEQ_IS_EFFECT(_seq) ((_seq->type & SEQ_TYPE_EFFECT) != 0) -#define SEQ_USE_DATA(_seq) (ELEM3(_seq->type, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIECLIP, SEQ_TYPE_MASK) || SEQ_HAS_PATH(_seq)) +#define SEQ_USE_DATA(_seq) (ELEM(_seq->type, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIECLIP, SEQ_TYPE_MASK) || SEQ_HAS_PATH(_seq)) static bool select_grouped_type(Editing *ed, Sequence *actseq) { @@ -1035,7 +1035,7 @@ static bool select_grouped_effect(Editing *ed, Sequence *actseq) SEQP_BEGIN (ed, seq) { - if (ELEM3(actseq, seq->seq1, seq->seq2, seq->seq3)) { + if (ELEM(actseq, seq->seq1, seq->seq2, seq->seq3)) { effects[seq->type] = true; } } diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index a94b73802b2..c0cfaed7867 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -279,24 +279,40 @@ static void sequencer_refresh(const bContext *C, ScrArea *sa) } break; case SEQ_VIEW_SEQUENCE_PREVIEW: - if (ar_main && (ar_main->flag & RGN_FLAG_HIDDEN)) { - ar_main->flag &= ~RGN_FLAG_HIDDEN; - ar_main->v2d.flag &= ~V2D_IS_INITIALISED; - view_changed = true; - } - if (ar_preview && (ar_preview->flag & RGN_FLAG_HIDDEN)) { - ar_preview->flag &= ~RGN_FLAG_HIDDEN; - ar_preview->v2d.flag &= ~V2D_IS_INITIALISED; - ar_preview->v2d.cur = ar_preview->v2d.tot; - view_changed = true; - } - if (ar_main && ar_main->alignment != RGN_ALIGN_NONE) { - ar_main->alignment = RGN_ALIGN_NONE; - view_changed = true; - } - if (ar_preview && ar_preview->alignment != RGN_ALIGN_TOP) { - ar_preview->alignment = RGN_ALIGN_TOP; - view_changed = true; + if (ar_main && ar_preview) { + /* Get available height (without DPI correction). */ + const float height = (sa->winy - ED_area_headersize()) / UI_DPI_FAC; + + /* We reuse hidden area's size, allows to find same layout as before if we just switch + * between one 'full window' view and the combined one. This gets lost if we switch to both + * 'full window' views before, though... Better than nothing. */ + if (ar_main->flag & RGN_FLAG_HIDDEN) { + ar_main->flag &= ~RGN_FLAG_HIDDEN; + ar_main->v2d.flag &= ~V2D_IS_INITIALISED; + ar_preview->sizey = (int)(height - ar_main->sizey); + view_changed = true; + } + if (ar_preview->flag & RGN_FLAG_HIDDEN) { + ar_preview->flag &= ~RGN_FLAG_HIDDEN; + ar_preview->v2d.flag &= ~V2D_IS_INITIALISED; + ar_preview->v2d.cur = ar_preview->v2d.tot; + ar_main->sizey = (int)(height - ar_preview->sizey); + view_changed = true; + } + if (ar_main->alignment != RGN_ALIGN_NONE) { + ar_main->alignment = RGN_ALIGN_NONE; + view_changed = true; + } + if (ar_preview->alignment != RGN_ALIGN_TOP) { + ar_preview->alignment = RGN_ALIGN_TOP; + view_changed = true; + } + /* Final check that both preview and main height are reasonable! */ + if (ar_preview->sizey < 10 || ar_main->sizey < 10 || ar_preview->sizey + ar_main->sizey > height) { + ar_preview->sizey = (int)(height * 0.4f + 0.5f); + ar_main->sizey = (int)(height - ar_preview->sizey); + view_changed = true; + } } break; } @@ -339,40 +355,6 @@ static void sequencer_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn } } -/* *********************** sequencer (main) region ************************ */ -/* add handlers, stuff you only do once or on area/region changes */ -static void sequencer_main_area_init(wmWindowManager *wm, ARegion *ar) -{ - wmKeyMap *keymap; - ListBase *lb; - - UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); - -// keymap = WM_keymap_find(wm->defaultconf, "Mask Editing", 0, 0); -// WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - - keymap = WM_keymap_find(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0); - WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - - /* own keymap */ - keymap = WM_keymap_find(wm->defaultconf, "Sequencer", SPACE_SEQ, 0); - WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - - /* add drop boxes */ - lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW); - - WM_event_add_dropbox_handler(&ar->handlers, lb); - -} - -static void sequencer_main_area_draw(const bContext *C, ARegion *ar) -{ -// ScrArea *sa = CTX_wm_area(C); - - /* NLE - strip editing timeline interface */ - draw_timeline_seq(C, ar); -} - /* ************* dropboxes ************* */ static int image_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) @@ -396,7 +378,7 @@ static int movie_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) int hand; if (drag->type == WM_DRAG_PATH) - if (ELEM3(drag->icon, 0, ICON_FILE_MOVIE, ICON_FILE_BLANK)) /* rule might not work? */ + if (ELEM(drag->icon, 0, ICON_FILE_MOVIE, ICON_FILE_BLANK)) /* rule might not work? */ if (find_nearest_seq(scene, &ar->v2d, &hand, event->mval) == NULL) return 1; return 0; @@ -439,7 +421,7 @@ static void sequencer_drop_copy(wmDrag *drag, wmDropBox *drop) static void sequencer_dropboxes(void) { ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW); - + WM_dropbox_add(lb, "SEQUENCER_OT_image_strip_add", image_drop_poll, sequencer_drop_copy); WM_dropbox_add(lb, "SEQUENCER_OT_movie_strip_add", movie_drop_poll, sequencer_drop_copy); WM_dropbox_add(lb, "SEQUENCER_OT_sound_strip_add", sound_drop_poll, sequencer_drop_copy); @@ -469,16 +451,37 @@ static int sequencer_context(const bContext *C, const char *member, bContextData return false; } - +/* *********************** sequencer (main) region ************************ */ /* add handlers, stuff you only do once or on area/region changes */ -static void sequencer_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar) +static void sequencer_main_area_init(wmWindowManager *wm, ARegion *ar) { - ED_region_header_init(ar); + wmKeyMap *keymap; + ListBase *lb; + + UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); + +#if 0 + keymap = WM_keymap_find(wm->defaultconf, "Mask Editing", 0, 0); + WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); +#endif + + keymap = WM_keymap_find(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0); + WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); + + /* own keymap */ + keymap = WM_keymap_find(wm->defaultconf, "Sequencer", SPACE_SEQ, 0); + WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); + + /* add drop boxes */ + lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW); + + WM_event_add_dropbox_handler(&ar->handlers, lb); } -static void sequencer_header_area_draw(const bContext *C, ARegion *ar) +static void sequencer_main_area_draw(const bContext *C, ARegion *ar) { - ED_region_header(C, ar); + /* NLE - strip editing timeline interface */ + draw_timeline_seq(C, ar); } static void sequencer_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) @@ -512,15 +515,29 @@ static void sequencer_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa } } +/* *********************** header region ************************ */ +/* add handlers, stuff you only do once or on area/region changes */ +static void sequencer_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar) +{ + ED_region_header_init(ar); +} + +static void sequencer_header_area_draw(const bContext *C, ARegion *ar) +{ + ED_region_header(C, ar); +} + /* *********************** preview region ************************ */ static void sequencer_preview_area_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); - -// keymap = WM_keymap_find(wm->defaultconf, "Mask Editing", 0, 0); -// WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); + +#if 0 + keymap = WM_keymap_find(wm->defaultconf, "Mask Editing", 0, 0); + WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); +#endif keymap = WM_keymap_find(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); @@ -593,7 +610,6 @@ static void sequencer_preview_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED break; } break; - case NC_MASK: if (wmn->action == NA_EDITED) { ED_region_tag_redraw(ar); @@ -654,10 +670,10 @@ void ED_spacetype_sequencer(void) { SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype sequencer"); ARegionType *art; - + st->spaceid = SPACE_SEQ; strncpy(st->name, "Sequencer", BKE_ST_MAXNAME); - + st->new = sequencer_new; st->free = sequencer_free; st->init = sequencer_init; @@ -682,13 +698,12 @@ void ED_spacetype_sequencer(void) /* preview */ art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region"); art->regionid = RGN_TYPE_PREVIEW; - art->prefsizey = 240; // XXX art->init = sequencer_preview_area_init; art->draw = sequencer_preview_area_draw; art->listener = sequencer_preview_area_listener; art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_GPENCIL; BLI_addhead(&st->regiontypes, art); - + /* regions: listview/buttons */ art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region"); art->regionid = RGN_TYPE_UI; @@ -698,7 +713,7 @@ void ED_spacetype_sequencer(void) art->init = sequencer_buttons_area_init; art->draw = sequencer_buttons_area_draw; BLI_addhead(&st->regiontypes, art); - + sequencer_buttons_register(art); /* regions: header */ @@ -706,13 +721,13 @@ void ED_spacetype_sequencer(void) art->regionid = RGN_TYPE_HEADER; art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; - + art->init = sequencer_header_area_init; art->draw = sequencer_header_area_draw; art->listener = sequencer_main_area_listener; - + BLI_addhead(&st->regiontypes, art); - + BKE_spacetype_register(st); /* set the sequencer callback when not in background mode */ diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index 6a98fd802f9..6ca6b2af1fd 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -1460,7 +1460,7 @@ void text_scroll_to_cursor(SpaceText *st, ScrArea *sa) ARegion *ar = NULL; int i, x, winx = 0; - if (ELEM3(NULL, st, st->text, st->text->curl)) return; + if (ELEM(NULL, st, st->text, st->text->curl)) return; text = st->text; diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c index 245cdadc7a2..e01a9d4b470 100644 --- a/source/blender/editors/space_view3d/drawarmature.c +++ b/source/blender/editors/space_view3d/drawarmature.c @@ -67,6 +67,7 @@ #include "view3d_intern.h" +#include "GPU_select.h" /* *************** Armature Drawing - Coloring API ***************************** */ @@ -93,7 +94,7 @@ static void set_pchan_colorset(Object *ob, bPoseChannel *pchan) short color_index = 0; /* sanity check */ - if (ELEM4(NULL, ob, arm, pose, pchan)) { + if (ELEM(NULL, ob, arm, pose, pchan)) { bcolor = NULL; return; } @@ -551,7 +552,7 @@ static void draw_bone_points(const short dt, int armflag, unsigned int boneflag, /* Draw root point if we are not connected */ if ((boneflag & BONE_CONNECTED) == 0) { if (id != -1) - glLoadName(id | BONESEL_ROOT); + GPU_select_load_id(id | BONESEL_ROOT); if (dt <= OB_WIRE) { if (armflag & ARM_EDITMODE) { @@ -574,7 +575,7 @@ static void draw_bone_points(const short dt, int armflag, unsigned int boneflag, /* Draw tip point */ if (id != -1) - glLoadName(id | BONESEL_TIP); + GPU_select_load_id(id | BONESEL_TIP); if (dt <= OB_WIRE) { if (armflag & ARM_EDITMODE) { @@ -787,7 +788,7 @@ static void draw_sphere_bone_wire(float smat[4][4], float imat[4][4], /* Draw root point if we are not connected */ if ((boneflag & BONE_CONNECTED) == 0) { if (id != -1) - glLoadName(id | BONESEL_ROOT); + GPU_select_load_id(id | BONESEL_ROOT); drawcircball(GL_LINE_LOOP, headvec, head, imat); } @@ -799,7 +800,7 @@ static void draw_sphere_bone_wire(float smat[4][4], float imat[4][4], } if (id != -1) - glLoadName(id | BONESEL_TIP); + GPU_select_load_id(id | BONESEL_TIP); drawcircball(GL_LINE_LOOP, tailvec, tail, imat); @@ -830,7 +831,7 @@ static void draw_sphere_bone_wire(float smat[4][4], float imat[4][4], cross_v3_v3v3(norvect, vec, imat[2]); if (id != -1) - glLoadName(id | BONESEL_BONE); + GPU_select_load_id(id | BONESEL_BONE); glBegin(GL_LINES); @@ -907,7 +908,7 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co /* Draw root point if we are not connected */ if ((boneflag & BONE_CONNECTED) == 0) { if (id != -1) - glLoadName(id | BONESEL_ROOT); + GPU_select_load_id(id | BONESEL_ROOT); gluSphere(qobj, head, 16, 10); } @@ -918,7 +919,7 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co } if (id != -1) - glLoadName(id | BONESEL_TIP); + GPU_select_load_id(id | BONESEL_TIP); glTranslatef(0.0f, 0.0f, length); gluSphere(qobj, tail, 16, 10); @@ -939,7 +940,7 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co if (length > (head + tail)) { if (id != -1) - glLoadName(id | BONESEL_BONE); + GPU_select_load_id(id | BONESEL_BONE); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(-1.0f, -1.0f); @@ -1009,7 +1010,7 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned /* Draw root point if we are not connected */ if ((boneflag & BONE_CONNECTED) == 0) { if (G.f & G_PICKSEL) { /* no bitmap in selection mode, crashes 3d cards... */ - glLoadName(id | BONESEL_ROOT); + GPU_select_load_id(id | BONESEL_ROOT); glBegin(GL_POINTS); glVertex3f(0.0f, 0.0f, 0.0f); glEnd(); @@ -1021,7 +1022,7 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned } if (id != -1) - glLoadName((GLuint) id | BONESEL_BONE); + GPU_select_load_id((GLuint) id | BONESEL_BONE); glBegin(GL_LINES); glVertex3f(0.0f, 0.0f, 0.0f); @@ -1031,7 +1032,7 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned /* tip */ if (G.f & G_PICKSEL) { /* no bitmap in selection mode, crashes 3d cards... */ - glLoadName(id | BONESEL_TIP); + GPU_select_load_id(id | BONESEL_TIP); glBegin(GL_POINTS); glVertex3f(0.0f, 1.0f, 0.0f); glEnd(); @@ -1043,7 +1044,7 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned /* further we send no names */ if (id != -1) - glLoadName(id & 0xFFFF); /* object tag, for bordersel optim */ + GPU_select_load_id(id & 0xFFFF); /* object tag, for bordersel optim */ if (armflag & ARM_POSEMODE) set_pchan_glColor(PCHAN_COLOR_LINEBONE, boneflag, constflag); @@ -1161,7 +1162,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl } if (id != -1) { - glLoadName((GLuint) id | BONESEL_BONE); + GPU_select_load_id((GLuint) id | BONESEL_BONE); } /* set up solid drawing */ @@ -1266,13 +1267,13 @@ static void draw_wire_bone(const short dt, int armflag, int boneflag, short cons /* this chunk not in object mode */ if (armflag & (ARM_EDITMODE | ARM_POSEMODE)) { if (id != -1) - glLoadName((GLuint) id | BONESEL_BONE); + GPU_select_load_id((GLuint) id | BONESEL_BONE); draw_wire_bone_segments(pchan, bbones, length, segments); /* further we send no names */ if (id != -1) - glLoadName(id & 0xFFFF); /* object tag, for bordersel optim */ + GPU_select_load_id(id & 0xFFFF); /* object tag, for bordersel optim */ } /* colors for modes */ @@ -1315,7 +1316,7 @@ static void draw_bone(const short dt, int armflag, int boneflag, short constflag /* now draw the bone itself */ if (id != -1) { - glLoadName((GLuint) id | BONESEL_BONE); + GPU_select_load_id((GLuint) id | BONESEL_BONE); } /* wire? */ @@ -1370,7 +1371,7 @@ static void draw_custom_bone(Scene *scene, View3D *v3d, RegionView3D *rv3d, Obje } if (id != -1) { - glLoadName((GLuint) id | BONESEL_BONE); + GPU_select_load_id((GLuint) id | BONESEL_BONE); } draw_object_instance(scene, v3d, rv3d, ob, dt, armflag & ARM_POSEMODE); @@ -1812,12 +1813,12 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, index += 0x10000; /* pose bones count in higher 2 bytes only */ } - /* very very confusing... but in object mode, solid draw, we cannot do glLoadName yet, + /* very very confusing... but in object mode, solid draw, we cannot do GPU_select_load_id yet, * stick bones and/or wire custom-shapes are drawn in next loop */ - if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) == 0 && (draw_wire == false)) { + if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) == 0 && (draw_wire == false) && index != -1) { /* object tag, for bordersel optim */ - glLoadName(index & 0xFFFF); + GPU_select_load_id(index & 0xFFFF); index = -1; } } @@ -1881,9 +1882,9 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, index += 0x10000; /* pose bones count in higher 2 bytes only */ } /* stick or wire bones have not been drawn yet so don't clear object selection in this case */ - if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) == 0 && draw_wire) { + if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) == 0 && draw_wire && index != -1) { /* object tag, for bordersel optim */ - glLoadName(index & 0xFFFF); + GPU_select_load_id(index & 0xFFFF); index = -1; } } @@ -1926,7 +1927,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, */ if ((do_dashed & 2) && ((bone->flag & BONE_CONNECTED) == 0)) { if (arm->flag & ARM_POSEMODE) { - glLoadName(index & 0xFFFF); /* object tag, for bordersel optim */ + GPU_select_load_id(index & 0xFFFF); /* object tag, for bordersel optim */ UI_ThemeColor(TH_WIRE); } setlinestyle(3); @@ -1946,7 +1947,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, if (constflag & PCHAN_HAS_TARGET) glColor3ub(200, 120, 0); else glColor3ub(200, 200, 50); /* add theme! */ - glLoadName(index & 0xFFFF); + GPU_select_load_id(index & 0xFFFF); pchan_draw_IK_root_lines(pchan, !(do_dashed & 2)); } } @@ -1954,7 +1955,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, if (bone->flag & BONE_SELECTED) { glColor3ub(150, 200, 50); /* add theme! */ - glLoadName(index & 0xFFFF); + GPU_select_load_id(index & 0xFFFF); pchan_draw_IK_root_lines(pchan, !(do_dashed & 2)); } } @@ -2020,7 +2021,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, /* draw DoFs */ if (arm->flag & ARM_POSEMODE) { - if (((base->flag & OB_FROMDUPLI) == 0)) { + if (((base->flag & OB_FROMDUPLI) == 0) && ((v3d->flag & V3D_HIDE_HELPLINES) == 0)) { draw_pose_dofs(ob); } } @@ -2174,7 +2175,7 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt) /* if wire over solid, set offset */ index = -1; - glLoadName(-1); + GPU_select_load_id(-1); if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) { if (G.f & G_PICKSEL) index = 0; @@ -2223,7 +2224,7 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt) /* offset to parent */ if (eBone->parent) { UI_ThemeColor(TH_WIRE_EDIT); - glLoadName(-1); /* -1 here is OK! */ + GPU_select_load_id(-1); /* -1 here is OK! */ setlinestyle(3); glBegin(GL_LINES); @@ -2240,7 +2241,7 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt) /* restore */ if (index != -1) { - glLoadName(-1); + GPU_select_load_id(-1); } if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) { diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c index bf0b7850839..89babf977e1 100644 --- a/source/blender/editors/space_view3d/drawmesh.c +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -212,12 +212,16 @@ static Material *give_current_material_or_def(Object *ob, int matnr) static struct TextureDrawState { Object *ob; + Image *stencil; + bool stencil_invert; bool use_game_mat; int is_lit, is_tex; int color_profile; bool use_backface_culling; unsigned char obcol[4]; -} Gtexdraw = {NULL, false, 0, 0, 0, false, {0, 0, 0, 0}}; + float stencil_col[4]; + bool is_texpaint; +} Gtexdraw = {NULL, NULL, false, false, 0, 0, 0, false, {0, 0, 0, 0}, {0.0f, 0.0f, 0.0f, 1.0f}, false}; static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material *ma, struct TextureDrawState gtexdraw) { @@ -229,13 +233,15 @@ static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material * static int c_lit; static int c_has_texface; - Object *litob = NULL; /* to get mode to turn off mipmap in painting mode */ int backculled = 1; int alphablend = GPU_BLEND_SOLID; int textured = 0; int lit = 0; int has_texface = texface != NULL; bool need_set_tpage = false; + bool texpaint = ((gtexdraw.ob->mode & OB_MODE_TEXTURE_PAINT) != 0); + + Image *ima = NULL; if (ma != NULL) { if (ma->mode & MA_TRANSP) { @@ -248,10 +254,10 @@ static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material * memset(&c_texface, 0, sizeof(MTFace)); c_badtex = false; c_has_texface = -1; + c_ma = NULL; } else { textured = gtexdraw.is_tex; - litob = gtexdraw.ob; } /* convert number of lights into boolean */ @@ -266,14 +272,16 @@ static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material * } } - if (texface) { + if (texface && !texpaint) { textured = textured && (texface->tpage); /* no material, render alpha if texture has depth=32 */ if (!ma && BKE_image_has_alpha(texface->tpage)) alphablend = GPU_BLEND_ALPHA; } - + else if (texpaint && ma) { + ima = ma->texpaintslot ? ma->texpaintslot[ma->paint_active_slot].ima : NULL; + } else textured = 0; @@ -287,11 +295,25 @@ static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material * /* need to re-set tpage if textured flag changed or existsment of texface changed.. */ need_set_tpage = textured != c_textured || has_texface != c_has_texface; /* ..or if settings inside texface were changed (if texface was used) */ - need_set_tpage |= texface && memcmp(&c_texface, texface, sizeof(c_texface)); + need_set_tpage |= (texpaint && c_ma != ma) || (texface && memcmp(&c_texface, texface, sizeof(c_texface))); if (need_set_tpage) { if (textured) { - c_badtex = !GPU_set_tpage(texface, !(litob->mode & OB_MODE_TEXTURE_PAINT), alphablend); + if (texpaint) { + c_badtex = false; + if (GPU_verify_image(ima, NULL, 0, 1, 0, false)) { + glEnable(GL_TEXTURE_2D); + } + else { + c_badtex = true; + GPU_clear_tpage(true); + glDisable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + } + } + else { + c_badtex = !GPU_set_tpage(texface, !texpaint, alphablend); + } } else { GPU_set_tpage(NULL, 0, 0); @@ -325,6 +347,7 @@ static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material * glDisable(GL_COLOR_MATERIAL); } c_lit = lit; + c_ma = ma; } return c_badtex; @@ -335,6 +358,7 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O unsigned char obcol[4]; bool is_tex, solidtex; Mesh *me = ob->data; + ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; /* XXX scene->obedit warning */ @@ -364,8 +388,34 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O else is_tex = false; Gtexdraw.ob = ob; + Gtexdraw.stencil = (imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL) ? imapaint->stencil : NULL; + Gtexdraw.stencil_invert = ((imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) != 0); + Gtexdraw.is_texpaint = (ob->mode == OB_MODE_TEXTURE_PAINT); + copy_v3_v3(Gtexdraw.stencil_col, imapaint->stencil_col); Gtexdraw.is_tex = is_tex; + /* load the stencil texture here */ + if (Gtexdraw.is_texpaint && (Gtexdraw.stencil != NULL)) { + glActiveTexture(GL_TEXTURE1); + if (GPU_verify_image(Gtexdraw.stencil, NULL, false, false, false, false)) { + glEnable(GL_TEXTURE_2D); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); + glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, Gtexdraw.stencil_col); + if (!Gtexdraw.stencil_invert) { + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_ONE_MINUS_SRC_COLOR); + } + else { + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR); + } + } + glActiveTexture(GL_TEXTURE0); + } + Gtexdraw.color_profile = BKE_scene_check_color_management_enabled(scene); Gtexdraw.use_game_mat = (RE_engines_find(scene->r.engine)->flag & RE_GAME) != 0; Gtexdraw.use_backface_culling = (v3d->flag2 & V3D_BACKFACE_CULLING) != 0; @@ -379,8 +429,24 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O static void draw_textured_end(void) { - /* switch off textures */ - GPU_set_tpage(NULL, 0, 0); + if (Gtexdraw.ob->mode & OB_MODE_TEXTURE_PAINT) { + if (Gtexdraw.stencil != NULL) { + glActiveTexture(GL_TEXTURE1); + glDisable(GL_TEXTURE_2D); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0); + } + /* manual reset, since we don't use tpage */ + glBindTexture(GL_TEXTURE_2D, 0); + /* force switch off textures */ + GPU_clear_tpage(true); + } + else { + /* switch off textures */ + GPU_set_tpage(NULL, 0, 0); + } glShadeModel(GL_FLAT); glDisable(GL_CULL_FACE); @@ -456,7 +522,7 @@ static DMDrawOption draw_tface__set_draw(MTFace *tface, const bool UNUSED(has_mc if (ma && (ma->game.flag & GEMAT_INVISIBLE)) return 0; - if (tface) + if (tface || Gtexdraw.is_texpaint) set_draw_settings_cached(0, tface, ma, Gtexdraw); /* always use color from mcol, as set in update_tface_color_layer */ @@ -770,7 +836,8 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d Object *ob, DerivedMesh *dm, const int draw_flags) { Mesh *me = ob->data; - + DMDrawFlag uvflag = DM_DRAW_USE_ACTIVE_UV; + /* correct for negative scale */ if (ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW); else glFrontFace(GL_CCW); @@ -780,6 +847,10 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + if (ob->mode & OB_MODE_TEXTURE_PAINT) { + uvflag = DM_DRAW_USE_TEXPAINT_UV; + } + if (ob->mode & OB_MODE_EDIT) { drawEMTFMapped_userData data; @@ -789,7 +860,7 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d data.mf = DM_get_tessface_data_layer(dm, CD_MFACE); data.tf = DM_get_tessface_data_layer(dm, CD_MTFACE); - dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, compareDrawOptionsEm, &data); + dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, compareDrawOptionsEm, &data, 0); } else if (draw_flags & DRAW_FACE_SELECT) { if (ob->mode & OB_MODE_WEIGHT_PAINT) @@ -801,15 +872,15 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d userData.mf = DM_get_tessface_data_layer(dm, CD_MFACE); userData.tf = DM_get_tessface_data_layer(dm, CD_MTFACE); userData.me = me; - dm->drawMappedFacesTex(dm, me->mpoly ? draw_tface_mapped__set_draw : NULL, compareDrawOptions, &userData); + dm->drawMappedFacesTex(dm, me->mpoly ? draw_tface_mapped__set_draw : NULL, compareDrawOptions, &userData, uvflag); } } else { if (GPU_buffer_legacy(dm)) { if (draw_flags & DRAW_MODIFIERS_PREVIEW) - dm->drawFacesTex(dm, draw_mcol__set_draw_legacy, NULL, NULL); + dm->drawFacesTex(dm, draw_mcol__set_draw_legacy, NULL, NULL, uvflag); else - dm->drawFacesTex(dm, draw_tface__set_draw_legacy, NULL, NULL); + dm->drawFacesTex(dm, draw_tface__set_draw_legacy, NULL, NULL, uvflag); } else { drawTFace_userData userData; @@ -820,7 +891,7 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d userData.tf = DM_get_tessface_data_layer(dm, CD_MTFACE); userData.me = NULL; - dm->drawFacesTex(dm, draw_tface__set_draw, compareDrawOptions, &userData); + dm->drawFacesTex(dm, draw_tface__set_draw, compareDrawOptions, &userData, uvflag); } } @@ -870,7 +941,7 @@ static void tex_mat_set_texture_cb(void *userData, int mat_nr, void *attribs) int texture_set = 0; /* draw image texture if we find one */ - if (ED_object_get_active_image(data->ob, mat_nr, &ima, &iuser, &node)) { + if (ED_object_get_active_image(data->ob, mat_nr, &ima, &iuser, &node, NULL)) { /* get openl texture */ int mipmap = 1; int bindcode = (ima) ? GPU_verify_image(ima, iuser, 0, 0, mipmap, false) : 0; @@ -955,7 +1026,8 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, /* if not cycles, or preview-modifiers, or drawing matcaps */ if ((draw_flags & DRAW_MODIFIERS_PREVIEW) || (v3d->flag2 & V3D_SHOW_SOLID_MATCAP) || - (BKE_scene_use_new_shading_nodes(scene) == false)) + (BKE_scene_use_new_shading_nodes(scene) == false) || + ((ob->mode & OB_MODE_TEXTURE_PAINT) && ELEM(v3d->drawtype, OB_TEXTURE, OB_SOLID))) { draw_mesh_textured_old(scene, v3d, rv3d, ob, dm, draw_flags); return; diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index c1689ef06db..13e010d2f97 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -86,6 +86,7 @@ #include "GPU_draw.h" #include "GPU_extensions.h" +#include "GPU_select.h" #include "ED_mesh.h" #include "ED_particle.h" @@ -301,7 +302,7 @@ bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt) if (BKE_scene_use_new_shading_nodes(scene)) return false; - return (scene->gm.matmode == GAME_MAT_GLSL) && (dt > OB_SOLID); + return ((scene->gm.matmode == GAME_MAT_GLSL) || (v3d->drawtype == OB_MATERIAL)) && (dt > OB_SOLID); } static bool check_alpha_pass(Base *base) @@ -1586,7 +1587,7 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D continue; if (dflag & DRAW_PICKING) - glLoadName(base->selcol + (tracknr << 16)); + GPU_select_load_id(base->selcol + (tracknr << 16)); glPushMatrix(); glTranslatef(track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]); @@ -1737,7 +1738,7 @@ static void draw_viewport_reconstruction(Scene *scene, Base *base, View3D *v3d, } if (dflag & DRAW_PICKING) - glLoadName(base->selcol); + GPU_select_load_id(base->selcol); } /* flag similar to draw_object() */ @@ -4868,7 +4869,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv normalize_v3(imat[1]); } - if (ELEM3(draw_as, PART_DRAW_DOT, PART_DRAW_CROSS, PART_DRAW_LINE) && + if (ELEM(draw_as, PART_DRAW_DOT, PART_DRAW_CROSS, PART_DRAW_LINE) && (part->draw_col > PART_DRAW_COL_MAT)) { create_cdata = 1; @@ -6479,7 +6480,7 @@ static bool drawmball(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, if (G.f & G_PICKSEL) { ml->selcol1 = code; - glLoadName(code++); + GPU_select_load_id(code++); } } drawcircball(GL_LINE_LOOP, &(ml->x), ml->rad, imat); @@ -6493,7 +6494,7 @@ static bool drawmball(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, if (G.f & G_PICKSEL) { ml->selcol2 = code; - glLoadName(code++); + GPU_select_load_id(code++); } drawcircball(GL_LINE_LOOP, &(ml->x), ml->rad * atanf(ml->s) / (float)M_PI_2, imat); } @@ -6782,7 +6783,7 @@ static void draw_bounding_volume(Object *ob, char type) if (ob->type == OB_MESH) { bb = BKE_mesh_boundbox_get(ob); } - else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { + else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { bb = BKE_curve_boundbox_get(ob); } else if (ob->type == OB_MBALL) { @@ -6839,7 +6840,7 @@ static void drawtexspace(Object *ob) if (ob->type == OB_MESH) { BKE_mesh_texspace_get(ob->data, loc, NULL, size); } - else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { + else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { BKE_curve_texspace_get(ob->data, loc, NULL, size); } else if (ob->type == OB_MBALL) { @@ -6877,7 +6878,7 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base, glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); glDepthMask(0); - if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { + if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { DerivedMesh *dm = ob->derivedFinal; bool has_faces = false; @@ -6921,7 +6922,7 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base, static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, const unsigned char ob_wire_col[4]) { - if (ELEM4(ob->type, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL)) { + if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL)) { if (scene->obedit == ob) { UI_ThemeColor(TH_WIRE_EDIT); @@ -6933,7 +6934,7 @@ static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, const ED_view3d_polygon_offset(rv3d, 1.0); glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */ - if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { + if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { if (ED_view3d_boundbox_clip(rv3d, ob->bb)) { if (ob->derivedFinal) { @@ -7182,7 +7183,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short if (ob->restrictflag & OB_RESTRICT_RENDER) return; - if (!has_particles && (ob->transflag & OB_DUPLI)) + if (!has_particles && (ob->transflag & (OB_DUPLI & ~OB_DUPLIFRAMES))) return; } } diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 77a5ac1f689..8b76ec3a56d 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -43,6 +43,7 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_depsgraph.h" #include "BKE_icons.h" #include "BKE_library.h" #include "BKE_main.h" @@ -286,7 +287,7 @@ static void view3d_stop_render_preview(wmWindowManager *wm, ARegion *ar) } } -void ED_view3d_shade_update(Main *bmain, View3D *v3d, ScrArea *sa) +void ED_view3d_shade_update(Main *bmain, Scene *scene, View3D *v3d, ScrArea *sa) { wmWindowManager *wm = bmain->wm.first; @@ -298,6 +299,10 @@ void ED_view3d_shade_update(Main *bmain, View3D *v3d, ScrArea *sa) view3d_stop_render_preview(wm, ar); } } + else if (scene->obedit != NULL && scene->obedit->type == OB_MESH) { + /* Tag mesh to load edit data. */ + DAG_id_tag_update(scene->obedit->data, 0); + } } /* ******************** default callbacks for view3d space ***************** */ @@ -483,6 +488,12 @@ static void view3d_main_area_init(wmWindowManager *wm, ARegion *ar) keymap = WM_keymap_find(wm->defaultconf, "Object Mode", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); + keymap = WM_keymap_find(wm->defaultconf, "Paint Curve", 0, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); + + keymap = WM_keymap_find(wm->defaultconf, "Curve", 0, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); + keymap = WM_keymap_find(wm->defaultconf, "Image Paint", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); @@ -673,7 +684,7 @@ static void view3d_dropboxes(void) WM_dropbox_add(lb, "MESH_OT_drop_named_image", view3d_ima_mesh_drop_poll, view3d_id_path_drop_copy); WM_dropbox_add(lb, "OBJECT_OT_drop_named_image", view3d_ima_empty_drop_poll, view3d_id_path_drop_copy); WM_dropbox_add(lb, "VIEW3D_OT_background_image_add", view3d_ima_bg_drop_poll, view3d_id_path_drop_copy); - WM_dropbox_add(lb, "OBJECT_OT_group_instance_add", view3d_group_drop_poll, view3d_group_drop_copy); + WM_dropbox_add(lb, "OBJECT_OT_group_instance_add", view3d_group_drop_poll, view3d_group_drop_copy); } @@ -779,7 +790,7 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN break; case ND_NLA: case ND_KEYFRAME: - if (ELEM3(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED)) + if (ELEM(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED)) ED_region_tag_redraw(ar); break; case ND_ANIMCHAN: @@ -860,14 +871,18 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN switch (wmn->data) { case ND_SHADING: case ND_NODES: + { + Object *ob = OBACT; if ((v3d->drawtype == OB_MATERIAL) || + (ob && (ob->mode == OB_MODE_TEXTURE_PAINT)) || (v3d->drawtype == OB_TEXTURE && - (scene->gm.matmode == GAME_MAT_GLSL || - BKE_scene_use_new_shading_nodes(scene)))) + (scene->gm.matmode == GAME_MAT_GLSL || + BKE_scene_use_new_shading_nodes(scene)))) { ED_region_tag_redraw(ar); } break; + } case ND_SHADING_DRAW: case ND_SHADING_LINKS: ED_region_tag_redraw(ar); @@ -905,7 +920,7 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN ED_region_tag_redraw(ar); break; case NC_MOVIECLIP: - if (wmn->data == ND_DISPLAY) + if (wmn->data == ND_DISPLAY || wmn->action == NA_EDITED) ED_region_tag_redraw(ar); break; case NC_SPACE: @@ -1030,7 +1045,7 @@ static void view3d_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa break; case ND_NLA: case ND_KEYFRAME: - if (ELEM3(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED)) + if (ELEM(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED)) ED_region_tag_redraw(ar); break; } @@ -1099,6 +1114,11 @@ static void view3d_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa if (wmn->data == ND_DATA || wmn->action == NA_EDITED) ED_region_tag_redraw(ar); break; + case NC_IMAGE: + /* Update for the image layers in texture paint. */ + if (wmn->action == NA_EDITED) + ED_region_tag_redraw(ar); + break; } } diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index dd08339cc94..004b3e1b7d3 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -881,7 +881,7 @@ static void draw_selected_name(Scene *scene, Object *ob, rcti *rect) } } } - else if (ELEM3(ob->type, OB_MESH, OB_LATTICE, OB_CURVE)) { + else if (ELEM(ob->type, OB_MESH, OB_LATTICE, OB_CURVE)) { Key *key = NULL; KeyBlock *kb = NULL; @@ -1287,6 +1287,12 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d) { /* do nothing */ } + /* texture paint mode sampling */ + else if (base && (base->object->mode & OB_MODE_TEXTURE_PAINT) && + (v3d->drawtype > OB_WIRE)) + { + /* do nothing */ + } else if ((base && (base->object->mode & OB_MODE_PARTICLE_EDIT)) && v3d->drawtype > OB_WIRE && (v3d->flag & V3D_ZBUF_SELECT)) { @@ -2509,7 +2515,7 @@ CustomDataMask ED_view3d_datamask(Scene *scene, View3D *v3d) mask |= CD_MASK_ORCO; } else { - if (scene->gm.matmode == GAME_MAT_GLSL) + if (scene->gm.matmode == GAME_MAT_GLSL || v3d->drawtype == OB_MATERIAL) mask |= CD_MASK_ORCO; } } diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index e3260dba485..4ca9eea578c 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -307,12 +307,12 @@ static void view3d_boxview_clip(ScrArea *sa) } for (val = 0; val < 8; val++) { - if (ELEM4(val, 0, 3, 4, 7)) + if (ELEM(val, 0, 3, 4, 7)) bb->vec[val][0] = -x1 - ofs[0]; else bb->vec[val][0] = x1 - ofs[0]; - if (ELEM4(val, 0, 1, 4, 5)) + if (ELEM(val, 0, 1, 4, 5)) bb->vec[val][1] = -y1 - ofs[1]; else bb->vec[val][1] = y1 - ofs[1]; @@ -465,11 +465,13 @@ void ED_view3d_quadview_update(ScrArea *sa, ARegion *ar, bool do_clip) * properties are always being edited, weak */ viewlock = rv3d->viewlock; - if ((viewlock & RV3D_LOCKED) == 0) + if ((viewlock & RV3D_LOCKED) == 0) { + do_clip = (viewlock & RV3D_BOXCLIP) != 0; viewlock = 0; - else if ((viewlock & RV3D_BOXVIEW) == 0) { - viewlock &= ~RV3D_BOXCLIP; + } + else if ((viewlock & RV3D_BOXVIEW) == 0 && (viewlock & RV3D_BOXCLIP) != 0) { do_clip = true; + viewlock &= ~RV3D_BOXCLIP; } for (; ar; ar = ar->prev) { @@ -3243,6 +3245,8 @@ static int render_border_exec(bContext *C, wmOperator *op) void VIEW3D_OT_render_border(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Set Render Border"; ot->description = "Set the boundaries of the border render and enable border render"; @@ -3262,7 +3266,8 @@ void VIEW3D_OT_render_border(wmOperatorType *ot) /* rna */ WM_operator_properties_border(ot); - RNA_def_boolean(ot->srna, "camera_only", 0, "Camera Only", "Set render border for camera view and final render only"); + prop = RNA_def_boolean(ot->srna, "camera_only", 0, "Camera Only", "Set render border for camera view and final render only"); + RNA_def_property_flag(prop, PROP_HIDDEN); } /* ********************* Clear render border operator ****************** */ @@ -4435,7 +4440,7 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2]) } } -static void view3d_cursor3d_update(bContext *C, const int *mval) +void ED_view3d_cursor3d_update(bContext *C, const int mval[2]) { Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); @@ -4451,7 +4456,7 @@ static void view3d_cursor3d_update(bContext *C, const int *mval) static int view3d_cursor3d_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - view3d_cursor3d_update(C, event->mval); + ED_view3d_cursor3d_update(C, event->mval); op->customdata = SET_INT_IN_POINTER(event->type); WM_event_add_modal_handler(C, op); @@ -4468,7 +4473,7 @@ static int view3d_cursor3d_modal(bContext *C, wmOperator *op, const wmEvent *eve switch (event->type) { case MOUSEMOVE: - view3d_cursor3d_update(C, event->mval); + ED_view3d_cursor3d_update(C, event->mval); break; case LEFTMOUSE: return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index e3d0e87066b..a88724a1cdd 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -32,6 +32,7 @@ #include <stdio.h> #include <stdlib.h> +#include "DNA_brush_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" @@ -45,6 +46,7 @@ #include "BKE_depsgraph.h" #include "BKE_main.h" #include "BKE_modifier.h" +#include "BKE_paint.h" #include "BKE_screen.h" #include "BKE_editmesh.h" @@ -308,7 +310,7 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) /* mode */ if (ob) { modeselect = ob->mode; - is_paint = ELEM4(ob->mode, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT); + is_paint = ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT); } else { modeselect = OB_MODE_OBJECT; @@ -336,8 +338,7 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) uiItemR(layout, &v3dptr, "viewport_shade", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); if (obedit == NULL && is_paint) { - - if (ob->mode & OB_MODE_WEIGHT_PAINT) { + if (ob->mode & OB_MODE_ALL_PAINT) { /* Only for Weight Paint. makes no sense in other paint modes. */ row = uiLayoutRow(layout, true); uiItemR(row, &v3dptr, "pivot_point", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index f61f58c12db..46ea52054c5 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -1194,15 +1194,32 @@ static short selectbuffer_ret_hits_5(unsigned int *buffer, const short hits15, c /* we want a select buffer with bones, if there are... */ /* so check three selection levels and compare */ -static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, const int mval[2]) +static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, const int mval[2], bool *p_do_nearest, bool enumerate) { rcti rect; int offs; short hits15, hits9 = 0, hits5 = 0; bool has_bones15 = false, has_bones9 = false, has_bones5 = false; - + static int last_mval[2] = {-100, -100}; + bool do_nearest = false; + View3D *v3d = vc->v3d; + + /* define if we use solid nearest select or not */ + if (v3d->drawtype > OB_WIRE) { + do_nearest = true; + if (len_manhattan_v2v2_int(mval, last_mval) < 3) { + do_nearest = false; + } + } + copy_v2_v2_int(last_mval, mval); + + if (p_do_nearest) + *p_do_nearest = do_nearest; + + do_nearest = do_nearest && !enumerate; + BLI_rcti_init(&rect, mval[0] - 14, mval[0] + 14, mval[1] - 14, mval[1] + 14); - hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect); + hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, do_nearest); if (hits15 == 1) { return selectbuffer_ret_hits_15(buffer, hits15); } @@ -1211,7 +1228,7 @@ static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buff offs = 4 * hits15; BLI_rcti_init(&rect, mval[0] - 9, mval[0] + 9, mval[1] - 9, mval[1] + 9); - hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect); + hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, do_nearest); if (hits9 == 1) { return selectbuffer_ret_hits_9(buffer, hits15, hits9); } @@ -1220,7 +1237,7 @@ static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buff offs += 4 * hits9; BLI_rcti_init(&rect, mval[0] - 5, mval[0] + 5, mval[1] - 5, mval[1] + 5); - hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect); + hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, do_nearest); if (hits5 == 1) { return selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5); } @@ -1242,25 +1259,13 @@ static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buff } /* returns basact */ -static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int hits, const int mval[2], - Base *startbase, bool has_bones) +static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int hits, + Base *startbase, bool has_bones, bool do_nearest) { Scene *scene = vc->scene; View3D *v3d = vc->v3d; Base *base, *basact = NULL; - static int lastmval[2] = {-100, -100}; int a; - bool do_nearest = false; - - /* define if we use solid nearest select or not */ - if (v3d->drawtype > OB_WIRE) { - do_nearest = true; - if (ABS(mval[0] - lastmval[0]) < 3 && ABS(mval[1] - lastmval[1]) < 3) { - if (!has_bones) /* hrms, if theres bones we always do nearest */ - do_nearest = false; - } - } - lastmval[0] = mval[0]; lastmval[1] = mval[1]; if (do_nearest) { unsigned int min = 0xFFFFFFFF; @@ -1343,16 +1348,17 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2]) Base *basact = NULL; unsigned int buffer[4 * MAXPICKBUF]; int hits; + bool do_nearest; /* setup view context for argument to callbacks */ view3d_operator_needs_opengl(C); view3d_set_viewcontext(C, &vc); - hits = mixed_bones_object_selectbuffer(&vc, buffer, mval); + hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, &do_nearest, false); if (hits > 0) { const bool has_bones = selectbuffer_has_bones(buffer, hits); - basact = mouse_select_eval_buffer(&vc, buffer, hits, mval, vc.scene->base.first, has_bones); + basact = mouse_select_eval_buffer(&vc, buffer, hits, vc.scene->base.first, has_bones, do_nearest); } return basact; @@ -1439,10 +1445,11 @@ static bool mouse_select(bContext *C, const int mval[2], } else { unsigned int buffer[4 * MAXPICKBUF]; + bool do_nearest; /* if objects have posemode set, the bones are in the same selection buffer */ - hits = mixed_bones_object_selectbuffer(&vc, buffer, mval); + hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, &do_nearest, enumerate); if (hits > 0) { /* note: bundles are handling in the same way as bones */ @@ -1453,7 +1460,7 @@ static bool mouse_select(bContext *C, const int mval[2], basact = object_mouse_select_menu(C, &vc, buffer, hits, mval, toggle); } else { - basact = mouse_select_eval_buffer(&vc, buffer, hits, mval, startbase, has_bones); + basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, has_bones, do_nearest); } if (has_bones && basact) { @@ -1511,7 +1518,7 @@ static bool mouse_select(bContext *C, const int mval[2], if (!changed) { /* fallback to regular object selection if no new bundles were selected, * allows to select object parented to reconstruction object */ - basact = mouse_select_eval_buffer(&vc, buffer, hits, mval, startbase, 0); + basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, 0, do_nearest); } } } @@ -1873,7 +1880,7 @@ static int do_meta_box_select(ViewContext *vc, rcti *rect, bool select, bool ext unsigned int buffer[4 * MAXPICKBUF]; short hits; - hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect); + hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, false); if (extend == false && select) BKE_mball_deselect_all(mb); @@ -1907,7 +1914,7 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool unsigned int buffer[4 * MAXPICKBUF]; short hits; - hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect); + hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, false); /* clear flag we use to detect point was affected */ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) @@ -2001,7 +2008,7 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b /* selection buffer now has bones potentially too, so we add MAXPICKBUF */ vbuffer = MEM_mallocN(4 * (totobj + MAXPICKBUF) * sizeof(unsigned int), "selection buffer"); - hits = view3d_opengl_select(vc, vbuffer, 4 * (totobj + MAXPICKBUF), rect); + hits = view3d_opengl_select(vc, vbuffer, 4 * (totobj + MAXPICKBUF), rect, false); /* * LOGIC NOTES (theeth): * The buffer and ListBase have the same relative order, which makes the selection diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 716f4b10fae..6d28accbc7b 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -56,6 +56,7 @@ #include "BIF_glutil.h" #include "GPU_draw.h" +#include "GPU_select.h" #include "WM_api.h" #include "WM_types.h" @@ -955,6 +956,78 @@ void view3d_viewmatrix_set(Scene *scene, View3D *v3d, RegionView3D *rv3d) } } +static void view3d_select_loop(ViewContext *vc, Scene *scene, View3D *v3d, ARegion *ar, bool use_obedit_skip) +{ + short code = 1; + char dt; + short dtx; + + if (vc->obedit && vc->obedit->type == OB_MBALL) { + draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR); + } + else if ((vc->obedit && vc->obedit->type == OB_ARMATURE)) { + /* if not drawing sketch, draw bones */ + if (!BDR_drawSketchNames(vc)) { + draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR); + } + } + else { + Base *base; + + v3d->xray = true; /* otherwise it postpones drawing */ + for (base = scene->base.first; base; base = base->next) { + if (base->lay & v3d->lay) { + + if ((base->object->restrictflag & OB_RESTRICT_SELECT) || + (use_obedit_skip && (scene->obedit->data == base->object->data))) + { + base->selcol = 0; + } + else { + base->selcol = code; + + if (GPU_select_load_id(code)) { + draw_object(scene, ar, v3d, base, DRAW_PICKING | DRAW_CONSTCOLOR); + + /* we draw duplicators for selection too */ + if ((base->object->transflag & OB_DUPLI)) { + ListBase *lb; + DupliObject *dob; + Base tbase; + + tbase.flag = OB_FROMDUPLI; + lb = object_duplilist(G.main->eval_ctx, scene, base->object); + + for (dob = lb->first; dob; dob = dob->next) { + float omat[4][4]; + + tbase.object = dob->ob; + copy_m4_m4(omat, dob->ob->obmat); + copy_m4_m4(dob->ob->obmat, dob->mat); + + /* extra service: draw the duplicator in drawtype of parent */ + /* MIN2 for the drawtype to allow bounding box objects in groups for lods */ + dt = tbase.object->dt; tbase.object->dt = MIN2(tbase.object->dt, base->object->dt); + dtx = tbase.object->dtx; tbase.object->dtx = base->object->dtx; + + draw_object(scene, ar, v3d, &tbase, DRAW_PICKING | DRAW_CONSTCOLOR); + + tbase.object->dt = dt; + tbase.object->dtx = dtx; + + copy_m4_m4(dob->ob->obmat, omat); + } + free_object_duplilist(lb); + } + } + code++; + } + } + } + v3d->xray = false; /* restore */ + } +} + /** * \warning be sure to account for a negative return value * This is an error, "Too many objects in select buffer" @@ -962,17 +1035,16 @@ void view3d_viewmatrix_set(Scene *scene, View3D *v3d, RegionView3D *rv3d) * * \note (vc->obedit == NULL) can be set to explicitly skip edit-object selection. */ -short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input) +short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input, bool do_nearest) { Scene *scene = vc->scene; View3D *v3d = vc->v3d; ARegion *ar = vc->ar; - rctf rect; - short code, hits; - char dt; - short dtx; + rctf rect, selrect; + short hits; const bool use_obedit_skip = (scene->obedit != NULL) && (vc->obedit == NULL); - + const bool do_passes = do_nearest && GPU_select_query_check_active(); + G.f |= G_PICKSEL; /* case not a border select */ @@ -985,6 +1057,8 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b else { BLI_rctf_rcti_copy(&rect, input); } + + selrect = rect; view3d_winmatrix_set(ar, v3d, &rect); mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat); @@ -997,78 +1071,24 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b if (vc->rv3d->rflag & RV3D_CLIPPING) ED_view3d_clipping_set(vc->rv3d); - glSelectBuffer(bufsize, (GLuint *)buffer); - glRenderMode(GL_SELECT); - glInitNames(); /* these two calls whatfor? It doesnt work otherwise */ - glPushName(-1); - code = 1; + if (do_passes) + GPU_select_begin(buffer, bufsize, &selrect, GPU_SELECT_NEAREST_FIRST_PASS, 0); + else + GPU_select_begin(buffer, bufsize, &selrect, GPU_SELECT_ALL, 0); + + view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip); + + hits = GPU_select_end(); - if (vc->obedit && vc->obedit->type == OB_MBALL) { - draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR); - } - else if ((vc->obedit && vc->obedit->type == OB_ARMATURE)) { - /* if not drawing sketch, draw bones */ - if (!BDR_drawSketchNames(vc)) { - draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR); - } - } - else { - Base *base; - - v3d->xray = true; /* otherwise it postpones drawing */ - for (base = scene->base.first; base; base = base->next) { - if (base->lay & v3d->lay) { - - if ((base->object->restrictflag & OB_RESTRICT_SELECT) || - (use_obedit_skip && (scene->obedit->data == base->object->data))) - { - base->selcol = 0; - } - else { - base->selcol = code; - glLoadName(code); - draw_object(scene, ar, v3d, base, DRAW_PICKING | DRAW_CONSTCOLOR); - - /* we draw duplicators for selection too */ - if ((base->object->transflag & OB_DUPLI)) { - ListBase *lb; - DupliObject *dob; - Base tbase; - - tbase.flag = OB_FROMDUPLI; - lb = object_duplilist(G.main->eval_ctx, scene, base->object); - - for (dob = lb->first; dob; dob = dob->next) { - float omat[4][4]; - - tbase.object = dob->ob; - copy_m4_m4(omat, dob->ob->obmat); - copy_m4_m4(dob->ob->obmat, dob->mat); - - /* extra service: draw the duplicator in drawtype of parent */ - /* MIN2 for the drawtype to allow bounding box objects in groups for lods */ - dt = tbase.object->dt; tbase.object->dt = MIN2(tbase.object->dt, base->object->dt); - dtx = tbase.object->dtx; tbase.object->dtx = base->object->dtx; - - draw_object(scene, ar, v3d, &tbase, DRAW_PICKING | DRAW_CONSTCOLOR); - - tbase.object->dt = dt; - tbase.object->dtx = dtx; - - copy_m4_m4(dob->ob->obmat, omat); - } - free_object_duplilist(lb); - } - code++; - } - } - } - v3d->xray = false; /* restore */ + /* second pass, to get the closest object to camera */ + if (do_passes) { + GPU_select_begin(buffer, bufsize, &selrect, GPU_SELECT_NEAREST_SECOND_PASS, hits); + + view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip); + + GPU_select_end(); } - - glPopName(); /* see above (pushname) */ - hits = glRenderMode(GL_RENDER); - + G.f &= ~G_PICKSEL; view3d_winmatrix_set(ar, v3d, NULL); mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat); @@ -1285,7 +1305,7 @@ static bool view3d_localview_init( return ok; } -static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmain, ScrArea *sa, const int smooth_viewtx) +static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmain, Scene *scene, ScrArea *sa, const int smooth_viewtx) { const bool free = true; ARegion *ar; @@ -1335,7 +1355,7 @@ static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmai } } - ED_view3d_shade_update(bmain, v3d, sa); + ED_view3d_shade_update(bmain, scene, v3d, sa); } } } @@ -1352,7 +1372,7 @@ static bool view3d_localview_exit( locallay = v3d->lay & 0xFF000000; - restore_localviewdata(wm, win, bmain, sa, smooth_viewtx); + restore_localviewdata(wm, win, bmain, scene, sa, smooth_viewtx); /* for when in other window the layers have changed */ if (v3d->scenelock) v3d->lay = scene->lay; diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt index 7765dd511b4..3ad5d94efd6 100644 --- a/source/blender/editors/transform/CMakeLists.txt +++ b/source/blender/editors/transform/CMakeLists.txt @@ -24,6 +24,7 @@ set(INC ../../blenkernel ../../blenlib ../../bmesh + ../../gpu ../../ikplugin ../../makesdna ../../makesrna diff --git a/source/blender/editors/transform/SConscript b/source/blender/editors/transform/SConscript index f3c8c13647a..4f47062e3a3 100644 --- a/source/blender/editors/transform/SConscript +++ b/source/blender/editors/transform/SConscript @@ -40,6 +40,7 @@ incs = [ '../../ikplugin', '../../makesdna', '../../makesrna', + '../../gpu', '../../windowmanager', ] diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index a53b4a75b20..58dee620a61 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -86,6 +86,9 @@ #include "transform.h" +/* Disabling, since when you type you know what you are doing, and being able to set it to zero is handy. */ +// #define USE_NUM_NO_ZERO + #define MAX_INFO_LEN 256 static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg); @@ -190,9 +193,9 @@ static bool transdata_check_local_center(TransInfo *t, short around) { return ((around == V3D_LOCAL) && ( (t->flag & (T_OBJECT | T_POSE)) || - (t->obedit && ELEM4(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)) || + (t->obedit && ELEM(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)) || (t->spacetype == SPACE_IPO) || - (t->options & (CTX_MOVIECLIP | CTX_MASK))) + (t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE))) ); } @@ -263,17 +266,27 @@ static void convertViewVec2D_mask(View2D *v2d, float r_vec[3], int dx, int dy) void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy) { if ((t->spacetype == SPACE_VIEW3D) && (t->ar->regiontype == RGN_TYPE_WINDOW)) { - const float mval_f[2] = {(float)dx, (float)dy}; - ED_view3d_win_to_delta(t->ar, mval_f, r_vec, t->zfac); + if (t->options & CTX_PAINT_CURVE) { + r_vec[0] = dx; + r_vec[1] = dy; + } + else { const float mval_f[2] = {(float)dx, (float)dy}; + ED_view3d_win_to_delta(t->ar, mval_f, r_vec, t->zfac); + } } else if (t->spacetype == SPACE_IMAGE) { float aspx, aspy; if (t->options & CTX_MASK) { - convertViewVec2D_mask(t->view, r_vec, dx, dy); ED_space_image_get_aspect(t->sa->spacedata.first, &aspx, &aspy); } + else if (t->options & CTX_PAINT_CURVE) { + r_vec[0] = dx; + r_vec[1] = dy; + + aspx = aspy = 1.0; + } else { convertViewVec2D(t->view, r_vec, dx, dy); ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy); @@ -351,6 +364,10 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr adr[0] = v[0]; adr[1] = v[1]; } + else if (t->options & CTX_PAINT_CURVE) { + adr[0] = vec[0]; + adr[1] = vec[1]; + } else { float aspx, aspy, v[2]; @@ -452,7 +469,11 @@ void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], const eV switch (t->spacetype) { case SPACE_VIEW3D: { - if (t->ar->regiontype == RGN_TYPE_WINDOW) { + if (t->options & CTX_PAINT_CURVE) { + adr[0] = vec[0]; + adr[1] = vec[1]; + } + else if (t->ar->regiontype == RGN_TYPE_WINDOW) { /* allow points behind the view [#33643] */ if (ED_view3d_project_float_global(t->ar, vec, adr, flag) != V3D_PROJ_RET_OK) { /* XXX, 2.64 and prior did this, weak! */ @@ -480,7 +501,7 @@ void projectFloatView(TransInfo *t, const float vec[3], float adr[2]) void applyAspectRatio(TransInfo *t, float vec[2]) { - if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION)) { + if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION) && !(t->options & CTX_PAINT_CURVE)) { SpaceImage *sima = t->sa->spacedata.first; float aspx, aspy; @@ -557,17 +578,23 @@ void removeAspectRatio(TransInfo *t, float vec[2]) static void viewRedrawForce(const bContext *C, TransInfo *t) { if (t->spacetype == SPACE_VIEW3D) { - /* Do we need more refined tags? */ - if (t->flag & T_POSE) - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); - else - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + if (t->options & CTX_PAINT_CURVE) { + wmWindow *window = CTX_wm_window(C); + WM_paint_cursor_tag_redraw(window, t->ar); + } + else { + /* Do we need more refined tags? */ + if (t->flag & T_POSE) + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); + else + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - /* for realtime animation record - send notifiers recognised by animation editors */ - // XXX: is this notifier a lame duck? - if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) - WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL); - + /* for realtime animation record - send notifiers recognised by animation editors */ + // XXX: is this notifier a lame duck? + if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) + WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL); + + } } else if (t->spacetype == SPACE_ACTION) { //SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first; @@ -593,6 +620,10 @@ static void viewRedrawForce(const bContext *C, TransInfo *t) WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask); } + else if (t->options & CTX_PAINT_CURVE) { + wmWindow *window = CTX_wm_window(C); + WM_paint_cursor_tag_redraw(window, t->ar); + } else { // XXX how to deal with lock? SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first; @@ -646,7 +677,7 @@ static void viewRedrawPost(bContext *C, TransInfo *t) allqueue(REDRAWIMAGE, 0); allqueue(REDRAWVIEW3D, 0); } - else if (ELEM3(t->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_IPO)) { + else if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_IPO)) { allqueue(REDRAWVIEW3D, 0); allqueue(REDRAWACTION, 0); allqueue(REDRAWNLA, 0); @@ -969,7 +1000,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; case TFM_MODAL_TRANSLATE: /* only switch when... */ - if (ELEM5(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) { + if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) { resetTransModal(t); resetTransRestrictions(t); restoreTransObjects(t); @@ -1025,7 +1056,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) case TFM_MODAL_ROTATE: /* only switch when... */ if (!(t->options & CTX_TEXTURE) && !(t->options & (CTX_MOVIECLIP | CTX_MASK))) { - if (ELEM6(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) { + if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) { resetTransModal(t); resetTransRestrictions(t); @@ -1045,7 +1076,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; case TFM_MODAL_RESIZE: /* only switch when... */ - if (ELEM5(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) { + if (ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) { /* Scale isn't normally very useful after extrude along normals, see T39756 */ if ((t->con.mode & CON_APPLY) && (t->con.orientation == V3D_MANIP_NORMAL)) { @@ -1308,7 +1339,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; case GKEY: /* only switch when... */ - if (ELEM3(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL) ) { + if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) { resetTransModal(t); resetTransRestrictions(t); restoreTransObjects(t); @@ -1320,7 +1351,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; case SKEY: /* only switch when... */ - if (ELEM3(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL) ) { + if (ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL)) { resetTransModal(t); resetTransRestrictions(t); restoreTransObjects(t); @@ -1333,7 +1364,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) case RKEY: /* only switch when... */ if (!(t->options & CTX_TEXTURE)) { - if (ELEM4(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) { + if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION)) { resetTransModal(t); resetTransRestrictions(t); @@ -2065,7 +2096,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve * moded are available from manipulator and doing such check could * lead to keymap conflicts for other modes (see #31584) */ - if (ELEM3(mode, TFM_TRANSLATION, TFM_ROTATION, TFM_RESIZE)) { + if (ELEM(mode, TFM_TRANSLATION, TFM_ROTATION, TFM_RESIZE)) { wmKeyMapItem *kmi; for (kmi = t->keymap->items.first; kmi; kmi = kmi->next) { @@ -3085,9 +3116,11 @@ static void initResize(TransInfo *t) t->num.flag |= NUM_AFFECT_ALL; if (!t->obedit) { t->flag |= T_NO_ZERO; +#ifdef USE_NUM_NO_ZERO t->num.val_flag[0] |= NUM_NO_ZERO; t->num.val_flag[1] |= NUM_NO_ZERO; t->num.val_flag[2] |= NUM_NO_ZERO; +#endif } t->idx_max = 2; @@ -3377,9 +3410,11 @@ static void initSkinResize(TransInfo *t) t->num.flag |= NUM_AFFECT_ALL; if (!t->obedit) { t->flag |= T_NO_ZERO; +#ifdef USE_NUM_NO_ZERO t->num.val_flag[0] |= NUM_NO_ZERO; t->num.val_flag[1] |= NUM_NO_ZERO; t->num.val_flag[2] |= NUM_NO_ZERO; +#endif } t->idx_max = 2; @@ -3592,8 +3627,15 @@ static void initRotation(TransInfo *t) if (t->flag & T_2D_EDIT) t->flag |= T_NO_CONSTRAINT; - negate_v3_v3(t->axis, t->viewinv[2]); - normalize_v3(t->axis); + if (t->options & CTX_PAINT_CURVE) { + t->axis[0] = 0.0; + t->axis[1] = 0.0; + t->axis[2] = -1.0; + } + else { + negate_v3_v3(t->axis, t->viewinv[2]); + normalize_v3(t->axis); + } copy_v3_v3(t->axis_orig, t->axis); } @@ -3627,7 +3669,7 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short if (td->flag & TD_USEQUAT) { - mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL); + mul_m3_series(fmat, td->smtx, mat, td->mtx); mat3_to_quat(quat, fmat); // Actual transform if (td->ext->quat) { @@ -3697,7 +3739,7 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short if ((t->flag & T_V3D_ALIGN) == 0) { /* align mode doesn't rotate objects itself */ /* euler or quaternion/axis-angle? */ if (td->ext->rotOrder == ROT_MODE_QUAT) { - mul_serie_m3(fmat, td->ext->r_mtx, mat, td->ext->r_smtx, NULL, NULL, NULL, NULL, NULL); + mul_m3_series(fmat, td->ext->r_smtx, mat, td->ext->r_mtx); mat3_to_quat(quat, fmat); /* Actual transform */ @@ -3712,7 +3754,7 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle); - mul_serie_m3(fmat, td->ext->r_mtx, mat, td->ext->r_smtx, NULL, NULL, NULL, NULL, NULL); + mul_m3_series(fmat, td->ext->r_smtx, mat, td->ext->r_mtx); mat3_to_quat(quat, fmat); /* Actual transform */ mul_qt_qtqt(tquat, quat, iquat); @@ -3769,7 +3811,7 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short if ((td->ext->rotOrder == ROT_MODE_QUAT) || (td->flag & TD_USEQUAT)) { /* can be called for texture space translate for example, then opt out */ if (td->ext->quat) { - mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL); + mul_m3_series(fmat, td->smtx, mat, td->mtx); mat3_to_quat(quat, fmat); // Actual transform mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat); @@ -3783,7 +3825,7 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle); - mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL); + mul_m3_series(fmat, td->smtx, mat, td->mtx); mat3_to_quat(quat, fmat); // Actual transform mul_qt_qtqt(tquat, quat, iquat); @@ -4480,7 +4522,9 @@ static void initCurveShrinkFatten(TransInfo *t) t->num.unit_type[0] = B_UNIT_NONE; t->flag |= T_NO_ZERO; +#ifdef USE_NUM_NO_ZERO t->num.val_flag[0] |= NUM_NO_ZERO; +#endif t->flag |= T_NO_CONSTRAINT; } @@ -4555,7 +4599,9 @@ static void initMaskShrinkFatten(TransInfo *t) t->num.unit_type[0] = B_UNIT_NONE; t->flag |= T_NO_ZERO; +#ifdef USE_NUM_NO_ZERO t->num.val_flag[0] |= NUM_NO_ZERO; +#endif t->flag |= T_NO_CONSTRAINT; } @@ -7707,7 +7753,7 @@ bool checkUseAxisMatrix(TransInfo *t) { /* currently only checks for editmode */ if (t->flag & T_EDIT) { - if ((t->around == V3D_LOCAL) && (ELEM4(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE))) { + if ((t->around == V3D_LOCAL) && (ELEM(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE))) { /* not all editmode supports axis-matrix */ return true; } diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 0bccf177128..012f9185d8b 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -130,15 +130,15 @@ typedef struct TransDataExtension { // float drotAxis[3]; /* Initial object drotAxis, TODO: not yet implemented */ float dquat[4]; /* Initial object dquat */ float dscale[3]; /* Initial object dscale */ - float *rot; /* Rotation of the data to transform (Faculative) */ + float *rot; /* Rotation of the data to transform */ float irot[3]; /* Initial rotation */ - float *quat; /* Rotation quaternion of the data to transform (Faculative) */ + float *quat; /* Rotation quaternion of the data to transform */ float iquat[4]; /* Initial rotation quaternion */ - float *rotAngle; /* Rotation angle of the data to transform (Faculative) */ + float *rotAngle; /* Rotation angle of the data to transform */ float irotAngle; /* Initial rotation angle */ - float *rotAxis; /* Rotation axis of the data to transform (Faculative) */ + float *rotAxis; /* Rotation axis of the data to transform */ float irotAxis[4]; /* Initial rotation axis */ - float *size; /* Size of the data to transform (Faculative) */ + float *size; /* Size of the data to transform */ float isize[3]; /* Initial size */ float obmat[4][4]; /* Object matrix */ float l_smtx[3][3]; /* use instead of td->smtx, It is the same but without the 'bone->bone_mat', see TD_PBONE_LOCAL_MTX_C */ @@ -532,6 +532,7 @@ void flushTransNodes(TransInfo *t); void flushTransSeq(TransInfo *t); void flushTransTracking(TransInfo *t); void flushTransMasking(TransInfo *t); +void flushTransPaintCurve(TransInfo *t); void restoreBones(TransInfo *t); /*********************** exported from transform_manipulator.c ********** */ diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 79f266df607..d8f17315c01 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -663,7 +663,7 @@ void drawConstraint(TransInfo *t) { TransCon *tc = &(t->con); - if (!ELEM3(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE)) + if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE)) return; if (!(tc->mode & CON_APPLY)) return; @@ -756,6 +756,9 @@ void drawPropCircle(const struct bContext *C, TransInfo *t) /* untested - mask aspect is TODO */ ED_space_image_get_aspect(t->sa->spacedata.first, &aspx, &aspy); } + else if (t->options & CTX_PAINT_CURVE) { + aspx = aspy = 1.0; + } else { ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy); } diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 0696ca55431..a5f57a0c464 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -33,6 +33,7 @@ #include <math.h> #include "DNA_anim_types.h" +#include "DNA_brush_types.h" #include "DNA_armature_types.h" #include "DNA_lattice_types.h" #include "DNA_mesh_types.h" @@ -80,6 +81,7 @@ #include "BKE_node.h" #include "BKE_object.h" #include "BKE_particle.h" +#include "BKE_paint.h" #include "BKE_pointcache.h" #include "BKE_report.h" #include "BKE_rigidbody.h" @@ -124,8 +126,8 @@ static void transform_around_single_fallback(TransInfo *t) { if ((t->total == 1) && - (ELEM3(t->around, V3D_CENTER, V3D_CENTROID, V3D_ACTIVE)) && - (ELEM3(t->mode, TFM_RESIZE, TFM_ROTATION, TFM_TRACKBALL))) + (ELEM(t->around, V3D_CENTER, V3D_CENTROID, V3D_ACTIVE)) && + (ELEM(t->mode, TFM_RESIZE, TFM_ROTATION, TFM_TRACKBALL))) { t->around = V3D_LOCAL; } @@ -282,7 +284,7 @@ static void createTransTexspace(TransInfo *t) } id = ob->data; - if (id == NULL || !ELEM3(GS(id->name), ID_ME, ID_CU, ID_MB)) { + if (id == NULL || !ELEM(GS(id->name), ID_ME, ID_CU, ID_MB)) { BKE_report(t->reports, RPT_ERROR, "Unsupported object type for text-space transform"); t->total = 0; return; @@ -584,12 +586,12 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr if (constraints_list_needinv(t, &pchan->constraints)) { copy_m3_m4(tmat, pchan->constinv); invert_m3_m3(cmat, tmat); - mul_serie_m3(td->mtx, pmat, omat, cmat, NULL, NULL, NULL, NULL, NULL); - mul_serie_m3(td->ext->r_mtx, rpmat, omat, cmat, NULL, NULL, NULL, NULL, NULL); + mul_m3_series(td->mtx, cmat, omat, pmat); + mul_m3_series(td->ext->r_mtx, cmat, omat, rpmat); } else { - mul_serie_m3(td->mtx, pmat, omat, NULL, NULL, NULL, NULL, NULL, NULL); - mul_serie_m3(td->ext->r_mtx, rpmat, omat, NULL, NULL, NULL, NULL, NULL, NULL); + mul_m3_series(td->mtx, omat, pmat); + mul_m3_series(td->ext->r_mtx, omat, rpmat); } invert_m3_m3(td->ext->r_smtx, td->ext->r_mtx); } @@ -2368,8 +2370,7 @@ static void createTransEditVerts(TransInfo *t) quat_to_mat3(qmat, quats[BM_elem_index_get(eve)]); if (defmats) - mul_serie_m3(mat, mtx, qmat, defmats[a], - NULL, NULL, NULL, NULL, NULL); + mul_m3_series(mat, defmats[a], qmat, mtx); else mul_m3_m3m3(mat, mtx, qmat); } @@ -3707,7 +3708,7 @@ static void bezt_to_transdata(TransData *td, TransData2D *td2d, TransDataGraph * static bool graph_edit_is_translation_mode(TransInfo *t) { - return ELEM4(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE, TFM_TIME_DUPLICATE); + return ELEM(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE, TFM_TIME_DUPLICATE); } static bool graph_edit_use_local_center(TransInfo *t) @@ -4767,12 +4768,12 @@ static bool constraints_list_needinv(TransInfo *t, ListBase *list) if ((con->flag & CONSTRAINT_DISABLE) == 0 && (con->enforce != 0.0f)) { /* (affirmative) returns for specific constraints here... */ /* constraints that require this regardless */ - if (ELEM5(con->type, - CONSTRAINT_TYPE_CHILDOF, - CONSTRAINT_TYPE_FOLLOWPATH, - CONSTRAINT_TYPE_CLAMPTO, - CONSTRAINT_TYPE_OBJECTSOLVER, - CONSTRAINT_TYPE_FOLLOWTRACK)) + if (ELEM(con->type, + CONSTRAINT_TYPE_CHILDOF, + CONSTRAINT_TYPE_FOLLOWPATH, + CONSTRAINT_TYPE_CLAMPTO, + CONSTRAINT_TYPE_OBJECTSOLVER, + CONSTRAINT_TYPE_FOLLOWTRACK)) { return true; } @@ -5848,6 +5849,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t) DAG_id_tag_update(&ob->id, OB_RECALC_DATA); } + else if (t->options & CTX_PAINT_CURVE) { + /* pass */ + } else if ((t->scene->basact) && (ob = t->scene->basact->object) && (ob->mode & OB_MODE_PARTICLE_EDIT) && @@ -7027,6 +7031,173 @@ void flushTransMasking(TransInfo *t) } } +typedef struct TransDataPaintCurve { + PaintCurvePoint *pcp; /* initial curve point */ + char id; +} TransDataPaintCurve; + + +#define PC_IS_ANY_SEL(pc) (((pc)->bez.f1 | (pc)->bez.f2 | (pc)->bez.f3) & SELECT) + +static void PaintCurveConvertHandle(PaintCurvePoint *pcp, int id, TransData2D *td2d, TransDataPaintCurve *tdpc, TransData *td) +{ + BezTriple *bezt = &pcp->bez; + copy_v2_v2(td2d->loc, bezt->vec[id]); + td2d->loc[2] = 0.0f; + td2d->loc2d = bezt->vec[id]; + + td->flag = 0; + td->loc = td2d->loc; + copy_v3_v3(td->center, bezt->vec[1]); + copy_v3_v3(td->iloc, td->loc); + + memset(td->axismtx, 0, sizeof(td->axismtx)); + td->axismtx[2][2] = 1.0f; + + td->ext = NULL; + td->val = NULL; + td->flag |= TD_SELECTED; + td->dist = 0.0; + + unit_m3(td->mtx); + unit_m3(td->smtx); + + tdpc->id = id; + tdpc->pcp = pcp; +} + +static void PaintCurvePointToTransData(PaintCurvePoint *pcp, TransData *td, TransData2D *td2d, TransDataPaintCurve *tdpc) +{ + BezTriple *bezt = &pcp->bez; + + if (pcp->bez.f2 == SELECT) { + int i; + for (i = 0; i < 3; i++) { + copy_v2_v2(td2d->loc, bezt->vec[i]); + td2d->loc[2] = 0.0f; + td2d->loc2d = bezt->vec[i]; + + td->flag = 0; + td->loc = td2d->loc; + copy_v3_v3(td->center, bezt->vec[1]); + copy_v3_v3(td->iloc, td->loc); + + memset(td->axismtx, 0, sizeof(td->axismtx)); + td->axismtx[2][2] = 1.0f; + + td->ext = NULL; + td->val = NULL; + td->flag |= TD_SELECTED; + td->dist = 0.0; + + unit_m3(td->mtx); + unit_m3(td->smtx); + + tdpc->id = i; + tdpc->pcp = pcp; + + td++; + td2d++; + tdpc++; + } + } + else { + if (bezt->f3 & SELECT) { + PaintCurveConvertHandle(pcp, 2, td2d, tdpc, td); + td2d++; + tdpc++; + td++; + } + + if (bezt->f1 & SELECT) { + PaintCurveConvertHandle(pcp, 0, td2d, tdpc, td); + } + } +} + +static void createTransPaintCurveVerts(bContext *C, TransInfo *t) +{ + Paint *paint = BKE_paint_get_active_from_context(C); + PaintCurve *pc; + PaintCurvePoint *pcp; + Brush *br; + TransData *td = NULL; + TransData2D *td2d = NULL; + TransDataPaintCurve *tdpc = NULL; + int i; + int total = 0; + + t->total = 0; + + if (!paint || !paint->brush || !paint->brush->paint_curve) + return; + + br = paint->brush; + pc = br->paint_curve; + + for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) { + if (PC_IS_ANY_SEL(pcp)) { + if (pcp->bez.f2 & SELECT) { + total += 3; + continue; + } + else { + if (pcp->bez.f1 & SELECT) + total++; + if (pcp->bez.f3 & SELECT) + total++; + } + } + } + + if (!total) + return; + + t->total = total; + td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransData2D"); + td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransData"); + tdpc = t->customData = MEM_callocN(t->total * sizeof(TransDataPaintCurve), "TransDataPaintCurve"); + t->flag |= T_FREE_CUSTOMDATA; + + for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) { + if (PC_IS_ANY_SEL(pcp)) { + PaintCurvePointToTransData (pcp, td, td2d, tdpc); + + if (pcp->bez.f2 & SELECT) { + td += 3; + td2d += 3; + tdpc += 3; + } + else { + if (pcp->bez.f1 & SELECT) { + td++; + td2d++; + tdpc++; + } + if (pcp->bez.f3 & SELECT) { + td++; + td2d++; + tdpc++; + } + } + } + } +} + + +void flushTransPaintCurve(TransInfo *t) +{ + int i; + TransData2D *td2d = t->data2d; + TransDataPaintCurve *tdpc = (TransDataPaintCurve *)t->customData; + + for (i = 0; i < t->total; i++, tdpc++, td2d++) { + PaintCurvePoint *pcp = tdpc->pcp; + copy_v2_v2(pcp->bez.vec[tdpc->id], td2d->loc); + } +} + + void createTransData(bContext *C, TransInfo *t) { Scene *scene = t->scene; @@ -7059,6 +7230,10 @@ void createTransData(bContext *C, TransInfo *t) sort_trans_data_dist(t); } } + else if (t->options & CTX_PAINT_CURVE) { + if (!ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) + createTransPaintCurveVerts(C, t); + } else if (t->obedit) { createTransUVs(C, t); if (t->data && (t->flag & T_PROP_EDIT)) { @@ -7165,7 +7340,7 @@ void createTransData(bContext *C, TransInfo *t) // XXX active-layer checking isn't done as that should probably be checked through context instead createTransPose(t, ob); } - else if (ob && (ob->mode & OB_MODE_WEIGHT_PAINT)) { + else if (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && !(t->options & CTX_PAINT_CURVE)) { /* important that ob_armature can be set even when its not selected [#23412] * lines below just check is also visible */ Object *ob_armature = modifiers_isDeformedByArmature(ob); @@ -7190,12 +7365,11 @@ void createTransData(bContext *C, TransInfo *t) sort_trans_data_dist(t); } } - else if (ob && (ob->mode & (OB_MODE_ALL_PAINT))) { - /* sculpt mode and project paint have own undo stack - * transform ops redo clears sculpt/project undo stack. - * - * Could use 'OB_MODE_ALL_PAINT' since there are key conflicts, - * transform + paint isn't well supported. */ + else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) { + if ((t->options & CTX_PAINT_CURVE) && !ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) { + t->flag |= T_POINTS | T_2D_EDIT; + createTransPaintCurveVerts(C, t); + } } else { createTransObject(C, t); diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 7d30af0c144..03f09d3b758 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -38,6 +38,7 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" +#include "DNA_brush_types.h" #include "DNA_lattice_types.h" #include "DNA_screen_types.h" #include "DNA_sequence_types.h" @@ -75,6 +76,7 @@ #include "BKE_lattice.h" #include "BKE_nla.h" #include "BKE_context.h" +#include "BKE_paint.h" #include "BKE_sequencer.h" #include "BKE_editmesh.h" #include "BKE_tracking.h" @@ -100,6 +102,7 @@ #include "WM_api.h" #include "UI_resources.h" +#include "UI_view2d.h" #include "transform.h" @@ -264,7 +267,7 @@ static void animrecord_check_state(Scene *scene, ID *id, wmTimer *animtimer) ScreenAnimData *sad = (animtimer) ? animtimer->customdata : NULL; /* sanity checks */ - if (ELEM3(NULL, scene, id, sad)) + if (ELEM(NULL, scene, id, sad)) return; /* check if we need a new strip if: @@ -655,6 +658,9 @@ static void recalcData_image(TransInfo *t) if (t->options & CTX_MASK) { recalcData_mask_common(t); } + else if (t->options & CTX_PAINT_CURVE) { + flushTransPaintCurve(t); + } else if (t->obedit && t->obedit->type == OB_MESH) { SpaceImage *sima = t->sa->spacedata.first; @@ -819,7 +825,7 @@ static void recalcData_objects(TransInfo *t) } } - if (!ELEM3(t->mode, TFM_BONE_ROLL, TFM_BONE_ENVELOPE, TFM_BONESIZE)) { + if (!ELEM(t->mode, TFM_BONE_ROLL, TFM_BONE_ENVELOPE, TFM_BONESIZE)) { /* fix roll */ for (i = 0; i < t->total; i++, td++) { if (td->extra) { @@ -967,6 +973,9 @@ void recalcData(TransInfo *t) else if (t->options & CTX_EDGE) { recalcData_objects(t); } + else if (t->options & CTX_PAINT_CURVE) { + flushTransPaintCurve(t); + } else if (t->spacetype == SPACE_IMAGE) { recalcData_image(t); } @@ -1075,6 +1084,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve ARegion *ar = CTX_wm_region(C); ScrArea *sa = CTX_wm_area(C); Object *obedit = CTX_data_edit_object(C); + Object *ob = CTX_data_active_object(C); PropertyRNA *prop; t->scene = sce; @@ -1195,11 +1205,18 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve /* exceptional case */ if (t->around == V3D_LOCAL && (t->settings->selectmode & SCE_SELECT_FACE)) { - if (ELEM3(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) { + if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) { t->options |= CTX_NO_PET; } } + if (ob && ob->mode & OB_MODE_ALL_PAINT) { + Paint *p = BKE_paint_get_active_from_context(C); + if (p && p->brush && (p->brush->flag & BRUSH_CURVE)) { + t->options |= CTX_PAINT_CURVE; + } + } + /* initialize UV transform from */ if (op && ((prop = RNA_struct_find_property(op->ptr, "correct_uv")))) { if (RNA_property_is_set(op->ptr, prop)) { @@ -1228,9 +1245,13 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve else if (sima->mode == SI_MODE_MASK) { t->options |= CTX_MASK; } - else { - /* image not in uv edit, nor in mask mode, can happen for some tools */ + else if (sima->mode == SI_MODE_PAINT) { + Paint *p = &sce->toolsettings->imapaint.paint; + if (p->brush && (p->brush->flag & BRUSH_CURVE)) { + t->options |= CTX_PAINT_CURVE; + } } + /* image not in uv edit, nor in mask mode, can happen for some tools */ } else if (t->spacetype == SPACE_NODE) { // XXX for now, get View2D from the active region @@ -1411,7 +1432,7 @@ void postTrans(bContext *C, TransInfo *t) } if (t->spacetype == SPACE_IMAGE) { - if (t->options & CTX_MASK) { + if (t->options & (CTX_MASK | CTX_PAINT_CURVE)) { /* pass */ } else { @@ -1541,6 +1562,13 @@ void calculateCenterCursor(TransInfo *t, float r_center[3]) invert_m3_m3(imat, mat); mul_m3_v3(imat, r_center); } + else if (t->options & CTX_PAINT_CURVE) { + if (ED_view3d_project_float_global(t->ar, cursor, r_center, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) { + r_center[0] = t->ar->winx / 2.0f; + r_center[1] = t->ar->winy / 2.0f; + } + r_center[2] = 0.0f; + } } void calculateCenterCursor2D(TransInfo *t, float r_center[2]) @@ -1588,6 +1616,12 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2]) r_center[0] = co[0] * aspx; r_center[1] = co[1] * aspy; } + else if (t->options & CTX_PAINT_CURVE) { + if (t->spacetype == SPACE_IMAGE) { + r_center[0] = UI_view2d_view_to_region_x(&t->ar->v2d, cursor[0]); + r_center[1] = UI_view2d_view_to_region_y(&t->ar->v2d, cursor[1]); + } + } else { r_center[0] = cursor[0] * aspx; r_center[1] = cursor[1] * aspy; @@ -1775,6 +1809,14 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3]) } } } + else if (t->options & CTX_PAINT_CURVE) { + Paint *p = BKE_paint_get_active(t->scene); + Brush *br = p->brush; + PaintCurve *pc = br->paint_curve; + copy_v3_v3(r_center, pc->points[pc->add_index - 1].bez.vec[1]); + r_center[2] = 0.0f; + ok = true; + } else { /* object mode */ Scene *scene = t->scene; diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index b1512f7b855..df501ca5da9 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -75,6 +75,8 @@ /* local module include */ #include "transform.h" +#include "GPU_select.h" + /* return codes for select, and drawing flags */ #define MAN_TRANS_X (1 << 0) @@ -878,8 +880,8 @@ static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int co /* axes */ if (flagx) { if (is_picksel) { - if (flagx & MAN_SCALE_X) glLoadName(MAN_SCALE_X); - else if (flagx & MAN_TRANS_X) glLoadName(MAN_TRANS_X); + if (flagx & MAN_SCALE_X) GPU_select_load_id(MAN_SCALE_X); + else if (flagx & MAN_TRANS_X) GPU_select_load_id(MAN_TRANS_X); } else { manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0])); @@ -893,8 +895,8 @@ static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int co case 1: if (flagy) { if (is_picksel) { - if (flagy & MAN_SCALE_Y) glLoadName(MAN_SCALE_Y); - else if (flagy & MAN_TRANS_Y) glLoadName(MAN_TRANS_Y); + if (flagy & MAN_SCALE_Y) GPU_select_load_id(MAN_SCALE_Y); + else if (flagy & MAN_TRANS_Y) GPU_select_load_id(MAN_TRANS_Y); } else { manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1])); @@ -908,8 +910,8 @@ static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int co case 2: if (flagz) { if (is_picksel) { - if (flagz & MAN_SCALE_Z) glLoadName(MAN_SCALE_Z); - else if (flagz & MAN_TRANS_Z) glLoadName(MAN_TRANS_Z); + if (flagz & MAN_SCALE_Z) GPU_select_load_id(MAN_SCALE_Z); + else if (flagz & MAN_TRANS_Z) GPU_select_load_id(MAN_TRANS_Z); } else { manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2])); @@ -995,7 +997,7 @@ static void draw_manipulator_rotate( /* Screen aligned trackball rot circle */ if (drawflags & MAN_ROT_T) { - if (is_picksel) glLoadName(MAN_ROT_T); + if (is_picksel) GPU_select_load_id(MAN_ROT_T); else UI_ThemeColor(TH_TRANSFORM); drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat); @@ -1003,7 +1005,7 @@ static void draw_manipulator_rotate( /* Screen aligned view rot circle */ if (drawflags & MAN_ROT_V) { - if (is_picksel) glLoadName(MAN_ROT_V); + if (is_picksel) GPU_select_load_id(MAN_ROT_V); else UI_ThemeColor(TH_TRANSFORM); drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f * size, unitmat); @@ -1082,7 +1084,7 @@ static void draw_manipulator_rotate( /* Z circle */ if (drawflags & MAN_ROT_Z) { preOrthoFront(ortho, matt, 2); - if (is_picksel) glLoadName(MAN_ROT_Z); + if (is_picksel) GPU_select_load_id(MAN_ROT_Z); else manipulator_setcolor(v3d, 'Z', colcode, 255); drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat); postOrtho(ortho); @@ -1090,7 +1092,7 @@ static void draw_manipulator_rotate( /* X circle */ if (drawflags & MAN_ROT_X) { preOrthoFront(ortho, matt, 0); - if (is_picksel) glLoadName(MAN_ROT_X); + if (is_picksel) GPU_select_load_id(MAN_ROT_X); else manipulator_setcolor(v3d, 'X', colcode, 255); glRotatef(90.0, 0.0, 1.0, 0.0); drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat); @@ -1100,7 +1102,7 @@ static void draw_manipulator_rotate( /* Y circle */ if (drawflags & MAN_ROT_Y) { preOrthoFront(ortho, matt, 1); - if (is_picksel) glLoadName(MAN_ROT_Y); + if (is_picksel) GPU_select_load_id(MAN_ROT_Y); else manipulator_setcolor(v3d, 'Y', colcode, 255); glRotatef(-90.0, 1.0, 0.0, 0.0); drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat); @@ -1117,7 +1119,7 @@ static void draw_manipulator_rotate( /* Z circle */ if (drawflags & MAN_ROT_Z) { preOrthoFront(ortho, rv3d->twmat, 2); - if (is_picksel) glLoadName(MAN_ROT_Z); + if (is_picksel) GPU_select_load_id(MAN_ROT_Z); else manipulator_setcolor(v3d, 'Z', colcode, 255); partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48); postOrtho(ortho); @@ -1125,7 +1127,7 @@ static void draw_manipulator_rotate( /* X circle */ if (drawflags & MAN_ROT_X) { preOrthoFront(ortho, rv3d->twmat, 0); - if (is_picksel) glLoadName(MAN_ROT_X); + if (is_picksel) GPU_select_load_id(MAN_ROT_X); else manipulator_setcolor(v3d, 'X', colcode, 255); glRotatef(90.0, 0.0, 1.0, 0.0); partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48); @@ -1135,7 +1137,7 @@ static void draw_manipulator_rotate( /* Y circle */ if (drawflags & MAN_ROT_Y) { preOrthoFront(ortho, rv3d->twmat, 1); - if (is_picksel) glLoadName(MAN_ROT_Y); + if (is_picksel) GPU_select_load_id(MAN_ROT_Y); else manipulator_setcolor(v3d, 'Y', colcode, 255); glRotatef(-90.0, 1.0, 0.0, 0.0); partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48); @@ -1152,7 +1154,7 @@ static void draw_manipulator_rotate( if (drawflags & MAN_ROT_Z) { preOrthoFront(ortho, rv3d->twmat, 2); glPushMatrix(); - if (is_picksel) glLoadName(MAN_ROT_Z); + if (is_picksel) GPU_select_load_id(MAN_ROT_Z); else manipulator_setcolor(v3d, 'Z', colcode, 255); partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64); @@ -1165,7 +1167,7 @@ static void draw_manipulator_rotate( if (drawflags & MAN_ROT_Y) { preOrthoFront(ortho, rv3d->twmat, 1); glPushMatrix(); - if (is_picksel) glLoadName(MAN_ROT_Y); + if (is_picksel) GPU_select_load_id(MAN_ROT_Y); else manipulator_setcolor(v3d, 'Y', colcode, 255); glRotatef(90.0, 1.0, 0.0, 0.0); @@ -1180,7 +1182,7 @@ static void draw_manipulator_rotate( if (drawflags & MAN_ROT_X) { preOrthoFront(ortho, rv3d->twmat, 0); glPushMatrix(); - if (is_picksel) glLoadName(MAN_ROT_X); + if (is_picksel) GPU_select_load_id(MAN_ROT_X); else manipulator_setcolor(v3d, 'X', colcode, 255); glRotatef(-90.0, 0.0, 1.0, 0.0); @@ -1283,7 +1285,7 @@ static void draw_manipulator_scale( int shift = 0; // XXX /* center circle, do not add to selection when shift is pressed (planar constraint) */ - if (is_picksel && shift == 0) glLoadName(MAN_SCALE_C); + if (is_picksel && shift == 0) GPU_select_load_id(MAN_SCALE_C); else manipulator_setcolor(v3d, 'C', colcode, 255); glPushMatrix(); @@ -1324,7 +1326,7 @@ static void draw_manipulator_scale( case 0: /* X cube */ if (drawflags & MAN_SCALE_X) { glTranslatef(dz, 0.0, 0.0); - if (is_picksel) glLoadName(MAN_SCALE_X); + if (is_picksel) GPU_select_load_id(MAN_SCALE_X); else manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0])); drawsolidcube(cusize); glTranslatef(-dz, 0.0, 0.0); @@ -1333,7 +1335,7 @@ static void draw_manipulator_scale( case 1: /* Y cube */ if (drawflags & MAN_SCALE_Y) { glTranslatef(0.0, dz, 0.0); - if (is_picksel) glLoadName(MAN_SCALE_Y); + if (is_picksel) GPU_select_load_id(MAN_SCALE_Y); else manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1])); drawsolidcube(cusize); glTranslatef(0.0, -dz, 0.0); @@ -1342,7 +1344,7 @@ static void draw_manipulator_scale( case 2: /* Z cube */ if (drawflags & MAN_SCALE_Z) { glTranslatef(0.0, 0.0, dz); - if (is_picksel) glLoadName(MAN_SCALE_Z); + if (is_picksel) GPU_select_load_id(MAN_SCALE_Z); else manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2])); drawsolidcube(cusize); glTranslatef(0.0, 0.0, -dz); @@ -1357,7 +1359,7 @@ static void draw_manipulator_scale( if (shift) { glTranslatef(0.0, -dz, 0.0); - glLoadName(MAN_SCALE_C); + GPU_select_load_id(MAN_SCALE_C); glBegin(GL_POINTS); glVertex3f(0.0, 0.0, 0.0); glEnd(); @@ -1419,7 +1421,7 @@ static void draw_manipulator_translate( glDisable(GL_DEPTH_TEST); /* center circle, do not add to selection when shift is pressed (planar constraint) */ - if (is_picksel && shift == 0) glLoadName(MAN_TRANS_C); + if (is_picksel && shift == 0) GPU_select_load_id(MAN_TRANS_C); else manipulator_setcolor(v3d, 'C', colcode, 255); glPushMatrix(); @@ -1432,7 +1434,7 @@ static void draw_manipulator_translate( glMultMatrixf(rv3d->twmat); /* axis */ - glLoadName(-1); + GPU_select_load_id(-1); // translate drawn as last, only axis when no combo with scale, or for ghosting if ((combo & V3D_MANIP_SCALE) == 0 || colcode == MAN_GHOST) { @@ -1455,7 +1457,7 @@ static void draw_manipulator_translate( case 0: /* Z Cone */ if (drawflags & MAN_TRANS_Z) { glTranslatef(0.0, 0.0, dz); - if (is_picksel) glLoadName(MAN_TRANS_Z); + if (is_picksel) GPU_select_load_id(MAN_TRANS_Z); else manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2])); draw_cone(qobj, cylen, cywid); glTranslatef(0.0, 0.0, -dz); @@ -1464,7 +1466,7 @@ static void draw_manipulator_translate( case 1: /* X Cone */ if (drawflags & MAN_TRANS_X) { glTranslatef(dz, 0.0, 0.0); - if (is_picksel) glLoadName(MAN_TRANS_X); + if (is_picksel) GPU_select_load_id(MAN_TRANS_X); else manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0])); glRotatef(90.0, 0.0, 1.0, 0.0); draw_cone(qobj, cylen, cywid); @@ -1475,7 +1477,7 @@ static void draw_manipulator_translate( case 2: /* Y Cone */ if (drawflags & MAN_TRANS_Y) { glTranslatef(0.0, dz, 0.0); - if (is_picksel) glLoadName(MAN_TRANS_Y); + if (is_picksel) GPU_select_load_id(MAN_TRANS_Y); else manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1])); glRotatef(-90.0, 1.0, 0.0, 0.0); draw_cone(qobj, cylen, cywid); @@ -1523,7 +1525,7 @@ static void draw_manipulator_rotate_cyl( unit_m4(unitmat); - if (is_picksel) glLoadName(MAN_ROT_V); + if (is_picksel) GPU_select_load_id(MAN_ROT_V); UI_ThemeColor(TH_TRANSFORM); drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f * size, unitmat); @@ -1576,7 +1578,7 @@ static void draw_manipulator_rotate_cyl( case 0: /* X cylinder */ if (drawflags & MAN_ROT_X) { glTranslatef(1.0, 0.0, 0.0); - if (is_picksel) glLoadName(MAN_ROT_X); + if (is_picksel) GPU_select_load_id(MAN_ROT_X); glRotatef(90.0, 0.0, 1.0, 0.0); manipulator_setcolor(v3d, 'X', colcode, 255); draw_cylinder(qobj, cylen, cywid); @@ -1587,7 +1589,7 @@ static void draw_manipulator_rotate_cyl( case 1: /* Y cylinder */ if (drawflags & MAN_ROT_Y) { glTranslatef(0.0, 1.0, 0.0); - if (is_picksel) glLoadName(MAN_ROT_Y); + if (is_picksel) GPU_select_load_id(MAN_ROT_Y); glRotatef(-90.0, 1.0, 0.0, 0.0); manipulator_setcolor(v3d, 'Y', colcode, 255); draw_cylinder(qobj, cylen, cywid); @@ -1598,7 +1600,7 @@ static void draw_manipulator_rotate_cyl( case 2: /* Z cylinder */ if (drawflags & MAN_ROT_Z) { glTranslatef(0.0, 0.0, 1.0); - if (is_picksel) glLoadName(MAN_ROT_Z); + if (is_picksel) GPU_select_load_id(MAN_ROT_Z); manipulator_setcolor(v3d, 'Z', colcode, 255); draw_cylinder(qobj, cylen, cywid); glTranslatef(0.0, 0.0, -1.0); @@ -1710,10 +1712,11 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl { View3D *v3d = sa->spacedata.first; RegionView3D *rv3d = ar->regiondata; - rctf rect; + rctf rect, selrect; GLuint buffer[64]; // max 4 items per select, so large enuf short hits; const bool is_picksel = true; + const bool do_passes = GPU_select_query_check_active(); /* XXX check a bit later on this... (ton) */ extern void view3d_winmatrix_set(ARegion *ar, View3D *v3d, rctf *rect); @@ -1728,13 +1731,15 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl rect.ymin = mval[1] - hotspot; rect.ymax = mval[1] + hotspot; + selrect = rect; + view3d_winmatrix_set(ar, v3d, &rect); mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); - glSelectBuffer(64, buffer); - glRenderMode(GL_SELECT); - glInitNames(); /* these two calls whatfor? It doesn't work otherwise */ - glPushName(-2); + if (do_passes) + GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_NEAREST_FIRST_PASS, 0); + else + GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_ALL, 0); /* do the drawing */ if (v3d->twtype & V3D_MANIP_ROTATE) { @@ -1746,8 +1751,23 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl if (v3d->twtype & V3D_MANIP_TRANSLATE) draw_manipulator_translate(v3d, rv3d, MAN_TRANS_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel); - glPopName(); - hits = glRenderMode(GL_RENDER); + hits = GPU_select_end(); + + if (do_passes) { + GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_NEAREST_SECOND_PASS, hits); + + /* do the drawing */ + if (v3d->twtype & V3D_MANIP_ROTATE) { + if (G.debug_value == 3) draw_manipulator_rotate_cyl(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel); + else draw_manipulator_rotate(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, false, is_picksel); + } + if (v3d->twtype & V3D_MANIP_SCALE) + draw_manipulator_scale(v3d, rv3d, MAN_SCALE_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel); + if (v3d->twtype & V3D_MANIP_TRANSLATE) + draw_manipulator_translate(v3d, rv3d, MAN_TRANS_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel); + + GPU_select_end(); + } view3d_winmatrix_set(ar, v3d, NULL); mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index ba90926df3b..69d135b8550 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -756,7 +756,7 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3], if (flag) { float tvec[3]; if ((v3d->around == V3D_LOCAL) || - ELEM3(flag, SEL_F2, SEL_F1 | SEL_F3, SEL_F1 | SEL_F2 | SEL_F3)) + ELEM(flag, SEL_F2, SEL_F1 | SEL_F3, SEL_F1 | SEL_F2 | SEL_F3)) { BKE_nurb_bezt_calc_normal(nu, bezt, tvec); add_v3_v3(normal, tvec); diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 451837fd311..abef2c9fc30 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -117,8 +117,8 @@ int BIF_snappingSupported(Object *obedit) { int status = 0; - if (obedit == NULL || ELEM5(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) /* only support object mesh, armature, curves */ - { + /* only support object mesh, armature, curves */ + if (obedit == NULL || ELEM(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) { status = 1; } @@ -337,6 +337,46 @@ void applyProject(TransInfo *t) mul_m3_v3(td->smtx, tvec); add_v3_v3(td->loc, tvec); + + if (t->tsnap.align && (t->flag & T_OBJECT)) { + /* handle alignment as well */ + const float *original_normal; + float axis[3]; + float mat[3][3]; + float angle; + float totmat[3][3], smat[3][3]; + float eul[3], fmat[3][3], quat[4]; + float obmat[3][3]; + + /* In pose mode, we want to align normals with Y axis of bones... */ + original_normal = td->axismtx[2]; + + cross_v3_v3v3(axis, original_normal, no); + angle = saacos(dot_v3v3(original_normal, no)); + + axis_angle_to_quat(quat, axis, angle); + + quat_to_mat3(mat, quat); + + mul_m3_m3m3(totmat, mat, td->mtx); + mul_m3_m3m3(smat, td->smtx, totmat); + + /* calculate the total rotatation in eulers */ + add_v3_v3v3(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */ + eulO_to_mat3(obmat, eul, td->ext->rotOrder); + /* mat = transform, obmat = object rotation */ + mul_m3_m3m3(fmat, smat, obmat); + + mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat); + + /* correct back for delta rot */ + sub_v3_v3v3(eul, eul, td->ext->drot); + + /* and apply */ + copy_v3_v3(td->ext->rot, eul); + + /* TODO support constraints for rotation too? see ElementRotation */ + } } } @@ -505,7 +545,7 @@ static void initSnappingMode(TransInfo *t) /* Edit mode */ if (t->tsnap.applySnap != NULL && // A snapping function actually exist - (obedit != NULL && ELEM5(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) ) // Temporary limited to edit mode meshes, armature, curves, mballs + (obedit != NULL && ELEM(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) ) // Temporary limited to edit mode meshes, armature, curves, mballs { /* Exclude editmesh if using proportional edit */ if ((obedit->type == OB_MESH) && (t->flag & T_PROP_EDIT)) { @@ -588,7 +628,7 @@ void initSnapping(TransInfo *t, wmOperator *op) } /* use scene defaults only when transform is modal */ else if (t->flag & T_MODAL) { - if (ELEM3(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE)) { + if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE)) { if (ts->snap_flag & SCE_SNAP) { t->modifiers |= MOD_SNAP; } @@ -658,7 +698,8 @@ static void setSnappingCallback(TransInfo *t) void addSnapPoint(TransInfo *t) { - if (t->tsnap.status & POINT_INIT) { + /* Currently only 3D viewport works for snapping points. */ + if (t->tsnap.status & POINT_INIT && t->spacetype == SPACE_VIEW3D) { TransSnapPoint *p = MEM_callocN(sizeof(TransSnapPoint), "SnapPoint"); t->tsnap.selectedPoint = p; @@ -1492,6 +1533,8 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes const float mval[2], float r_loc[3], float r_no[3], float *r_dist_px, float *r_depth, bool do_bb) { bool retval = false; + const bool do_ray_start_correction = (snap_mode == SCE_SNAP_MODE_FACE && ar && + !((RegionView3D *)ar->regiondata)->is_persp); int totvert = dm->getNumVerts(dm); if (totvert > 0) { @@ -1518,6 +1561,28 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes return retval; } } + else if (do_ray_start_correction) { + /* We *need* a reasonably valid len_diff in this case. + * Use BHVTree to find the closest face from ray_start_local. + */ + BVHTreeFromMesh treeData; + BVHTreeNearest nearest; + len_diff = 0.0f; /* In case BVHTree would fail for some reason... */ + + treeData.em_evil = em; + bvhtree_from_mesh_faces(&treeData, dm, 0.0f, 2, 6); + if (treeData.tree != NULL) { + nearest.index = -1; + nearest.dist_sq = FLT_MAX; + /* Compute and store result. */ + BLI_bvhtree_find_nearest(treeData.tree, ray_start_local, &nearest, + treeData.nearest_callback, &treeData); + if (nearest.index != -1) { + len_diff = sqrtf(nearest.dist_sq); + } + } + free_bvhtree_from_mesh(&treeData); + } switch (snap_mode) { case SCE_SNAP_MODE_FACE: @@ -1529,7 +1594,7 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes * been *inside* boundbox, leading to snap failures (see T38409). * Note also ar might be null (see T38435), in this case we assume ray_start is ok! */ - if (ar && !((RegionView3D *)ar->regiondata)->is_persp) { + if (do_ray_start_correction) { float ray_org_local[3]; copy_v3_v3(ray_org_local, ray_origin); @@ -2383,6 +2448,9 @@ static void applyGridIncrement(TransInfo *t, float *val, int max_index, float fa if (t->options & CTX_MASK) { ED_space_image_get_aspect(t->sa->spacedata.first, asp, asp + 1); } + else if (t->options & CTX_PAINT_CURVE) { + asp[0] = asp[1] = 1.0; + } else { ED_space_image_get_uv_aspect(t->sa->spacedata.first, asp, asp + 1); } diff --git a/source/blender/editors/util/ed_transverts.c b/source/blender/editors/util/ed_transverts.c index 3bd927e5b25..104b628c25a 100644 --- a/source/blender/editors/util/ed_transverts.c +++ b/source/blender/editors/util/ed_transverts.c @@ -192,7 +192,7 @@ static void set_mapped_co(void *vuserdata, int index, const float co[3], bool ED_transverts_check_obedit(Object *obedit) { - return (ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL)); + return (ELEM(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL)); } void ED_transverts_create_from_obedit(TransVertStore *tvs, Object *obedit, const int mode) diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 47fbfbe3eba..56b12fcdcda 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -86,7 +86,7 @@ void ED_editors_init(bContext *C) /* This is called during initialization, so we don't want to store any reports */ ReportList *reports = CTX_wm_reports(C); - int reports_flag_prev = reports->flag &= ~RPT_STORE; + int reports_flag_prev = reports->flag & ~RPT_STORE; SWAP(int, reports->flag, reports_flag_prev); diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c index a618ab8419b..fd8f16f5d02 100644 --- a/source/blender/editors/util/numinput.c +++ b/source/blender/editors/util/numinput.c @@ -98,7 +98,7 @@ void outputNumInput(NumInput *n, char *str, const float scale_length) const short i = (n->flag & NUM_AFFECT_ALL && n->idx != j && !(n->val_flag[j] & NUM_EDITED)) ? 0 : j; /* Use scale_length if needed! */ - const float fac = ELEM3(n->unit_type[j], B_UNIT_LENGTH, B_UNIT_AREA, B_UNIT_VOLUME) ? scale_length : 1.0f; + const float fac = ELEM(n->unit_type[j], B_UNIT_LENGTH, B_UNIT_AREA, B_UNIT_VOLUME) ? scale_length : 1.0f; if (n->val_flag[i] & NUM_EDITED) { /* Get the best precision, allows us to draw '10.0001' as '10' instead! */ @@ -189,15 +189,15 @@ bool applyNumInput(NumInput *n, float *vec) if (n->val_flag[i] & NUM_NO_NEGATIVE && val < 0.0f) { val = 0.0f; } - if (n->val_flag[i] & NUM_NO_ZERO && val == 0.0f) { - val = 0.0001f; - } if (n->val_flag[i] & NUM_NO_FRACTION && val != floorf(val)) { val = floorf(val + 0.5f); if (n->val_flag[i] & NUM_NO_ZERO && val == 0.0f) { val = 1.0f; } } + else if (n->val_flag[i] & NUM_NO_ZERO && val == 0.0f) { + val = 0.0001f; + } } vec[j] = val; } @@ -480,7 +480,7 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event) default_unit = "r"; /* Use scale_length if needed! */ - if (ELEM3(n->unit_type[idx], B_UNIT_LENGTH, B_UNIT_AREA, B_UNIT_VOLUME)) + if (ELEM(n->unit_type[idx], B_UNIT_LENGTH, B_UNIT_AREA, B_UNIT_VOLUME)) fac /= sce->unit.scale_length; BLI_strncpy(str_unit_convert, n->str, sizeof(str_unit_convert)); diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index a1cc23f735b..36c96a8d011 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -33,6 +33,7 @@ #include <stdlib.h> #include <string.h> +#include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" @@ -48,6 +49,8 @@ #include "BKE_DerivedMesh.h" #include "BKE_editmesh.h" +#include "BKE_material.h" + #include "BKE_scene.h" #include "BIF_gl.h" @@ -403,20 +406,28 @@ static void draw_uvs_other_mesh_new_shading(Object *ob, const Image *curimage) int a; BLI_bitmap *mat_test_array; bool ok = false; + int totcol = 0; if (me->mloopuv == NULL) { return; } - if (ob->totcol == 0) { + if (curimage && ob->totcol == 0) { return; } - mat_test_array = BLI_BITMAP_NEW_ALLOCA(ob->totcol); + totcol = max_ii(ob->totcol, 1); + mat_test_array = BLI_BITMAP_NEW_ALLOCA(totcol); - for (a = 0; a < ob->totcol; a++) { + for (a = 0; a < totcol; a++) { Image *image; - ED_object_get_active_image(ob, a + 1, &image, NULL, NULL); + + /* if no materials, assume a default material with no image */ + if (ob->totcol) + ED_object_get_active_image(ob, a + 1, &image, NULL, NULL, NULL); + else + image = NULL; + if (image == curimage) { BLI_BITMAP_ENABLE(mat_test_array, a); ok = true; @@ -429,7 +440,7 @@ static void draw_uvs_other_mesh_new_shading(Object *ob, const Image *curimage) for (a = me->totpoly; a != 0; a--, mpoly++) { const int mat_nr = mpoly->mat_nr; - if ((mat_nr >= ob->totcol) || + if ((mat_nr >= totcol) || (BLI_BITMAP_TEST(mat_test_array, mat_nr)) == 0) { continue; @@ -471,13 +482,39 @@ static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, Object *ob) { const bool new_shading_nodes = BKE_scene_use_new_shading_nodes(scene); Image *curimage = ED_space_image(sima); + Mesh *me = ob->data; + Material *ma; if (sima->flag & SI_DRAW_OTHER) { draw_uvs_other(scene, ob, curimage, new_shading_nodes); } UI_ThemeColor(TH_UV_SHADOW); - draw_uvs_other_mesh(ob, curimage, new_shading_nodes); + + ma = give_current_material(ob, ob->actcol); + + if (me->mtpoly) { + MPoly *mpoly = me->mpoly; + MLoopUV *mloopuv, *mloopuv_base; + int a, b; + if (!(ma && ma->texpaintslot && ma->texpaintslot[ma->paint_active_slot].uvname && + (mloopuv = CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, ma->texpaintslot[ma->paint_active_slot].uvname)))) + { + mloopuv = me->mloopuv; + } + + mloopuv_base = mloopuv; + + for (a = me->totpoly; a > 0; a--, mpoly++) { + glBegin(GL_LINE_LOOP); + + mloopuv = mloopuv_base + mpoly->loopstart; + for (b = 0; b < mpoly->totloop; b++, mloopuv++) { + glVertex2fv(mloopuv->uv); + } + glEnd(); + } + } } #ifdef USE_EDBM_LOOPTRIS @@ -540,7 +577,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) if (new_shading_nodes) { if (efa_act) { - ED_object_get_active_image(obedit, efa_act->mat_nr + 1, &curimage, NULL, NULL); + ED_object_get_active_image(obedit, efa_act->mat_nr + 1, &curimage, NULL, NULL, NULL); } else { curimage = ima; @@ -914,7 +951,7 @@ void draw_uvedit_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *obedi ToolSettings *toolsettings = scene->toolsettings; int show_uvedit, show_uvshadow, show_texpaint_uvshadow; - show_texpaint_uvshadow = (obact && obact->type == OB_MESH && obact->mode == OB_MODE_TEXTURE_PAINT); + show_texpaint_uvshadow = ED_space_image_show_texpaint(sima, obact); show_uvedit = ED_space_image_show_uvedit(sima, obedit); show_uvshadow = ED_space_image_show_uvshadow(sima, obedit); diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 6cf34d9f93f..0d8b5a524b6 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -137,21 +137,24 @@ static bool is_image_texture_node(bNode *node) } bool ED_object_get_active_image(Object *ob, int mat_nr, - Image **r_ima, ImageUser **r_iuser, bNode **r_node) + Image **r_ima, ImageUser **r_iuser, bNode **r_node, bNodeTree **r_ntree) { Material *ma = give_current_material(ob, mat_nr); - bNode *node = (ma && ma->use_nodes) ? nodeGetActiveTexture(ma->nodetree) : NULL; + bNodeTree *ntree = (ma && ma->use_nodes) ? ma->nodetree : NULL; + bNode *node = (ntree) ? nodeGetActiveTexture(ntree) : NULL; if (node && is_image_texture_node(node)) { if (r_ima) *r_ima = (Image *)node->id; if (r_iuser) *r_iuser = NULL; if (r_node) *r_node = node; + if (r_ntree) *r_ntree = ntree; return true; } if (r_ima) *r_ima = NULL; if (r_iuser) *r_iuser = NULL; if (r_node) *r_node = node; + if (r_ntree) *r_ntree = ntree; return false; } @@ -3827,7 +3830,8 @@ static void UV_OT_reveal(wmOperatorType *ot) static int uv_set_2d_cursor_poll(bContext *C) { return ED_operator_uvedit_space_image(C) || - ED_space_image_maskedit_poll(C); + ED_space_image_maskedit_poll(C) || + ED_space_image_paint_curve(C); } static int uv_set_2d_cursor_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 21e7bb00204..335d8e6589e 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -201,7 +201,7 @@ void uvedit_get_aspect(Scene *scene, Object *ob, BMEditMesh *em, float *aspx, fl if (efa) { if (BKE_scene_use_new_shading_nodes(scene)) { - ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL); + ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL, NULL); } else { MTexPoly *tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); @@ -938,7 +938,7 @@ static void uv_map_rotation_matrix(float result[4][4], RegionView3D *rv3d, Objec rotup[0][0] = 1.0f / radius; /* calculate transforms*/ - mul_serie_m4(result, rotup, rotside, viewmatrix, rotobj, NULL, NULL, NULL, NULL); + mul_m4_series(result, rotup, rotside, viewmatrix, rotobj); } static void uv_map_transform(bContext *C, wmOperator *op, float center[3], float rotmat[4][4]) diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp index dbbc4f77c26..57882cbce0c 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp @@ -449,7 +449,7 @@ void BlenderFileLoader::insertShapeNode(ObjectInstanceRen *obi, int id) return; // We allocate memory for the meshes to be imported - NodeTransform *currentMesh = new NodeTransform; + NodeGroup *currentMesh = new NodeGroup; NodeShape *shape = new NodeShape; unsigned vSize = 3 * 3 * numFaces; @@ -799,10 +799,6 @@ void BlenderFileLoader::insertShapeNode(ObjectInstanceRen *obi, int id) rep->setBBox(bbox); shape->AddRep(rep); - Matrix44r meshMat = Matrix44r::identity(); - currentMesh->setMatrix(meshMat); - currentMesh->Translate(0, 0, 0); - currentMesh->AddChild(shape); _Scene->AddChild(currentMesh); } diff --git a/source/blender/freestyle/intern/geometry/Grid.h b/source/blender/freestyle/intern/geometry/Grid.h index c0cab2a05db..c1d04f6b4cc 100644 --- a/source/blender/freestyle/intern/geometry/Grid.h +++ b/source/blender/freestyle/intern/geometry/Grid.h @@ -30,9 +30,7 @@ #include <cstring> // for memset #include <float.h> -#if !defined(_MSC_VER) || _MSC_VER >= 1700 #include <stdint.h> // For SET_UINT_IN_POINTER, i.e. uintptr_t. -#endif #include <vector> #include "Geom.h" diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp b/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp index 36cdb1b92ff..1ef29792d56 100644 --- a/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp +++ b/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp @@ -178,6 +178,19 @@ static int CurvePoint_second_svertex_set(BPy_CurvePoint *self, PyObject *value, return 0; } +PyDoc_STRVAR(CurvePoint_fedge_doc, +"Gets the FEdge for the two SVertices that given CurvePoints consists out of.\n" +"A shortcut for CurvePoint.first_svertex.get_fedge(CurvePoint.second_svertex).\n" +"\n" +":type: :class:`FEdge`"); + +static PyObject *CurvePoint_fedge_get(BPy_CurvePoint *self, void *UNUSED(closure)) +{ + SVertex *A = self->cp->A(); + Interface0D *B = (Interface0D *)self->cp->B(); + return Any_BPy_Interface1D_from_Interface1D(*(A->getFEdge(*B))); +} + PyDoc_STRVAR(CurvePoint_t2d_doc, "The 2D interpolation parameter.\n" "\n" @@ -204,6 +217,8 @@ static PyGetSetDef BPy_CurvePoint_getseters[] = { (char *)CurvePoint_first_svertex_doc, NULL}, {(char *)"second_svertex", (getter)CurvePoint_second_svertex_get, (setter)CurvePoint_second_svertex_set, (char *)CurvePoint_second_svertex_doc, NULL}, + {(char *)"fedge", (getter)CurvePoint_fedge_get, NULL, + CurvePoint_fedge_doc, NULL}, {(char *)"t2d", (getter)CurvePoint_t2d_get, (setter)CurvePoint_t2d_set, (char *)CurvePoint_t2d_doc, NULL}, {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ }; diff --git a/source/blender/freestyle/intern/stroke/StrokeRep.h b/source/blender/freestyle/intern/stroke/StrokeRep.h index 61a456cdf42..50615e0c571 100644 --- a/source/blender/freestyle/intern/stroke/StrokeRep.h +++ b/source/blender/freestyle/intern/stroke/StrokeRep.h @@ -37,7 +37,7 @@ #endif extern "C" { -#include "DNA_material_types.h" +#include "DNA_material_types.h" // for MAX_MTEX } namespace Freestyle { diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 739deffa519..13e46bc7de8 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -51,12 +51,14 @@ set(SRC intern/gpu_extensions.c intern/gpu_material.c intern/gpu_simple_shader.c + intern/gpu_select.c GPU_buffers.h GPU_draw.h GPU_extensions.h GPU_material.h GPU_simple_shader.h + GPU_select.h intern/gpu_codegen.h ) diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index 096b2080b2b..461995e37b5 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -139,6 +139,7 @@ void GPU_drawobject_free(struct DerivedMesh *dm); void GPU_vertex_setup(struct DerivedMesh *dm); void GPU_normal_setup(struct DerivedMesh *dm); void GPU_uv_setup(struct DerivedMesh *dm); +void GPU_texpaint_uv_setup(struct DerivedMesh *dm); /* colType is the cddata MCol type to use! */ void GPU_color_setup(struct DerivedMesh *dm, int colType); void GPU_edge_setup(struct DerivedMesh *dm); /* does not mix with other data */ diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h index bdd70a49e7a..3ddec157c49 100644 --- a/source/blender/gpu/GPU_draw.h +++ b/source/blender/gpu/GPU_draw.h @@ -87,7 +87,7 @@ int GPU_get_material_alpha_blend(void); * - passing NULL clears the state again */ int GPU_set_tpage(struct MTFace *tface, int mipmap, int transp); - +void GPU_clear_tpage(bool force); /* Lights * - returns how many lights were enabled * - this affects fixed functions materials and texface, not glsl */ diff --git a/source/blender/gpu/GPU_select.h b/source/blender/gpu/GPU_select.h new file mode 100644 index 00000000000..1a274e0ad9d --- /dev/null +++ b/source/blender/gpu/GPU_select.h @@ -0,0 +1,61 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2014 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Antony Riakiotakis. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file GPU_select.h + * \ingroup gpu + */ + +#ifndef __GPU_SELECT__ +#define __GPU_SELECT__ + +#include "DNA_vec_types.h" /* rcft */ +#include "BLI_sys_types.h" + +/* flags for mode of operation */ +enum { + GPU_SELECT_ALL = 1, + GPU_SELECT_NEAREST_FIRST_PASS = 2, + GPU_SELECT_NEAREST_SECOND_PASS = 3, +}; + +/* initialize and provide buffer for results */ +void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, char mode, int oldhits); + +/* loads a new selection id and ends previous query, if any. In second pass of selection it also returns + * if id has been hit on the first pass already. Thus we can skip drawing un-hit objects IMPORTANT: We rely on the order of object rendering on passes to be + * the same for this to work */ +bool GPU_select_load_id(unsigned int id); + +/* cleanup and flush selection results to buffer. Return number of hits and hits in buffer. + * if dopass is true, we will do a second pass with occlusion queries to get the closest hit */ +unsigned int GPU_select_end(void); + +/* does the GPU support occlusion queries? */ +bool GPU_select_query_check_support(void); + +/* is occlusion query supported and user activated? */ +bool GPU_select_query_check_active(void); + +#endif diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index f5256f18897..91eb2a43132 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -46,11 +46,13 @@ #include "BLI_ghash.h" #include "BLI_threads.h" +#include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "BKE_ccg.h" #include "BKE_DerivedMesh.h" #include "BKE_paint.h" +#include "BKE_material.h" #include "BKE_pbvh.h" #include "DNA_userdef_types.h" @@ -63,13 +65,16 @@ typedef enum { GPU_BUFFER_VERTEX_STATE = 1, GPU_BUFFER_NORMAL_STATE = 2, - GPU_BUFFER_TEXCOORD_STATE = 4, - GPU_BUFFER_COLOR_STATE = 8, - GPU_BUFFER_ELEMENT_STATE = 16, + GPU_BUFFER_TEXCOORD_UNIT_0_STATE = 4, + GPU_BUFFER_TEXCOORD_UNIT_1_STATE = 8, + GPU_BUFFER_COLOR_STATE = 16, + GPU_BUFFER_ELEMENT_STATE = 32, } GPUBufferState; #define MAX_GPU_ATTRIB_DATA 32 +#define BUFFER_OFFSET(n) ((GLubyte *)NULL + (n)) + /* -1 - undefined, 0 - vertex arrays, 1 - VBOs */ static int useVBOs = -1; static GPUBufferState GLStates = 0; @@ -611,7 +616,7 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object, } mat_orig_to_new = MEM_mallocN(sizeof(*mat_orig_to_new) * dm->totmat, - "GPU_buffer_setup.mat_orig_to_new"); + "GPU_buffer_setup.mat_orig_to_new"); cur_index_per_mat = MEM_mallocN(sizeof(int) * object->totmaterial, "GPU_buffer_setup.cur_index_per_mat"); for (i = 0; i < object->totmaterial; i++) { @@ -836,6 +841,61 @@ static void GPU_buffer_copy_uv(DerivedMesh *dm, float *varray, int *index, int * } } + +static void GPU_buffer_copy_uv_texpaint(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user)) +{ + int start; + int i, totface; + + int totmaterial = dm->totmat; + MTFace **mtface_base; + MTFace *stencil_base; + int stencil; + MFace *mf; + + /* should have been checked for before, reassert */ + BLI_assert(DM_get_tessface_data_layer(dm, CD_MTFACE)); + mf = dm->getTessFaceArray(dm); + mtface_base = MEM_mallocN(totmaterial * sizeof(*mtface_base), "texslots"); + + for (i = 0; i < totmaterial; i++) { + mtface_base[i] = DM_paint_uvlayer_active_get(dm, i); + } + + stencil = CustomData_get_stencil_layer(&dm->faceData, CD_MTFACE); + stencil_base = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, stencil); + + totface = dm->getNumTessFaces(dm); + + for (i = 0; i < totface; i++, mf++) { + int mat_i = mf->mat_nr; + start = index[mat_orig_to_new[mat_i]]; + + /* v1 v2 v3 */ + copy_v2_v2(&varray[start], mtface_base[mat_i][i].uv[0]); + copy_v2_v2(&varray[start + 2], stencil_base[i].uv[0]); + copy_v2_v2(&varray[start + 4], mtface_base[mat_i][i].uv[1]); + copy_v2_v2(&varray[start + 6], stencil_base[i].uv[1]); + copy_v2_v2(&varray[start + 8], mtface_base[mat_i][i].uv[2]); + copy_v2_v2(&varray[start + 10], stencil_base[i].uv[2]); + index[mat_orig_to_new[mat_i]] += 12; + + if (mf->v4) { + /* v3 v4 v1 */ + copy_v2_v2(&varray[start + 12], mtface_base[mat_i][i].uv[2]); + copy_v2_v2(&varray[start + 14], stencil_base[i].uv[2]); + copy_v2_v2(&varray[start + 16], mtface_base[mat_i][i].uv[3]); + copy_v2_v2(&varray[start + 18], stencil_base[i].uv[3]); + copy_v2_v2(&varray[start + 20], mtface_base[mat_i][i].uv[0]); + copy_v2_v2(&varray[start + 22], stencil_base[i].uv[0]); + index[mat_orig_to_new[mat_i]] += 12; + } + } + + MEM_freeN(mtface_base); +} + + static void copy_mcol_uc3(unsigned char *v, unsigned char *col) { v[0] = col[3]; @@ -925,6 +985,7 @@ typedef enum { GPU_BUFFER_NORMAL, GPU_BUFFER_COLOR, GPU_BUFFER_UV, + GPU_BUFFER_UV_TEXPAINT, GPU_BUFFER_EDGE, GPU_BUFFER_UVEDGE, } GPUBufferType; @@ -940,6 +1001,7 @@ const GPUBufferTypeSettings gpu_buffer_type_settings[] = { {GPU_buffer_copy_normal, GL_ARRAY_BUFFER_ARB, 3}, {GPU_buffer_copy_mcol, GL_ARRAY_BUFFER_ARB, 3}, {GPU_buffer_copy_uv, GL_ARRAY_BUFFER_ARB, 2}, + {GPU_buffer_copy_uv_texpaint, GL_ARRAY_BUFFER_ARB, 4}, {GPU_buffer_copy_edge, GL_ELEMENT_ARRAY_BUFFER_ARB, 2}, {GPU_buffer_copy_uvedge, GL_ELEMENT_ARRAY_BUFFER_ARB, 4} }; @@ -956,6 +1018,8 @@ static GPUBuffer **gpu_drawobject_buffer_from_type(GPUDrawObject *gdo, GPUBuffer return &gdo->colors; case GPU_BUFFER_UV: return &gdo->uv; + case GPU_BUFFER_UV_TEXPAINT: + return &gdo->uv; case GPU_BUFFER_EDGE: return &gdo->edges; case GPU_BUFFER_UVEDGE: @@ -977,6 +1041,8 @@ static int gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type) return sizeof(char) * 3 * dm->drawObject->tot_triangle_point; case GPU_BUFFER_UV: return sizeof(float) * 2 * dm->drawObject->tot_triangle_point; + case GPU_BUFFER_UV_TEXPAINT: + return sizeof(float) * 4 * dm->drawObject->tot_triangle_point; case GPU_BUFFER_EDGE: return sizeof(int) * 2 * dm->drawObject->totedge; case GPU_BUFFER_UVEDGE: @@ -1005,7 +1071,7 @@ static GPUBuffer *gpu_buffer_setup_type(DerivedMesh *dm, GPUBufferType type) if (!(user_data = DM_get_tessface_data_layer(dm, dm->drawObject->colType))) return NULL; } - else if (type == GPU_BUFFER_UV) { + else if (ELEM(type, GPU_BUFFER_UV, GPU_BUFFER_UV_TEXPAINT)) { if (!DM_get_tessface_data_layer(dm, CD_MTFACE)) return NULL; } @@ -1081,9 +1147,35 @@ void GPU_uv_setup(DerivedMesh *dm) glTexCoordPointer(2, GL_FLOAT, 0, dm->drawObject->uv->pointer); } - GLStates |= GPU_BUFFER_TEXCOORD_STATE; + GLStates |= GPU_BUFFER_TEXCOORD_UNIT_0_STATE; } +void GPU_texpaint_uv_setup(DerivedMesh *dm) +{ + if (!gpu_buffer_setup_common(dm, GPU_BUFFER_UV_TEXPAINT)) + return; + + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + if (useVBOs) { + glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->uv->id); + glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), 0); + glClientActiveTexture(GL_TEXTURE1); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), BUFFER_OFFSET(2 * sizeof(float))); + glClientActiveTexture(GL_TEXTURE0); + } + else { + glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), dm->drawObject->uv->pointer); + glClientActiveTexture(GL_TEXTURE1); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), (char *)dm->drawObject->uv->pointer + 2 * sizeof(float)); + glClientActiveTexture(GL_TEXTURE0); + } + + GLStates |= GPU_BUFFER_TEXCOORD_UNIT_0_STATE | GPU_BUFFER_TEXCOORD_UNIT_1_STATE; +} + + void GPU_color_setup(DerivedMesh *dm, int colType) { if (!dm->drawObject) { @@ -1241,8 +1333,13 @@ void GPU_buffer_unbind(void) glDisableClientState(GL_VERTEX_ARRAY); if (GLStates & GPU_BUFFER_NORMAL_STATE) glDisableClientState(GL_NORMAL_ARRAY); - if (GLStates & GPU_BUFFER_TEXCOORD_STATE) + if (GLStates & GPU_BUFFER_TEXCOORD_UNIT_0_STATE) + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + if (GLStates & GPU_BUFFER_TEXCOORD_UNIT_1_STATE) { + glClientActiveTexture(GL_TEXTURE1); glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTexture(GL_TEXTURE0); + } if (GLStates & GPU_BUFFER_COLOR_STATE) glDisableClientState(GL_COLOR_ARRAY); if (GLStates & GPU_BUFFER_ELEMENT_STATE) { @@ -1251,8 +1348,8 @@ void GPU_buffer_unbind(void) } } GLStates &= ~(GPU_BUFFER_VERTEX_STATE | GPU_BUFFER_NORMAL_STATE | - GPU_BUFFER_TEXCOORD_STATE | GPU_BUFFER_COLOR_STATE | - GPU_BUFFER_ELEMENT_STATE); + GPU_BUFFER_TEXCOORD_UNIT_0_STATE | GPU_BUFFER_TEXCOORD_UNIT_1_STATE | + GPU_BUFFER_COLOR_STATE | GPU_BUFFER_ELEMENT_STATE); for (i = 0; i < MAX_GPU_ATTRIB_DATA; i++) { if (attribData[i].index != -1) { @@ -2577,11 +2674,14 @@ bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, GSet *bm_faces, } else if (buffers->use_bmesh) { /* due to dynamc nature of dyntopo, only get first material */ - GSetIterator gs_iter; - BMFace *f; - BLI_gsetIterator_init(&gs_iter, bm_faces); - f = BLI_gsetIterator_getKey(&gs_iter); - GPU_material_diffuse_get(f->mat_nr + 1, diffuse_color); + if (BLI_gset_size(bm_faces) > 0) { + GSetIterator gs_iter; + BMFace *f; + + BLI_gsetIterator_init(&gs_iter, bm_faces); + f = BLI_gsetIterator_getKey(&gs_iter); + GPU_material_diffuse_get(f->mat_nr + 1, diffuse_color); + } } else { const DMFlagMat *flags = &buffers->grid_flag_mats[buffers->grid_indices[0]]; diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index b3155f0ad50..d60525dd34a 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -97,7 +97,7 @@ static char *gpu_str_skip_token(char *str, char *token, int max) /* skip a variable/function name */ while (*str) { - if (ELEM7(*str, ' ', '(', ')', ',', '\t', '\n', '\r')) + if (ELEM(*str, ' ', '(', ')', ',', '\t', '\n', '\r')) break; else { if (token && len < max-1) { @@ -115,7 +115,7 @@ static char *gpu_str_skip_token(char *str, char *token, int max) /* skip the next special characters: * note the missing ')' */ while (*str) { - if (ELEM6(*str, ' ', '(', ',', '\t', '\n', '\r')) + if (ELEM(*str, ' ', '(', ',', '\t', '\n', '\r')) str++; else break; diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 68b8492926b..fa9bc73dcbe 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -370,9 +370,9 @@ static void gpu_make_repbind(Image *ima) BKE_image_release_ibuf(ima, ibuf, NULL); } -static void gpu_clear_tpage(void) +void GPU_clear_tpage(bool force) { - if (GTS.lasttface==NULL) + if (GTS.lasttface==NULL && !force) return; GTS.lasttface= NULL; @@ -866,7 +866,7 @@ int GPU_set_tpage(MTFace *tface, int mipmap, int alphablend) /* check if we need to clear the state */ if (tface==NULL) { - gpu_clear_tpage(); + GPU_clear_tpage(false); return 0; } @@ -1548,7 +1548,7 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O /* setting 'do_alpha_after = true' indicates this object needs to be * drawn in a second alpha pass for improved blending */ if (do_alpha_after && !GMS.is_alpha_pass) - if (ELEM3(alphablend, GPU_BLEND_ALPHA, GPU_BLEND_ADD, GPU_BLEND_ALPHA_SORT)) + if (ELEM(alphablend, GPU_BLEND_ALPHA, GPU_BLEND_ADD, GPU_BLEND_ALPHA_SORT)) *do_alpha_after = true; GMS.alphablend[a]= alphablend; diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c new file mode 100644 index 00000000000..2df9e603903 --- /dev/null +++ b/source/blender/gpu/intern/gpu_select.c @@ -0,0 +1,246 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2014 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Antony Riakiotakis. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/gpu/intern/gpu_select.c + * \ingroup gpu + * + * Interface for accessing gpu-related methods for selection. The semantics will be + * similar to glRenderMode(GL_SELECT) since the goal is to maintain compatibility. + */ +#include "GPU_select.h" +#include "GPU_extensions.h" + +#include "BLI_utildefines.h" + +#include "MEM_guardedalloc.h" + +#include "DNA_userdef_types.h" + +#include <GL/glew.h> + +/* Ad hoc number of queries to allocate to skip doing many glGenQueries */ +#define ALLOC_QUERIES 200 + +typedef struct GPUQueryState { + /* To ignore selection id calls when not initialized */ + bool select_is_active; + /* Tracks whether a query has been issued so that gpu_load_id can end the previous one */ + bool query_issued; + /* array holding the OpenGL query identifiers */ + unsigned int *queries; + /* array holding the id corresponding to each query */ + unsigned int *id; + /* number of queries in *queries and *id */ + unsigned int num_of_queries; + /* index to the next query to start */ + unsigned int active_query; + /* flag to cache user preference for occlusion based selection */ + bool use_gpu_select; + /* cache on initialization */ + unsigned int *buffer; + unsigned int bufsize; + /* mode of operation */ + char mode; + unsigned int index; + int oldhits; +} GPUQueryState; + +static GPUQueryState g_query_state = {0}; + +void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, char mode, int oldhits) +{ + g_query_state.select_is_active = true; + g_query_state.query_issued = false; + g_query_state.active_query = 0; + g_query_state.use_gpu_select = GPU_select_query_check_active(); + g_query_state.num_of_queries = 0; + g_query_state.bufsize = bufsize; + g_query_state.buffer = buffer; + g_query_state.mode = mode; + g_query_state.index = 0; + g_query_state.oldhits = oldhits; + + if (!g_query_state.use_gpu_select) { + glSelectBuffer( bufsize, (GLuint *)buffer); + glRenderMode(GL_SELECT); + glInitNames(); + glPushName(-1); + } + else { + float viewport[4]; + + g_query_state.num_of_queries = ALLOC_QUERIES; + + g_query_state.queries = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.queries) , "gpu selection queries"); + g_query_state.id = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.id) , "gpu selection ids"); + glGenQueriesARB(g_query_state.num_of_queries, g_query_state.queries); + + glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_VIEWPORT_BIT); + /* disable writing to the framebuffer */ + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + + /* In order to save some fill rate we minimize the viewport using rect. + * We need to get the region of the scissor so that our geometry doesn't + * get rejected before the depth test. Should probably cull rect against + * scissor for viewport but this is a rare case I think */ + glGetFloatv(GL_SCISSOR_BOX, viewport); + if (!input || input->xmin == input->xmax) { + glViewport(viewport[0], viewport[1], 24, 24); + } + else { + glViewport(viewport[0], viewport[1], (int)(input->xmax - input->xmin), (int)(input->ymax - input->ymin)); + } + + /* occlusion queries operates on fragments that pass tests and since we are interested on all + * objects in the view frustum independently of their order, we need to disable the depth test */ + if (mode == GPU_SELECT_ALL) { + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + } + else if (mode == GPU_SELECT_NEAREST_FIRST_PASS) { + glClear(GL_DEPTH_BUFFER_BIT); + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glDepthFunc(GL_LEQUAL); + } + else if (mode == GPU_SELECT_NEAREST_SECOND_PASS) { + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glDepthFunc(GL_EQUAL); + } + } +} + +bool GPU_select_load_id(unsigned int id) +{ + /* if no selection mode active, ignore */ + if(!g_query_state.select_is_active) + return true; + + if (!g_query_state.use_gpu_select) { + glLoadName(id); + } + else { + if (g_query_state.query_issued) { + glEndQueryARB(GL_SAMPLES_PASSED_ARB); + } + /* if required, allocate extra queries */ + if (g_query_state.active_query == g_query_state.num_of_queries) { + g_query_state.num_of_queries += ALLOC_QUERIES; + g_query_state.queries = MEM_reallocN(g_query_state.queries, g_query_state.num_of_queries * sizeof(*g_query_state.queries)); + g_query_state.id = MEM_reallocN(g_query_state.id, g_query_state.num_of_queries * sizeof(*g_query_state.id)); + glGenQueriesARB(ALLOC_QUERIES, &g_query_state.queries[g_query_state.active_query]); + } + + glBeginQueryARB(GL_SAMPLES_PASSED_ARB, g_query_state.queries[g_query_state.active_query]); + g_query_state.id[g_query_state.active_query] = id; + g_query_state.active_query++; + g_query_state.query_issued = true; + + if (g_query_state.mode == GPU_SELECT_NEAREST_SECOND_PASS) { + if (g_query_state.buffer[g_query_state.index * 4 + 3] == id) { + g_query_state.index++; + return true; + } + else { + return false; + } + } + } + + return true; +} + +unsigned int GPU_select_end(void) +{ + unsigned int hits = 0; + if (!g_query_state.use_gpu_select) { + glPopName(); + hits = glRenderMode(GL_RENDER); + } + else { + int i; + + if (g_query_state.query_issued) { + glEndQueryARB(GL_SAMPLES_PASSED_ARB); + } + + for (i = 0; i < g_query_state.active_query; i++) { + unsigned int result; + glGetQueryObjectuivARB(g_query_state.queries[i], GL_QUERY_RESULT_ARB, &result); + if (result > 0) { + if (g_query_state.mode != GPU_SELECT_NEAREST_SECOND_PASS) { + if(hits < g_query_state.bufsize) { + g_query_state.buffer[hits * 4] = 1; + g_query_state.buffer[hits * 4 + 1] = 0xFFFF; + g_query_state.buffer[hits * 4 + 2] = 0xFFFF; + g_query_state.buffer[hits * 4 + 3] = g_query_state.id[i]; + + hits++; + } + else { + hits = -1; + break; + } + } + else { + int j; + /* search in buffer and make selected object first */ + for (j = 0; j < g_query_state.oldhits; j++) { + if (g_query_state.buffer[j * 4 + 3] == g_query_state.id[i]) { + g_query_state.buffer[j * 4 + 1] = 0; + g_query_state.buffer[j * 4 + 2] = 0; + } + } + break; + } + } + } + + glDeleteQueriesARB(g_query_state.num_of_queries, g_query_state.queries); + MEM_freeN(g_query_state.queries); + MEM_freeN(g_query_state.id); + glPopAttrib(); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + } + + g_query_state.select_is_active = false; + + return hits; +} + + +bool GPU_select_query_check_support(void) +{ + return GLEW_ARB_occlusion_query; +} + + +bool GPU_select_query_check_active(void) +{ + return GLEW_ARB_occlusion_query && + ((U.gpu_select_method == USER_SELECT_USE_OCCLUSION_QUERY) || + ((U.gpu_select_method == USER_SELECT_AUTO) && GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY))); +} diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index d5d0c7ef454..fb364018282 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -2257,6 +2257,11 @@ void node_attribute(vec3 attr_uv, out vec4 outcol, out vec3 outvec, out float ou outf = (attr_uv.x + attr_uv.y + attr_uv.z)/3.0; } +void node_uvmap(vec3 attr_uv, out vec3 outvec) +{ + outvec = attr_uv; +} + void node_geometry(vec3 I, vec3 N, mat4 toworld, out vec3 position, out vec3 normal, out vec3 tangent, out vec3 true_normal, out vec3 incoming, out vec3 parametric, diff --git a/source/blender/ikplugin/intern/iksolver_plugin.c b/source/blender/ikplugin/intern/iksolver_plugin.c index 80c508267f3..cd09b56b262 100644 --- a/source/blender/ikplugin/intern/iksolver_plugin.c +++ b/source/blender/ikplugin/intern/iksolver_plugin.c @@ -215,7 +215,7 @@ static void where_is_ik_bone(bPoseChannel *pchan, float ik_mat[3][3]) // nr = copy_m4_m3(ikmat, ik_mat); if (pchan->parent) - mul_serie_m4(pchan->pose_mat, pchan->parent->pose_mat, pchan->chan_mat, ikmat, NULL, NULL, NULL, NULL, NULL); + mul_m4_series(pchan->pose_mat, pchan->parent->pose_mat, pchan->chan_mat, ikmat); else mul_m4_m4m4(pchan->pose_mat, pchan->chan_mat, ikmat); @@ -420,7 +420,7 @@ static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree) /* end effector in world space */ copy_m4_m4(end_pose, pchan->pose_mat); copy_v3_v3(end_pose[3], pchan->pose_tail); - mul_serie_m4(world_pose, goalinv, ob->obmat, end_pose, NULL, NULL, NULL, NULL, NULL); + mul_m4_series(world_pose, goalinv, ob->obmat, end_pose); /* blend position */ goalpos[0] = fac * goalpos[0] + mfac * world_pose[3][0]; diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp index dbc4100e287..5077ccec256 100644 --- a/source/blender/ikplugin/intern/itasc_plugin.cpp +++ b/source/blender/ikplugin/intern/itasc_plugin.cpp @@ -566,7 +566,7 @@ static bool target_callback(const iTaSC::Timestamp& timestamp, const iTaSC::Fram float chanmat[4][4]; copy_m4_m4(chanmat, pchan->pose_mat); copy_v3_v3(chanmat[3], pchan->pose_tail); - mul_serie_m4(restmat, target->owner->obmat, chanmat, target->eeRest, NULL, NULL, NULL, NULL, NULL); + mul_m4_series(restmat, target->owner->obmat, chanmat, target->eeRest); } else { mul_m4_m4m4(restmat, target->owner->obmat, target->eeRest); diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 090e7a66d41..ce6a7eb1c47 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -163,6 +163,22 @@ typedef enum IMB_BlendMode { IMB_BLEND_DARKEN = 5, IMB_BLEND_ERASE_ALPHA = 6, IMB_BLEND_ADD_ALPHA = 7, + IMB_BLEND_OVERLAY = 8, + IMB_BLEND_HARDLIGHT = 9, + IMB_BLEND_COLORBURN = 10, + IMB_BLEND_LINEARBURN = 11, + IMB_BLEND_COLORDODGE = 12, + IMB_BLEND_SCREEN = 13, + IMB_BLEND_SOFTLIGHT = 14, + IMB_BLEND_PINLIGHT = 15, + IMB_BLEND_VIVIDLIGHT = 16, + IMB_BLEND_LINEARLIGHT = 17, + IMB_BLEND_DIFFERENCE = 18, + IMB_BLEND_EXCLUSION = 19, + IMB_BLEND_HUE = 20, + IMB_BLEND_SATURATION = 21, + IMB_BLEND_LUMINOSITY = 22, + IMB_BLEND_COLOR = 23, IMB_BLEND_COPY = 1000, IMB_BLEND_COPY_RGB = 1001, @@ -179,9 +195,9 @@ void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx, void IMB_rectcpy(struct ImBuf *drect, struct ImBuf *srect, int destx, int desty, int srcx, int srcy, int width, int height); void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *obuf, struct ImBuf *sbuf, - unsigned short *dmask, unsigned short *smask, unsigned short mask_max, + unsigned short *dmask, unsigned short *curvemask, unsigned short *mmask, float mask_max, int destx, int desty, int origx, int origy, int srcx, int srcy, - int width, int height, IMB_BlendMode mode); + int width, int height, IMB_BlendMode mode, bool accumulate); /** * diff --git a/source/blender/imbuf/intern/cineon/cineonlib.c b/source/blender/imbuf/intern/cineon/cineonlib.c index e8cb550fc05..880df0ce5c3 100644 --- a/source/blender/imbuf/intern/cineon/cineonlib.c +++ b/source/blender/imbuf/intern/cineon/cineonlib.c @@ -39,10 +39,6 @@ #include "BLI_fileops.h" #include "BLI_utildefines.h" -#if defined(_MSC_VER) && (_MSC_VER <= 1500) -#include "BLI_math_base.h" -#endif - #include "MEM_guardedalloc.h" /* diff --git a/source/blender/imbuf/intern/cineon/dpxlib.c b/source/blender/imbuf/intern/cineon/dpxlib.c index 84f80faeacc..626d05b05c5 100644 --- a/source/blender/imbuf/intern/cineon/dpxlib.c +++ b/source/blender/imbuf/intern/cineon/dpxlib.c @@ -39,10 +39,6 @@ #include "BLI_fileops.h" #include "BLI_utildefines.h" -#if defined(_MSC_VER) && (_MSC_VER <= 1500) -#include "BLI_math_base.h" -#endif - #include "MEM_guardedalloc.h" /* diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index 2dca3114765..b8b7d15bf28 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -896,7 +896,7 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa echan->chan_id = name[0]; layname[0] = '\0'; - if (ELEM4(name[0], 'R', 'G', 'B', 'A')) + if (ELEM(name[0], 'R', 'G', 'B', 'A')) strcpy(passname, "Combined"); else if (name[0] == 'Z') strcpy(passname, "Depth"); @@ -927,9 +927,9 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa * * Here we do some magic to distinguish such cases. */ - if (ELEM3(token[1], 'X', 'Y', 'Z') || - ELEM3(token[1], 'R', 'G', 'B') || - ELEM3(token[1], 'U', 'V', 'A')) + if (ELEM(token[1], 'X', 'Y', 'Z') || + ELEM(token[1], 'R', 'G', 'B') || + ELEM(token[1], 'U', 'V', 'A')) { echan->chan_id = token[1]; ok = true; diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c index 6df7587ee5c..dd2406e234e 100644 --- a/source/blender/imbuf/intern/rectop.c +++ b/source/blender/imbuf/intern/rectop.c @@ -65,6 +65,39 @@ void IMB_blend_color_byte(unsigned char dst[4], unsigned char src1[4], unsigned blend_color_erase_alpha_byte(dst, src1, src2); break; case IMB_BLEND_ADD_ALPHA: blend_color_add_alpha_byte(dst, src1, src2); break; + case IMB_BLEND_OVERLAY: + blend_color_overlay_byte(dst, src1, src2); break; + case IMB_BLEND_HARDLIGHT: + blend_color_hardlight_byte(dst, src1, src2); break; + case IMB_BLEND_COLORBURN: + blend_color_burn_byte(dst, src1, src2); break; + case IMB_BLEND_LINEARBURN: + blend_color_linearburn_byte(dst, src1, src2); break; + case IMB_BLEND_COLORDODGE: + blend_color_dodge_byte(dst, src1, src2); break; + case IMB_BLEND_SCREEN: + blend_color_screen_byte(dst, src1, src2); break; + case IMB_BLEND_SOFTLIGHT: + blend_color_softlight_byte(dst, src1, src2); break; + case IMB_BLEND_PINLIGHT: + blend_color_pinlight_byte(dst, src1, src2); break; + case IMB_BLEND_LINEARLIGHT: + blend_color_linearlight_byte(dst, src1, src2); break; + case IMB_BLEND_VIVIDLIGHT: + blend_color_vividlight_byte(dst, src1, src2); break; + case IMB_BLEND_DIFFERENCE: + blend_color_difference_byte(dst, src1, src2); break; + case IMB_BLEND_EXCLUSION: + blend_color_exclusion_byte(dst, src1, src2); break; + case IMB_BLEND_COLOR: + blend_color_color_byte(dst, src1, src2); break; + case IMB_BLEND_HUE: + blend_color_hue_byte(dst, src1, src2); break; + case IMB_BLEND_SATURATION: + blend_color_saturation_byte(dst, src1, src2); break; + case IMB_BLEND_LUMINOSITY: + blend_color_luminosity_byte(dst, src1, src2); break; + default: dst[0] = src1[0]; dst[1] = src1[1]; @@ -93,6 +126,38 @@ void IMB_blend_color_float(float dst[4], float src1[4], float src2[4], IMB_Blend blend_color_erase_alpha_float(dst, src1, src2); break; case IMB_BLEND_ADD_ALPHA: blend_color_add_alpha_float(dst, src1, src2); break; + case IMB_BLEND_OVERLAY: + blend_color_overlay_float(dst, src1, src2); break; + case IMB_BLEND_HARDLIGHT: + blend_color_hardlight_float(dst, src1, src2); break; + case IMB_BLEND_COLORBURN: + blend_color_burn_float(dst, src1, src2); break; + case IMB_BLEND_LINEARBURN: + blend_color_linearburn_float(dst, src1, src2); break; + case IMB_BLEND_COLORDODGE: + blend_color_dodge_float(dst, src1, src2); break; + case IMB_BLEND_SCREEN: + blend_color_screen_float(dst, src1, src2); break; + case IMB_BLEND_SOFTLIGHT: + blend_color_softlight_float(dst, src1, src2); break; + case IMB_BLEND_PINLIGHT: + blend_color_pinlight_float(dst, src1, src2); break; + case IMB_BLEND_LINEARLIGHT: + blend_color_linearlight_float(dst, src1, src2); break; + case IMB_BLEND_VIVIDLIGHT: + blend_color_vividlight_float(dst, src1, src2); break; + case IMB_BLEND_DIFFERENCE: + blend_color_difference_float(dst, src1, src2); break; + case IMB_BLEND_EXCLUSION: + blend_color_exclusion_float(dst, src1, src2); break; + case IMB_BLEND_COLOR: + blend_color_color_float(dst, src1, src2); break; + case IMB_BLEND_HUE: + blend_color_hue_float(dst, src1, src2); break; + case IMB_BLEND_SATURATION: + blend_color_saturation_float(dst, src1, src2); break; + case IMB_BLEND_LUMINOSITY: + blend_color_luminosity_float(dst, src1, src2); break; default: dst[0] = src1[0]; dst[1] = src1[1]; @@ -226,22 +291,23 @@ static void imb_rectclip3(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, int *destx, void IMB_rectcpy(ImBuf *dbuf, ImBuf *sbuf, int destx, int desty, int srcx, int srcy, int width, int height) { - IMB_rectblend(dbuf, dbuf, sbuf, NULL, NULL, 0, destx, desty, destx, desty, srcx, srcy, width, height, IMB_BLEND_COPY); + IMB_rectblend(dbuf, dbuf, sbuf, NULL, NULL, NULL, 0, destx, desty, destx, desty, srcx, srcy, width, height, IMB_BLEND_COPY, false); } typedef void (*IMB_blend_func)(unsigned char *dst, const unsigned char *src1, const unsigned char *src2); typedef void (*IMB_blend_func_float)(float *dst, const float *src1, const float *src2); -void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, - unsigned short *smask, unsigned short mask_max, +void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, unsigned short *curvemask, + unsigned short *texmask, float mask_max, int destx, int desty, int origx, int origy, int srcx, int srcy, int width, int height, - IMB_BlendMode mode) + IMB_BlendMode mode, bool accumulate) { unsigned int *drect = NULL, *orect, *srect = NULL, *dr, *or, *sr; float *drectf = NULL, *orectf, *srectf = NULL, *drf, *orf, *srf; - unsigned short *smaskrect = smask, *smr; + unsigned short *cmaskrect = curvemask, *cmr; unsigned short *dmaskrect = dmask, *dmr; + unsigned short *texmaskrect = texmask, *tmr; int do_float, do_char, srcskip, destskip, origskip, x; IMB_blend_func func = NULL; IMB_blend_func_float func_float = NULL; @@ -277,8 +343,11 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, if (do_float) srectf = sbuf->rect_float + (srcy * sbuf->x + srcx) * 4; srcskip = sbuf->x; - if (smaskrect) - smaskrect += srcy * sbuf->x + srcx; + if (cmaskrect) + cmaskrect += srcy * sbuf->x + srcx; + + if (texmaskrect) + texmaskrect += srcy * sbuf->x + srcx; } else { srect = drect; @@ -388,6 +457,70 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, func = blend_color_add_alpha_byte; func_float = blend_color_add_alpha_float; break; + case IMB_BLEND_OVERLAY: + func = blend_color_overlay_byte; + func_float = blend_color_overlay_float; + break; + case IMB_BLEND_HARDLIGHT: + func = blend_color_hardlight_byte; + func_float = blend_color_hardlight_float; + break; + case IMB_BLEND_COLORBURN: + func = blend_color_burn_byte; + func_float = blend_color_burn_float; + break; + case IMB_BLEND_LINEARBURN: + func = blend_color_linearburn_byte; + func_float = blend_color_linearburn_float; + break; + case IMB_BLEND_COLORDODGE: + func = blend_color_dodge_byte; + func_float = blend_color_dodge_float; + break; + case IMB_BLEND_SCREEN: + func = blend_color_screen_byte; + func_float = blend_color_screen_float; + break; + case IMB_BLEND_SOFTLIGHT: + func = blend_color_softlight_byte; + func_float = blend_color_softlight_float; + break; + case IMB_BLEND_PINLIGHT: + func = blend_color_pinlight_byte; + func_float = blend_color_pinlight_float; + break; + case IMB_BLEND_LINEARLIGHT: + func = blend_color_linearlight_byte; + func_float = blend_color_linearlight_float; + break; + case IMB_BLEND_VIVIDLIGHT: + func = blend_color_vividlight_byte; + func_float = blend_color_vividlight_float; + break; + case IMB_BLEND_DIFFERENCE: + func = blend_color_difference_byte; + func_float = blend_color_difference_float; + break; + case IMB_BLEND_EXCLUSION: + func = blend_color_exclusion_byte; + func_float = blend_color_exclusion_float; + break; + case IMB_BLEND_COLOR: + func = blend_color_color_byte; + func_float = blend_color_color_float; + break; + case IMB_BLEND_HUE: + func = blend_color_hue_byte; + func_float = blend_color_hue_float; + break; + case IMB_BLEND_SATURATION: + func = blend_color_saturation_byte; + func_float = blend_color_saturation_float; + break; + case IMB_BLEND_LUMINOSITY: + func = blend_color_luminosity_byte; + func_float = blend_color_luminosity_float; + break; default: break; } @@ -399,21 +532,60 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, or = orect; sr = srect; - if (dmaskrect && smaskrect) { + if (cmaskrect) { /* mask accumulation for painting */ - dmr = dmaskrect; - smr = smaskrect; + cmr = cmaskrect; + tmr = texmaskrect; - for (x = width; x > 0; x--, dr++, or++, sr++, dmr++, smr++) { - unsigned char *src = (unsigned char *)sr; + /* destination mask present, do max alpha masking */ + if (dmaskrect) { + dmr = dmaskrect; + for (x = width; x > 0; x--, dr++, or++, sr++, dmr++, cmr++) { + unsigned char *src = (unsigned char *)sr; + float mask_lim = mask_max * (*cmr); - if (src[3] && *smr) { - unsigned short mask = *dmr + (((mask_max - *dmr) * (*smr)) / 65535); + if (texmaskrect) + mask_lim *= ((*tmr++) / 65535.0f); - if (mask > *dmr) { - unsigned char mask_src[4]; + if (src[3] && mask_lim) { + float mask; + + if (accumulate) + mask = *dmr + mask_lim; + else + mask = *dmr + mask_lim - (*dmr * (*cmr / 65535.0f)); + + mask = min_ff(mask, 65535.0); + + if (mask > *dmr) { + unsigned char mask_src[4]; + + *dmr = mask; - *dmr = mask; + mask_src[0] = src[0]; + mask_src[1] = src[1]; + mask_src[2] = src[2]; + mask_src[3] = divide_round_i(src[3] * mask, 65535); + + func((unsigned char *)dr, (unsigned char *)or, mask_src); + } + } + } + dmaskrect += origskip; + } + /* no destination mask buffer, do regular blend with masktexture if present */ + else { + for (x = width; x > 0; x--, dr++, or++, sr++, cmr++) { + unsigned char *src = (unsigned char *)sr; + float mask = (float)mask_max * ((float)(*cmr)); + + if (texmaskrect) + mask *= ((float)(*tmr++) / 65535.0f); + + mask = min_ff(mask, 65535.0); + + if (src[3] && (mask > 0.0f)) { + unsigned char mask_src[4]; mask_src[0] = src[0]; mask_src[1] = src[1]; @@ -425,8 +597,9 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, } } - dmaskrect += origskip; - smaskrect += srcskip; + cmaskrect += srcskip; + if (texmaskrect) + texmaskrect += srcskip; } else { /* regular blending */ @@ -446,28 +619,65 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, orf = orectf; srf = srectf; - if (dmaskrect && smaskrect) { + if (cmaskrect) { /* mask accumulation for painting */ - dmr = dmaskrect; - smr = smaskrect; + cmr = cmaskrect; + tmr = texmaskrect; + + /* destination mask present, do max alpha masking */ + if (dmaskrect) { + dmr = dmaskrect; + for (x = width; x > 0; x--, drf += 4, orf += 4, srf += 4, dmr++, cmr++) { + float mask_lim = mask_max * (*cmr); + + if (texmaskrect) + mask_lim *= ((*tmr++) / 65535.0f); + + if (srf[3] && mask_lim) { + float mask; + + if (accumulate) + mask = min_ff(*dmr + mask_lim, 65535.0); + else + mask = *dmr + mask_lim - (*dmr * (*cmr / 65535.0f)); + + mask = min_ff(mask, 65535.0); + + if (mask > *dmr) { + float mask_srf[4]; + + *dmr = mask; + mul_v4_v4fl(mask_srf, srf, mask / 65535.0f); + + func_float(drf, orf, mask_srf); + } + } + } + dmaskrect += origskip; + } + /* no destination mask buffer, do regular blend with masktexture if present */ + else { + for (x = width; x > 0; x--, drf += 4, orf += 4, srf += 4, cmr++) { + float mask = (float)mask_max * ((float)(*cmr)); + + if (texmaskrect) + mask *= ((float)(*tmr++) / 65535.0f); - for (x = width; x > 0; x--, drf += 4, orf += 4, srf += 4, dmr++, smr++) { - if (srf[3] != 0 && *smr) { - unsigned short mask = *dmr + (((mask_max - *dmr) * (*smr)) / 65535); + mask = min_ff(mask, 65535.0); - if (mask > *dmr) { + if (srf[3] && (mask > 0.0f)) { float mask_srf[4]; - *dmr = mask; - mul_v4_v4fl(mask_srf, srf, mask * (1.0f / 65535.0f)); + mul_v4_v4fl(mask_srf, srf, mask / 65535.0f); func_float(drf, orf, mask_srf); } } } - dmaskrect += origskip; - smaskrect += srcskip; + cmaskrect += srcskip; + if (texmaskrect) + texmaskrect += srcskip; } else { /* regular blending */ diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c index c98b39c826b..e066443769d 100644 --- a/source/blender/imbuf/intern/scaling.c +++ b/source/blender/imbuf/intern/scaling.c @@ -1353,7 +1353,7 @@ static ImBuf *scaleupy(struct ImBuf *ibuf, int newy) val_g += 0.5f; val_r = rect[3]; - nval_r = rect[skipx + 4]; + nval_r = rect[skipx + 3]; diff_r = nval_r - val_r; val_r += 0.5f; diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c index b912c3e229a..32100aa2288 100644 --- a/source/blender/imbuf/intern/util.c +++ b/source/blender/imbuf/intern/util.c @@ -254,10 +254,6 @@ static int isqtime(const char *name) #ifdef WITH_FFMPEG -#if defined(_MSC_VER) && _MSC_VER < 1800 -#define va_copy(dst, src) ((dst) = (src)) -#endif - /* BLI_vsnprintf in ffmpeg_log_callback() causes invalid warning */ #ifdef __GNUC__ # pragma GCC diagnostic push diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index f429360e1cf..8483e5f08f9 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -168,14 +168,10 @@ typedef struct PreviewImage { #ifdef __BIG_ENDIAN__ /* big endian */ -# define MAKE_ID2(c, d) ( (c)<<8 | (d) ) -# define MOST_SIG_BYTE 0 -# define BBIG_ENDIAN +# define MAKE_ID2(c, d) ((c) << 8 | (d)) #else /* little endian */ -# define MAKE_ID2(c, d) ( (d)<<8 | (c) ) -# define MOST_SIG_BYTE 1 -# define BLITTLE_ENDIAN +# define MAKE_ID2(c, d) ((d) << 8 | (c)) #endif /* ID from database */ @@ -213,6 +209,8 @@ typedef struct PreviewImage { #define ID_MC MAKE_ID2('M', 'C') /* MovieClip */ #define ID_MSK MAKE_ID2('M', 'S') /* Mask */ #define ID_LS MAKE_ID2('L', 'S') /* FreestyleLineStyle */ +#define ID_PAL MAKE_ID2('P', 'L') /* Palette */ +#define ID_PC MAKE_ID2('P', 'C') /* Paint Curve */ /* NOTE! Fake IDs, needed for g.sipo->blocktype or outliner */ #define ID_SEQ MAKE_ID2('S', 'Q') @@ -235,7 +233,7 @@ typedef struct PreviewImage { # undef GS #endif // #define GS(a) (*((short *)(a))) -#define GS(a) (CHECK_TYPE_INLINE(a, const char *), (*((short *)(a)))) +#define GS(a) (CHECK_TYPE_INLINE(a, char *), (*((short *)(a)))) #define ID_NEW(a) if ( (a) && (a)->id.newid ) (a) = (void *)(a)->id.newid #define ID_NEW_US(a) if ( (a)->id.newid) { (a) = (void *)(a)->id.newid; (a)->id.us++; } diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index 86fa7058f97..9fbd70419f4 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -35,6 +35,7 @@ #include "DNA_ID.h" #include "DNA_texture_types.h" /* for MTex */ +#include "DNA_curve_types.h" //#ifndef MAX_MTEX // XXX Not used? //#define MAX_MTEX 18 @@ -62,6 +63,9 @@ typedef struct Brush { struct ImBuf *icon_imbuf; PreviewImage *preview; + struct ColorBand *gradient; /* color gradient */ + struct PaintCurve *paint_curve; + char icon_filepath[1024]; /* 1024 = FILE_MAX */ float normal_weight; @@ -71,6 +75,7 @@ typedef struct Brush { float weight; /* brush weight */ int size; /* brush diameter */ int flag; /* general purpose flag */ + int mask_pressure; /* pressure influence for mask */ float jitter; /* jitter the position of the brush */ int jitter_absolute; /* absolute jitter in pixels */ int overlay_flags; @@ -82,10 +87,17 @@ typedef struct Brush { float rgb[3]; /* color */ float alpha; /* opacity */ + float secondary_rgb[3]; /* background color */ + int sculpt_plane; /* the direction of movement for sculpt vertices */ float plane_offset; /* offset for plane brushes (clay, flatten, fill, scrape) */ + float pad; + int gradient_spacing; + int gradient_stroke_mode; /* source for stroke color gradient application */ + int gradient_fill_mode; /* source for fill tool color gradient application */ + char sculpt_tool; /* active sculpt tool */ char vertexpaint_tool; /* active vertex/weight paint blend mode (poorly named) */ char imagepaint_tool; /* active image paint tool */ @@ -100,12 +112,21 @@ typedef struct Brush { float texture_sample_bias; + /* overlay */ int texture_overlay_alpha; int mask_overlay_alpha; int cursor_overlay_alpha; float unprojected_radius; + /* soften/sharpen */ + float sharp_threshold; + int blur_kernel_radius; + int blur_mode; + + /* fill tool */ + float fill_threshold; + float add_col[3]; float sub_col[3]; @@ -116,6 +137,52 @@ typedef struct Brush { float mask_stencil_dimension[2]; } Brush; +typedef struct PaletteColor +{ + struct PaletteColor *next, *prev; + /* two values, one to store rgb, other to store values for sculpt/weight */ + float rgb[3]; + float value; +} PaletteColor; + +typedef struct Palette +{ + ID id; + + /* pointer to individual colours */ + ListBase colors; + ListBase deleted; + + int num_of_colours; + int active_color; +} Palette; + +typedef struct PaintCurvePoint +{ + BezTriple bez; /* bezier handle */ + float pressure; /* pressure on that point */ +} PaintCurvePoint; + +typedef struct PaintCurve +{ + ID id; + PaintCurvePoint *points; /* points of curve */ + int tot_points; + int add_index; /* index where next point will be added */ +} PaintCurve; + +/* Brush.gradient_source */ +typedef enum BrushGradientSourceStroke { + BRUSH_GRADIENT_PRESSURE = 0, /* gradient from pressure */ + BRUSH_GRADIENT_SPACING_REPEAT = 1, /* gradient from spacing */ + BRUSH_GRADIENT_SPACING_CLAMP = 2 /* gradient from spacing */ +} BrushGradientSourceStroke; + +typedef enum BrushGradientSourceFill { + BRUSH_GRADIENT_LINEAR = 0, /* gradient from pressure */ + BRUSH_GRADIENT_RADIAL = 1 /* gradient from spacing */ +} BrushGradientSourceFill; + /* Brush.flag */ typedef enum BrushFlags { BRUSH_AIRBRUSH = (1 << 0), @@ -124,7 +191,7 @@ typedef enum BrushFlags { BRUSH_SIZE_PRESSURE = (1 << 3), BRUSH_JITTER_PRESSURE = (1 << 4), BRUSH_SPACING_PRESSURE = (1 << 5), - // BRUSH_FIXED_TEX = (1 << 6), /* obsolete, use mtex->brush_map_mode = MTEX_MAP_MODE_TILED instead */ + BRUSH_UNUSED = (1 << 6), BRUSH_RAKE = (1 << 7), BRUSH_ANCHORED = (1 << 8), BRUSH_DIR_IN = (1 << 9), @@ -138,7 +205,7 @@ typedef enum BrushFlags { BRUSH_SPACE_ATTEN = (1 << 18), BRUSH_ADAPTIVE_SPACE = (1 << 19), BRUSH_LOCK_SIZE = (1 << 20), -// BRUSH_TEXTURE_OVERLAY = (1 << 21), /* obsolete, use overlay_flags |= BRUSH_OVERLAY_PRIMARY instead */ + BRUSH_USE_GRADIENT = (1 << 21), BRUSH_EDGE_TO_EDGE = (1 << 22), BRUSH_DRAG_DOT = (1 << 23), BRUSH_INVERSE_SMOOTH_PRESSURE = (1 << 24), @@ -146,13 +213,16 @@ typedef enum BrushFlags { BRUSH_PLANE_TRIM = (1 << 26), BRUSH_FRONTFACE = (1 << 27), BRUSH_CUSTOM_ICON = (1 << 28), - - /* temporary flag which sets up automatically for correct brush - * drawing when inverted modal operator is running */ - BRUSH_INVERTED = (1 << 29), - BRUSH_ABSOLUTE_JITTER = (1 << 30) + BRUSH_LINE = (1 << 29), + BRUSH_ABSOLUTE_JITTER = (1 << 30), + BRUSH_CURVE = (1 << 31) } BrushFlags; +typedef enum { + BRUSH_MASK_PRESSURE_RAMP = (1 << 1), + BRUSH_MASK_PRESSURE_CUTOFF = (1 << 2) +} BrushMaskPressureFlags; + /* Brush.overlay_flags */ typedef enum OverlayFlags { BRUSH_OVERLAY_CURSOR = (1), @@ -195,7 +265,9 @@ typedef enum BrushImagePaintTool { PAINT_TOOL_DRAW = 0, PAINT_TOOL_SOFTEN = 1, PAINT_TOOL_SMEAR = 2, - PAINT_TOOL_CLONE = 3 + PAINT_TOOL_CLONE = 3, + PAINT_TOOL_FILL = 4, + PAINT_TOOL_MASK = 5 } BrushImagePaintTool; /* direction that the brush displaces along */ @@ -222,6 +294,12 @@ typedef enum { BRUSH_MASK_SMOOTH = 1 } BrushMaskTool; +/* blur kernel types, Brush.blur_mode */ +typedef enum BlurKernelType { + KERNEL_GAUSSIAN, + KERNEL_BOX +} BlurKernelType; + #define MAX_BRUSH_PIXEL_RADIUS 200 #endif diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index e35e4673684..0277956cac5 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -796,7 +796,8 @@ typedef enum ePivotConstraint_Flag { typedef enum eFollowTrack_Flags { FOLLOWTRACK_ACTIVECLIP = (1<<0), - FOLLOWTRACK_USE_3D_POSITION = (1<<1) + FOLLOWTRACK_USE_3D_POSITION = (1<<1), + FOLLOWTRACK_USE_UNDISTORTION = (1<<2) } eFollowTrack_Flags; typedef enum eFollowTrack_FrameMethod { diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index 5fda38f52a1..ba617baa4e0 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -41,6 +41,7 @@ #endif struct MTex; +struct Image; struct ColorBand; struct Group; struct bNodeTree; @@ -82,6 +83,11 @@ typedef struct GameSettings { int pad1; } GameSettings; +typedef struct TexPaintSlot { + struct Image *ima; /* image to be painted on */ + char *uvname; /* customdata index for uv layer, MAX_NAME*/ +} TexPaintSlot; + typedef struct Material { ID id; struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */ @@ -182,8 +188,15 @@ typedef struct Material { float line_col[4]; short line_priority; short vcol_alpha; - int pad4; + /* texture painting */ + short paint_active_slot; + short paint_clone_slot; + short tot_slots; + short pad4[3]; + + struct TexPaintSlot *texpaintslot; /* cached slot for painting. Make sure to recalculate before use + * with refresh_texpaint_image_cache */ ListBase gpumaterial; /* runtime */ } Material; diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index b13353609c6..e0d25e763d4 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -852,6 +852,12 @@ typedef struct NodeShaderUVMap { char uv_map[64]; } NodeShaderUVMap; +typedef struct NodeSunBeams { + float source[2]; + + float ray_length; +} NodeSunBeams; + /* script node mode */ #define NODE_SCRIPT_INTERNAL 0 #define NODE_SCRIPT_EXTERNAL 1 diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 2e3cd878900..e576cbc018f 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -361,13 +361,13 @@ enum { #define OB_TYPE_SUPPORT_VGROUP(_type) \ (ELEM(_type, OB_MESH, OB_LATTICE)) #define OB_TYPE_SUPPORT_EDITMODE(_type) \ - (ELEM7(_type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL, OB_LATTICE, OB_ARMATURE)) + (ELEM(_type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL, OB_LATTICE, OB_ARMATURE)) #define OB_TYPE_SUPPORT_PARVERT(_type) \ - (ELEM4(_type, OB_MESH, OB_SURF, OB_CURVE, OB_LATTICE)) + (ELEM(_type, OB_MESH, OB_SURF, OB_CURVE, OB_LATTICE)) /* is this ID type used as object data */ #define OB_DATA_SUPPORT_ID(_id_type) \ - (ELEM8(_id_type, ID_ME, ID_CU, ID_MB, ID_LA, ID_SPK, ID_CA, ID_LT, ID_AR)) + (ELEM(_id_type, ID_ME, ID_CU, ID_MB, ID_LA, ID_SPK, ID_CA, ID_LT, ID_AR)) #define OB_DATA_SUPPORT_ID_CASE \ ID_ME: case ID_CU: case ID_MB: case ID_LA: case ID_SPK: case ID_CA: case ID_LT: case ID_AR diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 5f2aefdb53f..8a7ddb88f59 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -811,7 +811,8 @@ typedef struct TimeMarker { /* Paint Tool Base */ typedef struct Paint { struct Brush *brush; - + struct Palette *palette; + /* WM Paint cursor */ void *paint_cursor; unsigned char paint_cursor_col[4]; @@ -843,6 +844,9 @@ typedef struct ImagePaintSettings { int pad1; void *paintcursor; /* wm handle */ + struct Image *stencil; /* workaround until we support true layer masks */ + float stencil_col[3]; + float pad2; } ImagePaintSettings; /* ------------------------------------------- */ @@ -966,6 +970,11 @@ typedef struct UnifiedPaintSettings { /* unified brush weight, [0, 1] */ float weight; + /* unified brush color */ + float rgb[3]; + /* unified brush secondary color */ + float secondary_rgb[3]; + /* user preferences for sculpt and paint */ int flag; @@ -973,7 +982,6 @@ typedef struct UnifiedPaintSettings { /* record movement of mouse so that rake can start at an intuitive angle */ float last_rake[2]; - int pad; float brush_rotation; @@ -981,7 +989,14 @@ typedef struct UnifiedPaintSettings { * all data below are used to communicate with cursor drawing and tex sampling * *********************************************************************************/ int draw_anchored; - int anchored_size; + int anchored_size; + + char draw_inverted; + char pad3[7]; + + float overlap_factor; /* normalization factor due to accumulated value of curve along spacing. + * Calculated when brush spacing changes to dampen strength of stroke + * if space attenuation is used*/ float anchored_initial_mouse[2]; /* check is there an ongoing stroke right now */ @@ -1001,15 +1016,16 @@ typedef struct UnifiedPaintSettings { struct ColorSpace *colorspace; /* radius of brush, premultiplied with pressure. - * In case of anchored brushes contains that radius */ + * In case of anchored brushes contains the anchored radius */ float pixel_radius; - int pad2; + int pad4; } UnifiedPaintSettings; typedef enum { UNIFIED_PAINT_SIZE = (1 << 0), UNIFIED_PAINT_ALPHA = (1 << 1), UNIFIED_PAINT_WEIGHT = (1 << 5), + UNIFIED_PAINT_COLOR = (1 << 6), /* only used if unified size is enabled, mirrors the brush flags * BRUSH_LOCK_SIZE and BRUSH_SIZE_PRESSURE */ @@ -1627,8 +1643,8 @@ typedef enum eVGroupSelect { #define SCE_FRAME_DROP (1<<3) - /* return flag BKE_scene_base_iter_next function */ -#define F_ERROR -1 + /* return flag BKE_scene_base_iter_next functions */ +/* #define F_ERROR -1 */ /* UNUSED */ #define F_START 0 #define F_SCENE 1 #define F_DUPLI 3 @@ -1654,7 +1670,7 @@ enum { typedef enum { PAINT_SHOW_BRUSH = (1 << 0), PAINT_FAST_NAVIGATE = (1 << 1), - PAINT_SHOW_BRUSH_ON_SURFACE = (1 << 2), + PAINT_SHOW_BRUSH_ON_SURFACE = (1 << 2) } PaintFlags; /* Paint.symmetry_flags diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index 38d3c2786ce..556923cea54 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -271,12 +271,12 @@ typedef struct ARegion { // #define WIN_EQUAL 3 // UNUSED /* area->flag */ -#define HEADER_NO_PULLDOWN 1 -#define AREA_FLAG_DRAWJOINTO 2 -#define AREA_FLAG_DRAWJOINFROM 4 -#define AREA_TEMP_INFO 8 -#define AREA_FLAG_DRAWSPLIT_H 16 -#define AREA_FLAG_DRAWSPLIT_V 32 +#define HEADER_NO_PULLDOWN (1 << 0) +#define AREA_FLAG_DRAWJOINTO (1 << 1) +#define AREA_FLAG_DRAWJOINFROM (1 << 2) +#define AREA_TEMP_INFO (1 << 3) +#define AREA_FLAG_DRAWSPLIT_H (1 << 4) +#define AREA_FLAG_DRAWSPLIT_V (1 << 5) #define EDGEWIDTH 1 #define AREAGRID 4 diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index 69d4693ab05..4795048d346 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -249,6 +249,11 @@ typedef struct SpeedControlVars { int lastValidFrame; } SpeedControlVars; +typedef struct GaussianBlurVars { + float size_x; + float size_y; +} GaussianBlurVars; + /* ***************** Sequence modifiers ****************** */ typedef struct SequenceModifierData { @@ -421,7 +426,8 @@ enum { SEQ_TYPE_SPEED = 29, SEQ_TYPE_MULTICAM = 30, SEQ_TYPE_ADJUSTMENT = 31, - SEQ_TYPE_EFFECT_MAX = 31 + SEQ_TYPE_GAUSSIAN_BLUR = 40, + SEQ_TYPE_EFFECT_MAX = 40 }; #define SEQ_MOVIECLIP_RENDER_UNDISTORTED (1 << 0) @@ -434,7 +440,7 @@ enum { */ -#define SEQ_HAS_PATH(_seq) (ELEM4((_seq)->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) +#define SEQ_HAS_PATH(_seq) (ELEM((_seq)->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) /* modifiers */ diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index c7a6d4809a5..e7a98246ecc 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -809,6 +809,8 @@ typedef enum eSpaceImage_Flag { SI_DRAW_OTHER = (1 << 23), SI_COLOR_CORRECTION = (1 << 24), + + SI_NO_DRAW_TEXPAINT = (1 << 25) } eSpaceImage_Flag; /* Text Editor ============================================ */ diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index 1906f71a230..dc891f8d971 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -585,7 +585,7 @@ typedef struct ColorMapping { #define TEX_VD_IMAGE_SEQUENCE 3 #define TEX_VD_SMOKE 4 /* for voxels which use VoxelData->source_path */ -#define TEX_VD_IS_SOURCE_PATH(_format) (ELEM3(_format, TEX_VD_BLENDERVOXEL, TEX_VD_RAW_8BIT, TEX_VD_RAW_16BIT)) +#define TEX_VD_IS_SOURCE_PATH(_format) (ELEM(_format, TEX_VD_BLENDERVOXEL, TEX_VD_RAW_8BIT, TEX_VD_RAW_16BIT)) /* smoke data types */ #define TEX_VD_SMOKEDENSITY 0 diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 9229505d714..31b06220bc8 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -154,7 +154,6 @@ typedef struct uiGradientColors { char high_gradient[4]; int show_grad; int pad2; - } uiGradientColors; typedef struct ThemeUI { @@ -328,6 +327,9 @@ typedef struct ThemeSpace { char info_warning[4], info_warning_text[4]; char info_info[4], info_info_text[4]; char info_debug[4], info_debug_text[4]; + + char paint_curve_pivot[4]; + char paint_curve_handle[4]; } ThemeSpace; @@ -489,7 +491,8 @@ typedef struct UserDef { short color_picker_type; char ipo_new; /* interpolation mode for newly added F-Curves */ char keyhandles_new; /* handle types for newly added keyframes */ - char pad1[2]; + char gpu_select_method; + char pad1; short scrcastfps; /* frame rate for screencast to be played back */ short scrcastwait; /* milliseconds between screencast snapshots */ @@ -717,6 +720,13 @@ typedef enum eOpenGL_RenderingOptions { /* USER_DISABLE_AA = (1 << 4), */ /* DEPRECATED */ } eOpenGL_RenderingOptions; +/* selection method for opengl gpu_select_method */ +typedef enum eOpenGL_SelectOptions { + USER_SELECT_AUTO = 0, + USER_SELECT_USE_OCCLUSION_QUERY = 1, + USER_SELECT_USE_SELECT_RENDERMODE = 2 +} eOpenGL_SelectOptions; + /* wm draw method */ typedef enum eWM_DrawMethod { USER_DRAW_TRIPLE = 0, diff --git a/source/blender/makesdna/DNA_vfont_types.h b/source/blender/makesdna/DNA_vfont_types.h index 14ec6c9b312..7025a5767c4 100644 --- a/source/blender/makesdna/DNA_vfont_types.h +++ b/source/blender/makesdna/DNA_vfont_types.h @@ -66,7 +66,7 @@ typedef struct VFont { #define FO_SELCHANGE 10 /* BKE_vfont_to_curve will move the cursor in these cases */ -#define FO_CURS_IS_MOTION(mode) (ELEM4(mode, FO_CURSUP, FO_CURSDOWN, FO_PAGEUP, FO_PAGEDOWN)) +#define FO_CURS_IS_MOTION(mode) (ELEM(mode, FO_CURSUP, FO_CURSDOWN, FO_PAGEUP, FO_PAGEDOWN)) #define FO_BUILTIN_NAME "<builtin>" diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index add59bafc3f..ba2dd8b5d69 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -427,6 +427,9 @@ extern StructRNA RNA_OrController; extern StructRNA RNA_OutflowFluidSettings; extern StructRNA RNA_PackedFile; extern StructRNA RNA_Paint; +extern StructRNA RNA_PaintCurve; +extern StructRNA RNA_Palette; +extern StructRNA RNA_PaletteColor; extern StructRNA RNA_Panel; extern StructRNA RNA_Particle; extern StructRNA RNA_ParticleBrush; @@ -924,9 +927,22 @@ bool RNA_path_resolve_property(PointerRNA *ptr, const char *path, bool RNA_path_resolve_property_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index); +typedef struct PropertyElemRNA PropertyElemRNA; +struct PropertyElemRNA { + PropertyElemRNA *next, *prev; + PointerRNA ptr; + PropertyRNA *prop; + int index; +}; +bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, struct ListBase *r_elements); + char *RNA_path_from_ID_to_struct(PointerRNA *ptr); char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop); +char *RNA_path_resolve_from_type_to_property( + struct PointerRNA *ptr, struct PropertyRNA *prop, + const struct StructRNA *type); + char *RNA_path_full_ID_py(struct ID *id); char *RNA_path_full_struct_py(struct PointerRNA *ptr); char *RNA_path_full_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int index); diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 7f1f04cdb6a..9023f25e3d5 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -745,6 +745,24 @@ static void rna_clamp_value_range(FILE *f, PropertyRNA *prop) } } +#ifdef USE_RNA_RANGE_CHECK +static void rna_clamp_value_range_check( + FILE *f, PropertyRNA *prop, + const char *dnaname_prefix, const char *dnaname) +{ + if (prop->type == PROP_INT) { + IntPropertyRNA *iprop = (IntPropertyRNA *)prop; + fprintf(f, + " { BLI_STATIC_ASSERT(" + "(TYPEOF_MAX(%s%s) >= %d) && " + "(TYPEOF_MIN(%s%s) <= %d), " + "\"invalid limits\"); }\n", + dnaname_prefix, dnaname, iprop->hardmax, + dnaname_prefix, dnaname, iprop->hardmin); + } +} +#endif /* USE_RNA_RANGE_CHECK */ + static void rna_clamp_value(FILE *f, PropertyRNA *prop, int array) { if (prop->type == PROP_INT) { @@ -944,6 +962,18 @@ static char *rna_def_property_set_func(FILE *f, StructRNA *srna, PropertyRNA *pr } fprintf(f, " }\n"); } + +#ifdef USE_RNA_RANGE_CHECK + if (dp->dnaname && manualfunc == NULL) { + if (dp->dnaarraylength == 1) { + rna_clamp_value_range_check(f, prop, "data->", dp->dnaname); + } + else { + rna_clamp_value_range_check(f, prop, "*data->", dp->dnaname); + } + } +#endif + fprintf(f, "}\n\n"); } else { @@ -975,6 +1005,13 @@ static char *rna_def_property_set_func(FILE *f, StructRNA *srna, PropertyRNA *pr rna_clamp_value(f, prop, 0); } } + +#ifdef USE_RNA_RANGE_CHECK + if (dp->dnaname && manualfunc == NULL) { + rna_clamp_value_range_check(f, prop, "data->", dp->dnaname); + } +#endif + fprintf(f, "}\n\n"); } break; diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 7959e60da33..83fe56102ac 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -153,6 +153,8 @@ short RNA_type_to_ID_code(StructRNA *type) if (RNA_struct_is_a(type, &RNA_WindowManager)) return ID_WM; if (RNA_struct_is_a(type, &RNA_MovieClip)) return ID_MC; if (RNA_struct_is_a(type, &RNA_Mask)) return ID_MSK; + if (RNA_struct_is_a(type, &RNA_Palette)) return ID_PAL; + if (RNA_struct_is_a(type, &RNA_PaintCurve)) return ID_PC; return 0; } @@ -190,6 +192,9 @@ StructRNA *ID_code_to_RNA_type(short idcode) case ID_WM: return &RNA_WindowManager; case ID_MC: return &RNA_MovieClip; case ID_MSK: return &RNA_Mask; + case ID_PAL: return &RNA_Palette; + case ID_PC: return &RNA_PaintCurve; + default: return &RNA_ID; } } @@ -620,6 +625,10 @@ static void rna_def_library(BlenderRNA *brna) prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "Library"); RNA_def_property_ui_text(prop, "Parent", ""); + + prop = RNA_def_property(srna, "packed_file", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "packedfile"); + RNA_def_property_ui_text(prop, "Packed File", ""); } void RNA_def_ID(BlenderRNA *brna) { diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index ded0278b44d..8c76edd2f17 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -359,12 +359,12 @@ static bool rna_idproperty_verify_valid(PointerRNA *ptr, PropertyRNA *prop, IDPr if (idprop->subtype == IDP_FLOAT && prop->type != PROP_FLOAT) return false; - if (idprop->subtype == IDP_INT && !ELEM3(prop->type, PROP_BOOLEAN, PROP_INT, PROP_ENUM)) + if (idprop->subtype == IDP_INT && !ELEM(prop->type, PROP_BOOLEAN, PROP_INT, PROP_ENUM)) return false; break; case IDP_INT: - if (!ELEM3(prop->type, PROP_BOOLEAN, PROP_INT, PROP_ENUM)) + if (!ELEM(prop->type, PROP_BOOLEAN, PROP_INT, PROP_ENUM)) return false; break; case IDP_FLOAT: @@ -872,8 +872,8 @@ char RNA_property_array_item_char(PropertyRNA *prop, int index) if ((index < 4) && ELEM(subtype, PROP_QUATERNION, PROP_AXISANGLE)) { return quatitem[index]; } - else if ((index < 4) && ELEM8(subtype, PROP_TRANSLATION, PROP_DIRECTION, PROP_XYZ, PROP_XYZ_LENGTH, - PROP_EULER, PROP_VELOCITY, PROP_ACCELERATION, PROP_COORDS)) + else if ((index < 4) && ELEM(subtype, PROP_TRANSLATION, PROP_DIRECTION, PROP_XYZ, PROP_XYZ_LENGTH, + PROP_EULER, PROP_VELOCITY, PROP_ACCELERATION, PROP_COORDS)) { return vectoritem[index]; } @@ -902,7 +902,7 @@ int RNA_property_array_item_index(PropertyRNA *prop, char name) return 3; } } - else if (ELEM6(subtype, PROP_TRANSLATION, PROP_DIRECTION, PROP_XYZ, + else if (ELEM(subtype, PROP_TRANSLATION, PROP_DIRECTION, PROP_XYZ, PROP_EULER, PROP_VELOCITY, PROP_ACCELERATION)) { switch (name) { @@ -3329,7 +3329,7 @@ static int rna_raw_access(ReportList *reports, PointerRNA *ptr, PropertyRNA *pro /* check type */ itemtype = RNA_property_type(itemprop); - if (!ELEM3(itemtype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) { + if (!ELEM(itemtype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) { BKE_report(reports, RPT_ERROR, "Only boolean, int and float properties supported"); return 0; } @@ -3409,7 +3409,7 @@ static int rna_raw_access(ReportList *reports, PointerRNA *ptr, PropertyRNA *pro break; } - if (!ELEM3(itemtype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) { + if (!ELEM(itemtype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) { BKE_report(reports, RPT_ERROR, "Only boolean, int and float properties supported"); err = 1; break; @@ -4015,11 +4015,14 @@ static bool rna_path_parse_array_index(const char **path, PointerRNA *ptr, Prope } static bool rna_path_parse(PointerRNA *ptr, const char *path, - PointerRNA *r_ptr, PropertyRNA **r_prop, int *index, + PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index, + ListBase *r_elements, const bool eval_pointer) { PropertyRNA *prop; PointerRNA curptr; + PropertyElemRNA *prop_elem = NULL; + int index = -1; char fixedbuf[256]; int type; @@ -4061,6 +4064,14 @@ static bool rna_path_parse(PointerRNA *ptr, const char *path, if (!prop) return false; + if (r_elements) { + prop_elem = MEM_mallocN(sizeof(PropertyElemRNA), __func__); + prop_elem->ptr = curptr; + prop_elem->prop = prop; + prop_elem->index = -1; /* index will be added later, if needed. */ + BLI_addtail(r_elements, prop_elem); + } + type = RNA_property_type(prop); /* now look up the value of this property if it is a pointer or @@ -4076,7 +4087,7 @@ static bool rna_path_parse(PointerRNA *ptr, const char *path, curptr = nextptr; prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */ - if (index) *index = -1; + index = -1; } break; } @@ -4093,21 +4104,38 @@ static bool rna_path_parse(PointerRNA *ptr, const char *path, curptr = nextptr; prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */ - if (index) *index = -1; + index = -1; } break; } default: - if (index) { - if (!rna_path_parse_array_index(&path, &curptr, prop, index)) + if (r_index || prop_elem) { + if (!rna_path_parse_array_index(&path, &curptr, prop, &index)) { return false; + } + + if (prop_elem) { + prop_elem->index = index; + } } break; } } - *r_ptr = curptr; - *r_prop = prop; + if (r_ptr) + *r_ptr = curptr; + if (r_prop) + *r_prop = prop; + if (r_index) + *r_index = index; + + if (prop_elem && (prop_elem->ptr.data != curptr.data || prop_elem->prop != prop || prop_elem->index != index)) { + PropertyElemRNA *prop_elem = MEM_mallocN(sizeof(PropertyElemRNA), __func__); + prop_elem->ptr = curptr; + prop_elem->prop = prop; + prop_elem->index = index; + BLI_addtail(r_elements, prop_elem); + } return true; } @@ -4120,7 +4148,7 @@ static bool rna_path_parse(PointerRNA *ptr, const char *path, */ bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop) { - if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, true)) + if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, true)) return false; return r_ptr->data != NULL; @@ -4134,7 +4162,7 @@ bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, Prop */ bool RNA_path_resolve_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index) { - if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, true)) + if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, true)) return false; return r_ptr->data != NULL; @@ -4149,7 +4177,7 @@ bool RNA_path_resolve_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, */ bool RNA_path_resolve_property(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop) { - if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, false)) + if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, false)) return false; return r_ptr->data != NULL && *r_prop != NULL; @@ -4165,12 +4193,25 @@ bool RNA_path_resolve_property(PointerRNA *ptr, const char *path, PointerRNA *r_ */ bool RNA_path_resolve_property_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index) { - if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, false)) + if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, false)) return false; return r_ptr->data != NULL && *r_prop != NULL; } +/** + * Resolve the given RNA Path into a linked list of PropertyElemRNA's. + * + * To be used when complex operations over path are needed, like e.g. get relative paths, to avoid too much + * string operations. + * + * \return True if there was no error while resolving the path + * \note Assumes all pointers provided are valid + */ +bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, ListBase *r_elements) +{ + return rna_path_parse(ptr, path, NULL, NULL, NULL, r_elements, false); +} char *RNA_path_append(const char *path, PointerRNA *UNUSED(ptr), PropertyRNA *prop, int intkey, const char *strkey) { @@ -4498,6 +4539,47 @@ char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop) } /** + * \return the path to given ptr/prop from the closest ancestor of given type, if any (else return NULL). + */ +char *RNA_path_resolve_from_type_to_property( + PointerRNA *ptr, PropertyRNA *prop, + const StructRNA *type) +{ + /* Try to recursively find an "type"'d ancestor, + * to handle situations where path from ID is not enough. */ + PointerRNA idptr; + ListBase path_elems = {NULL}; + char *path = NULL; + char *full_path = RNA_path_from_ID_to_property(ptr, prop); + + if (full_path == NULL) { + return NULL; + } + + RNA_id_pointer_create(ptr->id.data, &idptr); + + if (RNA_path_resolve_elements(&idptr, full_path, &path_elems)) { + PropertyElemRNA *prop_elem; + + for (prop_elem = path_elems.last; prop_elem; prop_elem = prop_elem->prev) { + if (RNA_struct_is_a(prop_elem->ptr.type, type)) { + char *ref_path = RNA_path_from_ID_to_struct(&prop_elem->ptr); + if (ref_path) { + path = BLI_strdup(full_path + strlen(ref_path) + 1); /* +1 for the linking '.' */ + MEM_freeN(ref_path); + } + break; + } + } + + BLI_freelistN(&path_elems); + } + + MEM_freeN(full_path); + return path; +} + +/** * Get the ID as a python representation, eg: * bpy.data.foo["bar"] */ diff --git a/source/blender/makesrna/intern/rna_actuator.c b/source/blender/makesrna/intern/rna_actuator.c index 956077055a9..0114ffa35c0 100644 --- a/source/blender/makesrna/intern/rna_actuator.c +++ b/source/blender/makesrna/intern/rna_actuator.c @@ -150,7 +150,7 @@ static void rna_ConstraintActuator_type_set(struct PointerRNA *ptr, int value) switch (ca->type) { case ACT_CONST_TYPE_ORI: /* negative axis not supported in the orientation mode */ - if (ELEM3(ca->mode, ACT_CONST_DIRNX, ACT_CONST_DIRNY, ACT_CONST_DIRNZ)) + if (ELEM(ca->mode, ACT_CONST_DIRNX, ACT_CONST_DIRNY, ACT_CONST_DIRNZ)) ca->mode = ACT_CONST_NONE; break; diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 893cad2b76a..1ff99271146 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -55,6 +55,9 @@ static EnumPropertyItem sculpt_stroke_method_items[] = { {BRUSH_SPACE, "SPACE", 0, "Space", "Limit brush application to the distance specified by spacing"}, {BRUSH_AIRBRUSH, "AIRBRUSH", 0, "Airbrush", "Keep applying paint effect while holding mouse (spray)"}, {BRUSH_ANCHORED, "ANCHORED", 0, "Anchored", "Keep the brush anchored to the initial location"}, + {BRUSH_LINE, "LINE", 0, "Line", "Draw a line with dabs separated according to spacing"}, + {BRUSH_CURVE, "CURVE", 0, "Curve", + "Define the stroke curve with a bezier curve (dabs are separated according to spacing)"}, {0, NULL, 0, NULL, NULL} }; @@ -99,6 +102,8 @@ EnumPropertyItem brush_image_tool_items[] = { {PAINT_TOOL_SOFTEN, "SOFTEN", ICON_BRUSH_SOFTEN, "Soften", ""}, {PAINT_TOOL_SMEAR, "SMEAR", ICON_BRUSH_SMEAR, "Smear", ""}, {PAINT_TOOL_CLONE, "CLONE", ICON_BRUSH_CLONE, "Clone", ""}, + {PAINT_TOOL_FILL, "FILL", ICON_BRUSH_TEXFILL, "Fill", ""}, + {PAINT_TOOL_MASK, "MASK", ICON_BRUSH_TEXMASK, "Mask", ""}, {0, NULL, 0, NULL, NULL} }; @@ -120,9 +125,9 @@ EnumPropertyItem brush_image_tool_items[] = { static int rna_SculptToolCapabilities_has_accumulate_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - return ELEM6(br->sculpt_tool, - SCULPT_TOOL_BLOB, SCULPT_TOOL_CLAY, SCULPT_TOOL_CREASE, - SCULPT_TOOL_DRAW, SCULPT_TOOL_INFLATE, SCULPT_TOOL_LAYER); + return ELEM(br->sculpt_tool, + SCULPT_TOOL_BLOB, SCULPT_TOOL_CLAY, SCULPT_TOOL_CREASE, + SCULPT_TOOL_DRAW, SCULPT_TOOL_INFLATE, SCULPT_TOOL_LAYER); } static int rna_SculptToolCapabilities_has_auto_smooth_get(PointerRNA *ptr) @@ -142,9 +147,9 @@ static int rna_SculptToolCapabilities_has_jitter_get(PointerRNA *ptr) Brush *br = (Brush *)ptr->data; return (!(br->flag & BRUSH_ANCHORED) && !(br->flag & BRUSH_DRAG_DOT) && - !ELEM4(br->sculpt_tool, - SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, - SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB)); + !ELEM(br->sculpt_tool, + SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, + SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB)); } static int rna_SculptToolCapabilities_has_normal_weight_get(PointerRNA *ptr) @@ -156,7 +161,7 @@ static int rna_SculptToolCapabilities_has_normal_weight_get(PointerRNA *ptr) static int rna_BrushCapabilities_has_overlay_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - return ELEM3(br->mtex.brush_map_mode, + return ELEM(br->mtex.brush_map_mode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL); @@ -177,22 +182,22 @@ static int rna_SculptToolCapabilities_has_pinch_factor_get(PointerRNA *ptr) static int rna_SculptToolCapabilities_has_plane_offset_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - return ELEM5(br->sculpt_tool, SCULPT_TOOL_CLAY, SCULPT_TOOL_CLAY_STRIPS, - SCULPT_TOOL_FILL, SCULPT_TOOL_FLATTEN, SCULPT_TOOL_SCRAPE); + return ELEM(br->sculpt_tool, SCULPT_TOOL_CLAY, SCULPT_TOOL_CLAY_STRIPS, + SCULPT_TOOL_FILL, SCULPT_TOOL_FLATTEN, SCULPT_TOOL_SCRAPE); } static int rna_SculptToolCapabilities_has_random_texture_angle_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - return (!ELEM4(br->sculpt_tool, - SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, - SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB)); + return (!ELEM(br->sculpt_tool, + SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, + SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB)); } static int rna_BrushCapabilities_has_random_texture_angle_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - return (ELEM3(br->mtex.brush_map_mode, + return (ELEM(br->mtex.brush_map_mode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_AREA, MTEX_MAP_MODE_RANDOM) && @@ -202,19 +207,19 @@ static int rna_BrushCapabilities_has_random_texture_angle_get(PointerRNA *ptr) static int rna_SculptToolCapabilities_has_sculpt_plane_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - return !ELEM4(br->sculpt_tool, SCULPT_TOOL_INFLATE, - SCULPT_TOOL_MASK, SCULPT_TOOL_PINCH, - SCULPT_TOOL_SMOOTH); + return !ELEM(br->sculpt_tool, SCULPT_TOOL_INFLATE, + SCULPT_TOOL_MASK, SCULPT_TOOL_PINCH, + SCULPT_TOOL_SMOOTH); } static int rna_SculptToolCapabilities_has_secondary_color_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - return ELEM10(br->sculpt_tool, - SCULPT_TOOL_BLOB, SCULPT_TOOL_CLAY, SCULPT_TOOL_CLAY_STRIPS, - SCULPT_TOOL_CREASE, SCULPT_TOOL_DRAW, SCULPT_TOOL_FILL, - SCULPT_TOOL_FLATTEN, SCULPT_TOOL_INFLATE, SCULPT_TOOL_PINCH, - SCULPT_TOOL_SCRAPE); + return ELEM(br->sculpt_tool, + SCULPT_TOOL_BLOB, SCULPT_TOOL_CLAY, SCULPT_TOOL_CLAY_STRIPS, + SCULPT_TOOL_CREASE, SCULPT_TOOL_DRAW, SCULPT_TOOL_FILL, + SCULPT_TOOL_FLATTEN, SCULPT_TOOL_INFLATE, SCULPT_TOOL_PINCH, + SCULPT_TOOL_SCRAPE); } static int rna_SculptToolCapabilities_has_smooth_stroke_get(PointerRNA *ptr) @@ -222,19 +227,37 @@ static int rna_SculptToolCapabilities_has_smooth_stroke_get(PointerRNA *ptr) Brush *br = (Brush *)ptr->data; return (!(br->flag & BRUSH_ANCHORED) && !(br->flag & BRUSH_DRAG_DOT) && - !ELEM4(br->sculpt_tool, + !(br->flag & BRUSH_LINE) && + !(br->flag & BRUSH_CURVE) && + !ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB)); } +static int rna_BrushCapabilities_has_smooth_stroke_get(PointerRNA *ptr) +{ + Brush *br = (Brush *)ptr->data; + return (!(br->flag & BRUSH_ANCHORED) && + !(br->flag & BRUSH_DRAG_DOT) && + !(br->flag & BRUSH_LINE) && + !(br->flag & BRUSH_CURVE)); +} + static int rna_SculptToolCapabilities_has_space_attenuation_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - return ((br->flag & BRUSH_SPACE) && - !ELEM4(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, + return ((br->flag & (BRUSH_SPACE | BRUSH_LINE | BRUSH_CURVE)) && + !ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_SNAKE_HOOK)); } +static int rna_ImapaintToolCapabilities_has_space_attenuation_get(PointerRNA *ptr) +{ + Brush *br = (Brush *)ptr->data; + return (br->flag & (BRUSH_SPACE | BRUSH_LINE | BRUSH_CURVE)) && + br->imagepaint_tool != PAINT_TOOL_FILL; +} + static int rna_BrushCapabilities_has_spacing_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; @@ -250,12 +273,12 @@ static int rna_SculptToolCapabilities_has_strength_get(PointerRNA *ptr) static int rna_BrushCapabilities_has_texture_angle_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - return ELEM5(br->mtex.brush_map_mode, - MTEX_MAP_MODE_VIEW, - MTEX_MAP_MODE_AREA, - MTEX_MAP_MODE_TILED, - MTEX_MAP_MODE_STENCIL, - MTEX_MAP_MODE_RANDOM); + return ELEM(br->mtex.brush_map_mode, + MTEX_MAP_MODE_VIEW, + MTEX_MAP_MODE_AREA, + MTEX_MAP_MODE_TILED, + MTEX_MAP_MODE_STENCIL, + MTEX_MAP_MODE_RANDOM); } static int rna_SculptToolCapabilities_has_gravity_get(PointerRNA *ptr) @@ -267,17 +290,46 @@ static int rna_SculptToolCapabilities_has_gravity_get(PointerRNA *ptr) static int rna_BrushCapabilities_has_texture_angle_source_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - return ELEM3(br->mtex.brush_map_mode, + return ELEM(br->mtex.brush_map_mode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_AREA, MTEX_MAP_MODE_RANDOM); } -static PointerRNA rna_Sculpt_sculpt_tool_capabilities_get(PointerRNA *ptr) +static int rna_ImapaintToolCapabilities_has_accumulate_get(PointerRNA *ptr) +{ + /* only support for draw tool */ + Brush *br = (Brush *)ptr->data; + + return ((br->flag & BRUSH_AIRBRUSH) || + (br->flag & BRUSH_DRAG_DOT) || + (br->flag & BRUSH_ANCHORED) || + (br->imagepaint_tool == PAINT_TOOL_SOFTEN) || + (br->imagepaint_tool == PAINT_TOOL_SMEAR) || + (br->imagepaint_tool == PAINT_TOOL_FILL) || + (br->mtex.tex && !ELEM(br->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_3D)) + ) ? false : true; +} + +static int rna_ImapaintToolCapabilities_has_radius_get(PointerRNA *ptr) +{ + /* only support for draw tool */ + Brush *br = (Brush *)ptr->data; + + return (br->imagepaint_tool != PAINT_TOOL_FILL); +} + + +static PointerRNA rna_Sculpt_tool_capabilities_get(PointerRNA *ptr) { return rna_pointer_inherit_refine(ptr, &RNA_SculptToolCapabilities, ptr->id.data); } +static PointerRNA rna_Imapaint_tool_capabilities_get(PointerRNA *ptr) +{ + return rna_pointer_inherit_refine(ptr, &RNA_ImapaintToolCapabilities, ptr->id.data); +} + static PointerRNA rna_Brush_capabilities_get(PointerRNA *ptr) { return rna_pointer_inherit_refine(ptr, &RNA_BrushCapabilities, ptr->id.data); @@ -328,7 +380,6 @@ static void rna_Brush_size_update(Main *bmain, Scene *scene, PointerRNA *ptr) static void rna_Brush_sculpt_tool_update(Main *bmain, Scene *scene, PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - BKE_paint_invalidate_overlay_all(); rna_Brush_reset_icon(br, "sculpt"); rna_Brush_update(bmain, scene, ptr); } @@ -336,7 +387,6 @@ static void rna_Brush_sculpt_tool_update(Main *bmain, Scene *scene, PointerRNA * static void rna_Brush_vertex_tool_update(Main *bmain, Scene *scene, PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - BKE_paint_invalidate_overlay_all(); rna_Brush_reset_icon(br, "vertex_paint"); rna_Brush_update(bmain, scene, ptr); } @@ -344,11 +394,16 @@ static void rna_Brush_vertex_tool_update(Main *bmain, Scene *scene, PointerRNA * static void rna_Brush_imagepaint_tool_update(Main *bmain, Scene *scene, PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; - BKE_paint_invalidate_overlay_all(); rna_Brush_reset_icon(br, "image_paint"); rna_Brush_update(bmain, scene, ptr); } +static void rna_Brush_stroke_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, scene); + rna_Brush_update(bmain, scene, ptr); +} + static void rna_Brush_icon_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; @@ -388,6 +443,17 @@ static void rna_Brush_set_size(PointerRNA *ptr, int value) brush->size = value; } +static void rna_Brush_use_gradient_set(PointerRNA *ptr, int value) +{ + Brush *br = (Brush *)ptr->data; + + if (value) br->flag |= BRUSH_USE_GRADIENT; + else br->flag &= ~BRUSH_USE_GRADIENT; + + if ((br->flag & BRUSH_USE_GRADIENT) && br->gradient == NULL) + br->gradient = add_colorband(true); +} + static void rna_Brush_set_unprojected_radius(PointerRNA *ptr, float value) { Brush *brush = ptr->data; @@ -397,13 +463,16 @@ static void rna_Brush_set_unprojected_radius(PointerRNA *ptr, float value) brush->unprojected_radius = value; } -static EnumPropertyItem *rna_Brush_direction_itemf(bContext *UNUSED(C), PointerRNA *ptr, +static EnumPropertyItem *rna_Brush_direction_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *UNUSED(r_free)) { + PaintMode mode = BKE_paintmode_get_active_from_context(C); + static EnumPropertyItem prop_default_items[] = { {0, NULL, 0, NULL, NULL} }; + /* sculpt mode */ static EnumPropertyItem prop_flatten_contrast_items[] = { {0, "FLATTEN", 0, "Flatten", "Add effect of brush"}, {BRUSH_DIR_IN, "CONTRAST", 0, "Contrast", "Subtract effect of brush"}, @@ -434,41 +503,66 @@ static EnumPropertyItem *rna_Brush_direction_itemf(bContext *UNUSED(C), PointerR {0, NULL, 0, NULL, NULL} }; + /* texture paint mode */ + static EnumPropertyItem prop_soften_sharpen_items[] = { + {0, "SOFTEN", 0, "Soften", "Blur effect of brush"}, + {BRUSH_DIR_IN, "SHARPEN", 0, "Sharpen", "Sharpen effect of brush"}, + {0, NULL, 0, NULL, NULL} + }; + Brush *me = (Brush *)(ptr->data); - switch (me->sculpt_tool) { - case SCULPT_TOOL_DRAW: - case SCULPT_TOOL_CREASE: - case SCULPT_TOOL_BLOB: - case SCULPT_TOOL_LAYER: - case SCULPT_TOOL_CLAY: - case SCULPT_TOOL_CLAY_STRIPS: - return prop_direction_items; - - case SCULPT_TOOL_MASK: - switch ((BrushMaskTool)me->mask_tool) { - case BRUSH_MASK_DRAW: + switch (mode) { + case PAINT_SCULPT: + switch (me->sculpt_tool) { + case SCULPT_TOOL_DRAW: + case SCULPT_TOOL_CREASE: + case SCULPT_TOOL_BLOB: + case SCULPT_TOOL_LAYER: + case SCULPT_TOOL_CLAY: + case SCULPT_TOOL_CLAY_STRIPS: return prop_direction_items; - break; - case BRUSH_MASK_SMOOTH: - return prop_default_items; - break; - } - case SCULPT_TOOL_FLATTEN: - return prop_flatten_contrast_items; + case SCULPT_TOOL_MASK: + switch ((BrushMaskTool)me->mask_tool) { + case BRUSH_MASK_DRAW: + return prop_direction_items; + break; + case BRUSH_MASK_SMOOTH: + return prop_default_items; + break; + } - case SCULPT_TOOL_FILL: - return prop_fill_deepen_items; + case SCULPT_TOOL_FLATTEN: + return prop_flatten_contrast_items; - case SCULPT_TOOL_SCRAPE: - return prop_scrape_peaks_items; + case SCULPT_TOOL_FILL: + return prop_fill_deepen_items; - case SCULPT_TOOL_PINCH: - return prop_pinch_magnify_items; + case SCULPT_TOOL_SCRAPE: + return prop_scrape_peaks_items; - case SCULPT_TOOL_INFLATE: - return prop_inflate_deflate_items; + case SCULPT_TOOL_PINCH: + return prop_pinch_magnify_items; + + case SCULPT_TOOL_INFLATE: + return prop_inflate_deflate_items; + + default: + return prop_default_items; + } + break; + + case PAINT_TEXTURE_2D: + case PAINT_TEXTURE_PROJECTIVE: + switch (me->imagepaint_tool) { + case PAINT_TOOL_SOFTEN: + return prop_soften_sharpen_items; + + default: + return prop_default_items; + } + break; default: return prop_default_items; @@ -484,11 +578,15 @@ static EnumPropertyItem *rna_Brush_stroke_itemf(bContext *C, PointerRNA *UNUSED( {0, "DOTS", 0, "Dots", "Apply paint on each mouse move step"}, {BRUSH_SPACE, "SPACE", 0, "Space", "Limit brush application to the distance specified by spacing"}, {BRUSH_AIRBRUSH, "AIRBRUSH", 0, "Airbrush", "Keep applying paint effect while holding mouse (spray)"}, + {BRUSH_LINE, "LINE", 0, "Line", "Drag a line with dabs separated according to spacing"}, + {BRUSH_CURVE, "CURVE", 0, "Curve", "Define the stroke curve with a bezier curve. Dabs are separated according to spacing"}, {0, NULL, 0, NULL, NULL} }; switch (mode) { case PAINT_SCULPT: + case PAINT_TEXTURE_2D: + case PAINT_TEXTURE_PROJECTIVE: return sculpt_stroke_method_items; default: @@ -622,10 +720,39 @@ static void rna_def_brush_capabilities(BlenderRNA *brna) BRUSH_CAPABILITY(has_texture_angle, "Has Texture Angle"); BRUSH_CAPABILITY(has_texture_angle_source, "Has Texture Angle Source"); BRUSH_CAPABILITY(has_spacing, "Has Spacing"); + BRUSH_CAPABILITY(has_smooth_stroke, "Has Smooth Stroke"); + #undef BRUSH_CAPABILITY } +static void rna_def_image_paint_capabilities(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "ImapaintToolCapabilities", NULL); + RNA_def_struct_sdna(srna, "Brush"); + RNA_def_struct_nested(brna, srna, "Brush"); + RNA_def_struct_ui_text(srna, "Image Paint Capabilities", + "Read-only indications of which brush operations " + "are supported by the current image paint brush"); + +#define IMAPAINT_TOOL_CAPABILITY(prop_name_, ui_name_) \ + prop = RNA_def_property(srna, #prop_name_, \ + PROP_BOOLEAN, PROP_NONE); \ + RNA_def_property_clear_flag(prop, PROP_EDITABLE); \ + RNA_def_property_boolean_funcs(prop, "rna_ImapaintToolCapabilities_" \ + #prop_name_ "_get", NULL); \ + RNA_def_property_ui_text(prop, ui_name_, NULL) + + IMAPAINT_TOOL_CAPABILITY(has_accumulate, "Has Accumulate"); + IMAPAINT_TOOL_CAPABILITY(has_space_attenuation, "Has Space Attenuation"); + IMAPAINT_TOOL_CAPABILITY(has_radius, "Has Radius"); + +#undef IMAPAINT_TOOL_CAPABILITY +} + static void rna_def_brush(BlenderRNA *brna) { StructRNA *srna; @@ -640,6 +767,22 @@ static void rna_def_brush(BlenderRNA *brna) {IMB_BLEND_DARKEN, "DARKEN", 0, "Darken", "Use darken blending mode while painting"}, {IMB_BLEND_ERASE_ALPHA, "ERASE_ALPHA", 0, "Erase Alpha", "Erase alpha while painting"}, {IMB_BLEND_ADD_ALPHA, "ADD_ALPHA", 0, "Add Alpha", "Add alpha while painting"}, + {IMB_BLEND_OVERLAY, "OVERLAY", 0, "Overlay", "Use overlay blending mode while painting"}, + {IMB_BLEND_HARDLIGHT, "HARDLIGHT", 0, "Hard light", "Use hard light blending mode while painting"}, + {IMB_BLEND_COLORBURN, "COLORBURN", 0, "Color burn", "Use color burn blending mode while painting"}, + {IMB_BLEND_LINEARBURN, "LINEARBURN", 0, "Linear burn", "Use linear burn blending mode while painting"}, + {IMB_BLEND_COLORDODGE, "COLORDODGE", 0, "Color dodge", "Use color dodge blending mode while painting"}, + {IMB_BLEND_SCREEN, "SCREEN", 0, "Screen", "Use screen blending mode while painting"}, + {IMB_BLEND_SOFTLIGHT, "SOFTLIGHT", 0, "Soft light", "Use softlight blending mode while painting"}, + {IMB_BLEND_PINLIGHT, "PINLIGHT", 0, "Pin light", "Use pinlight blending mode while painting"}, + {IMB_BLEND_VIVIDLIGHT, "VIVIDLIGHT", 0, "Vivid light", "Use vividlight blending mode while painting"}, + {IMB_BLEND_LINEARLIGHT, "LINEARLIGHT", 0, "Linear light", "Use linearlight blending mode while painting"}, + {IMB_BLEND_DIFFERENCE, "DIFFERENCE", 0, "Difference", "Use difference blending mode while painting"}, + {IMB_BLEND_EXCLUSION, "EXCLUSION", 0, "Exclusion", "Use exclusion blending mode while painting"}, + {IMB_BLEND_HUE, "HUE", 0, "Hue", "Use hue blending mode while painting"}, + {IMB_BLEND_SATURATION, "SATURATION", 0, "Saturation", "Use saturation blending mode while painting"}, + {IMB_BLEND_LUMINOSITY, "LUMINOSITY", 0, "Luminosity", "Use luminosity blending mode while painting"}, + {IMB_BLEND_COLOR, "COLOR", 0, "Color", "Use color blending mode while painting"}, {0, NULL, 0, NULL, NULL} }; @@ -671,6 +814,32 @@ static void rna_def_brush(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem brush_blur_mode_items[] = { + {KERNEL_BOX, "BOX", 0, "Box", ""}, + {KERNEL_GAUSSIAN, "GAUSSIAN", 0, "Gaussian", ""}, + {0, NULL, 0, NULL, NULL} + }; + + static EnumPropertyItem brush_gradient_items[] = { + {BRUSH_GRADIENT_PRESSURE, "PRESSURE", 0, "Pressure", ""}, + {BRUSH_GRADIENT_SPACING_REPEAT, "SPACING_REPEAT", 0, "Repeat", ""}, + {BRUSH_GRADIENT_SPACING_CLAMP, "SPACING_CLAMP", 0, "Clamp", ""}, + {0, NULL, 0, NULL, NULL} + }; + + static EnumPropertyItem brush_gradient_fill_items[] = { + {BRUSH_GRADIENT_LINEAR, "LINEAR", 0, "Linear", ""}, + {BRUSH_GRADIENT_RADIAL, "RADIAL", 0, "Radial", ""}, + {0, NULL, 0, NULL, NULL} + }; + + static EnumPropertyItem brush_mask_pressure_items[] = { + {0, "NONE", 0, "Off", ""}, + {BRUSH_MASK_PRESSURE_RAMP, "RAMP", ICON_STYLUS_PRESSURE, "Ramp", ""}, + {BRUSH_MASK_PRESSURE_CUTOFF, "CUTOFF", ICON_STYLUS_PRESSURE, "Cutoff", ""}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "Brush", "ID"); RNA_def_struct_ui_text(srna, "Brush", "Brush datablock for storing brush settings for painting and sculpting"); RNA_def_struct_ui_icon(srna, ICON_BRUSH_DATA); @@ -710,7 +879,7 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_enum_items(prop, sculpt_stroke_method_items); RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Brush_stroke_itemf"); RNA_def_property_ui_text(prop, "Stroke Method", ""); - RNA_def_property_update(prop, 0, "rna_Brush_update"); + RNA_def_property_update(prop, 0, "rna_Brush_stroke_update"); prop = RNA_def_property(srna, "texture_angle_source_random", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); @@ -769,6 +938,13 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Spacing", "Spacing between brush daubs as a percentage of brush diameter"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "grad_spacing", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "gradient_spacing"); + RNA_def_property_range(prop, 1, 10000); + RNA_def_property_ui_range(prop, 1, 10000, 5, -1); + RNA_def_property_ui_text(prop, "Gradient Spacing", "Spacing before brush gradient goes full circle"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "smooth_stroke_radius", PROP_INT, PROP_NONE); RNA_def_property_range(prop, 10, 200); RNA_def_property_ui_text(prop, "Smooth Stroke Radius", "Minimum distance from last point before stroke continues"); @@ -791,7 +967,13 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "rgb"); RNA_def_property_ui_text(prop, "Color", ""); RNA_def_property_update(prop, 0, "rna_Brush_update"); - + + prop = RNA_def_property(srna, "secondary_color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_float_sdna(prop, NULL, "secondary_rgb"); + RNA_def_property_ui_text(prop, "Secondary Color", ""); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_range(prop, 0.0f, 1.0f); @@ -884,6 +1066,32 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Mask Stencil Dimensions", "Dimensions of mask stencil in viewport"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "sharp_threshold", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 100.0); + RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 3); + RNA_def_property_float_sdna(prop, NULL, "sharp_threshold"); + RNA_def_property_ui_text(prop, "Sharp Threshold", "Threshold below which, no sharpening is done"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + + prop = RNA_def_property(srna, "fill_threshold", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 100.0); + RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 3); + RNA_def_property_float_sdna(prop, NULL, "fill_threshold"); + RNA_def_property_ui_text(prop, "Fill Threshold", "Threshold above which filling is not propagated"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + + prop = RNA_def_property(srna, "blur_kernel_radius", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "blur_kernel_radius"); + RNA_def_property_range(prop, 1, 10000); + RNA_def_property_ui_range(prop, 1, 50, 1, -1); + RNA_def_property_ui_text(prop, "Kernel Radius", "Radius of kernel used for soften and sharpen in pixels"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + + prop = RNA_def_property(srna, "blur_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, brush_blur_mode_items); + RNA_def_property_ui_text(prop, "Blur Mode", ""); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + /* flag */ prop = RNA_def_property(srna, "use_airbrush", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_AIRBRUSH); @@ -919,7 +1127,13 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0); RNA_def_property_ui_text(prop, "Size Pressure", "Enable tablet pressure sensitivity for size"); RNA_def_property_update(prop, 0, "rna_Brush_update"); - + + prop = RNA_def_property(srna, "use_gradient", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_USE_GRADIENT); + RNA_def_property_boolean_funcs(prop, NULL, "rna_Brush_use_gradient_set"); + RNA_def_property_ui_text(prop, "Use Gradient", "Use Gradient by utilizing a sampling method"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "use_pressure_jitter", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_JITTER_PRESSURE); RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0); @@ -932,6 +1146,12 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Spacing Pressure", "Enable tablet pressure sensitivity for spacing"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "use_pressure_masking", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "mask_pressure"); + RNA_def_property_enum_items(prop, brush_mask_pressure_items); + RNA_def_property_ui_text(prop, "Mask Pressure Mode", "Pen pressure makes texture influence smaller"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "use_inverse_smooth_pressure", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_INVERSE_SMOOTH_PRESSURE); RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0); @@ -974,6 +1194,16 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Space", "Limit brush application to the distance specified by spacing"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "use_line", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_LINE); + RNA_def_property_ui_text(prop, "Line", "Draw a line with dabs separated according to spacing"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + + prop = RNA_def_property(srna, "use_curve", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_CURVE); + RNA_def_property_ui_text(prop, "Curve", "Define the stroke curve with a bezier curve. Dabs are separated according to spacing"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "use_smooth_stroke", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_SMOOTH_STROKE); RNA_def_property_ui_text(prop, "Smooth Stroke", "Brush lags behind mouse and follows a smoother path"); @@ -1015,7 +1245,7 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Edge-to-edge", "Drag anchor brush from edge-to-edge"); RNA_def_property_update(prop, 0, "rna_Brush_update"); - prop = RNA_def_property(srna, "use_drag_dot", PROP_BOOLEAN, PROP_NONE); + prop = RNA_def_property(srna, "use_restore_mesh", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_DRAG_DOT); RNA_def_property_ui_text(prop, "Restore Mesh", "Allow a single dot to be carefully positioned"); RNA_def_property_update(prop, 0, "rna_Brush_update"); @@ -1031,6 +1261,28 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Curve", "Editable falloff curve"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "paint_curve", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Paint Curve", "Active Paint Curve"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + + prop = RNA_def_property(srna, "gradient", PROP_POINTER, PROP_NEVER_NULL); + RNA_def_property_pointer_sdna(prop, NULL, "gradient"); + RNA_def_property_struct_type(prop, "ColorRamp"); + RNA_def_property_ui_text(prop, "Gradient", ""); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + + /* gradient source */ + prop = RNA_def_property(srna, "gradient_stroke_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, brush_gradient_items); + RNA_def_property_ui_text(prop, "Gradient Stroke Mode", ""); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + + prop = RNA_def_property(srna, "gradient_fill_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, brush_gradient_fill_items); + RNA_def_property_ui_text(prop, "Gradient Fill Mode", ""); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + /* overlay flags */ prop = RNA_def_property(srna, "use_primary_overlay", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "overlay_flags", BRUSH_OVERLAY_PRIMARY); @@ -1173,8 +1425,14 @@ static void rna_def_brush(BlenderRNA *brna) prop = RNA_def_property(srna, "sculpt_capabilities", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "SculptToolCapabilities"); - RNA_def_property_pointer_funcs(prop, "rna_Sculpt_sculpt_tool_capabilities_get", NULL, NULL, NULL); + RNA_def_property_pointer_funcs(prop, "rna_Sculpt_tool_capabilities_get", NULL, NULL, NULL); RNA_def_property_ui_text(prop, "Sculpt Capabilities", "Brush's capabilities in sculpt mode"); + + prop = RNA_def_property(srna, "image_paint_capabilities", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); + RNA_def_property_struct_type(prop, "ImapaintToolCapabilities"); + RNA_def_property_pointer_funcs(prop, "rna_Imapaint_tool_capabilities_get", NULL, NULL, NULL); + RNA_def_property_ui_text(prop, "Image Painting Capabilities", "Brush's capabilities in image paint mode"); } @@ -1211,6 +1469,11 @@ static void rna_def_operator_stroke_element(BlenderRNA *brna) RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Pressure", "Tablet pressure"); + prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_NONE); + RNA_def_property_flag(prop, PROP_IDPROPERTY); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_text(prop, "Brush Size", "Brush Size in screen space"); + prop = RNA_def_property(srna, "pen_flip", PROP_BOOLEAN, PROP_NONE); RNA_def_property_flag(prop, PROP_IDPROPERTY); RNA_def_property_ui_text(prop, "Flip", ""); @@ -1237,6 +1500,7 @@ void RNA_def_brush(BlenderRNA *brna) rna_def_brush(brna); rna_def_brush_capabilities(brna); rna_def_sculpt_capabilities(brna); + rna_def_image_paint_capabilities(brna); rna_def_brush_texture_slot(brna); rna_def_operator_stroke_element(brna); } diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c index fdba76e9aa2..4db873423f6 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -176,7 +176,7 @@ static char *rna_ColorRamp_path(PointerRNA *ptr) char *node_path; for (node = ntree->nodes.first; node; node = node->next) { - if (ELEM3(node->type, SH_NODE_VALTORGB, CMP_NODE_VALTORGB, TEX_NODE_VALTORGB)) { + if (ELEM(node->type, SH_NODE_VALTORGB, CMP_NODE_VALTORGB, TEX_NODE_VALTORGB)) { if (node->storage == ptr->data) { /* all node color ramp properties called 'color_ramp' * prepend path from ID to the node @@ -265,7 +265,7 @@ static char *rna_ColorRampElement_path(PointerRNA *ptr) bNode *node; for (node = ntree->nodes.first; node; node = node->next) { - if (ELEM3(node->type, SH_NODE_VALTORGB, CMP_NODE_VALTORGB, TEX_NODE_VALTORGB)) { + if (ELEM(node->type, SH_NODE_VALTORGB, CMP_NODE_VALTORGB, TEX_NODE_VALTORGB)) { RNA_pointer_create(id, &RNA_ColorRamp, node->storage, &ramp_ptr); COLRAMP_GETPATH; } @@ -324,7 +324,7 @@ static void rna_ColorRamp_update(Main *bmain, Scene *UNUSED(scene), PointerRNA * bNode *node; for (node = ntree->nodes.first; node; node = node->next) { - if (ELEM3(node->type, SH_NODE_VALTORGB, CMP_NODE_VALTORGB, TEX_NODE_VALTORGB)) { + if (ELEM(node->type, SH_NODE_VALTORGB, CMP_NODE_VALTORGB, TEX_NODE_VALTORGB)) { ED_node_tag_update_nodetree(bmain, ntree); } } diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 120992cffe8..5519b192ca4 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -351,7 +351,7 @@ static void rna_ActionConstraint_minmax_range(PointerRNA *ptr, float *min, float bActionConstraint *acon = (bActionConstraint *)con->data; /* 0, 1, 2 = magic numbers for rotX, rotY, rotZ */ - if (ELEM3(acon->type, 0, 1, 2)) { + if (ELEM(acon->type, 0, 1, 2)) { *min = -180.0f; *max = 180.0f; } @@ -2452,6 +2452,12 @@ static void rna_def_constraint_follow_track(BlenderRNA *brna) RNA_def_property_enum_items(prop, frame_method_items); RNA_def_property_ui_text(prop, "Frame Method", "How the footage fits in the camera frame"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update"); + + /* use undistortion */ + prop = RNA_def_property(srna, "use_undistorted_position", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", FOLLOWTRACK_USE_UNDISTORTION); + RNA_def_property_ui_text(prop, "Undistort", "Parent to undistorted position of 2D track"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); } static void rna_def_constraint_camera_solver(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index be275058957..83b7a81c649 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -202,6 +202,7 @@ void rna_def_texmat_common(struct StructRNA *srna, const char *texspace_editable void rna_def_mtex_common(struct BlenderRNA *brna, struct StructRNA *srna, const char *begin, const char *activeget, const char *activeset, const char *activeeditable, const char *structname, const char *structname_slots, const char *update, const char *update_index); +void rna_def_texpaint_slots(struct BlenderRNA *brna, struct StructRNA *srna); void rna_def_render_layer_common(struct StructRNA *srna, int scene); void rna_def_actionbone_group_common(struct StructRNA *srna, int update_flag, const char *update_cb); @@ -412,4 +413,24 @@ void rna_RenderPass_rect_set(PointerRNA *ptr, const float *values); # endif #endif +/* C11 for compile time range checks */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) +# define USE_RNA_RANGE_CHECK +# define TYPEOF_MAX(x) \ + _Generic((x), \ + bool: 1, \ + char: CHAR_MAX, signed char: SCHAR_MAX, unsigned char: UCHAR_MAX, \ + signed short: SHRT_MAX, unsigned short: USHRT_MAX, \ + signed int: INT_MAX, unsigned int: UINT_MAX, \ + float: FLT_MAX, double: DBL_MAX) + +# define TYPEOF_MIN(x) \ + _Generic((x), \ + bool: 0, \ + char: CHAR_MIN, signed char: SCHAR_MIN, unsigned char: 0, \ + signed short: SHRT_MIN, unsigned short: 0, \ + signed int: INT_MIN, unsigned int: 0, \ + float: -FLT_MAX, double: -DBL_MAX) +#endif + #endif /* __RNA_INTERNAL_H__ */ diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c index 3ede815b5b1..50b888b0247 100644 --- a/source/blender/makesrna/intern/rna_linestyle.c +++ b/source/blender/makesrna/intern/rna_linestyle.c @@ -500,7 +500,7 @@ static void rna_def_linestyle_mtex(BlenderRNA *brna) prop = RNA_def_property(srna, "use_tips", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "texflag", MTEX_TIPS); - RNA_def_property_ui_text(prop, "Use tips", "Lower half of the texture is for tips of the stroke"); + RNA_def_property_ui_text(prop, "Use Tips", "Lower half of the texture is for tips of the stroke"); RNA_def_property_update(prop, 0, "rna_LineStyle_update"); prop = RNA_def_property(srna, "texture_coords", PROP_ENUM, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index 7ae15b0b06c..70da4ab0fa0 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -82,6 +82,8 @@ EnumPropertyItem ramp_blend_items[] = { #include "DNA_node_types.h" #include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" #include "BKE_context.h" #include "BKE_depsgraph.h" @@ -92,6 +94,8 @@ EnumPropertyItem ramp_blend_items[] = { #include "BKE_paint.h" #include "ED_node.h" +#include "ED_image.h" +#include "BKE_scene.h" static void rna_Material_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { @@ -165,6 +169,50 @@ static void rna_Material_mtex_begin(CollectionPropertyIterator *iter, PointerRNA rna_iterator_array_begin(iter, (void *)ma->mtex, sizeof(MTex *), MAX_MTEX, 0, NULL); } +static void rna_Material_texpaint_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ + Material *ma = (Material *)ptr->data; + rna_iterator_array_begin(iter, (void *)ma->texpaintslot, sizeof(TexPaintSlot), ma->tot_slots, 0, NULL); +} + + +static void rna_Material_active_paint_texture_index_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + bScreen *sc; + Material *ma = ptr->id.data; + + + if (ma->use_nodes && ma->nodetree && BKE_scene_use_new_shading_nodes(scene)) { + struct bNode *node; + int index = 0; + for (node = ma->nodetree->nodes.first; node; node = node->next) { + if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) { + if (index++ == ma->paint_active_slot) { + break; + } + } + } + if (node) + nodeSetActive(ma->nodetree, node); + } + + for (sc = bmain->screen.first; sc; sc = sc->id.next) { + ScrArea *sa; + for (sa = sc->areabase.first; sa; sa = sa->next) { + SpaceLink *sl; + for (sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_IMAGE) { + SpaceImage *sima = (SpaceImage *)sl; + ED_space_image_set(sima, scene, scene->obedit, ma->texpaintslot[ma->paint_active_slot].ima); + } + } + } + } + + DAG_id_tag_update(&ma->id, 0); + WM_main_add_notifier(NC_MATERIAL | ND_SHADING, ma); +} + static PointerRNA rna_Material_active_texture_get(PointerRNA *ptr) { Material *ma = (Material *)ptr->data; @@ -307,7 +355,7 @@ static EnumPropertyItem *rna_Material_texture_coordinates_itemf(bContext *UNUSED if (ma->material_type == MA_TYPE_VOLUME) { } - else if (ELEM3(ma->material_type, MA_TYPE_SURFACE, MA_TYPE_HALO, MA_TYPE_WIRE)) { + else if (ELEM(ma->material_type, MA_TYPE_SURFACE, MA_TYPE_HALO, MA_TYPE_WIRE)) { RNA_enum_items_add_value(&item, &totitem, prop_texture_coordinates_items, TEXCO_UV); RNA_enum_items_add_value(&item, &totitem, prop_texture_coordinates_items, TEXCO_STRAND); RNA_enum_items_add_value(&item, &totitem, prop_texture_coordinates_items, TEXCO_WINDOW); @@ -2059,6 +2107,8 @@ void RNA_def_material(BlenderRNA *brna) "rna_Material_active_texture_set", "rna_Material_active_texture_editable", "MaterialTextureSlot", "MaterialTextureSlots", "rna_Material_update", "rna_Material_update"); + rna_def_texpaint_slots(brna, srna); + /* only material has this one */ prop = RNA_def_property(srna, "use_textures", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "septex", 1); @@ -2147,4 +2197,53 @@ void rna_def_mtex_common(BlenderRNA *brna, StructRNA *srna, const char *begin, RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING_LINKS, update_index); } +static void rna_def_tex_slot(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "TexPaintSlot", NULL); + RNA_def_struct_ui_text(srna, "Texture Paint Slot", + "Slot that contains information about texture painting"); + + prop = RNA_def_property(srna, "uv_layer", PROP_STRING, PROP_NONE); + RNA_def_property_string_maxlength(prop, 64); /* else it uses the pointer size! */ + RNA_def_property_string_sdna(prop, NULL, "uvname"); + RNA_def_property_ui_text(prop, "UV Map", "Name of UV map"); + RNA_def_property_update(prop, NC_GEOM | ND_DATA, "rna_Material_update"); + +} + + +void rna_def_texpaint_slots(BlenderRNA *brna, StructRNA *srna) +{ + PropertyRNA *prop; + + rna_def_tex_slot(brna); + + /* mtex */ + prop = RNA_def_property(srna, "texture_paint_images", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "texpaintslot", NULL); + RNA_def_property_collection_funcs(prop, "rna_Material_texpaint_begin", "rna_iterator_array_next", "rna_iterator_array_end", + "rna_iterator_array_dereference_get", NULL, NULL, NULL, NULL); + RNA_def_property_struct_type(prop, "Image"); + RNA_def_property_ui_text(prop, "Texture Slot Images", "Texture images used for texture painting"); + + prop = RNA_def_property(srna, "texture_paint_slots", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_funcs(prop, "rna_Material_texpaint_begin", "rna_iterator_array_next", "rna_iterator_array_end", + "rna_iterator_array_get", NULL, NULL, NULL, NULL); + RNA_def_property_struct_type(prop, "TexPaintSlot"); + RNA_def_property_ui_text(prop, "Texture Slots", "Texture slots defining the mapping and influence of textures"); + + prop = RNA_def_property(srna, "paint_active_slot", PROP_INT, PROP_UNSIGNED); + RNA_def_property_range(prop, 0, SHRT_MAX); + RNA_def_property_ui_text(prop, "Active Paint Texture Index", "Index of active texture paint slot"); + RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING_LINKS, "rna_Material_active_paint_texture_index_update"); + + prop = RNA_def_property(srna, "paint_clone_slot", PROP_INT, PROP_UNSIGNED); + RNA_def_property_range(prop, 0, SHRT_MAX); + RNA_def_property_ui_text(prop, "Clone Paint Texture Index", "Index of clone texture paint slot"); + RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING_LINKS, NULL); +} + #endif diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 8c0f9980108..b0b99dcd2ca 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -3121,11 +3121,13 @@ static void rna_def_mesh(BlenderRNA *brna) "rna_Mesh_uv_texture_stencil_set", NULL, NULL); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Mask UV Map", "UV map to mask the painted area"); + RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); prop = RNA_def_property(srna, "uv_texture_stencil_index", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_funcs(prop, "rna_Mesh_uv_texture_stencil_index_get", "rna_Mesh_uv_texture_stencil_index_set", "rna_Mesh_uv_texture_index_range"); RNA_def_property_ui_text(prop, "Mask UV Map Index", "Mask UV map index"); + RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); /* Tessellated face colors - used by renderers */ diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 065b6f787b6..8a177c6e2f9 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -6187,6 +6187,27 @@ static void def_cmp_planetrackdeform(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_cmp_sunbeams(StructRNA *srna) +{ + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "NodeSunBeams", "storage"); + + prop = RNA_def_property(srna, "source", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "source"); + RNA_def_property_range(prop, -100.0f, 100.0f); + RNA_def_property_ui_range(prop, -10.0f, 10.0f, 10, 3); + RNA_def_property_ui_text(prop, "Source", "Source point of rays as a factor of the image width & height"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "ray_length", PROP_FLOAT, PROP_UNSIGNED); + RNA_def_property_float_sdna(prop, NULL, "ray_length"); + RNA_def_property_range(prop, 0.0f, 100.0f); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 10, 3); + RNA_def_property_ui_text(prop, "Ray Length", "Length of rays as a factor of the image size"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); +} + /* -- Texture Nodes --------------------------------------------------------- */ static void def_tex_output(StructRNA *srna) diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index 0f37575146b..925672071bb 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -598,9 +598,11 @@ static char *rna_FieldSettings_path(PointerRNA *ptr) static void rna_EffectorWeight_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { - DAG_id_tag_update((ID *)ptr->id.data, OB_RECALC_DATA | PSYS_RECALC_RESET); + Scene *scene = (Scene *)ptr->id.data; + Base *base; - WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); + for (base = scene->base.first; base; base = base->next) + BKE_ptcache_object_reset(scene, base->object, PTCACHE_RESET_DEPSGRAPH); } static void rna_EffectorWeight_dependency_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) @@ -733,7 +735,7 @@ static EnumPropertyItem *rna_Effector_shape_itemf(bContext *UNUSED(C), PointerRN return curve_shape_items; } - else if (ELEM3(ob->type, OB_MESH, OB_SURF, OB_FONT)) { + else if (ELEM(ob->type, OB_MESH, OB_SURF, OB_FONT)) { if (ob->pd->forcefield == PFIELD_VORTEX) return vortex_shape_items; diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 674ea92fcbe..0e56b184990 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -432,25 +432,24 @@ static EnumPropertyItem *rna_Particle_Material_itemf(bContext *C, PointerRNA *UN return item; } -static void rna_ParticleSystem_uv_on_emitter(ParticleSystem *particlesystem, ReportList *reports, - ParticleSystemModifierData *modifier, ParticleData *particle, - int particle_no, int uv_no, - float r_uv[2]) +/* return < 0 means invalid (no matching tessellated face could be found). */ +static int rna_ParticleSystem_tessfaceidx_on_emitter(ParticleSystem *particlesystem, + ParticleSystemModifierData *modifier, ParticleData *particle, + int particle_no, float (**r_fuv)[4]) { ParticleSettings *part = 0; int totpart; int totchild = 0; - int num; + int totface; + int num = -1; - if (!CustomData_has_layer(&modifier->dm->loopData, CD_MLOOPUV)) { - BKE_report(reports, RPT_ERROR, "Mesh has no UV data"); - return; - } DM_ensure_tessface(modifier->dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */ + totface = modifier->dm->getNumTessFaces(modifier->dm); /* 1. check that everything is ok & updated */ - if (particlesystem == NULL) - return; + if (!particlesystem || !totface) { + return num; + } part = particlesystem->part; @@ -468,52 +467,31 @@ static void rna_ParticleSystem_uv_on_emitter(ParticleSystem *particlesystem, Rep totpart = particlesystem->totpart; if (particle_no >= totpart + totchild) - return; + return num; -/* 3. start creating renderable things */ - /* setup per particle individual stuff */ + /* 2. get matching face index. */ if (particle_no < totpart) { - - /* get uvco & mcol */ - num = (ELEM(particle->num_dmcache, DMCACHE_ISCHILD, DMCACHE_NOTFOUND)) ? - particle->num : particle->num_dmcache; + num = (ELEM(particle->num_dmcache, DMCACHE_ISCHILD, DMCACHE_NOTFOUND)) ? particle->num : particle->num_dmcache; if (num == DMCACHE_NOTFOUND) - if (particle->num < modifier->dm->getNumTessFaces(modifier->dm)) - num = particle->num; + num = particle->num; - if (r_uv && ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) { - if (num != DMCACHE_NOTFOUND) { - MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE); - MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, uv_no); - mtface += num; - - psys_interpolate_uvs(mtface, mface->v4, particle->fuv, r_uv); - } - else { - r_uv[0] = 0.0f; - r_uv[1] = 0.0f; + if (ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) { + if (num != DMCACHE_NOTFOUND && num < totface) { + *r_fuv = &particle->fuv; + return num; } } } else { ChildParticle *cpa = particlesystem->child + particle_no - totpart; - num = cpa->num; - /* get uvco & mcol */ if (part->childtype == PART_CHILD_FACES) { - if (r_uv && ELEM(PART_FROM_FACE, PART_FROM_FACE, PART_FROM_VOLUME)) { - if (cpa->num != DMCACHE_NOTFOUND) { - MFace *mface = modifier->dm->getTessFaceData(modifier->dm, cpa->num, CD_MFACE); - MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, uv_no); - mtface += cpa->num; - - psys_interpolate_uvs(mtface, mface->v4, cpa->fuv, r_uv); - } - else { - r_uv[0] = 0.0f; - r_uv[1] = 0.0f; + if (ELEM(PART_FROM_FACE, PART_FROM_FACE, PART_FROM_VOLUME)) { + if (num != DMCACHE_NOTFOUND && num < totface) { + *r_fuv = &cpa->fuv; + return num; } } } @@ -522,137 +500,78 @@ static void rna_ParticleSystem_uv_on_emitter(ParticleSystem *particlesystem, Rep num = parent->num_dmcache; if (num == DMCACHE_NOTFOUND) - if (parent->num < modifier->dm->getNumTessFaces(modifier->dm)) - num = parent->num; - - if (r_uv && ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) { - if (num != DMCACHE_NOTFOUND) { - MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE); - MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, uv_no); - mtface += num; - - psys_interpolate_uvs(mtface, mface->v4, parent->fuv, r_uv); - } - else { - r_uv[0] = 0.0f; - r_uv[1] = 0.0f; + num = parent->num; + + if (ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) { + if (num != DMCACHE_NOTFOUND && num < totface) { + *r_fuv = &parent->fuv; + return num; } } } } + + return -1; } -static void rna_ParticleSystem_mcol_on_emitter(ParticleSystem *particlesystem, ParticleSystemModifierData *modifier, - ParticleData *particle, int particle_no, int vcol_no, - float n_mcol[3]) +static void rna_ParticleSystem_uv_on_emitter(ParticleSystem *particlesystem, ReportList *reports, + ParticleSystemModifierData *modifier, ParticleData *particle, + int particle_no, int uv_no, float r_uv[2]) { - ParticleSettings *part; - int totpart; - int totchild = 0; - int num; - MCol mcol = {255, 255, 255, 255}; - - /* 1. check that everything is ok & updated */ - if (particlesystem == NULL) + if (!CustomData_has_layer(&modifier->dm->loopData, CD_MLOOPUV)) { + BKE_report(reports, RPT_ERROR, "Mesh has no UV data"); + zero_v2(r_uv); return; - - part = particlesystem->part; - - if (particlesystem->renderdata) { - totchild = particlesystem->totchild; - } - else { - totchild = (int)((float)particlesystem->totchild * (float)(part->disp) / 100.0f); } - /* can happen for disconnected/global hair */ - if (part->type == PART_HAIR && !particlesystem->childcache) - totchild = 0; - - totpart = particlesystem->totpart; - - if (particle_no >= totpart + totchild) - return; - - /* 3. start creating renderable things */ - /* setup per particle individual stuff */ - if (particle_no < totpart) { + { + float (*fuv)[4]; + /* Note all sanity checks are done in this helper func. */ + const int num = rna_ParticleSystem_tessfaceidx_on_emitter(particlesystem, modifier, particle, + particle_no, &fuv); - /* get uvco & mcol */ - num = particle->num_dmcache; + if (num < 0) { + /* No matching face found. */ + zero_v2(r_uv); + } + else { + MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE); + MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, uv_no); - if (num == DMCACHE_NOTFOUND) - if (particle->num < modifier->dm->getNumTessFaces(modifier->dm)) - num = particle->num; - - if (n_mcol && ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) { - if (num != DMCACHE_NOTFOUND) { - MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE); - MCol *mc = (MCol *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MCOL, vcol_no); - mc += num * 4; - - psys_interpolate_mcol(mc, mface->v4, particle->fuv, &mcol); - n_mcol[0] = (float)mcol.b / 255.0f; - n_mcol[1] = (float)mcol.g / 255.0f; - n_mcol[2] = (float)mcol.r / 255.0f; - } - else { - n_mcol[0] = 0.0f; - n_mcol[1] = 0.0f; - n_mcol[2] = 0.0f; - } + psys_interpolate_uvs(&mtface[num], mface->v4, *fuv, r_uv); } } - else { - ChildParticle *cpa = particlesystem->child + particle_no - totpart; +} - num = cpa->num; +static void rna_ParticleSystem_mcol_on_emitter(ParticleSystem *particlesystem, ReportList *reports, + ParticleSystemModifierData *modifier, ParticleData *particle, + int particle_no, int vcol_no, float r_mcol[3]) +{ + if (!CustomData_has_layer(&modifier->dm->loopData, CD_MLOOPCOL)) { + BKE_report(reports, RPT_ERROR, "Mesh has no VCol data"); + zero_v3(r_mcol); + return; + } - /* get uvco & mcol */ - if (part->childtype == PART_CHILD_FACES) { - if (n_mcol && ELEM(PART_FROM_FACE, PART_FROM_FACE, PART_FROM_VOLUME)) { - if (cpa->num != DMCACHE_NOTFOUND) { - MFace *mface = modifier->dm->getTessFaceData(modifier->dm, cpa->num, CD_MFACE); - MCol *mc = (MCol *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MCOL, vcol_no); - mc += cpa->num * 4; - - psys_interpolate_mcol(mc, mface->v4, cpa->fuv, &mcol); - n_mcol[0] = (float)mcol.b / 255.0f; - n_mcol[1] = (float)mcol.g / 255.0f; - n_mcol[2] = (float)mcol.r / 255.0f; - } - else { - n_mcol[0] = 0.0f; - n_mcol[1] = 0.0f; - n_mcol[2] = 0.0f; - } - } + { + float (*fuv)[4]; + /* Note all sanity checks are done in this helper func. */ + const int num = rna_ParticleSystem_tessfaceidx_on_emitter(particlesystem, modifier, particle, + particle_no, &fuv); + + if (num < 0) { + /* No matching face found. */ + zero_v3(r_mcol); } else { - ParticleData *parent = particlesystem->particles + cpa->parent; - num = parent->num_dmcache; - - if (num == DMCACHE_NOTFOUND) - if (parent->num < modifier->dm->getNumTessFaces(modifier->dm)) - num = parent->num; - - if (n_mcol && ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) { - if (num != DMCACHE_NOTFOUND) { - MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE); - MCol *mc = (MCol *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MCOL, vcol_no); - mc += num * 4; - - psys_interpolate_mcol(mc, mface->v4, parent->fuv, &mcol); - n_mcol[0] = (float)mcol.b / 255.0f; - n_mcol[1] = (float)mcol.g / 255.0f; - n_mcol[2] = (float)mcol.r / 255.0f; - } - else { - n_mcol[0] = 0.0f; - n_mcol[1] = 0.0f; - n_mcol[2] = 0.0f; - } - } + MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE); + MCol *mc = (MCol *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MCOL, vcol_no); + MCol mcol; + + psys_interpolate_mcol(&mc[num * 4], mface->v4, *fuv, &mcol); + r_mcol[0] = (float)mcol.b / 255.0f; + r_mcol[1] = (float)mcol.g / 255.0f; + r_mcol[2] = (float)mcol.r / 255.0f; } } } @@ -2520,7 +2439,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "simplify_refsize", PROP_INT, PROP_PIXEL); RNA_def_property_int_sdna(prop, NULL, "simplify_refsize"); - RNA_def_property_range(prop, 1, 32768); + RNA_def_property_range(prop, 1, SHRT_MAX); RNA_def_property_ui_text(prop, "Reference Size", "Reference size in pixels, after which simplification begins"); prop = RNA_def_property(srna, "simplify_rate", PROP_FLOAT, PROP_NONE); @@ -3496,6 +3415,7 @@ static void rna_def_particle_system(BlenderRNA *brna) /* extract hair mcols */ func = RNA_def_function(srna, "mcol_on_emitter", "rna_ParticleSystem_mcol_on_emitter"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Obtain mcol for all particles"); prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier"); RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 06c39938f30..3dafd00d3f5 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -880,7 +880,7 @@ static EnumPropertyItem *rna_ImageFormatSettings_color_depth_itemf(bContext *UNU } else { const int depth_ok = BKE_imtype_valid_depths(imf->imtype); - const int is_float = ELEM3(imf->imtype, R_IMF_IMTYPE_RADHDR, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER); + const int is_float = ELEM(imf->imtype, R_IMF_IMTYPE_RADHDR, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER); EnumPropertyItem *item_8bit = &image_color_depth_items[0]; EnumPropertyItem *item_10bit = &image_color_depth_items[1]; @@ -1316,7 +1316,7 @@ static void object_simplify_update(Object *ob) ob->id.flag &= ~LIB_DOIT; for (md = ob->modifiers.first; md; md = md->next) { - if (ELEM3(md->type, eModifierType_Subsurf, eModifierType_Multires, eModifierType_ParticleSystem)) { + if (ELEM(md->type, eModifierType_Subsurf, eModifierType_Multires, eModifierType_ParticleSystem)) { DAG_id_tag_update(&ob->id, OB_RECALC_DATA); } } @@ -2121,6 +2121,11 @@ static void rna_def_unified_paint_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Use Unified Weight", "Instead of per-brush weight, the weight is shared across brushes"); + prop = RNA_def_property(srna, "use_unified_color", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", UNIFIED_PAINT_COLOR); + RNA_def_property_ui_text(prop, "Use Unified Color", + "Instead of per-brush color, the color is shared across brushes"); + /* unified paint settings that override the equivalent settings * from the active brush */ prop = RNA_def_property(srna, "size", PROP_INT, PROP_PIXEL); @@ -2153,6 +2158,18 @@ static void rna_def_unified_paint_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Weight", "Weight to assign in vertex groups"); RNA_def_property_update(prop, 0, "rna_UnifiedPaintSettings_update"); + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_float_sdna(prop, NULL, "rgb"); + RNA_def_property_ui_text(prop, "Color", ""); + RNA_def_property_update(prop, 0, "rna_UnifiedPaintSettings_update"); + + prop = RNA_def_property(srna, "secondary_color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_float_sdna(prop, NULL, "secondary_rgb"); + RNA_def_property_ui_text(prop, "Secondary Color", ""); + RNA_def_property_update(prop, 0, "rna_UnifiedPaintSettings_update"); + prop = RNA_def_property(srna, "use_pressure_size", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", UNIFIED_PAINT_BRUSH_SIZE_PRESSURE); RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0); @@ -5622,7 +5639,7 @@ void RNA_def_scene(BlenderRNA *brna) prop = RNA_def_property(srna, "gravity", PROP_FLOAT, PROP_ACCELERATION); RNA_def_property_float_sdna(prop, NULL, "physics_settings.gravity"); RNA_def_property_array(prop, 3); - RNA_def_property_range(prop, -200.0f, 200.0f); + RNA_def_property_ui_range(prop, -200.0f, 200.0f, 1, 2); RNA_def_property_ui_text(prop, "Gravity", "Constant acceleration in a given direction"); RNA_def_property_update(prop, 0, "rna_Physics_update"); diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index a3a06893522..af6cf493f1e 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -285,8 +285,67 @@ static void rna_Paint_brush_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Po BKE_paint_invalidate_overlay_all(); WM_main_add_notifier(NC_BRUSH | NA_EDITED, br); } + +static void rna_ImaPaint_stencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) +{ + /* not the best solution maybe, but will refresh the 3D viewport */ + WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); +} #else +static void rna_def_palettecolor(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "PaletteColor", NULL); + RNA_def_struct_ui_text(srna, "Palette Color", ""); + + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_float_sdna(prop, NULL, "rgb"); + RNA_def_property_ui_text(prop, "Color", ""); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_float_sdna(prop, NULL, "value"); + RNA_def_property_ui_text(prop, "Value", ""); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_float_sdna(prop, NULL, "value"); + RNA_def_property_ui_text(prop, "Weight", ""); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); +} + + +static void rna_def_palette(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "Palette", "ID"); + RNA_def_struct_ui_text(srna, "Palette", ""); + RNA_def_struct_ui_icon(srna, ICON_COLOR); + + prop = RNA_def_property(srna, "colors", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "PaletteColor"); + RNA_def_property_ui_text(prop, "Palette Color", "Colors that are part of this palette"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); +} + +static void rna_def_paint_curve(BlenderRNA *brna) +{ + StructRNA *srna; + + srna = RNA_def_struct(brna, "PaintCurve", "ID"); + RNA_def_struct_ui_text(srna, "Paint Curve", ""); + RNA_def_struct_ui_icon(srna, ICON_CURVE_BEZCURVE); +} + + static void rna_def_paint(BlenderRNA *brna) { StructRNA *srna; @@ -302,6 +361,11 @@ static void rna_def_paint(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Brush", "Active Brush"); RNA_def_property_update(prop, 0, "rna_Paint_brush_update"); + prop = RNA_def_property(srna, "palette", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, NULL); + RNA_def_property_ui_text(prop, "Palette", "Active Palette"); + prop = RNA_def_property(srna, "show_brush", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_SHOW_BRUSH); RNA_def_property_ui_text(prop, "Show Brush", ""); @@ -532,12 +596,24 @@ static void rna_def_image_paint(BlenderRNA *brna) prop = RNA_def_property(srna, "use_stencil_layer", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMAGEPAINT_PROJECT_LAYER_STENCIL); RNA_def_property_ui_text(prop, "Stencil Layer", "Set the mask layer from the UV map buttons"); - RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_stencil_update"); prop = RNA_def_property(srna, "invert_stencil", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMAGEPAINT_PROJECT_LAYER_STENCIL_INV); RNA_def_property_ui_text(prop, "Invert", "Invert the stencil layer"); - RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_stencil_update"); + + prop = RNA_def_property(srna, "stencil_image", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "stencil"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Stencil Image", "Image used as stencil"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_stencil_update"); + + prop = RNA_def_property(srna, "stencil_color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_float_sdna(prop, NULL, "stencil_col"); + RNA_def_property_ui_text(prop, "Stencil Color", "Stencil color in the viewport"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_stencil_update"); prop = RNA_def_property(srna, "use_clone_layer", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", IMAGEPAINT_PROJECT_LAYER_CLONE); @@ -741,6 +817,9 @@ void RNA_def_sculpt_paint(BlenderRNA *brna) { /* *** Non-Animated *** */ RNA_define_animate_sdna(false); + rna_def_palettecolor(brna); + rna_def_palette(brna); + rna_def_paint_curve(brna); rna_def_paint(brna); rna_def_sculpt(brna); rna_def_uv_sculpt(brna); diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index ddae8b2a01a..00f0a6ff487 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -539,6 +539,8 @@ static StructRNA *rna_Sequence_refine(struct PointerRNA *ptr) return &RNA_ColorSequence; case SEQ_TYPE_SPEED: return &RNA_SpeedControlSequence; + case SEQ_TYPE_GAUSSIAN_BLUR: + return &RNA_GaussianBlurSequence; default: return &RNA_Sequence; } @@ -1374,6 +1376,7 @@ static void rna_def_sequence(BlenderRNA *brna) {SEQ_TYPE_SPEED, "SPEED", 0, "Speed", ""}, {SEQ_TYPE_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""}, {SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""}, + {SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""}, {0, NULL, 0, NULL, NULL} }; @@ -2203,6 +2206,23 @@ static void rna_def_speed_control(StructRNA *srna) RNA_def_property_boolean_sdna(prop, NULL, "flags", SEQ_SPEED_COMPRESS_IPO_Y); RNA_def_property_ui_text(prop, "Scale to length", "Scale values from 0.0 to 1.0 to target sequence length"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); + +} + +static void rna_def_gaussian_blur(StructRNA *srna) +{ + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "GaussianBlurVars", "effectdata"); + prop = RNA_def_property(srna, "size_x", PROP_FLOAT, PROP_UNSIGNED); + RNA_def_property_ui_text(prop, "Size X", "Size of the blur along X axis"); + RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, -1); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); + + prop = RNA_def_property(srna, "size_y", PROP_FLOAT, PROP_UNSIGNED); + RNA_def_property_ui_text(prop, "Size Y", "Size of the blur along Y axis"); + RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, -1); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); } static EffectInfo def_effects[] = { @@ -2227,6 +2247,8 @@ static EffectInfo def_effects[] = { "Sequence strip applying affine transformations to other strips", rna_def_transform, 1}, {"WipeSequence", "Wipe Sequence", "Sequence strip creating a wipe transition", rna_def_wipe, 1}, + {"GaussianBlurSequence", "Gaussian Blur Sequence", "Sequence strip creating a gaussian blur", + rna_def_gaussian_blur, 1}, {"", "", "", NULL, 0} }; diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c index 30fcb63169b..70370f1ae36 100644 --- a/source/blender/makesrna/intern/rna_sequencer_api.c +++ b/source/blender/makesrna/intern/rna_sequencer_api.c @@ -468,6 +468,7 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop) {SEQ_TYPE_SPEED, "SPEED", 0, "Speed", ""}, {SEQ_TYPE_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""}, {SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""}, + {SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""}, {0, NULL, 0, NULL, NULL} }; diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 39d6e665077..0ddc63e57cf 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -87,6 +87,18 @@ EnumPropertyItem space_type_items[] = { {0, NULL, 0, NULL, NULL} }; +static EnumPropertyItem pivot_items_full[] = { + {V3D_CENTER, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center", + "Pivot around bounding box center of selected object(s)"}, + {V3D_CURSOR, "CURSOR", ICON_CURSOR, "3D Cursor", "Pivot around the 3D cursor"}, + {V3D_LOCAL, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION, + "Individual Origins", "Pivot around each object's own origin"}, + {V3D_CENTROID, "MEDIAN_POINT", ICON_ROTATECENTER, "Median Point", + "Pivot around the median point of selected objects"}, + {V3D_ACTIVE, "ACTIVE_ELEMENT", ICON_ROTACTIVE, "Active Element", "Pivot around active object"}, + {0, NULL, 0, NULL, NULL} +}; + static EnumPropertyItem draw_channels_items[] = { {SI_USE_ALPHA, "COLOR_ALPHA", ICON_IMAGE_RGB_ALPHA, "Color and Alpha", "Draw image with RGB colors and alpha transparency"}, @@ -454,12 +466,12 @@ static void rna_SpaceView3D_layer_update(Main *bmain, Scene *UNUSED(scene), Poin DAG_on_visible_update(bmain, false); } -static void rna_SpaceView3D_viewport_shade_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_SpaceView3D_viewport_shade_update(Main *bmain, Scene *scene, PointerRNA *ptr) { View3D *v3d = (View3D *)(ptr->data); ScrArea *sa = rna_area_from_space(ptr); - ED_view3d_shade_update(bmain, v3d, sa); + ED_view3d_shade_update(bmain, scene, v3d, sa); } static void rna_SpaceView3D_matcap_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) @@ -616,9 +628,7 @@ static int rna_SpaceView3D_viewport_shade_get(PointerRNA *ptr) View3D *v3d = (View3D *)ptr->data; int drawtype = v3d->drawtype; - if (drawtype == OB_MATERIAL && !BKE_scene_use_new_shading_nodes(scene)) - return OB_SOLID; - else if (drawtype == OB_RENDER && !(type && type->view_draw)) + if (drawtype == OB_RENDER && !(type && type->view_draw)) return OB_SOLID; return drawtype; @@ -637,9 +647,7 @@ static EnumPropertyItem *rna_SpaceView3D_viewport_shade_itemf(bContext *UNUSED(C RNA_enum_items_add_value(&item, &totitem, viewport_shade_items, OB_WIRE); RNA_enum_items_add_value(&item, &totitem, viewport_shade_items, OB_SOLID); RNA_enum_items_add_value(&item, &totitem, viewport_shade_items, OB_TEXTURE); - - if (BKE_scene_use_new_shading_nodes(scene)) - RNA_enum_items_add_value(&item, &totitem, viewport_shade_items, OB_MATERIAL); + RNA_enum_items_add_value(&item, &totitem, viewport_shade_items, OB_MATERIAL); if (type && type->view_draw) RNA_enum_items_add_value(&item, &totitem, viewport_shade_items, OB_RENDER); @@ -803,6 +811,24 @@ static void rna_SpaceImageEditor_scopes_update(Main *UNUSED(bmain), Scene *scene ED_space_image_release_buffer(sima, ibuf, lock); } +static EnumPropertyItem *rna_SpaceImageEditor_pivot_itemf(bContext *UNUSED(C), PointerRNA *ptr, + PropertyRNA *UNUSED(prop), bool *UNUSED(r_free)) +{ + static EnumPropertyItem pivot_items[] = { + {V3D_CENTER, "CENTER", ICON_ROTATE, "Bounding Box Center", ""}, + {V3D_CENTROID, "MEDIAN", ICON_ROTATECENTER, "Median Point", ""}, + {V3D_CURSOR, "CURSOR", ICON_CURSOR, "2D Cursor", ""}, + {0, NULL, 0, NULL, NULL} + }; + + SpaceImage *sima = (SpaceImage *)ptr->data; + + if (sima->mode == SI_MODE_PAINT) + return pivot_items_full; + else + return pivot_items; +} + /* Space Text Editor */ static void rna_SpaceTextEditor_word_wrap_set(PointerRNA *ptr, int value) @@ -1492,6 +1518,11 @@ static void rna_def_space_image_uv(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Draw Other Objects", "Draw other selected objects that share the same image"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL); + prop = RNA_def_property(srna, "show_texpaint", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SI_NO_DRAW_TEXPAINT); + RNA_def_property_ui_text(prop, "Draw Texture Paint UVs", "Draw overlay of texture paint uv layer"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL); + prop = RNA_def_property(srna, "show_normalized_coords", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SI_COORDFLOATS); RNA_def_property_ui_text(prop, "Normalized Coordinates", @@ -1752,18 +1783,6 @@ static void rna_def_space_view3d(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; - static EnumPropertyItem pivot_items[] = { - {V3D_CENTER, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center", - "Pivot around bounding box center of selected object(s)"}, - {V3D_CURSOR, "CURSOR", ICON_CURSOR, "3D Cursor", "Pivot around the 3D cursor"}, - {V3D_LOCAL, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION, - "Individual Origins", "Pivot around each object's own origin"}, - {V3D_CENTROID, "MEDIAN_POINT", ICON_ROTATECENTER, "Median Point", - "Pivot around the median point of selected objects"}, - {V3D_ACTIVE, "ACTIVE_ELEMENT", ICON_ROTACTIVE, "Active Element", "Pivot around active object"}, - {0, NULL, 0, NULL, NULL} - }; - static EnumPropertyItem manipulators_items[] = { {V3D_MANIP_TRANSLATE, "TRANSLATE", ICON_MAN_TRANS, "Manipulator Translate", "Use the manipulator for movement transformations"}, @@ -2042,7 +2061,7 @@ static void rna_def_space_view3d(BlenderRNA *brna) prop = RNA_def_property(srna, "pivot_point", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "around"); - RNA_def_property_enum_items(prop, pivot_items); + RNA_def_property_enum_items(prop, pivot_items_full); RNA_def_property_ui_text(prop, "Pivot Point", "Pivot center for rotation/scaling"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_pivot_update"); @@ -2310,13 +2329,6 @@ static void rna_def_space_image(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; - static EnumPropertyItem pivot_items[] = { - {V3D_CENTER, "CENTER", ICON_ROTATE, "Bounding Box Center", ""}, - {V3D_CENTROID, "MEDIAN", ICON_ROTATECENTER, "Median Point", ""}, - {V3D_CURSOR, "CURSOR", ICON_CURSOR, "2D Cursor", ""}, - {0, NULL, 0, NULL, NULL} - }; - StructRNA *srna; PropertyRNA *prop; @@ -2404,7 +2416,8 @@ static void rna_def_space_image(BlenderRNA *brna) prop = RNA_def_property(srna, "pivot_point", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "around"); - RNA_def_property_enum_items(prop, pivot_items); + RNA_def_property_enum_items(prop, pivot_items_full); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_SpaceImageEditor_pivot_itemf"); RNA_def_property_ui_text(prop, "Pivot", "Rotation/Scaling Pivot"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL); diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c index 537ffe630a2..899da62d9d3 100644 --- a/source/blender/makesrna/intern/rna_tracking.c +++ b/source/blender/makesrna/intern/rna_tracking.c @@ -393,6 +393,7 @@ static void rna_tracking_flushUpdate(Main *UNUSED(bmain), Scene *scene, PointerR nodeUpdateID(scene->nodetree, &clip->id); WM_main_add_notifier(NC_SCENE | ND_NODES, NULL); + WM_main_add_notifier(NC_SCENE, NULL); DAG_id_tag_update(&clip->id, 0); } diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index d3d17a90f99..da3d7b029ed 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -740,6 +740,11 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_boolean(func, "lock_luminosity", false, "", "Keep the color at its original vector length"); RNA_def_boolean(func, "cubic", false, "", "Cubic saturation for picking values close to white"); + func = RNA_def_function(srna, "template_palette", "uiTemplatePalette"); + RNA_def_function_ui_description(func, "Item. A palette used to pick colors"); + api_ui_item_rna_common(func); + RNA_def_boolean(func, "color", 0, "", "Display the colors as colors or values"); + func = RNA_def_function(srna, "template_image_layers", "uiTemplateImageLayers"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); parm = RNA_def_pointer(func, "image", "Image", "", ""); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 3a9b3e539d1..850e68d3d90 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -91,6 +91,7 @@ EnumPropertyItem navigation_mode_items[] = { #include "BKE_idprop.h" #include "GPU_draw.h" +#include "GPU_select.h" #include "BLF_api.h" @@ -332,6 +333,11 @@ static void rna_UserDef_viewport_lights_update(Main *bmain, Scene *scene, Pointe rna_userdef_update(bmain, scene, ptr); } +static int rna_Scene_GPU_selection_supported(UserDef *UNUSED(U)) +{ + return GPU_select_query_check_support(); +} + static void rna_userdef_autosave_update(Main *bmain, Scene *scene, PointerRNA *ptr) { wmWindowManager *wm = bmain->wm.first; @@ -1292,7 +1298,23 @@ static void rna_def_userdef_theme_spaces_face(StructRNA *srna) RNA_def_property_update(prop, 0, "rna_userdef_update"); } -static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, bool incl_nurbs, bool incl_lastsel, bool incl_vector) +static void rna_def_userdef_theme_spaces_paint_curves(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "paint_curve_handle", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Paint Curve Handle", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "paint_curve_pivot", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Paint Curve Pivot", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); +} + +static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, bool incl_nurbs, bool incl_lastsel, + bool incl_vector, bool incl_verthandle) { PropertyRNA *prop; @@ -1377,8 +1399,8 @@ static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, bool incl_nurbs RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Align handle selected color", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - - if (incl_nurbs == false) { + + if (!incl_nurbs) { /* assume that when nurbs are off, this is for 2D (i.e. anim) editors */ prop = RNA_def_property(srna, "handle_auto_clamped", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "handle_auto_clamped"); @@ -1400,6 +1422,23 @@ static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, bool incl_nurbs RNA_def_property_ui_text(prop, "Last selected point", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); } + + if (incl_verthandle) { + prop = RNA_def_property(srna, "handle_vertex", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Handle Vertex", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "handle_vertex_select", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Handle Vertex Select", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "handle_vertex_size", PROP_INT, PROP_NONE); + RNA_def_property_range(prop, 0, 255); + RNA_def_property_ui_text(prop, "Handle Vertex Size", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + } } static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna) @@ -1488,7 +1527,7 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna) rna_def_userdef_theme_spaces_vertex(srna); rna_def_userdef_theme_spaces_edge(srna); rna_def_userdef_theme_spaces_face(srna); - rna_def_userdef_theme_spaces_curves(srna, true, true, true); + rna_def_userdef_theme_spaces_curves(srna, true, true, true, false); prop = RNA_def_property(srna, "extra_edge_len", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_array(prop, 3); @@ -1567,6 +1606,8 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna) RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Skin Root", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); + + rna_def_userdef_theme_spaces_paint_curves(srna); } @@ -1632,22 +1673,7 @@ static void rna_def_userdef_theme_space_graph(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_userdef_update"); rna_def_userdef_theme_spaces_vertex(srna); - rna_def_userdef_theme_spaces_curves(srna, false, true, true); - - prop = RNA_def_property(srna, "handle_vertex", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Handle Vertex", ""); - RNA_def_property_update(prop, 0, "rna_userdef_update"); - - prop = RNA_def_property(srna, "handle_vertex_select", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Handle Vertex Select", ""); - RNA_def_property_update(prop, 0, "rna_userdef_update"); - - prop = RNA_def_property(srna, "handle_vertex_size", PROP_INT, PROP_NONE); - RNA_def_property_range(prop, 0, 255); - RNA_def_property_ui_text(prop, "Handle Vertex Size", ""); - RNA_def_property_update(prop, 0, "rna_userdef_update"); + rna_def_userdef_theme_spaces_curves(srna, false, true, true, true); } static void rna_def_userdef_theme_space_file(BlenderRNA *brna) @@ -2258,7 +2284,9 @@ static void rna_def_userdef_theme_space_image(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Current Frame", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - rna_def_userdef_theme_spaces_curves(srna, false, false, false); + rna_def_userdef_theme_spaces_curves(srna, false, false, false, true); + + rna_def_userdef_theme_spaces_paint_curves(srna); } static void rna_def_userdef_theme_space_seq(BlenderRNA *brna) @@ -2745,21 +2773,6 @@ static void rna_def_userdef_theme_space_clip(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Current Frame", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop = RNA_def_property(srna, "handle_vertex", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Handle Vertex", ""); - RNA_def_property_update(prop, 0, "rna_userdef_update"); - - prop = RNA_def_property(srna, "handle_vertex_select", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Handle Vertex Select", ""); - RNA_def_property_update(prop, 0, "rna_userdef_update"); - - prop = RNA_def_property(srna, "handle_vertex_size", PROP_INT, PROP_NONE); - RNA_def_property_range(prop, 0, 255); - RNA_def_property_ui_text(prop, "Handle Vertex Size", ""); - RNA_def_property_update(prop, 0, "rna_userdef_update"); - prop = RNA_def_property(srna, "strips", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "strip"); RNA_def_property_array(prop, 3); @@ -2772,7 +2785,7 @@ static void rna_def_userdef_theme_space_clip(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Strips Selected", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - rna_def_userdef_theme_spaces_curves(srna, false, false, false); + rna_def_userdef_theme_spaces_curves(srna, false, false, false, true); } static void rna_def_userdef_themes(BlenderRNA *brna) @@ -3141,7 +3154,7 @@ static void rna_def_userdef_view(BlenderRNA *brna) /* display */ prop = RNA_def_property(srna, "show_tooltips", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_TOOLTIPS); - RNA_def_property_ui_text(prop, "Tooltips", "Display tooltips"); + RNA_def_property_ui_text(prop, "Tooltips", "Display tooltips (when off hold Alt to force display)"); prop = RNA_def_property(srna, "show_tooltips_python", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", USER_TOOLTIPS_PYTHON); @@ -3569,7 +3582,9 @@ static void rna_def_userdef_edit(BlenderRNA *brna) static void rna_def_userdef_system(BlenderRNA *brna) { + FunctionRNA *func; PropertyRNA *prop; + PropertyRNA *parm; StructRNA *srna; static EnumPropertyItem gl_texture_clamp_items[] = { @@ -3689,6 +3704,13 @@ static void rna_def_userdef_system(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem gpu_select_method_items[] = { + {USER_SELECT_AUTO, "AUTO", 0, "Automatic", ""}, + {USER_SELECT_USE_SELECT_RENDERMODE, "GL_SELECT", 0, "OpenGL Select", ""}, + {USER_SELECT_USE_OCCLUSION_QUERY, "GL_QUERY", 0, "OpenGL Occlusion Queries", ""}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "UserPreferencesSystem", NULL); RNA_def_struct_sdna(srna, "UserDef"); RNA_def_struct_nested(brna, srna, "UserPreferences"); @@ -3931,12 +3953,24 @@ static void rna_def_userdef_system(BlenderRNA *brna) RNA_def_property_boolean_negative_sdna(prop, NULL, "text_render", USER_TEXT_DISABLE_AA); RNA_def_property_ui_text(prop, "Text Anti-aliasing", "Draw user interface text anti-aliased"); RNA_def_property_update(prop, 0, "rna_userdef_text_update"); - + + func = RNA_def_function(srna, "is_occlusion_query_supported", "rna_Scene_GPU_selection_supported"); + parm = RNA_def_boolean(func, "is_supported", 0, "Occlusion Query Support", + "Check if GPU supports Occlusion Queries"); + RNA_def_function_return(func, parm); + + prop = RNA_def_property(srna, "select_method", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "gpu_select_method"); + RNA_def_property_enum_items(prop, gpu_select_method_items); + RNA_def_property_ui_text(prop, "Selection Method", + "Use OpenGL occlusion queries or selection render mode to accelerate selection"); + /* Full scene anti-aliasing */ prop = RNA_def_property(srna, "multi_sample", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "ogl_multisamples"); RNA_def_property_enum_items(prop, multi_sample_levels); - RNA_def_property_ui_text(prop, "MultiSample", "Enable OpenGL multi-sampling, only for systems that support it, requires restart"); + RNA_def_property_ui_text(prop, "MultiSample", + "Enable OpenGL multi-sampling, only for systems that support it, requires restart"); prop = RNA_def_property(srna, "use_region_overlap", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag2", USER_REGION_OVERLAP); diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index 0a4a6140c02..085834de602 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -370,9 +370,8 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd, else unit_m4(obinv); - mul_serie_m4(result_mat, offset, - obinv, amd->offset_ob->obmat, - NULL, NULL, NULL, NULL, NULL); + mul_m4_series(result_mat, offset, + obinv, amd->offset_ob->obmat); copy_m4_m4(offset, result_mat); } diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c index c89bc8c1d41..f6d7c03df32 100644 --- a/source/blender/modifiers/intern/MOD_hook.c +++ b/source/blender/modifiers/intern/MOD_hook.c @@ -156,8 +156,7 @@ static void deformVerts_do(HookModifierData *hmd, Object *ob, DerivedMesh *dm, copy_m4_m4(dmat, hmd->object->obmat); } invert_m4_m4(ob->imat, ob->obmat); - mul_serie_m4(mat, ob->imat, dmat, hmd->parentinv, - NULL, NULL, NULL, NULL, NULL); + mul_m4_series(mat, ob->imat, dmat, hmd->parentinv); modifier_get_vgroup(ob, dm, hmd->name, &dvert, &defgrp_index); max_dvert = (dvert) ? numVerts : 0; diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c index 7f21376ef48..838336a8f8a 100644 --- a/source/blender/modifiers/intern/MOD_mask.c +++ b/source/blender/modifiers/intern/MOD_mask.c @@ -153,7 +153,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, const int defbase_tot = BLI_countlist(&ob->defbase); /* check that there is armature object with bones to use, otherwise return original mesh */ - if (ELEM3(NULL, oba, oba->pose, ob->defbase.first)) + if (ELEM(NULL, oba, oba->pose, ob->defbase.first)) return dm; /* determine whether each vertexgroup is associated with a selected bone or not diff --git a/source/blender/modifiers/intern/MOD_meshcache_mdd.c b/source/blender/modifiers/intern/MOD_meshcache_mdd.c index 0cbf07ca907..90fc750de3b 100644 --- a/source/blender/modifiers/intern/MOD_meshcache_mdd.c +++ b/source/blender/modifiers/intern/MOD_meshcache_mdd.c @@ -30,9 +30,11 @@ #include "BLI_sys_types.h" #include "BLI_utildefines.h" -#include "BLI_endian_switch.h" #include "BLI_fileops.h" #include "BLI_math.h" +#ifdef __LITTLE_ENDIAN__ +# include "BLI_endian_switch.h" +#endif #include "MOD_meshcache_util.h" /* own include */ diff --git a/source/blender/modifiers/intern/MOD_meshcache_pc2.c b/source/blender/modifiers/intern/MOD_meshcache_pc2.c index ac0363f8673..3ef0ee54886 100644 --- a/source/blender/modifiers/intern/MOD_meshcache_pc2.c +++ b/source/blender/modifiers/intern/MOD_meshcache_pc2.c @@ -32,6 +32,9 @@ #include "BLI_utildefines.h" #include "BLI_fileops.h" #include "BLI_math.h" +#ifdef __BIG_ENDIAN__ +# include "BLI_endian_switch.h" +#endif #include "MOD_meshcache_util.h" /* own include */ diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c index eebb687aa8d..229f4911ab4 100644 --- a/source/blender/modifiers/intern/MOD_shrinkwrap.c +++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c @@ -37,6 +37,7 @@ #include "DNA_object_types.h" +#include "BLI_math.h" #include "BLI_string.h" #include "BLI_utildefines.h" diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c index ccba2097264..3314196b776 100644 --- a/source/blender/modifiers/intern/MOD_simpledeform.c +++ b/source/blender/modifiers/intern/MOD_simpledeform.c @@ -42,7 +42,6 @@ #include "BKE_cdderivedmesh.h" #include "BKE_modifier.h" #include "BKE_deform.h" -#include "BKE_shrinkwrap.h" #include "depsgraph_private.h" @@ -166,7 +165,7 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object /* Calculate matrixs do convert between coordinate spaces */ if (smd->origin) { transf = &tmp_transf; - space_transform_from_matrixs(transf, ob->obmat, smd->origin->obmat); + BLI_SPACE_TRANSFORM_SETUP(transf, ob, smd->origin); } /* Setup vars, @@ -182,7 +181,9 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object float tmp[3]; copy_v3_v3(tmp, vertexCos[i]); - if (transf) space_transform_apply(transf, tmp); + if (transf) { + BLI_space_transform_apply(transf, tmp); + } lower = min_ff(lower, tmp[limit_axis]); upper = max_ff(upper, tmp[limit_axis]); @@ -220,7 +221,7 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object float co[3], dcut[3] = {0.0f, 0.0f, 0.0f}; if (transf) { - space_transform_apply(transf, vertexCos[i]); + BLI_space_transform_apply(transf, vertexCos[i]); } copy_v3_v3(co, vertexCos[i]); @@ -236,7 +237,7 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object interp_v3_v3v3(vertexCos[i], vertexCos[i], co, weight); /* Use vertex weight has coef of linear interpolation */ if (transf) { - space_transform_invert(transf, vertexCos[i]); + BLI_space_transform_invert(transf, vertexCos[i]); } } } diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c index 386d6d985fb..829c2b88995 100644 --- a/source/blender/modifiers/intern/MOD_util.c +++ b/source/blender/modifiers/intern/MOD_util.c @@ -198,7 +198,7 @@ DerivedMesh *get_dm(Object *ob, struct BMEditMesh *em, DerivedMesh *dm, DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, BKE_mesh_orco_verts_get(ob)); } } - else if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { + else if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { dm = CDDM_from_curve(ob); } diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c index 12ecae8ad4f..744b6b62c2a 100644 --- a/source/blender/modifiers/intern/MOD_weightvg_util.c +++ b/source/blender/modifiers/intern/MOD_weightvg_util.c @@ -66,9 +66,9 @@ void weightvg_do_map(int num, float *new_w, short falloff_type, CurveMapping *cm /* Return immediately, if we have nothing to do! */ /* Also security checks... */ if (((falloff_type == MOD_WVG_MAPPING_CURVE) && (cmap == NULL)) || - !ELEM7(falloff_type, MOD_WVG_MAPPING_CURVE, MOD_WVG_MAPPING_SHARP, MOD_WVG_MAPPING_SMOOTH, - MOD_WVG_MAPPING_ROOT, MOD_WVG_MAPPING_SPHERE, MOD_WVG_MAPPING_RANDOM, - MOD_WVG_MAPPING_STEP)) + !ELEM(falloff_type, MOD_WVG_MAPPING_CURVE, MOD_WVG_MAPPING_SHARP, MOD_WVG_MAPPING_SMOOTH, + MOD_WVG_MAPPING_ROOT, MOD_WVG_MAPPING_SPHERE, MOD_WVG_MAPPING_RANDOM, + MOD_WVG_MAPPING_STEP)) { return; } diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index f5ae8561300..010fe1d5a29 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -43,7 +43,6 @@ #include "BKE_deform.h" #include "BKE_library.h" #include "BKE_modifier.h" -#include "BKE_shrinkwrap.h" /* For SpaceTransform stuff. */ #include "BKE_texture.h" /* Texture masking. */ #include "depsgraph_private.h" @@ -73,12 +72,12 @@ static void get_vert2geom_distance(int numVerts, float (*v_cos)[3], DerivedMesh *target, const SpaceTransform *loc2trgt) { int i; - BVHTreeFromMesh treeData_v = NULL_BVHTreeFromMesh; - BVHTreeFromMesh treeData_e = NULL_BVHTreeFromMesh; - BVHTreeFromMesh treeData_f = NULL_BVHTreeFromMesh; - BVHTreeNearest nearest_v = NULL_BVHTreeNearest; - BVHTreeNearest nearest_e = NULL_BVHTreeNearest; - BVHTreeNearest nearest_f = NULL_BVHTreeNearest; + BVHTreeFromMesh treeData_v = {0}; + BVHTreeFromMesh treeData_e = {0}; + BVHTreeFromMesh treeData_f = {0}; + BVHTreeNearest nearest_v = {0}; + BVHTreeNearest nearest_e = {0}; + BVHTreeNearest nearest_f = {0}; if (dist_v) { /* Create a bvh-tree of the given target's verts. */ @@ -120,7 +119,7 @@ static void get_vert2geom_distance(int numVerts, float (*v_cos)[3], /* Convert the vertex to tree coordinates. */ copy_v3_v3(tmp_co, v_cos[i]); - space_transform_apply(loc2trgt, tmp_co); + BLI_space_transform_apply(loc2trgt, tmp_co); /* Use local proximity heuristics (to reduce the nearest search). * @@ -465,7 +464,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der DerivedMesh *target_dm = obr->derivedFinal; bool free_target_dm = false; if (!target_dm) { - if (ELEM3(obr->type, OB_CURVE, OB_SURF, OB_FONT)) + if (ELEM(obr->type, OB_CURVE, OB_SURF, OB_FONT)) target_dm = CDDM_from_curve(obr); else if (obr->type == OB_MESH) { Mesh *me = (Mesh *)obr->data; @@ -484,7 +483,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der float *dists_e = use_trgt_edges ? MEM_mallocN(sizeof(float) * numIdx, "dists_e") : NULL; float *dists_f = use_trgt_faces ? MEM_mallocN(sizeof(float) * numIdx, "dists_f") : NULL; - SPACE_TRANSFORM_SETUP(&loc2trgt, ob, obr); + BLI_SPACE_TRANSFORM_SETUP(&loc2trgt, ob, obr); get_vert2geom_distance(numIdx, v_cos, dists_v, dists_e, dists_f, target_dm, &loc2trgt); for (i = 0; i < numIdx; i++) { diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 6fed0d16848..e09a0892370 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -105,6 +105,7 @@ set(SRC composite/nodes/node_composite_setalpha.c composite/nodes/node_composite_splitViewer.c composite/nodes/node_composite_stabilize2d.c + composite/nodes/node_composite_sunbeams.c composite/nodes/node_composite_texture.c composite/nodes/node_composite_tonemap.c composite/nodes/node_composite_trackpos.c diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h index ad5f35b8faa..961fdbfc0fb 100644 --- a/source/blender/nodes/NOD_composite.h +++ b/source/blender/nodes/NOD_composite.h @@ -125,7 +125,7 @@ void register_node_type_cmp_mask(void); void register_node_type_cmp_glare(void); void register_node_type_cmp_tonemap(void); void register_node_type_cmp_lensdist(void); - +void register_node_type_cmp_sunbeams(void); void register_node_type_cmp_colorcorrection(void); void register_node_type_cmp_boxmask(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 8d6c4abaef6..be87abd7b7e 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -208,6 +208,7 @@ DefNode( CompositorNode, CMP_NODE_TRACKPOS, def_cmp_trackpos, "TRACK DefNode( CompositorNode, CMP_NODE_PIXELATE, 0, "PIXELATE", Pixelate, "Pixelate", "" ) DefNode( CompositorNode, CMP_NODE_PLANETRACKDEFORM,def_cmp_planetrackdeform,"PLANETRACKDEFORM",PlaneTrackDeform,"Plane Track Deform","" ) DefNode( CompositorNode, CMP_NODE_CORNERPIN, 0, "CORNERPIN", CornerPin, "Corner Pin", "" ) +DefNode( CompositorNode, CMP_NODE_SUNBEAMS, def_cmp_sunbeams, "SUNBEAMS", SunBeams, "Sun Beams", "" ) DefNode( TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" ) DefNode( TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" ) diff --git a/source/blender/nodes/composite/nodes/node_composite_sunbeams.c b/source/blender/nodes/composite/nodes/node_composite_sunbeams.c new file mode 100644 index 00000000000..4d937d63b75 --- /dev/null +++ b/source/blender/nodes/composite/nodes/node_composite_sunbeams.c @@ -0,0 +1,63 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2014 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Lukas Toenne + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/nodes/composite/nodes/node_composite_sunbeams.c + * \ingroup cmpnodes + */ + +#include "node_composite_util.h" + +static bNodeSocketTemplate inputs[] = { + { SOCK_RGBA, 1, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, + { -1, 0, "" } +}; +static bNodeSocketTemplate outputs[] = { + { SOCK_RGBA, 0, N_("Image")}, + { -1, 0, "" } +}; + +static void init(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeSunBeams *data = MEM_callocN(sizeof(NodeSunBeams), "sun beams node"); + + data->source[0] = 0.5f; + data->source[1] = 0.5f; + + node->storage = data; +} + +void register_node_type_cmp_sunbeams(void) +{ + static bNodeType ntype; + + cmp_node_type_base(&ntype, CMP_NODE_SUNBEAMS, "Sun Beams", NODE_CLASS_OP_FILTER, 0); + node_type_socket_templates(&ntype, inputs, outputs); + node_type_init(&ntype, init); + node_type_storage(&ntype, "NodeSunBeams", node_free_standard_storage, node_copy_standard_storage); + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/intern/node_common.c b/source/blender/nodes/intern/node_common.c index ae834f9e7cc..c58c9c902ec 100644 --- a/source/blender/nodes/intern/node_common.c +++ b/source/blender/nodes/intern/node_common.c @@ -336,6 +336,40 @@ void ntree_update_reroute_nodes(bNodeTree *ntree) node_reroute_inherit_type_recursive(ntree, node); } +static bool node_is_connected_to_output_recursive(bNodeTree *ntree, bNode *node) +{ + bNodeLink *link; + + /* avoid redundant checks, and infinite loops in case of cyclic node links */ + if (node->done) + return false; + node->done = 1; + + /* main test, done before child loop so it catches output nodes themselves as well */ + if (node->typeinfo->nclass == NODE_CLASS_OUTPUT && node->flag & NODE_DO_OUTPUT) + return true; + + /* test all connected nodes, first positive find is sufficient to return true */ + for (link = ntree->links.first; link; link = link->next) { + if (link->fromnode == node) { + if (node_is_connected_to_output_recursive(ntree, link->tonode)) + return true; + } + } + return false; +} + +bool BKE_node_is_connected_to_output(bNodeTree *ntree, bNode *node) +{ + bNode *tnode; + + /* clear flags */ + for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) + tnode->done = 0; + + return node_is_connected_to_output_recursive(ntree, node); +} + void BKE_node_tree_unlink_id(ID *id, struct bNodeTree *ntree) { bNode *node; diff --git a/source/blender/nodes/intern/node_exec.c b/source/blender/nodes/intern/node_exec.c index 0e5f72c831b..ec481839a16 100644 --- a/source/blender/nodes/intern/node_exec.c +++ b/source/blender/nodes/intern/node_exec.c @@ -47,7 +47,7 @@ /* supported socket types in old nodes */ int node_exec_socket_use_stack(bNodeSocket *sock) { - return ELEM4(sock->type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_SHADER); + return ELEM(sock->type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_SHADER); } /* for a given socket, find the actual stack entry */ diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c index 55dafaeca35..75ca4b87f09 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c @@ -30,7 +30,7 @@ /* **************** OUTPUT ******************** */ static bNodeSocketTemplate sh_node_bsdf_glass_in[] = { - { SOCK_RGBA, 1, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 1, N_("Color"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f}, { SOCK_FLOAT, 1, N_("Roughness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, { SOCK_FLOAT, 1, N_("IOR"), 1.45f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f}, { SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, diff --git a/source/blender/nodes/shader/nodes/node_shader_uvmap.c b/source/blender/nodes/shader/nodes/node_shader_uvmap.c index fff1bc1df95..0f96cb45fe0 100644 --- a/source/blender/nodes/shader/nodes/node_shader_uvmap.c +++ b/source/blender/nodes/shader/nodes/node_shader_uvmap.c @@ -42,6 +42,14 @@ static void node_shader_init_uvmap(bNodeTree *UNUSED(ntree), bNode *node) node->storage = attr; } +static int node_shader_gpu_uvmap(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) +{ + NodeShaderUVMap *attr = node->storage; + GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, attr->uv_map); + + return GPU_stack_link(mat, "node_uvmap", in, out, mtface); +} + /* node type definition */ void register_node_type_sh_uvmap(void) { @@ -53,6 +61,7 @@ void register_node_type_sh_uvmap(void) node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); node_type_init(&ntype, node_shader_init_uvmap); node_type_storage(&ntype, "NodeShaderUVMap", node_free_standard_storage, node_copy_standard_storage); + node_type_gpu(&ntype, node_shader_gpu_uvmap); nodeRegisterType(&ntype); } diff --git a/source/blender/python/bmesh/bmesh_py_utils.c b/source/blender/python/bmesh/bmesh_py_utils.c index 3c412cf2a08..88e369af8bb 100644 --- a/source/blender/python/bmesh/bmesh_py_utils.c +++ b/source/blender/python/bmesh/bmesh_py_utils.c @@ -595,7 +595,9 @@ static PyObject *bpy_bm_utils_face_split_edgenet(PyObject *UNUSED(self), PyObjec if (ok) { PyObject *ret = BPy_BMFace_Array_As_Tuple(bm, face_arr, face_arr_len); - MEM_freeN(face_arr); + if (face_arr) { + MEM_freeN(face_arr); + } return ret; } else { diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c index 9b819977345..e77a528bb09 100644 --- a/source/blender/python/generic/bgl.c +++ b/source/blender/python/generic/bgl.c @@ -301,7 +301,7 @@ static PyObject *Buffer_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject if (!PyArg_ParseTuple(args, "iO|O: bgl.Buffer", &type, &length_ob, &init)) { return NULL; } - if (!ELEM5(type, GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE)) { + if (!ELEM(type, GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE)) { PyErr_SetString(PyExc_AttributeError, "invalid first argument type, should be one of " "GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT or GL_DOUBLE"); diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 440af035bcd..3fdc3641173 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -1363,7 +1363,7 @@ PyObject *pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop) if (subtype == PROP_BYTESTRING) { ret = PyBytes_FromStringAndSize(buf, buf_len); } - else if (ELEM3(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) { + else if (ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) { ret = PyC_UnicodeFromByteAndSize(buf, buf_len); } else { @@ -1629,7 +1629,7 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb /* Unicode String */ #ifdef USE_STRING_COERCE PyObject *value_coerce = NULL; - if (ELEM3(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) { + if (ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) { /* TODO, get size */ param = PyC_UnicodeAsByte(value, &value_coerce); } @@ -4894,7 +4894,7 @@ static PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *dat if (subtype == PROP_BYTESTRING) { ret = PyBytes_FromString(data_ch); } - else if (ELEM3(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) { + else if (ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) { ret = PyC_UnicodeFromByte(data_ch); } else { diff --git a/source/blender/python/mathutils/mathutils_Euler.c b/source/blender/python/mathutils/mathutils_Euler.c index 5d8252d3c72..f6d124938a4 100644 --- a/source/blender/python/mathutils/mathutils_Euler.c +++ b/source/blender/python/mathutils/mathutils_Euler.c @@ -83,14 +83,23 @@ static const char *euler_order_str(EulerObject *self) short euler_order_from_string(const char *str, const char *error_prefix) { if ((str[0] && str[1] && str[2] && str[3] == '\0')) { + +#ifdef __LITTLE_ENDIAN__ +# define MAKE_ID3(a, b, c) (((a)) | ((b) << 8) | ((c) << 16)) +#else +# define MAKE_ID3(a, b, c) (((a) << 24) | ((b) << 16) | ((c) << 8)) +#endif + switch (*((PY_INT32_T *)str)) { - case 'X' | 'Y' << 8 | 'Z' << 16: return EULER_ORDER_XYZ; - case 'X' | 'Z' << 8 | 'Y' << 16: return EULER_ORDER_XZY; - case 'Y' | 'X' << 8 | 'Z' << 16: return EULER_ORDER_YXZ; - case 'Y' | 'Z' << 8 | 'X' << 16: return EULER_ORDER_YZX; - case 'Z' | 'X' << 8 | 'Y' << 16: return EULER_ORDER_ZXY; - case 'Z' | 'Y' << 8 | 'X' << 16: return EULER_ORDER_ZYX; + case MAKE_ID3('X', 'Y', 'Z'): return EULER_ORDER_XYZ; + case MAKE_ID3('X', 'Z', 'Y'): return EULER_ORDER_XZY; + case MAKE_ID3('Y', 'X', 'Z'): return EULER_ORDER_YXZ; + case MAKE_ID3('Y', 'Z', 'X'): return EULER_ORDER_YZX; + case MAKE_ID3('Z', 'X', 'Y'): return EULER_ORDER_ZXY; + case MAKE_ID3('Z', 'Y', 'X'): return EULER_ORDER_ZYX; } + +#undef MAKE_ID3 } PyErr_Format(PyExc_ValueError, @@ -203,7 +212,7 @@ static PyObject *Euler_rotate_axis(EulerObject *self, PyObject *args) return NULL; } - if (!(ELEM3(axis, 'X', 'Y', 'Z'))) { + if (!(ELEM(axis, 'X', 'Y', 'Z'))) { PyErr_SetString(PyExc_ValueError, "Euler.rotate_axis(): " "expected axis to be 'X', 'Y' or 'Z'"); diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c index a719691d5d4..15a9860be0a 100644 --- a/source/blender/python/mathutils/mathutils_Vector.c +++ b/source/blender/python/mathutils/mathutils_Vector.c @@ -814,17 +814,20 @@ static PyObject *Vector_orthogonal(VectorObject *self) { float vec[3]; - if (self->size != 3) { + if (self->size > 3) { PyErr_SetString(PyExc_TypeError, "Vector.orthogonal(): " - "Vector must be 3D"); + "Vector must be 3D or 2D"); return NULL; } if (BaseMath_ReadCallback(self) == -1) return NULL; - ortho_v3_v3(vec, self->vec); + if (self->size == 3) + ortho_v3_v3(vec, self->vec); + else + ortho_v2_v2(vec, self->vec); return Vector_CreatePyObject(vec, self->size, Py_NEW, Py_TYPE(self)); } diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c index 139764abb00..20d69caf02d 100644 --- a/source/blender/python/mathutils/mathutils_geometry.c +++ b/source/blender/python/mathutils/mathutils_geometry.c @@ -229,6 +229,11 @@ static PyObject *M_Geometry_intersect_line_line(PyObject *UNUSED(self), PyObject } result = isect_line_line_v3(v1, v2, v3, v4, i1, i2); + /* The return-code isnt exposed, + * this way we can check know how close the lines are. */ + if (result == 1) { + closest_to_line_v3(i2, i1, v3, v4); + } if (result == 0) { /* colinear */ @@ -597,7 +602,7 @@ static PyObject *M_Geometry_intersect_line_plane(PyObject *UNUSED(self), PyObjec return NULL; } - if (ELEM4(2, line_a->size, line_b->size, plane_co->size, plane_no->size)) { + if (ELEM(2, line_a->size, line_b->size, plane_co->size, plane_no->size)) { PyErr_SetString(PyExc_ValueError, "geometry.intersect_line_plane(...): " " can't use 2D Vectors"); @@ -654,7 +659,7 @@ static PyObject *M_Geometry_intersect_plane_plane(PyObject *UNUSED(self), PyObje return NULL; } - if (ELEM4(2, plane_a_co->size, plane_a_no->size, plane_b_co->size, plane_b_no->size)) { + if (ELEM(2, plane_a_co->size, plane_a_no->size, plane_b_co->size, plane_b_no->size)) { PyErr_SetString(PyExc_ValueError, "geometry.intersect_plane_plane(...): " " can't use 2D Vectors"); @@ -726,7 +731,7 @@ static PyObject *M_Geometry_intersect_line_sphere(PyObject *UNUSED(self), PyObje return NULL; } - if (ELEM3(2, line_a->size, line_b->size, sphere_co->size)) { + if (ELEM(2, line_a->size, line_b->size, sphere_co->size)) { PyErr_SetString(PyExc_ValueError, "geometry.intersect_line_sphere(...): " " can't use 2D Vectors"); @@ -893,13 +898,69 @@ static PyObject *M_Geometry_intersect_point_line(PyObject *UNUSED(self), PyObjec return ret; } +PyDoc_STRVAR(M_Geometry_intersect_point_tri_doc, +".. function:: intersect_point_tri(pt, tri_p1, tri_p2, tri_p3)\n" +"\n" +" Takes 4 vectors: one is the point and the next 3 define the triangle.\n" +"\n" +" :arg pt: Point\n" +" :type pt: :class:`mathutils.Vector`\n" +" :arg tri_p1: First point of the triangle\n" +" :type tri_p1: :class:`mathutils.Vector`\n" +" :arg tri_p2: Second point of the triangle\n" +" :type tri_p2: :class:`mathutils.Vector`\n" +" :arg tri_p3: Third point of the triangle\n" +" :type tri_p3: :class:`mathutils.Vector`\n" +" :return: Point on the triangles plane or None if its outside the triangle\n" +" :rtype: :class:`mathutils.Vector` or None\n" +); +static PyObject *M_Geometry_intersect_point_tri(PyObject *UNUSED(self), PyObject *args) +{ + VectorObject *pt_vec, *tri_p1, *tri_p2, *tri_p3; + float vi[3]; + + if (!PyArg_ParseTuple(args, "O!O!O!O!:intersect_point_tri", + &vector_Type, &pt_vec, + &vector_Type, &tri_p1, + &vector_Type, &tri_p2, + &vector_Type, &tri_p3)) + { + return NULL; + } + + if (BaseMath_ReadCallback(pt_vec) == -1 || + BaseMath_ReadCallback(tri_p1) == -1 || + BaseMath_ReadCallback(tri_p2) == -1 || + BaseMath_ReadCallback(tri_p3) == -1) + { + return NULL; + } + + if (pt_vec->size < 3 || + tri_p1->size < 3 || + tri_p2->size < 3 || + tri_p3->size < 3) + { + PyErr_SetString(PyExc_ValueError, + "One of more of the vector arguments wasn't a 3D vector"); + return NULL; + } + + if (isect_point_tri_v3(pt_vec->vec, tri_p1->vec, tri_p2->vec, tri_p3->vec, vi)) { + return Vector_CreatePyObject(vi, 3, Py_NEW, NULL); + } + else { + Py_RETURN_NONE; + } +} + PyDoc_STRVAR(M_Geometry_intersect_point_tri_2d_doc, ".. function:: intersect_point_tri_2d(pt, tri_p1, tri_p2, tri_p3)\n" "\n" " Takes 4 vectors (using only the x and y coordinates): one is the point and the next 3 define the triangle. Returns 1 if the point is within the triangle, otherwise 0.\n" "\n" " :arg pt: Point\n" -" :type v1: :class:`mathutils.Vector`\n" +" :type pt: :class:`mathutils.Vector`\n" " :arg tri_p1: First point of the triangle\n" " :type tri_p1: :class:`mathutils.Vector`\n" " :arg tri_p2: Second point of the triangle\n" @@ -1606,6 +1667,7 @@ static PyObject *M_Geometry_convex_hull_2d(PyObject *UNUSED(self), PyObject *poi static PyMethodDef M_Geometry_methods[] = { {"intersect_ray_tri", (PyCFunction) M_Geometry_intersect_ray_tri, METH_VARARGS, M_Geometry_intersect_ray_tri_doc}, {"intersect_point_line", (PyCFunction) M_Geometry_intersect_point_line, METH_VARARGS, M_Geometry_intersect_point_line_doc}, + {"intersect_point_tri", (PyCFunction) M_Geometry_intersect_point_tri, METH_VARARGS, M_Geometry_intersect_point_tri_doc}, {"intersect_point_tri_2d", (PyCFunction) M_Geometry_intersect_point_tri_2d, METH_VARARGS, M_Geometry_intersect_point_tri_2d_doc}, {"intersect_point_quad_2d", (PyCFunction) M_Geometry_intersect_point_quad_2d, METH_VARARGS, M_Geometry_intersect_point_quad_2d_doc}, {"intersect_line_line", (PyCFunction) M_Geometry_intersect_line_line, METH_VARARGS, M_Geometry_intersect_line_line_doc}, diff --git a/source/blender/render/extern/include/RE_bake.h b/source/blender/render/extern/include/RE_bake.h index 8f2a0e382a4..481da452529 100644 --- a/source/blender/render/extern/include/RE_bake.h +++ b/source/blender/render/extern/include/RE_bake.h @@ -39,7 +39,7 @@ typedef struct BakeImage { struct Image *image; int width; int height; - int offset; + size_t offset; } BakeImage; typedef struct BakeImages { @@ -72,35 +72,35 @@ bool RE_bake_has_engine(struct Render *re); bool RE_bake_engine( struct Render *re, struct Object *object, const BakePixel pixel_array[], - const int num_pixels, const int depth, const ScenePassType pass_type, float result[]); + const size_t num_pixels, const int depth, const ScenePassType pass_type, float result[]); /* bake.c */ int RE_pass_depth(const ScenePassType pass_type); bool RE_bake_internal( struct Render *re, struct Object *object, const BakePixel pixel_array[], - const int num_pixels, const int depth, const ScenePassType pass_type, float result[]); + const size_t num_pixels, const int depth, const ScenePassType pass_type, float result[]); bool RE_bake_pixels_populate_from_objects( struct Mesh *me_low, BakePixel pixel_array_from[], - BakeHighPolyData highpoly[], const int tot_highpoly, const int num_pixels, const bool is_custom_cage, + BakeHighPolyData highpoly[], const int tot_highpoly, const size_t num_pixels, const bool is_custom_cage, const float cage_extrusion, float mat_low[4][4], float mat_cage[4][4], struct Mesh *me_cage); void RE_bake_pixels_populate( struct Mesh *me, struct BakePixel *pixel_array, - const int num_pixels, const struct BakeImages *bake_images, const char *uv_layer); + const size_t num_pixels, const struct BakeImages *bake_images, const char *uv_layer); -void RE_bake_mask_fill(const BakePixel pixel_array[], const int num_pixels, char *mask); +void RE_bake_mask_fill(const BakePixel pixel_array[], const size_t num_pixels, char *mask); void RE_bake_margin(struct ImBuf *ibuf, char *mask, const int margin); void RE_bake_normal_world_to_object( - const BakePixel pixel_array[], const int num_pixels, const int depth, float result[], + const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[], struct Object *ob, const BakeNormalSwizzle normal_swizzle[3]); void RE_bake_normal_world_to_tangent( - const BakePixel pixel_array[], const int num_pixels, const int depth, float result[], + const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[], struct Mesh *me, const BakeNormalSwizzle normal_swizzle[3], float mat[4][4]); void RE_bake_normal_world_to_world( - const BakePixel pixel_array[], const int num_pixels, const int depth, float result[], + const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[], const BakeNormalSwizzle normal_swizzle[3]); void RE_bake_ibuf_clear(struct Image *image, const bool is_tangent); diff --git a/source/blender/render/intern/source/bake.c b/source/blender/render/intern/source/bake.c index f2793a9bc5b..15634c93491 100644 --- a/source/blender/render/intern/source/bake.c +++ b/source/blender/render/intern/source/bake.c @@ -174,7 +174,7 @@ static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int UNUSED(qua /* only do AO for a full bake (and obviously AO bakes) * AO for light bakes is a leftover and might not be needed */ - if (ELEM3(bs->type, RE_BAKE_ALL, RE_BAKE_AO, RE_BAKE_LIGHT)) + if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_AO, RE_BAKE_LIGHT)) shade_samples_do_AO(ssamp); if (shi->mat->nodetree && shi->mat->use_nodes) { @@ -303,7 +303,7 @@ static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int UNUSED(qua rgb_float_to_uchar(col, shr.combined); } - if (ELEM3(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE, RE_BAKE_VERTEX_COLORS)) { + if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE, RE_BAKE_VERTEX_COLORS)) { col[3] = FTOCHAR(shr.alpha); } else { diff --git a/source/blender/render/intern/source/bake_api.c b/source/blender/render/intern/source/bake_api.c index 15ad6051f4c..08fea632cd4 100644 --- a/source/blender/render/intern/source/bake_api.c +++ b/source/blender/render/intern/source/bake_api.c @@ -120,7 +120,7 @@ static void store_bake_pixel(void *handle, int x, int y, float u, float v) BakePixel *pixel; const int width = bd->bk_image->width; - const int offset = bd->bk_image->offset; + const size_t offset = bd->bk_image->offset; const int i = offset + y * width + x; pixel = &bd->pixel_array[i]; @@ -134,9 +134,9 @@ static void store_bake_pixel(void *handle, int x, int y, float u, float v) pixel->dv_dy = bd->dv_dy; } -void RE_bake_mask_fill(const BakePixel pixel_array[], const int num_pixels, char *mask) +void RE_bake_mask_fill(const BakePixel pixel_array[], const size_t num_pixels, char *mask) { - int i; + size_t i; if (!mask) return; @@ -438,10 +438,10 @@ static void mesh_calc_tri_tessface( bool RE_bake_pixels_populate_from_objects( struct Mesh *me_low, BakePixel pixel_array_from[], - BakeHighPolyData highpoly[], const int tot_highpoly, const int num_pixels, const bool is_custom_cage, + BakeHighPolyData highpoly[], const int tot_highpoly, const size_t num_pixels, const bool is_custom_cage, const float cage_extrusion, float mat_low[4][4], float mat_cage[4][4], struct Mesh *me_cage) { - int i; + size_t i; int primitive_id; float u, v; float imat_low [4][4]; @@ -594,11 +594,11 @@ static void bake_differentials(BakeDataZSpan *bd, const float *uv1, const float void RE_bake_pixels_populate( Mesh *me, BakePixel pixel_array[], - const int num_pixels, const BakeImages *bake_images, const char *uv_layer) + const size_t num_pixels, const BakeImages *bake_images, const char *uv_layer) { BakeDataZSpan bd; - int i, a; - int p_id; + size_t i; + int a, p_id; MTFace *mtface; MFace *mface; @@ -725,11 +725,11 @@ static void normal_compress(float out[3], const float in[3], const BakeNormalSwi * This function converts an object space normal map to a tangent space normal map for a given low poly mesh */ void RE_bake_normal_world_to_tangent( - const BakePixel pixel_array[], const int num_pixels, const int depth, + const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[], Mesh *me, const BakeNormalSwizzle normal_swizzle[3], float mat[4][4]) { - int i; + size_t i; TriTessFace *triangles; @@ -756,7 +756,7 @@ void RE_bake_normal_world_to_tangent( float tsm[3][3]; /* tangent space matrix */ float itsm[3][3]; - int offset; + size_t offset; float nor[3]; /* texture normal */ bool is_smooth; @@ -834,16 +834,16 @@ void RE_bake_normal_world_to_tangent( } void RE_bake_normal_world_to_object( - const BakePixel pixel_array[], const int num_pixels, const int depth, + const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[], struct Object *ob, const BakeNormalSwizzle normal_swizzle[3]) { - int i; + size_t i; float iobmat[4][4]; invert_m4_m4(iobmat, ob->obmat); for (i = 0; i < num_pixels; i++) { - int offset; + size_t offset; float nor[3]; if (pixel_array[i].primitive_id == -1) @@ -862,13 +862,13 @@ void RE_bake_normal_world_to_object( } void RE_bake_normal_world_to_world( - const BakePixel pixel_array[], const int num_pixels, const int depth, + const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[], const BakeNormalSwizzle normal_swizzle[3]) { - int i; + size_t i; for (i = 0; i < num_pixels; i++) { - int offset; + size_t offset; float nor[3]; if (pixel_array[i].primitive_id == -1) @@ -908,12 +908,12 @@ void RE_bake_ibuf_clear(Image *image, const bool is_tangent) /** * not the real UV, but the internal per-face UV instead * I'm using it to test if everything is correct */ -static bool bake_uv(const BakePixel pixel_array[], const int num_pixels, const int depth, float result[]) +static bool bake_uv(const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[]) { - int i; + size_t i; for (i=0; i < num_pixels; i++) { - int offset = i * depth; + size_t offset = i * depth; copy_v2_v2(&result[offset], pixel_array[i].uv); } @@ -922,7 +922,7 @@ static bool bake_uv(const BakePixel pixel_array[], const int num_pixels, const i bool RE_bake_internal( Render *UNUSED(re), Object *UNUSED(object), const BakePixel pixel_array[], - const int num_pixels, const int depth, const ScenePassType pass_type, float result[]) + const size_t num_pixels, const int depth, const ScenePassType pass_type, float result[]) { switch (pass_type) { case SCE_PASS_UV: diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 5c44f1cd0c1..c6ebe44c5da 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -3704,8 +3704,8 @@ static GroupObject *add_render_lamp(Render *re, Object *ob) /* Annoying, lamp UI does this, but the UI might not have been used? - add here too. * make sure this matches buttons_shading.c's logic */ - if (ELEM4(la->type, LA_AREA, LA_SPOT, LA_SUN, LA_LOCAL) && (la->mode & LA_SHAD_RAY)) - if (ELEM3(la->type, LA_SPOT, LA_SUN, LA_LOCAL)) + if (ELEM(la->type, LA_AREA, LA_SPOT, LA_SUN, LA_LOCAL) && (la->mode & LA_SHAD_RAY)) + if (ELEM(la->type, LA_SPOT, LA_SUN, LA_LOCAL)) if (la->ray_samp_method == LA_SAMP_CONSTANT) la->ray_samp_method = LA_SAMP_HALTON; lar->ray_samp_method= la->ray_samp_method; @@ -4546,8 +4546,7 @@ static void set_dupli_tex_mat(Render *re, ObjectInstanceRen *obi, DupliObject *d obi->duplitexmat= BLI_memarena_alloc(re->memArena, sizeof(float)*4*4); invert_m4_m4(imat, dob->mat); - mul_serie_m4(obi->duplitexmat, re->viewmat, omat, imat, re->viewinv, - NULL, NULL, NULL, NULL); + mul_m4_series(obi->duplitexmat, re->viewmat, omat, imat, re->viewinv); } copy_v3_v3(obi->dupliorco, dob->orco); @@ -4831,7 +4830,7 @@ static int allow_render_dupli_instance(Render *UNUSED(re), DupliObject *dob, Obj } for (psys=obd->particlesystem.first; psys; psys=psys->next) - if (!ELEM5(psys->part->ren_as, PART_DRAW_BB, PART_DRAW_LINE, PART_DRAW_PATH, PART_DRAW_OB, PART_DRAW_GR)) + if (!ELEM(psys->part->ren_as, PART_DRAW_BB, PART_DRAW_LINE, PART_DRAW_PATH, PART_DRAW_OB, PART_DRAW_GR)) return 0; /* don't allow lamp, animated duplis, or radio render */ @@ -5833,8 +5832,8 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay, Object *camera; float mat[4][4]; float amb[3]; - const short onlyselected= !ELEM5(type, RE_BAKE_LIGHT, RE_BAKE_ALL, RE_BAKE_SHADOW, RE_BAKE_AO, RE_BAKE_VERTEX_COLORS); - const short nolamps= ELEM5(type, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_VERTEX_COLORS); + const short onlyselected= !ELEM(type, RE_BAKE_LIGHT, RE_BAKE_ALL, RE_BAKE_SHADOW, RE_BAKE_AO, RE_BAKE_VERTEX_COLORS); + const short nolamps= ELEM(type, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_VERTEX_COLORS); re->main= bmain; re->scene= scene; @@ -5858,7 +5857,7 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay, if (type==RE_BAKE_VERTEX_COLORS) re->flag |= R_NEED_VCOL; - if (!actob && ELEM6(type, RE_BAKE_LIGHT, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_VERTEX_COLORS)) { + if (!actob && ELEM(type, RE_BAKE_LIGHT, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_VERTEX_COLORS)) { re->r.mode &= ~R_SHADOW; re->r.mode &= ~R_RAYTRACE; } diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index 58e3038682c..3c35d500948 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -425,7 +425,7 @@ bool RE_bake_has_engine(Render *re) bool RE_bake_engine( Render *re, Object *object, const BakePixel pixel_array[], - const int num_pixels, const int depth, + const size_t num_pixels, const int depth, const ScenePassType pass_type, float result[]) { RenderEngineType *type = RE_engines_find(re->r.engine); diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 2131b820bd4..9e14645a732 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -1935,6 +1935,8 @@ static void add_freestyle(Render *re, int render) { SceneRenderLayer *srl, *actsrl; LinkData *link; + Render *r; + const bool do_link = (re->r.mode & R_MBLUR) == 0 || re->i.curblur == re->r.mblur_samples; actsrl = BLI_findlink(&re->r.layers, re->r.actlay); @@ -1951,15 +1953,17 @@ static void add_freestyle(Render *re, int render) FRS_init_stroke_rendering(re); - for (srl= (SceneRenderLayer *)re->r.layers.first; srl; srl= srl->next) { - - link = (LinkData *)MEM_callocN(sizeof(LinkData), "LinkData to Freestyle render"); - BLI_addtail(&re->freestyle_renders, link); - + for (srl = (SceneRenderLayer *)re->r.layers.first; srl; srl = srl->next) { + if (do_link) { + link = (LinkData *)MEM_callocN(sizeof(LinkData), "LinkData to Freestyle render"); + BLI_addtail(&re->freestyle_renders, link); + } if ((re->r.scemode & R_SINGLE_LAYER) && srl != actsrl) continue; if (FRS_is_freestyle_enabled(srl)) { - link->data = (void *)FRS_do_stroke_rendering(re, srl, render); + r = FRS_do_stroke_rendering(re, srl, render); + if (do_link) + link->data = (void *)r; } } diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c index 253f8a1383f..dd14c2495e8 100644 --- a/source/blender/render/intern/source/render_texture.c +++ b/source/blender/render/intern/source/render_texture.c @@ -3564,7 +3564,7 @@ Material *RE_init_sample_material(Material *orig_mat, Scene *scene) /* depending of material type, strip non-compatible mapping modes */ if (mat->material_type == MA_TYPE_SURFACE) { - if (!ELEM4(mtex->texco, TEXCO_ORCO, TEXCO_OBJECT, TEXCO_GLOB, TEXCO_UV)) { + if (!ELEM(mtex->texco, TEXCO_ORCO, TEXCO_OBJECT, TEXCO_GLOB, TEXCO_UV)) { /* ignore this texture */ mtex->texco = 0; continue; @@ -3573,7 +3573,7 @@ Material *RE_init_sample_material(Material *orig_mat, Scene *scene) mtex->mapto = (mtex->mapto & MAP_COL) | (mtex->mapto & MAP_ALPHA); } else if (mat->material_type == MA_TYPE_VOLUME) { - if (!ELEM3(mtex->texco, TEXCO_OBJECT, TEXCO_ORCO, TEXCO_GLOB)) { + if (!ELEM(mtex->texco, TEXCO_OBJECT, TEXCO_ORCO, TEXCO_GLOB)) { /* ignore */ mtex->texco = 0; continue; diff --git a/source/blender/render/intern/source/shadbuf.c b/source/blender/render/intern/source/shadbuf.c index 9d337e542a1..aa420d7e7c8 100644 --- a/source/blender/render/intern/source/shadbuf.c +++ b/source/blender/render/intern/source/shadbuf.c @@ -784,7 +784,7 @@ void makeshadowbuf(Render *re, LampRen *lar) perspective_m4(shb->winmat, -wsize, wsize, -wsize, wsize, shb->d, shb->clipend); mul_m4_m4m4(shb->persmat, shb->winmat, shb->viewmat); - if (ELEM3(lar->buftype, LA_SHADBUF_REGULAR, LA_SHADBUF_HALFWAY, LA_SHADBUF_DEEP)) { + if (ELEM(lar->buftype, LA_SHADBUF_REGULAR, LA_SHADBUF_HALFWAY, LA_SHADBUF_DEEP)) { shb->totbuf= lar->buffers; /* jitter, weights - not threadsafe! */ diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index fe3af5b840e..d5c4c407bf6 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -499,7 +499,7 @@ static void vol_shade_one_lamp(struct ShadeInput *shi, const float co[3], const if (shi->mat->vol.shade_type == MA_VOL_SHADE_SHADOWED) { mul_v3_fl(lacol, vol_get_shadow(shi, lar, co)); } - else if (ELEM3(shi->mat->vol.shade_type, MA_VOL_SHADE_SHADED, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE)) { + else if (ELEM(shi->mat->vol.shade_type, MA_VOL_SHADE_SHADED, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE)) { Isect is; if (shi->mat->vol.shadeflag & MA_VOL_RECV_EXT_SHADOW) { diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index cfa795cb3b7..253976052fd 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -344,8 +344,10 @@ void WM_event_print(const struct wmEvent *event); void WM_operator_region_active_win_set(struct bContext *C); /* drag and drop */ -struct wmDrag *WM_event_start_drag(struct bContext *C, int icon, int type, void *poin, double value); +struct wmDrag *WM_event_start_drag(struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags); void WM_event_drag_image(struct wmDrag *, struct ImBuf *, float scale, int sx, int sy); +void WM_drag_free(struct wmDrag *drag); +void WM_drag_free_list(struct ListBase *lb); struct wmDropBox *WM_dropbox_add(ListBase *lb, const char *idname, int (*poll)(struct bContext *, struct wmDrag *, const struct wmEvent *event), void (*copy)(struct wmDrag *, struct wmDropBox *)); diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 9ad1bc97f4d..123a07d281c 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -597,6 +597,12 @@ typedef struct wmReport { #define WM_DRAG_PATH 2 #define WM_DRAG_NAME 3 #define WM_DRAG_VALUE 4 +#define WM_DRAG_COLOR 5 + +typedef enum wmDragFlags { + WM_DRAG_NOP = 0, + WM_DRAG_FREE_DATA = 1, +} wmDragFlags; /* note: structs need not exported? */ @@ -613,6 +619,7 @@ typedef struct wmDrag { int sx, sy; char opname[200]; /* if set, draws operator name*/ + unsigned int flags; } wmDrag; /* dropboxes are like keymaps, part of the screen/area/region definition */ diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 28bddb47778..d05cc572c45 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -462,7 +462,8 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm) BLI_freelistN(&wm->queue); BLI_freelistN(&wm->paintcursors); - BLI_freelistN(&wm->drags); + + WM_drag_free_list(&wm->drags); wm_reports_free(wm); diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index 2aa177602cb..e5bba9285b4 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -143,7 +143,7 @@ void wm_dropbox_free(void) /* *********************************** */ /* note that the pointer should be valid allocated and not on stack */ -wmDrag *WM_event_start_drag(struct bContext *C, int icon, int type, void *poin, double value) +wmDrag *WM_event_start_drag(struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags) { wmWindowManager *wm = CTX_wm_manager(C); wmDrag *drag = MEM_callocN(sizeof(struct wmDrag), "new drag"); @@ -152,6 +152,7 @@ wmDrag *WM_event_start_drag(struct bContext *C, int icon, int type, void *poin, /* if multiple drags are added, they're drawn as list */ BLI_addtail(&wm->drags, drag); + drag->flags = flags; drag->icon = icon; drag->type = type; if (type == WM_DRAG_PATH) @@ -171,6 +172,22 @@ void WM_event_drag_image(wmDrag *drag, ImBuf *imb, float scale, int sx, int sy) drag->sy = sy; } +void WM_drag_free(wmDrag *drag) +{ + if ((drag->flags & WM_DRAG_FREE_DATA) && drag->poin) { + MEM_freeN(drag->poin); + } + + MEM_freeN(drag); +} + +void WM_drag_free_list(struct ListBase *lb) +{ + wmDrag *drag; + while ((drag = BLI_pophead(lb))) { + WM_drag_free(drag); + } +} static const char *dropbox_active(bContext *C, ListBase *handlers, wmDrag *drag, wmEvent *event) { diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 96824eca578..2f20e8c234f 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -592,7 +592,7 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) bScreen *screen = win->screen; ScrArea *sa; ARegion *ar; - int copytex = 0, paintcursor = 1; + int copytex = 0; if (win->drawdata) { glClearColor(0, 0, 0, 0); @@ -639,7 +639,7 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) wm_triple_copy_textures(win, triple); } - if (paintcursor && wm->paintcursors.first) { + if (wm->paintcursors.first) { for (sa = screen->areabase.first; sa; sa = sa->next) { for (ar = sa->regionbase.first; ar; ar = ar->next) { if (ar->swinid && ar->swinid == screen->subwinactive) { @@ -685,8 +685,6 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) CTX_wm_menu_set(C, ar); ED_region_do_draw(C, ar); CTX_wm_menu_set(C, NULL); - /* when a menu is being drawn, don't do the paint cursors */ - paintcursor = 0; } } diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 9f1359dfb9b..7e2b7f2eb65 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -111,10 +111,13 @@ void wm_event_free(wmEvent *event) if (event->customdata) { if (event->customdatafree) { /* note: pointer to listbase struct elsewhere */ - if (event->custom == EVT_DATA_LISTBASE) - BLI_freelistN(event->customdata); - else + if (event->custom == EVT_DATA_DRAGDROP) { + ListBase *lb = event->customdata; + WM_drag_free_list(lb); + } + else { MEM_freeN(event->customdata); + } } } @@ -289,7 +292,7 @@ void wm_event_do_notifiers(bContext *C) do_anim = true; } } - if (ELEM5(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_SCENE, NC_WM)) { + if (ELEM(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_SCENE, NC_WM)) { ED_info_stats_clear(win->screen->scene); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, NULL); } @@ -393,7 +396,7 @@ static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *eve ARegion *region = CTX_wm_region(C); ARegion *menu = CTX_wm_menu(C); static bool do_wheel_ui = true; - const bool is_wheel = ELEM3(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, MOUSEPAN); + const bool is_wheel = ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, MOUSEPAN); int retval; /* UI code doesn't handle return values - it just always returns break. @@ -1934,17 +1937,17 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers wmDropBox *drop = handler->dropboxes->first; for (; drop; drop = drop->next) { /* other drop custom types allowed */ - if (event->custom == EVT_DATA_LISTBASE) { + if (event->custom == EVT_DATA_DRAGDROP) { ListBase *lb = (ListBase *)event->customdata; wmDrag *drag; for (drag = lb->first; drag; drag = drag->next) { if (drop->poll(C, drag, event)) { - drop->copy(drag, drop); /* free the drags before calling operator */ - BLI_freelistN(event->customdata); + WM_drag_free_list(lb); + event->customdata = NULL; event->custom = 0; @@ -2010,7 +2013,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) if (CTX_wm_window(C) == NULL) return action; - if (!ELEM3(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE, EVENT_NONE) && !ISTIMER(event->type)) { + if (!ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE, EVENT_NONE) && !ISTIMER(event->type)) { /* test for CLICK events */ if (wm_action_not_handled(action)) { @@ -2146,10 +2149,12 @@ static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *even return; } - if (event->type == MOUSEMOVE || ISKEYMODIFIER(event->type)) + if (event->type == MOUSEMOVE || ISKEYMODIFIER(event->type)) { win->screen->do_draw_drag = true; + } else if (event->type == ESCKEY) { - BLI_freelistN(&wm->drags); + WM_drag_free_list(&wm->drags); + win->screen->do_draw_drag = true; } else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { @@ -2161,7 +2166,7 @@ static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *even MEM_freeN(event->customdata); } - event->custom = EVT_DATA_LISTBASE; + event->custom = EVT_DATA_DRAGDROP; event->customdata = &wm->drags; event->customdatafree = 1; @@ -2694,7 +2699,7 @@ bool WM_modal_tweak_exit(const wmEvent *event, int tweak_event) else { /* if the initial event wasn't a tweak event then * ignore USER_RELEASECONFIRM setting: see [#26756] */ - if (ELEM3(tweak_event, EVT_TWEAK_L, EVT_TWEAK_M, EVT_TWEAK_R) == 0) { + if (ELEM(tweak_event, EVT_TWEAK_L, EVT_TWEAK_M, EVT_TWEAK_R) == 0) { return 1; } } diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 0bc6442348c..3c28d2b93cd 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -278,11 +278,13 @@ static void wm_window_match_do(bContext *C, ListBase *oldwmlist) /* in case UserDef was read, we re-initialize all, and do versioning */ static void wm_init_userdef(bContext *C, const bool from_memory) { + Main *bmain = CTX_data_main(C); + /* versioning is here */ UI_init_userdef(); MEM_CacheLimiter_set_maximum(((size_t)U.memcachelimit) * 1024 * 1024); - sound_init(CTX_data_main(C)); + sound_init(bmain); /* needed so loading a file from the command line respects user-pref [#26156] */ BKE_BIT_TEST_SET(G.fileflags, U.flag & USER_FILENOUI, G_FILE_NO_UI); @@ -295,7 +297,7 @@ static void wm_init_userdef(bContext *C, const bool from_memory) /* avoid re-saving for every small change to our prefs, allow overrides */ if (from_memory) { - UI_init_userdef_factory(); + BLO_update_defaults_userpref_blend(); } /* update tempdir from user preferences */ diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index c9ef473a442..3e287a3907b 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -74,7 +74,7 @@ wmGesture *WM_gesture_new(bContext *C, const wmEvent *event, int type) wm_subwindow_origin_get(window, gesture->swinid, &sx, &sy); - if (ELEM5(type, WM_GESTURE_RECT, WM_GESTURE_CROSS_RECT, WM_GESTURE_TWEAK, + if (ELEM(type, WM_GESTURE_RECT, WM_GESTURE_CROSS_RECT, WM_GESTURE_TWEAK, WM_GESTURE_CIRCLE, WM_GESTURE_STRAIGHTLINE)) { rcti *rect = MEM_callocN(sizeof(rcti), "gesture rect new"); diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index 0163517545f..a95f2af1a8f 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -1108,9 +1108,9 @@ int WM_keymap_item_compare(wmKeyMapItem *k1, wmKeyMapItem *k2) if (k1->val != KM_ANY && k2->val != KM_ANY) { /* take click, press, release conflict into account */ - if (k1->val == KM_CLICK && ELEM3(k2->val, KM_PRESS, KM_RELEASE, KM_CLICK) == 0) + if (k1->val == KM_CLICK && ELEM(k2->val, KM_PRESS, KM_RELEASE, KM_CLICK) == 0) return 0; - if (k2->val == KM_CLICK && ELEM3(k1->val, KM_PRESS, KM_RELEASE, KM_CLICK) == 0) + if (k2->val == KM_CLICK && ELEM(k1->val, KM_PRESS, KM_RELEASE, KM_CLICK) == 0) return 0; if (k1->val != k2->val) return 0; diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index ba454bb1818..0239175835e 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -501,7 +501,7 @@ void WM_operator_py_idname(char *to, const char *from) int ofs = (sep - from); /* note, we use ascii tolower instead of system tolower, because the - * latter depends on the locale, and can lead to idname mistmatch */ + * latter depends on the locale, and can lead to idname mismatch */ memcpy(to, from, sizeof(char) * ofs); BLI_ascii_strtolower(to, ofs); @@ -3291,7 +3291,7 @@ void wm_tweakevent_test(bContext *C, wmEvent *event, int action) if (win->tweak == NULL) { if (CTX_wm_region(C)) { if (event->val == KM_PRESS) { - if (ELEM3(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE)) { + if (ELEM(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE)) { win->tweak = WM_gesture_new(C, event, WM_GESTURE_TWEAK); } } @@ -4032,7 +4032,7 @@ static int radial_control_invoke(bContext *C, wmOperator *op, const wmEvent *eve /* get subtype of property */ rc->subtype = RNA_property_subtype(rc->prop); - if (!ELEM5(rc->subtype, PROP_NONE, PROP_DISTANCE, PROP_FACTOR, PROP_ANGLE, PROP_PIXEL)) { + if (!ELEM(rc->subtype, PROP_NONE, PROP_DISTANCE, PROP_FACTOR, PROP_ANGLE, PROP_PIXEL)) { BKE_report(op->reports, RPT_ERROR, "Property must be a none, distance, a factor, or an angle"); MEM_freeN(rc); return OPERATOR_CANCELLED; @@ -4165,8 +4165,6 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even static void WM_OT_radial_control(wmOperatorType *ot) { - PropertyRNA *prop; - ot->name = "Radial Control"; ot->idname = "WM_OT_radial_control"; ot->description = "Set some size property (like e.g. brush size) with mouse wheel"; @@ -4178,32 +4176,23 @@ static void WM_OT_radial_control(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; /* all paths relative to the context */ - prop = RNA_def_string(ot->srna, "data_path_primary", NULL, 0, "Primary Data Path", "Primary path of property to be set by the radial control"); - RNA_def_property_flag(prop, PROP_HIDDEN); + RNA_def_string(ot->srna, "data_path_primary", NULL, 0, "Primary Data Path", "Primary path of property to be set by the radial control"); - prop = RNA_def_string(ot->srna, "data_path_secondary", NULL, 0, "Secondary Data Path", "Secondary path of property to be set by the radial control"); - RNA_def_property_flag(prop, PROP_HIDDEN); + RNA_def_string(ot->srna, "data_path_secondary", NULL, 0, "Secondary Data Path", "Secondary path of property to be set by the radial control"); - prop = RNA_def_string(ot->srna, "use_secondary", NULL, 0, "Use Secondary", "Path of property to select between the primary and secondary data paths"); - RNA_def_property_flag(prop, PROP_HIDDEN); + RNA_def_string(ot->srna, "use_secondary", NULL, 0, "Use Secondary", "Path of property to select between the primary and secondary data paths"); - prop = RNA_def_string(ot->srna, "rotation_path", NULL, 0, "Rotation Path", "Path of property used to rotate the texture display"); - RNA_def_property_flag(prop, PROP_HIDDEN); + RNA_def_string(ot->srna, "rotation_path", NULL, 0, "Rotation Path", "Path of property used to rotate the texture display"); - prop = RNA_def_string(ot->srna, "color_path", NULL, 0, "Color Path", "Path of property used to set the color of the control"); - RNA_def_property_flag(prop, PROP_HIDDEN); + RNA_def_string(ot->srna, "color_path", NULL, 0, "Color Path", "Path of property used to set the color of the control"); - prop = RNA_def_string(ot->srna, "fill_color_path", NULL, 0, "Fill Color Path", "Path of property used to set the fill color of the control"); - RNA_def_property_flag(prop, PROP_HIDDEN); + RNA_def_string(ot->srna, "fill_color_path", NULL, 0, "Fill Color Path", "Path of property used to set the fill color of the control"); - prop = RNA_def_string(ot->srna, "zoom_path", NULL, 0, "Zoom Path", "Path of property used to set the zoom level for the control"); - RNA_def_property_flag(prop, PROP_HIDDEN); + RNA_def_string(ot->srna, "zoom_path", NULL, 0, "Zoom Path", "Path of property used to set the zoom level for the control"); - prop = RNA_def_string(ot->srna, "image_id", NULL, 0, "Image ID", "Path of ID that is used to generate an image for the control"); - RNA_def_property_flag(prop, PROP_HIDDEN); + RNA_def_string(ot->srna, "image_id", NULL, 0, "Image ID", "Path of ID that is used to generate an image for the control"); - prop = RNA_def_boolean(ot->srna, "secondary_tex", 0, "Secondary Texture", "Tweak brush secondary/mask texture"); - RNA_def_property_flag(prop, PROP_HIDDEN); + RNA_def_boolean(ot->srna, "secondary_tex", 0, "Secondary Texture", "Tweak brush secondary/mask texture"); } /* ************************** timer for testing ***************** */ diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c index 1792ea40a1a..db4459b1799 100644 --- a/source/blender/windowmanager/intern/wm_subwindow.c +++ b/source/blender/windowmanager/intern/wm_subwindow.c @@ -308,7 +308,7 @@ void wmSubWindowScissorSet(wmWindow *win, int swinid, const rcti *srct, bool src int scissor_height = BLI_rcti_size_y(srct); /* typically a single pixel doesn't matter, - * but one pixel offset is noticable with viewport border render */ + * but one pixel offset is noticeable with viewport border render */ if (srct_pad) { scissor_width += 1; scissor_height += 1; diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index b30fadd46e6..56e094891f5 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -1016,7 +1016,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr /* make blender drop event with custom data pointing to wm drags */ event.type = EVT_DROP; event.val = KM_RELEASE; - event.custom = EVT_DATA_LISTBASE; + event.custom = EVT_DATA_DRAGDROP; event.customdata = &wm->drags; event.customdatafree = 1; @@ -1035,7 +1035,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr /* try to get icon type from extension */ icon = ED_file_extension_icon((char *)stra->strings[a]); - WM_event_start_drag(C, icon, WM_DRAG_PATH, stra->strings[a], 0.0); + WM_event_start_drag(C, icon, WM_DRAG_PATH, stra->strings[a], 0.0, WM_DRAG_NOP); /* void poin should point to string, it makes a copy */ break; /* only one drop element supported now */ } diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index 4a274d25170..6d3cdf6a270 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -38,7 +38,7 @@ /* customdata type */ #define EVT_DATA_GESTURE 1 #define EVT_DATA_TIMER 2 -#define EVT_DATA_LISTBASE 3 +#define EVT_DATA_DRAGDROP 3 #define EVT_DATA_NDOF_MOTION 4 /* tablet active, matches GHOST_TTabletMode */ diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt index e0365f9ea6c..188fb01d23d 100644 --- a/source/blenderplayer/CMakeLists.txt +++ b/source/blenderplayer/CMakeLists.txt @@ -228,3 +228,9 @@ if(WITH_PLAYER) endif() setup_liblinks(blenderplayer) + +# We put CLEW and CUEW here because OPENSUBDIV_LIBRARIES dpeends on them.. +if(WITH_CYCLES OR WITH_COMPOSITOR OR WITH_OPENSUBDIV) + target_link_libraries(blenderplayer "extern_clew") + target_link_libraries(blenderplayer "extern_cuew") +endif() diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index 5fa8a119488..318f10b8baa 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -414,7 +414,7 @@ void ED_view3D_background_image_remove(struct View3D *v3d, struct BGpic *bgpic) void ED_view3D_background_image_clear(struct View3D *v3d) RET_NONE void ED_view3d_update_viewmat(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, float viewmat[4][4], float winmat[4][4]) RET_NONE float ED_view3d_grid_scale(struct Scene *scene, struct View3D *v3d, const char **grid_unit) RET_ZERO -void ED_view3d_shade_update(struct Main *bmain, struct View3D *v3d, struct ScrArea *sa) RET_NONE +void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View3D *v3d, struct ScrArea *sa) RET_NONE void ED_node_shader_default(const struct bContext *C, struct ID *id) RET_NONE void ED_screen_animation_timer_update(struct bScreen *screen, int redraws, int refresh) RET_NONE struct bScreen *ED_screen_animation_playing(const struct wmWindowManager *wm) RET_NULL @@ -564,6 +564,7 @@ void uiTemplateColorspaceSettings(struct uiLayout *layout, struct PointerRNA *pt void uiTemplateColormanagedViewSettings(struct uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname) RET_NONE void uiTemplateComponentMenu(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name) RET_NONE void uiTemplateNodeSocket(struct uiLayout *layout, struct bContext *C, float *color) RET_NONE +void uiTemplatePalette(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname, int color) RET_NONE /* rna render */ struct RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername) RET_NULL diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 8deadb9c7b7..fbda69225b3 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -274,7 +274,7 @@ elseif(APPLE) if(WITH_PYTHON_MODULE) set(TARGETDIR_VER ${TARGETDIR}/${BLENDER_VERSION}) else() - set(TARGETDIR_VER ${TARGETDIR}/blender.app/Contents/MacOS/${BLENDER_VERSION}) + set(TARGETDIR_VER ${TARGETDIR}/blender.app/Contents/Resources/${BLENDER_VERSION}) endif() endif() @@ -511,16 +511,22 @@ if(UNIX AND NOT APPLE) PATTERN "idlelib" EXCLUDE # ./idlelib PATTERN "test" EXCLUDE # ./test PATTERN "turtledemo" EXCLUDE # ./turtledemo - PATTERN "turtle.py" EXCLUDE # ./turtle.py + PATTERN "turtle.py" EXCLUDE # ./turtle.py ) # # doesnt work, todo # install(CODE "execute_process(COMMAND find ${TARGETDIR}/${BLENDER_VERSION}/python/lib/ -name '*.so' -exec strip -s {} '\;')") - + if(WITH_PYTHON_INSTALL_NUMPY) + # Install to the same directory as the source, so debian-like + # distros are happy with their policy. + set(_suffix "site-packages") + if(${PYTHON_NUMPY_PATH} MATCHES "dist-packages") + set(_suffix "dist-packages") + endif() install( DIRECTORY ${PYTHON_NUMPY_PATH}/numpy - DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}/python${PYTHON_VERSION}/site-packages + DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}/python${PYTHON_VERSION}/${_suffix} PATTERN ".svn" EXCLUDE PATTERN "__pycache__" EXCLUDE # * any cache * PATTERN "*.pyc" EXCLUDE # * any cache * @@ -534,19 +540,47 @@ if(UNIX AND NOT APPLE) PATTERN "*.h" EXCLUDE # some includes are not in include dirs PATTERN "*.a" EXCLUDE # ./core/lib/libnpymath.a - for linking, we dont need. ) + unset(_suffix) endif() # Copy requests, we need to generalize site-packages if(WITH_PYTHON_INSTALL_REQUESTS) + set(_suffix "site-packages") + if(${PYTHON_REQUESTS_PATH} MATCHES "dist-packages") + set(_suffix "dist-packages") + endif() install( - DIRECTORY ${PYTHON_LIBPATH}/python${PYTHON_VERSION}/site-packages/requests - DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}/python${PYTHON_VERSION}/site-packages + DIRECTORY ${PYTHON_REQUESTS_PATH}/requests + DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}/python${PYTHON_VERSION}/${_suffix} PATTERN ".svn" EXCLUDE PATTERN "__pycache__" EXCLUDE # * any cache * PATTERN "*.pyc" EXCLUDE # * any cache * PATTERN "*.pyo" EXCLUDE # * any cache * PATTERN "cacert.pem" EXCLUDE # for now we don't deal with security ) + # On some platforms requests does have extra dependencies. + set(_requests_deps "chardet" "urllib3") + foreach(_requests_dep ${_requests_deps}) + if(EXISTS ${PYTHON_REQUESTS_PATH}/${_requests_dep}) + install( + DIRECTORY ${PYTHON_REQUESTS_PATH}/${_requests_dep} + DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}/python${PYTHON_VERSION}/${_suffix} + PATTERN ".svn" EXCLUDE + PATTERN "__pycache__" EXCLUDE # * any cache * + PATTERN "*.pyc" EXCLUDE # * any cache * + PATTERN "*.pyo" EXCLUDE # * any cache * + ) + endif() + endforeach() + if(EXISTS ${PYTHON_REQUESTS_PATH}/six.py) + install( + FILES ${PYTHON_REQUESTS_PATH}/six.py + DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}/python${PYTHON_VERSION}/${_suffix} + ) + endif() + unset(_requests_dep) + unset(_requests_deps) + unset(_suffix) endif() unset(_target_LIB) @@ -703,12 +737,10 @@ elseif(WIN32) endif() if(WITH_SDL) - if(NOT CMAKE_CL_64) - install( - FILES ${LIBDIR}/sdl/lib/SDL.dll - DESTINATION ${TARGETDIR} - ) - endif() + install( + FILES ${LIBDIR}/sdl/lib/SDL.dll + DESTINATION ${TARGETDIR} + ) endif() if(NOT CMAKE_CL_64) @@ -794,6 +826,13 @@ elseif(APPLE) ) endif() + if(WITH_LLVM AND NOT LLVM_STATIC) + install( + FILES ${LIBDIR}/llvm/lib/libLLVM-3.4.dylib + DESTINATION ${TARGETDIR}/blender.app/Contents/MacOS + ) + endif() + # python if(WITH_PYTHON AND NOT WITH_PYTHON_MODULE AND NOT WITH_PYTHON_FRAMEWORK) # the python zip is first extract as part of the build process, @@ -893,3 +932,18 @@ setup_blender_sorted_libs() target_link_libraries(blender ${BLENDER_SORTED_LIBS}) setup_liblinks(blender) + +# ----------------------------------------------------------------------------- +# Setup launcher + +if(WIN32 AND NOT WITH_PYTHON_MODULE) + set(LAUNCHER_SRC + creator_launch_win.c + ../icons/winblender.rc + ) + add_executable(blender-launcher ${LAUNCHER_SRC}) + target_link_libraries(blender-launcher ${PLATFORM_LINKLIBS}) + + set_target_properties(blender PROPERTIES OUTPUT_NAME blender-app) + set_target_properties(blender-launcher PROPERTIES OUTPUT_NAME blender) +endif() diff --git a/source/creator/creator_launch_win.c b/source/creator/creator_launch_win.c new file mode 100644 index 00000000000..e998343c876 --- /dev/null +++ b/source/creator/creator_launch_win.c @@ -0,0 +1,69 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2014 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/* Binary name to launch. */ +#define BLENDER_BINARY "blender-app.exe" + +#define WIN32_LEAN_AND_MEAN +#include <stdio.h> +#include <stdlib.h> +#include <windows.h> + +int main(int argc, char **argv) +{ + PROCESS_INFORMATION processInformation = {0}; + STARTUPINFOA startupInfo = {0}; + BOOL result; + char command[65536]; + int i, len = sizeof(command); + + _putenv_s("OMP_WAIT_POLICY", "PASSIVE"); + + startupInfo.cb = sizeof(startupInfo); + + strncpy(command, BLENDER_BINARY, len - 1); + len -= strlen(BLENDER_BINARY); + for (i = 1; i < argc; ++i) { + strncat(command, " ", len - 1); + strncat(command, argv[i], len - 2); + len -= strlen(argv[i]) + 1; + } + + result = CreateProcessA(NULL, command, NULL, NULL, TRUE, + 0, NULL, NULL, + &startupInfo, &processInformation); + + if (!result) { + fprintf(stderr, "Error launching " BLENDER_BINARY "\n"); + return EXIT_FAILURE; + } + + WaitForSingleObject(processInformation.hProcess, INFINITE); + + CloseHandle(processInformation.hProcess); + CloseHandle(processInformation.hThread); + + return EXIT_SUCCESS; +} diff --git a/source/creator/osx_locals.map b/source/creator/osx_locals.map index c3dd8b62792..a1d7e7fed57 100644 --- a/source/creator/osx_locals.map +++ b/source/creator/osx_locals.map @@ -1,3 +1,5 @@ ## The symbols will be treated as if they were marked as __private_extern__ ## (aka visibility=hidden) and will not be global in the output file *boost* +*__ZNSt6vector* + diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp index e11bc84a0da..8d73e591113 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.cpp +++ b/source/gameengine/Converter/BL_ArmatureObject.cpp @@ -101,7 +101,7 @@ static void game_copy_pose(bPose **dst, bPose *src, int copy_constraint) out->chanhash = NULL; out->agroups.first= out->agroups.last= NULL; out->ikdata = NULL; - out->ikparam = MEM_dupallocN(out->ikparam); + out->ikparam = MEM_dupallocN(src->ikparam); out->flag |= POSE_GAME_ENGINE; BLI_duplicatelist(&out->chanbase, &src->chanbase); @@ -231,6 +231,8 @@ BL_ArmatureObject::BL_ArmatureObject( m_objArma = BKE_object_copy(armature); m_objArma->data = BKE_armature_copy((bArmature *)armature->data); m_pose = m_objArma->pose; + // need this to get iTaSC working ok in the BGE + m_pose->flag |= POSE_GAME_ENGINE; memcpy(m_obmat, m_objArma->obmat, sizeof(m_obmat)); } diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index e511f01e9c6..87b64582e11 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -876,7 +876,7 @@ static bool ConvertMaterial( material->alphablend = GEMAT_ALPHA; // always zsort alpha + add - if ((ELEM3(material->alphablend, GEMAT_ALPHA, GEMAT_ALPHA_SORT, GEMAT_ADD) || texalpha) && (material->alphablend != GEMAT_CLIP )) { + if ((ELEM(material->alphablend, GEMAT_ALPHA, GEMAT_ALPHA_SORT, GEMAT_ADD) || texalpha) && (material->alphablend != GEMAT_CLIP )) { material->ras_mode |= ALPHA; material->ras_mode |= (mat && (mat->game.alpha_blend & GEMAT_ALPHA_SORT))? ZSORT: 0; } diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp index 68a71218b8c..9ebdfea6156 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp @@ -616,7 +616,7 @@ void KX_BlenderMaterial::ActivateMeshSlot(const RAS_MeshSlot & ms, RAS_IRasteriz /* we do blend modes here, because they can change per object * with the same material due to obcolor/obalpha */ alphablend = mBlenderShader->GetAlphaBlend(); - if (ELEM3(alphablend, GEMAT_SOLID, GEMAT_ALPHA, GEMAT_ALPHA_SORT) && mMaterial->alphablend != GEMAT_SOLID) + if (ELEM(alphablend, GEMAT_SOLID, GEMAT_ALPHA, GEMAT_ALPHA_SORT) && mMaterial->alphablend != GEMAT_SOLID) alphablend = mMaterial->alphablend; rasty->SetAlphaBlend(alphablend); diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index 639cd98bb47..c681e0842c4 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -51,6 +51,7 @@ typedef unsigned long uint_ptr; #include "KX_Light.h" // only for their ::Type #include "KX_FontObject.h" // only for their ::Type #include "RAS_MeshObject.h" +#include "KX_NavMeshObject.h" #include "KX_MeshProxy.h" #include "KX_PolyProxy.h" #include <stdio.h> // printf @@ -3795,7 +3796,8 @@ bool ConvertPythonToGameObject(PyObject *value, KX_GameObject **object, bool py_ if ( PyObject_TypeCheck(value, &KX_GameObject::Type) || PyObject_TypeCheck(value, &KX_LightObject::Type) || PyObject_TypeCheck(value, &KX_Camera::Type) || - PyObject_TypeCheck(value, &KX_FontObject::Type)) + PyObject_TypeCheck(value, &KX_FontObject::Type) || + PyObject_TypeCheck(value, &KX_NavMeshObject::Type)) { *object = static_cast<KX_GameObject*>BGE_PROXY_REF(value); diff --git a/source/gameengine/Ketsji/KX_Light.cpp b/source/gameengine/Ketsji/KX_Light.cpp index 37c36da0db3..5b5981f930b 100644 --- a/source/gameengine/Ketsji/KX_Light.cpp +++ b/source/gameengine/Ketsji/KX_Light.cpp @@ -231,7 +231,7 @@ int KX_LightObject::pyattr_set_distance(void *self_v, const KX_PYATTRIBUTE_DEF * else if (val > 5000.f) val = 5000.f; - self->m_lightobj->m_energy = val; + self->m_lightobj->m_distance = val; return PY_SET_ATTR_SUCCESS; } diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp index e21ac386bc8..a9f6bb0d2ff 100644 --- a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp +++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp @@ -72,9 +72,9 @@ KX_MouseFocusSensor::KX_MouseFocusSensor(SCA_MouseManager* eventmgr, : SCA_MouseSensor(eventmgr, startx, starty, mousemode, gameobj), m_focusmode(focusmode), m_bTouchPulse(bTouchPulse), - m_propertyname(propname), - m_bFindMaterial(bFindMaterial), m_bXRay(bXRay), + m_bFindMaterial(bFindMaterial), + m_propertyname(propname), m_kxscene(kxscene), m_kxengine(kxengine) { diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.h b/source/gameengine/Ketsji/KX_MouseFocusSensor.h index 903c3c03571..0c7c8ab676a 100644 --- a/source/gameengine/Ketsji/KX_MouseFocusSensor.h +++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.h @@ -137,7 +137,7 @@ class KX_MouseFocusSensor : public SCA_MouseSensor bool m_bTouchPulse; /** - * Flags get trought other objects + * Flags get through other objects */ bool m_bXRay; diff --git a/source/gameengine/Ketsji/KX_NavMeshObject.cpp b/source/gameengine/Ketsji/KX_NavMeshObject.cpp index 998b856497e..8360681759a 100644 --- a/source/gameengine/Ketsji/KX_NavMeshObject.cpp +++ b/source/gameengine/Ketsji/KX_NavMeshObject.cpp @@ -111,7 +111,7 @@ bool KX_NavMeshObject::BuildVertIndArrays(float *&vertices, int& nverts, float *&dvertices, int &ndvertsuniq, unsigned short *&dtris, int& ndtris, int &vertsPerPoly) { - DerivedMesh* dm = mesh_create_derived_no_virtual(KX_GetActiveScene()->GetBlenderScene(), GetBlenderObject(), + DerivedMesh* dm = mesh_create_derived_no_virtual(GetScene()->GetBlenderScene(), GetBlenderObject(), NULL, CD_MASK_MESH); CustomData *pdata = dm->getPolyDataLayout(dm); int* recastData = (int*) CustomData_get_layer(pdata, CD_RECAST); diff --git a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp index e9843b0af5b..ebf1b9ec577 100644 --- a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp +++ b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp @@ -740,6 +740,7 @@ PyObject *initPythonConstraintBinding() KX_MACRO_addTypesToDict(d, ANGULAR_CONSTRAINT, PHY_ANGULAR_CONSTRAINT); KX_MACRO_addTypesToDict(d, CONETWIST_CONSTRAINT, PHY_CONE_TWIST_CONSTRAINT); KX_MACRO_addTypesToDict(d, VEHICLE_CONSTRAINT, PHY_VEHICLE_CONSTRAINT); + KX_MACRO_addTypesToDict(d, GENERIC_6DOF_CONSTRAINT, PHY_GENERIC_6DOF_CONSTRAINT); // Check for errors if (PyErr_Occurred()) { diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index bbf9f427a6c..dc603319df4 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -201,7 +201,16 @@ static PyObject *gp_OrigPythonSysModules= NULL; //#define KX_MACRO_addToDict(dict, name) PyDict_SetItemString(dict, #name, PyLong_FromLong(SCA_IInputDevice::KX_##name)) //#define KX_MACRO_addToDict(dict, name) PyDict_SetItemString(dict, #name, item=PyLong_FromLong(name)); Py_DECREF(item) /* For the defines for types from logic bricks, we do stuff explicitly... */ -#define KX_MACRO_addTypesToDict(dict, name, name2) PyDict_SetItemString(dict, #name, item=PyLong_FromLong(name2)); Py_DECREF(item) +#define KX_MACRO_addTypesToDict(dict, name, value) KX_MACRO_addTypesToDict_fn(dict, #name, value) +static void KX_MACRO_addTypesToDict_fn(PyObject *dict, const char *name, long value) +{ + PyObject *item; + + item = PyLong_FromLong(value); + PyDict_SetItemString(dict, name, item); + Py_DECREF(item); +} + // temporarily python stuff, will be put in another place later ! @@ -2270,7 +2279,6 @@ PyObject *initRasterizer(RAS_IRasterizer* rasty,RAS_ICanvas* canvas) PyObject *m; PyObject *d; - PyObject *item; /* Use existing module where possible * be careful not to init any runtime vars after this */ @@ -2400,7 +2408,6 @@ PyObject *initGameKeys() { PyObject *m; PyObject *d; - PyObject *item; /* Use existing module where possible */ m = PyImport_ImportModule( "GameKeys" ); diff --git a/source/gameengine/Ketsji/KX_SteeringActuator.cpp b/source/gameengine/Ketsji/KX_SteeringActuator.cpp index 2fa72c04a20..ff192299702 100644 --- a/source/gameengine/Ketsji/KX_SteeringActuator.cpp +++ b/source/gameengine/Ketsji/KX_SteeringActuator.cpp @@ -602,7 +602,7 @@ int KX_SteeringActuator::pyattr_set_navmesh(void *self, const struct KX_PYATTRIB if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: KX_SteeringActuator")) return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error - if (!PyObject_TypeCheck(value, &KX_NavMeshObject::Type)) + if (dynamic_cast<KX_NavMeshObject *>(gameobj) == NULL) { PyErr_Format(PyExc_TypeError, "KX_NavMeshObject is expected"); return PY_SET_ATTR_FAIL; diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp index db2c21226d8..e17d4402556 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp @@ -84,7 +84,7 @@ void DrawRasterizerLine(const float* from,const float* to,int color); // This was copied from the old KX_ConvertPhysicsObjects #ifdef WIN32 -#if defined(_MSC_VER) && (_MSC_VER >= 1310) +#ifdef _MSC_VER //only use SIMD Hull code under Win32 //#define TEST_HULL 1 #ifdef TEST_HULL diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp index b138f84ea97..c8975c245cb 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp @@ -247,7 +247,7 @@ void RAS_StorageIM::IndexPrimitivesInternal(RAS_MeshSlot& ms, bool multi) //ms.m_pDerivedMesh->drawMappedFacesTex(ms.m_pDerivedMesh, CheckTexfaceDM, mcol); current_blmat_nr = current_polymat->GetMaterialIndex(); current_image = current_polymat->GetBlenderImage(); - ms.m_pDerivedMesh->drawFacesTex(ms.m_pDerivedMesh, CheckTexDM, NULL, NULL); + ms.m_pDerivedMesh->drawFacesTex(ms.m_pDerivedMesh, CheckTexDM, NULL, NULL, DM_DRAW_USE_ACTIVE_UV); } return; } diff --git a/source/gameengine/VideoTexture/ImageBuff.cpp b/source/gameengine/VideoTexture/ImageBuff.cpp index 6cc8d287e66..705d9136cbe 100644 --- a/source/gameengine/VideoTexture/ImageBuff.cpp +++ b/source/gameengine/VideoTexture/ImageBuff.cpp @@ -163,7 +163,7 @@ void ImageBuff::plot(unsigned char *img, short width, short height, short x, sho // assign temporarily our buffer to the ImBuf buffer, we use the same format tmpbuf->rect = (unsigned int*)img; m_imbuf->rect = m_image; - IMB_rectblend(m_imbuf, m_imbuf, tmpbuf, NULL, NULL, 0, x, y, x, y, 0, 0, width, height, (IMB_BlendMode)mode); + IMB_rectblend(m_imbuf, m_imbuf, tmpbuf, NULL, NULL, NULL, 0, x, y, x, y, 0, 0, width, height, (IMB_BlendMode)mode, false); // remove so that MB_freeImBuf will free our buffer m_imbuf->rect = NULL; tmpbuf->rect = NULL; @@ -186,7 +186,7 @@ void ImageBuff::plot(ImageBuff *img, short x, short y, short mode) // assign temporarily our buffer to the ImBuf buffer, we use the same format img->m_imbuf->rect = img->m_image; m_imbuf->rect = m_image; - IMB_rectblend(m_imbuf, m_imbuf, img->m_imbuf, NULL, NULL, 0, x, y, x, y, 0, 0, img->m_imbuf->x, img->m_imbuf->y, (IMB_BlendMode)mode); + IMB_rectblend(m_imbuf, m_imbuf, img->m_imbuf, NULL, NULL, NULL, 0, x, y, x, y, 0, 0, img->m_imbuf->x, img->m_imbuf->y, (IMB_BlendMode)mode, false); // remove so that MB_freeImBuf will free our buffer m_imbuf->rect = NULL; img->m_imbuf->rect = NULL; |