diff options
author | Tamito Kajiyama <rd6t-kjym@asahi-net.or.jp> | 2013-01-06 02:24:05 +0400 |
---|---|---|
committer | Tamito Kajiyama <rd6t-kjym@asahi-net.or.jp> | 2013-01-06 02:24:05 +0400 |
commit | feccbaabbd39c18b2f552964ebd8dfab4eeaed89 (patch) | |
tree | 0069f654883a7a02dd320649ce61bd7933748111 /source/blender/editors | |
parent | a22096e8019c461128a0907e4026859996ec1b5c (diff) | |
parent | 37ba969c74840142682cf22f34610f3b65b86cf4 (diff) |
Merged changes in the trunk up to revision 53584.
Conflicts resolved:
release/scripts/startup/bl_ui/properties_render.py
source/blender/blenloader/intern/readfile.c
source/blender/editors/interface/interface_templates.c
source/blender/makesrna/RNA_enum_types.h
Also made additional code updates for:
r53355 UIList - Python-extendable list of UI items
r53460 Alpha premul pipeline cleanup
Diffstat (limited to 'source/blender/editors')
109 files changed, 5253 insertions, 2353 deletions
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index ca036a8540e..6687cce88cd 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -62,16 +62,28 @@ /* Check if the operator can be run from the current context */ static int change_frame_poll(bContext *C) { - ScrArea *curarea = CTX_wm_area(C); + ScrArea *sa = CTX_wm_area(C); /* XXX temp? prevent changes during render */ - if (G.is_rendering) return 0; + if (G.is_rendering) return FALSE; - /* as long as there is an active area, and it isn't a Graph Editor - * (since the Graph Editor has its own version which does extra stuff), - * we're fine + /* although it's only included in keymaps for regions using ED_KEYMAP_ANIMATION, + * this shouldn't show up in 3D editor (or others without 2D timeline view) via search */ - return ((curarea) && (curarea->spacetype != SPACE_IPO)); + if (sa) { + if (ELEM5(sa->spacetype, SPACE_TIME, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) { + return TRUE; + } + else if (sa->spacetype == SPACE_IPO) { + /* NOTE: Graph Editor has special version which does some extra stuff. + * No need to show the generic error message for that case though! + */ + return FALSE; + } + } + + CTX_wm_operator_poll_msg_set(C, "Expected an timeline/animation area to be active"); + return FALSE; } /* Set the new frame number */ @@ -83,7 +95,7 @@ static void change_frame_apply(bContext *C, wmOperator *op) /* set the new frame number */ CFRA = RNA_int_get(op->ptr, "frame"); FRAMENUMBER_MIN_CLAMP(CFRA); - SUBFRA = 0.f; + SUBFRA = 0.0f; /* do updates */ sound_seek_scene(bmain, scene); @@ -161,7 +173,7 @@ static int change_frame_modal(bContext *C, wmOperator *op, wmEvent *event) static void ANIM_OT_change_frame(wmOperatorType *ot) { /* identifiers */ - ot->name = "Change frame"; + ot->name = "Change Frame"; ot->idname = "ANIM_OT_change_frame"; ot->description = "Interactively change the current frame number"; @@ -175,7 +187,7 @@ static void ANIM_OT_change_frame(wmOperatorType *ot) ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO | OPTYPE_GRAB_POINTER; /* rna */ - RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME); + ot->prop = RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME); } /* ****************** set preview range operator ****************************/ diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 8ba330e7c3c..9add193a514 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -540,8 +540,8 @@ static float setting_get_rna_value(PointerRNA *ptr, PropertyRNA *prop, int index enum { VISUALKEY_NONE = 0, VISUALKEY_LOC, - VISUALKEY_ROT - /* VISUALKEY_SCA */ /* TODO - looks like support can be added now */ + VISUALKEY_ROT, + VISUALKEY_SCA, }; /* This helper function determines if visual-keyframing should be used when @@ -560,7 +560,7 @@ static short visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop) /* validate data */ if (ELEM3(NULL, ptr, ptr->data, prop)) return 0; - + /* get first constraint and determine type of keyframe constraints to check for * - constraints can be on either Objects or PoseChannels, so we only check if the * ptr->type is RNA_Object or RNA_PoseBone, which are the RNA wrapping-info for @@ -586,7 +586,7 @@ static short visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop) /* check if any data to search using */ if (ELEM(NULL, con, identifier) && (has_parent == FALSE)) return 0; - + /* location or rotation identifiers only... */ if (identifier == NULL) { printf("%s failed: NULL identifier\n", __func__); @@ -598,6 +598,9 @@ static short visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop) else if (strstr(identifier, "rotation")) { searchtype = VISUALKEY_ROT; } + else if (strstr(identifier, "scale")) { + searchtype = VISUALKEY_SCA; + } else { printf("%s failed: identifier - '%s'\n", __func__, identifier); return 0; @@ -628,7 +631,7 @@ static short visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop) return 1; case CONSTRAINT_TYPE_KINEMATIC: return 1; - + /* single-transform constraits */ case CONSTRAINT_TYPE_TRACKTO: if (searchtype == VISUALKEY_ROT) return 1; @@ -642,15 +645,21 @@ static short visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop) case CONSTRAINT_TYPE_LOCLIMIT: if (searchtype == VISUALKEY_LOC) return 1; break; - case CONSTRAINT_TYPE_ROTLIKE: - if (searchtype == VISUALKEY_ROT) return 1; + case CONSTRAINT_TYPE_SIZELIMIT: + if (searchtype == VISUALKEY_SCA) return 1; break; case CONSTRAINT_TYPE_DISTLIMIT: if (searchtype == VISUALKEY_LOC) return 1; break; + case CONSTRAINT_TYPE_ROTLIKE: + if (searchtype == VISUALKEY_ROT) return 1; + break; case CONSTRAINT_TYPE_LOCLIKE: if (searchtype == VISUALKEY_LOC) return 1; break; + case CONSTRAINT_TYPE_SIZELIKE: + if (searchtype == VISUALKEY_SCA) return 1; + break; case CONSTRAINT_TYPE_LOCKTRACK: if (searchtype == VISUALKEY_ROT) return 1; break; @@ -675,45 +684,26 @@ static short visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop) static float visualkey_get_value(PointerRNA *ptr, PropertyRNA *prop, int array_index) { const char *identifier = RNA_property_identifier(prop); + float tmat[4][4]; + int rotmode; /* handle for Objects or PoseChannels only + * - only Location, Rotation or Scale keyframes are supported curently * - constraints can be on either Objects or PoseChannels, so we only check if the - * ptr->type is RNA_Object or RNA_PoseBone, which are the RNA wrapping-info for + * ptr->type is RNA_Object or RNA_PoseBone, which are the RNA wrapping-info for * those structs, allowing us to identify the owner of the data - * - assume that array_index will be sane + * - assume that array_index will be sane */ if (ptr->type == &RNA_Object) { Object *ob = (Object *)ptr->data; - - /* only Location or Rotation keyframes are supported now */ + + /* Loc code is specific... */ if (strstr(identifier, "location")) { return ob->obmat[3][array_index]; } - else if (strstr(identifier, "rotation_euler")) { - float eul[3]; - - mat4_to_eulO(eul, ob->rotmode, ob->obmat); - return eul[array_index]; - } - else if (strstr(identifier, "rotation_quaternion")) { - float trimat[3][3], quat[4]; - - copy_m3_m4(trimat, ob->obmat); - mat3_to_quat_is_ok(quat, trimat); - - return quat[array_index]; - } - else if (strstr(identifier, "rotation_axis_angle")) { - float axis[3], angle; - - mat4_to_axis_angle(axis, &angle, ob->obmat); - - /* w = 0, x,y,z = 1,2,3 */ - if (array_index == 0) - return angle; - else - return axis[array_index - 1]; - } + + copy_m4_m4(tmat, ob->obmat); + rotmode = ob->rotmode; } else if (ptr->type == &RNA_PoseBone) { Object *ob = (Object *)ptr->id.data; /* we assume that this is always set, and is an object */ @@ -726,42 +716,53 @@ static float visualkey_get_value(PointerRNA *ptr, PropertyRNA *prop, int array_i * will be what owns the pose-channel that is getting this anyway. */ copy_m4_m4(tmat, pchan->pose_mat); - constraint_mat_convertspace(ob, pchan, tmat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL); + BKE_constraint_mat_convertspace(ob, pchan, tmat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL); + rotmode = pchan->rotmode; - /* Loc, Rot/Quat keyframes are supported... */ + /* Loc code is specific... */ if (strstr(identifier, "location")) { /* only use for non-connected bones */ - if ((pchan->bone->parent) && !(pchan->bone->flag & BONE_CONNECTED)) + if ((pchan->bone->parent == NULL) || !(pchan->bone->flag & BONE_CONNECTED)) return tmat[3][array_index]; - else if (pchan->bone->parent == NULL) - return tmat[3][array_index]; - } - else if (strstr(identifier, "rotation_euler")) { - float eul[3]; - - mat4_to_eulO(eul, pchan->rotmode, tmat); - return eul[array_index]; - } - else if (strstr(identifier, "rotation_quaternion")) { - float trimat[3][3], quat[4]; - - copy_m3_m4(trimat, tmat); - mat3_to_quat_is_ok(quat, trimat); - - return quat[array_index]; - } - else if (strstr(identifier, "rotation_axis_angle")) { - float axis[3], angle; - - mat4_to_axis_angle(axis, &angle, tmat); - - /* w = 0, x,y,z = 1,2,3 */ - if (array_index == 0) - return angle; - else - return axis[array_index - 1]; } } + else { + return setting_get_rna_value(ptr, prop, array_index); + } + + /* Rot/Scale code are common! */ + if (strstr(identifier, "rotation_euler")) { + float eul[3]; + + mat4_to_eulO(eul, rotmode, tmat); + return eul[array_index]; + } + else if (strstr(identifier, "rotation_quaternion")) { + float mat3[3][3], quat[4]; + + copy_m3_m4(mat3, tmat); + mat3_to_quat_is_ok(quat, mat3); + + return quat[array_index]; + } + else if (strstr(identifier, "rotation_axis_angle")) { + float axis[3], angle; + + mat4_to_axis_angle(axis, &angle, tmat); + + /* w = 0, x,y,z = 1,2,3 */ + if (array_index == 0) + return angle; + else + return axis[array_index - 1]; + } + else if (strstr(identifier, "scale")) { + float scale[3]; + + mat4_to_size(scale, tmat); + + return scale[array_index]; + } /* as the function hasn't returned yet, read value from system in the default way */ return setting_get_rna_value(ptr, prop, array_index); diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c index ae405c0e113..37314373e98 100644 --- a/source/blender/editors/armature/editarmature.c +++ b/source/blender/editors/armature/editarmature.c @@ -812,7 +812,7 @@ static void joined_armature_fix_links(Object *tarArm, Object *srcArm, bPoseChann pose = ob->pose; for (pchant = pose->chanbase.first; pchant; pchant = pchant->next) { for (con = pchant->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -859,7 +859,7 @@ static void joined_armature_fix_links(Object *tarArm, Object *srcArm, bPoseChann /* fix object-level constraints */ if (ob != srcArm) { for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -1032,7 +1032,7 @@ static void separated_armature_fix_links(Object *origArm, Object *newArm) if (ob->type == OB_ARMATURE) { for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -1070,7 +1070,7 @@ static void separated_armature_fix_links(Object *origArm, Object *newArm) /* fix object-level constraints */ if (ob != origArm) { for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -1712,7 +1712,7 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op)) } else { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -2523,7 +2523,7 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Obj /* does this constraint have a subtarget in * this armature? */ - bConstraintTypeInfo *cti = constraint_get_typeinfo(curcon); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(curcon); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -5533,7 +5533,7 @@ static void constraint_bone_name_fix(Object *ob, ListBase *conlist, char *oldnam bConstraintTarget *ct; for (curcon = conlist->first; curcon; curcon = curcon->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(curcon); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(curcon); ListBase targets = {NULL, NULL}; if (cti && cti->get_constraint_targets) { diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c index 68cfc7fb8c0..3e34a4c6808 100644 --- a/source/blender/editors/armature/editarmature_retarget.c +++ b/source/blender/editors/armature/editarmature_retarget.c @@ -725,7 +725,7 @@ static void RIG_reconnectControlBones(RigGraph *rg) /* DO SOME MAGIC HERE */ for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -850,7 +850,7 @@ static void RIG_reconnectControlBones(RigGraph *rg) /* DO SOME MAGIC HERE */ for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -1830,7 +1830,9 @@ static float calcCostLengthDistance(BArcIterator *iter, float **vec_cache, RigEd } #endif -static float calcCostAngleLengthDistance(BArcIterator *iter, float **UNUSED(vec_cache), RigEdge *edge, float *vec0, float *vec1, float *vec2, int i1, int i2, float angle_weight, float length_weight, float distance_weight) +static float calcCostAngleLengthDistance(BArcIterator *iter, float **UNUSED(vec_cache), RigEdge *edge, + float *vec0, float *vec1, float *vec2, int i1, int i2, + float angle_weight, float length_weight, float distance_weight) { float vec_second[3], vec_first[3]; float length2; @@ -1878,7 +1880,9 @@ static void copyMemoPositions(int *positions, MemoNode *table, int nb_positions, } } -static MemoNode *solveJoints(MemoNode *table, BArcIterator *iter, float **vec_cache, int nb_joints, int nb_positions, int previous, int current, RigEdge *edge, int joints_left, float angle_weight, float length_weight, float distance_weight) +static MemoNode *solveJoints(MemoNode *table, BArcIterator *iter, float **vec_cache, + int nb_joints, int nb_positions, int previous, int current, RigEdge *edge, + int joints_left, float angle_weight, float length_weight, float distance_weight) { MemoNode *node; int index = indexMemoNode(nb_positions, previous, current, joints_left); diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index 2848db18d59..19a97fa0810 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -649,7 +649,9 @@ static float heat_limit_weight(float weight) return weight; } -void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3], int *selected, const char **err_str) +void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, + bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, + float (*root)[3], float (*tip)[3], int *selected, const char **err_str) { LaplacianSystem *sys; MPoly *mp; diff --git a/source/blender/editors/armature/poseobject.c b/source/blender/editors/armature/poseobject.c index 576e5983d16..49d4b670cde 100644 --- a/source/blender/editors/armature/poseobject.c +++ b/source/blender/editors/armature/poseobject.c @@ -417,7 +417,7 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op { if (pchan->bone->flag & BONE_SELECTED) { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -925,7 +925,7 @@ static void pose_copy_menu(Scene *scene) /* copy constraints to tmpbase and apply 'local' tags before * appending to list of constraints for this channel */ - copy_constraints(&tmp_constraints, &pchanact->constraints, TRUE); + BKE_copy_constraints(&tmp_constraints, &pchanact->constraints, TRUE); if ((ob->proxy) && (pchan->bone->layer & arm->layer_protected)) { bConstraint *con; @@ -1034,7 +1034,7 @@ static void pose_copy_menu(Scene *scene) /* copy constraints to tmpbase and apply 'local' tags before * appending to list of constraints for this channel */ - copy_constraints(&tmp_constraints, &const_copy, TRUE); + BKE_copy_constraints(&tmp_constraints, &const_copy, TRUE); if ((ob->proxy) && (pchan->bone->layer & arm->layer_protected)) { /* add proxy-local tags */ for (con = tmp_constraints.first; con; con = con->next) diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 1b4a67d38c0..f5ab002e0ef 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -291,9 +291,9 @@ int mesh_get_x_mirror_vert(struct Object *ob, int index); struct BMVert *editbmesh_get_x_mirror_vert(struct Object *ob, struct BMEditMesh *em, struct BMVert *eve, const float co[3], int index); int *mesh_get_x_mirror_faces(struct Object *ob, struct BMEditMesh *em); -int ED_mesh_pick_vert(struct bContext *C, struct Mesh *me, const int mval[2], unsigned int *index, int size); -int ED_mesh_pick_face(struct bContext *C, struct Mesh *me, const int mval[2], unsigned int *index, int size); -int ED_mesh_pick_face_vert(struct bContext *C, struct Mesh *me, struct Object *ob, const int mval[2], unsigned int *index, int size); +int ED_mesh_pick_vert(struct bContext *C, struct Object *ob, const int mval[2], unsigned int *index, int size, int use_zbuf); +int ED_mesh_pick_face(struct bContext *C, struct Object *ob, const int mval[2], unsigned int *index, int size); +int ED_mesh_pick_face_vert(struct bContext *C, struct Object *ob, const int mval[2], unsigned int *index, int size); #define ED_MESH_PICK_DEFAULT_VERT_SIZE 50 #define ED_MESH_PICK_DEFAULT_FACE_SIZE 3 diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index f7f58a4ee7a..3d13938c204 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -85,6 +85,7 @@ typedef struct ViewDepths { } ViewDepths; float *give_cursor(struct Scene *scene, struct View3D *v3d); +void ED_view3d_cursor3d_position(struct bContext *C, float *fp, int mx, int my); void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist); void ED_view3d_from_m4(float mat[4][4], float ofs[3], float quat[4], float *dist); @@ -124,6 +125,10 @@ typedef enum { /* view3d_iterators.c */ /* foreach iterators */ +void meshobject_foreachScreenVert( + struct ViewContext *vc, + void (*func)(void *userData, struct MVert *eve, const float screen_co[2], int index), + void *userData, const eV3DProjTest clip_flag); void mesh_foreachScreenVert( struct ViewContext *vc, void (*func)(void *userData, struct BMVert *eve, const float screen_co[2], int index), diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index 99f7f0856b3..0a794040692 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -699,9 +699,7 @@ DEF_ICON(RNDCURVE) DEF_ICON(PROP_OFF) DEF_ICON(PROP_ON) DEF_ICON(PROP_CON) -#ifndef DEF_ICON_BLANK_SKIP - DEF_ICON(BLANK212) -#endif +DEF_ICON(SCULPT_DYNTOPO) DEF_ICON(PARTICLE_POINT) DEF_ICON(PARTICLE_TIP) DEF_ICON(PARTICLE_PATH) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 90f8779b2c7..080367c4325 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -56,6 +56,7 @@ struct PropertyRNA; struct ReportList; struct rcti; struct rctf; +struct uiList; struct uiStyle; struct uiFontStyle; struct uiWidgetColors; @@ -658,6 +659,7 @@ void uiDrawPanels(const struct bContext *C, struct ARegion *ar); struct Panel *uiBeginPanel(struct ScrArea *sa, struct ARegion *ar, uiBlock *block, struct PanelType *pt, int *open); void uiEndPanel(uiBlock *block, int width, int height); +void uiScalePanels(struct ARegion *ar, float new_width); /* Handlers * @@ -778,7 +780,7 @@ uiLayout *uiLayoutRow(uiLayout *layout, int align); uiLayout *uiLayoutColumn(uiLayout *layout, int align); uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, int align); uiLayout *uiLayoutBox(uiLayout *layout); -uiLayout *uiLayoutListBox(uiLayout *layout, struct PointerRNA *ptr, struct PropertyRNA *prop, +uiLayout *uiLayoutListBox(uiLayout *layout, struct uiList *ui_list, struct PointerRNA *ptr, struct PropertyRNA *prop, struct PointerRNA *actptr, struct PropertyRNA *actprop); uiLayout *uiLayoutAbsolute(uiLayout *layout, int align); uiLayout *uiLayoutSplit(uiLayout *layout, float percentage, int align); @@ -824,7 +826,9 @@ void uiTemplateTextureImage(uiLayout *layout, struct bContext *C, struct Tex *te void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C); void uiTemplateKeymapItemProperties(uiLayout *layout, struct PointerRNA *ptr); -void uiTemplateList(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, struct PointerRNA *activeptr, const char *activeprop, const char *prop_list, int rows, int maxrows, int type); +void uiTemplateList(uiLayout *layout, struct bContext *C, const char *listtype_name, const char *list_id, + struct PointerRNA *dataptr, const char *propname, struct PointerRNA *active_dataptr, + const char *active_propname, int rows, int maxrows, int layout_type); void uiTemplateNodeLink(uiLayout *layout, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input); void uiTemplateNodeView(uiLayout *layout, struct bContext *C, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input); void uiTemplateTextureUser(uiLayout *layout, struct bContext *C); diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h index aa94bdec724..f578d68b852 100644 --- a/source/blender/editors/include/UI_interface_icons.h +++ b/source/blender/editors/include/UI_interface_icons.h @@ -32,12 +32,14 @@ #ifndef __UI_INTERFACE_ICONS_H__ #define __UI_INTERFACE_ICONS_H__ +struct bContext; struct Image; struct ImBuf; struct World; struct Tex; struct Lamp; struct Material; +struct PointerRNA; typedef struct IconFile { struct IconFile *next, *prev; @@ -74,5 +76,6 @@ void UI_icons_free_drawinfo(void *drawinfo); struct ListBase *UI_iconfile_list(void); int UI_iconfile_get_index(const char *filename); +int UI_rnaptr_icon_get(struct bContext *C, struct PointerRNA *ptr, int rnaicon, int big); #endif /* __UI_INTERFACE_ICONS_H__ */ diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index 236cc371d8b..1035f5815f2 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -122,9 +122,12 @@ enum { TH_SYNTAX_B, TH_SYNTAX_V, + TH_SYNTAX_R, TH_SYNTAX_C, TH_SYNTAX_L, + TH_SYNTAX_D, TH_SYNTAX_N, + TH_SYNTAX_S, TH_BONE_SOLID, TH_BONE_POSE, diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index 3ae1e93dc3d..81a0f526049 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -148,7 +148,6 @@ typedef struct View2DScrollers View2DScrollers; void UI_view2d_region_reinit(struct View2D *v2d, short type, int winx, int winy); void UI_view2d_curRect_validate(struct View2D *v2d); -void UI_view2d_curRect_validate_resize(struct View2D *v2d, int resize); void UI_view2d_curRect_reset(struct View2D *v2d); void UI_view2d_sync(struct bScreen *screen, struct ScrArea *sa, struct View2D *v2dcur, int flag); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 25f85883d9c..1d26cbd344b 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -2666,6 +2666,8 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str, /* we could do some more error checks here */ if ((type & BUTTYPE) == LABEL) { + if ((poin != NULL || min != 0.0f || max != 0.0f || (a1 == 0.0f && a2 != 0.0f) || (a1 != 0.0f && a1 != 1.0f))) + printf("blah\n"); BLI_assert((poin != NULL || min != 0.0f || max != 0.0f || (a1 == 0.0f && a2 != 0.0f) || (a1 != 0.0f && a1 != 1.0f)) == FALSE); } diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index fed84092133..1c9cd92271c 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -44,6 +44,7 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "BLI_math.h" #include "BLI_blenlib.h" @@ -219,6 +220,29 @@ static void button_timers_tooltip_remove(bContext *C, uiBut *but); /* ******************** menu navigation helpers ************** */ +/* assumes event type is MOUSEPAN */ +void ui_pan_to_scroll(wmEvent *event, int *type, int *val) +{ + static int lastdy = 0; + int dy = event->prevy - event->y; + + /* sign differs, reset */ + if ((dy > 0 && lastdy < 0) || (dy < 0 && lastdy > 0)) + lastdy = dy; + else { + lastdy += dy; + + if (ABS(lastdy) > (int)UI_UNIT_Y) { + *val = KM_PRESS; + if (event->prevy - event->y > 0) + *type = WHEELUPMOUSE; + else + *type = WHEELDOWNMOUSE; + lastdy = 0; + } + } +} + static int ui_but_editable(uiBut *but) { return ELEM5(but->type, LABEL, SEPR, ROUNDBOX, LISTBOX, PROGRESSBAR); @@ -1893,6 +1917,7 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle case WHEELUPMOUSE: case WHEELDOWNMOUSE: case MOUSEMOVE: + case MOUSEPAN: if (data->searchbox) ui_searchbox_event(C, data->searchbox, but, event); @@ -2687,12 +2712,16 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton ui_window_to_block(data->region, block, &mx, &my); if (data->state == BUTTON_STATE_HIGHLIGHT) { + int type = event->type, val = event->val; + + ui_pan_to_scroll(event, &type, &val); + /* XXX hardcoded keymap check.... */ - if (event->type == WHEELDOWNMOUSE && event->alt) { + if (type == WHEELDOWNMOUSE && event->alt) { mx = but->rect.xmin; click = 1; } - else if (event->type == WHEELUPMOUSE && event->alt) { + else if (type == WHEELUPMOUSE && event->alt) { mx = but->rect.xmax; click = 1; } @@ -2911,12 +2940,16 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton ui_window_to_block(data->region, block, &mx, &my); if (data->state == BUTTON_STATE_HIGHLIGHT) { + int type = event->type, val = event->val; + + ui_pan_to_scroll(event, &type, &val); + /* XXX hardcoded keymap check.... */ - if (event->type == WHEELDOWNMOUSE && event->alt) { + if (type == WHEELDOWNMOUSE && event->alt) { mx = but->rect.xmin; click = 2; } - else if (event->type == WHEELUPMOUSE && event->alt) { + else if (type == WHEELUPMOUSE && event->alt) { mx = but->rect.xmax; click = 2; } @@ -3142,7 +3175,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, wm } } else if (but->type == COLOR) { - if (ELEM(event->type, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) { + if (ELEM3(event->type, MOUSEPAN, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) { float *hsv = ui_block_hsv_get(but->block); float col[3]; @@ -3151,8 +3184,12 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, wm if (event->type == WHEELDOWNMOUSE) hsv[2] = CLAMPIS(hsv[2] - 0.05f, 0.0f, 1.0f); - else + else if (event->type == WHEELUPMOUSE) hsv[2] = CLAMPIS(hsv[2] + 0.05f, 0.0f, 1.0f); + else { + float fac = 0.005 * (event->y - event->prevy); + hsv[2] = CLAMPIS(hsv[2] + fac, 0.0f, 1.0f); + } hsv_to_rgb_v(hsv, data->vec); ui_set_but_vectorf(but, data->vec); @@ -5248,32 +5285,15 @@ static int ui_mouse_inside_region(ARegion *ar, int x, int y) */ if (ar->v2d.mask.xmin != ar->v2d.mask.xmax) { View2D *v2d = &ar->v2d; - rcti mask_rct; int mx, my; /* convert window coordinates to region coordinates */ mx = x; my = y; ui_window_to_region(ar, &mx, &my); - - /* make a copy of the mask rect, and tweak accordingly for hidden scrollbars */ - mask_rct = v2d->mask; - - if (v2d->scroll & (V2D_SCROLL_VERTICAL_HIDE | V2D_SCROLL_VERTICAL_FULLR)) { - if (v2d->scroll & V2D_SCROLL_LEFT) - mask_rct.xmin = v2d->vert.xmin; - else if (v2d->scroll & V2D_SCROLL_RIGHT) - mask_rct.xmax = v2d->vert.xmax; - } - if (v2d->scroll & (V2D_SCROLL_HORIZONTAL_HIDE | V2D_SCROLL_HORIZONTAL_FULLR)) { - if (v2d->scroll & (V2D_SCROLL_BOTTOM | V2D_SCROLL_BOTTOM_O)) - mask_rct.ymin = v2d->hor.ymin; - else if (v2d->scroll & V2D_SCROLL_TOP) - mask_rct.ymax = v2d->hor.ymax; - } - + /* check if in the rect */ - if (!BLI_rcti_isect_pt(&mask_rct, mx, my)) + if (!BLI_rcti_isect_pt(&v2d->mask, mx, my)) return 0; } @@ -6109,64 +6129,81 @@ static int ui_handle_list_event(bContext *C, wmEvent *event, ARegion *ar) uiBut *but = ui_list_find_mouse_over(ar, event->x, event->y); int retval = WM_UI_HANDLER_CONTINUE; int value, min, max; + int type = event->type, val = event->val; - if (but && (event->val == KM_PRESS)) { - Panel *pa = but->block->panel; + if (but) { + uiList *ui_list = but->custom_data; - if (ELEM(event->type, UPARROWKEY, DOWNARROWKEY) || - ((ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->alt))) - { - /* activate up/down the list */ - value = RNA_property_int_get(&but->rnapoin, but->rnaprop); + if (ui_list) { + + /* convert pan to scrollwheel */ + if (type == MOUSEPAN) { + ui_pan_to_scroll(event, &type, &val); + + /* if type still is mousepan, we call it handled, since delta-y accumulate */ + /* also see wm_event_system.c do_wheel_ui hack */ + if (type == MOUSEPAN) + retval = WM_UI_HANDLER_BREAK; + } + + if (val == KM_PRESS) { + + if (ELEM(type, UPARROWKEY, DOWNARROWKEY) || + ((ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->alt))) + { + /* activate up/down the list */ + value = RNA_property_int_get(&but->rnapoin, but->rnaprop); - if (ELEM(event->type, UPARROWKEY, WHEELUPMOUSE)) - value--; - else - value++; + if (ELEM(type, UPARROWKEY, WHEELUPMOUSE)) + value--; + else + value++; - CLAMP(value, 0, pa->list_last_len - 1); + CLAMP(value, 0, ui_list->list_last_len - 1); - if (value < pa->list_scroll) - pa->list_scroll = value; - else if (value >= pa->list_scroll + pa->list_size) - pa->list_scroll = value - pa->list_size + 1; + if (value < ui_list->list_scroll) + ui_list->list_scroll = value; + else if (value >= ui_list->list_scroll + ui_list->list_size) + ui_list->list_scroll = value - ui_list->list_size + 1; - RNA_property_int_range(&but->rnapoin, but->rnaprop, &min, &max); - value = CLAMPIS(value, min, max); + RNA_property_int_range(&but->rnapoin, but->rnaprop, &min, &max); + value = CLAMPIS(value, min, max); - RNA_property_int_set(&but->rnapoin, but->rnaprop, value); - RNA_property_update(C, &but->rnapoin, but->rnaprop); - ED_region_tag_redraw(ar); + RNA_property_int_set(&but->rnapoin, but->rnaprop, value); + RNA_property_update(C, &but->rnapoin, but->rnaprop); + ED_region_tag_redraw(ar); - retval = WM_UI_HANDLER_BREAK; - } - else if (ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->shift) { - /* silly replacement for proper grip */ - if (pa->list_grip_size == 0) - pa->list_grip_size = pa->list_size; + retval = WM_UI_HANDLER_BREAK; + } + else if (ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->shift) { + /* silly replacement for proper grip */ + if (ui_list->list_grip_size == 0) + ui_list->list_grip_size = ui_list->list_size; - if (event->type == WHEELUPMOUSE) - pa->list_grip_size--; - else - pa->list_grip_size++; + if (type == WHEELUPMOUSE) + ui_list->list_grip_size--; + else + ui_list->list_grip_size++; - pa->list_grip_size = MAX2(pa->list_grip_size, 1); + ui_list->list_grip_size = MAX2(ui_list->list_grip_size, 1); - ED_region_tag_redraw(ar); + ED_region_tag_redraw(ar); - retval = WM_UI_HANDLER_BREAK; - } - else if (ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE)) { - if (pa->list_last_len > pa->list_size) { - /* list template will clamp */ - if (event->type == WHEELUPMOUSE) - pa->list_scroll--; - else - pa->list_scroll++; + retval = WM_UI_HANDLER_BREAK; + } + else if (ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE)) { + if (ui_list->list_last_len > ui_list->list_size) { + /* list template will clamp */ + if (type == WHEELUPMOUSE) + ui_list->list_scroll--; + else + ui_list->list_scroll++; - ED_region_tag_redraw(ar); + ED_region_tag_redraw(ar); - retval = WM_UI_HANDLER_BREAK; + retval = WM_UI_HANDLER_BREAK; + } + } } } } @@ -6472,21 +6509,29 @@ static int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle case DOWNARROWKEY: case WHEELUPMOUSE: case WHEELDOWNMOUSE: + case MOUSEPAN: /* arrowkeys: only handle for block_loop blocks */ if (event->alt || event->shift || event->ctrl || event->oskey) { /* pass */ } else if (inside || (block->flag & UI_BLOCK_LOOP)) { - if (event->val == KM_PRESS) { + int type = event->type; + int val = event->val; + + /* convert pan to scrollwheel */ + if (type == MOUSEPAN) + ui_pan_to_scroll(event, &type, &val); + + if (val == KM_PRESS) { PASS_EVENT_TO_PARENT_IF_NONACTIVE; but = ui_but_find_activated(ar); if (but) { /* is there a situation where UI_LEFT or UI_RIGHT would also change navigation direction? */ - if (((ELEM(event->type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_DOWN)) || - ((ELEM(event->type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_RIGHT)) || - ((ELEM(event->type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_TOP))) + if (((ELEM(type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_DOWN)) || + ((ELEM(type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_RIGHT)) || + ((ELEM(type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_TOP))) { /* the following is just a hack - uiBut->type set to BUT and BUTM have there menus built * opposite ways - this should be changed so that all popup-menus use the same uiBlock->direction */ @@ -6509,9 +6554,9 @@ static int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle } if (!but) { - if (((ELEM(event->type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_DOWN)) || - ((ELEM(event->type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_RIGHT)) || - ((ELEM(event->type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_TOP))) + if (((ELEM(type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_DOWN)) || + ((ELEM(type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_RIGHT)) || + ((ELEM(type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_TOP))) { if ((bt = ui_but_first(block)) && (bt->type & BUT)) { bt = ui_but_last(block); @@ -6928,8 +6973,6 @@ static int ui_handler_region_menu(bContext *C, wmEvent *event, void *UNUSED(user { ARegion *ar; uiBut *but; - uiHandleButtonData *data; - int retval; /* here we handle buttons at the window level, modal, for example * while number sliding, text editing, or when a menu block is open */ @@ -6940,17 +6983,23 @@ static int ui_handler_region_menu(bContext *C, wmEvent *event, void *UNUSED(user but = ui_but_find_activated(ar); if (but) { + uiHandleButtonData *data; + /* handle activated button events */ data = but->active; if (data->state == BUTTON_STATE_MENU_OPEN) { + int retval; + /* handle events for menus and their buttons recursively, * this will handle events from the top to the bottom menu */ if (data->menu) retval = ui_handle_menus_recursive(C, event, data->menu, 0); /* handle events for the activated button */ - if (retval == WM_UI_HANDLER_CONTINUE || event->type == TIMER) { + if ((data->menu && (retval == WM_UI_HANDLER_CONTINUE)) || + (event->type == TIMER)) + { if (data->menu && data->menu->menuretval) ui_handle_button_return_submenu(C, event, but); else diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 2928a5607c0..ebc80d61af3 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -49,6 +49,7 @@ #include "BLI_utildefines.h" #include "DNA_brush_types.h" +#include "DNA_dynamicpaint_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" @@ -75,8 +76,8 @@ #include "interface_intern.h" -#define ICON_IMAGE_W 600 -#define ICON_IMAGE_H 640 +// #define ICON_IMAGE_W 600 +// #define ICON_IMAGE_H 640 #define ICON_GRID_COLS 26 #define ICON_GRID_ROWS 30 @@ -574,13 +575,15 @@ static void init_internal_icons(void) glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, b16buf->x, b16buf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, b16buf->rect); while (b16buf->x > 1) { - b16buf = IMB_onehalf(b16buf); - glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, b16buf->x, b16buf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, b16buf->rect); + ImBuf *nbuf = IMB_onehalf(b16buf); + glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, nbuf->x, nbuf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nbuf->rect); level++; + IMB_freeImBuf(b16buf); + b16buf = nbuf; } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); @@ -597,7 +600,7 @@ static void init_internal_icons(void) else icontype = ICON_TYPE_BUFFER; - if (b16buf) { + if (b32buf) { for (y = 0; y < ICON_GRID_ROWS; y++) { for (x = 0; x < ICON_GRID_COLS; x++) { def_internal_icon(b32buf, BIFICONID_FIRST + y * ICON_GRID_COLS + x, @@ -1179,6 +1182,44 @@ int ui_id_icon_get(bContext *C, ID *id, int big) return iconid; } +int UI_rnaptr_icon_get(bContext *C, PointerRNA *ptr, int rnaicon, int big) +{ + ID *id = NULL; + + if (!ptr->data) + return rnaicon; + + /* try ID, material, texture or dynapaint slot */ + if (RNA_struct_is_ID(ptr->type)) { + id = ptr->id.data; + } + else if (RNA_struct_is_a(ptr->type, &RNA_MaterialSlot)) { + id = RNA_pointer_get(ptr, "material").data; + } + else if (RNA_struct_is_a(ptr->type, &RNA_TextureSlot)) { + id = RNA_pointer_get(ptr, "texture").data; + } + else if (RNA_struct_is_a(ptr->type, &RNA_DynamicPaintSurface)) { + DynamicPaintSurface *surface = (DynamicPaintSurface *)ptr->data; + + if (surface->format == MOD_DPAINT_SURFACE_F_PTEX) + return ICON_TEXTURE_SHADED; + else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) + return ICON_OUTLINER_DATA_MESH; + else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) + return ICON_FILE_IMAGE; + } + + /* get icon from ID */ + if (id) { + int icon = ui_id_icon_get(C, id, big); + + return icon ? icon : rnaicon; + } + + return rnaicon; +} + static void icon_draw_at_size(float x, float y, int icon_id, float aspect, float alpha, enum eIconSizes size, int nocreate) { int draw_size = get_draw_size(size); diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index f088b3a54f4..706301dc060 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -271,6 +271,9 @@ struct uiBut { /* active button data */ struct uiHandleButtonData *active; + /* Custom button data. */ + void *custom_data; + char *editstr; double *editval; float *editvec; @@ -504,6 +507,7 @@ void ui_draw_but_IMAGE(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, rct void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, rcti *rect); /* interface_handlers.c */ +extern void ui_pan_to_scroll(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_active_free(const struct bContext *C, uiBut *but); extern int ui_button_is_active(struct ARegion *ar); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index a15256bc86f..f4af1f036a3 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -186,13 +186,13 @@ static const char *ui_item_name_add_colon(const char *name, char namestr[UI_MAX_ static int ui_item_fit(int item, int pos, int all, int available, int last, int alignment, int *offset) { + if (offset) + *offset = 0; + /* available == 0 is unlimited */ if (available == 0) return item; - - if (offset) - *offset = 0; - + if (all > available) { /* contents is bigger than available space */ if (last) @@ -346,7 +346,9 @@ static void ui_layer_but_cb(bContext *C, void *arg_but, void *arg_index) } /* create buttons for an item with an RNA array */ -static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int len, int x, int y, int w, int UNUSED(h), int expand, int slider, int toggle, int icon_only) +static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, int icon, + PointerRNA *ptr, PropertyRNA *prop, int len, int x, int y, int w, int UNUSED(h), + int expand, int slider, int toggle, int icon_only) { uiStyle *style = layout->root->style; uiBut *but; @@ -2306,11 +2308,14 @@ uiLayout *uiLayoutBox(uiLayout *layout) return (uiLayout *)ui_layout_box(layout, ROUNDBOX); } -uiLayout *uiLayoutListBox(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *actptr, PropertyRNA *actprop) +uiLayout *uiLayoutListBox(uiLayout *layout, uiList *ui_list, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *actptr, + PropertyRNA *actprop) { uiLayoutItemBx *box = ui_layout_box(layout, LISTBOX); uiBut *but = box->roundbox; + but->custom_data = ui_list; + but->rnasearchpoin = *ptr; but->rnasearchprop = prop; but->rnapoin = *actptr; diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 5b6a609e4d2..9fbf2fe8898 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -112,7 +112,7 @@ static int panel_aligned(ScrArea *sa, ARegion *ar) else if (sa->spacetype == SPACE_FILE && ar->regiontype == RGN_TYPE_CHANNELS) return BUT_VERTICAL; else if (sa->spacetype == SPACE_IMAGE && ar->regiontype == RGN_TYPE_PREVIEW) - return BUT_VERTICAL; + return BUT_VERTICAL; else if (ELEM3(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS)) return BUT_VERTICAL; @@ -812,8 +812,8 @@ static void ui_panels_size(ScrArea *sa, ARegion *ar, int *x, int *y) { Panel *pa; int align = panel_aligned(sa, ar); - int sizex = UI_PANEL_WIDTH; - int sizey = UI_PANEL_WIDTH; + int sizex = 0; + int sizey = 0; /* compute size taken up by panels, for setting in view2d */ for (pa = ar->panels.first; pa; pa = pa->next) { @@ -834,6 +834,11 @@ static void ui_panels_size(ScrArea *sa, ARegion *ar, int *x, int *y) } } + if (sizex == 0) + sizex = UI_PANEL_WIDTH; + if (sizey == 0) + sizey = -UI_PANEL_WIDTH; + *x = sizex; *y = sizey; } @@ -956,6 +961,25 @@ void uiDrawPanels(const bContext *C, ARegion *ar) } } +void uiScalePanels(ARegion *ar, float new_width) +{ + uiBlock *block; + uiBut *but; + + for (block = ar->uiblocks.first; block; block = block->next) { + if (block->panel) { + float fac = new_width / (float)block->panel->sizex; + printf("scaled %f\n", fac); + block->panel->sizex = new_width; + + for (but = block->buttons.first; but; but = but->next) { + but->rect.xmin *= fac; + but->rect.xmax *= fac; + } + } + } +} + /* ------------ panel merging ---------------- */ static void check_panel_overlap(ARegion *ar, Panel *panel) diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 57c126c31c5..4a8ad5d24a6 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -651,10 +651,10 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) ofsx = 0; //(but->block->panel) ? but->block->panel->ofsx : 0; ofsy = 0; //(but->block->panel) ? but->block->panel->ofsy : 0; - rect_fl.xmin = (but->rect.xmin + but->rect.xmax) * 0.5f + ofsx - (TIP_BORDER_X ); - rect_fl.xmax = rect_fl.xmin + fontw + (TIP_BORDER_X ); - rect_fl.ymax = but->rect.ymin + ofsy - (TIP_BORDER_Y ); - rect_fl.ymin = rect_fl.ymax - fonth - (TIP_BORDER_Y ); + rect_fl.xmin = (but->rect.xmin + but->rect.xmax) * 0.5f + ofsx - TIP_BORDER_X; + rect_fl.xmax = rect_fl.xmin + fontw + TIP_BORDER_X; + rect_fl.ymax = but->rect.ymin + ofsy - TIP_BORDER_Y; + rect_fl.ymin = rect_fl.ymax - fonth - TIP_BORDER_Y; #undef TIP_MARGIN_Y #undef TIP_BORDER_X @@ -896,8 +896,12 @@ void ui_searchbox_apply(uiBut *but, ARegion *ar) void ui_searchbox_event(bContext *C, ARegion *ar, uiBut *but, wmEvent *event) { uiSearchboxData *data = ar->regiondata; + int type = event->type, val = event->val; - switch (event->type) { + if (type == MOUSEPAN) + ui_pan_to_scroll(event, &type, &val); + + switch (type) { case WHEELUPMOUSE: case UPARROWKEY: ui_searchbox_select(C, ar, but, -1); @@ -1527,6 +1531,7 @@ static void ui_block_region_draw(const bContext *C, ARegion *ar) static void ui_popup_block_clip(wmWindow *window, uiBlock *block) { + uiBut *bt; int width = UI_ThemeMenuShadowWidth(); int winx, winy; @@ -1536,7 +1541,6 @@ static void ui_popup_block_clip(wmWindow *window, uiBlock *block) winx = WM_window_pixels_x(window); winy = WM_window_pixels_y(window); - // wm_window_get_size(window, &winx, &winy); if (block->rect.xmin < width) block->rect.xmin = width; @@ -1547,6 +1551,15 @@ static void ui_popup_block_clip(wmWindow *window, uiBlock *block) block->rect.ymin = width; if (block->rect.ymax > winy - MENU_TOP) block->rect.ymax = winy - MENU_TOP; + + /* ensure menu items draw inside left/right boundary */ + for (bt = block->buttons.first; bt; bt = bt->next) { + if (bt->rect.xmin < block->rect.xmin) + bt->rect.xmin = block->rect.xmin; + if (bt->rect.xmax > block->rect.xmax) + bt->rect.xmax = block->rect.xmax; + } + } void ui_popup_block_scrolltest(uiBlock *block) diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 33f647d1db6..f704ac0e203 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -31,18 +31,16 @@ #include "MEM_guardedalloc.h" -#include "DNA_anim_types.h" #include "DNA_dynamicpaint_types.h" -#include "DNA_key_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" -#include "DNA_userdef_types.h" #include "BLI_utildefines.h" #include "BLI_string.h" #include "BLI_ghash.h" #include "BLI_rect.h" +#include "BLF_api.h" #include "BLF_translation.h" #include "BKE_animsys.h" @@ -59,6 +57,7 @@ #include "BKE_displist.h" #include "BKE_sca.h" #include "BKE_scene.h" +#include "BKE_screen.h" #include "ED_screen.h" #include "ED_object.h" @@ -71,11 +70,9 @@ #include "WM_types.h" #include "UI_interface.h" +#include "UI_interface_icons.h" #include "interface_intern.h" -#include "BLF_api.h" -#include "BLF_translation.h" - void UI_template_fix_linking(void) { } @@ -1090,7 +1087,7 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con) // int rb_col; // UNUSED /* get constraint typeinfo */ - cti = constraint_get_typeinfo(con); + cti = BKE_constraint_get_typeinfo(con); if (cti == NULL) { /* exception for 'Null' constraint - it doesn't have constraint typeinfo! */ BLI_strncpy(typestr, (con->type == CONSTRAINT_TYPE_NULL) ? "Null" : "Unknown", sizeof(typestr)); @@ -1099,7 +1096,7 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con) BLI_strncpy(typestr, cti->name, sizeof(typestr)); /* determine whether constraint is proxy protected or not */ - if (proxylocked_constraints_owner(ob, pchan)) + if (BKE_proxylocked_constraints_owner(ob, pchan)) proxy_protected = (con->flag & CONSTRAINT_PROXY_LOCAL) == 0; else proxy_protected = 0; @@ -1161,7 +1158,7 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con) * * Up/Down buttons should only be shown (or not grayed - todo) if they serve some purpose. */ - if (proxylocked_constraints_owner(ob, pchan)) { + if (BKE_proxylocked_constraints_owner(ob, pchan)) { if (con->prev) { prev_proxylock = (con->prev->flag & CONSTRAINT_PROXY_LOCAL) ? 0 : 1; } @@ -2341,437 +2338,195 @@ void uiTemplateGameStates(uiLayout *layout, PointerRNA *ptr, const char *propnam /************************* List Template **************************/ - -static int list_item_icon_get(bContext *C, PointerRNA *itemptr, int rnaicon, int big) +static void uilist_draw_item_default(struct uiList *ui_list, struct bContext *UNUSED(C), struct uiLayout *layout, + struct PointerRNA *UNUSED(dataptr), struct PointerRNA *itemptr, int icon, + struct PointerRNA *UNUSED(active_dataptr), const char *UNUSED(active_propname), + int UNUSED(index)) { - ID *id = NULL; - int icon; - - if (!itemptr->data) - return rnaicon; - - /* try ID, material or texture slot */ - if (RNA_struct_is_ID(itemptr->type)) { - id = itemptr->id.data; - } - else if (RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) { - id = RNA_pointer_get(itemptr, "material").data; - } - else if (RNA_struct_is_a(itemptr->type, &RNA_TextureSlot)) { - id = RNA_pointer_get(itemptr, "texture").data; - } - else if (RNA_struct_is_a(itemptr->type, &RNA_DynamicPaintSurface)) { - DynamicPaintSurface *surface = (DynamicPaintSurface *)itemptr->data; - - if (surface->format == MOD_DPAINT_SURFACE_F_PTEX) return ICON_TEXTURE_SHADED; - else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) return ICON_OUTLINER_DATA_MESH; - else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) return ICON_FILE_IMAGE; - } - - /* get icon from ID */ - if (id) { - icon = ui_id_icon_get(C, id, big); - - if (icon) - return icon; - } - - return rnaicon; -} - -static void list_item_row(bContext *C, uiLayout *layout, PointerRNA *ptr, PointerRNA *itemptr, int i, - int rnaicon, PointerRNA *activeptr, PropertyRNA *activeprop, const char *prop_list_id) -{ - uiBlock *block = uiLayoutGetBlock(layout); - uiBut *but; - uiLayout *split, *overlap, *sub, *row; char *namebuf; const char *name; - int icon; - - overlap = uiLayoutOverlap(layout); - - /* list item behind label & other buttons */ - sub = uiLayoutRow(overlap, FALSE); - - but = uiDefButR_prop(block, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, activeptr, activeprop, - 0, 0, i, 0, 0, ""); - uiButSetFlag(but, UI_BUT_NO_TOOLTIP); - - sub = uiLayoutRow(overlap, FALSE); - - /* retrieve icon and name */ - icon = list_item_icon_get(C, itemptr, rnaicon, 0); - if (icon == ICON_NONE || icon == ICON_DOT) - icon = 0; namebuf = RNA_struct_name_get_alloc(itemptr, NULL, 0, NULL); name = (namebuf) ? namebuf : ""; - /* hardcoded types */ - if (itemptr->type == &RNA_MeshTexturePolyLayer || itemptr->type == &RNA_MeshLoopColorLayer) { - uiItemL(sub, name, icon); - uiBlockSetEmboss(block, UI_EMBOSSN); - uiDefIconButR(block, TOG, 0, ICON_SCENE, 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "active_render", - 0, 0, 0, 0, 0, NULL); - uiBlockSetEmboss(block, UI_EMBOSS); + /* Simplest one! */ + switch (ui_list->layout_type) { + case UILST_LAYOUT_GRID: + uiItemL(layout, "", icon); + break; + case UILST_LAYOUT_DEFAULT: + case UILST_LAYOUT_COMPACT: + default: + uiItemL(layout, name, icon); + break; } - else if (RNA_struct_is_a(itemptr->type, &RNA_MaterialTextureSlot)) { - uiItemL(sub, name, icon); - uiBlockSetEmboss(block, UI_EMBOSS); - uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, ptr, "use_textures", i, 0, 0, 0, 0, NULL); - } -#ifdef WITH_FREESTYLE - else if (RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer) || - RNA_struct_is_a(itemptr->type, &RNA_FreestyleLineSet)) { -#else - else if (RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer)) { -#endif - uiItemL(sub, name, icon); - uiBlockSetEmboss(block, UI_EMBOSS); - uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "use", 0, 0, 0, 0, 0, NULL); - } - else if (RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) { - /* provision to draw active node name */ - Material *ma, *manode; - Scene *scene = CTX_data_scene(C); - Object *ob = (Object *)ptr->id.data; - int index = (Material **)itemptr->data - ob->mat; - - /* default item with material base name */ - uiItemL(sub, name, icon); - ma = give_current_material(ob, index + 1); - if (ma && !BKE_scene_use_new_shading_nodes(scene)) { - manode = give_node_material(ma); - if (manode) { - char str[MAX_ID_NAME + 12]; - BLI_snprintf(str, sizeof(str), IFACE_("Node %s"), manode->id.name + 2); - uiItemL(sub, str, ui_id_icon_get(C, &manode->id, 1)); - } - else if (ma->use_nodes) { - uiItemL(sub, IFACE_("Node <none>"), ICON_NONE); - } - } - } - else if (itemptr->type == &RNA_ShapeKey) { - Object *ob = (Object *)activeptr->data; - Key *key = (Key *)itemptr->id.data; - KeyBlock *kb = (KeyBlock *)itemptr->data; - - split = uiLayoutSplit(sub, 0.66f, FALSE); - - uiItemL(split, name, icon); - - uiBlockSetEmboss(block, UI_EMBOSSN); - row = uiLayoutRow(split, TRUE); - if (i == 0 || (key->type != KEY_RELATIVE)) uiItemL(row, "", ICON_NONE); - else uiItemR(row, itemptr, "value", 0, "", ICON_NONE); - uiItemR(row, itemptr, "mute", 0, "", ICON_NONE); - - if ((kb->flag & KEYBLOCK_MUTE) || - (ob->mode == OB_MODE_EDIT && !((ob->shapeflag & OB_SHAPE_EDIT_MODE) && ob->type == OB_MESH))) - { - uiLayoutSetActive(row, FALSE); - } - uiBlockSetEmboss(block, UI_EMBOSS); - } - else if (itemptr->type == &RNA_VertexGroup) { - bDeformGroup *dg = (bDeformGroup *)itemptr->data; - uiItemL(sub, name, icon); - /* RNA does not allow nice lock icons, use lower level buttons */ -#if 0 - uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "lock_weight", 0, 0, 0, 0, 0, NULL); -#else - uiBlockSetEmboss(block, UI_EMBOSSN); - uiDefIconButBitC(block, TOG, DG_LOCK_WEIGHT, 0, (dg->flag & DG_LOCK_WEIGHT) ? ICON_LOCKED : ICON_UNLOCKED, - 0, 0, UI_UNIT_X, UI_UNIT_Y, &dg->flag, 0, 0, 0, 0, - TIP_("Maintain relative weights while painting")); - uiBlockSetEmboss(block, UI_EMBOSS); -#endif - } - else if (itemptr->type == &RNA_KeyingSetPath) { - KS_Path *ksp = (KS_Path *)itemptr->data; - - /* icon needs to be the type of ID which is currently active */ - RNA_enum_icon_from_value(id_type_items, ksp->idtype, &icon); - - /* nothing else special to do... */ - uiItemL(sub, name, icon); /* fails, backdrop LISTROW... */ - } - else if (itemptr->type == &RNA_DynamicPaintSurface) { - char name_final[96]; - const char *enum_name; - PropertyRNA *prop = RNA_struct_find_property(itemptr, "surface_type"); - DynamicPaintSurface *surface = (DynamicPaintSurface *)itemptr->data; - - RNA_property_enum_name(C, itemptr, prop, RNA_property_enum_get(itemptr, prop), &enum_name); - - BLI_snprintf(name_final, sizeof(name_final), "%s (%s)", name, enum_name); - uiItemL(sub, name_final, icon); - if (dynamicPaint_surfaceHasColorPreview(surface)) { - uiBlockSetEmboss(block, UI_EMBOSSN); - uiDefIconButR(block, OPTION, 0, - (surface->flags & MOD_DPAINT_PREVIEW) ? ICON_RESTRICT_VIEW_OFF : ICON_RESTRICT_VIEW_ON, - 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "show_preview", 0, 0, 0, 0, 0, NULL); - uiBlockSetEmboss(block, UI_EMBOSS); - } - uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "is_active", i, 0, 0, 0, 0, NULL); - } - else if (itemptr->type == &RNA_MovieTrackingObject) { - MovieTrackingObject *tracking_object = (MovieTrackingObject *)itemptr->data; - - split = uiLayoutSplit(sub, 0.75f, FALSE); - if (tracking_object->flag & TRACKING_OBJECT_CAMERA) { - uiItemL(split, name, ICON_CAMERA_DATA); - } - else { - uiItemL(split, name, ICON_OBJECT_DATA); - } - } - else if (itemptr->type == &RNA_MaskLayer) { - split = uiLayoutRow(sub, FALSE); - - uiItemL(split, name, icon); - - uiBlockSetEmboss(block, UI_EMBOSSN); - row = uiLayoutRow(split, TRUE); - uiItemR(row, itemptr, "alpha", 0, "", ICON_NONE); - uiItemR(row, itemptr, "hide", 0, "", ICON_NONE); - uiItemR(row, itemptr, "hide_select", 0, "", ICON_NONE); - uiItemR(row, itemptr, "hide_render", 0, "", ICON_NONE); - - uiBlockSetEmboss(block, UI_EMBOSS); - } - - /* There is a last chance to display custom controls (in addition to the name/label): - * If the given item property group features a string property named as prop_list, - * this tries to add controls for all properties of the item listed in that string property. - * (colon-separated names). - * - * This is especially useful for python. E.g., if you list a collection of this property - * group: - * - * class TestPropertyGroup(bpy.types.PropertyGroup): - * bool = BoolProperty(default=False) - * integer = IntProperty() - * string = StringProperty() - * - * # A string of all identifiers (colon-separated) which property's controls should be - * # displayed in a template_list. - * template_list_controls = StringProperty(default="integer:bool:string", options={"HIDDEN"}) - * - * ... you'll get a numfield for the integer prop, a check box for the bool prop, and a textfield - * for the string prop, after the name of each item of the collection. - */ - else if (prop_list_id) { - row = uiLayoutRow(sub, TRUE); - uiItemL(row, name, icon); - - /* XXX: Check, as sometimes we get an itemptr looking like - * {id = {data = 0x0}, type = 0x0, data = 0x0} - * which would obviously produce a sigsev... */ - if (itemptr->type) { - /* If the special property is set for the item, and it is a collection... */ - PropertyRNA *prop_list = RNA_struct_find_property(itemptr, prop_list_id); - - if (prop_list && RNA_property_type(prop_list) == PROP_STRING) { - int prop_names_len; - char *prop_names = RNA_property_string_get_alloc(itemptr, prop_list, NULL, 0, &prop_names_len); - char *prop_names_end = prop_names + prop_names_len; - char *id = prop_names; - char *id_next; - while (id < prop_names_end) { - if ((id_next = strchr(id, ':'))) *id_next++ = '\0'; - else id_next = prop_names_end; - uiItemR(row, itemptr, id, 0, NULL, ICON_NONE); - id = id_next; - } - MEM_freeN(prop_names); - } - } - } - - else - uiItemL(sub, name, icon); /* fails, backdrop LISTROW... */ - /* free name */ if (namebuf) { MEM_freeN(namebuf); } } -void uiTemplateList(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, PointerRNA *activeptr, - const char *activepropname, const char *prop_list, int rows, int maxrows, int listtype) +void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, const char *list_id, + PointerRNA *dataptr, const char *propname, PointerRNA *active_dataptr, + const char *active_propname, int rows, int maxrows, int layout_type) { + uiListType *ui_list_type; + uiList *ui_list = NULL; + ARegion *ar; + uiListDrawItemFunc draw_item; + PropertyRNA *prop = NULL, *activeprop; PropertyType type, activetype; StructRNA *ptype; - uiLayout *box, *row, *col; - uiBlock *block; + uiLayout *box, *row, *col, *sub, *overlap; + uiBlock *block, *subblock; uiBut *but; - Panel *pa; - const char *name; + + char ui_list_id[UI_MAX_NAME_STR]; char numstr[32]; - int rnaicon = 0, icon = 0, i = 0, activei = 0, len = 0, items, found, min, max; + int rnaicon = ICON_NONE, icon = ICON_NONE; + int i = 0, activei = 0; + int len = 0; + int items; + int found; + int min, max; /* validate arguments */ block = uiLayoutGetBlock(layout); - pa = block->panel; - if (!pa) { - RNA_warning("Only works inside a panel"); + if (!active_dataptr->data) { + RNA_warning("No active data"); return; } - if (!activeptr->data) - return; - - if (ptr->data) { - prop = RNA_struct_find_property(ptr, propname); + if (dataptr->data) { + prop = RNA_struct_find_property(dataptr, propname); if (!prop) { - RNA_warning("Property not found: %s.%s", RNA_struct_identifier(ptr->type), propname); + RNA_warning("Property not found: %s.%s", RNA_struct_identifier(dataptr->type), propname); return; } } - activeprop = RNA_struct_find_property(activeptr, activepropname); + activeprop = RNA_struct_find_property(active_dataptr, active_propname); if (!activeprop) { - RNA_warning("Property not found: %s.%s", RNA_struct_identifier(ptr->type), activepropname); + RNA_warning("Property not found: %s.%s", RNA_struct_identifier(active_dataptr->type), active_propname); return; } if (prop) { type = RNA_property_type(prop); if (type != PROP_COLLECTION) { - RNA_warning("uiExpected collection property"); + RNA_warning("Expected a collection data property"); return; } } activetype = RNA_property_type(activeprop); if (activetype != PROP_INT) { - RNA_warning("Expected integer property"); + RNA_warning("Expected an integer active data property"); return; } /* get icon */ - if (ptr->data && prop) { - ptype = RNA_property_pointer_type(ptr, prop); + if (dataptr->data && prop) { + ptype = RNA_property_pointer_type(dataptr, prop); rnaicon = RNA_struct_ui_icon(ptype); } /* get active data */ - activei = RNA_property_int_get(activeptr, activeprop); - - if (listtype == 'i') { - box = uiLayoutListBox(layout, ptr, prop, activeptr, activeprop); - col = uiLayoutColumn(box, TRUE); - row = uiLayoutRow(col, FALSE); + activei = RNA_property_int_get(active_dataptr, activeprop); - if (ptr->data && prop) { - /* create list items */ - RNA_PROP_BEGIN (ptr, itemptr, prop) - { - /* create button */ - if (!(i % 9)) - row = uiLayoutRow(col, FALSE); + /* Find the uiList type. */ + ui_list_type = WM_uilisttype_find(listtype_name, FALSE); - icon = list_item_icon_get(C, &itemptr, rnaicon, 1); - but = uiDefIconButR_prop(block, LISTROW, 0, icon, 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, activeptr, - activeprop, 0, 0, i, 0, 0, ""); - uiButSetFlag(but, UI_BUT_NO_TOOLTIP); - - - i++; + if (ui_list_type == NULL) { + RNA_warning("List type %s not found", listtype_name); + return; } - RNA_PROP_END; - } - } - else if (listtype == 'c') { - /* compact layout */ - row = uiLayoutRow(layout, TRUE); + draw_item = ui_list_type->draw_item ? ui_list_type->draw_item : uilist_draw_item_default; - if (ptr->data && prop) { - /* create list items */ - RNA_PROP_BEGIN (ptr, itemptr, prop) - { - found = (activei == i); + /* Find or add the uiList to the current Region. */ + /* We tag the list id with the list type... */ + BLI_snprintf(ui_list_id, sizeof(ui_list_id), "%s_%s", ui_list_type->idname, list_id ? list_id : ""); - if (found) { - /* create button */ - name = RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL); - icon = list_item_icon_get(C, &itemptr, rnaicon, 0); - uiItemL(row, (name) ? name : "", icon); + ar = CTX_wm_region(C); + ui_list = BLI_findstring(&ar->ui_lists, ui_list_id, offsetof(uiList, list_id)); - if (name) { - MEM_freeN((void *)name); + if (!ui_list) { + ui_list = MEM_callocN(sizeof(uiList), __func__); + BLI_strncpy(ui_list->list_id, ui_list_id, sizeof(ui_list->list_id)); + BLI_addtail(&ar->ui_lists, ui_list); } - } - i++; - } - RNA_PROP_END; - } - - /* if not found, add in dummy button */ - if (i == 0) - uiItemL(row, "", ICON_NONE); + /* Because we can't actually pass type across save&load... */ + ui_list->type = ui_list_type; + ui_list->layout_type = layout_type; - /* next/prev button */ - BLI_snprintf(numstr, sizeof(numstr), "%d :", i); - but = uiDefIconTextButR_prop(block, NUM, 0, 0, numstr, 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, activeptr, - activeprop, 0, 0, 0, 0, 0, ""); - if (i == 0) - uiButSetFlag(but, UI_BUT_DISABLED); - } - else { + switch (layout_type) { + case UILST_LAYOUT_DEFAULT: /* default rows */ if (rows == 0) rows = 5; if (maxrows == 0) maxrows = 5; - if (pa->list_grip_size != 0) - rows = pa->list_grip_size; + if (ui_list->list_grip_size != 0) + rows = ui_list->list_grip_size; /* layout */ - box = uiLayoutListBox(layout, ptr, prop, activeptr, activeprop); + box = uiLayoutListBox(layout, ui_list, dataptr, prop, active_dataptr, activeprop); row = uiLayoutRow(box, FALSE); col = uiLayoutColumn(row, TRUE); /* init numbers */ - RNA_property_int_range(activeptr, activeprop, &min, &max); + RNA_property_int_range(active_dataptr, activeprop, &min, &max); if (prop) - len = RNA_property_collection_length(ptr, prop); + len = RNA_property_collection_length(dataptr, prop); items = CLAMPIS(len, rows, MAX2(rows, maxrows)); /* if list length changes and active is out of view, scroll to it */ - if (pa->list_last_len != len) - if ((activei < pa->list_scroll || activei >= pa->list_scroll + items)) - pa->list_scroll = activei; + if ((ui_list->list_last_len != len) && + (activei < ui_list->list_scroll || activei >= ui_list->list_scroll + items)) { + ui_list->list_scroll = activei; + } - pa->list_scroll = MIN2(pa->list_scroll, len - items); - pa->list_scroll = MAX2(pa->list_scroll, 0); - pa->list_size = items; - pa->list_last_len = len; + ui_list->list_scroll = min_ii(ui_list->list_scroll, len - items); + ui_list->list_scroll = max_ii(ui_list->list_scroll, 0); + ui_list->list_size = items; + ui_list->list_last_len = len; - if (ptr->data && prop) { + if (dataptr->data && prop) { /* create list items */ - RNA_PROP_BEGIN (ptr, itemptr, prop) + RNA_PROP_BEGIN (dataptr, itemptr, prop) { - if (i >= pa->list_scroll && i < pa->list_scroll + items) - list_item_row(C, col, ptr, &itemptr, i, rnaicon, activeptr, activeprop, prop_list); + if (i >= ui_list->list_scroll && i < ui_list->list_scroll + items) { + subblock = uiLayoutGetBlock(col); + overlap = uiLayoutOverlap(col); + + /* list item behind label & other buttons */ + sub = uiLayoutRow(overlap, FALSE); + + but = uiDefButR_prop(subblock, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, + active_dataptr, activeprop, 0, 0, i, 0, 0, ""); + uiButSetFlag(but, UI_BUT_NO_TOOLTIP); + + sub = uiLayoutRow(overlap, FALSE); + icon = UI_rnaptr_icon_get(C, &itemptr, rnaicon, FALSE); + if (icon == ICON_DOT) + icon = ICON_NONE; + draw_item(ui_list, C, sub, dataptr, &itemptr, icon, active_dataptr, active_propname, i); + } i++; } RNA_PROP_END; } /* add dummy buttons to fill space */ - while (i < pa->list_scroll + items) { - if (i >= pa->list_scroll) + while (i < ui_list->list_scroll + items) { + if (i >= ui_list->list_scroll) uiItemL(col, "", ICON_NONE); i++; } @@ -2779,9 +2534,75 @@ void uiTemplateList(uiLayout *layout, bContext *C, PointerRNA *ptr, const char * /* add scrollbar */ if (len > items) { col = uiLayoutColumn(row, FALSE); - uiDefButI(block, SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * items, &pa->list_scroll, + uiDefButI(block, SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * items, &ui_list->list_scroll, 0, len - items, items, 0, ""); } + break; + case UILST_LAYOUT_COMPACT: + row = uiLayoutRow(layout, TRUE); + + if (dataptr->data && prop) { + /* create list items */ + RNA_PROP_BEGIN (dataptr, itemptr, prop) + { + found = (activei == i); + + if (found) { + icon = UI_rnaptr_icon_get(C, &itemptr, rnaicon, FALSE); + if (icon == ICON_DOT) + icon = ICON_NONE; + draw_item(ui_list, C, row, dataptr, &itemptr, icon, active_dataptr, active_propname, i); + } + + i++; +} + RNA_PROP_END; + } + + /* if list is empty, add in dummy button */ + if (i == 0) + uiItemL(row, "", ICON_NONE); + + /* next/prev button */ + BLI_snprintf(numstr, sizeof(numstr), "%d :", i); + but = uiDefIconTextButR_prop(block, NUM, 0, 0, numstr, 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, + active_dataptr, activeprop, 0, 0, 0, 0, 0, ""); + if (i == 0) + uiButSetFlag(but, UI_BUT_DISABLED); + break; + case UILST_LAYOUT_GRID: + box = uiLayoutListBox(layout, ui_list, dataptr, prop, active_dataptr, activeprop); + col = uiLayoutColumn(box, TRUE); + row = uiLayoutRow(col, FALSE); + + if (dataptr->data && prop) { + /* create list items */ + RNA_PROP_BEGIN (dataptr, itemptr, prop) + { + /* create button */ + if (!(i % 9)) + row = uiLayoutRow(col, FALSE); + + subblock = uiLayoutGetBlock(row); + overlap = uiLayoutOverlap(row); + + /* list item behind label & other buttons */ + sub = uiLayoutRow(overlap, FALSE); + + but = uiDefButR_prop(subblock, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, + active_dataptr, activeprop, 0, 0, i, 0, 0, ""); + uiButSetFlag(but, UI_BUT_NO_TOOLTIP); + + sub = uiLayoutRow(overlap, FALSE); + + icon = UI_rnaptr_icon_get(C, &itemptr, rnaicon, FALSE); + draw_item(ui_list, C, sub, dataptr, &itemptr, icon, active_dataptr, active_propname, i); + + i++; + } + RNA_PROP_END; + } + break; } } @@ -3095,7 +2916,7 @@ void uiTemplateColorspaceSettings(uiLayout *layout, PointerRNA *ptr, const char colorspace_settings_ptr = RNA_property_pointer_get(ptr, prop); - uiItemL(layout, "Color Space:", ICON_NONE); + uiItemL(layout, "Input Color Space:", ICON_NONE); uiItemR(layout, &colorspace_settings_ptr, "name", 0, "", ICON_NONE); } diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 4687647223a..e4ad3a4f73b 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1324,11 +1324,13 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB /* icons default draw 0.8f x height */ rect->xmin += (int)(0.8f * BLI_rcti_size_y(rect)); - if (but->editstr || (but->flag & UI_TEXT_LEFT)) - rect->xmin += 0.4f * U.widget_unit; + if (but->editstr || (but->flag & UI_TEXT_LEFT)) { + rect->xmin += (0.4f * U.widget_unit) / but->block->aspect; + } + } + else if ((but->flag & UI_TEXT_LEFT)) { + rect->xmin += (0.4f * U.widget_unit) / but->block->aspect; } - else if ((but->flag & UI_TEXT_LEFT)) - rect->xmin += 0.4f * U.widget_unit; /* always draw text for textbutton cursor */ widget_draw_text(fstyle, wcol, but, rect); @@ -2319,7 +2321,7 @@ void ui_draw_link_bezier(const rcti *rect) glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(2, GL_FLOAT, 0, coord_array); - glDrawArrays(GL_LINE_STRIP, 0, LINK_RESOL); + glDrawArrays(GL_LINE_STRIP, 0, LINK_RESOL + 1); glDisableClientState(GL_VERTEX_ARRAY); glDisable(GL_BLEND); @@ -3467,14 +3469,14 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int ic if (iconid) { float height, aspect; int xs = rect->xmin + 0.2f * UI_UNIT_X; - int ys = 1 + (rect->ymin + rect->ymax - UI_DPI_ICON_SIZE) / 2; + int ys = rect->ymin + 0.1f * BLI_rcti_size_y(rect); /* icons are 80% of height of button (16 pixels inside 20 height) */ height = 0.8f * BLI_rcti_size_y(rect); aspect = ICON_DEFAULT_HEIGHT / height; - + glEnable(GL_BLEND); - UI_icon_draw_aspect(xs, ys, iconid, aspect, 0.5f); /* XXX scale weak get from fstyle? */ + UI_icon_draw_aspect(xs, ys, iconid, aspect, 1.0f); /* XXX scale weak get from fstyle? */ glDisable(GL_BLEND); } } diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index fd84c1fd4c4..361bdfacbb2 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -364,8 +364,14 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo cp = ts->syntaxc; break; case TH_SYNTAX_L: cp = ts->syntaxl; break; + case TH_SYNTAX_D: + cp = ts->syntaxd; break; + case TH_SYNTAX_R: + cp = ts->syntaxr; break; case TH_SYNTAX_N: cp = ts->syntaxn; break; + case TH_SYNTAX_S: + cp = ts->syntaxs; break; case TH_NODE: cp = ts->syntaxl; break; @@ -879,8 +885,8 @@ void ui_theme_init_default(void) rgba_char_args_set_fl(btheme->tima.preview_stitch_vert, 0.0, 0.0, 1.0, 0.2); rgba_char_args_set_fl(btheme->tima.preview_stitch_stitchable, 0.0, 1.0, 0.0, 1.0); rgba_char_args_set_fl(btheme->tima.preview_stitch_unstitchable, 1.0, 0.0, 0.0, 1.0); - rgba_char_args_set_fl(btheme->tima.preview_stitch_active, 0.886, 0.824, 0.765, 0.140); - + rgba_char_args_set_fl(btheme->tima.preview_stitch_active, 0.886, 0.824, 0.765, 0.140); + /* space text */ btheme->text = btheme->tv3d; rgba_char_args_set(btheme->text.back, 153, 153, 153, 255); @@ -890,10 +896,13 @@ void ui_theme_init_default(void) /* syntax highlighting */ rgba_char_args_set(btheme->text.syntaxn, 0, 0, 200, 255); /* Numbers Blue*/ - rgba_char_args_set(btheme->text.syntaxl, 100, 0, 0, 255); /* Strings red */ - rgba_char_args_set(btheme->text.syntaxc, 0, 100, 50, 255); /* Comments greenish */ - rgba_char_args_set(btheme->text.syntaxv, 95, 95, 0, 255); /* Special */ - rgba_char_args_set(btheme->text.syntaxb, 128, 0, 80, 255); /* Builtin, red-purple */ + rgba_char_args_set(btheme->text.syntaxl, 100, 0, 0, 255); /* Strings Red */ + rgba_char_args_set(btheme->text.syntaxc, 0, 100, 50, 255); /* Comments Greenish */ + rgba_char_args_set(btheme->text.syntaxv, 95, 95, 0, 255); /* Special Yellow*/ + rgba_char_args_set(btheme->text.syntaxd, 50, 0, 140, 255); /* Decorator/Preprocessor Dir. Blue-purple */ + rgba_char_args_set(btheme->text.syntaxr, 140, 60, 0, 255); /* Reserved Orange*/ + rgba_char_args_set(btheme->text.syntaxb, 128, 0, 80, 255); /* Builtin Red-purple */ + rgba_char_args_set(btheme->text.syntaxs, 76, 76, 76, 255); /* Grey (mix between fg/bg) */ /* space oops */ btheme->toops = btheme->tv3d; @@ -2106,6 +2115,15 @@ void init_userdef_do_versions(void) } } } + + if (!MAIN_VERSION_ATLEAST(bmain, 266, 4)) { + bTheme *btheme; + for (btheme = U.themes.first; btheme; btheme = btheme->next) { + rgba_char_args_set(btheme->text.syntaxd, 50, 0, 140, 255); /* Decorator/Preprocessor Dir. Blue-purple */ + rgba_char_args_set(btheme->text.syntaxr, 140, 60, 0, 255); /* Reserved Orange */ + rgba_char_args_set(btheme->text.syntaxs, 76, 76, 76, 255); /* Grey (mix between fg/bg) */ + } + } if (U.pixelsize == 0.0f) U.pixelsize = 1.0f; diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index 190d90b3c36..d0d631e14a5 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -60,6 +60,8 @@ #include "interface_intern.h" +static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_scrollers); + /* *********************************************************************** */ /* XXX still unresolved: scrolls hide/unhide vs region mask handling */ @@ -73,15 +75,15 @@ */ static int view2d_scroll_mapped(int scroll) { - if (scroll & V2D_SCROLL_HORIZONTAL_HIDE) + if (scroll & V2D_SCROLL_HORIZONTAL_FULLR) scroll &= ~(V2D_SCROLL_HORIZONTAL); - if (scroll & V2D_SCROLL_VERTICAL_HIDE) + if (scroll & V2D_SCROLL_VERTICAL_FULLR) scroll &= ~(V2D_SCROLL_VERTICAL); return scroll; } /* called each time cur changes, to dynamically update masks */ -static void view2d_masks(View2D *v2d) +static void view2d_masks(View2D *v2d, int check_scrollers) { int scroll; @@ -90,19 +92,26 @@ static void view2d_masks(View2D *v2d) v2d->mask.xmax = v2d->winx - 1; /* -1 yes! masks are pixels */ v2d->mask.ymax = v2d->winy - 1; -#if 0 - /* XXX see above */ - v2d->scroll &= ~(V2D_SCROLL_HORIZONTAL_HIDE | V2D_SCROLL_VERTICAL_HIDE); - /* check size if: */ - if (v2d->scroll & V2D_SCROLL_HORIZONTAL) - if (!(v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL)) - if (BLI_rctf_size_x(&v2d->tot) <= BLI_rcti_size_x(&v2d->cur)) - v2d->scroll |= V2D_SCROLL_HORIZONTAL_HIDE; - if (v2d->scroll & V2D_SCROLL_VERTICAL) - if (!(v2d->scroll & V2D_SCROLL_SCALE_VERTICAL)) - if (BLI_rctf_size_y(&v2d->tot) <= BLI_rctf_size_y(&v2d->cur)) - v2d->scroll |= V2D_SCROLL_VERTICAL_HIDE; -#endif + if (check_scrollers) { + /* check size if hiding flag is set: */ + if (v2d->scroll & V2D_SCROLL_HORIZONTAL_HIDE) { + if (!(v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL)) { + if (BLI_rctf_size_x(&v2d->tot) > BLI_rctf_size_x(&v2d->cur)) + v2d->scroll &= ~V2D_SCROLL_HORIZONTAL_FULLR; + else + v2d->scroll |= V2D_SCROLL_HORIZONTAL_FULLR; + } + } + if (v2d->scroll & V2D_SCROLL_VERTICAL_HIDE) { + if (!(v2d->scroll & V2D_SCROLL_SCALE_VERTICAL)) { + if (BLI_rctf_size_y(&v2d->tot) + 0.01f > BLI_rctf_size_y(&v2d->cur)) + v2d->scroll &= ~V2D_SCROLL_VERTICAL_FULLR; + else + v2d->scroll |= V2D_SCROLL_VERTICAL_FULLR; + } + } + } + scroll = view2d_scroll_mapped(v2d->scroll); /* scrollers shrink mask area, but should be based off regionsize @@ -126,8 +135,8 @@ static void view2d_masks(View2D *v2d) } /* horizontal scroller */ - if (scroll & (V2D_SCROLL_BOTTOM | V2D_SCROLL_BOTTOM_O)) { - /* on bottom edge of region (V2D_SCROLL_BOTTOM_O is outliner, the other is for standard) */ + if (scroll & (V2D_SCROLL_BOTTOM)) { + /* on bottom edge of region */ v2d->hor = v2d->mask; v2d->hor.ymax = V2D_SCROLL_HEIGHT; v2d->mask.ymin = v2d->hor.ymax + 1; @@ -142,8 +151,8 @@ static void view2d_masks(View2D *v2d) /* adjust vertical scroller if there's a horizontal scroller, to leave corner free */ if (scroll & V2D_SCROLL_VERTICAL) { /* just set y min/max for vertical scroller to y min/max of mask as appropriate */ - if (scroll & (V2D_SCROLL_BOTTOM | V2D_SCROLL_BOTTOM_O)) { - /* on bottom edge of region (V2D_SCROLL_BOTTOM_O is outliner, the other is for standard) */ + if (scroll & (V2D_SCROLL_BOTTOM)) { + /* on bottom edge of region */ v2d->vert.ymin = v2d->mask.ymin; } else if (scroll & V2D_SCROLL_TOP) { @@ -152,7 +161,6 @@ static void view2d_masks(View2D *v2d) } } } - } /* Refresh and Validation */ @@ -165,163 +173,173 @@ static void view2d_masks(View2D *v2d) */ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy) { - short tot_changed = 0, init = 0; + short tot_changed = 0, do_init; uiStyle *style = UI_GetStyle(); - /* initialize data if there is a need for such */ - if ((v2d->flag & V2D_IS_INITIALISED) == 0) { - /* set initialized flag so that View2D doesn't get reinitialised next time again */ - v2d->flag |= V2D_IS_INITIALISED; - - init = 1; + do_init = (v2d->flag & V2D_IS_INITIALISED) == 0; - /* see eView2D_CommonViewTypes in UI_view2d.h for available view presets */ - switch (type) { - /* 'standard view' - optimum setup for 'standard' view behavior, - * that should be used new views as basis for their - * own unique View2D settings, which should be used instead of this in most cases... + /* see eView2D_CommonViewTypes in UI_view2d.h for available view presets */ + switch (type) { + /* 'standard view' - optimum setup for 'standard' view behavior, + * that should be used new views as basis for their + * own unique View2D settings, which should be used instead of this in most cases... + */ + case V2D_COMMONVIEW_STANDARD: + { + /* for now, aspect ratio should be maintained, and zoom is clamped within sane default limits */ + v2d->keepzoom = (V2D_KEEPASPECT | V2D_LIMITZOOM); + v2d->minzoom = 0.01f; + v2d->maxzoom = 1000.0f; + + /* tot rect and cur should be same size, and aligned using 'standard' OpenGL coordinates for now + * - region can resize 'tot' later to fit other data + * - keeptot is only within bounds, as strict locking is not that critical + * - view is aligned for (0,0) -> (winx-1, winy-1) setup */ - case V2D_COMMONVIEW_STANDARD: - { - /* for now, aspect ratio should be maintained, and zoom is clamped within sane default limits */ - v2d->keepzoom = (V2D_KEEPASPECT | V2D_LIMITZOOM); - v2d->minzoom = 0.01f; - v2d->maxzoom = 1000.0f; - - /* tot rect and cur should be same size, and aligned using 'standard' OpenGL coordinates for now - * - region can resize 'tot' later to fit other data - * - keeptot is only within bounds, as strict locking is not that critical - * - view is aligned for (0,0) -> (winx-1, winy-1) setup - */ - v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y); - v2d->keeptot = V2D_KEEPTOT_BOUNDS; - + v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y); + v2d->keeptot = V2D_KEEPTOT_BOUNDS; + + if (do_init) { v2d->tot.xmin = v2d->tot.ymin = 0.0f; v2d->tot.xmax = (float)(winx - 1); v2d->tot.ymax = (float)(winy - 1); v2d->cur = v2d->tot; - - /* scrollers - should we have these by default? */ - /* XXX for now, we don't override this, or set it either! */ } - break; + /* scrollers - should we have these by default? */ + /* XXX for now, we don't override this, or set it either! */ + } + break; + + /* 'list/channel view' - zoom, aspect ratio, and alignment restrictions are set here */ + case V2D_COMMONVIEW_LIST: + { + /* zoom + aspect ratio are locked */ + v2d->keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT); + v2d->minzoom = v2d->maxzoom = 1.0f; - /* 'list/channel view' - zoom, aspect ratio, and alignment restrictions are set here */ - case V2D_COMMONVIEW_LIST: - { - /* zoom + aspect ratio are locked */ - v2d->keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT); - v2d->minzoom = v2d->maxzoom = 1.0f; - - /* tot rect has strictly regulated placement, and must only occur in +/- quadrant */ - v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y); - v2d->keeptot = V2D_KEEPTOT_STRICT; - tot_changed = 1; - - /* scroller settings are currently not set here... that is left for regions... */ - } - break; - - /* 'stack view' - practically the same as list/channel view, except is located in the pos y half instead. - * zoom, aspect ratio, and alignment restrictions are set here */ - case V2D_COMMONVIEW_STACK: - { - /* zoom + aspect ratio are locked */ - v2d->keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT); - v2d->minzoom = v2d->maxzoom = 1.0f; - - /* tot rect has strictly regulated placement, and must only occur in +/+ quadrant */ - v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y); - v2d->keeptot = V2D_KEEPTOT_STRICT; - tot_changed = 1; - - /* scroller settings are currently not set here... that is left for regions... */ - } - break; + /* tot rect has strictly regulated placement, and must only occur in +/- quadrant */ + v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y); + v2d->keeptot = V2D_KEEPTOT_STRICT; + tot_changed = do_init; + + /* scroller settings are currently not set here... that is left for regions... */ + } + break; + + /* 'stack view' - practically the same as list/channel view, except is located in the pos y half instead. + * zoom, aspect ratio, and alignment restrictions are set here */ + case V2D_COMMONVIEW_STACK: + { + /* zoom + aspect ratio are locked */ + v2d->keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT); + v2d->minzoom = v2d->maxzoom = 1.0f; + + /* tot rect has strictly regulated placement, and must only occur in +/+ quadrant */ + v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y); + v2d->keeptot = V2D_KEEPTOT_STRICT; + tot_changed = do_init; + + /* scroller settings are currently not set here... that is left for regions... */ + } + break; + + /* 'header' regions - zoom, aspect ratio, alignment, and panning restrictions are set here */ + case V2D_COMMONVIEW_HEADER: + { + /* zoom + aspect ratio are locked */ + v2d->keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT); + v2d->minzoom = v2d->maxzoom = 1.0f; + + if (do_init) { + v2d->tot.xmin = 0.0f; + v2d->tot.xmax = winx; + v2d->tot.ymin = 0.0f; + v2d->tot.ymax = winy; + v2d->cur = v2d->tot; - /* 'header' regions - zoom, aspect ratio, alignment, and panning restrictions are set here */ - case V2D_COMMONVIEW_HEADER: - { - /* zoom + aspect ratio are locked */ - v2d->keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT); - v2d->minzoom = v2d->maxzoom = 1.0f; v2d->min[0] = v2d->max[0] = (float)(winx - 1); v2d->min[1] = v2d->max[1] = (float)(winy - 1); - - /* tot rect has strictly regulated placement, and must only occur in +/+ quadrant */ - v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y); - v2d->keeptot = V2D_KEEPTOT_STRICT; - tot_changed = 1; - - /* panning in y-axis is prohibited */ - v2d->keepofs = V2D_LOCKOFS_Y; - - /* absolutely no scrollers allowed */ - v2d->scroll = 0; - } - break; + /* tot rect has strictly regulated placement, and must only occur in +/+ quadrant */ + v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y); + v2d->keeptot = V2D_KEEPTOT_STRICT; + tot_changed = do_init; + + /* panning in y-axis is prohibited */ + v2d->keepofs = V2D_LOCKOFS_Y; + + /* absolutely no scrollers allowed */ + v2d->scroll = 0; + + } + break; + + /* panels view, with horizontal/vertical align */ + case V2D_COMMONVIEW_PANELS_UI: + { - /* panels view, with horizontal/vertical align */ - case V2D_COMMONVIEW_PANELS_UI: - { + /* for now, aspect ratio should be maintained, and zoom is clamped within sane default limits */ + v2d->keepzoom = (V2D_KEEPASPECT | V2D_LIMITZOOM | V2D_KEEPZOOM); + v2d->minzoom = 0.5f; + v2d->maxzoom = 2.0f; + + v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y); + v2d->keeptot = V2D_KEEPTOT_BOUNDS; + + /* note, scroll is being flipped in ED_region_panels() drawing */ + v2d->scroll |= V2D_SCROLL_HORIZONTAL_HIDE; + v2d->scroll |= V2D_SCROLL_VERTICAL_HIDE; + + if (do_init) { float panelzoom = (style) ? style->panelzoom : 1.0f; + float scrolw = v2d->scroll & V2D_SCROLL_RIGHT ? V2D_SCROLL_WIDTH : 0.0f; - /* for now, aspect ratio should be maintained, and zoom is clamped within sane default limits */ - v2d->keepzoom = (V2D_KEEPASPECT | V2D_LIMITZOOM | V2D_KEEPZOOM); - v2d->minzoom = 0.5f; - v2d->maxzoom = 2.0f; - //tot_changed = 1; - - v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y); - v2d->keeptot = V2D_KEEPTOT_BOUNDS; - - v2d->scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM); - v2d->scroll |= V2D_SCROLL_HORIZONTAL_HIDE; - v2d->scroll &= ~V2D_SCROLL_VERTICAL_HIDE; - v2d->tot.xmin = 0.0f; - v2d->tot.xmax = winx; + v2d->tot.xmax = winx - scrolw; v2d->tot.ymax = 0.0f; v2d->tot.ymin = -winy; v2d->cur.xmin = 0.0f; - /* bad workaround for keeping zoom level with scrollers */ - v2d->cur.xmax = (winx - V2D_SCROLL_WIDTH) * panelzoom; + v2d->cur.xmax = (winx) * panelzoom - scrolw; v2d->cur.ymax = 0.0f; v2d->cur.ymin = (-winy) * panelzoom; } - break; - - /* other view types are completely defined using their own settings already */ - default: - /* we don't do anything here, as settings should be fine, but just make sure that rect */ - break; } + break; + + /* other view types are completely defined using their own settings already */ + default: + /* we don't do anything here, as settings should be fine, but just make sure that rect */ + break; } + /* set initialized flag so that View2D doesn't get reinitialised next time again */ + v2d->flag |= V2D_IS_INITIALISED; + /* store view size */ v2d->winx = winx; v2d->winy = winy; - /* set masks */ - view2d_masks(v2d); + /* set masks (always do), but leave scroller scheck to totrect_set */ + view2d_masks(v2d, 0); /* set 'tot' rect before setting cur? */ - if (tot_changed) - UI_view2d_totRect_set_resize(v2d, winx, winy, !init); + /* XXX confusing stuff here still - I made this function not check scroller hide - that happens in totrect_set */ + if (tot_changed) + UI_view2d_totRect_set_resize(v2d, winx, winy, !do_init); else - UI_view2d_curRect_validate_resize(v2d, !init); + ui_view2d_curRect_validate_resize(v2d, !do_init, 0); + } /* Ensure View2D rects remain in a viable configuration * - cur is not allowed to be: larger than max, smaller than min, or outside of tot */ // XXX pre2.5 -> this used to be called test_view2d() -void UI_view2d_curRect_validate_resize(View2D *v2d, int resize) +static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_scrollers) { float totwidth, totheight, curwidth, curheight, width, height; float winx, winy; @@ -715,12 +733,12 @@ void UI_view2d_curRect_validate_resize(View2D *v2d, int resize) } /* set masks */ - view2d_masks(v2d); + view2d_masks(v2d, mask_scrollers); } void UI_view2d_curRect_validate(View2D *v2d) { - UI_view2d_curRect_validate_resize(v2d, 0); + ui_view2d_curRect_validate_resize(v2d, 0, 1); } /* ------------------ */ @@ -844,7 +862,7 @@ void UI_view2d_curRect_reset(View2D *v2d) /* Change the size of the maximum viewable area (i.e. 'tot' rect) */ void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, int resize) { - int scroll = view2d_scroll_mapped(v2d->scroll); +// int scroll = view2d_scroll_mapped(v2d->scroll); /* don't do anything if either value is 0 */ width = abs(width); @@ -853,10 +871,10 @@ void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, int resize /* hrumf! */ /* XXX: there are work arounds for this in the panel and file browse code. */ /* round to int, because this is called with width + V2D_SCROLL_WIDTH */ - if (scroll & V2D_SCROLL_HORIZONTAL) - width -= (int)V2D_SCROLL_WIDTH; - if (scroll & V2D_SCROLL_VERTICAL) - height -= (int)V2D_SCROLL_HEIGHT; +// if (scroll & V2D_SCROLL_HORIZONTAL) +// width -= (int)V2D_SCROLL_WIDTH; +// if (scroll & V2D_SCROLL_VERTICAL) +// height -= (int)V2D_SCROLL_HEIGHT; if (ELEM(0, width, height)) { if (G.debug & G_DEBUG) @@ -903,12 +921,21 @@ void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, int resize } /* make sure that 'cur' rect is in a valid state as a result of these changes */ - UI_view2d_curRect_validate_resize(v2d, resize); + ui_view2d_curRect_validate_resize(v2d, resize, 1); + } void UI_view2d_totRect_set(View2D *v2d, int width, int height) { + int scroll = view2d_scroll_mapped(v2d->scroll); + UI_view2d_totRect_set_resize(v2d, width, height, 0); + + /* solve bad recursion... if scroller state changed, mask is different, so you get different rects */ + if (scroll != view2d_scroll_mapped(v2d->scroll)) { + UI_view2d_totRect_set_resize(v2d, width, height, 0); + } + } int UI_view2d_tab_set(View2D *v2d, int tab) @@ -1494,15 +1521,6 @@ View2DScrollers *UI_view2d_scrollers_calc(const bContext *C, View2D *v2d, CLAMP(scrollers->hor_min, hor.xmin, hor.xmax - V2D_SCROLLER_HANDLE_SIZE); } - /* check whether sliders can disappear due to the full-range being used */ - if (v2d->keeptot) { - if ((fac1 <= 0.0f) && (fac2 >= 1.0f)) { - v2d->scroll |= V2D_SCROLL_HORIZONTAL_FULLR; - scrollers->horfull = 1; - } - else - v2d->scroll &= ~V2D_SCROLL_HORIZONTAL_FULLR; - } } /* vertical scrollers */ @@ -1536,15 +1554,6 @@ View2DScrollers *UI_view2d_scrollers_calc(const bContext *C, View2D *v2d, CLAMP(scrollers->vert_min, vert.ymin, vert.ymax - V2D_SCROLLER_HANDLE_SIZE); } - /* check whether sliders can disappear due to the full-range being used */ - if (v2d->keeptot) { - if ((fac1 <= 0.0f) && (fac2 >= 1.0f)) { - v2d->scroll |= V2D_SCROLL_VERTICAL_FULLR; - scrollers->vertfull = 1; - } - else - v2d->scroll &= ~V2D_SCROLL_VERTICAL_FULLR; - } } /* grid markings on scrollbars */ @@ -1618,45 +1627,42 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v /* horizontal scrollbar */ if (scroll & V2D_SCROLL_HORIZONTAL) { - /* only draw scrollbar when it doesn't fill the entire space */ - if (vs->horfull == 0) { - bTheme *btheme = UI_GetTheme(); - uiWidgetColors wcol = btheme->tui.wcol_scroll; - rcti slider; - int state; - unsigned char col[4]; - - slider.xmin = vs->hor_min; - slider.xmax = vs->hor_max; - slider.ymin = hor.ymin; - slider.ymax = hor.ymax; - - state = (v2d->scroll_ui & V2D_SCROLL_H_ACTIVE) ? UI_SCROLL_PRESSED : 0; - - /* show zoom handles if: - * - zooming on x-axis is allowed (no scroll otherwise) - * - slider bubble is large enough (no overdraw confusion) - * - scale is shown on the scroller - * (workaround to make sure that button windows don't show these, - * and only the time-grids with their zoomability can do so) - */ - if ((v2d->keepzoom & V2D_LOCKZOOM_X) == 0 && - (v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL) && - (BLI_rcti_size_x(&slider) > V2D_SCROLLER_HANDLE_SIZE)) - { - state |= UI_SCROLL_ARROWS; - } - - /* clean rect behind slider, but not with transparent background */ - UI_GetThemeColor4ubv(TH_BACK, col); - if (col[3] == 255) { - glColor3ub(col[0], col[1], col[2]); - glRecti(v2d->hor.xmin, v2d->hor.ymin, v2d->hor.xmax, v2d->hor.ymax); - } - - uiWidgetScrollDraw(&wcol, &hor, &slider, state); + bTheme *btheme = UI_GetTheme(); + uiWidgetColors wcol = btheme->tui.wcol_scroll; + rcti slider; + int state; + unsigned char col[4]; + + slider.xmin = vs->hor_min; + slider.xmax = vs->hor_max; + slider.ymin = hor.ymin; + slider.ymax = hor.ymax; + + state = (v2d->scroll_ui & V2D_SCROLL_H_ACTIVE) ? UI_SCROLL_PRESSED : 0; + + /* show zoom handles if: + * - zooming on x-axis is allowed (no scroll otherwise) + * - slider bubble is large enough (no overdraw confusion) + * - scale is shown on the scroller + * (workaround to make sure that button windows don't show these, + * and only the time-grids with their zoomability can do so) + */ + if ((v2d->keepzoom & V2D_LOCKZOOM_X) == 0 && + (v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL) && + (BLI_rcti_size_x(&slider) > V2D_SCROLLER_HANDLE_SIZE)) + { + state |= UI_SCROLL_ARROWS; } + /* clean rect behind slider, but not with transparent background */ + UI_GetThemeColor4ubv(TH_BACK, col); + if (col[3] == 255) { + glColor3ub(col[0], col[1], col[2]); + glRecti(v2d->hor.xmin, v2d->hor.ymin, v2d->hor.xmax, v2d->hor.ymax); + } + + uiWidgetScrollDraw(&wcol, &hor, &slider, state); + /* scale indicators */ if ((scroll & V2D_SCROLL_SCALE_HORIZONTAL) && (vs->grid)) { View2DGrid *grid = vs->grid; @@ -1734,45 +1740,42 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v /* vertical scrollbar */ if (scroll & V2D_SCROLL_VERTICAL) { - /* only draw scrollbar when it doesn't fill the entire space */ - if (vs->vertfull == 0) { - bTheme *btheme = UI_GetTheme(); - uiWidgetColors wcol = btheme->tui.wcol_scroll; - rcti slider; - int state; - unsigned char col[4]; - - slider.xmin = vert.xmin; - slider.xmax = vert.xmax; - slider.ymin = vs->vert_min; - slider.ymax = vs->vert_max; - - state = (v2d->scroll_ui & V2D_SCROLL_V_ACTIVE) ? UI_SCROLL_PRESSED : 0; - - /* show zoom handles if: - * - zooming on y-axis is allowed (no scroll otherwise) - * - slider bubble is large enough (no overdraw confusion) - * - scale is shown on the scroller - * (workaround to make sure that button windows don't show these, - * and only the time-grids with their zoomability can do so) - */ - if ((v2d->keepzoom & V2D_LOCKZOOM_Y) == 0 && - (v2d->scroll & V2D_SCROLL_SCALE_VERTICAL) && - (BLI_rcti_size_y(&slider) > V2D_SCROLLER_HANDLE_SIZE)) - { - state |= UI_SCROLL_ARROWS; - } - - /* clean rect behind slider, but not with transparent background */ - UI_GetThemeColor4ubv(TH_BACK, col); - if (col[3] == 255) { - glColor3ub(col[0], col[1], col[2]); - glRecti(v2d->vert.xmin, v2d->vert.ymin, v2d->vert.xmax, v2d->vert.ymax); - } - - uiWidgetScrollDraw(&wcol, &vert, &slider, state); + bTheme *btheme = UI_GetTheme(); + uiWidgetColors wcol = btheme->tui.wcol_scroll; + rcti slider; + int state; + unsigned char col[4]; + + slider.xmin = vert.xmin; + slider.xmax = vert.xmax; + slider.ymin = vs->vert_min; + slider.ymax = vs->vert_max; + + state = (v2d->scroll_ui & V2D_SCROLL_V_ACTIVE) ? UI_SCROLL_PRESSED : 0; + + /* show zoom handles if: + * - zooming on y-axis is allowed (no scroll otherwise) + * - slider bubble is large enough (no overdraw confusion) + * - scale is shown on the scroller + * (workaround to make sure that button windows don't show these, + * and only the time-grids with their zoomability can do so) + */ + if ((v2d->keepzoom & V2D_LOCKZOOM_Y) == 0 && + (v2d->scroll & V2D_SCROLL_SCALE_VERTICAL) && + (BLI_rcti_size_y(&slider) > V2D_SCROLLER_HANDLE_SIZE)) + { + state |= UI_SCROLL_ARROWS; } + /* clean rect behind slider, but not with transparent background */ + UI_GetThemeColor4ubv(TH_BACK, col); + if (col[3] == 255) { + glColor3ub(col[0], col[1], col[2]); + glRecti(v2d->vert.xmin, v2d->vert.ymin, v2d->vert.xmax, v2d->vert.ymax); + } + + uiWidgetScrollDraw(&wcol, &vert, &slider, state); + /* scale indiators */ if ((scroll & V2D_SCROLL_SCALE_VERTICAL) && (vs->grid)) { diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index 006644bf366..cc473998340 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -937,7 +937,7 @@ static int view_zoomdrag_invoke(bContext *C, wmOperator *op, wmEvent *event) vzd = op->customdata; v2d = vzd->v2d; - if (event->type == MOUSEZOOM) { + if (event->type == MOUSEZOOM || event->type == MOUSEPAN) { float dx, dy, fac; vzd->lastx = event->prevx; @@ -948,6 +948,8 @@ static int view_zoomdrag_invoke(bContext *C, wmOperator *op, wmEvent *event) */ fac = 0.01f * (event->x - event->prevx); dx = fac * BLI_rctf_size_x(&v2d->cur) / 10.0f; + if (event->type == MOUSEPAN) + fac = 0.01f * (event->y - event->prevy); dy = fac * BLI_rctf_size_y(&v2d->cur) / 10.0f; RNA_float_set(op->ptr, "deltax", dx); @@ -1744,8 +1746,8 @@ static int scroller_activate_invoke(bContext *C, wmOperator *op, wmEvent *event) } /* zone is also inappropriate if scroller is not visible... */ - if (((vsm->scroller == 'h') && (v2d->scroll & (V2D_SCROLL_HORIZONTAL_HIDE | V2D_SCROLL_HORIZONTAL_FULLR))) || - ((vsm->scroller == 'v') && (v2d->scroll & (V2D_SCROLL_VERTICAL_HIDE | V2D_SCROLL_VERTICAL_FULLR))) ) + if (((vsm->scroller == 'h') && (v2d->scroll & (V2D_SCROLL_HORIZONTAL_FULLR))) || + ((vsm->scroller == 'v') && (v2d->scroll & (V2D_SCROLL_VERTICAL_FULLR))) ) { /* free customdata initialized */ scroller_activate_exit(C, op); @@ -1903,6 +1905,7 @@ void UI_view2d_keymap(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_in", WHEELINMOUSE, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_out", PADMINUS, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_in", PADPLUSKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MOUSEPAN, 0, KM_CTRL, 0); WM_keymap_verify_item(keymap, "VIEW2D_OT_smoothview", TIMER1, KM_ANY, KM_ANY, 0); @@ -1951,6 +1954,7 @@ void UI_view2d_keymap(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MOUSEZOOM, 0, 0, 0); + WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MOUSEPAN, 0, KM_CTRL, 0); WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_out", PADMINUS, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_in", PADPLUSKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "VIEW2D_OT_reset", HOMEKEY, KM_PRESS, 0, 0); diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index 29139c5154f..3fbfaabbc0d 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -69,7 +69,14 @@ void paintface_flush_flags(Object *ob) int totface, totpoly; int i; - if (me == NULL || dm == NULL) + if (me == NULL) + return; + + /* we could call this directly in all areas that change selection, + * since this could become slow for realtime updates (circle-select for eg) */ + BKE_mesh_flush_select_from_polys(me); + + if (dm == NULL) return; /* @@ -477,7 +484,7 @@ int paintface_mouse_select(struct bContext *C, Object *ob, const int mval[2], in /* Get the face under the cursor */ me = BKE_mesh_from_object(ob); - if (!ED_mesh_pick_face(C, me, mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) + if (!ED_mesh_pick_face(C, ob, mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) return 0; if (index >= me->totpoly) @@ -603,7 +610,14 @@ void paintvert_flush_flags(Object *ob) int totvert; int i; - if (me == NULL || dm == NULL) + if (me == NULL) + return; + + /* we could call this directly in all areas that change selection, + * since this could become slow for realtime updates (circle-select for eg) */ + BKE_mesh_flush_select_from_verts(me); + + if (dm == NULL) return; index_array = dm->getVertDataArray(dm, CD_ORIGINDEX); diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index c8a1264fd10..590bcd5939e 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -1315,7 +1315,7 @@ static void knife_bgl_get_mats(KnifeTool_OpData *UNUSED(kcd), bglMats *mats) //copy_m4_m4(mats->projection, kcd->vc.rv3d->winmat); } -/* Calculate maximum excursion (doubled) from (0,0,0) of mesh */ +/* Calculate maximum excursion from (0,0,0) of mesh */ static void calc_ortho_extent(KnifeTool_OpData *kcd) { BMIter iter; @@ -1328,7 +1328,19 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd) for (i = 0; i < 3; i++) max_xyz = max_ff(max_xyz, fabs(v->co[i])); } - kcd->ortho_extent = 2 * max_xyz; + kcd->ortho_extent = max_xyz; +} + +/* Clip the line (v1, v2) to planes perpendicular to it and distances d from + * the closest point on the line to the origin */ +static void clip_to_ortho_planes(float v1[3], float v2[3], float d) +{ + float closest[3]; + const float origin[3] = {0.0f, 0.0f, 0.0f}; + + closest_to_line_v3(closest, origin, v1, v2); + dist_ensure_v3_v3fl(v1, closest, d); + dist_ensure_v3_v3fl(v2, closest, d); } /* Finds visible (or all, if cutting through) edges that intersects the current screen drag line */ @@ -1375,8 +1387,8 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) if (kcd->is_ortho) { if (kcd->ortho_extent == 0.0f) calc_ortho_extent(kcd); - limit_dist_v3(v1, v3, kcd->ortho_extent + 10.0f); - limit_dist_v3(v2, v4, kcd->ortho_extent + 10.0f); + clip_to_ortho_planes(v1, v3, kcd->ortho_extent + 10.0f); + clip_to_ortho_planes(v2, v4, kcd->ortho_extent + 10.0f); } BLI_smallhash_init(ehash); diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 41b263e8929..27c68ce21bc 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -1674,7 +1674,7 @@ static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op) BMEditMesh *em = BMEdit_FromObject(obedit); int usex = TRUE, usey = TRUE, usez = TRUE, preserve_volume = TRUE; int i, repeat; - float lambda; + float lambda_factor; float lambda_border; BMIter fiter; BMFace *f; @@ -1695,7 +1695,7 @@ static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op) } repeat = RNA_int_get(op->ptr, "repeat"); - lambda = RNA_float_get(op->ptr, "lambda"); + lambda_factor = RNA_float_get(op->ptr, "lambda_factor"); lambda_border = RNA_float_get(op->ptr, "lambda_border"); usex = RNA_boolean_get(op->ptr, "use_x"); usey = RNA_boolean_get(op->ptr, "use_y"); @@ -1706,8 +1706,8 @@ static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op) for (i = 0; i < repeat; i++) { if (!EDBM_op_callf(em, op, - "smooth_laplacian_vert verts=%hv lambda=%f lambda_border=%f use_x=%b use_y=%b use_z=%b preserve_volume=%b", - BM_ELEM_SELECT, lambda, lambda_border, usex, usey, usez, preserve_volume)) + "smooth_laplacian_vert verts=%hv lambda_factor=%f lambda_border=%f use_x=%b use_y=%b use_z=%b preserve_volume=%b", + BM_ELEM_SELECT, lambda_factor, lambda_border, usex, usey, usez, preserve_volume)) { return OPERATOR_CANCELLED; } @@ -1740,7 +1740,7 @@ void MESH_OT_vertices_smooth_laplacian(wmOperatorType *ot) RNA_def_int(ot->srna, "repeat", 1, 1, 200, "Number of iterations to smooth the mesh", "", 1, 200); - RNA_def_float(ot->srna, "lambda", 0.00005f, 0.0000001f, 1000.0f, + RNA_def_float(ot->srna, "lambda_factor", 0.00005f, 0.0000001f, 1000.0f, "Lambda factor", "", 0.0000001f, 1000.0f); RNA_def_float(ot->srna, "lambda_border", 0.00005f, 0.0000001f, 1000.0f, "Lambda factor in border", "", 0.0000001f, 1000.0f); @@ -3582,7 +3582,7 @@ void MESH_OT_dissolve_limited(wmOperatorType *ot) prop = RNA_def_float_rotation(ot->srna, "angle_limit", 0, NULL, 0.0f, DEG2RADF(180.0f), "Max Angle", "Angle limit", 0.0f, DEG2RADF(180.0f)); - RNA_def_property_float_default(prop, DEG2RADF(15.0f)); + RNA_def_property_float_default(prop, DEG2RADF(5.0f)); RNA_def_boolean(ot->srna, "use_dissolve_boundaries", 0, "All Boundaries", "Dissolve all vertices inbetween face boundaries"); } @@ -4768,6 +4768,7 @@ static int edbm_bevel_calc(wmOperator *op) #ifdef NEW_BEVEL float offset = RNA_float_get(op->ptr, "offset"); int segments = RNA_int_get(op->ptr, "segments"); + int vertex_only = RNA_boolean_get(op->ptr, "vertex_only"); /* revert to original mesh */ if (opdata->is_modal) { @@ -4775,8 +4776,8 @@ static int edbm_bevel_calc(wmOperator *op) } if (!EDBM_op_init(em, &bmop, op, - "bevel geom=%hev offset=%f segments=%i", - BM_ELEM_SELECT, offset, segments)) + "bevel geom=%hev offset=%f segments=%i vertex_only=%b", + BM_ELEM_SELECT, offset, segments, vertex_only)) { return 0; } @@ -5101,6 +5102,7 @@ void MESH_OT_bevel(wmOperatorType *ot) #ifdef NEW_BEVEL RNA_def_float(ot->srna, "offset", 0.0f, -FLT_MAX, FLT_MAX, "Offset", "", 0.0f, 1.0f); RNA_def_int(ot->srna, "segments", 1, 1, 50, "Segments", "Segments for curved edge", 1, 8); + RNA_def_boolean(ot->srna, "vertex_only", FALSE, "Vertex only", "Bevel only vertices"); #else /* take note, used as a factor _and_ a distance depending on 'use_dist' */ RNA_def_float(ot->srna, "percent", 0.0f, -FLT_MAX, FLT_MAX, "Percentage", "", 0.0f, 1.0f); @@ -5732,18 +5734,6 @@ static int mesh_symmetrize_exec(bContext *C, wmOperator *op) void MESH_OT_symmetrize(struct wmOperatorType *ot) { - static EnumPropertyItem axis_direction_items[] = { - {BMO_SYMMETRIZE_NEGATIVE_X, "NEGATIVE_X", 0, "-X to +X", ""}, - {BMO_SYMMETRIZE_POSITIVE_X, "POSITIVE_X", 0, "+X to -X", ""}, - - {BMO_SYMMETRIZE_NEGATIVE_Y, "NEGATIVE_Y", 0, "-Y to +Y", ""}, - {BMO_SYMMETRIZE_POSITIVE_Y, "POSITIVE_Y", 0, "+Y to -Y", ""}, - - {BMO_SYMMETRIZE_NEGATIVE_Z, "NEGATIVE_Z", 0, "-Z to +Z", ""}, - {BMO_SYMMETRIZE_POSITIVE_Z, "POSITIVE_Z", 0, "+Z to -Z", ""}, - {0, NULL, 0, NULL, NULL}, - }; - /* identifiers */ ot->name = "Symmetrize"; ot->description = "Enforce symmetry (both form and topological) across an axis"; @@ -5756,7 +5746,7 @@ void MESH_OT_symmetrize(struct wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - ot->prop = RNA_def_enum(ot->srna, "direction", axis_direction_items, + ot->prop = RNA_def_enum(ot->srna, "direction", symmetrize_direction_items, BMO_SYMMETRIZE_NEGATIVE_X, "Direction", "Which sides to copy from and to"); } diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c index 1a81cab8de7..99fa85b3ee7 100644 --- a/source/blender/editors/mesh/mesh_navmesh.c +++ b/source/blender/editors/mesh/mesh_navmesh.c @@ -157,8 +157,9 @@ static void createVertsTrisData(bContext *C, LinkNode *obs, int *nverts_r, float *tris_r = tris; } -static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts, int ntris, int *tris, - struct recast_polyMesh **pmesh, struct recast_polyMeshDetail **dmesh) +static bool buildNavMesh(const RecastData *recastParams, int nverts, float *verts, int ntris, int *tris, + struct recast_polyMesh **pmesh, struct recast_polyMeshDetail **dmesh, + ReportList *reports) { float bmin[3], bmax[3]; struct recast_heightfield *solid; @@ -185,14 +186,20 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts /* Set the area where the navigation will be build. */ recast_calcGridSize(bmin, bmax, recastParams->cellsize, &width, &height); + /* zero dimensions cause zero alloc later on [#33758] */ + if (width <= 0 || height <= 0) { + BKE_report(reports, RPT_ERROR, "Object has a width or height of zero"); + return false; + } + /* ** Step 2: Rasterize input polygon soup ** */ /* Allocate voxel heightfield where we rasterize our input data to */ solid = recast_newHeightfield(); if (!recast_createHeightfield(solid, width, height, bmin, bmax, recastParams->cellsize, recastParams->cellheight)) { recast_destroyHeightfield(solid); - - return 0; + BKE_report(reports, RPT_ERROR, "Failed to create height field"); + return false; } /* Allocate array that can hold triangle flags */ @@ -215,7 +222,8 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts recast_destroyHeightfield(solid); recast_destroyCompactHeightfield(chf); - return 0; + BKE_report(reports, RPT_ERROR, "Failed to create compact height field"); + return false; } recast_destroyHeightfield(solid); @@ -224,21 +232,24 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts if (!recast_erodeWalkableArea(walkableRadius, chf)) { recast_destroyCompactHeightfield(chf); - return 0; + BKE_report(reports, RPT_ERROR, "Failed to erode walkable area"); + return false; } /* Prepare for region partitioning, by calculating distance field along the walkable surface */ if (!recast_buildDistanceField(chf)) { recast_destroyCompactHeightfield(chf); - return 0; + BKE_report(reports, RPT_ERROR, "Failed to build distance field"); + return false; } /* Partition the walkable surface into simple regions without holes */ if (!recast_buildRegions(chf, 0, minRegionArea, mergeRegionArea)) { recast_destroyCompactHeightfield(chf); - return 0; + BKE_report(reports, RPT_ERROR, "Failed to build regions"); + return false; } /* ** Step 5: Trace and simplify region contours ** */ @@ -249,7 +260,8 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts recast_destroyCompactHeightfield(chf); recast_destroyContourSet(cset); - return 0; + BKE_report(reports, RPT_ERROR, "Failed to build contours"); + return false; } /* ** Step 6: Build polygons mesh from contours ** */ @@ -259,7 +271,8 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts recast_destroyContourSet(cset); recast_destroyPolyMesh(*pmesh); - return 0; + BKE_report(reports, RPT_ERROR, "Failed to build poly mesh"); + return false; } @@ -272,13 +285,14 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts recast_destroyPolyMesh(*pmesh); recast_destroyPolyMeshDetail(*dmesh); - return 0; + BKE_report(reports, RPT_ERROR, "Failed to build poly mesh detail"); + return false; } recast_destroyCompactHeightfield(chf); recast_destroyContourSet(cset); - return 1; + return true; } static Object *createRepresentation(bContext *C, struct recast_polyMesh *pmesh, struct recast_polyMeshDetail *dmesh, Base *base) @@ -437,6 +451,7 @@ static int navmesh_create_exec(bContext *C, wmOperator *op) if (obs) { struct recast_polyMesh *pmesh = NULL; struct recast_polyMeshDetail *dmesh = NULL; + bool ok; int nverts = 0, ntris = 0; int *tris = 0; @@ -444,13 +459,14 @@ static int navmesh_create_exec(bContext *C, wmOperator *op) createVertsTrisData(C, obs, &nverts, &verts, &ntris, &tris); BLI_linklist_free(obs, NULL); - buildNavMesh(&scene->gm.recastData, nverts, verts, ntris, tris, &pmesh, &dmesh); - createRepresentation(C, pmesh, dmesh, navmeshBase); + if ((ok = buildNavMesh(&scene->gm.recastData, nverts, verts, ntris, tris, &pmesh, &dmesh, op->reports))) { + createRepresentation(C, pmesh, dmesh, navmeshBase); + } MEM_freeN(verts); MEM_freeN(tris); - return OPERATOR_FINISHED; + return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } else { BKE_report(op->reports, RPT_ERROR, "No mesh objects found"); diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index 773331d20f8..96b8f1080b9 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -40,6 +40,8 @@ #include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_view3d_types.h" #include "BLI_math.h" #include "BLI_blenlib.h" @@ -1165,9 +1167,12 @@ int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em) * * \return boolean TRUE == Found */ -int ED_mesh_pick_face(bContext *C, Mesh *me, const int mval[2], unsigned int *index, int size) +int ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], unsigned int *index, int size) { ViewContext vc; + Mesh *me = ob->data; + + BLI_assert(me && GS(me->id.name) == ID_ME); if (!me || me->totpoly == 0) return 0; @@ -1197,11 +1202,14 @@ int ED_mesh_pick_face(bContext *C, Mesh *me, const int mval[2], unsigned int *in * Use when the back buffer stores face index values. but we want a vert. * This gets the face then finds the closest vertex to mval. */ -int ED_mesh_pick_face_vert(bContext *C, Mesh *me, Object *ob, const int mval[2], unsigned int *index, int size) +int ED_mesh_pick_face_vert(bContext *C, Object *ob, const int mval[2], unsigned int *index, int size) { unsigned int poly_index; + Mesh *me = ob->data; - if (ED_mesh_pick_face(C, me, mval, &poly_index, size)) { + BLI_assert(me && GS(me->id.name) == ID_ME); + + if (ED_mesh_pick_face(C, ob, mval, &poly_index, size)) { Scene *scene = CTX_data_scene(C); struct ARegion *ar = CTX_wm_region(C); @@ -1210,6 +1218,8 @@ int ED_mesh_pick_face_vert(bContext *C, Mesh *me, Object *ob, const int mval[2], int v_idx_best = -1; if (dm->getVertCo) { + RegionView3D *rv3d = ar->regiondata; + /* find the vert closest to 'mval' */ const float mval_f[2] = {(float)mval[0], (float)mval[1]}; @@ -1217,14 +1227,15 @@ int ED_mesh_pick_face_vert(bContext *C, Mesh *me, Object *ob, const int mval[2], int fidx; float len_best = FLT_MAX; + ED_view3d_init_mats_rv3d(ob, rv3d); + fidx = mp->totloop - 1; do { float co[3], sco[2], len; const int v_idx = me->mloop[mp->loopstart + fidx].v; dm->getVertCo(dm, v_idx, co); - mul_m4_v3(ob->obmat, co); - if (ED_view3d_project_float_global(ar, co, sco, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { - len = len_squared_v2v2(mval_f, sco); + if (ED_view3d_project_float_object(ar, co, sco, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { + len = len_manhattan_v2v2(mval_f, sco); if (len < len_best) { len_best = len; v_idx_best = v_idx; @@ -1250,31 +1261,97 @@ int ED_mesh_pick_face_vert(bContext *C, Mesh *me, Object *ob, const int mval[2], * * \return boolean TRUE == Found */ -int ED_mesh_pick_vert(bContext *C, Mesh *me, const int mval[2], unsigned int *index, int size) +typedef struct VertPickData { + const MVert *mvert; + const float *mval_f; /* [2] */ + ARegion *ar; + + /* runtime */ + float len_best; + int v_idx_best; +} VertPickData; + +static void ed_mesh_pick_vert__mapFunc(void *userData, int index, const float co[3], + const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) +{ + VertPickData *data = userData; + if ((data->mvert[index].flag & ME_HIDE) == 0) { + float sco[2]; + + if (ED_view3d_project_float_object(data->ar, co, sco, V3D_PROJ_TEST_CLIP_DEFAULT) == V3D_PROJ_RET_OK) { + const float len = len_manhattan_v2v2(data->mval_f, sco); + if (len < data->len_best) { + data->len_best = len; + data->v_idx_best = index; + } + } + } +} +int ED_mesh_pick_vert(bContext *C, Object *ob, const int mval[2], unsigned int *index, int size, int use_zbuf) { ViewContext vc; + Mesh *me = ob->data; + + BLI_assert(me && GS(me->id.name) == ID_ME); if (!me || me->totvert == 0) return 0; view3d_set_viewcontext(C, &vc); - if (size > 0) { - /* sample rect to increase chances of selecting, so that when clicking - * on an face in the backbuf, we can still select a vert */ + if (use_zbuf) { + if (size > 0) { + /* sample rect to increase chances of selecting, so that when clicking + * on an face in the backbuf, we can still select a vert */ - float dummy_dist; - *index = view3d_sample_backbuf_rect(&vc, mval, size, 1, me->totvert + 1, &dummy_dist, 0, NULL, NULL); + float dummy_dist; + *index = view3d_sample_backbuf_rect(&vc, mval, size, 1, me->totvert + 1, &dummy_dist, 0, NULL, NULL); + } + else { + /* sample only on the exact position */ + *index = view3d_sample_backbuf(&vc, mval[0], mval[1]); + } + + if ((*index) <= 0 || (*index) > (unsigned int)me->totvert) + return 0; + + (*index)--; } else { - /* sample only on the exact position */ - *index = view3d_sample_backbuf(&vc, mval[0], mval[1]); - } + /* derived mesh to find deformed locations */ + DerivedMesh *dm = mesh_get_derived_final(vc.scene, ob, CD_MASK_BAREMESH); + ARegion *ar = vc.ar; + RegionView3D *rv3d = ar->regiondata; - if ((*index) <= 0 || (*index) > (unsigned int)me->totvert) - return 0; + /* find the vert closest to 'mval' */ + const float mval_f[2] = {(float)mval[0], + (float)mval[1]}; - (*index)--; + VertPickData data = {0}; + + ED_view3d_init_mats_rv3d(ob, rv3d); + + if (dm == NULL) { + return 0; + } + + /* setup data */ + data.mvert = me->mvert; + data.ar = ar; + data.mval_f = mval_f; + data.len_best = FLT_MAX; + data.v_idx_best = -1; + + dm->foreachMappedVert(dm, ed_mesh_pick_vert__mapFunc, &data); + + dm->release(dm); + + if (data.v_idx_best == -1) { + return 0; + } + + *index = data.v_idx_best; + } return 1; } diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 473119c90f3..4db416b6f72 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -808,9 +808,16 @@ static int group_instance_add_exec(bContext *C, wmOperator *op) if (RNA_struct_property_is_set(op->ptr, "name")) { char name[MAX_ID_NAME - 2]; - + RNA_string_get(op->ptr, "name", name); group = (Group *)BKE_libblock_find_name(ID_GR, name); + + if (0 == RNA_struct_property_is_set(op->ptr, "location")) { + wmEvent *event = CTX_wm_window(C)->eventstate; + ED_object_location_from_view(C, loc); + ED_view3d_cursor3d_position(C, loc, event->x, event->y); + RNA_float_set_array(op->ptr, "location", loc); + } } else group = BLI_findlink(&CTX_data_main(C)->group, RNA_enum_get(op->ptr, "group")); @@ -1994,6 +2001,7 @@ void OBJECT_OT_duplicate(wmOperatorType *ot) static int add_named_exec(bContext *C, wmOperator *op) { + wmEvent *event = CTX_wm_window(C)->eventstate; Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Base *basen, *base; @@ -2026,6 +2034,8 @@ static int add_named_exec(bContext *C, wmOperator *op) basen->lay = basen->object->lay = scene->lay; ED_object_location_from_view(C, basen->object->loc); + ED_view3d_cursor3d_position(C, basen->object->loc, event->x, event->y); + ED_base_object_activate(C, basen); copy_object_set_idnew(C, dupflag); diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index d3ebd1dae0a..f36c6d79783 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -89,6 +89,7 @@ typedef struct MultiresBakerJobData { struct MultiresBakerJobData *next, *prev; DerivedMesh *lores_dm, *hires_dm; int simple, lvl, tot_lvl; + ListBase images; } MultiresBakerJobData; /* data passing to multires-baker job */ @@ -429,7 +430,7 @@ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, floa RE_multires_bake_images(&bkr); - BLI_freelistN(&bkr.image); + data->images = bkr.image; baked_objects++; } @@ -439,12 +440,22 @@ static void multiresbake_freejob(void *bkv) { MultiresBakeJob *bkj = bkv; MultiresBakerJobData *data, *next; + LinkData *link; data = bkj->data.first; while (data) { next = data->next; data->lores_dm->release(data->lores_dm); data->hires_dm->release(data->hires_dm); + + /* delete here, since this delete will be called from main thread */ + for (link = data->images.first; link; link = link->next) { + Image *ima = (Image *)link->data; + GPU_free_image(ima); + } + + BLI_freelistN(&data->images); + MEM_freeN(data); data = next; } diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index f78e1203bc4..6cb7cd5e326 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -141,7 +141,7 @@ ListBase *get_constraint_lb(Object *ob, bConstraint *con, bPoseChannel **pchan_r /* single constraint */ bConstraint *get_active_constraint(Object *ob) { - return constraints_get_active(get_active_constraints(ob)); + return BKE_constraints_get_active(get_active_constraints(ob)); } /* -------------- Constraint Management (Add New, Remove, Rename) -------------------- */ @@ -225,7 +225,7 @@ static void update_pyconstraint_cb(void *arg1, void *arg2) /* helper function for add_constriant - sets the last target for the active constraint */ static void set_constraint_nth_target(bConstraint *con, Object *target, const char subtarget[], int index) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; int num_targets, i; @@ -297,7 +297,7 @@ static void test_constraints(Object *owner, bPoseChannel *pchan) /* Check all constraints - is constraint valid? */ if (conlist) { for (curcon = conlist->first; curcon; curcon = curcon->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(curcon); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(curcon); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -610,7 +610,7 @@ static bConstraint *edit_constraint_property_get(wmOperator *op, Object *ob, int list = get_active_constraints(ob); } - con = constraints_findByName(list, constraint_name); + con = BKE_constraints_findByName(list, constraint_name); //if (G.debug & G_DEBUG) //printf("constraint found = %p, %s\n", (void *)con, (con)?con->name:"<Not found>"); @@ -1123,7 +1123,7 @@ void ED_object_constraint_set_active(Object *ob, bConstraint *con) if ((lb && con) && (con->flag & CONSTRAINT_ACTIVE)) return; - constraints_set_active(lb, con); + BKE_constraints_set_active(lb, con); } void ED_object_constraint_update(Object *ob) @@ -1162,9 +1162,9 @@ static int constraint_delete_exec(bContext *C, wmOperator *UNUSED(op)) const short is_ik = ELEM(con->type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK); /* free the constraint */ - if (remove_constraint(lb, con)) { + if (BKE_remove_constraint(lb, con)) { /* there's no active constraint now, so make sure this is the case */ - constraints_set_active(lb, NULL); + BKE_constraints_set_active(lb, NULL); ED_object_constraint_update(ob); /* needed to set the flags on posebones correctly */ @@ -1308,7 +1308,7 @@ static int pose_constraints_clear_exec(bContext *C, wmOperator *UNUSED(op)) /* free constraints for all selected bones */ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones) { - free_constraints(&pchan->constraints); + BKE_free_constraints(&pchan->constraints); pchan->constflag &= ~(PCHAN_HAS_IK | PCHAN_HAS_SPLINEIK | PCHAN_HAS_CONST); } CTX_DATA_END; @@ -1346,7 +1346,7 @@ static int object_constraints_clear_exec(bContext *C, wmOperator *UNUSED(op)) /* do freeing */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { - free_constraints(&ob->constraints); + BKE_free_constraints(&ob->constraints); DAG_id_tag_update(&ob->id, OB_RECALC_OB); } CTX_DATA_END; @@ -1391,7 +1391,7 @@ static int pose_constraint_copy_exec(bContext *C, wmOperator *op) { /* if we're not handling the object we're copying from, copy all constraints over */ if (pchan != chan) { - copy_constraints(&chan->constraints, &pchan->constraints, TRUE); + BKE_copy_constraints(&chan->constraints, &pchan->constraints, TRUE); /* update flags (need to add here, not just copy) */ chan->constflag |= pchan->constflag; } @@ -1432,7 +1432,7 @@ static int object_constraint_copy_exec(bContext *C, wmOperator *UNUSED(op)) { /* if we're not handling the object we're copying from, copy all constraints over */ if (obact != ob) { - copy_constraints(&ob->constraints, &obact->constraints, TRUE); + BKE_copy_constraints(&ob->constraints, &obact->constraints, TRUE); DAG_id_tag_update(&ob->id, OB_RECALC_DATA); } } @@ -1642,9 +1642,9 @@ static int constraint_add_exec(bContext *C, wmOperator *op, Object *ob, ListBase /* create a new constraint of the type requried, and add it to the active/given constraints list */ if (pchan) - con = add_pose_constraint(ob, pchan, NULL, type); + con = BKE_add_pose_constraint(ob, pchan, NULL, type); else - con = add_ob_constraint(ob, NULL, type); + con = BKE_add_ob_constraint(ob, NULL, type); /* get the first selected object/bone, and make that the target * - apart from the buttons-window add buttons, we shouldn't add in this way @@ -1940,7 +1940,7 @@ static int pose_ik_clear_exec(bContext *C, wmOperator *UNUSED(op)) for (con = pchan->constraints.first; con; con = next) { next = con->next; if (con->type == CONSTRAINT_TYPE_KINEMATIC) { - remove_constraint(&pchan->constraints, con); + BKE_remove_constraint(&pchan->constraints, con); } } pchan->constflag &= ~(PCHAN_HAS_IK | PCHAN_HAS_TARGET); diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index c9492d8f683..fcc3b5d012e 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -954,7 +954,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event) } else if (event == 22) { /* Copy the constraint channels over */ - copy_constraints(&base->object->constraints, &ob->constraints, TRUE); + BKE_copy_constraints(&base->object->constraints, &ob->constraints, TRUE); do_scene_sort = TRUE; } diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c index a3bf27a19d6..7bf1a5db3b1 100644 --- a/source/blender/editors/object/object_group.c +++ b/source/blender/editors/object/object_group.c @@ -313,7 +313,7 @@ static int group_create_exec(bContext *C, wmOperator *op) group = add_group(name); - CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) + CTX_DATA_BEGIN (C, Base *, base, selected_bases) { add_to_group(group, base->object, scene, base); } diff --git a/source/blender/editors/object/object_lattice.c b/source/blender/editors/object/object_lattice.c index 4aa2e825954..c9eae776ac7 100644 --- a/source/blender/editors/object/object_lattice.c +++ b/source/blender/editors/object/object_lattice.c @@ -52,7 +52,7 @@ #include "BKE_depsgraph.h" #include "BKE_key.h" #include "BKE_lattice.h" -#include "BKE_mesh.h" +#include "BKE_deform.h" #include "ED_lattice.h" #include "ED_object.h" @@ -77,7 +77,7 @@ void free_editLatt(Object *ob) if (editlt->def) MEM_freeN(editlt->def); if (editlt->dvert) - free_dverts(editlt->dvert, editlt->pntsu * editlt->pntsv * editlt->pntsw); + BKE_defvert_array_free(editlt->dvert, editlt->pntsu * editlt->pntsv * editlt->pntsw); MEM_freeN(editlt); MEM_freeN(lt->editlatt); @@ -104,7 +104,7 @@ void make_editLatt(Object *obedit) if (lt->dvert) { int tot = lt->pntsu * lt->pntsv * lt->pntsw; lt->editlatt->latt->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert"); - copy_dverts(lt->editlatt->latt->dvert, lt->dvert, tot); + BKE_defvert_array_copy(lt->editlatt->latt->dvert, lt->dvert, tot); } if (lt->key) lt->editlatt->shapenr = obedit->shapenr; @@ -156,7 +156,7 @@ void load_editLatt(Object *obedit) } if (lt->dvert) { - free_dverts(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); + BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); lt->dvert = NULL; } @@ -164,7 +164,7 @@ void load_editLatt(Object *obedit) tot = lt->pntsu * lt->pntsv * lt->pntsw; lt->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert"); - copy_dverts(lt->dvert, editlt->dvert, tot); + BKE_defvert_array_copy(lt->dvert, editlt->dvert, tot); } } diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index d19277d20a2..03b50c05071 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -252,15 +252,6 @@ void ED_operatormacros_object(void) RNA_enum_set(otmacro->ptr, "proportional", PROP_EDIT_OFF); } - /* XXX */ - ot = WM_operatortype_append_macro("OBJECT_OT_add_named_cursor", "Add Named At Cursor", - "Add named object at cursor", OPTYPE_UNDO | OPTYPE_REGISTER); - if (ot) { - RNA_def_string(ot->srna, "name", "Cube", MAX_ID_NAME - 2, "Name", "Object name to add"); - - WM_operatortype_macro_define(ot, "VIEW3D_OT_cursor3d"); - WM_operatortype_macro_define(ot, "OBJECT_OT_add_named"); - } } static int object_mode_poll(bContext *C) diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 0988a196fb1..fa44d3d7fb4 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -716,12 +716,12 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object bFollowPathConstraint *data; float cmat[4][4], vec[3]; - con = add_ob_constraint(ob, "AutoPath", CONSTRAINT_TYPE_FOLLOWPATH); + con = BKE_add_ob_constraint(ob, "AutoPath", CONSTRAINT_TYPE_FOLLOWPATH); data = con->data; data->tar = par; - get_constraint_target_matrix(scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra); + BKE_get_constraint_target_matrix(scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra); sub_v3_v3v3(vec, ob->obmat[3], cmat[3]); ob->loc[0] = vec[0]; @@ -1051,7 +1051,7 @@ static int object_track_clear_exec(bContext *C, wmOperator *op) for (con = ob->constraints.last; con; con = pcon) { pcon = con->prev; if (ELEM3(con->type, CONSTRAINT_TYPE_TRACKTO, CONSTRAINT_TYPE_LOCKTRACK, CONSTRAINT_TYPE_DAMPTRACK)) - remove_constraint(&ob->constraints, con); + BKE_remove_constraint(&ob->constraints, con); } if (type == 1) @@ -1109,7 +1109,7 @@ static int track_set_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { if (ob != obact) { - con = add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_DAMPTRACK); + con = BKE_add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_DAMPTRACK); data = con->data; data->tar = obact; @@ -1129,7 +1129,7 @@ static int track_set_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { if (ob != obact) { - con = add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_TRACKTO); + con = BKE_add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_TRACKTO); data = con->data; data->tar = obact; @@ -1151,7 +1151,7 @@ static int track_set_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { if (ob != obact) { - con = add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_LOCKTRACK); + con = BKE_add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_LOCKTRACK); data = con->data; data->tar = obact; diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index 2aa737d204d..07eca749a74 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -42,6 +42,7 @@ #include "DNA_property_types.h" #include "DNA_scene_types.h" #include "DNA_armature_types.h" +#include "DNA_lamp_types.h" #include "BLI_math.h" #include "BLI_listbase.h" @@ -525,6 +526,7 @@ static EnumPropertyItem prop_select_grouped_types[] = { {10, "COLOR", 0, "Color", "Object Color"}, {11, "PROPERTIES", 0, "Properties", "Game Properties"}, {12, "KEYINGSET", 0, "Keying Set", "Objects included in active Keying Set"}, + {13, "LAMP_TYPE", 0, "Lamp Type", "Matching lamp types"}, {0, NULL, 0, NULL, NULL} }; @@ -656,7 +658,25 @@ static short select_grouped_siblings(bContext *C, Object *ob) CTX_DATA_END; return changed; } +static short select_similar_lamps(bContext *C, Object *ob) +{ + Lamp *la = ob->data; + + short changed = 0; + CTX_DATA_BEGIN (C, Base *, base, selectable_bases) + { + if (base->object->type == OB_LAMP) { + Lamp *la_test = base->object->data; + if ((la->type == la_test->type) && !(base->flag & SELECT)) { + ED_base_object_select(base, BA_SELECT); + changed = 1; + } + } + } + CTX_DATA_END; + return changed; +} static short select_grouped_type(bContext *C, Object *ob) { short changed = 0; @@ -803,7 +823,12 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_ERROR, "No active object"); return OPERATOR_CANCELLED; } - + + if (nr == 13 && ob->type != OB_LAMP) { + BKE_report(op->reports, RPT_ERROR, "Active object must be a lamp"); + return OPERATOR_CANCELLED; + } + if (nr == 1) changed |= select_grouped_children(C, ob, 1); else if (nr == 2) changed |= select_grouped_children(C, ob, 0); else if (nr == 3) changed |= select_grouped_parent(C); @@ -816,6 +841,7 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op) else if (nr == 10) changed |= select_grouped_color(C, ob); else if (nr == 11) changed |= select_grouped_gameprops(C, ob); else if (nr == 12) changed |= select_grouped_keyingset(C, ob); + else if (nr == 13) changed |= select_similar_lamps(C, ob); if (changed) { WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index 16fe94ff2e5..cbc076b3342 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -281,7 +281,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender) IMB_color_to_bw(ibuf); } - BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, scene->r.im_format.imtype, scene->r.scemode & R_EXTENSION, FALSE); + BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, &scene->r.im_format, scene->r.scemode & R_EXTENSION, FALSE); ok = BKE_imbuf_write_as(ibuf, name, &scene->r.im_format, TRUE); /* no need to stamp here */ if (ok) printf("OpenGL Render written to '%s'\n", name); else printf("OpenGL Render failed to write '%s'\n", name); @@ -505,7 +505,7 @@ static int screen_opengl_render_anim_step(bContext *C, wmOperator *op) is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype); if (!is_movie) { - BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, scene->r.im_format.imtype, scene->r.scemode & R_EXTENSION, TRUE); + BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, &scene->r.im_format, scene->r.scemode & R_EXTENSION, TRUE); if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) { printf("skipping existing frame \"%s\"\n", name); diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index a864fe306b3..8d748d3ea20 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -280,11 +280,6 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre sce->r.tiley = sce->r.ysch / 4; } - /* exception: don't apply render part of display transform for texture previews or icons */ - if ((id && sp->pr_method == PR_ICON_RENDER) || id_type == ID_TE) { - BKE_scene_disable_color_management(sce); - } - if ((id && sp->pr_method == PR_ICON_RENDER) && id_type != ID_WO) sce->r.alphamode = R_ALPHAPREMUL; else @@ -488,24 +483,15 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre /* new UI convention: draw is in pixel space already. */ /* uses ROUNDBOX button in block to get the rect */ -static int ed_preview_draw_rect(ScrArea *sa, Scene *sce, ID *id, int split, int first, rcti *rect, rcti *newrect) +static int ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect, rcti *newrect) { Render *re; RenderResult rres; char name[32]; - int do_gamma_correct = FALSE, do_predivide = FALSE; int offx = 0; int newx = BLI_rcti_size_x(rect); int newy = BLI_rcti_size_y(rect); - if (id && GS(id->name) != ID_TE) { - /* exception: don't color manage texture previews - show the raw values */ - if (sce) { - do_gamma_correct = TRUE; - do_predivide = sce->r.color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE; - } - } - if (!split || first) sprintf(name, "Preview %p", (void *)sa); else sprintf(name, "SecondPreview %p", (void *)sa); @@ -520,8 +506,10 @@ static int ed_preview_draw_rect(ScrArea *sa, Scene *sce, ID *id, int split, int } } + /* test if something rendered ok */ re = RE_GetRender(name); RE_AcquireResultImage(re, &rres); + RE_ReleaseResultImage(re); if (rres.rectf) { @@ -531,40 +519,20 @@ static int ed_preview_draw_rect(ScrArea *sa, Scene *sce, ID *id, int split, int newrect->ymax = max_ii(newrect->ymax, rect->ymin + rres.recty); if (rres.rectx && rres.recty) { - /* temporary conversion to byte for drawing */ + unsigned char *rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int), "ed_preview_draw_rect"); float fx = rect->xmin + offx; float fy = rect->ymin; - int dither = 0; - unsigned char *rect_byte; - - rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int), "ed_preview_draw_rect"); - - if (do_gamma_correct) { - IMB_display_buffer_transform_apply(rect_byte, rres.rectf, rres.rectx, rres.recty, 4, - &sce->view_settings, &sce->display_settings, do_predivide); - - } - else { - /* OCIO_TODO: currently seems an exception for textures (came fro mlegacish time), - * but is it indeed expected behavior, or textures should be - * color managed as well? - */ - IMB_buffer_byte_from_float(rect_byte, rres.rectf, - 4, dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, do_predivide, - rres.rectx, rres.recty, rres.rectx, rres.rectx); - } - + + RE_ResultGet32(re, (unsigned int *)rect_byte); glaDrawPixelsSafe(fx, fy, rres.rectx, rres.recty, rres.rectx, GL_RGBA, GL_UNSIGNED_BYTE, rect_byte); - + MEM_freeN(rect_byte); + + return 1; } - - RE_ReleaseResultImage(re); - return 1; } } - RE_ReleaseResultImage(re); return 0; } @@ -572,7 +540,6 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r { if (idp) { ScrArea *sa = CTX_wm_area(C); - Scene *sce = CTX_data_scene(C); ID *id = (ID *)idp; ID *parent = (ID *)parentp; MTex *slot = (MTex *)slotp; @@ -588,11 +555,11 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r newrect.ymax = rect->ymin; if (parent) { - ok = ed_preview_draw_rect(sa, sce, id, 1, 1, rect, &newrect); - ok &= ed_preview_draw_rect(sa, sce, parent, 1, 0, rect, &newrect); + ok = ed_preview_draw_rect(sa, 1, 1, rect, &newrect); + ok &= ed_preview_draw_rect(sa, 1, 0, rect, &newrect); } else - ok = ed_preview_draw_rect(sa, sce, id, 0, 0, rect, &newrect); + ok = ed_preview_draw_rect(sa, 0, 0, rect, &newrect); if (ok) *rect = newrect; diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index bc33936b2e3..dfc53d0b195 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -1310,7 +1310,7 @@ static int envmap_save_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "filepath", path); if (scene->r.scemode & R_EXTENSION) { - BKE_add_image_extension(path, imtype); + BKE_add_image_extension(path, &scene->r.im_format); } WM_cursor_wait(1); diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index fbdec3dd8ad..5af60726f14 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -574,8 +574,8 @@ static void area_azone_initialize(bScreen *screen, ScrArea *sa) az = (AZone *)MEM_callocN(sizeof(AZone), "actionzone"); BLI_addtail(&(sa->actionzones), az); az->type = AZONE_AREA; - az->x1 = sa->totrct.xmin - 1; - az->y1 = sa->totrct.ymin - 1; + az->x1 = sa->totrct.xmin; + az->y1 = sa->totrct.ymin; az->x2 = sa->totrct.xmin + (AZONESPOT - 1); az->y2 = sa->totrct.ymin + (AZONESPOT - 1); BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2); @@ -917,7 +917,7 @@ static int region_is_overlap(wmWindow *win, ScrArea *sa, ARegion *ar) { if (U.uiflag2 & USER_REGION_OVERLAP) if (WM_is_draw_triple(win)) - if (ELEM5(sa->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_SEQ, SPACE_CLIP, SPACE_NODE)) + if (ELEM4(sa->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_SEQ, SPACE_CLIP)) if (ELEM3(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS)) return 1; return 0; @@ -1300,6 +1300,9 @@ void ED_region_init(bContext *C, ARegion *ar) ar->winx = BLI_rcti_size_x(&ar->winrct) + 1; ar->winy = BLI_rcti_size_y(&ar->winrct) + 1; + /* v2d mask is used to subtract scrollbars from a 2d view. Needs initialize here. */ + BLI_rcti_init(&ar->v2d.mask, 0, ar->winx - 1, 0, ar->winy -1); + /* UI convention */ wmOrtho2(-0.01f, ar->winx - 0.01f, -0.01f, ar->winy - 0.01f); glLoadIdentity(); @@ -1612,86 +1615,141 @@ void ED_region_panels(const bContext *C, ARegion *ar, int vertical, const char * View2D *v2d = &ar->v2d; View2DScrollers *scrollers; int x, y, xco, yco, w, em, triangle, open, newcontext = 0; - + int redo; + int scroll; + if (contextnr >= 0) newcontext = UI_view2d_tab_set(v2d, contextnr); - + + /* before setting the view */ if (vertical) { - w = BLI_rctf_size_x(&v2d->cur); - em = (ar->type->prefsizex) ? UI_UNIT_Y / 2 : UI_UNIT_Y; + /* only allow scrolling in vertical direction */ + v2d->keepofs |= V2D_LOCKOFS_X | V2D_KEEPOFS_Y; + v2d->keepofs &= ~(V2D_LOCKOFS_Y | V2D_KEEPOFS_X); + v2d->scroll &= ~(V2D_SCROLL_BOTTOM); + v2d->scroll |= (V2D_SCROLL_RIGHT); } else { - w = UI_PANEL_WIDTH; - em = (ar->type->prefsizex) ? UI_UNIT_Y / 2 : UI_UNIT_Y; + /* for now, allow scrolling in both directions (since layouts are optimized for vertical, + * they often don't fit in horizontal layout) + */ + v2d->keepofs &= ~(V2D_LOCKOFS_X | V2D_LOCKOFS_Y | V2D_KEEPOFS_X | V2D_KEEPOFS_Y); + v2d->scroll |= (V2D_SCROLL_BOTTOM); + v2d->scroll &= ~(V2D_SCROLL_RIGHT); } - /* create panels */ - uiBeginPanels(C, ar); + scroll = v2d->scroll; + + /* sortof hack - but we cannot predict the height of panels, until it's being generated */ + /* the layout engine works with fixed width (from v2d->cur), which is being set at end of the loop */ + /* in case scroller settings (hide flags) differ from previous, the whole loop gets done again */ + for (redo = 2; redo > 0; redo--) { + + if (vertical) { + w = BLI_rctf_size_x(&v2d->cur); + em = (ar->type->prefsizex) ? UI_UNIT_Y / 2 : UI_UNIT_Y; + } + else { + w = UI_PANEL_WIDTH; + em = (ar->type->prefsizex) ? UI_UNIT_Y / 2 : UI_UNIT_Y; + } + + /* create panels */ + uiBeginPanels(C, ar); - /* set view2d view matrix for scrolling (without scrollers) */ - UI_view2d_view_ortho(v2d); + /* set view2d view matrix - uiBeginBlock() stores it */ + UI_view2d_view_ortho(v2d); - for (pt = ar->type->paneltypes.first; pt; pt = pt->next) { - /* verify context */ - if (context) - if (pt->context[0] && strcmp(context, pt->context) != 0) - continue; + for (pt = ar->type->paneltypes.first; pt; pt = pt->next) { + /* verify context */ + if (context) + if (pt->context[0] && strcmp(context, pt->context) != 0) + continue; - /* draw panel */ - if (pt->draw && (!pt->poll || pt->poll(C, pt))) { - block = uiBeginBlock(C, ar, pt->idname, UI_EMBOSS); - panel = uiBeginPanel(sa, ar, block, pt, &open); + /* draw panel */ + if (pt->draw && (!pt->poll || pt->poll(C, pt))) { + block = uiBeginBlock(C, ar, pt->idname, UI_EMBOSS); + panel = uiBeginPanel(sa, ar, block, pt, &open); - /* bad fixed values */ - triangle = (int)(UI_UNIT_Y * 1.1f); + /* bad fixed values */ + triangle = (int)(UI_UNIT_Y * 1.1f); - if (pt->draw_header && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) { - /* for enabled buttons */ - panel->layout = uiBlockLayout(block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, - triangle, (UI_UNIT_Y * 1.1f) + style->panelspace, UI_UNIT_Y, 1, style); + if (pt->draw_header && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) { + /* for enabled buttons */ + panel->layout = uiBlockLayout(block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, + triangle, (UI_UNIT_Y * 1.1f) + style->panelspace, UI_UNIT_Y, 1, style); - pt->draw_header(C, panel); + pt->draw_header(C, panel); - uiBlockLayoutResolve(block, &xco, &yco); - panel->labelofs = xco - triangle; - panel->layout = NULL; - } - else { - panel->labelofs = 0; - } + uiBlockLayoutResolve(block, &xco, &yco); + panel->labelofs = xco - triangle; + panel->layout = NULL; + } + else { + panel->labelofs = 0; + } - if (open) { - short panelContext; - - /* panel context can either be toolbar region or normal panels region */ - if (ar->regiontype == RGN_TYPE_TOOLS) - panelContext = UI_LAYOUT_TOOLBAR; - else - panelContext = UI_LAYOUT_PANEL; - - panel->layout = uiBlockLayout(block, UI_LAYOUT_VERTICAL, panelContext, - style->panelspace, 0, w - 2 * style->panelspace, em, style); + if (open) { + short panelContext; + + /* panel context can either be toolbar region or normal panels region */ + if (ar->regiontype == RGN_TYPE_TOOLS) + panelContext = UI_LAYOUT_TOOLBAR; + else + panelContext = UI_LAYOUT_PANEL; + + panel->layout = uiBlockLayout(block, UI_LAYOUT_VERTICAL, panelContext, + style->panelspace, 0, w - 2 * style->panelspace, em, style); - pt->draw(C, panel); + pt->draw(C, panel); - uiBlockLayoutResolve(block, &xco, &yco); - panel->layout = NULL; + uiBlockLayoutResolve(block, &xco, &yco); + panel->layout = NULL; - yco -= 2 * style->panelspace; - uiEndPanel(block, w, -yco); - } - else { - yco = 0; - uiEndPanel(block, w, 0); + yco -= 2 * style->panelspace; + uiEndPanel(block, w, -yco); + } + else { + yco = 0; + uiEndPanel(block, w, 0); + } + + uiEndBlock(C, block); } + } - uiEndBlock(C, block); + /* align panels and return size */ + uiEndPanels(C, ar, &x, &y); + + /* before setting the view */ + if (vertical) { + /* we always keep the scroll offset - so the total view gets increased with the scrolled away part */ + if (v2d->cur.ymax < - 0.001f) + y = min_ii(y, v2d->cur.ymin); + + y = -y; + } + else { + /* don't jump back when panels close or hide */ + if (!newcontext) + x = max_ii(x, v2d->cur.xmax); + y = -y; } + + /* this also changes the 'cur' */ + UI_view2d_totRect_set(v2d, x, y); + + if (scroll != v2d->scroll) { + /* Note: this code scales fine, but because of rounding differences, positions of elements + * flip +1 or -1 pixel compared to redoing the entire layout again. + * Leaving in commented code for future tests */ + /* uiScalePanels(ar, BLI_rctf_size_x(&v2d->cur)); + break; */ + } + else break; } - - /* align panels and return size */ - uiEndPanels(C, ar, &x, &y); - + + /* clear */ if (ar->overlap) { /* view should be in pixelspace */ @@ -1706,36 +1764,6 @@ void ED_region_panels(const bContext *C, ARegion *ar, int vertical, const char * glClear(GL_COLOR_BUFFER_BIT); } - /* before setting the view */ - if (vertical) { - /* only allow scrolling in vertical direction */ - v2d->keepofs |= V2D_LOCKOFS_X | V2D_KEEPOFS_Y; - v2d->keepofs &= ~(V2D_LOCKOFS_Y | V2D_KEEPOFS_X); - v2d->scroll |= V2D_SCROLL_HORIZONTAL_HIDE; - v2d->scroll &= ~V2D_SCROLL_VERTICAL_HIDE; - - /* ensure tot is set correctly, to keep views on bottons, with sliders */ - y = min_ii(y, v2d->cur.ymin); - y = -y; - } - else { - /* for now, allow scrolling in both directions (since layouts are optimized for vertical, - * they often don't fit in horizontal layout) - */ - v2d->keepofs &= ~(V2D_LOCKOFS_X | V2D_LOCKOFS_Y | V2D_KEEPOFS_X | V2D_KEEPOFS_Y); - //v2d->keepofs |= V2D_LOCKOFS_Y|V2D_KEEPOFS_X; - //v2d->keepofs &= ~(V2D_LOCKOFS_X|V2D_KEEPOFS_Y); - v2d->scroll |= V2D_SCROLL_VERTICAL_HIDE; - v2d->scroll &= ~V2D_SCROLL_HORIZONTAL_HIDE; - - /* don't jump back when panels close or hide */ - if (!newcontext) - x = max_ii(x, v2d->cur.xmax); - y = -y; - } - - /* +V2D_SCROLL_HEIGHT is workaround to set the actual height (needs to be int) */ - UI_view2d_totRect_set(v2d, x + (int)V2D_SCROLL_WIDTH, y + (int)V2D_SCROLL_HEIGHT); /* set the view */ UI_view2d_view_ortho(v2d); @@ -1755,17 +1783,6 @@ void ED_region_panels(const bContext *C, ARegion *ar, int vertical, const char * void ED_region_panels_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; - - /* XXX quick hacks for files saved with 2.5 already (i.e. the builtin defaults file) - * scrollbars for button regions */ - ar->v2d.scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM); - ar->v2d.scroll |= V2D_SCROLL_HORIZONTAL_HIDE; - ar->v2d.scroll &= ~V2D_SCROLL_VERTICAL_HIDE; - ar->v2d.keepzoom |= V2D_KEEPZOOM; - - /* correctly initialized User-Prefs? */ - if (!(ar->v2d.align & V2D_ALIGN_NO_POS_Y)) - ar->v2d.flag &= ~V2D_IS_INITIALISED; UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_PANELS_UI, ar->winx, ar->winy); @@ -1828,6 +1845,7 @@ void ED_region_header(const bContext *C, ARegion *ar) void ED_region_header_init(ARegion *ar) { + ar->v2d.flag &= ~V2D_IS_INITIALISED; UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_HEADER, ar->winx, ar->winy); } diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c index ca85daadf3b..2982e1f21af 100644 --- a/source/blender/editors/screen/screendump.c +++ b/source/blender/editors/screen/screendump.c @@ -223,7 +223,7 @@ static int screenshot_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event) static int screenshot_check(bContext *UNUSED(C), wmOperator *op) { ScreenshotData *scd = op->customdata; - return WM_operator_filesel_ensure_ext_imtype(op, scd->im_format.imtype); + return WM_operator_filesel_ensure_ext_imtype(op, &scd->im_format); } static int screenshot_cancel(bContext *UNUSED(C), wmOperator *op) @@ -361,7 +361,7 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float char name[FILE_MAX]; int ok; - BKE_makepicstring(name, rd.pic, sj->bmain->name, rd.cfra, rd.im_format.imtype, rd.scemode & R_EXTENSION, TRUE); + BKE_makepicstring(name, rd.pic, sj->bmain->name, rd.cfra, &rd.im_format, rd.scemode & R_EXTENSION, TRUE); ibuf->rect = sj->dumprect; ok = BKE_imbuf_write(ibuf, name, &rd.im_format); diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index ae72dce1415..5bed31e2e52 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -42,6 +42,7 @@ set(SRC paint_cursor.c paint_hide.c paint_image.c + paint_image_2d.c paint_mask.c paint_ops.c paint_stroke.c diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c index 36fe4715fc0..d50261a3b98 100644 --- a/source/blender/editors/sculpt_paint/paint_hide.c +++ b/source/blender/editors/sculpt_paint/paint_hide.c @@ -112,8 +112,8 @@ static void partialvis_update_mesh(Object *ob, int *vert_indices; int any_changed = 0, any_visible = 0, totvert, i; - BLI_pbvh_node_num_verts(pbvh, node, NULL, &totvert); - BLI_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert); + BKE_pbvh_node_num_verts(pbvh, node, NULL, &totvert); + BKE_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert); paint_mask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK); sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN); @@ -136,8 +136,8 @@ static void partialvis_update_mesh(Object *ob, } if (any_changed) { - BLI_pbvh_node_mark_rebuild_draw(node); - BLI_pbvh_node_fully_hidden_set(node, !any_visible); + BKE_pbvh_node_mark_rebuild_draw(node); + BKE_pbvh_node_fully_hidden_set(node, !any_visible); } } @@ -157,11 +157,11 @@ static void partialvis_update_grids(Object *ob, int *grid_indices, totgrid, any_changed, i; /* get PBVH data */ - BLI_pbvh_node_get_grids(pbvh, node, + BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, NULL, NULL, &grids, NULL); - grid_hidden = BLI_pbvh_grid_hidden(pbvh); - BLI_pbvh_get_grid_key(pbvh, &key); + grid_hidden = BKE_pbvh_grid_hidden(pbvh); + BKE_pbvh_get_grid_key(pbvh, &key); sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN); @@ -226,12 +226,81 @@ static void partialvis_update_grids(Object *ob, /* mark updates if anything was hidden/shown */ if (any_changed) { - BLI_pbvh_node_mark_rebuild_draw(node); - BLI_pbvh_node_fully_hidden_set(node, !any_visible); + BKE_pbvh_node_mark_rebuild_draw(node); + BKE_pbvh_node_fully_hidden_set(node, !any_visible); multires_mark_as_modified(ob, MULTIRES_HIDDEN_MODIFIED); } } +static void partialvis_update_bmesh_verts(BMesh *bm, + GHash *verts, + PartialVisAction action, + PartialVisArea area, + float planes[4][4], + int *any_changed, + int *any_visible) +{ + GHashIterator gh_iter; + + GHASH_ITER (gh_iter, verts) { + BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + float *vmask = CustomData_bmesh_get(&bm->vdata, + v->head.data, + CD_PAINT_MASK); + + /* hide vertex if in the hide volume */ + if (is_effected(area, planes, v->co, *vmask)) { + if (action == PARTIALVIS_HIDE) + BM_elem_flag_enable(v, BM_ELEM_HIDDEN); + else + BM_elem_flag_disable(v, BM_ELEM_HIDDEN); + (*any_changed) = TRUE; + } + + if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) + (*any_visible) = TRUE; + } +} + +static void partialvis_update_bmesh(Object *ob, + PBVH *pbvh, + PBVHNode *node, + PartialVisAction action, + PartialVisArea area, + float planes[4][4]) +{ + BMesh *bm; + GHash *unique, *other; + int any_changed = 0, any_visible = 0; + + bm = BKE_pbvh_get_bmesh(pbvh); + unique = BKE_pbvh_bmesh_node_unique_verts(node); + other = BKE_pbvh_bmesh_node_other_verts(node); + + sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN); + + partialvis_update_bmesh_verts(bm, + unique, + action, + area, + planes, + &any_changed, + &any_visible); + + partialvis_update_bmesh_verts(bm, + other, + action, + area, + planes, + &any_changed, + &any_visible); + + if (any_changed) { + BKE_pbvh_node_mark_rebuild_draw(node); + BKE_pbvh_node_fully_hidden_set(node, !any_visible); + } +} + static void rect_from_props(rcti *rect, PointerRNA *ptr) { rect->xmin = RNA_int_get(ptr, "xmin"); @@ -265,22 +334,22 @@ static void get_pbvh_nodes(PBVH *pbvh, float clip_planes[4][4], PartialVisArea mode) { - BLI_pbvh_SearchCallback cb = NULL; + BKE_pbvh_SearchCallback cb = NULL; /* select search callback */ switch (mode) { case PARTIALVIS_INSIDE: - cb = BLI_pbvh_node_planes_contain_AABB; + cb = BKE_pbvh_node_planes_contain_AABB; break; case PARTIALVIS_OUTSIDE: - cb = BLI_pbvh_node_planes_exclude_AABB; + cb = BKE_pbvh_node_planes_exclude_AABB; break; case PARTIALVIS_ALL: case PARTIALVIS_MASKED: break; } - BLI_pbvh_search_gather(pbvh, cb, clip_planes, nodes, totnode); + BKE_pbvh_search_gather(pbvh, cb, clip_planes, nodes, totnode); } static int hide_show_exec(bContext *C, wmOperator *op) @@ -310,7 +379,7 @@ static int hide_show_exec(bContext *C, wmOperator *op) ob->sculpt->pbvh = pbvh; get_pbvh_nodes(pbvh, &nodes, &totnode, clip_planes, area); - pbvh_type = BLI_pbvh_type(pbvh); + pbvh_type = BKE_pbvh_type(pbvh); /* start undo */ switch (action) { @@ -330,6 +399,9 @@ static int hide_show_exec(bContext *C, wmOperator *op) case PBVH_GRIDS: partialvis_update_grids(ob, pbvh, nodes[i], action, area, clip_planes); break; + case PBVH_BMESH: + partialvis_update_bmesh(ob, pbvh, nodes[i], action, area, clip_planes); + break; } } diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 8c9531e5554..fa8252c824d 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -42,7 +42,6 @@ #include "BLI_math.h" #include "BLI_blenlib.h" -#include "BLI_dynstr.h" #include "BLI_linklist.h" #include "BLI_memarena.h" #include "BLI_threads.h" @@ -54,13 +53,9 @@ #include "IMB_imbuf_types.h" #include "DNA_brush_types.h" -#include "DNA_camera_types.h" #include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" -#include "DNA_scene_types.h" -#include "DNA_texture_types.h" #include "BKE_camera.h" #include "BKE_context.h" @@ -77,8 +72,7 @@ #include "BKE_paint.h" #include "BKE_report.h" #include "BKE_scene.h" -#include "BKE_global.h" -#include "BKE_deform.h" +#include "BKE_colortools.h" #include "BKE_tessmesh.h" @@ -102,7 +96,6 @@ #include "RNA_enum_types.h" #include "GPU_draw.h" -#include "GPU_extensions.h" #include "IMB_colormanagement.h" @@ -5142,15 +5135,16 @@ static int texture_paint_init(bContext *C, wmOperator *op) return 0; } } - - paint_brush_init_tex(pop->s.brush); - + /* note, if we have no UVs on the derived mesh, then we must return here */ if (pop->mode == PAINT_MODE_3D_PROJECT) { /* initialize all data from the context */ project_state_init(C, OBACT, &pop->ps); - + + /* needed so multiple threads don't try to initialize the brush at once (can leak memory) */ + curvemapping_initialize(pop->ps.brush->curve); + paint_brush_init_tex(pop->ps.brush); pop->ps.source = PROJ_SRC_VIEW; @@ -5168,6 +5162,9 @@ static int texture_paint_init(bContext *C, wmOperator *op) if (pop->ps.dm == NULL) return 0; } + else { + paint_brush_init_tex(pop->s.brush); + } settings->imapaint.flag |= IMAGEPAINT_DRAWING; undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name, @@ -5237,8 +5234,6 @@ static void paint_exit(bContext *C, wmOperator *op) if (pop->restore_projection) settings->imapaint.flag &= ~IMAGEPAINT_PROJECT_DISABLE; - paint_brush_exit_tex(pop->s.brush); - settings->imapaint.flag &= ~IMAGEPAINT_DRAWING; imapaint_canvas_free(&pop->s); BKE_brush_painter_free(pop->painter); @@ -5250,6 +5245,8 @@ static void paint_exit(bContext *C, wmOperator *op) project_paint_end(&pop->ps); } else { + paint_brush_exit_tex(pop->s.brush); + /* non projection 3d paint, could move into own function of more needs adding */ if (pop->s.dm_release) pop->s.dm->release(pop->s.dm); diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c new file mode 100644 index 00000000000..c30996f03de --- /dev/null +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -0,0 +1,561 @@ +/* + * ***** 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) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/sculpt_paint/paint_image_2d.c + * \ingroup bke + */ +//#include <math.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_brush_types.h" +#include "DNA_scene_types.h" + +#include "BKE_brush.h" + +#include "BLI_math.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "RE_shader_ext.h" + + /* Brush Painting for 2D image editor */ + +typedef struct BrushPainterCache { + short enabled; + + int size; /* size override, if 0 uses 2*BKE_brush_size_get(brush) */ + short flt; /* need float imbuf? */ + short texonly; /* no alpha, color or fallof, only texture in imbuf */ + + int lastsize; + float lastalpha; + float lastjitter; + + ImBuf *ibuf; + ImBuf *texibuf; + ImBuf *maskibuf; +} BrushPainterCache; + +struct BrushPainter { + Scene *scene; + Brush *brush; + + float lastmousepos[2]; /* mouse position of last paint call */ + + float accumdistance; /* accumulated distance of brush since last paint op */ + float lastpaintpos[2]; /* position of last paint op */ + float startpaintpos[2]; /* position of first paint */ + + double accumtime; /* accumulated time since last paint op (airbrush) */ + double lasttime; /* time of last update */ + + float lastpressure; + + short firsttouch; /* first paint op */ + + float startsize; + float startalpha; + float startjitter; + float startspacing; + + BrushPainterCache cache; +}; + +BrushPainter *BKE_brush_painter_new(Scene *scene, Brush *brush) +{ + 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->startsize = BKE_brush_size_get(scene, brush); + painter->startalpha = BKE_brush_alpha_get(scene, brush); + painter->startjitter = brush->jitter; + painter->startspacing = brush->spacing; + + return painter; +} + + +static void brush_pressure_apply(BrushPainter *painter, Brush *brush, float pressure) +{ + if (BKE_brush_use_alpha_pressure(painter->scene, brush)) + BKE_brush_alpha_set(painter->scene, brush, max_ff(0.0f, painter->startalpha * pressure)); + if (BKE_brush_use_size_pressure(painter->scene, brush)) + BKE_brush_size_set(painter->scene, brush, max_ff(1.0f, painter->startsize * pressure)); + if (brush->flag & BRUSH_JITTER_PRESSURE) + brush->jitter = max_ff(0.0f, painter->startjitter * pressure); + if (brush->flag & BRUSH_SPACING_PRESSURE) + brush->spacing = max_ff(1.0f, painter->startspacing * (1.5f - pressure)); +} + + +void BKE_brush_painter_require_imbuf(BrushPainter *painter, short flt, short texonly, int size) +{ + if ((painter->cache.flt != flt) || (painter->cache.size != size) || + ((painter->cache.texonly != texonly) && texonly)) + { + if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf); + if (painter->cache.maskibuf) IMB_freeImBuf(painter->cache.maskibuf); + painter->cache.ibuf = painter->cache.maskibuf = NULL; + painter->cache.lastsize = -1; /* force ibuf create in refresh */ + } + + if (painter->cache.flt != flt) { + if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf); + painter->cache.texibuf = NULL; + painter->cache.lastsize = -1; /* force ibuf create in refresh */ + } + + painter->cache.size = size; + painter->cache.flt = flt; + painter->cache.texonly = texonly; + painter->cache.enabled = 1; +} + +void BKE_brush_painter_free(BrushPainter *painter) +{ + Brush *brush = painter->brush; + + BKE_brush_size_set(painter->scene, brush, painter->startsize); + BKE_brush_alpha_set(painter->scene, brush, painter->startalpha); + brush->jitter = painter->startjitter; + brush->spacing = painter->startspacing; + + if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf); + if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf); + if (painter->cache.maskibuf) IMB_freeImBuf(painter->cache.maskibuf); + MEM_freeN(painter); +} + +static void brush_painter_do_partial(BrushPainter *painter, ImBuf *oldtexibuf, + int x, int y, int w, int h, int xt, int yt, + const float pos[2]) +{ + Scene *scene = painter->scene; + Brush *brush = painter->brush; + ImBuf *ibuf, *maskibuf, *texibuf; + float *bf, *mf, *tf, *otf = NULL, xoff, yoff, xy[2], rgba[4]; + unsigned char *b, *m, *t, *ot = NULL; + int dotexold, origx = x, origy = y; + const int radius = BKE_brush_size_get(painter->scene, brush); + + xoff = -radius + 0.5f; + yoff = -radius + 0.5f; + xoff += (int)pos[0] - (int)painter->startpaintpos[0]; + yoff += (int)pos[1] - (int)painter->startpaintpos[1]; + + ibuf = painter->cache.ibuf; + texibuf = painter->cache.texibuf; + maskibuf = painter->cache.maskibuf; + + dotexold = (oldtexibuf != NULL); + + /* not sure if it's actually needed or it's a mistake in coords/sizes + * calculation in brush_painter_fixed_tex_partial_update(), but without this + * limitation memory gets corrupted at fast strokes with quite big spacing (sergey) */ + w = min_ii(w, ibuf->x); + h = min_ii(h, ibuf->y); + + if (painter->cache.flt) { + for (; y < h; y++) { + bf = ibuf->rect_float + (y * ibuf->x + origx) * 4; + tf = texibuf->rect_float + (y * texibuf->x + origx) * 4; + mf = maskibuf->rect_float + (y * maskibuf->x + origx) * 4; + + if (dotexold) + otf = oldtexibuf->rect_float + ((y - origy + yt) * oldtexibuf->x + xt) * 4; + + for (x = origx; x < w; x++, bf += 4, mf += 4, tf += 4) { + if (dotexold) { + copy_v3_v3(tf, otf); + tf[3] = otf[3]; + otf += 4; + } + else { + xy[0] = x + xoff; + xy[1] = y + yoff; + + BKE_brush_sample_tex(scene, brush, xy, tf, 0); + } + + bf[0] = tf[0] * mf[0]; + bf[1] = tf[1] * mf[1]; + bf[2] = tf[2] * mf[2]; + bf[3] = tf[3] * mf[3]; + } + } + } + else { + for (; y < h; y++) { + b = (unsigned char *)ibuf->rect + (y * ibuf->x + origx) * 4; + t = (unsigned char *)texibuf->rect + (y * texibuf->x + origx) * 4; + m = (unsigned char *)maskibuf->rect + (y * maskibuf->x + origx) * 4; + + if (dotexold) + ot = (unsigned char *)oldtexibuf->rect + ((y - origy + yt) * oldtexibuf->x + xt) * 4; + + for (x = origx; x < w; x++, b += 4, m += 4, t += 4) { + if (dotexold) { + t[0] = ot[0]; + t[1] = ot[1]; + t[2] = ot[2]; + t[3] = ot[3]; + ot += 4; + } + else { + xy[0] = x + xoff; + xy[1] = y + yoff; + + BKE_brush_sample_tex(scene, brush, xy, rgba, 0); + rgba_float_to_uchar(t, rgba); + } + + b[0] = t[0] * m[0] / 255; + b[1] = t[1] * m[1] / 255; + b[2] = t[2] * m[2] / 255; + b[3] = t[3] * m[3] / 255; + } + } + } +} + +static void brush_painter_fixed_tex_partial_update(BrushPainter *painter, const float pos[2]) +{ + 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; + const int diameter = 2 * BKE_brush_size_get(scene, brush); + + imbflag = (cache->flt) ? IB_rectfloat : IB_rect; + if (!cache->ibuf) + cache->ibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag); + ibuf = cache->ibuf; + + oldtexibuf = cache->texibuf; + cache->texibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag); + + 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; + + IMB_rectclip(cache->texibuf, oldtexibuf, &destx, &desty, &srcx, &srcy, &w, &h); + } + else { + srcx = srcy = 0; + destx = desty = 0; + w = h = 0; + } + + x1 = destx; + y1 = desty; + x2 = destx + w; + y2 = desty + h; + + /* blend existing texture in new position */ + if ((x1 < x2) && (y1 < y2)) + brush_painter_do_partial(painter, oldtexibuf, x1, y1, x2, y2, srcx, srcy, pos); + + if (oldtexibuf) + IMB_freeImBuf(oldtexibuf); + + /* sample texture in new areas */ + if ((0 < x1) && (0 < ibuf->y)) + brush_painter_do_partial(painter, NULL, 0, 0, x1, ibuf->y, 0, 0, pos); + if ((x2 < ibuf->x) && (0 < ibuf->y)) + brush_painter_do_partial(painter, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0, pos); + if ((x1 < x2) && (0 < y1)) + brush_painter_do_partial(painter, NULL, x1, 0, x2, y1, 0, 0, pos); + if ((x1 < x2) && (y2 < ibuf->y)) + brush_painter_do_partial(painter, NULL, x1, y2, x2, ibuf->y, 0, 0, pos); +} + +static void brush_painter_refresh_cache(BrushPainter *painter, const float pos[2], int use_color_correction) +{ + const Scene *scene = painter->scene; + Brush *brush = painter->brush; + BrushPainterCache *cache = &painter->cache; + MTex *mtex = &brush->mtex; + int size; + short flt; + const int diameter = 2 * BKE_brush_size_get(scene, brush); + const float alpha = BKE_brush_alpha_get(scene, brush); + + if (diameter != cache->lastsize || + alpha != cache->lastalpha || + brush->jitter != cache->lastjitter) + { + if (cache->ibuf) { + IMB_freeImBuf(cache->ibuf); + cache->ibuf = NULL; + } + if (cache->maskibuf) { + IMB_freeImBuf(cache->maskibuf); + cache->maskibuf = NULL; + } + + flt = cache->flt; + size = (cache->size) ? cache->size : diameter; + + if (brush->flag & BRUSH_FIXED_TEX) { + BKE_brush_imbuf_new(scene, brush, flt, 3, size, &cache->maskibuf, use_color_correction); + brush_painter_fixed_tex_partial_update(painter, pos); + } + else + BKE_brush_imbuf_new(scene, brush, flt, 2, size, &cache->ibuf, use_color_correction); + + cache->lastsize = diameter; + cache->lastalpha = alpha; + cache->lastjitter = brush->jitter; + } + else if ((brush->flag & BRUSH_FIXED_TEX) && mtex && mtex->tex) { + int dx = (int)painter->lastpaintpos[0] - (int)pos[0]; + int dy = (int)painter->lastpaintpos[1] - (int)pos[1]; + + if ((dx != 0) || (dy != 0)) + brush_painter_fixed_tex_partial_update(painter, pos); + } +} + +void BKE_brush_painter_break_stroke(BrushPainter *painter) +{ + painter->firsttouch = 1; +} + + +int BKE_brush_painter_paint(BrushPainter *painter, BrushFunc func, const float pos[2], double time, float pressure, + void *user, int use_color_correction) +{ + Scene *scene = painter->scene; + Brush *brush = painter->brush; + int totpaintops = 0; + + if (pressure == 0.0f) { + if (painter->lastpressure) // XXX - hack, operator misses + pressure = painter->lastpressure; + else + pressure = 1.0f; /* zero pressure == not using tablet */ + } + if (painter->firsttouch) { + /* paint exactly once on first touch */ + painter->startpaintpos[0] = pos[0]; + painter->startpaintpos[1] = pos[1]; + + brush_pressure_apply(painter, brush, pressure); + if (painter->cache.enabled) + brush_painter_refresh_cache(painter, pos, use_color_correction); + totpaintops += func(user, painter->cache.ibuf, pos, pos); + + painter->lasttime = time; + painter->firsttouch = 0; + painter->lastpaintpos[0] = pos[0]; + painter->lastpaintpos[1] = pos[1]; + } +#if 0 + else if (painter->brush->flag & BRUSH_AIRBRUSH) { + float spacing, step, paintpos[2], dmousepos[2], len; + double starttime, curtime = time; + + /* compute brush spacing adapted to brush size */ + spacing = brush->rate; //radius*brush->spacing*0.01f; + + /* setup starting time, direction vector and accumulated time */ + starttime = painter->accumtime; + sub_v2_v2v2(dmousepos, pos, painter->lastmousepos); + len = normalize_v2(dmousepos); + painter->accumtime += curtime - painter->lasttime; + + /* do paint op over unpainted time distance */ + while (painter->accumtime >= spacing) { + step = (spacing - starttime) * len; + paintpos[0] = painter->lastmousepos[0] + dmousepos[0] * step; + paintpos[1] = painter->lastmousepos[1] + dmousepos[1] * step; + + if (painter->cache.enabled) + brush_painter_refresh_cache(painter); + totpaintops += func(user, painter->cache.ibuf, + painter->lastpaintpos, paintpos); + + painter->lastpaintpos[0] = paintpos[0]; + painter->lastpaintpos[1] = paintpos[1]; + painter->accumtime -= spacing; + starttime -= spacing; + } + + painter->lasttime = curtime; + } +#endif + else { + float startdistance, spacing, step, paintpos[2], dmousepos[2], finalpos[2]; + float t, len, press; + const int radius = BKE_brush_size_get(scene, brush); + + /* compute brush spacing adapted to brush radius, spacing may depend + * on pressure, so update it */ + brush_pressure_apply(painter, brush, painter->lastpressure); + spacing = max_ff(1.0f, radius) * brush->spacing * 0.01f; + + /* setup starting distance, direction vector and accumulated distance */ + startdistance = painter->accumdistance; + sub_v2_v2v2(dmousepos, pos, painter->lastmousepos); + len = normalize_v2(dmousepos); + painter->accumdistance += len; + + if (brush->flag & BRUSH_SPACE) { + /* do paint op over unpainted distance */ + while ((len > 0.0f) && (painter->accumdistance >= spacing)) { + step = spacing - startdistance; + paintpos[0] = painter->lastmousepos[0] + dmousepos[0] * step; + paintpos[1] = painter->lastmousepos[1] + dmousepos[1] * step; + + t = step / len; + press = (1.0f - t) * painter->lastpressure + t * pressure; + brush_pressure_apply(painter, brush, press); + spacing = max_ff(1.0f, radius) * brush->spacing * 0.01f; + + BKE_brush_jitter_pos(scene, brush, paintpos, finalpos); + + if (painter->cache.enabled) + brush_painter_refresh_cache(painter, finalpos, use_color_correction); + + totpaintops += + func(user, painter->cache.ibuf, painter->lastpaintpos, finalpos); + + painter->lastpaintpos[0] = paintpos[0]; + painter->lastpaintpos[1] = paintpos[1]; + painter->accumdistance -= spacing; + startdistance -= spacing; + } + } + else { + BKE_brush_jitter_pos(scene, brush, pos, finalpos); + + if (painter->cache.enabled) + brush_painter_refresh_cache(painter, finalpos, use_color_correction); + + totpaintops += func(user, painter->cache.ibuf, pos, finalpos); + + painter->lastpaintpos[0] = pos[0]; + painter->lastpaintpos[1] = pos[1]; + painter->accumdistance = 0; + } + + /* do airbrush paint ops, based on the number of paint ops left over + * from regular painting. this is a temporary solution until we have + * accurate time stamps for mouse move events */ + if (brush->flag & BRUSH_AIRBRUSH) { + double curtime = time; + double painttime = brush->rate * totpaintops; + + painter->accumtime += curtime - painter->lasttime; + if (painter->accumtime <= painttime) + painter->accumtime = 0.0; + else + painter->accumtime -= painttime; + + while (painter->accumtime >= (double)brush->rate) { + brush_pressure_apply(painter, brush, pressure); + + BKE_brush_jitter_pos(scene, brush, pos, finalpos); + + if (painter->cache.enabled) + brush_painter_refresh_cache(painter, finalpos, use_color_correction); + + totpaintops += + func(user, painter->cache.ibuf, painter->lastmousepos, finalpos); + painter->accumtime -= (double)brush->rate; + } + + painter->lasttime = curtime; + } + } + + painter->lastmousepos[0] = pos[0]; + painter->lastmousepos[1] = pos[1]; + painter->lastpressure = pressure; + + BKE_brush_alpha_set(scene, brush, painter->startalpha); + BKE_brush_size_set(scene, brush, painter->startsize); + brush->jitter = painter->startjitter; + brush->spacing = painter->startspacing; + + return totpaintops; +} + + +/* TODO: should probably be unified with BrushPainter stuff? */ +unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side) +{ + unsigned int *texcache = NULL; + MTex *mtex = &br->mtex; + TexResult texres = {0}; + int hasrgb, ix, iy; + int side = half_side * 2; + + if (mtex->tex) { + float x, y, step = 2.0 / side, co[3]; + + texcache = MEM_callocN(sizeof(int) * side * side, "Brush texture cache"); + + /*do normalized cannonical view coords for texture*/ + for (y = -1.0, iy = 0; iy < side; iy++, y += step) { + for (x = -1.0, ix = 0; ix < side; ix++, x += step) { + co[0] = x; + co[1] = y; + co[2] = 0.0f; + + /* This is copied from displace modifier code */ + hasrgb = multitex_ext(mtex->tex, co, NULL, NULL, 0, &texres); + + /* if the texture gave an RGB value, we assume it didn't give a valid + * intensity, so calculate one (formula from do_material_tex). + * if the texture didn't give an RGB value, copy the intensity across + */ + if (hasrgb & TEX_RGB) + texres.tin = rgb_to_grayscale(&texres.tr); + + ((char *)texcache)[(iy * side + ix) * 4] = + ((char *)texcache)[(iy * side + ix) * 4 + 1] = + ((char *)texcache)[(iy * side + ix) * 4 + 2] = + ((char *)texcache)[(iy * side + ix) * 4 + 3] = (char)(texres.tin * 255.0f); + } + } + } + + return texcache; +} + diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index 9fe7fc1d3ac..3cf67667f39 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -96,7 +96,7 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op) pbvh = dm->getPBVH(ob, dm); ob->sculpt->pbvh = pbvh; - BLI_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode); + BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode); sculpt_undo_push_begin("Mask flood fill"); @@ -105,12 +105,12 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op) sculpt_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK); - BLI_pbvh_vertex_iter_begin(pbvh, nodes[i], vi, PBVH_ITER_UNIQUE) { + BKE_pbvh_vertex_iter_begin(pbvh, nodes[i], vi, PBVH_ITER_UNIQUE) { mask_flood_fill_set_elem(vi.mask, mode, value); - } BLI_pbvh_vertex_iter_end; + } BKE_pbvh_vertex_iter_end; - BLI_pbvh_node_mark_update(nodes[i]); - if (BLI_pbvh_type(pbvh) == PBVH_GRIDS) + BKE_pbvh_node_mark_update(nodes[i]); + if (BKE_pbvh_type(pbvh) == PBVH_GRIDS) multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED); } diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index 10b9f26dbcd..9e702c16e2f 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -648,6 +648,18 @@ void ED_keymap_paint(wmKeyConfig *keyconf) kmi = WM_keymap_add_item(keymap, "PAINT_OT_mask_flood_fill", IKEY, KM_PRESS, KM_CTRL, 0); RNA_enum_set(kmi->ptr, "mode", PAINT_MASK_INVERT); + /* Toggle dynamic topology */ + WM_keymap_add_item(keymap, "SCULPT_OT_dynamic_topology_toggle", DKEY, KM_PRESS, KM_CTRL, 0); + + /* Dynamic-topology detail size + * + * This should be improved further, perhaps by showing a triangle + * grid rather than brush alpha */ + kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", DKEY, KM_PRESS, KM_SHIFT, 0); + set_brush_rc_props(kmi->ptr, "sculpt", "detail_size", NULL, 0); + RNA_string_set(kmi->ptr, "data_path_primary", + "tool_settings.sculpt.detail_size"); + /* multires switch */ kmi = WM_keymap_add_item(keymap, "OBJECT_OT_subdivision_set", PAGEUPKEY, KM_PRESS, 0, 0); RNA_int_set(kmi->ptr, "level", 1); diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 9ebeb61a7bb..2f4115dcd94 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -416,6 +416,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event) if (!stroke->stroke_started) { copy_v2_v2(stroke->last_mouse_position, sample_average.mouse); stroke->stroke_started = stroke->test_start(C, op, sample_average.mouse); + BLI_assert((stroke->stroke_started & ~1) == 0); /* 0/1 */ if (stroke->stroke_started) { stroke->smooth_stroke_cursor = diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 359486a4a8d..08c26aaa755 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -372,31 +372,22 @@ static int wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active) bDeformGroup *defgroup = BLI_findlink(&ob->defbase, vgroup_active); if (defgroup) { - bDeformGroup *curdef; int mirrdef; char name[MAXBONENAME]; flip_side_name(name, defgroup->name, FALSE); - - if (strcmp(name, defgroup->name) != 0) { - for (curdef = ob->defbase.first, mirrdef = 0; curdef; curdef = curdef->next, mirrdef++) { - if (!strcmp(curdef->name, name)) { - break; - } - } - - if (curdef == NULL) { - int olddef = ob->actdef; /* tsk, ED_vgroup_add sets the active defgroup */ - curdef = ED_vgroup_add_name(ob, name); - ob->actdef = olddef; - } - - /* curdef should never be NULL unless this is - * a lamp and ED_vgroup_add_name fails */ - if (curdef) { - return mirrdef; + mirrdef = defgroup_name_index(ob, name); + if (mirrdef == -1) { + int olddef = ob->actdef; /* tsk, ED_vgroup_add sets the active defgroup */ + if (ED_vgroup_add_name(ob, name)) { + mirrdef = BLI_countlist(&ob->defbase) - 1; } + ob->actdef = olddef; } + + /* curdef should never be NULL unless this is + * a lamp and ED_vgroup_add_name fails */ + return mirrdef; } return -1; @@ -414,7 +405,7 @@ static void free_vpaint_prev(VPaint *vp) static void free_wpaint_prev(VPaint *vp) { if (vp->wpaint_prev) { - MEM_freeN(vp->wpaint_prev); + BKE_defvert_array_free(vp->wpaint_prev, vp->tot); vp->wpaint_prev = NULL; vp->tot = 0; } @@ -441,7 +432,7 @@ static void copy_wpaint_prev(VPaint *wp, MDeformVert *dverts, int dcount) wp->wpaint_prev = MEM_mallocN(sizeof(MDeformVert) * dcount, "wpaint prev"); wp->tot = dcount; - copy_dverts(wp->wpaint_prev, dverts, dcount); + BKE_defvert_array_copy(wp->wpaint_prev, dverts, dcount); } } @@ -868,7 +859,10 @@ static float calc_vp_strength_dl(VPaint *vp, ViewContext *vc, const float co[3], { float vertco[2]; - if (ED_view3d_project_float_global(vc->ar, co, vertco, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { + if (ED_view3d_project_float_object(vc->ar, + co, vertco, + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) + { float delta[2]; float dist_squared; @@ -1037,15 +1031,15 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, wmEvent *event) view3d_operator_needs_opengl(C); if (use_vert_sel) { - if (ED_mesh_pick_vert(C, me, event->mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE)) { + if (ED_mesh_pick_vert(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, TRUE)) { v_idx_best = index; } } else { - if (ED_mesh_pick_face_vert(C, me, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { + if (ED_mesh_pick_face_vert(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { v_idx_best = index; } - else if (ED_mesh_pick_face(C, me, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { + else if (ED_mesh_pick_face(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { /* this relies on knowning the internal worksings of ED_mesh_pick_face_vert() */ BKE_report(op->reports, RPT_WARNING, "The modifier used does not support deformed locations"); } @@ -1126,13 +1120,13 @@ static EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, PointerRNA view3d_operator_needs_opengl(C); if (use_vert_sel) { - if (ED_mesh_pick_vert(C, me, mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE)) { + if (ED_mesh_pick_vert(C, vc.obact, mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, TRUE)) { MDeformVert *dvert = &me->dvert[index]; found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups); } } else { - if (ED_mesh_pick_face(C, me, mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { + if (ED_mesh_pick_face(C, vc.obact, mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) { MPoly *mp = &me->mpoly[index]; unsigned int fidx = mp->totloop - 1; @@ -2058,32 +2052,28 @@ struct WPaintData { int vgroup_mirror; DMCoNo *vertexcosnos; float wpimat[3][3]; - + /* variables for auto normalize */ const char *vgroup_validmap; /* stores if vgroups tie to deforming bones or not */ const char *lock_flags; int defbase_tot; }; -static int wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UNUSED(mouse[2])) +/* ensure we have data on wpaint start, add if needed */ +static int wpaint_ensure_data(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - struct PaintStroke *stroke = op->customdata; - ToolSettings *ts = scene->toolsettings; - VPaint *wp = ts->wpaint; Object *ob = CTX_data_active_object(C); - struct WPaintData *wpd; - Mesh *me; + Mesh *me = BKE_mesh_from_object(ob); - float mat[4][4], imat[4][4]; - if (scene->obedit) { return FALSE; } - - me = BKE_mesh_from_object(ob); - if (me == NULL || me->totpoly == 0) return OPERATOR_PASS_THROUGH; - + + if (me == NULL || me->totpoly == 0) { + return FALSE; + } + /* if nothing was added yet, we make dverts and a vertex deform group */ if (!me->dvert) { ED_vgroup_data_create(&me->id); @@ -2122,6 +2112,25 @@ static int wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UNU return FALSE; } + return TRUE; +} + +static int wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UNUSED(mouse[2])) +{ + Scene *scene = CTX_data_scene(C); + struct PaintStroke *stroke = op->customdata; + ToolSettings *ts = scene->toolsettings; + VPaint *wp = ts->wpaint; + Object *ob = CTX_data_active_object(C); + Mesh *me = BKE_mesh_from_object(ob); + struct WPaintData *wpd; + + float mat[4][4], imat[4][4]; + + if (wpaint_ensure_data(C, op) == FALSE) { + return FALSE; + } + { /* check if we are attempting to paint onto a locked vertex group, * and other options disallow it from doing anything useful */ @@ -2184,7 +2193,15 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P unsigned int index, totindex; float alpha; float mval[2]; - int use_vert_sel; + bool use_vert_sel; + bool use_face_sel; + bool use_depth; + + MDeformWeight *(*dw_func)(MDeformVert *, const int) = + (brush->vertexpaint_tool == PAINT_BLEND_BLUR) ? + ((wp->flag & VP_ONLYVGROUP) ? + (MDeformWeight *(*)(MDeformVert *, const int))defvert_find_index : + defvert_verify_index) : NULL; const float pressure = RNA_float_get(itemptr, "pressure"); const float brush_size_pressure = BKE_brush_size_get(scene, brush) * (BKE_brush_use_size_pressure(scene, brush) ? pressure : 1.0f); @@ -2201,7 +2218,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P ED_region_tag_redraw(CTX_wm_region(C)); return; } - + vc = &wpd->vc; ob = vc->obact; me = ob->data; @@ -2242,31 +2259,38 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P swap_m4m4(wpd->vc.rv3d->persmat, mat); use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; + use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + use_depth = (vc->v3d->flag & V3D_ZBUF_SELECT); /* which faces are involved */ - if (wp->flag & VP_AREA) { - /* Ugly hack, to avoid drawing vertex index when getting the face index buffer - campbell */ - me->editflag &= ~ME_EDIT_PAINT_VERT_SEL; - totindex = sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure); - me->editflag |= use_vert_sel ? ME_EDIT_PAINT_VERT_SEL : 0; - } - else { - indexar[0] = view3d_sample_backbuf(vc, mval[0], mval[1]); - if (indexar[0]) totindex = 1; - else totindex = 0; - } + if (use_depth) { + if (wp->flag & VP_AREA) { + /* Ugly hack, to avoid drawing vertex index when getting the face index buffer - campbell */ + me->editflag &= ~ME_EDIT_PAINT_VERT_SEL; + totindex = sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure); + me->editflag |= use_vert_sel ? ME_EDIT_PAINT_VERT_SEL : 0; + } + else { + indexar[0] = view3d_sample_backbuf(vc, mval[0], mval[1]); + if (indexar[0]) totindex = 1; + else totindex = 0; + } - if ((me->editflag & ME_EDIT_PAINT_FACE_SEL) && me->mpoly) { - for (index = 0; index < totindex; index++) { - if (indexar[index] && indexar[index] <= me->totpoly) { - MPoly *mpoly = ((MPoly *)me->mpoly) + (indexar[index] - 1); - - if ((mpoly->flag & ME_FACE_SEL) == 0) { - indexar[index] = 0; + if (use_face_sel && me->mpoly) { + for (index = 0; index < totindex; index++) { + if (indexar[index] && indexar[index] <= me->totpoly) { + MPoly *mpoly = ((MPoly *)me->mpoly) + (indexar[index] - 1); + + if ((mpoly->flag & ME_FACE_SEL) == 0) { + indexar[index] = 0; + } } } } } + else { + indexar = NULL; + } /* make sure each vertex gets treated only once */ /* and calculate filter weight */ @@ -2275,80 +2299,121 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P paintweight = 0.0f; else paintweight = BKE_brush_weight_get(scene, brush); - - for (index = 0; index < totindex; index++) { - if (indexar[index] && indexar[index] <= me->totpoly) { - MPoly *mpoly = me->mpoly + (indexar[index] - 1); - MLoop *ml = me->mloop + mpoly->loopstart; - int i; - if (use_vert_sel) { - for (i = 0; i < mpoly->totloop; i++, ml++) { - me->dvert[ml->v].flag = (me->mvert[ml->v].flag & SELECT); +#define WP_BLUR_ACCUM(v_idx_var) \ + { \ + const unsigned int vidx = v_idx_var; \ + const float fac = calc_vp_strength_dl(wp, vc, wpd->vertexcosnos[vidx].co, mval, brush_size_pressure); \ + if (fac > 0.0f) { \ + MDeformWeight *dw = dw_func(&me->dvert[vidx], wpi.vgroup_active); \ + paintweight += dw ? (dw->weight * fac) : 0.0f; \ + totw += fac; \ + } \ + } (void)0 + + + if (use_depth) { + for (index = 0; index < totindex; index++) { + if (indexar[index] && indexar[index] <= me->totpoly) { + MPoly *mpoly = me->mpoly + (indexar[index] - 1); + MLoop *ml = me->mloop + mpoly->loopstart; + int i; + + if (use_vert_sel) { + for (i = 0; i < mpoly->totloop; i++, ml++) { + me->dvert[ml->v].flag = (me->mvert[ml->v].flag & SELECT); + } } - } - else { - for (i = 0; i < mpoly->totloop; i++, ml++) { - me->dvert[ml->v].flag = 1; + else { + for (i = 0; i < mpoly->totloop; i++, ml++) { + me->dvert[ml->v].flag = 1; + } } - } - - if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) { - MDeformWeight *dw, *(*dw_func)(MDeformVert *, const int); - - if (wp->flag & VP_ONLYVGROUP) - dw_func = (MDeformWeight *(*)(MDeformVert *, const int))defvert_find_index; - else - dw_func = defvert_verify_index; - - ml = me->mloop + mpoly->loopstart; - for (i = 0; i < mpoly->totloop; i++, ml++) { - unsigned int vidx = ml->v; - const float fac = calc_vp_strength_dl(wp, vc, wpd->vertexcosnos[vidx].co, mval, brush_size_pressure); - if (fac > 0.0f) { - dw = dw_func(&me->dvert[vidx], wpi.vgroup_active); - paintweight += dw ? (dw->weight * fac) : 0.0f; - totw += fac; + + if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) { + ml = me->mloop + mpoly->loopstart; + for (i = 0; i < mpoly->totloop; i++, ml++) { + WP_BLUR_ACCUM(ml->v); } } } } } - + else { + const unsigned int totvert = me->totvert; + unsigned int i; + + /* in the case of face selection we need to flush */ + if (use_vert_sel || use_face_sel) { + for (i = 0; i < totvert; i++) { + me->dvert[i].flag = me->mvert[i].flag & SELECT; + } + } + else { + for (i = 0; i < totvert; i++) { + me->dvert[i].flag = SELECT; + } + } + + if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) { + for (i = 0; i < totvert; i++) { + WP_BLUR_ACCUM(i); + } + } + } + +#undef WP_BLUR_ACCUM + + if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) { paintweight /= totw; } - for (index = 0; index < totindex; index++) { +#define WP_PAINT(v_idx_var) \ + { \ + unsigned int vidx = v_idx_var; \ + if (me->dvert[vidx].flag) { \ + alpha = calc_vp_alpha_dl(wp, vc, wpd->wpimat, &wpd->vertexcosnos[vidx], \ + mval, brush_size_pressure, brush_alpha_pressure); \ + if (alpha) { \ + do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight); \ + } \ + me->dvert[vidx].flag = 0; \ + } \ + } (void)0 + + if (use_depth) { + for (index = 0; index < totindex; index++) { - if (indexar[index] && indexar[index] <= me->totpoly) { - MPoly *mpoly = me->mpoly + (indexar[index] - 1); - MLoop *ml = me->mloop + mpoly->loopstart; - int i; - - for (i = 0; i < mpoly->totloop; i++, ml++) { - unsigned int vidx = ml->v; - - if (me->dvert[vidx].flag) { - alpha = calc_vp_alpha_dl(wp, vc, wpd->wpimat, &wpd->vertexcosnos[vidx], - mval, brush_size_pressure, brush_alpha_pressure); - if (alpha) { - do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight); - } - me->dvert[vidx].flag = 0; + if (indexar[index] && indexar[index] <= me->totpoly) { + MPoly *mpoly = me->mpoly + (indexar[index] - 1); + MLoop *ml = me->mloop + mpoly->loopstart; + int i; + + for (i = 0; i < mpoly->totloop; i++, ml++) { + WP_PAINT(ml->v); } } } } + else { + const unsigned int totvert = me->totvert; + unsigned int i; + + for (i = 0; i < totvert; i++) { + WP_PAINT(i); + } + } +#undef WP_PAINT /* *** free wpi members */ MEM_freeN((void *)wpi.defbase_sel); - /* *** don't freeing wpi members */ + /* *** done freeing wpi members */ swap_m4m4(vc->rv3d->persmat, mat); - + DAG_id_tag_update(ob->data, 0); ED_region_tag_redraw(vc->ar); } @@ -2442,7 +2507,7 @@ void PAINT_OT_weight_paint(wmOperatorType *ot) RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); } -static int weight_paint_set_exec(bContext *C, wmOperator *UNUSED(op)) +static int weight_paint_set_exec(bContext *C, wmOperator *op) { struct Scene *scene = CTX_data_scene(C); Object *obact = CTX_data_active_object(C); @@ -2450,6 +2515,10 @@ static int weight_paint_set_exec(bContext *C, wmOperator *UNUSED(op)) Brush *brush = paint_brush(&ts->wpaint->paint); float vgroup_weight = BKE_brush_weight_get(scene, brush); + if (wpaint_ensure_data(C, op) == FALSE) { + return OPERATOR_CANCELLED; + } + wpaint_fill(scene->toolsettings->wpaint, obact, vgroup_weight); ED_region_tag_redraw(CTX_wm_region(C)); /* XXX - should redraw all 3D views */ return OPERATOR_FINISHED; @@ -2992,9 +3061,9 @@ static void gradientVert__mapFunc(void *userData, int index, const float co[3], * the screen coords of the verts need to be cached because * updating the mesh may move them about (entering feedback loop) */ if (grad_data->is_init) { - if (ED_view3d_project_float_global(grad_data->ar, + if (ED_view3d_project_float_object(grad_data->ar, co, vs->sco, - V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) + V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) { /* ok */ MDeformVert *dv = &me->dvert[index]; @@ -3022,11 +3091,9 @@ static void gradientVert__mapFunc(void *userData, int index, const float co[3], if (grad_data->type == WPAINT_GRADIENT_TYPE_LINEAR) { alpha = line_point_factor_v2(vs->sco, grad_data->sco_start, grad_data->sco_end); } - else if (grad_data->type == WPAINT_GRADIENT_TYPE_RADIAL) { - alpha = len_v2v2(grad_data->sco_start, vs->sco) * grad_data->sco_line_div; - } else { - BLI_assert(0); + BLI_assert(grad_data->type == WPAINT_GRADIENT_TYPE_RADIAL); + alpha = len_v2v2(grad_data->sco_start, vs->sco) * grad_data->sco_line_div; } /* no need to clamp 'alpha' yet */ @@ -3082,7 +3149,7 @@ static int paint_weight_gradient_modal(bContext *C, wmOperator *op, wmEvent *eve VPaint *wp = ts->wpaint; Object *ob = CTX_data_active_object(C); Mesh *me = ob->data; - copy_dverts(me->dvert, wp->wpaint_prev, me->totvert); + BKE_defvert_array_copy(me->dvert, wp->wpaint_prev, me->totvert); free_wpaint_prev(wp); DAG_id_tag_update(&ob->id, OB_RECALC_DATA); @@ -3159,7 +3226,13 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op) static int paint_weight_gradient_invoke(bContext *C, wmOperator *op, wmEvent *event) { - int ret = WM_gesture_straightline_invoke(C, op, event); + int ret; + + if (wpaint_ensure_data(C, op) == FALSE) { + return OPERATOR_CANCELLED; + } + + ret = WM_gesture_straightline_invoke(C, op, event); if (ret & OPERATOR_RUNNING_MODAL) { struct ARegion *ar = CTX_wm_region(C); if (ar->regiontype == RGN_TYPE_WINDOW) { diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 8325b47beab..54ae2ebf588 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -65,6 +65,7 @@ #include "BKE_report.h" #include "BKE_lattice.h" /* for armature_deform_verts */ #include "BKE_node.h" +#include "BKE_object.h" #include "BKE_subsurf.h" #include "BIF_glutil.h" @@ -86,6 +87,8 @@ #include "GPU_buffers.h" +#include "bmesh.h" + #include <math.h> #include <stdlib.h> #include <string.h> @@ -98,8 +101,13 @@ void ED_sculpt_force_update(bContext *C) { Object *ob = CTX_data_active_object(C); - if (ob && (ob->mode & OB_MODE_SCULPT)) + if (ob && (ob->mode & OB_MODE_SCULPT)) { multires_force_update(ob); + + /* Set reorder=false so that saving the file doesn't reorder + * the BMesh's elements */ + sculptsession_bm_to_me(ob, FALSE); + } } float *ED_sculpt_get_last_stroke(struct Object *ob) @@ -172,7 +180,8 @@ static int sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob) Mesh *me = (Mesh *)ob->data; MultiresModifierData *mmd = sculpt_multires_active(scene, ob); - if (mmd) return 0; + if (mmd || ob->sculpt->bm) + return 0; /* non-locked shape keys could be handled in the same way as deformed mesh */ if ((ob->shapeflag & OB_SHAPE_LOCK) == 0 && me->key && ob->shapenr) @@ -281,12 +290,130 @@ typedef struct StrokeCache { rcti previous_r; /* previous redraw rectangle */ } StrokeCache; +/************** Access to original unmodified vertex data *************/ + +typedef struct { + BMLog *bm_log; + + SculptUndoNode *unode; + float (*coords)[3]; + short (*normals)[3]; + float *vmasks; + + /* Original coordinate, normal, and mask */ + const float *co; + float mask; + short no[3]; +} SculptOrigVertData; + + +/* Initialize a SculptOrigVertData for accessing original vertex data; + * handles BMesh, mesh, and multires */ +static void sculpt_orig_vert_data_unode_init(SculptOrigVertData *data, + Object *ob, + SculptUndoNode *unode) +{ + SculptSession *ss = ob->sculpt; + BMesh *bm = ss->bm; + + memset(data, 0, sizeof(*data)); + data->unode = unode; + + if (bm) { + data->bm_log = ss->bm_log; + } + else { + data->coords = data->unode->co; + data->normals = data->unode->no; + data->vmasks = data->unode->mask; + } +} + +/* Initialize a SculptOrigVertData for accessing original vertex data; + * handles BMesh, mesh, and multires */ +static void sculpt_orig_vert_data_init(SculptOrigVertData *data, + Object *ob, + PBVHNode *node) +{ + SculptUndoNode *unode; + unode = sculpt_undo_push_node(ob, node, SCULPT_UNDO_COORDS); + sculpt_orig_vert_data_unode_init(data, ob, unode); + +} + +/* Update a SculptOrigVertData for a particular vertex from the PBVH + * iterator */ +static void sculpt_orig_vert_data_update(SculptOrigVertData *orig_data, + PBVHVertexIter *iter) +{ + if (orig_data->unode->type == SCULPT_UNDO_COORDS) { + if (orig_data->coords) { + orig_data->co = orig_data->coords[iter->i]; + } + else { + orig_data->co = BM_log_original_vert_co(orig_data->bm_log, iter->bm_vert); + } + + if (orig_data->normals) { + copy_v3_v3_short(orig_data->no, orig_data->normals[iter->i]); + } + else { + /* TODO: log doesn't store normals yet */ + normal_float_to_short_v3(orig_data->no, iter->bm_vert->no); + } + } + else if (orig_data->unode->type == SCULPT_UNDO_MASK) { + if (orig_data->vmasks) { + orig_data->mask = orig_data->vmasks[iter->i]; + } + else { + orig_data->mask = BM_log_original_mask(orig_data->bm_log, iter->bm_vert); + } + } +} + +/**********************************************************************/ + +/* Returns true if the stroke will use dynamic topology, false + otherwise. + + Factors: some brushes like grab cannot do dynamic topology. + Others, like smooth, are better without. Same goes for alt- + key smoothing. */ +static int sculpt_stroke_dynamic_topology(const SculptSession *ss, + const Brush *brush) +{ + return ((BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) && + + (!ss->cache || (!ss->cache->alt_smooth)) && + + /* Requires mesh restore, which doesn't work with + * dynamic-topology */ + !(brush->flag & BRUSH_ANCHORED) && + !(brush->flag & BRUSH_RESTORE_MESH) && + + (!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, + + /* These brushes could handle dynamic topology, + * but user feedback indicates it's better not + * to */ + SCULPT_TOOL_SMOOTH, + SCULPT_TOOL_MASK))); +} /*** paint mesh ***/ -static void paint_mesh_restore_co(Sculpt *sd, SculptSession *ss) +static void paint_mesh_restore_co(Sculpt *sd, Object *ob) { + SculptSession *ss = ob->sculpt; StrokeCache *cache = ss->cache; + const Brush *brush = paint_brush(&sd->paint); int i; PBVHNode **nodes; @@ -296,31 +423,38 @@ static void paint_mesh_restore_co(Sculpt *sd, SculptSession *ss) (void)sd; /* quied unused warning */ #endif - BLI_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) for (n = 0; n < totnode; n++) { SculptUndoNode *unode; - - unode = sculpt_undo_get_node(nodes[n]); + SculptUndoType type = (brush->sculpt_tool == SCULPT_TOOL_MASK ? + SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS); + + unode = sculpt_undo_push_node(ob, nodes[n], type); if (unode) { PBVHVertexIter vd; + SculptOrigVertData orig_data; - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + sculpt_orig_vert_data_unode_init(&orig_data, ob, unode); + + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { - if (unode->type == SCULPT_UNDO_COORDS) { - copy_v3_v3(vd.co, unode->co[vd.i]); - if (vd.no) copy_v3_v3_short(vd.no, unode->no[vd.i]); - else normal_short_to_float_v3(vd.fno, unode->no[vd.i]); + sculpt_orig_vert_data_update(&orig_data, &vd); + + if (orig_data.unode->type == SCULPT_UNDO_COORDS) { + copy_v3_v3(vd.co, orig_data.co); + if (vd.no) copy_v3_v3_short(vd.no, orig_data.no); + else normal_short_to_float_v3(vd.fno, orig_data.no); } - else if (unode->type == SCULPT_UNDO_MASK) { - *vd.mask = unode->mask[vd.i]; + else if (orig_data.unode->type == SCULPT_UNDO_MASK) { + *vd.mask = orig_data.mask; } if (vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; - BLI_pbvh_node_mark_update(nodes[n]); + BKE_pbvh_node_mark_update(nodes[n]); } } @@ -347,7 +481,7 @@ static int sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d, if (!pbvh) return 0; - BLI_pbvh_redraw_BB(pbvh, bb_min, bb_max); + BKE_pbvh_redraw_BB(pbvh, bb_min, bb_max); /* convert 3D bounding box to screen space */ if (!paint_convert_bb_to_rect(rect, @@ -387,7 +521,7 @@ void sculpt_get_redraw_planes(float planes[4][4], ARegion *ar, /* clear redraw flag from nodes */ if (pbvh) - BLI_pbvh_update(pbvh, PBVH_UpdateRedraw, NULL); + BKE_pbvh_update(pbvh, PBVH_UpdateRedraw, NULL); } /************************ Brush Testing *******************/ @@ -405,7 +539,7 @@ static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test) test->dist = 0.0f; /* just for initialize */ } -static int sculpt_brush_test(SculptBrushTest *test, float co[3]) +static int sculpt_brush_test(SculptBrushTest *test, const float co[3]) { float distsq = len_squared_v3v3(co, test->location); @@ -418,7 +552,7 @@ static int sculpt_brush_test(SculptBrushTest *test, float co[3]) } } -static int sculpt_brush_test_sq(SculptBrushTest *test, float co[3]) +static int sculpt_brush_test_sq(SculptBrushTest *test, const float co[3]) { float distsq = len_squared_v3v3(co, test->location); @@ -734,7 +868,8 @@ static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather) } /* Return a multiplier for brush strength on a particular vertex. */ -static float tex_strength(SculptSession *ss, Brush *br, float point[3], +static float tex_strength(SculptSession *ss, Brush *br, + const float point[3], const float len, const float sculpt_normal[3], const short vno[3], @@ -871,9 +1006,9 @@ static int sculpt_search_sphere_cb(PBVHNode *node, void *data_v) int i; if (data->original) - BLI_pbvh_node_get_original_BB(node, bb_min, bb_max); + BKE_pbvh_node_get_original_BB(node, bb_min, bb_max); else - BLI_pbvh_node_get_BB(node, bb_min, bb_max); + BKE_pbvh_node_get_BB(node, bb_min, bb_max); for (i = 0; i < 3; ++i) { if (bb_min[i] > center[i]) @@ -926,6 +1061,11 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod original = (paint_brush(&sd->paint)->sculpt_tool == SCULPT_TOOL_GRAB ? TRUE : ss->cache->original); + /* In general the original coords are not available with dynamic + * topology */ + if (ss->bm) + original = FALSE; + (void)sd; /* unused w/o openmp */ zero_v3(an); @@ -942,7 +1082,7 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod sculpt_brush_test_init(ss, &test); if (original) { - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_fast(&test, unode->co[vd.i])) { float fno[3]; @@ -951,10 +1091,10 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno); } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } else { - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_fast(&test, vd.co)) { if (vd.no) { @@ -968,7 +1108,7 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod } } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } #pragma omp critical @@ -1210,6 +1350,71 @@ static float neighbor_average_mask(SculptSession *ss, unsigned vert) return vmask[vert]; } +/* Same logic as neighbor_average(), but for bmesh rather than mesh */ +static void bmesh_neighbor_average(float avg[3], BMVert *v) +{ + const int vfcount = BM_vert_face_count(v); + + zero_v3(avg); + + /* Don't modify corner vertices */ + if (vfcount > 1) { + BMIter liter; + BMLoop *l; + int i, total = 0; + + BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { + BMVert *adj_v[3] = {l->prev->v, v, l->next->v}; + + for (i = 0; i < 3; i++) { + if (vfcount != 2 || BM_vert_face_count(adj_v[i]) <= 2) { + add_v3_v3(avg, adj_v[i]->co); + total++; + } + } + } + + if (total > 0) { + mul_v3_fl(avg, 1.0f / total); + return; + } + } + + copy_v3_v3(avg, v->co); +} + +/* Same logic as neighbor_average_mask(), but for bmesh rather than mesh */ +static float bmesh_neighbor_average_mask(BMesh *bm, BMVert *v) +{ + BMIter liter; + BMLoop *l; + float avg = 0; + int i, total = 0; + + BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { + BMVert *adj_v[3] = {l->prev->v, v, l->next->v}; + + for (i = 0; i < 3; i++) { + BMVert *v2 = adj_v[i]; + float *vmask = CustomData_bmesh_get(&bm->vdata, + v2->head.data, + CD_PAINT_MASK); + avg += (*vmask); + total++; + } + } + + if (total > 0) { + return avg / (float)total; + } + else { + float *vmask = CustomData_bmesh_get(&bm->vdata, + v->head.data, + CD_PAINT_MASK); + return (*vmask); + } +} + static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, float bstrength, int smooth_mask) { Brush *brush = paint_brush(&sd->paint); @@ -1220,7 +1425,7 @@ static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test(&test, vd.co)) { const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist, @@ -1248,7 +1453,48 @@ static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; +} + +static void do_bmesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, float bstrength, int smooth_mask) +{ + Brush *brush = paint_brush(&sd->paint); + PBVHVertexIter vd; + SculptBrushTest test; + + CLAMP(bstrength, 0.0f, 1.0f); + + sculpt_brush_test_init(ss, &test); + + BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) + { + if (sculpt_brush_test(&test, vd.co)) { + const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist, + ss->cache->view_normal, vd.no, vd.fno, + smooth_mask ? 0 : *vd.mask); + if (smooth_mask) { + float val = bmesh_neighbor_average_mask(ss->bm, vd.bm_vert) - *vd.mask; + val *= fade * bstrength; + *vd.mask += val; + CLAMP(*vd.mask, 0, 1); + } + else { + float avg[3], val[3]; + + bmesh_neighbor_average(avg, vd.bm_vert); + sub_v3_v3v3(val, avg, vd.co); + mul_v3_fl(val, fade); + + add_v3_v3(val, vd.co); + + sculpt_clip(sd, ss, vd.co, val); + } + + if (vd.mvert) + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; } static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, @@ -1269,9 +1515,9 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no CLAMP(bstrength, 0.0f, 1.0f); - BLI_pbvh_node_get_grids(ss->pbvh, node, &grid_indices, &totgrid, + BKE_pbvh_node_get_grids(ss->pbvh, node, &grid_indices, &totgrid, NULL, &gridsize, &griddata, &gridadj); - BLI_pbvh_get_grid_key(ss->pbvh, &key); + BKE_pbvh_get_grid_key(ss->pbvh, &key); thread_num = 0; #ifdef _OPENMP @@ -1405,7 +1651,7 @@ static void smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, SculptSession *ss = ob->sculpt; const int max_iterations = 4; const float fract = 1.0f / max_iterations; - PBVHType type = BLI_pbvh_type(ss->pbvh); + PBVHType type = BKE_pbvh_type(ss->pbvh); int iteration, n, count; float last; @@ -1433,6 +1679,9 @@ static void smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, do_mesh_smooth_brush(sd, ss, nodes[n], strength, smooth_mask); break; + case PBVH_BMESH: + do_bmesh_smooth_brush(sd, ss, nodes[n], strength, smooth_mask); + break; } } @@ -1462,7 +1711,7 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test(&test, vd.co)) { float fade = tex_strength(ss, brush, vd.co, test.dist, @@ -1474,7 +1723,7 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot if (vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } } @@ -1514,11 +1763,11 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) SculptBrushTest test; float (*proxy)[3]; - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test(&test, vd.co)) { /* offset vertex */ @@ -1532,7 +1781,7 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -1570,11 +1819,11 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod SculptBrushTest test; float (*proxy)[3]; - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test(&test, vd.co)) { /* offset vertex */ @@ -1597,7 +1846,7 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -1614,11 +1863,11 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode SculptBrushTest test; float (*proxy)[3]; - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test(&test, vd.co)) { float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist, @@ -1633,7 +1882,7 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -1659,26 +1908,27 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; - SculptUndoNode *unode; SculptBrushTest test; - float (*origco)[3]; - short (*origno)[3]; + SculptOrigVertData orig_data; float (*proxy)[3]; - unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS); - origco = unode->co; - origno = unode->no; + sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]); - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test(&test, origco[vd.i])) { - const float fade = bstrength * tex_strength(ss, brush, origco[vd.i], test.dist, - ss->cache->sculpt_normal_symm, origno[vd.i], - NULL, vd.mask ? *vd.mask : 0.0f); + sculpt_orig_vert_data_update(&orig_data, &vd); + + if (sculpt_brush_test(&test, orig_data.co)) { + const float fade = bstrength * tex_strength(ss, brush, + orig_data.co, + test.dist, + ss->cache->sculpt_normal_symm, + orig_data.no, + NULL, vd.mask ? *vd.mask : 0.0f); mul_v3_v3fl(proxy[vd.i], grab_delta, fade); @@ -1686,7 +1936,7 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -1710,11 +1960,11 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode SculptBrushTest test; float (*proxy)[3]; - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test(&test, vd.co)) { const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist, @@ -1727,7 +1977,7 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -1759,11 +2009,11 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to SculptBrushTest test; float (*proxy)[3]; - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test(&test, vd.co)) { const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist, @@ -1776,7 +2026,7 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -1797,26 +2047,27 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; - SculptUndoNode *unode; SculptBrushTest test; - float (*origco)[3]; - short (*origno)[3]; + SculptOrigVertData orig_data; float (*proxy)[3]; - unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS); - origco = unode->co; - origno = unode->no; + sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]); - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test(&test, origco[vd.i])) { - const float fade = bstrength * tex_strength(ss, brush, origco[vd.i], test.dist, + sculpt_orig_vert_data_update(&orig_data, &vd); + + if (sculpt_brush_test(&test, orig_data.co)) { + const float fade = bstrength * tex_strength(ss, brush, + orig_data.co, + test.dist, ss->cache->sculpt_normal_symm, - origno[vd.i], NULL, vd.mask ? *vd.mask : 0.0f); + orig_data.no, + NULL, vd.mask ? *vd.mask : 0.0f); mul_v3_v3fl(proxy[vd.i], cono, fade); @@ -1824,7 +2075,7 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -1850,36 +2101,37 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; - SculptUndoNode *unode; SculptBrushTest test; - float (*origco)[3]; - short (*origno)[3]; + SculptOrigVertData orig_data; float (*proxy)[3]; - unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS); - origco = unode->co; - origno = unode->no; + sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]); - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test(&test, origco[vd.i])) { - const float fade = bstrength * tex_strength(ss, brush, origco[vd.i], test.dist, + sculpt_orig_vert_data_update(&orig_data, &vd); + + if (sculpt_brush_test(&test, orig_data.co)) { + const float fade = bstrength * tex_strength(ss, brush, + orig_data.co, + test.dist, ss->cache->sculpt_normal_symm, - origno[vd.i], NULL, vd.mask ? *vd.mask : 0.0f); + orig_data.no, + NULL, vd.mask ? *vd.mask : 0.0f); - mul_v3_m4v3(proxy[vd.i], m, origco[vd.i]); - sub_v3_v3(proxy[vd.i], origco[vd.i]); + mul_v3_m4v3(proxy[vd.i], m, orig_data.co); + sub_v3_v3(proxy[vd.i], orig_data.co); mul_v3_fl(proxy[vd.i], fade); if (vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -1901,25 +2153,25 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode for (n = 0; n < totnode; n++) { PBVHVertexIter vd; SculptBrushTest test; - SculptUndoNode *unode; - float (*origco)[3], *layer_disp; + SculptOrigVertData orig_data; + float *layer_disp; /* XXX: layer brush needs conversion to proxy but its more complicated */ - /* proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; */ + /* proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; */ - unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS); - origco = unode->co; - if (!unode->layer_disp) { - #pragma omp critical - unode->layer_disp = MEM_callocN(sizeof(float) * unode->totvert, "layer disp"); - } - - layer_disp = unode->layer_disp; + sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]); + #pragma omp critical + { + layer_disp = BKE_pbvh_node_layer_disp_get(ss->pbvh, nodes[n]); + } + sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test(&test, origco[vd.i])) { + sculpt_orig_vert_data_update(&orig_data, &vd); + + if (sculpt_brush_test(&test, orig_data.co)) { const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist, ss->cache->sculpt_normal_symm, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f); @@ -1941,7 +2193,7 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode add_v3_v3(val, ss->layer_co[index]); } else { - add_v3_v3(val, origco[vd.i]); + add_v3_v3(val, orig_data.co); } sculpt_clip(sd, ss, vd.co, val); @@ -1950,7 +2202,7 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -1967,11 +2219,11 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno SculptBrushTest test; float (*proxy)[3]; - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test(&test, vd.co)) { const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist, @@ -1989,7 +2241,7 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -2016,24 +2268,24 @@ static void calc_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int to sculpt_brush_test_init(ss, &test); if (ss->cache->original) { - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_fast(&test, unode->co[vd.i])) { add_v3_v3(private_fc, unode->co[vd.i]); private_count++; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } else { - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_fast(&test, vd.co)) { add_v3_v3(private_fc, vd.co); private_count++; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } #pragma omp critical @@ -2082,8 +2334,8 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob, unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS); sculpt_brush_test_init(ss, &test); - if (ss->cache->original) { - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + if (ss->cache->original && unode->co) { + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_fast(&test, unode->co[vd.i])) { /* for area normal */ @@ -2097,10 +2349,10 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob, private_count++; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } else { - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_fast(&test, vd.co)) { /* for area normal */ @@ -2119,7 +2371,7 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob, private_count++; } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } #pragma omp critical @@ -2301,11 +2553,11 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno SculptBrushTest test; float (*proxy)[3]; - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_sq(&test, vd.co)) { float intr[3]; @@ -2326,7 +2578,7 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno } } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -2373,11 +2625,11 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) SculptBrushTest test; float (*proxy)[3]; - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_sq(&test, vd.co)) { if (plane_point_side_flip(vd.co, an, fc, flip)) { @@ -2401,7 +2653,7 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) } } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -2475,11 +2727,11 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t SculptBrushTest test; float (*proxy)[3]; - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_cube(&test, vd.co, mat)) { if (plane_point_side_flip(vd.co, sn, fc, flip)) { @@ -2503,7 +2755,7 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t } } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -2539,11 +2791,11 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) SculptBrushTest test; float (*proxy)[3]; - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_sq(&test, vd.co)) { if (plane_point_side(vd.co, an, fc)) { @@ -2567,7 +2819,7 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) } } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -2603,11 +2855,11 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod SculptBrushTest test; float (*proxy)[3]; - proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_sq(&test, vd.co)) { if (!plane_point_side(vd.co, an, fc)) { @@ -2631,7 +2883,7 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod } } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } } @@ -2688,6 +2940,65 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3]) BKE_key_convert_from_vertcos(ob, kb, vertCos); } +/* Note: we do the topology update before any brush actions to avoid + * issues with the proxies. The size of the proxy can't change, so + * topology must be updated first. */ +static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush) +{ + SculptSession *ss = ob->sculpt; + SculptSearchSphereData data; + PBVHNode **nodes = NULL; + float radius; + int n, totnode; + + /* Build a list of all nodes that are potentially within the + * brush's area of influence */ + data.ss = ss; + data.sd = sd; + + 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); + + 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) { + PBVHTopologyUpdateMode mode = PBVH_Subdivide; + + if ((sd->flags & SCULPT_DYNTOPO_COLLAPSE) || + (brush->sculpt_tool == SCULPT_TOOL_SIMPLIFY)) + { + mode |= PBVH_Collapse; + } + + for (n = 0; n < totnode; n++) { + sculpt_undo_push_node(ob, nodes[n], + brush->sculpt_tool == SCULPT_TOOL_MASK ? + SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS); + BKE_pbvh_node_mark_update(nodes[n]); + + if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { + BKE_pbvh_node_mark_topology_update(nodes[n]); + BKE_pbvh_bmesh_node_save_orig(nodes[n]); + } + } + + if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { + BKE_pbvh_bmesh_update_topology(ss->pbvh, mode, + ss->cache->location, + ss->cache->radius); + } + + MEM_freeN(nodes); + } +} + static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush) { SculptSession *ss = ob->sculpt; @@ -2704,7 +3015,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush) SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB, SCULPT_TOOL_LAYER); - BLI_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode); + 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) { @@ -2713,7 +3024,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush) sculpt_undo_push_node(ob, nodes[n], brush->sculpt_tool == SCULPT_TOOL_MASK ? SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS); - BLI_pbvh_node_mark_update(nodes[n]); + BKE_pbvh_node_mark_update(nodes[n]); } if (brush_needs_sculpt_normal(brush)) @@ -2821,7 +3132,7 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob) PBVHNode **nodes; int totnode, n; - BLI_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode); + BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode); if (!ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER)) { /* these brushes start from original coordinates */ @@ -2835,18 +3146,25 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob) int proxy_count; float (*orco)[3]; - if (use_orco) + if (use_orco && !ss->bm) orco = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS)->co; - BLI_pbvh_node_get_proxies(nodes[n], &proxies, &proxy_count); + BKE_pbvh_node_get_proxies(nodes[n], &proxies, &proxy_count); - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { float val[3]; int p; - if (use_orco) - copy_v3_v3(val, orco[vd.i]); + if (use_orco) { + if (ss->bm) { + copy_v3_v3(val, + BM_log_original_vert_co(ss->bm_log, + vd.bm_vert)); + } + else + copy_v3_v3(val, orco[vd.i]); + } else copy_v3_v3(val, vd.co); @@ -2858,9 +3176,9 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob) if (ss->modifiers_active) sculpt_flush_pbvhvert_deform(ob, &vd); } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; - BLI_pbvh_node_free_proxies(nodes[n]); + BKE_pbvh_node_free_proxies(nodes[n]); } } @@ -2877,7 +3195,7 @@ static void sculpt_update_keyblock(Object *ob) /* Keyblock update happens after handling deformation caused by modifiers, * so ss->orig_cos would be updated with new stroke */ if (ss->orig_cos) vertCos = ss->orig_cos; - else vertCos = BLI_pbvh_get_vertCos(ss->pbvh); + else vertCos = BKE_pbvh_get_vertCos(ss->pbvh); if (vertCos) { sculpt_vertcos_to_key(ob, ss->kb, vertCos); @@ -2905,13 +3223,13 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob) if (ss->kb) vertCos = MEM_callocN(sizeof(*vertCos) * me->totvert, "flushStrokeDeofrm keyVerts"); - BLI_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP) for (n = 0; n < totnode; n++) { PBVHVertexIter vd; - BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) + BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { sculpt_flush_pbvhvert_deform(ob, &vd); @@ -2920,7 +3238,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob) copy_v3_v3(vertCos[index], ss->orig_cos[index]); } } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } if (vertCos) { @@ -2978,7 +3296,10 @@ static void calc_brushdata_symm(Sculpt *sd, StrokeCache *cache, const char symm, mul_m4_v3(cache->symm_rot_mat, cache->grab_delta_symmetry); } +typedef void (*BrushActionFunc)(Sculpt *sd, Object *ob, Brush *brush); + static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush, + BrushActionFunc action, const char symm, const int axis, const float feather) { @@ -2989,7 +3310,7 @@ static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush, const float angle = 2 * M_PI * i / sd->radial_symm[axis - 'X']; ss->cache->radial_symmetry_pass = i; calc_brushdata_symm(sd, ss->cache, symm, axis, angle, feather); - do_brush_action(sd, ob, brush); + action(sd, ob, brush); } } @@ -3006,7 +3327,8 @@ static void sculpt_fix_noise_tear(Sculpt *sd, Object *ob) multires_stitch_grids(ob); } -static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob) +static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob, + BrushActionFunc action) { Brush *brush = paint_brush(&sd->paint); SculptSession *ss = ob->sculpt; @@ -3017,7 +3339,6 @@ 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->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 */ @@ -3027,23 +3348,13 @@ static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob) cache->radial_symmetry_pass = 0; calc_brushdata_symm(sd, cache, i, 0, 0, feather); - do_brush_action(sd, ob, brush); + action(sd, ob, brush); - do_radial_symmetry(sd, ob, brush, i, 'X', feather); - do_radial_symmetry(sd, ob, brush, i, 'Y', feather); - do_radial_symmetry(sd, ob, brush, i, 'Z', feather); + do_radial_symmetry(sd, ob, brush, action, i, 'X', feather); + do_radial_symmetry(sd, ob, brush, action, i, 'Y', feather); + do_radial_symmetry(sd, ob, brush, action, i, 'Z', feather); } } - - sculpt_combine_proxies(sd, ob); - - /* hack to fix noise texture tearing mesh */ - sculpt_fix_noise_tear(sd, ob); - - if (ss->modifiers_active) - sculpt_flush_stroke_deform(sd, ob); - - cache->first_time = 0; } static void sculpt_update_tex(const Scene *scene, Sculpt *sd, SculptSession *ss) @@ -3142,7 +3453,7 @@ void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, ss->orig_cos = (ss->kb) ? BKE_key_convert_to_vertcos(ob, ss->kb) : mesh_getVertexCos(me, NULL); crazyspace_build_sculpt(scene, ob, &ss->deform_imats, &ss->deform_cos); - BLI_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos); + BKE_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos); for (a = 0; a < me->totvert; ++a) { invert_m3(ss->deform_imats[a]); @@ -3152,12 +3463,12 @@ void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, else free_sculptsession_deformMats(ss); /* if pbvh is deformed, key block is already applied to it */ - if (ss->kb && !BLI_pbvh_isDeformed(ss->pbvh)) { + if (ss->kb && !BKE_pbvh_isDeformed(ss->pbvh)) { float (*vertCos)[3] = BKE_key_convert_to_vertcos(ob, ss->kb); if (vertCos) { /* apply shape keys coordinates to PBVH */ - BLI_pbvh_apply_vertCos(ss->pbvh, vertCos); + BKE_pbvh_apply_vertCos(ss->pbvh, vertCos); MEM_freeN(vertCos); } } @@ -3220,6 +3531,8 @@ static const char *sculpt_tool_name(Sculpt *sd) return "Rotate Brush"; case SCULPT_TOOL_MASK: return "Mask Brush"; + case SCULPT_TOOL_SIMPLIFY: + return "Simplify Brush"; } return "Sculpting"; @@ -3291,7 +3604,7 @@ static void sculpt_omp_start(Sculpt *sd, SculptSession *ss) if (ss->multires) { int i, gridsize, array_mem_size; - BLI_pbvh_node_get_grids(ss->pbvh, NULL, NULL, NULL, NULL, + BKE_pbvh_node_get_grids(ss->pbvh, NULL, NULL, NULL, NULL, &gridsize, NULL, NULL); array_mem_size = cache->num_threads * sizeof(void *); @@ -3406,8 +3719,9 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio ED_view3d_global_to_vector(cache->vc->rv3d, cache->vc->rv3d->twmat[3], cache->true_view_normal); /* Initialize layer brush displacements and persistent coords */ if (brush->sculpt_tool == SCULPT_TOOL_LAYER) { - /* not supported yet for multires */ - if (!ss->multires && !ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) { + /* not supported yet for multires or dynamic topology */ + if (!ss->multires && !ss->bm && !ss->layer_co && + (brush->flag & BRUSH_PERSISTENT)) { if (!ss->layer_co) ss->layer_co = MEM_mallocN(sizeof(float) * 3 * ss->totvert, "sculpt mesh vertices copy"); @@ -3721,17 +4035,26 @@ typedef struct { static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin) { - if (BLI_pbvh_node_get_tmin(node) < *tmin) { + if (BKE_pbvh_node_get_tmin(node) < *tmin) { SculptRaycastData *srd = data_v; float (*origco)[3] = NULL; + int use_origco = FALSE; if (srd->original && srd->ss->cache) { - /* intersect with coordinates from before we started stroke */ - SculptUndoNode *unode = sculpt_undo_get_node(node); - origco = (unode) ? unode->co : NULL; + if (BKE_pbvh_type(srd->ss->pbvh) == PBVH_BMESH) { + use_origco = TRUE; + } + else { + /* intersect with coordinates from before we started stroke */ + SculptUndoNode *unode = sculpt_undo_get_node(node); + origco = (unode) ? unode->co : NULL; + use_origco = origco ? TRUE : FALSE; + } } - if (BLI_pbvh_node_raycast(srd->ss->pbvh, node, origco, srd->ray_start, srd->ray_normal, &srd->dist)) { + if (BKE_pbvh_node_raycast(srd->ss->pbvh, node, origco, use_origco, + srd->ray_start, srd->ray_normal, &srd->dist)) + { srd->hit = 1; *tmin = srd->dist; } @@ -3780,7 +4103,7 @@ int sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2]) srd.dist = dist; srd.hit = 0; srd.original = (cache) ? cache->original : 0; - BLI_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd, + BKE_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd, ray_start, ray_normal, srd.original); copy_v3_v3(out, ray_normal); @@ -3829,8 +4152,9 @@ static int sculpt_brush_stroke_init(bContext *C, wmOperator *op) return 1; } -static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss) +static void sculpt_restore_mesh(Sculpt *sd, Object *ob) { + SculptSession *ss = ob->sculpt; Brush *brush = paint_brush(&sd->paint); /* Restore the mesh before continuing with anchored stroke */ @@ -3839,7 +4163,7 @@ static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss) BKE_brush_use_size_pressure(ss->cache->vc->scene, brush)) || (brush->flag & BRUSH_RESTORE_MESH)) { - paint_mesh_restore_co(sd, ss); + paint_mesh_restore_co(sd, ob); } } @@ -3862,7 +4186,7 @@ static void sculpt_flush_update(bContext *C) else { rcti r; - BLI_pbvh_update(ss->pbvh, PBVH_UpdateBB, NULL); + BKE_pbvh_update(ss->pbvh, PBVH_UpdateBB, NULL); if (sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r)) { if (ss->cache) ss->cache->previous_r = r; @@ -3917,11 +4241,33 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, P Sculpt *sd = CTX_data_tool_settings(C)->sculpt; Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; + const Brush *brush = paint_brush(&sd->paint); sculpt_stroke_modifiers_check(C, ob); sculpt_update_cache_variants(C, sd, ob, stroke, itemptr); - sculpt_restore_mesh(sd, ss); - do_symmetrical_brush_actions(sd, ob); + sculpt_restore_mesh(sd, ob); + + BKE_pbvh_bmesh_detail_size_set(ss->pbvh, + (ss->cache->radius / + (float)ss->cache->pixel_radius) * + (float)sd->detail_size); + + if (sculpt_stroke_dynamic_topology(ss, brush)) { + do_symmetrical_brush_actions(sd, ob, sculpt_topology_update); + } + + if (paint_brush(&sd->paint)->sculpt_tool != SCULPT_TOOL_SIMPLIFY) + do_symmetrical_brush_actions(sd, ob, do_brush_action); + + sculpt_combine_proxies(sd, ob); + + /* hack to fix noise texture tearing mesh */ + sculpt_fix_noise_tear(sd, ob); + + if (ss->modifiers_active) + sculpt_flush_stroke_deform(sd, ob); + + ss->cache->first_time = FALSE; /* Cleanup */ sculpt_flush_update(C); @@ -3980,7 +4326,10 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str sculpt_undo_push_end(); - BLI_pbvh_update(ss->pbvh, PBVH_UpdateOriginalBB, NULL); + BKE_pbvh_update(ss->pbvh, PBVH_UpdateOriginalBB, NULL); + + if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) + BKE_pbvh_bmesh_after_stroke(ss->pbvh); /* optimization: if there is locked key and active modifiers present in */ /* the stack, keyblock is updating at each step. otherwise we could update */ @@ -4055,7 +4404,7 @@ static int sculpt_brush_stroke_cancel(bContext *C, wmOperator *op) Sculpt *sd = CTX_data_tool_settings(C)->sculpt; if (ss->cache) { - paint_mesh_restore_co(sd, ss); + paint_mesh_restore_co(sd, ob); } paint_stroke_cancel(C, op); @@ -4137,6 +4486,266 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/************************** Dynamic Topology **************************/ + +static void sculpt_dynamic_topology_triangulate(BMesh *bm) +{ + BMO_op_callf(bm, BMO_FLAG_DEFAULTS, "triangulate faces=%af"); +} + +void sculpt_pbvh_clear(Object *ob) +{ + SculptSession *ss = ob->sculpt; + DerivedMesh *dm = ob->derivedFinal; + + /* Clear out any existing DM and PBVH */ + if (ss->pbvh) + BKE_pbvh_free(ss->pbvh); + ss->pbvh = NULL; + if (dm) + dm->getPBVH(NULL, dm); + BKE_object_free_display(ob); +} + +void sculpt_update_after_dynamic_topology_toggle(bContext *C) +{ + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + Sculpt *sd = scene->toolsettings->sculpt; + + /* Create the PBVH */ + sculpt_update_mesh_elements(scene, sd, ob, FALSE, FALSE); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); +} + +void sculpt_dynamic_topology_enable(bContext *C) +{ + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; + Mesh *me = ob->data; + + sculpt_pbvh_clear(ob); + + ss->bm_smooth_shading = (scene->toolsettings->sculpt->flags & + SCULPT_DYNTOPO_SMOOTH_SHADING); + + /* Create triangles-only BMesh */ + ss->bm = BM_mesh_create(&bm_mesh_allocsize_default); + + BM_mesh_bm_from_me(ss->bm, me, TRUE, ob->shapenr); + sculpt_dynamic_topology_triangulate(ss->bm); + BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK); + BM_mesh_normals_update(ss->bm, TRUE); + + /* Enable dynamic topology */ + me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY; + + /* Enable logging for undo/redo */ + ss->bm_log = BM_log_create(ss->bm); + + /* Refresh */ + sculpt_update_after_dynamic_topology_toggle(C); +} + +/* Free the sculpt BMesh and BMLog + * + * If 'unode' is given, the BMesh's data is copied out to the unode + * before the BMesh is deleted so that it can be restored from */ +void sculpt_dynamic_topology_disable(bContext *C, + SculptUndoNode *unode) +{ + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; + Mesh *me = ob->data; + + sculpt_pbvh_clear(ob); + + if (unode) { + /* Free all existing custom data */ + CustomData_free(&me->vdata, me->totvert); + CustomData_free(&me->edata, me->totedge); + CustomData_free(&me->fdata, me->totface); + CustomData_free(&me->ldata, me->totloop); + CustomData_free(&me->pdata, me->totpoly); + + /* Copy over stored custom data */ + me->totvert = unode->bm_enter_totvert; + me->totloop = unode->bm_enter_totloop; + me->totpoly = unode->bm_enter_totpoly; + me->totedge = unode->bm_enter_totedge; + me->totface = 0; + CustomData_copy(&unode->bm_enter_vdata, &me->vdata, CD_MASK_MESH, + CD_DUPLICATE, unode->bm_enter_totvert); + CustomData_copy(&unode->bm_enter_edata, &me->edata, CD_MASK_MESH, + CD_DUPLICATE, unode->bm_enter_totedge); + CustomData_copy(&unode->bm_enter_ldata, &me->ldata, CD_MASK_MESH, + CD_DUPLICATE, unode->bm_enter_totloop); + CustomData_copy(&unode->bm_enter_pdata, &me->pdata, CD_MASK_MESH, + CD_DUPLICATE, unode->bm_enter_totpoly); + + mesh_update_customdata_pointers(me, FALSE); + } else { + sculptsession_bm_to_me(ob, TRUE); + } + + BM_mesh_free(ss->bm); + + /* Clear data */ + me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY; + ss->bm = NULL; + BM_log_free(ss->bm_log); + ss->bm_log = NULL; + + /* Refresh */ + sculpt_update_after_dynamic_topology_toggle(C); +} + +static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; + + if (ss->bm) { + sculpt_undo_push_begin("Dynamic topology disable"); + sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_END); + sculpt_dynamic_topology_disable(C, NULL); + } + else { + sculpt_undo_push_begin("Dynamic topology enable"); + sculpt_dynamic_topology_enable(C); + sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN); + } + sculpt_undo_push_end(); + + return OPERATOR_FINISHED; +} + +static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, + wmEvent *UNUSED(event)) +{ + Object *ob = CTX_data_active_object(C); + Mesh *me = ob->data; + SculptSession *ss = ob->sculpt; + const char *msg = "Dynamic-topology sculpting will not preserve" + "vertex colors, UVs, or other customdata"; + + if (!ss->bm) { + int i; + + 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) && + (CustomData_has_layer(&me->vdata, i) || + CustomData_has_layer(&me->edata, i) || + CustomData_has_layer(&me->fdata, i))) { + /* The mesh has customdata that will be lost, let the + * user confirm this is OK */ + return WM_operator_confirm_message(C, op, msg); + } + } + } + + return sculpt_dynamic_topology_toggle_exec(C, op); +} + +static void SCULPT_OT_dynamic_topology_toggle(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Dynamic Topology Toggle"; + ot->idname = "SCULPT_OT_dynamic_topology_toggle"; + ot->description = "Dynamic topology alters the mesh topology while sculpting"; + + /* api callbacks */ + ot->invoke = sculpt_dynamic_topology_toggle_invoke; + ot->exec = sculpt_dynamic_topology_toggle_exec; + ot->poll = sculpt_mode_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/************************* SCULPT_OT_optimize *************************/ + +static int sculpt_optimize_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = CTX_data_active_object(C); + + sculpt_pbvh_clear(ob); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + return OPERATOR_FINISHED; +} + +static int sculpt_and_dynamic_topology_poll(bContext *C) +{ + Object *ob = CTX_data_active_object(C); + + return sculpt_mode_poll(C) && ob->sculpt->bm; +} + +/* The BVH gets less optimal more quickly with dynamic topology than + * regular sculpting. There is no doubt more clever stuff we can do to + * optimize it on the fly, but for now this gives the user a nicer way + * to recalculate it than toggling modes. */ +static void SCULPT_OT_optimize(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Optimize"; + ot->idname = "SCULPT_OT_optimize"; + ot->description = "Recalculate the sculpt BVH to improve performance"; + + /* api callbacks */ + ot->exec = sculpt_optimize_exec; + ot->poll = sculpt_and_dynamic_topology_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/********************* Dynamic topology symmetrize ********************/ + +static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = CTX_data_active_object(C); + const Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + SculptSession *ss = ob->sculpt; + + /* To simplify undo for symmetrize, all BMesh elements are logged + * as deleted, then after symmetrize operation all BMesh elements + * are logged as added (as opposed to attempting to store just the + * parts that symmetrize modifies) */ + sculpt_undo_push_begin("Dynamic topology symmetrize"); + sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE); + BM_log_before_all_removed(ss->bm, ss->bm_log); + + /* Symmetrize and re-triangulate */ + BMO_op_callf(ss->bm, BMO_FLAG_DEFAULTS, + "symmetrize input=%avef direction=%i", + sd->symmetrize_direction); + sculpt_dynamic_topology_triangulate(ss->bm); + + /* Finish undo */ + BM_log_all_added(ss->bm, ss->bm_log); + sculpt_undo_push_end(); + + /* Redraw */ + sculpt_pbvh_clear(ob); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + return OPERATOR_FINISHED; +} + +static void SCULPT_OT_symmetrize(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Symmetrize"; + ot->idname = "SCULPT_OT_symmetrize"; + + /* api callbacks */ + ot->exec = sculpt_symmetrize_exec; + ot->poll = sculpt_and_dynamic_topology_poll; +} + /**** Toggle operator for turning sculpt mode on or off ****/ static void sculpt_init_session(Scene *scene, Object *ob) @@ -4222,6 +4831,7 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op)) Scene *scene = CTX_data_scene(C); ToolSettings *ts = CTX_data_tool_settings(C); Object *ob = CTX_data_active_object(C); + Mesh *me = ob->data; MultiresModifierData *mmd = sculpt_multires_active(scene, ob); int flush_recalc = 0; @@ -4234,9 +4844,16 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op)) if (mmd) multires_force_update(ob); - if (flush_recalc) + if (flush_recalc || (ob->sculpt && ob->sculpt->bm)) DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) { + /* Dynamic topology must be disabled before exiting sculpt + * mode to ensure the undo stack stays in a consistent + * state */ + sculpt_dynamic_topology_toggle_exec(C, NULL); + } + /* Leave sculptmode */ ob->mode &= ~OB_MODE_SCULPT; @@ -4257,6 +4874,9 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op)) ts->sculpt->flags |= SCULPT_SYMM_X; } + if (!ts->sculpt->detail_size) + ts->sculpt->detail_size = 30; + /* Create sculpt mode session data */ if (ob->sculpt) free_sculptsession(ob); @@ -4271,7 +4891,7 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op)) } BKE_paint_init(&ts->sculpt->paint, PAINT_CURSOR_SCULPT); - + paint_cursor_start(C, sculpt_poll); } @@ -4299,4 +4919,7 @@ void ED_operatortypes_sculpt(void) WM_operatortype_append(SCULPT_OT_brush_stroke); WM_operatortype_append(SCULPT_OT_sculptmode_toggle); WM_operatortype_append(SCULPT_OT_set_persistent_base); + WM_operatortype_append(SCULPT_OT_dynamic_topology_toggle); + WM_operatortype_append(SCULPT_OT_optimize); + WM_operatortype_append(SCULPT_OT_symmetrize); } diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 44068122b89..e56962a3964 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -49,6 +49,7 @@ struct Object; struct Scene; struct Sculpt; struct SculptStroke; +struct SculptUndoNode; /* Interface */ struct MultiresModifierData *sculpt_multires_active(struct Scene *scene, struct Object *ob); @@ -67,12 +68,22 @@ void free_sculptsession_deformMats(struct SculptSession *ss); /* Stroke */ int sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2]); +/* Dynamic topology */ +void sculpt_pbvh_clear(Object *ob); +void sculpt_update_after_dynamic_topology_toggle(bContext *C); +void sculpt_dynamic_topology_enable(struct bContext *C); +void sculpt_dynamic_topology_disable(struct bContext *C, + struct SculptUndoNode *unode); + /* Undo */ typedef enum { SCULPT_UNDO_COORDS, SCULPT_UNDO_HIDDEN, - SCULPT_UNDO_MASK + SCULPT_UNDO_MASK, + SCULPT_UNDO_DYNTOPO_BEGIN, + SCULPT_UNDO_DYNTOPO_END, + SCULPT_UNDO_DYNTOPO_SYMMETRIZE, } SculptUndoType; typedef struct SculptUndoNode { @@ -101,8 +112,17 @@ typedef struct SculptUndoNode { int *grids; /* to restore into right location */ BLI_bitmap *grid_hidden; - /* layer brush */ - float *layer_disp; + /* bmesh */ + struct BMLogEntry *bm_entry; + int applied; + CustomData bm_enter_vdata; + CustomData bm_enter_edata; + CustomData bm_enter_ldata; + CustomData bm_enter_pdata; + int bm_enter_totvert; + int bm_enter_totedge; + int bm_enter_totloop; + int bm_enter_totpoly; /* shape keys */ char shapeName[sizeof(((KeyBlock *)0))->name]; diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 1b3fd24ae22..c828e8c8651 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -65,6 +65,7 @@ #include "GPU_buffers.h" #include "ED_sculpt.h" +#include "bmesh.h" #include "paint_intern.h" #include "sculpt_intern.h" @@ -72,10 +73,10 @@ static void update_cb(PBVHNode *node, void *rebuild) { - BLI_pbvh_node_mark_update(node); + BKE_pbvh_node_mark_update(node); if (*((int *)rebuild)) - BLI_pbvh_node_mark_rebuild_draw(node); - BLI_pbvh_node_fully_hidden_set(node, 0); + BKE_pbvh_node_mark_rebuild_draw(node); + BKE_pbvh_node_fully_hidden_set(node, 0); } static void sculpt_undo_restore_deformed(const SculptSession *ss, @@ -142,7 +143,7 @@ static int sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoNo /* pbvh uses it's own mvert array, so coords should be */ /* propagated to pbvh here */ - BLI_pbvh_apply_vertCos(ss->pbvh, vertCos); + BKE_pbvh_apply_vertCos(ss->pbvh, vertCos); MEM_freeN(vertCos); } @@ -261,6 +262,111 @@ static int sculpt_undo_restore_mask(bContext *C, DerivedMesh *dm, SculptUndoNode return 1; } +static void sculpt_undo_bmesh_restore_generic(SculptUndoNode *unode, + Object *ob, + SculptSession *ss) +{ + if (unode->applied) { + BM_log_undo(ss->bm, ss->bm_log); + unode->applied = FALSE; + } + else { + BM_log_redo(ss->bm, ss->bm_log); + unode->applied = TRUE; + } + + /* A bit lame, but for now just recreate the PBVH. The alternative + * is to store changes to the PBVH in the undo stack. */ + sculpt_pbvh_clear(ob); +} + +/* Create empty sculpt BMesh and enable logging */ +static void sculpt_undo_bmesh_enable(Object *ob, + SculptUndoNode *unode) +{ + SculptSession *ss = ob->sculpt; + Mesh *me = ob->data; + + sculpt_pbvh_clear(ob); + + /* Create empty BMesh and enable logging */ + ss->bm = BM_mesh_create(&bm_mesh_allocsize_default); + BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK); + me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY; + + /* Restore the BMLog using saved entries */ + ss->bm_log = BM_log_from_existing_entries_create(ss->bm, + unode->bm_entry); +} + +static void sculpt_undo_bmesh_restore_begin(bContext *C, + SculptUndoNode *unode, + Object *ob, + SculptSession *ss) +{ + if (unode->applied) { + sculpt_dynamic_topology_disable(C, unode); + unode->applied = FALSE; + } + else { + sculpt_undo_bmesh_enable(ob, unode); + + /* Restore the mesh from the first log entry */ + BM_log_redo(ss->bm, ss->bm_log); + + unode->applied = TRUE; + } +} + +static void sculpt_undo_bmesh_restore_end(bContext *C, + SculptUndoNode *unode, + Object *ob, + SculptSession *ss) +{ + if (unode->applied) { + sculpt_undo_bmesh_enable(ob, unode); + + /* Restore the mesh from the last log entry */ + BM_log_undo(ss->bm, ss->bm_log); + + unode->applied = FALSE; + } + else { + /* Disable dynamic topology sculpting */ + sculpt_dynamic_topology_disable(C, NULL); + unode->applied = TRUE; + } +} + +/* Handle all dynamic-topology updates + * + * Returns TRUE if this was a dynamic-topology undo step, otherwise + * returns FALSE to indicate the non-dyntopo code should run. */ +static int sculpt_undo_bmesh_restore(bContext *C, + SculptUndoNode *unode, + Object *ob, + SculptSession *ss) +{ + switch (unode->type) { + case SCULPT_UNDO_DYNTOPO_BEGIN: + sculpt_undo_bmesh_restore_begin(C, unode, ob, ss); + return TRUE; + + case SCULPT_UNDO_DYNTOPO_END: + sculpt_undo_bmesh_restore_end(C, unode, ob, ss); + return TRUE; + + default: + if (ss->bm_log) { + sculpt_undo_bmesh_restore_generic(unode, ob, ss); + return TRUE; + } + break; + } + + return FALSE; +} + static void sculpt_undo_restore(bContext *C, ListBase *lb) { Scene *scene = CTX_data_scene(C); @@ -289,6 +395,9 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb) /* call _after_ sculpt_update_mesh_elements() which may update 'ob->derivedFinal' */ dm = mesh_get_derived_final(scene, ob, 0); + if (lb->first && sculpt_undo_bmesh_restore(C, lb->first, ob, ss)) + return; + for (unode = lb->first; unode; unode = unode->next) { if (!(strcmp(unode->idname, ob->id.name) == 0)) continue; @@ -306,9 +415,6 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb) continue; } } - else { - continue; - } switch (unode->type) { case SCULPT_UNDO_COORDS: @@ -323,6 +429,12 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb) if (sculpt_undo_restore_mask(C, dm, unode)) update = TRUE; break; + + case SCULPT_UNDO_DYNTOPO_BEGIN: + case SCULPT_UNDO_DYNTOPO_END: + case SCULPT_UNDO_DYNTOPO_SYMMETRIZE: + BLI_assert(!"Dynamic topology should've already been handled"); + break; } } @@ -331,8 +443,8 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb) /* we update all nodes still, should be more clever, but also * needs to work correct when exiting/entering sculpt mode and * the nodes get recreated, though in that case it could do all */ - BLI_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, &rebuild); - BLI_pbvh_update(ss->pbvh, PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw, NULL); + BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, &rebuild); + BKE_pbvh_update(ss->pbvh, PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw, NULL); if ((mmd = sculpt_multires_active(scene, ob))) { if (rebuild) @@ -374,8 +486,6 @@ static void sculpt_undo_free(ListBase *lb) MEM_freeN(unode->index); if (unode->grids) MEM_freeN(unode->grids); - if (unode->layer_disp) - MEM_freeN(unode->layer_disp); if (unode->orig_co) MEM_freeN(unode->orig_co); if (unode->vert_hidden) @@ -389,6 +499,17 @@ static void sculpt_undo_free(ListBase *lb) } if (unode->mask) MEM_freeN(unode->mask); + if (unode->bm_entry) { + BM_log_entry_drop(unode->bm_entry); + } + if (unode->bm_enter_totvert) + CustomData_free(&unode->bm_enter_vdata, unode->bm_enter_totvert); + if (unode->bm_enter_totedge) + CustomData_free(&unode->bm_enter_edata, unode->bm_enter_totedge); + if (unode->bm_enter_totloop) + CustomData_free(&unode->bm_enter_ldata, unode->bm_enter_totloop); + if (unode->bm_enter_totpoly) + CustomData_free(&unode->bm_enter_pdata, unode->bm_enter_totpoly); } } @@ -410,9 +531,9 @@ static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh, BLI_bitmap *grid_hidden; int i, *grid_indices, totgrid; - grid_hidden = BLI_pbvh_grid_hidden(pbvh); + grid_hidden = BKE_pbvh_grid_hidden(pbvh); - BLI_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, + BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, NULL, NULL, NULL, NULL); unode->grid_hidden = MEM_mapallocN(sizeof(BLI_bitmap) * totgrid, @@ -439,11 +560,13 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, unode->type = type; unode->node = node; - BLI_pbvh_node_num_verts(ss->pbvh, node, &totvert, &allvert); - BLI_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid, - &maxgrid, &gridsize, NULL, NULL); + if (node) { + BKE_pbvh_node_num_verts(ss->pbvh, node, &totvert, &allvert); + BKE_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid, + &maxgrid, &gridsize, NULL, NULL); - unode->totvert = totvert; + unode->totvert = totvert; + } /* we will use this while sculpting, is mapalloc slow to access then? */ @@ -468,6 +591,11 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, unode->mask = MEM_mapallocN(sizeof(float) * allvert, "SculptUndoNode.mask"); undo_paint_push_count_alloc(UNDO_PAINT_MESH, (sizeof(float) * sizeof(int)) * allvert); break; + case SCULPT_UNDO_DYNTOPO_BEGIN: + case SCULPT_UNDO_DYNTOPO_END: + case SCULPT_UNDO_DYNTOPO_SYMMETRIZE: + BLI_assert(!"Dynamic topology should've already been handled"); + break; } BLI_addtail(lb, unode); @@ -496,7 +624,7 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode) SculptSession *ss = ob->sculpt; PBVHVertexIter vd; - BLI_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL) + BKE_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL) { copy_v3_v3(unode->co[vd.i], vd.co); if (vd.no) copy_v3_v3_short(unode->no[vd.i], vd.no); @@ -505,7 +633,7 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode) if (ss->modifiers_active) copy_v3_v3(unode->orig_co[vd.i], ss->orig_cos[unode->index[vd.i]]); } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } static void sculpt_undo_store_hidden(Object *ob, SculptUndoNode *unode) @@ -521,8 +649,8 @@ static void sculpt_undo_store_hidden(Object *ob, SculptUndoNode *unode) int *vert_indices, allvert; int i; - BLI_pbvh_node_num_verts(pbvh, node, NULL, &allvert); - BLI_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert); + BKE_pbvh_node_num_verts(pbvh, node, NULL, &allvert); + BKE_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert); for (i = 0; i < allvert; i++) { BLI_BITMAP_MODIFY(unode->vert_hidden, i, mvert[vert_indices[i]].flag & ME_HIDE); @@ -535,11 +663,85 @@ static void sculpt_undo_store_mask(Object *ob, SculptUndoNode *unode) SculptSession *ss = ob->sculpt; PBVHVertexIter vd; - BLI_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL) + BKE_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL) { unode->mask[vd.i] = *vd.mask; } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; +} + +static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, + PBVHNode *node, + SculptUndoType type) +{ + ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_MESH); + SculptUndoNode *unode = lb->first; + SculptSession *ss = ob->sculpt; + PBVHVertexIter vd; + + if (!lb->first) { + unode = MEM_callocN(sizeof(*unode), AT); + + BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname)); + unode->type = type; + unode->applied = TRUE; + + if (type == SCULPT_UNDO_DYNTOPO_END) { + unode->bm_entry = BM_log_entry_add(ss->bm_log); + BM_log_before_all_removed(ss->bm, ss->bm_log); + } + else if (type == SCULPT_UNDO_DYNTOPO_BEGIN) { + Mesh *me = ob->data; + + /* Store a copy of the mesh's current vertices, loops, and + * polys. A full copy like this is needed because entering + * dynamic-topology immediately does topological edits + * (converting polys to triangles) that the BMLog can't + * fully restore from */ + CustomData_copy(&me->vdata, &unode->bm_enter_vdata, CD_MASK_MESH, + CD_DUPLICATE, me->totvert); + CustomData_copy(&me->edata, &unode->bm_enter_edata, CD_MASK_MESH, + CD_DUPLICATE, me->totedge); + CustomData_copy(&me->ldata, &unode->bm_enter_ldata, CD_MASK_MESH, + CD_DUPLICATE, me->totloop); + CustomData_copy(&me->pdata, &unode->bm_enter_pdata, CD_MASK_MESH, + CD_DUPLICATE, me->totpoly); + unode->bm_enter_totvert = me->totvert; + unode->bm_enter_totedge = me->totedge; + unode->bm_enter_totloop = me->totloop; + unode->bm_enter_totpoly = me->totpoly; + + unode->bm_entry = BM_log_entry_add(ss->bm_log); + BM_log_all_added(ss->bm, ss->bm_log); + } + else { + unode->bm_entry = BM_log_entry_add(ss->bm_log); + } + + BLI_addtail(lb, unode); + } + + if (node) { + switch (type) { + case SCULPT_UNDO_COORDS: + case SCULPT_UNDO_HIDDEN: + case SCULPT_UNDO_MASK: + /* Before any vertex values get modified, ensure their + * original positions are logged */ + BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL) { + BM_log_vert_before_modified(ss->bm, ss->bm_log, vd.bm_vert); + } + BKE_pbvh_vertex_iter_end; + break; + + case SCULPT_UNDO_DYNTOPO_BEGIN: + case SCULPT_UNDO_DYNTOPO_END: + case SCULPT_UNDO_DYNTOPO_SYMMETRIZE: + break; + } + } + + return unode; } SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, @@ -551,7 +753,18 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, /* list is manipulated by multiple threads, so we lock */ BLI_lock_thread(LOCK_CUSTOM1); - if ((unode = sculpt_undo_get_node(node))) { + if (ss->bm || + ELEM(type, + SCULPT_UNDO_DYNTOPO_BEGIN, + SCULPT_UNDO_DYNTOPO_END)) + { + /* Dynamic topology stores only one undo node per stroke, + * regardless of the number of PBVH nodes modified */ + unode = sculpt_undo_bmesh_push(ob, node, type); + BLI_unlock_thread(LOCK_CUSTOM1); + return unode; + } + else if ((unode = sculpt_undo_get_node(node))) { BLI_unlock_thread(LOCK_CUSTOM1); return unode; } @@ -564,14 +777,14 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, if (unode->grids) { int totgrid, *grids; - BLI_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid, + BKE_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid, NULL, NULL, NULL, NULL); memcpy(unode->grids, grids, sizeof(int) * totgrid); } else { int *vert_indices, allvert; - BLI_pbvh_node_num_verts(ss->pbvh, node, NULL, &allvert); - BLI_pbvh_node_get_verts(ss->pbvh, node, &vert_indices, NULL); + BKE_pbvh_node_num_verts(ss->pbvh, node, NULL, &allvert); + BKE_pbvh_node_get_verts(ss->pbvh, node, &vert_indices, NULL); memcpy(unode->index, vert_indices, sizeof(int) * unode->totvert); } @@ -585,6 +798,11 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, case SCULPT_UNDO_MASK: sculpt_undo_store_mask(ob, unode); break; + case SCULPT_UNDO_DYNTOPO_BEGIN: + case SCULPT_UNDO_DYNTOPO_END: + case SCULPT_UNDO_DYNTOPO_SYMMETRIZE: + BLI_assert(!"Dynamic topology should've already been handled"); + break; } /* store active shape key */ @@ -612,10 +830,8 @@ void sculpt_undo_push_end(void) unode->no = NULL; } - if (unode->layer_disp) { - MEM_freeN(unode->layer_disp); - unode->layer_disp = NULL; - } + if (unode->node) + BKE_pbvh_node_layer_disp_free(unode->node); } undo_paint_push_end(UNDO_PAINT_MESH); diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c index 9bd7d2a44ca..4b1954c8889 100644 --- a/source/blender/editors/space_action/action_draw.c +++ b/source/blender/editors/space_action/action_draw.c @@ -82,13 +82,7 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar) filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - /* Update max-extent of channels here (taking into account scrollers): - * - this is done to allow the channel list to be scrollable, but must be done here - * to avoid regenerating the list again and/or also because channels list is drawn first - * - offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for - * start of list offset, and the second is as a correction for the scrollers. - */ - height = ((items * ACHANNEL_STEP) + (ACHANNEL_HEIGHT * 2)); + height = ((items * ACHANNEL_STEP) + (ACHANNEL_HEIGHT)); if (height > BLI_rcti_size_y(&v2d->mask)) { /* don't use totrect set, as the width stays the same * (NOTE: this is ok here, the configuration is pretty straightforward) @@ -199,13 +193,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - /* Update max-extent of channels here (taking into account scrollers): - * - this is done to allow the channel list to be scrollable, but must be done here - * to avoid regenerating the list again and/or also because channels list is drawn first - * - offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for - * start of list offset, and the second is as a correction for the scrollers. - */ - height = ((items * ACHANNEL_STEP) + (ACHANNEL_HEIGHT * 2)); + height = ((items * ACHANNEL_STEP) + (ACHANNEL_HEIGHT)); /* don't use totrect set, as the width stays the same * (NOTE: this is ok here, the configuration is pretty straightforward) */ diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index c5f3ccee101..e0ca589c1fb 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -219,6 +219,9 @@ static void action_channel_area_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; + /* ensure the 2d view sync works - main region has bottom scroller */ + ar->v2d.scroll = V2D_SCROLL_BOTTOM; + UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); /* own keymap */ @@ -231,7 +234,6 @@ static void action_channel_area_draw(const bContext *C, ARegion *ar) /* draw entirely, view changes should be handled here */ bAnimContext ac; View2D *v2d = &ar->v2d; - View2DScrollers *scrollers; /* clear and setup matrix */ UI_ThemeClearColor(TH_BACK); @@ -247,10 +249,7 @@ static void action_channel_area_draw(const bContext *C, ARegion *ar) /* reset view matrix */ UI_view2d_view_restore(C); - /* scrollers */ - scrollers = UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY); - UI_view2d_scrollers_draw(C, v2d, scrollers); - UI_view2d_scrollers_free(scrollers); + /* no scrollers here */ } diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c index 77662d8ac13..56a890c714a 100644 --- a/source/blender/editors/space_clip/tracking_ops.c +++ b/source/blender/editors/space_clip/tracking_ops.c @@ -1801,7 +1801,7 @@ static void object_solver_inverted_matrix(Scene *scene, Object *ob, float invmat int found = FALSE; for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); if (!cti) continue; @@ -1832,7 +1832,7 @@ static Object *object_solver_camera(Scene *scene, Object *ob) bConstraint *con; for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); if (!cti) continue; diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index fb438ae45fb..08f01b47b52 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -321,8 +321,7 @@ void file_calc_previews(const bContext *C, ARegion *ar) View2D *v2d = &ar->v2d; ED_fileselect_init_layout(sfile, ar); - /* +SCROLL_HEIGHT is bad hack to work around issue in UI_view2d_totRect_set */ - UI_view2d_totRect_set(v2d, sfile->layout->width, sfile->layout->height + V2D_SCROLL_HEIGHT); + UI_view2d_totRect_set(v2d, sfile->layout->width, sfile->layout->height); } static void file_draw_preview(uiBlock *block, struct direntry *file, int sx, int sy, ImBuf *imb, FileLayout *layout, short dropshadow) diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index fa7c6bd472a..734c0e6c479 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -309,6 +309,12 @@ static void graph_channel_area_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; + /* make sure we keep the hide flags */ + ar->v2d.scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM); + ar->v2d.scroll &= ~(V2D_SCROLL_LEFT | V2D_SCROLL_TOP); /* prevent any noise of past */ + ar->v2d.scroll |= V2D_SCROLL_HORIZONTAL_HIDE; + ar->v2d.scroll |= V2D_SCROLL_VERTICAL_HIDE; + UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); /* own keymap */ diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index d02186e59dd..060a181612b 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -219,7 +219,7 @@ static void preview_cb(ScrArea *sa, struct uiBlock *block) BLI_rcti_translate(disprect, -curarea->winrct.xmin, -curarea->winrct.ymin); calc_image_view(sima, 'p'); -// printf("winrct %d %d %d %d\n", disprect->xmin, disprect->ymin,disprect->xmax, disprect->ymax); +// printf("winrct %d %d %d %d\n", disprect->xmin, disprect->ymin, disprect->xmax, disprect->ymax); /* map to image space coordinates */ mval[0] = disprect->xmin; mval[1] = disprect->ymin; areamouseco_to_ipoco(v2d, mval, &dispf.xmin, &dispf.ymin); @@ -236,7 +236,7 @@ static void preview_cb(ScrArea *sa, struct uiBlock *block) CLAMP(disprect->xmax, 0, winx); CLAMP(disprect->ymin, 0, winy); CLAMP(disprect->ymax, 0, winy); -// printf("drawrct %d %d %d %d\n", disprect->xmin, disprect->ymin,disprect->xmax, disprect->ymax); +// printf("drawrct %d %d %d %d\n", disprect->xmin, disprect->ymin, disprect->xmax, disprect->ymax); } @@ -674,6 +674,24 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char if (ima->source != IMA_SRC_GENERATED) { if (compact == 0) { /* background image view doesnt need these */ + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); + int has_alpha = TRUE; + + if (ibuf) { + int imtype = BKE_ftype_to_imtype(ibuf->ftype); + char valid_channels = BKE_imtype_valid_channels(imtype); + + has_alpha = valid_channels & IMA_CHAN_FLAG_ALPHA; + + BKE_image_release_ibuf(ima, ibuf, NULL); + } + + if (has_alpha) { + col = uiLayoutColumn(layout, FALSE); + uiItemR(col, &imaptr, "use_alpha", 0, NULL, ICON_NONE); + uiItemR(col, &imaptr, "alpha_mode", 0, "Alpha", ICON_NONE); + } + uiItemS(layout); split = uiLayoutSplit(layout, 0.0f, FALSE); @@ -694,10 +712,6 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char row = uiLayoutRow(col, FALSE); uiLayoutSetActive(row, RNA_boolean_get(&imaptr, "use_fields")); uiItemR(row, &imaptr, "field_order", UI_ITEM_R_EXPAND, NULL, ICON_NONE); - - row = uiLayoutRow(layout, FALSE); - uiItemR(row, &imaptr, "use_premultiply", 0, NULL, ICON_NONE); - uiItemR(row, &imaptr, "use_color_unpremultiply", 0, NULL, ICON_NONE); } } @@ -796,6 +810,8 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, int color_man } if (imf->imtype == R_IMF_IMTYPE_JP2) { + uiItemR(col, imfptr, "jpeg2k_codec", 0, NULL, ICON_NONE); + row = uiLayoutRow(col, FALSE); uiItemR(row, imfptr, "use_jpeg2k_cinema_preset", 0, NULL, ICON_NONE); uiItemR(row, imfptr, "use_jpeg2k_cinema_48", 0, NULL, ICON_NONE); diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index d565e6f9e9a..0534b9f4ffd 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -75,13 +75,15 @@ #include "WM_types.h" #include "RE_pipeline.h" +#include "RE_engine.h" #include "image_intern.h" -static void draw_render_info(Scene *scene, Image *ima, ARegion *ar) +static void draw_render_info(Scene *scene, Image *ima, ARegion *ar, float zoomx, float zoomy) { RenderResult *rr; - + Render *re = RE_GetRender(scene->id.name); + rr = BKE_image_acquire_renderresult(scene, ima); if (rr && rr->text) { @@ -89,6 +91,73 @@ static void draw_render_info(Scene *scene, Image *ima, ARegion *ar) } BKE_image_release_renderresult(scene, ima); + + if (re) { + int total_tiles; + rcti *tiles; + + RE_engine_get_current_tiles(re, &total_tiles, &tiles); + + if (total_tiles) { + int i, x, y; + rcti *tile; + + /* find window pixel coordinates of origin */ + UI_view2d_to_region_no_clip(&ar->v2d, 0.0f, 0.0f, &x, &y); + + glPushMatrix(); + glTranslatef(x, y, 0.0f); + glScalef(zoomx, zoomy, 1.0f); + + if (scene->r.mode & R_BORDER) { + glTranslatef(-scene->r.border.xmin * scene->r.xsch * scene->r.size / 100.0f, + -scene->r.border.ymin * scene->r.ysch * scene->r.size / 100.0f, + 0.0f); + } + + UI_ThemeColor(TH_FACE_SELECT); + + for (i = 0, tile = tiles; i < total_tiles; i++, tile++) { + float delta_x = 4.0f * UI_DPI_FAC / zoomx; + float delta_y = 4.0f * UI_DPI_FAC / zoomy; + + delta_x = min_ff(delta_x, tile->xmax - tile->xmin); + delta_y = min_ff(delta_y, tile->ymax - tile->ymin); + + /* left bottom corner */ + glBegin(GL_LINE_STRIP); + glVertex2f(tile->xmin, tile->ymin + delta_y); + glVertex2f(tile->xmin, tile->ymin); + glVertex2f(tile->xmin + delta_x, tile->ymin); + glEnd(); + + /* left top corner */ + glBegin(GL_LINE_STRIP); + glVertex2f(tile->xmin, tile->ymax - delta_y); + glVertex2f(tile->xmin, tile->ymax); + glVertex2f(tile->xmin + delta_x, tile->ymax); + glEnd(); + + /* right bottom corner */ + glBegin(GL_LINE_STRIP); + glVertex2f(tile->xmax - delta_x, tile->ymin); + glVertex2f(tile->xmax, tile->ymin); + glVertex2f(tile->xmax, tile->ymin + delta_y); + glEnd(); + + /* right top corner */ + glBegin(GL_LINE_STRIP); + glVertex2f(tile->xmax - delta_x, tile->ymax); + glVertex2f(tile->xmax, tile->ymax); + glVertex2f(tile->xmax, tile->ymax - delta_y); + glEnd(); + } + + MEM_freeN(tiles); + + glPopMatrix(); + } + } } /* used by node view too */ @@ -146,7 +215,7 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, int color_manage, int use_def if (channels >= 3) { glColor3ubv(red); if (fp) - BLI_snprintf(str, sizeof(str), " R:%-.4f", fp[0]); + BLI_snprintf(str, sizeof(str), " R:%-.5f", fp[0]); else if (cp) BLI_snprintf(str, sizeof(str), " R:%-3d", cp[0]); else @@ -157,7 +226,7 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, int color_manage, int use_def glColor3ubv(green); if (fp) - BLI_snprintf(str, sizeof(str), " G:%-.4f", fp[1]); + BLI_snprintf(str, sizeof(str), " G:%-.5f", fp[1]); else if (cp) BLI_snprintf(str, sizeof(str), " G:%-3d", cp[1]); else @@ -168,7 +237,7 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, int color_manage, int use_def glColor3ubv(blue); if (fp) - BLI_snprintf(str, sizeof(str), " B:%-.4f", fp[2]); + BLI_snprintf(str, sizeof(str), " B:%-.5f", fp[2]); else if (cp) BLI_snprintf(str, sizeof(str), " B:%-3d", cp[2]); else @@ -518,8 +587,8 @@ static void draw_image_buffer_tiled(SpaceImage *sima, ARegion *ar, Scene *scene, sima->curtile = ima->xrep * ima->yrep - 1; /* retrieve part of image buffer */ - dx = ibuf->x / ima->xrep; - dy = ibuf->y / ima->yrep; + dx = max_ii(ibuf->x / ima->xrep, 1); + dy = max_ii(ibuf->y / ima->yrep, 1); sx = (sima->curtile % ima->xrep) * dx; sy = (sima->curtile / ima->xrep) * dy; rect = get_part_from_buffer((unsigned int *)display_buffer, ibuf->x, sx, sy, sx + dx, sy + dy); @@ -786,7 +855,6 @@ void draw_image_main(const bContext *C, ARegion *ar) if (sima->mode == SI_MODE_PAINT) draw_image_paint_helpers(C, ar, scene, zoomx, zoomy); - /* XXX integrate this code */ #if 0 if (ibuf) { @@ -812,5 +880,5 @@ void draw_image_main(const bContext *C, ARegion *ar) /* render info */ if (ima && show_render) - draw_render_info(scene, ima, ar); + draw_render_info(scene, ima, ar, zoomx, zoomy); } diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 0d0fdc6be1c..f1662bc254d 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -457,7 +457,7 @@ enum { static int image_view_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event) { - if (event->type == MOUSEZOOM) { + if (event->type == MOUSEZOOM || event->type == MOUSEPAN) { SpaceImage *sima = CTX_wm_space_image(C); ARegion *ar = CTX_wm_region(C); float delta, factor, location[2]; @@ -1217,7 +1217,7 @@ static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima, simopts->im_format.imtype = R_IMF_IMTYPE_PNG; } else { - simopts->im_format.imtype = BKE_ftype_to_imtype(ibuf->ftype); + BKE_imbuf_to_image_format(&simopts->im_format, ibuf); } //simopts->subimtype = scene->r.subimtype; /* XXX - this is lame, we need to make these available too! */ simopts->im_format.quality = ibuf->ftype & 0xff; @@ -1434,7 +1434,7 @@ static int image_save_as_exec(bContext *C, wmOperator *op) static int image_save_as_check(bContext *UNUSED(C), wmOperator *op) { ImageFormatData *imf = op->customdata; - return WM_operator_filesel_ensure_ext_imtype(op, imf->imtype); + return WM_operator_filesel_ensure_ext_imtype(op, imf); } static int image_save_as_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) @@ -1559,6 +1559,7 @@ static int image_save_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); SaveImageOptions simopts; + save_image_options_defaults(&simopts); if (save_image_options_init(&simopts, sima, scene, FALSE) == 0) return OPERATOR_CANCELLED; save_image_options_from_op(&simopts, op); diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index b0e9f8bcf99..9492e29734d 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -292,6 +292,7 @@ static void image_keymap(struct wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_out", PADMINUS, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom", MOUSEZOOM, 0, 0, 0); + WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom", MOUSEPAN, 0, KM_CTRL, 0); /* ctrl now works as well, shift + numpad works as arrow keys on Windows */ RNA_float_set(WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_ratio", PAD8, KM_PRESS, KM_CTRL, 0)->ptr, "ratio", 8.0f); diff --git a/source/blender/editors/space_info/info_intern.h b/source/blender/editors/space_info/info_intern.h index 80018e849d3..62e9a3a7f73 100644 --- a/source/blender/editors/space_info/info_intern.h +++ b/source/blender/editors/space_info/info_intern.h @@ -39,11 +39,15 @@ struct ReportList; void FILE_OT_pack_all(struct wmOperatorType *ot); void FILE_OT_unpack_all(struct wmOperatorType *ot); +void FILE_OT_pack_libraries(struct wmOperatorType *ot); +void FILE_OT_unpack_libraries(struct wmOperatorType *ot); + void FILE_OT_make_paths_relative(struct wmOperatorType *ot); void FILE_OT_make_paths_absolute(struct wmOperatorType *ot); void FILE_OT_report_missing_files(struct wmOperatorType *ot); void FILE_OT_find_missing_files(struct wmOperatorType *ot); + void INFO_OT_reports_display_update(struct wmOperatorType *ot); /* info_draw.c */ diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c index e902a4ea6f4..104349e172a 100644 --- a/source/blender/editors/space_info/info_ops.c +++ b/source/blender/editors/space_info/info_ops.c @@ -66,15 +66,70 @@ #include "info_intern.h" +/********************* pack blend file libararies operator *********************/ + +static int pack_libraries_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + + packLibraries(bmain, op->reports); + + return OPERATOR_FINISHED; +} + +void FILE_OT_pack_libraries(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Pack Blender Libraries"; + ot->idname = "FILE_OT_pack_libraries"; + ot->description = "Pack all used Blender library files into the current .blend"; + + /* api callbacks */ + ot->exec = pack_libraries_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static int unpack_libraries_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + + unpackLibraries(bmain, op->reports); + + return OPERATOR_FINISHED; +} + +static int unpack_libraries_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +{ + return WM_operator_confirm_message(C, op, "Unpack Blender Libraries - creates directories, all new paths should work"); +} + +void FILE_OT_unpack_libraries(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Unpack Blender Libraries"; + ot->idname = "FILE_OT_unpack_libraries"; + ot->description = "Unpack all used Blender library files from this .blend file"; + + /* api callbacks */ + ot->invoke = unpack_libraries_invoke; + ot->exec = unpack_libraries_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + + /********************* pack all operator *********************/ static int pack_all_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - + packAll(bmain, op->reports); G.fileflags |= G_AUTOPACK; - + return OPERATOR_FINISHED; } @@ -83,7 +138,7 @@ static int pack_all_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) Main *bmain = CTX_data_main(C); Image *ima; ImBuf *ibuf; - + // first check for dirty images for (ima = bmain->image.first; ima; ima = ima->id.next) { if (ima->ibufs.first) { /* XXX FIX */ @@ -93,16 +148,16 @@ static int pack_all_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) BKE_image_release_ibuf(ima, ibuf, NULL); break; } - + BKE_image_release_ibuf(ima, ibuf, NULL); } } - + if (ima) { uiPupMenuOkee(C, "FILE_OT_pack_all", "Some images are painted on. These changes will be lost. Continue?"); return OPERATOR_CANCELLED; } - + return pack_all_exec(C, op); } @@ -116,11 +171,12 @@ void FILE_OT_pack_all(wmOperatorType *ot) /* api callbacks */ ot->exec = pack_all_exec; ot->invoke = pack_all_invoke; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + /********************* unpack all operator *********************/ static const EnumPropertyItem unpack_all_method_items[] = { diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c index 5e5e0c87feb..3f73fc2605a 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.c @@ -39,6 +39,7 @@ #include "DNA_scene_types.h" #include "BLI_utildefines.h" +#include "BLI_math.h" #include "BKE_anim.h" #include "BKE_blender.h" @@ -47,6 +48,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_key.h" #include "BKE_mesh.h" +#include "BKE_paint.h" #include "BKE_particle.h" #include "BKE_tessmesh.h" @@ -62,7 +64,7 @@ typedef struct SceneStats { int totbone, totbonesel; int totobj, totobjsel; int totlamp, totlampsel; - int tottri, totmesh, totcurve; + int tottri, totmesh; char infostr[512]; } SceneStats; @@ -74,7 +76,7 @@ static void stats_object(Object *ob, int sel, int totob, SceneStats *stats) { /* we assume derivedmesh is already built, this strictly does stats now. */ DerivedMesh *dm = ob->derivedFinal; - int totvert, totedge, totface; + int totvert, totedge, totface, totloop; stats->totmesh += totob; @@ -82,10 +84,12 @@ static void stats_object(Object *ob, int sel, int totob, SceneStats *stats) totvert = dm->getNumVerts(dm); totedge = dm->getNumEdges(dm); totface = dm->getNumPolys(dm); + totloop = dm->getNumLoops(dm); stats->totvert += totvert * totob; stats->totedge += totedge * totob; stats->totface += totface * totob; + stats->tottri += poly_to_tri_count(totface, totloop) * totob; if (sel) { stats->totvertsel += totvert; @@ -103,40 +107,23 @@ static void stats_object(Object *ob, int sel, int totob, SceneStats *stats) case OB_SURF: case OB_CURVE: case OB_FONT: - { - int tot = 0, totf = 0; - - stats->totcurve += totob; - - if (ob->disp.first) - BKE_displist_count(&ob->disp, &tot, &totf); - - tot *= totob; - totf *= totob; - - stats->totvert += tot; - stats->totface += totf; - - if (sel) { - stats->totvertsel += tot; - stats->totfacesel += totf; - } - break; - } case OB_MBALL: { - int tot = 0, totf = 0; + int totv = 0, totf = 0, tottri = 0; - BKE_displist_count(&ob->disp, &tot, &totf); + if (ob->disp.first) + BKE_displist_count(&ob->disp, &totv, &totf, &tottri); - tot *= totob; - totf *= totob; + totv *= totob; + totf *= totob; + tottri *= totob; - stats->totvert += tot; + stats->totvert += totv; stats->totface += totf; + stats->tottri += tottri; if (sel) { - stats->totvertsel += tot; + stats->totvertsel += totv; stats->totfacesel += totf; } break; @@ -260,6 +247,12 @@ static void stats_object_pose(Object *ob, SceneStats *stats) } } +static void stats_object_sculpt_dynamic_topology(Object *ob, SceneStats *stats) +{ + stats->totvert = ob->sculpt->bm->totvert; + stats->tottri = ob->sculpt->bm->totface; +} + static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats) { if (base->flag & SELECT) stats->totobjsel++; @@ -319,6 +312,12 @@ static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats) } } +static int stats_is_object_dynamic_topology_sculpt(Object *ob) +{ + return (ob && (ob->mode & OB_MODE_SCULPT) && + ob->sculpt && ob->sculpt->bm); +} + /* Statistics displayed in info header. Called regularly on scene changes. */ static void stats_update(Scene *scene) { @@ -334,6 +333,10 @@ static void stats_update(Scene *scene) /* Pose Mode */ stats_object_pose(ob, &stats); } + else if (stats_is_object_dynamic_topology_sculpt(ob)) { + /* Dynamic-topology sculpt mode */ + stats_object_sculpt_dynamic_topology(ob, &stats); + } else { /* Objects */ for (base = scene->base.first; base; base = base->next) @@ -388,9 +391,12 @@ static void stats_string(Scene *scene) s += sprintf(s, "Bones:%d/%d %s", stats->totbonesel, stats->totbone, memstr); } + else if (stats_is_object_dynamic_topology_sculpt(ob)) { + s += sprintf(s, "Verts:%d | Tris:%d", stats->totvert, stats->tottri); + } else { - s += sprintf(s, "Verts:%d | Faces:%d | Objects:%d/%d | Lamps:%d/%d%s", - stats->totvert, stats->totface, stats->totobjsel, stats->totobj, stats->totlampsel, stats->totlamp, memstr); + s += sprintf(s, "Verts:%d | Faces:%d| Tris:%d | Objects:%d/%d | Lamps:%d/%d%s", + stats->totvert, stats->totface, stats->tottri, stats->totobjsel, stats->totobj, stats->totlampsel, stats->totlamp, memstr); } if (ob) diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c index db9be22eedb..60b04f7b029 100644 --- a/source/blender/editors/space_info/space_info.c +++ b/source/blender/editors/space_info/space_info.c @@ -178,7 +178,10 @@ static void info_main_area_draw(const bContext *C, ARegion *ar) static void info_operatortypes(void) { WM_operatortype_append(FILE_OT_pack_all); + WM_operatortype_append(FILE_OT_pack_libraries); WM_operatortype_append(FILE_OT_unpack_all); + WM_operatortype_append(FILE_OT_unpack_libraries); + WM_operatortype_append(FILE_OT_make_paths_relative); WM_operatortype_append(FILE_OT_make_paths_absolute); WM_operatortype_append(FILE_OT_report_missing_files); diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index 00745062582..a7599f21ad5 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -1006,7 +1006,7 @@ static void draw_sensor_actuator(uiLayout *layout, PointerRNA *ptr) static void draw_sensor_armature(uiLayout *layout, PointerRNA *ptr) { - bSensor *sens = (bSensor*)ptr->data; + bSensor *sens = (bSensor *)ptr->data; bArmatureSensor *as = (bArmatureSensor *) sens->data; Object *ob = (Object *)ptr->id.data; PointerRNA pose_ptr, pchan_ptr; @@ -1476,7 +1476,7 @@ static void draw_actuator_action(uiLayout *layout, PointerRNA *ptr) static void draw_actuator_armature(uiLayout *layout, PointerRNA *ptr) { - bActuator *act = (bActuator*)ptr->data; + bActuator *act = (bActuator *)ptr->data; bArmatureActuator *aa = (bArmatureActuator *) act->data; Object *ob = (Object *)ptr->id.data; bConstraint *constraint = NULL; diff --git a/source/blender/editors/space_logic/space_logic.c b/source/blender/editors/space_logic/space_logic.c index 4cd53215697..8795d655e77 100644 --- a/source/blender/editors/space_logic/space_logic.c +++ b/source/blender/editors/space_logic/space_logic.c @@ -148,7 +148,7 @@ static SpaceLink *logic_new(const bContext *C) /* not spacelink itself */ static void logic_free(SpaceLink *UNUSED(sl)) { -// Spacelogic *slogic= (SpaceLogic*) sl; +// Spacelogic *slogic= (SpaceLogic *) sl; // if (slogic->gpd) // XXX BKE_gpencil_free(slogic->gpd); diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 59dd66a0207..8797cb4a459 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -399,8 +399,8 @@ static void node_buts_curvecol(uiLayout *layout, bContext *UNUSED(C), PointerRNA static void node_buts_normal(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - bNodeTree *ntree = (bNodeTree*)ptr->id.data; - bNode *node = (bNode*)ptr->data; + bNodeTree *ntree = (bNodeTree *)ptr->id.data; + bNode *node = (bNode *)ptr->data; bNodeSocket *sock = node->outputs.first; /* first socket stores normal */ PointerRNA sockptr; @@ -2152,12 +2152,12 @@ static void node_composit_buts_file_output_details(uiLayout *layout, bContext *C active_index = RNA_int_get(ptr, "active_input_index"); /* using different collection properties if multilayer format is enabled */ if (multilayer) { - uiTemplateList(col, C, ptr, "layer_slots", ptr, "active_input_index", NULL, 0, 0, 0); + uiTemplateList(col, C, "UI_UL_list", "", ptr, "layer_slots", ptr, "active_input_index", 0, 0, 0); RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "layer_slots"), active_index, &active_input_ptr); } else { - uiTemplateList(col, C, ptr, "file_slots", ptr, "active_input_index", NULL, 0, 0, 0); + uiTemplateList(col, C, "UI_UL_list", "", ptr, "file_slots", ptr, "active_input_index", 0, 0, 0); RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "file_slots"), active_index, &active_input_ptr); } diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c index f386657c460..492ff0dcbd4 100644 --- a/source/blender/editors/space_node/node_view.c +++ b/source/blender/editors/space_node/node_view.c @@ -69,12 +69,15 @@ static int space_node_view_flag(bContext *C, SpaceNode *snode, ARegion *ar, cons bNode *node; rctf cur_new; float oldwidth, oldheight, width, height; + float oldasp, asp; int tot = 0; int has_frame = FALSE; oldwidth = BLI_rctf_size_x(&ar->v2d.cur); oldheight = BLI_rctf_size_y(&ar->v2d.cur); + oldasp = oldwidth / oldheight; + BLI_rctf_init_minmax(&cur_new); if (snode->edittree) { @@ -93,6 +96,7 @@ static int space_node_view_flag(bContext *C, SpaceNode *snode, ARegion *ar, cons if (tot) { width = BLI_rctf_size_x(&cur_new); height = BLI_rctf_size_y(&cur_new); + asp = width / height; /* for single non-frame nodes, don't zoom in, just pan view, * but do allow zooming out, this allows for big nodes to be zoomed out */ @@ -104,17 +108,15 @@ static int space_node_view_flag(bContext *C, SpaceNode *snode, ARegion *ar, cons BLI_rctf_resize(&cur_new, oldwidth, oldheight); } else { - if (width > height) { - float newheight; - newheight = oldheight * width / oldwidth; - cur_new.ymin = cur_new.ymin - newheight / 4; - cur_new.ymax = cur_new.ymax + newheight / 4; + if (oldasp < asp) { + const float height_new = width / oldasp; + cur_new.ymin = cur_new.ymin - height_new / 2.0f; + cur_new.ymax = cur_new.ymax + height_new / 2.0f; } else { - float newwidth; - newwidth = oldwidth * height / oldheight; - cur_new.xmin = cur_new.xmin - newwidth / 4; - cur_new.xmax = cur_new.xmax + newwidth / 4; + const float width_new = height * oldasp; + cur_new.xmin = cur_new.xmin - width_new / 2.0f; + cur_new.xmax = cur_new.xmax + width_new / 2.0f; } } diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 6913ebc8a11..1a058104c78 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -421,17 +421,17 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar uiBlockSetEmboss(block, UI_EMBOSSN); bt = uiDefIconButR(block, ICONTOG, 0, ICON_RESTRICT_VIEW_OFF, - (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, &ptr, "hide", -1, 0, 0, -1, -1, NULL); uiButSetFunc(bt, restrictbutton_view_cb, scene, ob); bt = uiDefIconButR(block, ICONTOG, 0, ICON_RESTRICT_SELECT_OFF, - (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, &ptr, "hide_select", -1, 0, 0, -1, -1, NULL); uiButSetFunc(bt, restrictbutton_sel_cb, scene, ob); bt = uiDefIconButR(block, ICONTOG, 0, ICON_RESTRICT_RENDER_OFF, - (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, &ptr, "hide_render", -1, 0, 0, -1, -1, NULL); uiButSetFunc(bt, restrictbutton_rend_cb, scene, ob); @@ -445,15 +445,21 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar uiBlockSetEmboss(block, UI_EMBOSSN); restrict_bool = group_restrict_flag(gr, OB_RESTRICT_VIEW); - bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_VIEW_ON : ICON_RESTRICT_VIEW_OFF, (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View"); + bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_VIEW_ON : ICON_RESTRICT_VIEW_OFF, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + NULL, 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View"); uiButSetFunc(bt, restrictbutton_gr_restrict_view, scene, gr); restrict_bool = group_restrict_flag(gr, OB_RESTRICT_SELECT); - bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_SELECT_ON : ICON_RESTRICT_SELECT_OFF, (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "Restrict/Allow selection in the 3D View"); + bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_SELECT_ON : ICON_RESTRICT_SELECT_OFF, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + NULL, 0, 0, 0, 0, "Restrict/Allow selection in the 3D View"); uiButSetFunc(bt, restrictbutton_gr_restrict_select, scene, gr); restrict_bool = group_restrict_flag(gr, OB_RESTRICT_RENDER); - bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_RENDER_ON : ICON_RESTRICT_RENDER_OFF, (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "Restrict/Allow renderability"); + bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_RENDER_ON : ICON_RESTRICT_RENDER_OFF, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + NULL, 0, 0, 0, 0, "Restrict/Allow renderability"); uiButSetFunc(bt, restrictbutton_gr_restrict_render, scene, gr); uiBlockSetEmboss(block, UI_EMBOSS); @@ -463,7 +469,8 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar uiBlockSetEmboss(block, UI_EMBOSSN); bt = uiDefIconButBitI(block, ICONTOGN, SCE_LAY_DISABLE, 0, ICON_CHECKBOX_HLT - 1, - (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, te->directdata, 0, 0, 0, 0, "Render this RenderLayer"); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + te->directdata, 0, 0, 0, 0, "Render this RenderLayer"); uiButSetFunc(bt, restrictbutton_r_lay_cb, tselem->id, NULL); uiBlockSetEmboss(block, UI_EMBOSS); @@ -476,13 +483,18 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar bt = uiDefIconButBitI(block, ICONTOG, passflag, 0, ICON_CHECKBOX_HLT - 1, - (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, layflag, 0, 0, 0, 0, "Render this Pass"); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + layflag, 0, 0, 0, 0, "Render this Pass"); uiButSetFunc(bt, restrictbutton_r_lay_cb, tselem->id, NULL); layflag++; /* is lay_xor */ - if (ELEM8(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)) + if (ELEM8(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, - (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, layflag, 0, 0, 0, 0, "Exclude this Pass from Combined"); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + layflag, 0, 0, 0, 0, "Exclude this Pass from Combined"); + } uiButSetFunc(bt, restrictbutton_r_lay_cb, tselem->id, NULL); uiBlockSetEmboss(block, UI_EMBOSS); @@ -493,11 +505,13 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar uiBlockSetEmboss(block, UI_EMBOSSN); bt = uiDefIconButBitI(block, ICONTOGN, eModifierMode_Realtime, 0, ICON_RESTRICT_VIEW_OFF, - (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, &(md->mode), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View"); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + &(md->mode), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View"); uiButSetFunc(bt, restrictbutton_modifier_cb, scene, ob); bt = uiDefIconButBitI(block, ICONTOGN, eModifierMode_Render, 0, ICON_RESTRICT_RENDER_OFF, - (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, &(md->mode), 0, 0, 0, 0, "Restrict/Allow renderability"); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + &(md->mode), 0, 0, 0, 0, "Restrict/Allow renderability"); uiButSetFunc(bt, restrictbutton_modifier_cb, scene, ob); } else if (tselem->type == TSE_POSE_CHANNEL) { @@ -506,11 +520,13 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar uiBlockSetEmboss(block, UI_EMBOSSN); bt = uiDefIconButBitI(block, ICONTOG, BONE_HIDDEN_P, 0, ICON_RESTRICT_VIEW_OFF, - (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, &(bone->flag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View"); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + &(bone->flag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View"); uiButSetFunc(bt, restrictbutton_bone_cb, NULL, bone); bt = uiDefIconButBitI(block, ICONTOG, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF, - (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, &(bone->flag), 0, 0, 0, 0, "Restrict/Allow selection in the 3D View"); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + &(bone->flag), 0, 0, 0, 0, "Restrict/Allow selection in the 3D View"); uiButSetFunc(bt, restrictbutton_bone_cb, NULL, NULL); } else if (tselem->type == TSE_EBONE) { @@ -518,11 +534,13 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar uiBlockSetEmboss(block, UI_EMBOSSN); bt = uiDefIconButBitI(block, ICONTOG, BONE_HIDDEN_A, 0, ICON_RESTRICT_VIEW_OFF, - (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, &(ebone->flag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View"); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + &(ebone->flag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View"); uiButSetFunc(bt, restrictbutton_ebone_cb, NULL, ebone); bt = uiDefIconButBitI(block, ICONTOG, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF, - (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, &(ebone->flag), 0, 0, 0, 0, "Restrict/Allow selection in the 3D View"); + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y, + &(ebone->flag), 0, 0, 0, 0, "Restrict/Allow selection in the 3D View"); uiButSetFunc(bt, restrictbutton_ebone_cb, NULL, NULL); } } @@ -535,7 +553,7 @@ static void outliner_draw_rnacols(ARegion *ar, int sizex) { View2D *v2d = &ar->v2d; - float miny = v2d->cur.ymin - V2D_SCROLL_HEIGHT; + float miny = v2d->cur.ymin; if (miny < v2d->tot.ymin) miny = v2d->tot.ymin; UI_ThemeColorShadeAlpha(TH_BACK, -15, -200); @@ -832,7 +850,7 @@ static void outliner_draw_keymapbuts(uiBlock *block, ARegion *ar, SpaceOops *soo /* rna property */ if (kmi->ptr && kmi->ptr->data) { - uiDefBut(block, LABEL, 0, "(RNA property)", xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->oskey, 0, 0, 0, 0, ""); xstart += butw2; + uiDefBut(block, LABEL, 0, "(RNA property)", xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, NULL, 0, 0, 0, 0, ""); xstart += butw2; } (void)xstart; @@ -1515,13 +1533,13 @@ static void outliner_draw_struct_marks(ARegion *ar, SpaceOops *soops, ListBase * /* selection status */ if (TSELEM_OPEN(tselem, soops)) if (tselem->type == TSE_RNA_STRUCT) - glRecti(0, *starty + 1, (int)ar->v2d.cur.xmax + V2D_SCROLL_WIDTH, *starty + UI_UNIT_Y - 1); + glRecti(0, *starty + 1, (int)ar->v2d.cur.xmax, *starty + UI_UNIT_Y - 1); *starty -= UI_UNIT_Y; if (TSELEM_OPEN(tselem, soops)) { outliner_draw_struct_marks(ar, soops, &te->subtree, starty); if (tselem->type == TSE_RNA_STRUCT) - fdrawline(0, (float)*starty + UI_UNIT_Y, ar->v2d.cur.xmax + V2D_SCROLL_WIDTH, (float)*starty + UI_UNIT_Y); + fdrawline(0, (float)*starty + UI_UNIT_Y, ar->v2d.cur.xmax, (float)*starty + UI_UNIT_Y); } } } @@ -1590,7 +1608,7 @@ static void outliner_back(ARegion *ar) ystart = UI_UNIT_Y * (ystart / (UI_UNIT_Y)) - OL_Y_OFFSET; while (ystart + 2 * UI_UNIT_Y > ar->v2d.cur.ymin) { - glRecti(0, ystart, (int)ar->v2d.cur.xmax + V2D_SCROLL_WIDTH, ystart + UI_UNIT_Y); + glRecti(0, ystart, (int)ar->v2d.cur.xmax, ystart + UI_UNIT_Y); ystart -= 2 * UI_UNIT_Y; } } @@ -1601,10 +1619,8 @@ static void outliner_draw_restrictcols(ARegion *ar) /* background underneath */ UI_ThemeColor(TH_BACK); - glRecti((int)ar->v2d.cur.xmax - OL_TOGW, - (int)ar->v2d.cur.ymin - V2D_SCROLL_HEIGHT - 1, - (int)ar->v2d.cur.xmax + V2D_SCROLL_WIDTH, - (int)ar->v2d.cur.ymax); + glRecti((int)(ar->v2d.cur.xmax - OL_TOGW), + (int)(ar->v2d.cur.ymin - 1), (int)ar->v2d.cur.xmax, (int)ar->v2d.cur.ymax); UI_ThemeColorShade(TH_BACK, 6); ystart = (int)ar->v2d.tot.ymax; @@ -1618,22 +1634,22 @@ static void outliner_draw_restrictcols(ARegion *ar) UI_ThemeColorShadeAlpha(TH_BACK, -15, -200); /* view */ - fdrawline(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, - ar->v2d.cur.ymax, - ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, - ar->v2d.cur.ymin - V2D_SCROLL_HEIGHT); + sdrawline((int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), + (int)ar->v2d.cur.ymax, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), + (int)ar->v2d.cur.ymin); /* render */ - fdrawline(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX, - ar->v2d.cur.ymax, - ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX, - ar->v2d.cur.ymin - V2D_SCROLL_HEIGHT); + sdrawline((int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), + (int)ar->v2d.cur.ymax, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), + (int)ar->v2d.cur.ymin); /* render */ - fdrawline(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX, - ar->v2d.cur.ymax, - ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX, - ar->v2d.cur.ymin - V2D_SCROLL_HEIGHT); + sdrawline((int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), + (int)ar->v2d.cur.ymax, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), + (int)ar->v2d.cur.ymin); } /* ****************************************************** */ @@ -1682,11 +1698,9 @@ void draw_outliner(const bContext *C) // XXX this isn't that great yet... if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0) sizex += OL_TOGW * 3; + } - /* tweak to display last line (when list bigger than window) */ - sizey += V2D_SCROLL_HEIGHT; - /* adds vertical offset */ sizey += OL_Y_OFFSET; diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index f9fca378568..63452de18d0 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -116,8 +116,8 @@ typedef struct TreeElement { /* size constants */ #define OL_Y_OFFSET 2 -#define OL_TOG_RESTRICT_VIEWX (UI_UNIT_X * 3) -#define OL_TOG_RESTRICT_SELECTX (UI_UNIT_X * 2) +#define OL_TOG_RESTRICT_VIEWX (UI_UNIT_X * 3.0f) +#define OL_TOG_RESTRICT_SELECTX (UI_UNIT_X * 2.0f) #define OL_TOG_RESTRICT_RENDERX UI_UNIT_X #define OL_TOGW OL_TOG_RESTRICT_VIEWX diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index ddbc49bf995..f723fbedc7b 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -803,8 +803,12 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i } /* One exception */ - if (type == TSE_ID_BASE); - else if (id == NULL) return NULL; + if (type == TSE_ID_BASE) { + /* pass */ + } + else if (id == NULL) { + return NULL; + } te = MEM_callocN(sizeof(TreeElement), "tree elem"); /* add to the visual tree */ @@ -832,7 +836,11 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i /* pass */ } else { - te->name = id->name + 2; // default, can be overridden by Library or non-ID data + /* do here too, for blend file viewer, own ID_LI then shows file name */ + if (GS(id->name) == ID_LI) + te->name = ((Library *)id)->name; + else + te->name = id->name + 2; // default, can be overridden by Library or non-ID data te->idcode = GS(id->name); } @@ -840,7 +848,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i TreeStoreElem *tsepar = parent ? TREESTORE(parent) : NULL; /* ID datablock */ - if (tsepar==NULL || tsepar->type != TSE_ID_BASE) + if (tsepar == NULL || tsepar->type != TSE_ID_BASE) outliner_add_id_contents(soops, te, tselem, id); } else if (type == TSE_ANIM_DATA) { @@ -1511,7 +1519,7 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops) } /* make hierarchy */ ten = soops->tree.first; - ten= ten->next; /* first one is main */ + ten = ten->next; /* first one is main */ while (ten) { TreeElement *nten = ten->next, *par; tselem = TREESTORE(ten); diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index ecc09a35670..4bf88376b74 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -67,6 +67,17 @@ static void outliner_main_area_init(wmWindowManager *wm, ARegion *ar) ListBase *lb; wmKeyMap *keymap; + /* make sure we keep the hide flags */ + ar->v2d.scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM); + ar->v2d.scroll &= ~(V2D_SCROLL_LEFT | V2D_SCROLL_TOP); /* prevent any noise of past */ + ar->v2d.scroll |= V2D_SCROLL_HORIZONTAL_HIDE; + ar->v2d.scroll |= V2D_SCROLL_VERTICAL_HIDE; + + ar->v2d.align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y); + ar->v2d.keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT); + ar->v2d.keeptot = V2D_KEEPTOT_STRICT; + ar->v2d.minzoom = ar->v2d.maxzoom = 1.0f; + UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); /* own keymap */ @@ -410,12 +421,6 @@ static SpaceLink *outliner_new(const bContext *UNUSED(C)) BLI_addtail(&soutliner->regionbase, ar); ar->regiontype = RGN_TYPE_WINDOW; - ar->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM_O); - ar->v2d.align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y); - ar->v2d.keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT); - ar->v2d.keeptot = V2D_KEEPTOT_STRICT; - ar->v2d.minzoom = ar->v2d.maxzoom = 1.0f; - return (SpaceLink *)soutliner; } diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index 6219a9061f4..29a6a1f6d50 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -49,6 +49,8 @@ #include "DNA_mask_types.h" #include "DNA_userdef_types.h" +#include "BLF_translation.h" + #include "BKE_context.h" #include "BKE_global.h" #include "BKE_library.h" @@ -400,6 +402,7 @@ void SEQUENCER_OT_movieclip_strip_add(struct wmOperatorType *ot) sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME); prop = RNA_def_enum(ot->srna, "clip", DummyRNA_NULL_items, 0, "Clip", ""); RNA_def_enum_funcs(prop, RNA_movieclip_itemf); + RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_MOVIECLIP); ot->prop = prop; } @@ -871,7 +874,7 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op) if (BKE_sequence_test_overlap(ed->seqbasep, seq)) BKE_sequence_base_shuffle(ed->seqbasep, seq, scene); } - BKE_sequencer_update_changed_seq_and_deps(scene, seq, 1, 1); /* runs calc_sequence */ + BKE_sequencer_update_changed_seq_and_deps(scene, seq, 1, 1); /* runs BKE_sequence_calc */ /* not sure if this is needed with update_changed_seq_and_deps. diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 409f655bb79..c6c70ccb424 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -925,7 +925,7 @@ static void set_filter_seq(Scene *scene) if (seq->type == SEQ_TYPE_MOVIE) { seq->flag |= SEQ_FILTERY; reload_sequence_new_file(scene, seq, FALSE); - calc_sequence(scene, seq); + BKE_sequence_calc(scene, seq); } } @@ -1906,6 +1906,9 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op)) for (seq = ed->seqbasep->first; seq; seq = seq->next) BKE_sequence_calc(scene, seq); + if (BKE_sequence_test_overlap(ed->seqbasep, ms->parseq)) + BKE_sequence_base_shuffle(ed->seqbasep, ms->parseq, scene); + BKE_sequencer_active_set(scene, ms->parseq); ms->parseq->flag |= SELECT; diff --git a/source/blender/editors/space_text/CMakeLists.txt b/source/blender/editors/space_text/CMakeLists.txt index 6aaf4212779..a33a9abada1 100644 --- a/source/blender/editors/space_text/CMakeLists.txt +++ b/source/blender/editors/space_text/CMakeLists.txt @@ -36,12 +36,13 @@ set(INC_SYS set(SRC space_text.c + text_autocomplete.c text_draw.c text_format.c + text_format_osl.c text_format_py.c text_header.c text_ops.c - text_python.c text_format.h text_intern.h diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c index 9ac66ca1698..fa3eefcc0f7 100644 --- a/source/blender/editors/space_text/space_text.c +++ b/source/blender/editors/space_text/space_text.c @@ -223,6 +223,8 @@ static void text_operatortypes(void) WM_operatortype_append(TEXT_OT_to_3d_object); WM_operatortype_append(TEXT_OT_resolve_conflict); + + WM_operatortype_append(TEXT_OT_autocomplete); } static void text_keymap(struct wmKeyConfig *keyconf) @@ -276,7 +278,7 @@ static void text_keymap(struct wmKeyConfig *keyconf) kmi = WM_keymap_add_item(keymap, "WM_OT_context_cycle_int", PADMINUS, KM_PRESS, KM_CTRL, 0); RNA_string_set(kmi->ptr, "data_path", "space_data.font_size"); RNA_boolean_set(kmi->ptr, "reverse", TRUE); - + WM_keymap_add_item(keymap, "TEXT_OT_new", NKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "TEXT_OT_open", OKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "TEXT_OT_reload", RKEY, KM_PRESS, KM_ALT, 0); @@ -375,6 +377,8 @@ static void text_keymap(struct wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "TEXT_OT_line_break", PADENTER, KM_PRESS, 0, 0); WM_keymap_add_menu(keymap, "TEXT_MT_toolbox", RIGHTMOUSE, KM_PRESS, KM_ANY, 0); + + WM_keymap_add_item(keymap, "TEXT_OT_autocomplete", SPACEKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "TEXT_OT_line_number", KM_TEXTINPUT, KM_ANY, KM_ANY, 0); WM_keymap_add_item(keymap, "TEXT_OT_insert", KM_TEXTINPUT, KM_ANY, KM_ANY, 0); // last! @@ -555,5 +559,6 @@ void ED_spacetype_text(void) /* register formatters */ ED_text_format_register_py(); + ED_text_format_register_osl(); } diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c new file mode 100644 index 00000000000..e406a1b7166 --- /dev/null +++ b/source/blender/editors/space_text/text_autocomplete.c @@ -0,0 +1,541 @@ +/* + * ***** 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) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_text/text_autocomplete.c + * \ingroup sptext + */ + +#include <ctype.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_text_types.h" + +#include "BLI_blenlib.h" +#include "BLI_ghash.h" + +#include "BKE_context.h" +#include "BKE_text.h" +#include "BKE_screen.h" +#include "BKE_suggestions.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_screen.h" +#include "UI_interface.h" + +#include "text_format.h" +#include "text_intern.h" /* own include */ + + +/* -------------------------------------------------------------------- */ +/* Public API */ + +int text_do_suggest_select(SpaceText *st, ARegion *ar) +{ + SuggItem *item, *first, *last /* , *sel */ /* UNUSED */; + TextLine *tmp; + int l, x, y, w, h, i; + int tgti, *top; + int mval[2] = {0, 0}; + + if (!st || !st->text) return 0; + if (!texttool_text_is_active(st->text)) return 0; + + first = texttool_suggest_first(); + last = texttool_suggest_last(); + /* sel = texttool_suggest_selected(); */ /* UNUSED */ + top = texttool_suggest_top(); + + if (!last || !first) + return 0; + + /* Count the visible lines to the cursor */ + for (tmp = st->text->curl, l = -st->top; tmp; tmp = tmp->prev, l++) ; + if (l < 0) return 0; + + text_update_character_width(st); + + if (st->showlinenrs) { + x = st->cwidth * (st->text->curc - st->left) + TXT_OFFSET + TEXTXLOC - 4; + } + else { + x = st->cwidth * (st->text->curc - st->left) + TXT_OFFSET - 4; + } + y = ar->winy - st->lheight_dpi * l - 2; + + w = SUGG_LIST_WIDTH * st->cwidth + U.widget_unit; + h = SUGG_LIST_SIZE * st->lheight_dpi + 0.4f * U.widget_unit; + + // XXX getmouseco_areawin(mval); + + if (mval[0] < x || x + w < mval[0] || mval[1] < y - h || y < mval[1]) + return 0; + + /* Work out which of the items is at the top of the visible list */ + for (i = 0, item = first; i < *top && item->next; i++, item = item->next) ; + + /* Work out the target item index in the visible list */ + tgti = (y - mval[1] - 4) / st->lheight_dpi; + if (tgti < 0 || tgti > SUGG_LIST_SIZE) + return 1; + + for (i = tgti; i > 0 && item->next; i--, item = item->next) ; + if (item) + texttool_suggest_select(item); + return 1; +} + +void text_pop_suggest_list(void) +{ + SuggItem *item, *sel; + int *top, i; + + item = texttool_suggest_first(); + sel = texttool_suggest_selected(); + top = texttool_suggest_top(); + + i = 0; + while (item && item != sel) { + item = item->next; + i++; + } + if (i > *top + SUGG_LIST_SIZE - 1) + *top = i - SUGG_LIST_SIZE + 1; + else if (i < *top) + *top = i; +} + +/* -------------------------------------------------------------------- */ +/* Private API */ + +static void text_autocomplete_free(bContext *C, wmOperator *op); + +static GHash *text_autocomplete_build(Text *text) +{ + GHash *gh; + int seek_len = 0; + const char *seek; + texttool_text_clear(); + + texttool_text_set_active(text); + + /* first get the word we're at */ + { + const int i = text_find_identifier_start(text->curl->line, text->curc); + seek_len = text->curc - i; + seek = text->curl->line + i; + + // BLI_strncpy(seek, seek_ptr, seek_len); + } + + /* now walk over entire doc and suggest words */ + { + TextLine *linep; + + gh = BLI_ghash_str_new(__func__); + + for (linep = text->lines.first; linep; linep = linep->next) { + int i_start = 0; + int i_end = 0; + + while (i_start < linep->len) { + /* seek identifier beginning */ + while (i_start < linep->len && !text_check_identifier(linep->line[i_start])) { + i_start++; + } + i_end = i_start; + while (i_end < linep->len && text_check_identifier(linep->line[i_end])) { + i_end++; + } + + if (i_start != i_end) { + char *str_sub = &linep->line[i_start]; + const int choice_len = i_end - i_start; + + if ((choice_len > seek_len) && + (seek_len == 0 || strncmp(seek, str_sub, seek_len) == 0) && + (seek != str_sub)) + { + // printf("Adding: %s\n", s); + char str_sub_last = str_sub[choice_len]; + str_sub[choice_len] = '\0'; + if (!BLI_ghash_lookup(gh, str_sub)) { + char *str_dup = BLI_strdupn(str_sub, choice_len); + BLI_ghash_insert(gh, str_dup, str_dup); /* A 'set' would make more sense here */ + } + str_sub[choice_len] = str_sub_last; + } + } + i_start = i_end; + } + } + + { + GHashIterator *iter = BLI_ghashIterator_new(gh); + + /* get the formatter for highlighting */ + TextFormatType *tft; + tft = ED_text_format_get(text); + + for (; !BLI_ghashIterator_isDone(iter); BLI_ghashIterator_step(iter)) { + const char *s = BLI_ghashIterator_getValue(iter); + texttool_suggest_add(s, tft->format_identifier(s)); + } + BLI_ghashIterator_free(iter); + + } + } + + texttool_suggest_prefix(seek, seek_len); + + return gh; +} + +/* -- */ + +static void get_suggest_prefix(Text *text, int offset) +{ + int i, len; + char *line; + + if (!text) return; + if (!texttool_text_is_active(text)) return; + + line = text->curl->line; + i = text_find_identifier_start(line, text->curc + offset); + len = text->curc - i + offset; + texttool_suggest_prefix(line + i, len); +} + +static void confirm_suggestion(Text *text) +{ + SuggItem *sel; + int i, over = 0; + const char *line; + + if (!text) return; + if (!texttool_text_is_active(text)) return; + + sel = texttool_suggest_selected(); + if (!sel) return; + + line = text->curl->line; + i = text_find_identifier_start(line, text->curc /* - skipleft */); + over = text->curc - i; + +// for (i = 0; i < skipleft; i++) +// txt_move_left(text, 0); + for (i = 0; i < over; i++) + txt_move_left(text, 1); + + txt_insert_buf(text, sel->name); + +// for (i = 0; i < skipleft; i++) +// txt_move_right(text, 0); + + texttool_text_clear(); +} + +/* -- */ + + +static int text_autocomplete_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +{ + SpaceText *st = CTX_wm_space_text(C); + Text *text = CTX_data_edit_text(C); + + st->doplugins = TRUE; + op->customdata = text_autocomplete_build(text); + + if (texttool_suggest_first()) { + + ED_area_tag_redraw(CTX_wm_area(C)); + + if (texttool_suggest_first() == texttool_suggest_last()) { + confirm_suggestion(st->text); + text_update_line_edited(st->text->curl); + text_autocomplete_free(C, op); + return OPERATOR_FINISHED; + } + else { + WM_event_add_modal_handler(C, op); + return OPERATOR_RUNNING_MODAL; + } + } + else { + text_autocomplete_free(C, op); + return OPERATOR_CANCELLED; + } +} + +static int doc_scroll = 0; + +static int text_autocomplete_modal(bContext *C, wmOperator *op, wmEvent *event) +{ + SpaceText *st = CTX_wm_space_text(C); + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); + + int draw = 0, tools = 0, swallow = 0, scroll = 1; + Text *text = CTX_data_edit_text(C); + int retval = OPERATOR_RUNNING_MODAL; + + (void)text; + + if (st->doplugins && texttool_text_is_active(st->text)) { + if (texttool_suggest_first()) tools |= TOOL_SUGG_LIST; + if (texttool_docs_get()) tools |= TOOL_DOCUMENT; + } + + switch (event->type) { + case LEFTMOUSE: + if (event->val == KM_PRESS) { + if (text_do_suggest_select(st, ar)) + swallow = 1; + else { + if (tools & TOOL_SUGG_LIST) texttool_suggest_clear(); + if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0; + retval = OPERATOR_FINISHED; + } + draw = 1; + } + break; + case MIDDLEMOUSE: + if (event->val == KM_PRESS) { + if (text_do_suggest_select(st, ar)) { + confirm_suggestion(st->text); + text_update_line_edited(st->text->curl); + swallow = 1; + } + else { + if (tools & TOOL_SUGG_LIST) texttool_suggest_clear(); + if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0; + retval = OPERATOR_FINISHED; + } + draw = 1; + } + break; + case ESCKEY: + if (event->val == KM_PRESS) { + draw = swallow = 1; + if (tools & TOOL_SUGG_LIST) texttool_suggest_clear(); + else if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0; + else draw = swallow = 0; + retval = OPERATOR_CANCELLED; + } + break; + case RETKEY: + if (event->val == KM_PRESS) { + if (tools & TOOL_SUGG_LIST) { + confirm_suggestion(st->text); + text_update_line_edited(st->text->curl); + swallow = 1; + draw = 1; + } + if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0, draw = 1; + retval = OPERATOR_FINISHED; + } + break; + case LEFTARROWKEY: + case BACKSPACEKEY: + if (event->val == KM_PRESS) { + if (tools & TOOL_SUGG_LIST) { + if (event->ctrl) { + texttool_suggest_clear(); + retval = OPERATOR_CANCELLED; + } + else { + /* Work out which char we are about to delete/pass */ + if (st->text->curl && st->text->curc > 0) { + char ch = st->text->curl->line[st->text->curc - 1]; + if ((ch == '_' || !ispunct(ch)) && !text_check_whitespace(ch)) { + get_suggest_prefix(st->text, -1); + text_pop_suggest_list(); + } + else { + texttool_suggest_clear(); + retval = OPERATOR_CANCELLED; + } + } + else { + texttool_suggest_clear(); + retval = OPERATOR_CANCELLED; + } + } + } + if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0; + } + break; + case RIGHTARROWKEY: + if (event->val == KM_PRESS) { + if (tools & TOOL_SUGG_LIST) { + if (event->ctrl) { + texttool_suggest_clear(); + retval = OPERATOR_CANCELLED; + } + else { + /* Work out which char we are about to pass */ + if (st->text->curl && st->text->curc < st->text->curl->len) { + char ch = st->text->curl->line[st->text->curc + 1]; + if ((ch == '_' || !ispunct(ch)) && !text_check_whitespace(ch)) { + get_suggest_prefix(st->text, 1); + text_pop_suggest_list(); + } + else { + texttool_suggest_clear(); + retval = OPERATOR_CANCELLED; + } + } + else { + texttool_suggest_clear(); + retval = OPERATOR_CANCELLED; + } + } + } + if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0; + } + break; + case PAGEDOWNKEY: + scroll = SUGG_LIST_SIZE - 1; + case WHEELDOWNMOUSE: + case DOWNARROWKEY: + if (event->val == KM_PRESS) { + if (tools & TOOL_DOCUMENT) { + doc_scroll++; + swallow = 1; + draw = 1; + } + else if (tools & TOOL_SUGG_LIST) { + SuggItem *sel = texttool_suggest_selected(); + if (!sel) { + texttool_suggest_select(texttool_suggest_first()); + } + else { + while (sel && sel != texttool_suggest_last() && sel->next && scroll--) { + texttool_suggest_select(sel->next); + sel = sel->next; + } + } + text_pop_suggest_list(); + swallow = 1; + draw = 1; + } + } + break; + case PAGEUPKEY: + scroll = SUGG_LIST_SIZE - 1; + case WHEELUPMOUSE: + case UPARROWKEY: + if (event->val == KM_PRESS) { + if (tools & TOOL_DOCUMENT) { + if (doc_scroll > 0) doc_scroll--; + swallow = 1; + draw = 1; + } + else if (tools & TOOL_SUGG_LIST) { + SuggItem *sel = texttool_suggest_selected(); + while (sel && sel != texttool_suggest_first() && sel->prev && scroll--) { + texttool_suggest_select(sel->prev); + sel = sel->prev; + } + text_pop_suggest_list(); + swallow = 1; + draw = 1; + } + } + break; + case RIGHTSHIFTKEY: + case LEFTSHIFTKEY: + break; +#if 0 + default: + if (tools & TOOL_SUGG_LIST) texttool_suggest_clear(), draw = 1; + if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0, draw = 1; +#endif + } + + if (draw) { + ED_area_tag_redraw(CTX_wm_area(C)); + } + +// if (swallow) { +// retval = OPERATOR_RUNNING_MODAL; +// } + + if (texttool_suggest_first()) { + if (retval != OPERATOR_RUNNING_MODAL) { + text_autocomplete_free(C, op); + } + return retval; + } + else { + text_autocomplete_free(C, op); + return OPERATOR_FINISHED; + } +} + +static void text_autocomplete_free(bContext *C, wmOperator *op) +{ + GHash *gh = op->customdata; + if (gh) { + BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN); + op->customdata = NULL; + } + + /* other stuff */ + { + SpaceText *st = CTX_wm_space_text(C); + st->doplugins = FALSE; + texttool_text_clear(); + } +} + +static int text_autocomplete_cancel(bContext *C, wmOperator *op) +{ + text_autocomplete_free(C, op); + return OPERATOR_CANCELLED; +} + +void TEXT_OT_autocomplete(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Text Auto Complete"; + ot->description = "Show a list of used text in the open document"; + ot->idname = "TEXT_OT_autocomplete"; + + /* api callbacks */ + ot->invoke = text_autocomplete_invoke; + ot->cancel = text_autocomplete_cancel; + ot->modal = text_autocomplete_modal; + ot->poll = text_space_edit_poll; + + /* flags */ + ot->flag = OPTYPE_BLOCKING; +} diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index 7d4c9e5af98..c264368e714 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -77,26 +77,17 @@ static int text_font_draw(SpaceText *UNUSED(st), int x, int y, const char *str) static int text_font_draw_character(SpaceText *st, int x, int y, char c) { - char str[2]; - str[0] = c; - str[1] = '\0'; - BLF_position(mono, x, y, 0); - BLF_draw(mono, str, 1); + BLF_draw(mono, &c, 1); return st->cwidth; } static int text_font_draw_character_utf8(SpaceText *st, int x, int y, const char *c) { - char str[BLI_UTF8_MAX + 1]; - size_t len = BLI_str_utf8_size_safe(c); - memcpy(str, c, len); - str[len] = '\0'; - + const size_t len = BLI_str_utf8_size_safe(c); BLF_position(mono, x, y, 0); - BLF_draw(mono, str, len); - + BLF_draw(mono, c, len); return st->cwidth; } @@ -117,27 +108,33 @@ static void txt_format_text(SpaceText *st) static void format_draw_color(char formatchar) { switch (formatchar) { - case '_': /* Whitespace */ + case FMT_TYPE_WHITESPACE: break; - case '!': /* Symbols */ - UI_ThemeColorBlend(TH_TEXT, TH_BACK, 0.5f); + case FMT_TYPE_SYMBOL: + UI_ThemeColor(TH_SYNTAX_S); break; - case '#': /* Comments */ + case FMT_TYPE_COMMENT: UI_ThemeColor(TH_SYNTAX_C); break; - case 'n': /* Numerals */ + case FMT_TYPE_NUMERAL: UI_ThemeColor(TH_SYNTAX_N); break; - case 'l': /* Strings */ + case FMT_TYPE_STRING: UI_ThemeColor(TH_SYNTAX_L); break; - case 'v': /* Specials: class, def */ + case FMT_TYPE_DIRECTIVE: + UI_ThemeColor(TH_SYNTAX_D); + break; + case FMT_TYPE_SPECIAL: UI_ThemeColor(TH_SYNTAX_V); break; - case 'b': /* Keywords: for, print, etc. */ + case FMT_TYPE_RESERVED: + UI_ThemeColor(TH_SYNTAX_R); + break; + case FMT_TYPE_KEYWORD: UI_ThemeColor(TH_SYNTAX_B); break; - case 'q': /* Other text (identifiers) */ + case FMT_TYPE_DEFAULT: default: UI_ThemeColor(TH_TEXT); break; @@ -359,6 +356,7 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w FlattenString fs; int basex, i, a, start, end, max, lines; /* view */ int mi, ma, mstart, mend; /* mem */ + char fmt_prev = 0xff; flatten_string(st, &fs, str); str = fs.buf; @@ -382,7 +380,9 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w /* Draw the visible portion of text on the overshot line */ for (a = start, ma = mstart; a < end; a++, ma += BLI_str_utf8_size_safe(str + ma)) { - if (st->showsyntax && format) format_draw_color(format[a]); + if (st->showsyntax && format) { + if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]); + } x += text_font_draw_character_utf8(st, x, y, str + ma); } y -= st->lheight_dpi + TXT_LINE_SPACING; @@ -400,8 +400,9 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w /* Draw the remaining text */ for (a = start, ma = mstart; str[ma] && y > 0; a++, ma += BLI_str_utf8_size_safe(str + ma)) { - if (st->showsyntax && format) - format_draw_color(format[a]); + if (st->showsyntax && format) { + if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]); + } x += text_font_draw_character_utf8(st, x, y, str + ma); } @@ -432,15 +433,18 @@ static int text_draw(SpaceText *st, char *str, int cshift, int maxwidth, int dra if (st->showsyntax && format) { int a, str_shift = 0; + char fmt_prev = 0xff; format = format + cshift; for (a = 0; a < amount; a++) { - format_draw_color(format[a]); + if (format[a] != fmt_prev) format_draw_color(fmt_prev = format[a]); x += text_font_draw_character_utf8(st, x, y, in + str_shift); str_shift += BLI_str_utf8_size_safe(in + str_shift); } } - else text_font_draw(st, x, y, in); + else { + text_font_draw(st, x, y, in); + } } else { while (w-- && *acc++ < maxwidth) @@ -890,7 +894,7 @@ static void draw_documentation(SpaceText *st, ARegion *ar) /* top = */ /* UNUSED */ y = ar->winy - st->lheight_dpi * l - 2; boxw = DOC_WIDTH * st->cwidth + 20; - boxh = (DOC_HEIGHT + 1) * st->lheight_dpi; + boxh = (DOC_HEIGHT + 1) * (st->lheight_dpi + TXT_LINE_SPACING); /* Draw panel */ UI_ThemeColor(TH_BACK); @@ -953,9 +957,11 @@ static void draw_suggestion_list(SpaceText *st, ARegion *ar) SuggItem *item, *first, *last, *sel; TextLine *tmp; char str[SUGG_LIST_WIDTH + 1]; - int w, boxw = 0, boxh, i, l, x, y, b, *top; + int w, boxw = 0, boxh, i, l, x, y, *top; + const int lheight = st->lheight_dpi + TXT_LINE_SPACING; + const int margin_x = 2; - if (!st || !st->text) return; + if (!st->text) return; if (!texttool_text_is_active(st->text)) return; first = texttool_suggest_first(); @@ -977,14 +983,20 @@ static void draw_suggestion_list(SpaceText *st, ARegion *ar) else { x = st->cwidth * (st->text->curc - st->left) + TXT_OFFSET - 4; } - y = ar->winy - st->lheight_dpi * l - 2; + /* offset back so the start of the text lines up with the suggestions, + * not essential but makes suggestions easier to follow */ + x -= st->cwidth * (st->text->curc - text_find_identifier_start(st->text->curl->line, st->text->curc)); + y = ar->winy - lheight * l - 2; boxw = SUGG_LIST_WIDTH * st->cwidth + 20; - boxh = SUGG_LIST_SIZE * st->lheight_dpi + 8; + boxh = SUGG_LIST_SIZE * lheight + 8; + /* not needed but stands out nicer */ + uiDrawBoxShadow(220, x, y - boxh, x + boxw, y); + UI_ThemeColor(TH_SHADE1); glRecti(x - 1, y + 1, x + boxw + 1, y - boxh - 1); - UI_ThemeColor(TH_BACK); + UI_ThemeColorShade(TH_BACK, 16); glRecti(x, y, x + boxw, y - boxh); /* Set the top 'item' of the visible list */ @@ -992,7 +1004,7 @@ static void draw_suggestion_list(SpaceText *st, ARegion *ar) for (i = 0; i < SUGG_LIST_SIZE && item; i++, item = item->next) { - y -= st->lheight_dpi; + y -= lheight; BLI_strncpy(str, item->name, SUGG_LIST_WIDTH); @@ -1000,21 +1012,11 @@ static void draw_suggestion_list(SpaceText *st, ARegion *ar) if (item == sel) { UI_ThemeColor(TH_SHADE2); - glRecti(x + 16, y - 3, x + 16 + w, y + st->lheight_dpi - 3); + glRecti(x + margin_x, y - 3, x + margin_x + w, y + lheight - 3); } - b = 1; /* b=1 color block, text is default. b=0 no block, color text */ - switch (item->type) { - case 'k': UI_ThemeColor(TH_SYNTAX_B); b = 0; break; - case 'm': UI_ThemeColor(TH_TEXT); break; - case 'f': UI_ThemeColor(TH_SYNTAX_L); break; - case 'v': UI_ThemeColor(TH_SYNTAX_N); break; - case '?': UI_ThemeColor(TH_TEXT); b = 0; break; - } - if (b) { - glRecti(x + 8, y + 2, x + 11, y + 5); - UI_ThemeColor(TH_TEXT); - } - text_draw(st, str, 0, 0, 1, x + 16, y - 1, NULL); + + format_draw_color(item->type); + text_draw(st, str, 0, 0, 1, x + margin_x, y - 1, NULL); if (item == last) break; } @@ -1027,7 +1029,7 @@ static void draw_cursor(SpaceText *st, ARegion *ar) Text *text = st->text; int vcurl, vcurc, vsell, vselc, hidden = 0; int x, y, w, i; - int lheight = st->lheight_dpi + TXT_LINE_SPACING; + const int lheight = st->lheight_dpi + TXT_LINE_SPACING; /* Draw the selection */ if (text->curl != text->sell || text->curc != text->selc) { @@ -1168,7 +1170,7 @@ static void draw_brackets(SpaceText *st, ARegion *ar) stack = 0; /* Don't highlight backets if syntax HL is off or bracket in string or comment. */ - if (!linep->format || linep->format[fc] == 'l' || linep->format[fc] == '#') + if (!linep->format || linep->format[fc] == FMT_TYPE_STRING || linep->format[fc] == FMT_TYPE_COMMENT) return; if (b > 0) { @@ -1177,7 +1179,7 @@ static void draw_brackets(SpaceText *st, ARegion *ar) c += BLI_str_utf8_size_safe(linep->line + c); while (linep) { while (c < linep->len) { - if (linep->format && linep->format[fc] != 'l' && linep->format[fc] != '#') { + if (linep->format && linep->format[fc] != FMT_TYPE_STRING && linep->format[fc] != FMT_TYPE_COMMENT) { b = text_check_bracket(linep->line[c]); if (b == find) { if (stack == 0) { @@ -1206,7 +1208,7 @@ static void draw_brackets(SpaceText *st, ARegion *ar) if (c > 0) c -= linep->line + c - BLI_str_prev_char_utf8(linep->line + c); while (linep) { while (fc >= 0) { - if (linep->format && linep->format[fc] != 'l' && linep->format[fc] != '#') { + if (linep->format && linep->format[fc] != FMT_TYPE_STRING && linep->format[fc] != FMT_TYPE_COMMENT) { b = text_check_bracket(linep->line[c]); if (b == find) { if (stack == 0) { @@ -1271,7 +1273,7 @@ static void draw_brackets(SpaceText *st, ARegion *ar) void draw_text_main(SpaceText *st, ARegion *ar) { Text *text = st->text; - TextFormatType *tft = ED_text_format_get(text); + TextFormatType *tft; TextLine *tmp; rcti scroll, back; char linenr[12]; @@ -1299,6 +1301,7 @@ void draw_text_main(SpaceText *st, ARegion *ar) calc_text_rcts(st, ar, &scroll, &back); /* scroll will hold the entire bar size */ /* update syntax formatting if needed */ + tft = ED_text_format_get(text); tmp = text->lines.first; lineno = 0; for (i = 0; i < st->top && tmp; i++) { diff --git a/source/blender/editors/space_text/text_format.c b/source/blender/editors/space_text/text_format.c index 0b3856f4414..294f94dd4b7 100644 --- a/source/blender/editors/space_text/text_format.c +++ b/source/blender/editors/space_text/text_format.c @@ -113,6 +113,14 @@ void flatten_string_free(FlattenString *fs) MEM_freeN(fs->accum); } +/* takes a string within fs->buf and returns its length */ +int flatten_string_strlen(FlattenString *fs, const char *str) +{ + const int len = (fs->pos - (int)(str - fs->buf)) - 1; + BLI_assert(strlen(str) == len); + return len; +} + /* Ensures the format string for the given line is long enough, reallocating * as needed. Allocation is done here, alone, to ensure consistency. */ int text_check_format_len(TextLine *line, unsigned int len) @@ -139,10 +147,16 @@ void ED_text_format_register(TextFormatType *tft) BLI_addtail(&tft_lb, tft); } -TextFormatType *ED_text_format_get(Text *UNUSED(text)) +TextFormatType *ED_text_format_get(Text *text) { /* NOTE: once more types are added we'll need to return some type based on 'text' * for now this function is more of a placeholder */ - return tft_lb.first; + /* XXX, wrong, but OK for testing */ + if (text && BLI_testextensie(text->id.name + 2, ".osl")) { + return tft_lb.last; + } + else { + return tft_lb.first; + } } diff --git a/source/blender/editors/space_text/text_format.h b/source/blender/editors/space_text/text_format.h index 7b5b326db6a..e593e41d42c 100644 --- a/source/blender/editors/space_text/text_format.h +++ b/source/blender/editors/space_text/text_format.h @@ -41,8 +41,24 @@ typedef struct FlattenString { int pos, len; } FlattenString; +/* format continuation flags (stored just after the NULL terminator) */ +enum { + FMT_CONT_NOP = 0, /* no continuation */ + FMT_CONT_QUOTESINGLE = (1 << 0), /* single quotes */ + FMT_CONT_QUOTEDOUBLE = (1 << 1), /* double quotes */ + FMT_CONT_TRIPLE = (1 << 2), /* triplets of quotes: """ or ''' */ + FMT_CONT_QUOTESINGLE_TRIPLE = (FMT_CONT_TRIPLE | FMT_CONT_QUOTESINGLE), + FMT_CONT_QUOTEDOUBLE_TRIPLE = (FMT_CONT_TRIPLE | FMT_CONT_QUOTEDOUBLE), + FMT_CONT_COMMENT_C = (1 << 3), /* multi-line comments, OSL only (C style) */ + FMT_CONT_COMMENT_CXX = (1 << 4), /* single-line comments, OSL only (C++ style) */ +}; +#define FMT_CONT_ALL \ + (FMT_CONT_QUOTESINGLE | FMT_CONT_QUOTEDOUBLE | FMT_CONT_TRIPLE | FMT_CONT_COMMENT_C | FMT_CONT_COMMENT_CXX) + int flatten_string(struct SpaceText *st, FlattenString *fs, const char *in); void flatten_string_free(FlattenString *fs); +int flatten_string_strlen(FlattenString *fs, const char *str); + int text_check_format_len(TextLine *line, unsigned int len); @@ -50,28 +66,43 @@ int text_check_format_len(TextLine *line, unsigned int len); typedef struct TextFormatType { struct TextFormatType *next, *prev; + char (*format_identifier)(const char *string); + /* Formats the specified line. If do_next is set, the process will move on to * the succeeding line if it is affected (eg. multiline strings). Format strings * may contain any of the following characters: - * '_' Whitespace - * '#' Comment text - * '!' Punctuation and other symbols - * 'n' Numerals - * 'l' String letters - * 'v' Special variables (class, def) - * 'b' Built-in names (print, for, etc.) - * 'q' Other text (identifiers, etc.) + * * It is terminated with a null-terminator '\0' followed by a continuation - * flag indicating whether the line is part of a multi-line string. */ + * flag indicating whether the line is part of a multi-line string. + * + * See: FMT_TYPE_ enums below + */ void (*format_line)(SpaceText *st, TextLine *line, int do_next); const char **ext; /* NULL terminated extensions */ } TextFormatType; +enum { + FMT_TYPE_WHITESPACE = '_', /* Whitespace */ + FMT_TYPE_COMMENT = '#', /* Comment text */ + FMT_TYPE_SYMBOL = '!', /* Punctuation and other symbols */ + FMT_TYPE_NUMERAL = 'n', /* Numerals */ + FMT_TYPE_STRING = 'l', /* String letters */ + FMT_TYPE_DIRECTIVE = 'd', /* Decorator / Preprocessor directive */ + FMT_TYPE_SPECIAL = 'v', /* Special variables (class, def) */ + FMT_TYPE_RESERVED = 'r', /* Reserved keywords currently not in use, but still prohibited (OSL -> switch e.g.) */ + FMT_TYPE_KEYWORD = 'b', /* Built-in names (return, for, etc.) */ + FMT_TYPE_DEFAULT = 'q', /* Regular text (identifiers, etc.) */ +}; + TextFormatType *ED_text_format_get(Text *text); void ED_text_format_register(TextFormatType *tft); /* formatters */ void ED_text_format_register_py(void); +void ED_text_format_register_osl(void); + +#define STR_LITERAL_STARTSWITH(str, str_literal, len_var) \ + (strncmp(str, str_literal, len_var = (sizeof(str_literal) - 1)) == 0) #endif /* __TEXT_FORMAT_H__ */ diff --git a/source/blender/editors/space_text/text_format_osl.c b/source/blender/editors/space_text/text_format_osl.c new file mode 100644 index 00000000000..3120e88163e --- /dev/null +++ b/source/blender/editors/space_text/text_format_osl.c @@ -0,0 +1,335 @@ +/* + * ***** 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 + * 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) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_text/text_format_osl.c + * \ingroup sptext + */ + +#include <string.h> + +#include "BLI_blenlib.h" + +#include "DNA_text_types.h" +#include "DNA_space_types.h" + +#include "BKE_text.h" + +#include "text_format.h" + +/* *** Local Functions (for format_line) *** */ + +static int txtfmt_osl_find_builtinfunc(const char *string) +{ + int i, len; + /* list is from + * https://github.com/imageworks/OpenShadingLanguage/raw/master/src/doc/osl-languagespec.pdf + */ + if (STR_LITERAL_STARTSWITH(string, "break", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "closure", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "color", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "continue", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "do", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "else", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "emit", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "float", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "for", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "if", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "illuminance", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "illuminate", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "int", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "matrix", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "normal", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "output", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "point", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "public", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "return", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "string", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "struct", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "vector", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "void", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "while", len)) i = len; + else i = 0; + + /* If next source char is an identifier (eg. 'i' in "definate") no match */ + if (i == 0 || text_check_identifier(string[i])) + return -1; + return i; +} + +static int txtfmt_osl_find_reserved(const char *string) +{ + int i, len; + /* list is from... + * https://github.com/imageworks/OpenShadingLanguage/raw/master/src/doc/osl-languagespec.pdf + */ + if (STR_LITERAL_STARTSWITH(string, "bool", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "case", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "catch", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "char", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "const", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "delete", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "default", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "double", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "enum", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "extern", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "false", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "friend", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "goto", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "inline", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "long", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "new", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "operator", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "private", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "protected", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "short", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "signed", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sizeof", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "static", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "switch", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "template", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "this", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "throw", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "true", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "try", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "typedef", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "uniform", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "union", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "unsigned", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "varying", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "virtual", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "volatile", len)) i = len; + else i = 0; + + /* If next source char is an identifier (eg. 'i' in "definate") no match */ + if (i == 0 || text_check_identifier(string[i])) + return -1; + return i; +} + +/* Checks the specified source string for a OSL special name. This name must + * start at the beginning of the source string and must be followed by a non- + * identifier (see text_check_identifier(char)) or null character. + * + * If a special name is found, the length of the matching name is returned. + * Otherwise, -1 is returned. */ + +static int txtfmt_osl_find_specialvar(const char *string) +{ + int i, len; + + /* OSL shader types */ + if (STR_LITERAL_STARTSWITH(string, "shader", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "surface", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "volume", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "displacement", len)) i = len; + else i = 0; + + /* If next source char is an identifier (eg. 'i' in "definate") no match */ + if (i == 0 || text_check_identifier(string[i])) + return -1; + return i; +} + +/* matches py 'txtfmt_osl_find_decorator' */ +static int txtfmt_osl_find_preprocessor(const char *string) +{ + if (string[0] == '#') { + int i = 1; + /* Whitespace is ok '# foo' */ + while (text_check_whitespace(string[i])) { + i++; + } + while (text_check_identifier(string[i])) { + i++; + } + return i; + } + return -1; +} + +static char txtfmt_osl_format_identifier(const char *str) +{ + char fmt; + if ((txtfmt_osl_find_specialvar(str)) != -1) fmt = FMT_TYPE_SPECIAL; + else if ((txtfmt_osl_find_builtinfunc(str)) != -1) fmt = FMT_TYPE_KEYWORD; + else if ((txtfmt_osl_find_reserved(str)) != -1) fmt = FMT_TYPE_RESERVED; + else if ((txtfmt_osl_find_preprocessor(str)) != -1) fmt = FMT_TYPE_DIRECTIVE; + else fmt = FMT_TYPE_DEFAULT; + return fmt; +} + +static void txtfmt_osl_format_line(SpaceText *st, TextLine *line, const int do_next) +{ + FlattenString fs; + const char *str; + char *fmt; + char cont_orig, cont, find, prev = ' '; + int len, i; + + /* Get continuation from previous line */ + if (line->prev && line->prev->format != NULL) { + fmt = line->prev->format; + cont = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */ + BLI_assert((FMT_CONT_ALL & cont) == cont); + } + else { + cont = FMT_CONT_NOP; + } + + /* Get original continuation from this line */ + if (line->format != NULL) { + fmt = line->format; + cont_orig = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */ + BLI_assert((FMT_CONT_ALL & cont_orig) == cont_orig); + } + else { + cont_orig = 0xFF; + } + + len = flatten_string(st, &fs, line->line); + str = fs.buf; + if (!text_check_format_len(line, len)) { + flatten_string_free(&fs); + return; + } + fmt = line->format; + + while (*str) { + /* Handle escape sequences by skipping both \ and next char */ + if (*str == '\\') { + *fmt = prev; fmt++; str++; + if (*str == '\0') break; + *fmt = prev; fmt++; str += BLI_str_utf8_size_safe(str); + continue; + } + /* Handle continuations */ + else if (cont) { + /* C-Style comments */ + if (cont & FMT_CONT_COMMENT_CXX) { + *fmt = FMT_TYPE_COMMENT; + } + else if (cont & FMT_CONT_COMMENT_C) { + if (*str == '*' && *(str + 1) == '/') { + *fmt = FMT_TYPE_COMMENT; fmt++; str++; + *fmt = FMT_TYPE_COMMENT; + cont = FMT_CONT_NOP; + } + else { + *fmt = FMT_TYPE_COMMENT; + } + /* Handle other comments */ + } + else { + find = (cont & FMT_CONT_QUOTEDOUBLE) ? '"' : '\''; + if (*str == find) cont = 0; + *fmt = FMT_TYPE_STRING; + } + + str += BLI_str_utf8_size_safe(str) - 1; + } + /* Not in a string... */ + else { + /* Deal with comments first */ + if (*str == '/' && *(str + 1) == '/') { + cont = FMT_CONT_COMMENT_CXX; + *fmt = FMT_TYPE_COMMENT; + } + /* C-Style (multi-line) comments */ + else if (*str == '/' && *(str + 1) == '*') { + cont = FMT_CONT_COMMENT_C; + *fmt = FMT_TYPE_COMMENT; fmt++; str++; + *fmt = FMT_TYPE_COMMENT; + } + else if (*str == '"' || *str == '\'') { + /* Strings */ + find = *str; + cont = (*str == '"') ? FMT_CONT_QUOTEDOUBLE : FMT_CONT_QUOTESINGLE; + *fmt = FMT_TYPE_STRING; + } + /* Whitespace (all ws. has been converted to spaces) */ + else if (*str == ' ') { + *fmt = FMT_TYPE_WHITESPACE; + } + /* Numbers (digits not part of an identifier and periods followed by digits) */ + else if ((prev != FMT_TYPE_DEFAULT && text_check_digit(*str)) || + (*str == '.' && text_check_digit(*(str + 1)))) + { + *fmt = FMT_TYPE_NUMERAL; + } + /* Punctuation */ + else if ((*str != '#') && text_check_delim(*str)) { + *fmt = FMT_TYPE_SYMBOL; + } + /* Identifiers and other text (no previous ws. or delims. so text continues) */ + else if (prev == FMT_TYPE_DEFAULT) { + str += BLI_str_utf8_size_safe(str) - 1; + *fmt = FMT_TYPE_DEFAULT; + } + /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */ + else { + /* Special vars(v) or built-in keywords(b) */ + /* keep in sync with 'txtfmt_osl_format_identifier()' */ + if ((i = txtfmt_osl_find_specialvar(str)) != -1) prev = FMT_TYPE_SPECIAL; + else if ((i = txtfmt_osl_find_builtinfunc(str)) != -1) prev = FMT_TYPE_KEYWORD; + else if ((i = txtfmt_osl_find_reserved(str)) != -1) prev = FMT_TYPE_RESERVED; + else if ((i = txtfmt_osl_find_preprocessor(str)) != -1) prev = FMT_TYPE_DIRECTIVE; + + if (i > 0) { + memset(fmt, prev, i); + i--; fmt += i; str += i; + } + else { + str += BLI_str_utf8_size_safe(str) - 1; + *fmt = FMT_TYPE_DEFAULT; + } + } + } + prev = *fmt; fmt++; str++; + } + + /* Terminate and add continuation char */ + *fmt = '\0'; fmt++; + *fmt = cont; + + /* If continuation has changed and we're allowed, process the next line */ + if (cont != cont_orig && do_next && line->next) { + txtfmt_osl_format_line(st, line->next, do_next); + } + + flatten_string_free(&fs); +} + +void ED_text_format_register_osl(void) +{ + static TextFormatType tft = {0}; + static const char *ext[] = {"osl", NULL}; + + tft.format_identifier = txtfmt_osl_format_identifier; + tft.format_line = txtfmt_osl_format_line; + tft.ext = ext; + + ED_text_format_register(&tft); +} diff --git a/source/blender/editors/space_text/text_format_py.c b/source/blender/editors/space_text/text_format_py.c index 2a0f483d80c..cbccc6a770f 100644 --- a/source/blender/editors/space_text/text_format_py.c +++ b/source/blender/editors/space_text/text_format_py.c @@ -41,7 +41,6 @@ /* *** Local Functions (for format_line) *** */ - /* Checks the specified source string for a Python built-in function name. This * name must start at the beginning of the source string and must be followed by * a non-identifier (see text_check_identifier(char)) or null character. @@ -53,38 +52,53 @@ * http://docs.python.org/py3k/reference/lexical_analysis.html#keywords */ -static int txtfmt_py_find_builtinfunc(char *string) +static int txtfmt_py_find_builtinfunc(const char *string) { - int a, i; - const char *builtinfuncs[] = { - /* "False", "None", "True", */ /* see find_bool() */ - "and", "as", "assert", "break", - "class", "continue", "def", "del", "elif", "else", "except", - "finally", "for", "from", "global", "if", "import", "in", - "is", "lambda", "nonlocal", "not", "or", "pass", "raise", - "return", "try", "while", "with", "yield", - }; - - for (a = 0; a < sizeof(builtinfuncs) / sizeof(builtinfuncs[0]); a++) { - i = 0; - while (1) { - /* If we hit the end of a keyword... (eg. "def") */ - if (builtinfuncs[a][i] == '\0') { - /* If we still have identifier chars in the source (eg. "definate") */ - if (text_check_identifier(string[i])) - i = -1; /* No match */ - break; /* Next keyword if no match, otherwise we're done */ - - /* If chars mismatch, move on to next keyword */ - } - else if (string[i] != builtinfuncs[a][i]) { - i = -1; - break; /* Break inner loop, start next keyword */ - } - i++; - } - if (i > 0) break; /* If we have a match, we're done */ - } + int i, len; + /* list is from... + * ", ".join(['"%s"' % kw + * for kw in __import__("keyword").kwlist + * if kw not in {"False", "None", "True", "def", "class"}]) + * + * ... and for this code: + * print("\n".join(['else if (STR_LITERAL_STARTSWITH(string, "%s", len)) i = len;' % kw + * for kw in __import__("keyword").kwlist + * if kw not in {"False", "None", "True", "def", "class"}])) + */ + + if (STR_LITERAL_STARTSWITH(string, "and", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "as", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "assert", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "break", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "continue", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "del", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "elif", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "else", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "except", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "finally", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "for", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "from", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "global", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "if", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "import", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "in", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "is", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "lambda", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "nonlocal", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "not", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "or", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "pass", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "raise", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "return", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "try", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "while", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "with", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "yield", len)) i = len; + else i = 0; + + /* If next source char is an identifier (eg. 'i' in "definate") no match */ + if (i == 0 || text_check_identifier(string[i])) + return -1; return i; } @@ -95,25 +109,28 @@ static int txtfmt_py_find_builtinfunc(char *string) * If a special name is found, the length of the matching name is returned. * Otherwise, -1 is returned. */ -static int txtfmt_py_find_specialvar(char *string) +static int txtfmt_py_find_specialvar(const char *string) { - int i = 0; - /* Check for "def" */ - if (string[0] == 'd' && string[1] == 'e' && string[2] == 'f') - i = 3; - /* Check for "class" */ - else if (string[0] == 'c' && string[1] == 'l' && string[2] == 'a' && string[3] == 's' && string[4] == 's') - i = 5; + int i, len; + + if (STR_LITERAL_STARTSWITH(string, "def", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "class", len)) i = len; + else i = 0; + /* If next source char is an identifier (eg. 'i' in "definate") no match */ if (i == 0 || text_check_identifier(string[i])) return -1; return i; } -static int txtfmt_py_find_decorator(char *string) +static int txtfmt_py_find_decorator(const char *string) { if (string[0] == '@') { int i = 1; + /* Whitespace is ok '@ foo' */ + while (text_check_whitespace(string[i])) { + i++; + } while (text_check_identifier(string[i])) { i++; } @@ -122,46 +139,57 @@ static int txtfmt_py_find_decorator(char *string) return -1; } -static int txtfmt_py_find_bool(char *string) +static int txtfmt_py_find_bool(const char *string) { - int i = 0; - /* Check for "False" */ - if (string[0] == 'F' && string[1] == 'a' && string[2] == 'l' && string[3] == 's' && string[4] == 'e') - i = 5; - /* Check for "True" */ - else if (string[0] == 'T' && string[1] == 'r' && string[2] == 'u' && string[3] == 'e') - i = 4; - /* Check for "None" */ - else if (string[0] == 'N' && string[1] == 'o' && string[2] == 'n' && string[3] == 'e') - i = 4; - /* If next source char is an identifier (eg. 'i' in "definate") no match */ + int i, len; + + if (STR_LITERAL_STARTSWITH(string, "None", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "True", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "False", len)) i = len; + else i = 0; + + /* If next source char is an identifier (eg. 'i' in "Nonetheless") no match */ if (i == 0 || text_check_identifier(string[i])) return -1; return i; } -static void txtfmt_py_format_line(SpaceText *st, TextLine *line, int do_next) +static char txtfmt_py_format_identifier(const char *str) +{ + char fmt; + if ((txtfmt_py_find_specialvar(str)) != -1) fmt = FMT_TYPE_SPECIAL; + else if ((txtfmt_py_find_builtinfunc(str)) != -1) fmt = FMT_TYPE_KEYWORD; + else if ((txtfmt_py_find_decorator(str)) != -1) fmt = FMT_TYPE_RESERVED; + else fmt = FMT_TYPE_DEFAULT; + return fmt; +} + +static void txtfmt_py_format_line(SpaceText *st, TextLine *line, const int do_next) { FlattenString fs; - char *str, *fmt, orig, cont, find, prev = ' '; + const char *str; + char *fmt; + char cont_orig, cont, find, prev = ' '; int len, i; /* Get continuation from previous line */ if (line->prev && line->prev->format != NULL) { fmt = line->prev->format; cont = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */ + BLI_assert((FMT_CONT_ALL & cont) == cont); } else { - cont = 0; + cont = FMT_CONT_NOP; } /* Get original continuation from this line */ if (line->format != NULL) { fmt = line->format; - orig = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */ + cont_orig = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */ + BLI_assert((FMT_CONT_ALL & cont_orig) == cont_orig); } else { - orig = 0xFF; + cont_orig = 0xFF; } len = flatten_string(st, &fs, line->line); @@ -183,93 +211,90 @@ static void txtfmt_py_format_line(SpaceText *st, TextLine *line, int do_next) /* Handle continuations */ else if (cont) { /* Triple strings ("""...""" or '''...''') */ - if (cont & TXT_TRISTR) { - find = (cont & TXT_DBLQUOTSTR) ? '"' : '\''; + if (cont & FMT_CONT_TRIPLE) { + find = (cont & FMT_CONT_QUOTEDOUBLE) ? '"' : '\''; if (*str == find && *(str + 1) == find && *(str + 2) == find) { - *fmt = 'l'; fmt++; str++; - *fmt = 'l'; fmt++; str++; - cont = 0; + *fmt = FMT_TYPE_STRING; fmt++; str++; + *fmt = FMT_TYPE_STRING; fmt++; str++; + cont = FMT_CONT_NOP; } /* Handle other strings */ } else { - find = (cont & TXT_DBLQUOTSTR) ? '"' : '\''; - if (*str == find) cont = 0; + find = (cont & FMT_CONT_QUOTEDOUBLE) ? '"' : '\''; + if (*str == find) cont = FMT_CONT_NOP; } - *fmt = 'l'; + *fmt = FMT_TYPE_STRING; str += BLI_str_utf8_size_safe(str) - 1; } /* Not in a string... */ else { /* Deal with comments first */ - if (prev == '#' || *str == '#') { - *fmt = '#'; + if (prev == FMT_TYPE_COMMENT || *str == '#') { + *fmt = FMT_TYPE_COMMENT; str += BLI_str_utf8_size_safe(str) - 1; } else if (*str == '"' || *str == '\'') { /* Strings */ find = *str; - cont = (*str == '"') ? TXT_DBLQUOTSTR : TXT_SNGQUOTSTR; + cont = (*str == '"') ? FMT_CONT_QUOTEDOUBLE : FMT_CONT_QUOTESINGLE; if (*(str + 1) == find && *(str + 2) == find) { - *fmt = 'l'; fmt++; str++; - *fmt = 'l'; fmt++; str++; - cont |= TXT_TRISTR; + *fmt = FMT_TYPE_STRING; fmt++; str++; + *fmt = FMT_TYPE_STRING; fmt++; str++; + cont |= FMT_CONT_TRIPLE; } - *fmt = 'l'; + *fmt = FMT_TYPE_STRING; } /* Whitespace (all ws. has been converted to spaces) */ - else if (*str == ' ') - *fmt = '_'; + else if (*str == ' ') { + *fmt = FMT_TYPE_WHITESPACE; + } /* Numbers (digits not part of an identifier and periods followed by digits) */ - else if ((prev != 'q' && text_check_digit(*str)) || (*str == '.' && text_check_digit(*(str + 1)))) - *fmt = 'n'; + else if ((prev != FMT_TYPE_DEFAULT && text_check_digit(*str)) || + (*str == '.' && text_check_digit(*(str + 1)))) + { + *fmt = FMT_TYPE_NUMERAL; + } /* Booleans */ - else if (prev != 'q' && (i = txtfmt_py_find_bool(str)) != -1) + else if (prev != FMT_TYPE_DEFAULT && (i = txtfmt_py_find_bool(str)) != -1) { if (i > 0) { - while (i > 1) { - *fmt = 'n'; fmt++; str++; - i--; - } - *fmt = 'n'; + memset(fmt, FMT_TYPE_NUMERAL, i); + i--; fmt += i; str += i; } else { str += BLI_str_utf8_size_safe(str) - 1; - *fmt = 'q'; + *fmt = FMT_TYPE_DEFAULT; } + } /* Punctuation */ - else if (text_check_delim(*str)) - *fmt = '!'; + else if ((*str != '@') && text_check_delim(*str)) { + *fmt = FMT_TYPE_SYMBOL; + } /* Identifiers and other text (no previous ws. or delims. so text continues) */ - else if (prev == 'q') { + else if (prev == FMT_TYPE_DEFAULT) { str += BLI_str_utf8_size_safe(str) - 1; - *fmt = 'q'; + *fmt = FMT_TYPE_DEFAULT; } /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */ else { /* Special vars(v) or built-in keywords(b) */ - if ((i = txtfmt_py_find_specialvar(str)) != -1) - prev = 'v'; - else if ((i = txtfmt_py_find_builtinfunc(str)) != -1) - prev = 'b'; - else if ((i = txtfmt_py_find_decorator(str)) != -1) - prev = 'v'; /* could have a new color for this */ + /* keep in sync with 'txtfmt_py_format_identifier()' */ + if ((i = txtfmt_py_find_specialvar(str)) != -1) prev = FMT_TYPE_SPECIAL; + else if ((i = txtfmt_py_find_builtinfunc(str)) != -1) prev = FMT_TYPE_KEYWORD; + else if ((i = txtfmt_py_find_decorator(str)) != -1) prev = FMT_TYPE_DIRECTIVE; + if (i > 0) { - while (i > 1) { - *fmt = prev; fmt++; str++; - i--; - } - *fmt = prev; + memset(fmt, prev, i); + i--; fmt += i; str += i; } else { str += BLI_str_utf8_size_safe(str) - 1; - *fmt = 'q'; + *fmt = FMT_TYPE_DEFAULT; } } } - prev = *fmt; - fmt++; - str++; + prev = *fmt; fmt++; str++; } /* Terminate and add continuation char */ @@ -277,7 +302,7 @@ static void txtfmt_py_format_line(SpaceText *st, TextLine *line, int do_next) *fmt = cont; /* If continuation has changed and we're allowed, process the next line */ - if (cont != orig && do_next && line->next) { + if (cont != cont_orig && do_next && line->next) { txtfmt_py_format_line(st, line->next, do_next); } @@ -289,7 +314,8 @@ void ED_text_format_register_py(void) static TextFormatType tft = {0}; static const char *ext[] = {"py", NULL}; - tft.format_line = txtfmt_py_format_line; + tft.format_identifier = txtfmt_py_format_identifier; + tft.format_line = txtfmt_py_format_line; tft.ext = ext; ED_text_format_register(&tft); diff --git a/source/blender/editors/space_text/text_intern.h b/source/blender/editors/space_text/text_intern.h index c7f9512737f..799bc49b624 100644 --- a/source/blender/editors/space_text/text_intern.h +++ b/source/blender/editors/space_text/text_intern.h @@ -143,6 +143,11 @@ void TEXT_OT_to_3d_object(struct wmOperatorType *ot); void TEXT_OT_resolve_conflict(struct wmOperatorType *ot); +int text_space_edit_poll(struct bContext *C); + +/* text_autocomplete.c */ +void TEXT_OT_autocomplete(struct wmOperatorType *ot); + /* space_text.c */ extern const char *text_context_dir[]; /* doc access */ diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index 01041c0e385..21966ef614c 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -98,7 +98,7 @@ static int text_edit_poll(bContext *C) return 1; } -static int text_space_edit_poll(bContext *C) +int text_space_edit_poll(bContext *C) { SpaceText *st = CTX_wm_space_text(C); Text *text = CTX_data_edit_text(C); @@ -1931,6 +1931,8 @@ static int text_jump_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) void TEXT_OT_jump(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Jump"; ot->idname = "TEXT_OT_jump"; @@ -1942,7 +1944,8 @@ void TEXT_OT_jump(wmOperatorType *ot) ot->poll = text_edit_poll; /* properties */ - RNA_def_int(ot->srna, "line", 1, 1, INT_MAX, "Line", "Line number to jump to", 1, 10000); + prop = RNA_def_int(ot->srna, "line", 1, 1, INT_MAX, "Line", "Line number to jump to", 1, 10000); + RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_TEXT); } /******************* delete operator **********************/ diff --git a/source/blender/editors/space_text/text_python.c b/source/blender/editors/space_text/text_python.c deleted file mode 100644 index 1201302dad0..00000000000 --- a/source/blender/editors/space_text/text_python.c +++ /dev/null @@ -1,358 +0,0 @@ -/* - * ***** 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) 2008 Blender Foundation. - * All rights reserved. - * - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/space_text/text_python.c - * \ingroup sptext - */ - -#include <ctype.h> - -#include "DNA_screen_types.h" -#include "DNA_space_types.h" -#include "DNA_text_types.h" -#include "DNA_userdef_types.h" - -#include "BKE_suggestions.h" -#include "BKE_text.h" - -#include "BLI_blenlib.h" - -#include "WM_types.h" - -#include "text_intern.h" - -int text_do_suggest_select(SpaceText *st, ARegion *ar) -{ - SuggItem *item, *first, *last /* , *sel */ /* UNUSED */; - TextLine *tmp; - int l, x, y, w, h, i; - int tgti, *top; - int mval[2] = {0, 0}; - - if (!st || !st->text) return 0; - if (!texttool_text_is_active(st->text)) return 0; - - first = texttool_suggest_first(); - last = texttool_suggest_last(); - /* sel = texttool_suggest_selected(); */ /* UNUSED */ - top = texttool_suggest_top(); - - if (!last || !first) - return 0; - - /* Count the visible lines to the cursor */ - for (tmp = st->text->curl, l = -st->top; tmp; tmp = tmp->prev, l++) ; - if (l < 0) return 0; - - text_update_character_width(st); - - if (st->showlinenrs) { - x = st->cwidth * (st->text->curc - st->left) + TXT_OFFSET + TEXTXLOC - 4; - } - else { - x = st->cwidth * (st->text->curc - st->left) + TXT_OFFSET - 4; - } - y = ar->winy - st->lheight_dpi * l - 2; - - w = SUGG_LIST_WIDTH * st->cwidth + U.widget_unit; - h = SUGG_LIST_SIZE * st->lheight_dpi + 0.4f * U.widget_unit; - - // XXX getmouseco_areawin(mval); - - if (mval[0] < x || x + w < mval[0] || mval[1] < y - h || y < mval[1]) - return 0; - - /* Work out which of the items is at the top of the visible list */ - for (i = 0, item = first; i < *top && item->next; i++, item = item->next) ; - - /* Work out the target item index in the visible list */ - tgti = (y - mval[1] - 4) / st->lheight_dpi; - if (tgti < 0 || tgti > SUGG_LIST_SIZE) - return 1; - - for (i = tgti; i > 0 && item->next; i--, item = item->next) ; - if (item) - texttool_suggest_select(item); - return 1; -} - -void text_pop_suggest_list(void) -{ - SuggItem *item, *sel; - int *top, i; - - item = texttool_suggest_first(); - sel = texttool_suggest_selected(); - top = texttool_suggest_top(); - - i = 0; - while (item && item != sel) { - item = item->next; - i++; - } - if (i > *top + SUGG_LIST_SIZE - 1) - *top = i - SUGG_LIST_SIZE + 1; - else if (i < *top) - *top = i; -} - -static void get_suggest_prefix(Text *text, int offset) -{ - int i, len; - char *line, tmp[256]; - - if (!text) return; - if (!texttool_text_is_active(text)) return; - - line = text->curl->line; - for (i = text->curc - 1 + offset; i >= 0; i--) - if (!text_check_identifier(line[i])) - break; - i++; - len = text->curc - i + offset; - if (len > 255) { - printf("Suggestion prefix too long\n"); - len = 255; - } - BLI_strncpy(tmp, line + i, len); - tmp[len] = '\0'; - texttool_suggest_prefix(tmp); -} - -static void confirm_suggestion(Text *text, int skipleft) -{ - SuggItem *sel; - int i, over = 0; - char *line; - - if (!text) return; - if (!texttool_text_is_active(text)) return; - - sel = texttool_suggest_selected(); - if (!sel) return; - - line = text->curl->line; - i = text->curc - skipleft - 1; - while (i >= 0) { - if (!text_check_identifier(line[i])) - break; - over++; - i--; - } - - for (i = 0; i < skipleft; i++) - txt_move_left(text, 0); - for (i = 0; i < over; i++) - txt_move_left(text, 1); - - txt_insert_buf(text, sel->name); - - for (i = 0; i < skipleft; i++) - txt_move_right(text, 0); - - texttool_text_clear(); -} - -// XXX -#define LR_SHIFTKEY 0 -#define LR_ALTKEY 0 -#define LR_CTRLKEY 0 - -// XXX -static int doc_scroll = 0; - -static short UNUSED_FUNCTION(do_texttools) (SpaceText * st, char ascii, unsigned short evnt, short val) -{ - ARegion *ar = NULL; // XXX - int qual = 0; // XXX - int draw = 0, tools = 0, swallow = 0, scroll = 1; - if (!texttool_text_is_active(st->text)) return 0; - if (!st->text || st->text->id.lib) return 0; - - if (st->doplugins && texttool_text_is_active(st->text)) { - if (texttool_suggest_first()) tools |= TOOL_SUGG_LIST; - if (texttool_docs_get()) tools |= TOOL_DOCUMENT; - } - - if (ascii) { - if (tools & TOOL_SUGG_LIST) { - if ((ascii != '_' && ascii != '*' && ispunct(ascii)) || text_check_whitespace(ascii)) { - confirm_suggestion(st->text, 0); - text_update_line_edited(st->text->curl); - } - else if ((st->overwrite && txt_replace_char(st->text, ascii)) || txt_add_char(st->text, ascii)) { - get_suggest_prefix(st->text, 0); - text_pop_suggest_list(); - swallow = 1; - draw = 1; - } - } - if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0, draw = 1; - - } - else if (val == 1 && evnt) { - switch (evnt) { - case LEFTMOUSE: - if (text_do_suggest_select(st, ar)) - swallow = 1; - else { - if (tools & TOOL_SUGG_LIST) texttool_suggest_clear(); - if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0; - } - draw = 1; - break; - case MIDDLEMOUSE: - if (text_do_suggest_select(st, ar)) { - confirm_suggestion(st->text, 0); - text_update_line_edited(st->text->curl); - swallow = 1; - } - else { - if (tools & TOOL_SUGG_LIST) texttool_suggest_clear(); - if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0; - } - draw = 1; - break; - case ESCKEY: - draw = swallow = 1; - if (tools & TOOL_SUGG_LIST) texttool_suggest_clear(); - else if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0; - else draw = swallow = 0; - break; - case RETKEY: - if (tools & TOOL_SUGG_LIST) { - confirm_suggestion(st->text, 0); - text_update_line_edited(st->text->curl); - swallow = 1; - draw = 1; - } - if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0, draw = 1; - break; - case LEFTARROWKEY: - case BACKSPACEKEY: - if (tools & TOOL_SUGG_LIST) { - if (qual) - texttool_suggest_clear(); - else { - /* Work out which char we are about to delete/pass */ - if (st->text->curl && st->text->curc > 0) { - char ch = st->text->curl->line[st->text->curc - 1]; - if ((ch == '_' || !ispunct(ch)) && !text_check_whitespace(ch)) { - get_suggest_prefix(st->text, -1); - text_pop_suggest_list(); - } - else - texttool_suggest_clear(); - } - else - texttool_suggest_clear(); - } - } - if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0; - break; - case RIGHTARROWKEY: - if (tools & TOOL_SUGG_LIST) { - if (qual) - texttool_suggest_clear(); - else { - /* Work out which char we are about to pass */ - if (st->text->curl && st->text->curc < st->text->curl->len) { - char ch = st->text->curl->line[st->text->curc + 1]; - if ((ch == '_' || !ispunct(ch)) && !text_check_whitespace(ch)) { - get_suggest_prefix(st->text, 1); - text_pop_suggest_list(); - } - else - texttool_suggest_clear(); - } - else - texttool_suggest_clear(); - } - } - if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0; - break; - case PAGEDOWNKEY: - scroll = SUGG_LIST_SIZE - 1; - case WHEELDOWNMOUSE: - case DOWNARROWKEY: - if (tools & TOOL_DOCUMENT) { - doc_scroll++; - swallow = 1; - draw = 1; - break; - } - else if (tools & TOOL_SUGG_LIST) { - SuggItem *sel = texttool_suggest_selected(); - if (!sel) { - texttool_suggest_select(texttool_suggest_first()); - } - else { - while (sel && sel != texttool_suggest_last() && sel->next && scroll--) { - texttool_suggest_select(sel->next); - sel = sel->next; - } - } - text_pop_suggest_list(); - swallow = 1; - draw = 1; - break; - } - case PAGEUPKEY: - scroll = SUGG_LIST_SIZE - 1; - case WHEELUPMOUSE: - case UPARROWKEY: - if (tools & TOOL_DOCUMENT) { - if (doc_scroll > 0) doc_scroll--; - swallow = 1; - draw = 1; - break; - } - else if (tools & TOOL_SUGG_LIST) { - SuggItem *sel = texttool_suggest_selected(); - while (sel && sel != texttool_suggest_first() && sel->prev && scroll--) { - texttool_suggest_select(sel->prev); - sel = sel->prev; - } - text_pop_suggest_list(); - swallow = 1; - draw = 1; - break; - } - case RIGHTSHIFTKEY: - case LEFTSHIFTKEY: - break; - default: - if (tools & TOOL_SUGG_LIST) texttool_suggest_clear(), draw = 1; - if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0, draw = 1; - } - } - - if (draw) { - // XXX redraw_alltext(); - } - - return swallow; -} diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c index 1ea3876f5cc..5ebbebec35b 100644 --- a/source/blender/editors/space_userpref/space_userpref.c +++ b/source/blender/editors/space_userpref/space_userpref.c @@ -105,14 +105,16 @@ static SpaceLink *userpref_duplicate(SpaceLink *sl) /* add handlers, stuff you only do once or on area/region changes */ static void userpref_main_area_init(wmWindowManager *wm, ARegion *ar) { + /* do not use here, the properties changed in userprefs do a system-wide refresh, then scroller jumps back */ + /* ar->v2d.flag &= ~V2D_IS_INITIALISED; */ + + ar->v2d.scroll = V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HIDE; + ED_region_panels_init(wm, ar); } static void userpref_main_area_draw(const bContext *C, ARegion *ar) { - /* this solves "vibrating UI" bug #25422 */ - UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_PANELS_UI, ar->winx, ar->winy); - ED_region_panels(C, ar, 1, NULL, -1); } diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c index e36654323fd..fa72f28cc44 100644 --- a/source/blender/editors/space_view3d/drawmesh.c +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -396,6 +396,7 @@ static void draw_textured_end(void) glShadeModel(GL_FLAT); glDisable(GL_CULL_FACE); + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); /* XXX, bad patch - GPU_default_lights() calls * glLightfv(GL_POSITION, ...) which @@ -1018,7 +1019,7 @@ void draw_mesh_paint(View3D *v3d, RegionView3D *rv3d, const short do_light = (v3d->drawtype >= OB_SOLID); /* hide faces in face select mode */ - if (draw_flags & DRAW_FACE_SELECT) + if (me->editflag & (ME_EDIT_PAINT_VERT_SEL | ME_EDIT_PAINT_FACE_SEL)) facemask = wpaint__setSolidDrawOptions_facemask; if (ob->mode & OB_MODE_WEIGHT_PAINT) { @@ -1066,12 +1067,18 @@ void draw_mesh_paint(View3D *v3d, RegionView3D *rv3d, draw_mesh_face_select(rv3d, me, dm); } else if ((do_light == FALSE) || (ob->dtx & OB_DRAWWIRE)) { + const int use_depth = (v3d->flag & V3D_ZBUF_SELECT); /* weight paint in solid mode, special case. focus on making the weights clear * rather than the shading, this is also forced in wire view */ - bglPolygonOffset(rv3d->dist, 1.0); - glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */ + if (use_depth) { + bglPolygonOffset(rv3d->dist, 1.0); + glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */ + } + else { + glDisable(GL_DEPTH_TEST); + } glEnable(GL_BLEND); glColor4ub(255, 255, 255, 96); @@ -1080,8 +1087,14 @@ void draw_mesh_paint(View3D *v3d, RegionView3D *rv3d, dm->drawEdges(dm, 1, 1); - bglPolygonOffset(rv3d->dist, 0.0); - glDepthMask(1); + if (use_depth) { + bglPolygonOffset(rv3d->dist, 0.0); + glDepthMask(1); + } + else { + glEnable(GL_DEPTH_TEST); + } + glDisable(GL_LINE_STIPPLE); glDisable(GL_BLEND); } diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 3722e6797f8..ebb5fd30666 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -101,7 +101,7 @@ typedef enum eWireDrawMode { } eWireDrawMode; typedef struct drawDMVerts_userData { - BMEditMesh *em; /* BMESH BRANCH ONLY */ + BMEditMesh *em; int sel; BMVert *eve_act; @@ -119,7 +119,7 @@ typedef struct drawDMVerts_userData { } drawDMVerts_userData; typedef struct drawDMEdgesSel_userData { - BMEditMesh *em; /* BMESH BRANCH ONLY */ + BMEditMesh *em; unsigned char *baseCol, *selCol, *actCol; BMEdge *eed_act; @@ -132,8 +132,8 @@ typedef struct drawDMFacesSel_userData { unsigned char *cols[3]; #endif - DerivedMesh *dm; /* BMESH BRANCH ONLY */ - BMEditMesh *em; /* BMESH BRANCH ONLY */ + DerivedMesh *dm; + BMEditMesh *em; BMFace *efa_act; int *orig_index_mf_to_mpoly; @@ -2629,10 +2629,10 @@ static void draw_em_measure_stats(View3D *v3d, Object *ob, BMEditMesh *em, UnitS /* make the precision of the display value proportionate to the gridsize */ - if (grid < 0.01f) conv_float = "%.6g"; - else if (grid < 0.1f) conv_float = "%.5g"; - else if (grid < 1.0f) conv_float = "%.4g"; - else if (grid < 10.0f) conv_float = "%.3g"; + if (grid <= 0.01f) conv_float = "%.6g"; + else if (grid <= 0.1f) conv_float = "%.5g"; + else if (grid <= 1.0f) conv_float = "%.4g"; + else if (grid <= 10.0f) conv_float = "%.3g"; else conv_float = "%.2g"; if (me->drawflag & ME_DRAWEXTRA_EDGELEN) { @@ -3312,11 +3312,15 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D } if (is_obact && paint_vertsel_test(ob)) { - + const int use_depth = (v3d->flag & V3D_ZBUF_SELECT); glColor3f(0.0f, 0.0f, 0.0f); glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); - + + if (!use_depth) glDisable(GL_DEPTH_TEST); + else bglPolygonOffset(rv3d->dist, 1.0); drawSelectedVertices(dm, ob->data); + if (!use_depth) glEnable(GL_DEPTH_TEST); + else bglPolygonOffset(rv3d->dist, 0.0); glPointSize(1.0f); } @@ -6949,10 +6953,10 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short UI_make_axis_color(col1, col2, 'Z'); glColor3ubv(col2); - cob = constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); + cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); for (curcon = list->first; curcon; curcon = curcon->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(curcon); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(curcon); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -7006,7 +7010,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short } } - constraints_clear_evalob(cob); + BKE_constraints_clear_evalob(cob); } } @@ -7167,7 +7171,21 @@ static DMDrawOption bbs_mesh_solid_hide2__setDrawOpts(void *userData, int index) return DM_DRAW_OPTION_SKIP; } } -static void bbs_mesh_solid(Scene *scene, Object *ob) + +static void bbs_mesh_solid_verts(Scene *scene, Object *ob) +{ + Mesh *me = ob->data; + DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask); + glColor3ub(0, 0, 0); + + dm->drawMappedFaces(dm, bbs_mesh_solid_hide2__setDrawOpts, GPU_enable_material, NULL, me, 0); + + bbs_obmode_mesh_verts(ob, dm, 1); + bm_vertoffs = me->totvert + 1; + dm->release(dm); +} + +static void bbs_mesh_solid_faces(Scene *scene, Object *ob) { DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask); Mesh *me = (Mesh *)ob->data; @@ -7232,18 +7250,10 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec /* currently vertex select only supports weight paint */ (ob->mode & OB_MODE_WEIGHT_PAINT)) { - DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask); - glColor3ub(0, 0, 0); - - dm->drawMappedFaces(dm, bbs_mesh_solid_hide2__setDrawOpts, GPU_enable_material, NULL, me, 0); - - - bbs_obmode_mesh_verts(ob, dm, 1); - bm_vertoffs = me->totvert + 1; - dm->release(dm); + bbs_mesh_solid_verts(scene, ob); } else { - bbs_mesh_solid(scene, ob); + bbs_mesh_solid_faces(scene, ob); } } break; diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 4ade47fbdc7..1d87895d64a 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -520,14 +520,8 @@ static int view3d_ima_ob_drop_poll(bContext *C, wmDrag *drag, wmEvent *event) static void view3d_ob_drop_copy(wmDrag *drag, wmDropBox *drop) { ID *id = (ID *)drag->poin; - PointerRNA ptr; - /* need to put name in sub-operator in macro */ - ptr = RNA_pointer_get(drop->ptr, "OBJECT_OT_add_named"); - if (ptr.data) - RNA_string_set(&ptr, "name", id->name + 2); - else - RNA_string_set(drop->ptr, "name", id->name + 2); + RNA_string_set(drop->ptr, "name", id->name + 2); } static void view3d_group_drop_copy(wmDrag *drag, wmDropBox *drop) @@ -561,7 +555,7 @@ static void view3d_dropboxes(void) { ListBase *lb = WM_dropboxmap_find("View3D", SPACE_VIEW3D, RGN_TYPE_WINDOW); - WM_dropbox_add(lb, "OBJECT_OT_add_named_cursor", view3d_ob_drop_poll, view3d_ob_drop_copy); + WM_dropbox_add(lb, "OBJECT_OT_add_named", view3d_ob_drop_poll, view3d_ob_drop_copy); WM_dropbox_add(lb, "OBJECT_OT_drop_named_material", view3d_mat_drop_poll, view3d_id_drop_copy); WM_dropbox_add(lb, "MESH_OT_drop_named_image", view3d_ima_ob_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); diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 7475f65317a..4ccf26e12b1 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -2596,10 +2596,10 @@ void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar, linearrgb_to_srgb_v3_v3(backcol, &scene->world->horr); } - glClearColor(backcol[0], backcol[1], backcol[2], 0.0); + glClearColor(backcol[0], backcol[1], backcol[2], 0.0f); } else { - UI_ThemeClearColor(TH_BACK); + UI_ThemeClearColor(TH_BACK); } diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 78c3f4e4f4a..e984a3f5cfd 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -921,7 +921,8 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event) } if (event->type == MOUSEPAN) { - viewrotate_apply(vod, event->prevx, event->prevy); + /* invert it, trackpad scroll then follows how you mapped it globally */ + viewrotate_apply(vod, 2 * event->x - event->prevx, 2 * event->y - event->prevy); ED_view3d_depth_tag_update(rv3d); viewops_data_free(C, op); @@ -1008,17 +1009,20 @@ void ndof_to_quat(struct wmNDOFMotionData *ndof, float q[4]) */ static int ndof_orbit_invoke(bContext *C, wmOperator *op, wmEvent *event) { - ViewOpsData *vod = op->customdata; if (event->type != NDOF_MOTION) return OPERATOR_CANCELLED; else { View3D *v3d = CTX_wm_view3d(C); + ViewOpsData *vod; RegionView3D *rv3d = CTX_wm_region_view3d(C); wmNDOFMotionData *ndof = (wmNDOFMotionData *) event->customdata; ED_view3d_camera_lock_init(v3d, rv3d); + viewops_data_create(C, op, event); + vod = op->customdata; + rv3d->rot_angle = 0.f; /* off by default, until changed later this function */ if (ndof->progress != P_FINISHING) { @@ -1138,8 +1142,10 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, wmEvent *event) } } + viewops_data_free(C, op); + ED_view3d_camera_lock_sync(v3d, rv3d); - + ED_region_tag_redraw(CTX_wm_region(C)); return OPERATOR_FINISHED; @@ -1161,6 +1167,181 @@ void VIEW3D_OT_ndof_orbit(struct wmOperatorType *ot) ot->flag = 0; } + +static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + + if (event->type != NDOF_MOTION) + return OPERATOR_CANCELLED; + else { + ViewOpsData *vod; + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + wmNDOFMotionData *ndof = (wmNDOFMotionData *) event->customdata; + + ED_view3d_camera_lock_init(v3d, rv3d); + + rv3d->rot_angle = 0.f; /* off by default, until changed later this function */ + + viewops_data_create(C, op, event); + vod = op->customdata; + + if (ndof->progress != P_FINISHING) { + const float dt = ndof->dt; + + /* tune these until everything feels right */ + const float rot_sensitivity = 1.f; + + const float zoom_sensitivity = 1.f; + + const float pan_sensitivity = 1.f; + const int has_rotation = rv3d->viewlock != RV3D_LOCKED && !is_zero_v3(ndof->rvec); + + float view_inv[4]; + invert_qt_qt(view_inv, rv3d->viewquat); + + /* #define DEBUG_NDOF_MOTION */ + #ifdef DEBUG_NDOF_MOTION + printf("ndof: T=(%.2f,%.2f,%.2f) R=(%.2f,%.2f,%.2f) dt=%.3f delivered to 3D view\n", + ndof->tx, ndof->ty, ndof->tz, ndof->rx, ndof->ry, ndof->rz, ndof->dt); + #endif + + if (ndof->tz) { + /* Zoom! + * velocity should be proportional to the linear velocity attained by rotational motion of same strength + * [got that?] + * proportional to arclength = radius * angle + */ + float zoom_distance = zoom_sensitivity * rv3d->dist * dt * ndof->tz; + + if (U.ndof_flag & NDOF_ZOOM_INVERT) + zoom_distance = -zoom_distance; + + rv3d->dist += zoom_distance; + } + + if (rv3d->viewlock == RV3D_LOCKED) { + /* rotation not allowed -- explore panning options instead */ + float pan_vec[3] = {ndof->tx, ndof->ty, 0.0f}; + mul_v3_fl(pan_vec, pan_sensitivity * rv3d->dist * dt); + + /* transform motion from view to world coordinates */ + invert_qt_qt(view_inv, rv3d->viewquat); + mul_qt_v3(view_inv, pan_vec); + + /* move center of view opposite of hand motion (this is camera mode, not object mode) */ + sub_v3_v3(rv3d->ofs, pan_vec); + } + + if (has_rotation) { + + rv3d->view = RV3D_VIEW_USER; + + if (U.ndof_flag & NDOF_TURNTABLE) { + + /* turntable view code by John Aughey, adapted for 3D mouse by [mce] */ + float angle, rot[4]; + float xvec[3] = {1, 0, 0}; + + /* Determine the direction of the x vector (for rotating up and down) */ + mul_qt_v3(view_inv, xvec); + + /* Perform the up/down rotation */ + angle = rot_sensitivity * dt * ndof->rx; + if (U.ndof_flag & NDOF_TILT_INVERT_AXIS) + angle = -angle; + rot[0] = cos(angle); + mul_v3_v3fl(rot + 1, xvec, sin(angle)); + mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot); + + /* Perform the orbital rotation */ + angle = rot_sensitivity * dt * ndof->ry; + if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS) + angle = -angle; + + /* update the onscreen doo-dad */ + rv3d->rot_angle = angle; + rv3d->rot_axis[0] = 0; + rv3d->rot_axis[1] = 0; + rv3d->rot_axis[2] = 1; + + rot[0] = cos(angle); + rot[1] = rot[2] = 0.0; + rot[3] = sin(angle); + mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot); + + } + else { + float rot[4]; + float axis[3]; + float angle = rot_sensitivity * ndof_to_axis_angle(ndof, axis); + + if (U.ndof_flag & NDOF_ROLL_INVERT_AXIS) + axis[2] = -axis[2]; + + if (U.ndof_flag & NDOF_TILT_INVERT_AXIS) + axis[0] = -axis[0]; + + if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS) + axis[1] = -axis[1]; + + + /* transform rotation axis from view to world coordinates */ + mul_qt_v3(view_inv, axis); + + /* update the onscreen doo-dad */ + rv3d->rot_angle = angle; + copy_v3_v3(rv3d->rot_axis, axis); + + axis_angle_to_quat(rot, axis, angle); + + /* apply rotation */ + mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot); + + } + + /* rotate around custom center */ + if (vod && vod->use_dyn_ofs) { + float q1[4]; + + /* compute the post multiplication quat, to rotate the offset correctly */ + conjugate_qt_qt(q1, vod->oldquat); + mul_qt_qtqt(q1, q1, rv3d->viewquat); + + conjugate_qt(q1); /* conj == inv for unit quat */ + copy_v3_v3(rv3d->ofs, vod->ofs); + sub_v3_v3(rv3d->ofs, vod->dyn_ofs); + mul_qt_v3(q1, rv3d->ofs); + add_v3_v3(rv3d->ofs, vod->dyn_ofs); + } + } + } + + viewops_data_free(C, op); + + ED_view3d_camera_lock_sync(v3d, rv3d); + + ED_region_tag_redraw(CTX_wm_region(C)); + + return OPERATOR_FINISHED; + } +} + +void VIEW3D_OT_ndof_orbit_zoom(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "NDOF Orbit View with zoom"; + ot->description = "Explore every angle of an object using the 3D mouse"; + ot->idname = "VIEW3D_OT_ndof_orbit_zoom"; + + /* api callbacks */ + ot->invoke = ndof_orbit_zoom_invoke; + ot->poll = ED_operator_view3d_active; + + /* flags */ + ot->flag = 0; +} + /* -- "pan" navigation * -- zoom or dolly? */ @@ -1197,8 +1378,7 @@ static int ndof_pan_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) mul_v3_fl(pan_vec, pan_sensitivity * rv3d->dist * dt); #else /* ------------------------------------------------------- dolly with Z */ - float speed = 10.f; /* blender units per second */ - /* ^^ this is ok for default cube scene, but should scale with.. something */ + float speed = rv3d->dist; /* uses distance from pivot to define dolly */ /* tune these until everything feels right */ const float forward_sensitivity = 1.f; @@ -1261,8 +1441,9 @@ void VIEW3D_OT_ndof_pan(struct wmOperatorType *ot) */ static int ndof_all_invoke(bContext *C, wmOperator *op, wmEvent *event) { - if (event->type != NDOF_MOTION) + if (event->type != NDOF_MOTION) { return OPERATOR_CANCELLED; + } else { ViewOpsData *vod; @@ -1282,23 +1463,14 @@ static int ndof_all_invoke(bContext *C, wmOperator *op, wmEvent *event) const float dt = ndof->dt; float view_inv[4]; - float speed = 10.f; /* blender units per second */ - /* ^^ this is ok for default cube scene, but should scale with.. something */ + float speed = rv3d->dist; /* uses distance from pivot to define dolly */ /* tune these until everything feels right */ const float forward_sensitivity = 1.f; const float vertical_sensitivity = 0.4f; const float lateral_sensitivity = 0.6f; - float pan_vec[3]; const float rot_sensitivity = 1.f; -#if 0 - const float zoom_sensitivity = 1.f; - const float pan_sensitivity = 1.f; - float rot[4]; - float angle = rot_sensitivity * ndof_to_axis_angle(ndof, axis); - float axis[3]; -#endif /* inverse view */ invert_qt_qt(view_inv, rv3d->viewquat); @@ -1389,7 +1561,7 @@ static int ndof_all_invoke(bContext *C, wmOperator *op, wmEvent *event) } /* rotate around custom center */ - if (vod && vod->use_dyn_ofs) { + if (vod->use_dyn_ofs) { float q1[4]; /* compute the post multiplication quat, to rotate the offset correctly */ @@ -1404,10 +1576,13 @@ static int ndof_all_invoke(bContext *C, wmOperator *op, wmEvent *event) } } + + viewops_data_free(C, op); + ED_view3d_camera_lock_sync(v3d, rv3d); ED_region_tag_redraw(CTX_wm_region(C)); - viewops_data_free(C, op); + return OPERATOR_FINISHED; } } @@ -3677,17 +3852,21 @@ void VIEW3D_OT_clip_border(wmOperatorType *ot) /* ***************** 3d cursor cursor op ******************* */ -/* mx my in region coords */ -static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +/* cursor position in vec, result in vec, mval in region coords */ +/* note: cannot use event->mval here (called by object_add() */ +void ED_view3d_cursor3d_position(bContext *C, float *fp, int mx, int my) { Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); - float *fp = give_cursor(scene, v3d); float mval_fl[2]; + int mval[2]; int flip; + mval[0] = mx - ar->winrct.xmin; + mval[1] = my - ar->winrct.ymin; + flip = initgrabz(rv3d, fp[0], fp[1], fp[2]); /* reset the depth based on the view offset (we _know_ the offset is infront of us) */ @@ -3702,20 +3881,20 @@ static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent * if (U.uiflag & USER_ZBUF_CURSOR) { /* maybe this should be accessed some other way */ view3d_operator_needs_opengl(C); - if (ED_view3d_autodist(scene, ar, v3d, event->mval, fp)) + if (ED_view3d_autodist(scene, ar, v3d, mval, fp)) depth_used = TRUE; } if (depth_used == FALSE) { float dvec[3]; - VECSUB2D(mval_fl, mval_fl, event->mval); + VECSUB2D(mval_fl, mval_fl, mval); ED_view3d_win_to_delta(ar, mval_fl, dvec); sub_v3_v3(fp, dvec); } } else { - const float dx = ((float)(event->mval[0] - (ar->winx / 2))) * rv3d->zfac / (ar->winx / 2); - const float dy = ((float)(event->mval[1] - (ar->winy / 2))) * rv3d->zfac / (ar->winy / 2); + const float dx = ((float)(mval[0] - (ar->winx / 2))) * rv3d->zfac / (ar->winx / 2); + const float dy = ((float)(mval[1] - (ar->winy / 2))) * rv3d->zfac / (ar->winy / 2); const float fz = (rv3d->persmat[0][3] * fp[0] + rv3d->persmat[1][3] * fp[1] + rv3d->persmat[2][3] * fp[2] + @@ -3726,11 +3905,21 @@ static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent * fp[2] = (rv3d->persinv[0][2] * dx + rv3d->persinv[1][2] * dy + rv3d->persinv[2][2] * fz) - rv3d->ofs[2]; } +} + +static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +{ + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); + float *fp = give_cursor(scene, v3d); + + ED_view3d_cursor3d_position(C, fp, event->x, event->y); + if (v3d && v3d->localvd) WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); else WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene); - + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index 79bf003a563..2b30e4e6b81 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -487,11 +487,17 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) block = uiLayoutGetBlock(row); if (v3d->twflag & V3D_USE_MANIPULATOR) { - but = uiDefIconButBitC(block, TOG, V3D_MANIP_TRANSLATE, B_MAN_TRANS, ICON_MAN_TRANS, 0, 0, UI_UNIT_X, UI_UNIT_Y, &v3d->twtype, 1.0, 0.0, 0, 0, TIP_("Translate manipulator - Shift-Click for multiple modes")); + but = uiDefIconButBitC(block, TOG, V3D_MANIP_TRANSLATE, B_MAN_TRANS, ICON_MAN_TRANS, + 0, 0, UI_UNIT_X, UI_UNIT_Y, &v3d->twtype, 1.0, 0.0, 0, 0, + TIP_("Translate manipulator - Shift-Click for multiple modes")); uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */ - but = uiDefIconButBitC(block, TOG, V3D_MANIP_ROTATE, B_MAN_ROT, ICON_MAN_ROT, 0, 0, UI_UNIT_X, UI_UNIT_Y, &v3d->twtype, 1.0, 0.0, 0, 0, TIP_("Rotate manipulator - Shift-Click for multiple modes")); + but = uiDefIconButBitC(block, TOG, V3D_MANIP_ROTATE, B_MAN_ROT, ICON_MAN_ROT, + 0, 0, UI_UNIT_X, UI_UNIT_Y, &v3d->twtype, 1.0, 0.0, 0, 0, + TIP_("Rotate manipulator - Shift-Click for multiple modes")); uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */ - but = uiDefIconButBitC(block, TOG, V3D_MANIP_SCALE, B_MAN_SCALE, ICON_MAN_SCALE, 0, 0, UI_UNIT_X, UI_UNIT_Y, &v3d->twtype, 1.0, 0.0, 0, 0, TIP_("Scale manipulator - Shift-Click for multiple modes")); + but = uiDefIconButBitC(block, TOG, V3D_MANIP_SCALE, B_MAN_SCALE, ICON_MAN_SCALE, + 0, 0, UI_UNIT_X, UI_UNIT_Y, &v3d->twtype, 1.0, 0.0, 0, 0, + TIP_("Scale manipulator - Shift-Click for multiple modes")); uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */ } @@ -500,7 +506,8 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) } str_menu = BIF_menustringTransformOrientation(C, "Orientation"); - but = uiDefButC(block, MENU, B_MAN_MODE, str_menu, 0, 0, 70 * dpi_fac, UI_UNIT_Y, &v3d->twmode, 0, 0, 0, 0, TIP_("Transform Orientation")); + but = uiDefButC(block, MENU, B_MAN_MODE, str_menu, 0, 0, 70 * dpi_fac, UI_UNIT_Y, &v3d->twmode, 0, 0, 0, 0, + TIP_("Transform Orientation")); uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */ MEM_freeN((void *)str_menu); } diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index f8a7cdde8a5..a6daf610052 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -77,6 +77,7 @@ void VIEW3D_OT_zoom_camera_1_to_1(struct wmOperatorType *ot); void VIEW3D_OT_move(struct wmOperatorType *ot); void VIEW3D_OT_rotate(struct wmOperatorType *ot); void VIEW3D_OT_ndof_orbit(struct wmOperatorType *ot); +void VIEW3D_OT_ndof_orbit_zoom(struct wmOperatorType *ot); void VIEW3D_OT_ndof_pan(struct wmOperatorType *ot); void VIEW3D_OT_ndof_all(struct wmOperatorType *ot); void VIEW3D_OT_view_all(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c index a0b36e57d69..81e890c37ee 100644 --- a/source/blender/editors/space_view3d/view3d_iterators.c +++ b/source/blender/editors/space_view3d/view3d_iterators.c @@ -27,6 +27,7 @@ #include "DNA_curve_types.h" #include "DNA_lattice_types.h" #include "DNA_meta_types.h" +#include "DNA_mesh_types.h" #include "DNA_armature_types.h" #include "DNA_object_types.h" @@ -47,6 +48,12 @@ #include "ED_object.h" #include "ED_view3d.h" +typedef struct foreachScreenObjectVert_userData { + void (*func)(void *userData, MVert *mv, const float screen_co_b[2], int index); + void *userData; + ViewContext vc; + eV3DProjTest clip_flag; +} foreachScreenObjectVert_userData; typedef struct foreachScreenVert_userData { void (*func)(void *userData, BMVert *eve, const float screen_co_b[2], int index); @@ -79,6 +86,46 @@ typedef struct foreachScreenFace_userData { /* ------------------------------------------------------------------------ */ + +static void meshobject_foreachScreenVert__mapFunc(void *userData, int index, const float co[3], + const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) +{ + foreachScreenObjectVert_userData *data = userData; + struct MVert *mv = &((Mesh *)(data->vc.obact->data))->mvert[index]; + + if (!(mv->flag & ME_HIDE)) { + float screen_co[2]; + + if (ED_view3d_project_float_object(data->vc.ar, co, screen_co, data->clip_flag) != V3D_PROJ_RET_OK) { + return; + } + + data->func(data->userData, mv, screen_co, index); + } +} + +void meshobject_foreachScreenVert( + ViewContext *vc, + void (*func)(void *userData, MVert *eve, const float screen_co[2], int index), + void *userData, eV3DProjTest clip_flag) +{ + foreachScreenObjectVert_userData data; + DerivedMesh *dm = mesh_get_derived_deform(vc->scene, vc->obact, CD_MASK_BAREMESH); + + data.vc = *vc; + data.func = func; + data.userData = userData; + data.clip_flag = clip_flag; + + if (clip_flag & V3D_PROJ_TEST_CLIP_BB) { + ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */ + } + + dm->foreachMappedVert(dm, meshobject_foreachScreenVert__mapFunc, &data); + + dm->release(dm); +} + static void mesh_foreachScreenVert__mapFunc(void *userData, int index, const float co[3], const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) { diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 4101ced616a..615ae71cf9b 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -131,6 +131,7 @@ void view3d_operatortypes(void) WM_operatortype_append(VIEW3D_OT_zoom); WM_operatortype_append(VIEW3D_OT_zoom_camera_1_to_1); WM_operatortype_append(VIEW3D_OT_dolly); + WM_operatortype_append(VIEW3D_OT_ndof_orbit_zoom); WM_operatortype_append(VIEW3D_OT_ndof_orbit); WM_operatortype_append(VIEW3D_OT_ndof_pan); WM_operatortype_append(VIEW3D_OT_ndof_all); @@ -195,34 +196,6 @@ void view3d_keymap(wmKeyConfig *keyconf) /* only for region 3D window */ keymap = WM_keymap_find(keyconf, "3D View", SPACE_VIEW3D, 0); - - /* NDOF: begin */ - /* note: positioned here so keymaps show keyboard keys if assigned */ - /* 3D mouse */ - WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_orbit", NDOF_MOTION, 0, KM_CTRL, 0); - WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_pan", NDOF_MOTION, 0, KM_SHIFT, 0); - WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_all", NDOF_MOTION, 0, 0, 0); - WM_keymap_add_item(keymap, "VIEW3D_OT_view_selected", NDOF_BUTTON_FIT, KM_PRESS, 0, 0); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_FRONT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_FRONT); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_BACK, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_BACK); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_LEFT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_LEFT); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_RIGHT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_RIGHT); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_TOP, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_TOP); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_BOTTOM, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_BOTTOM); - - /* 3D mouse align */ - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_FRONT, KM_PRESS, KM_SHIFT, 0); - RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_FRONT); - RNA_boolean_set(kmi->ptr, "align_active", TRUE); - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_RIGHT, KM_PRESS, KM_SHIFT, 0); - RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_RIGHT); - RNA_boolean_set(kmi->ptr, "align_active", TRUE); - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_TOP, KM_PRESS, KM_SHIFT, 0); - RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_TOP); - RNA_boolean_set(kmi->ptr, "align_active", TRUE); - /* NDOF: end */ - - kmi = WM_keymap_verify_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_ANY, 0); RNA_boolean_set(kmi->ptr, "release_confirm", TRUE); /* @@ -248,9 +221,9 @@ void view3d_keymap(wmKeyConfig *keyconf) WM_keymap_verify_item(keymap, "VIEW3D_OT_smoothview", TIMER1, KM_ANY, KM_ANY, 0); - WM_keymap_add_item(keymap, "VIEW3D_OT_rotate", MOUSEPAN, 0, KM_ALT, 0); + WM_keymap_add_item(keymap, "VIEW3D_OT_rotate", MOUSEPAN, 0, 0, 0); WM_keymap_add_item(keymap, "VIEW3D_OT_rotate", MOUSEROTATE, 0, 0, 0); - WM_keymap_add_item(keymap, "VIEW3D_OT_move", MOUSEPAN, 0, 0, 0); + WM_keymap_add_item(keymap, "VIEW3D_OT_move", MOUSEPAN, 0, KM_SHIFT, 0); WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", MOUSEZOOM, 0, 0, 0); WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", MOUSEPAN, 0, KM_CTRL, 0); @@ -331,6 +304,34 @@ void view3d_keymap(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "VIEW3D_OT_localview", PADSLASHKEY, KM_PRESS, 0, 0); + /* NDOF: begin */ + /* note: positioned here so keymaps show keyboard keys if assigned */ + /* 3D mouse */ + WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_orbit_zoom", NDOF_MOTION, 0, 0, 0); + WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_orbit", NDOF_MOTION, 0, KM_CTRL, 0); + WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_pan", NDOF_MOTION, 0, KM_SHIFT, 0); + WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_all", NDOF_MOTION, 0, KM_CTRL | KM_SHIFT, 0); + WM_keymap_add_item(keymap, "VIEW3D_OT_view_selected", NDOF_BUTTON_FIT, KM_PRESS, 0, 0); + RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_FRONT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_FRONT); + RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_BACK, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_BACK); + RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_LEFT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_LEFT); + RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_RIGHT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_RIGHT); + RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_TOP, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_TOP); + RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_BOTTOM, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_BOTTOM); + + /* 3D mouse align */ + kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_FRONT, KM_PRESS, KM_SHIFT, 0); + RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_FRONT); + RNA_boolean_set(kmi->ptr, "align_active", TRUE); + kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_RIGHT, KM_PRESS, KM_SHIFT, 0); + RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_RIGHT); + RNA_boolean_set(kmi->ptr, "align_active", TRUE); + kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_TOP, KM_PRESS, KM_SHIFT, 0); + RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_TOP); + RNA_boolean_set(kmi->ptr, "align_active", TRUE); + /* NDOF: end */ + + /* layers, shift + alt are properties set in invoke() */ RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", ACCENTGRAVEKEY, KM_PRESS, 0, 0)->ptr, "nr", 0); RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", ONEKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 1); diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c index d4bdf6c3177..c428cb02236 100644 --- a/source/blender/editors/space_view3d/view3d_project.c +++ b/source/blender/editors/space_view3d/view3d_project.c @@ -110,7 +110,7 @@ eV3DProjStatus ED_view3d_project_base(struct ARegion *ar, struct Base *base) /* perspmat is typically... * - 'rv3d->perspmat', is_local == FALSE - * - 'rv3d->perspmatob', is_local == TRUE + * - 'rv3d->persmatob', is_local == TRUE */ static eV3DProjStatus ed_view3d_project__internal(ARegion *ar, float perspmat[4][4], const int is_local, /* normally hidden */ diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index d37042fa2ec..dac887f7f13 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -70,6 +70,7 @@ #include "BKE_paint.h" #include "BKE_tessmesh.h" #include "BKE_tracking.h" +#include "BKE_utildefines.h" #include "BIF_gl.h" @@ -741,67 +742,19 @@ static void do_lasso_select_meta(ViewContext *vc, const int mcords[][2], short m mball_foreachScreenElem(vc, do_lasso_select_mball__doSelectElem, &data, V3D_PROJ_TEST_CLIP_DEFAULT); } -static int do_paintvert_box_select(ViewContext *vc, rcti *rect, int select, int extend) +static void do_lasso_select_meshobject__doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index)) { - Mesh *me; - MVert *mvert; - struct ImBuf *ibuf; - unsigned int *rt; - int a, index; - char *selar; - int sx = BLI_rcti_size_x(rect) + 1; - int sy = BLI_rcti_size_y(rect) + 1; - - me = vc->obact->data; - - if (me == NULL || me->totvert == 0 || sx * sy <= 0) - return OPERATOR_CANCELLED; - - selar = MEM_callocN(me->totvert + 1, "selar"); - - if (extend == 0 && select) - paintvert_deselect_all_visible(vc->obact, SEL_DESELECT, FALSE); - - view3d_validate_backbuf(vc); - - ibuf = IMB_allocImBuf(sx, sy, 32, IB_rect); - rt = ibuf->rect; - glReadPixels(rect->xmin + vc->ar->winrct.xmin, rect->ymin + vc->ar->winrct.ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect); - if (ENDIAN_ORDER == B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf); - - a = sx * sy; - while (a--) { - if (*rt) { - index = WM_framebuffer_to_index(*rt); - if (index <= me->totvert) selar[index] = 1; - } - rt++; - } + LassoSelectUserData *data = userData; - mvert = me->mvert; - for (a = 1; a <= me->totvert; a++, mvert++) { - if (selar[a]) { - if ((mvert->flag & ME_HIDE) == 0) { - if (select) mvert->flag |= SELECT; - else mvert->flag &= ~SELECT; - } - } + if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)) + { + BKE_BIT_TEST_SET(mv->flag, data->select, SELECT); } - - IMB_freeImBuf(ibuf); - MEM_freeN(selar); - -#ifdef __APPLE__ - glReadBuffer(GL_BACK); -#endif - - paintvert_flush_flags(vc->obact); - - return OPERATOR_FINISHED; } - static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], short moves, short extend, short select) { + const int use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT); Object *ob = vc->obact; Mesh *me = ob ? ob->data : NULL; rcti rect; @@ -811,14 +764,31 @@ static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], sh if (extend == 0 && select) paintvert_deselect_all_visible(ob, SEL_DESELECT, FALSE); /* flush selection at the end */ - bm_vertoffs = me->totvert + 1; /* max index array */ BLI_lasso_boundbox(&rect, mcords, moves); - EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax); - edbm_backbuf_check_and_select_verts_obmode(me, select); + if (use_zbuf) { + bm_vertoffs = me->totvert + 1; /* max index array */ - EDBM_backbuf_free(); + EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + + edbm_backbuf_check_and_select_verts_obmode(me, select); + + EDBM_backbuf_free(); + } + else { + LassoSelectUserData data; + rcti rect; + + BLI_lasso_boundbox(&rect, mcords, moves); + + view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select); + + ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); + + meshobject_foreachScreenVert(vc, do_lasso_select_meshobject__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT); + + } paintvert_flush_flags(ob); } @@ -1217,31 +1187,42 @@ static Base *object_mouse_select_menu(bContext *C, ViewContext *vc, unsigned int } } +static int selectbuffer_has_bones(const unsigned int *buffer, const unsigned int hits) +{ + unsigned int i; + for (i = 0; i < hits; i++) { + if (buffer[(4 * i) + 3] & 0xFFFF0000) { + return TRUE; + } + } + return FALSE; +} + /* 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]) { rcti rect; int offs; - short a, hits15, hits9 = 0, hits5 = 0; - short has_bones15 = 0, has_bones9 = 0, has_bones5 = 0; + short hits15, hits9 = 0, hits5 = 0; + short has_bones15 = FALSE, has_bones9 = FALSE, has_bones5 = FALSE; BLI_rcti_init(&rect, mval[0] - 14, mval[0] + 14, mval[1] - 14, mval[1] + 14); hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect); if (hits15 > 0) { - for (a = 0; a < hits15; a++) if (buffer[4 * a + 3] & 0xFFFF0000) has_bones15 = 1; + has_bones15 = selectbuffer_has_bones(buffer, hits15); 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); if (hits9 > 0) { - for (a = 0; a < hits9; a++) if (buffer[offs + 4 * a + 3] & 0xFFFF0000) has_bones9 = 1; + has_bones9 = selectbuffer_has_bones(buffer + offs, hits9); 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); if (hits5 > 0) { - for (a = 0; a < hits5; a++) if (buffer[offs + 4 * a + 3] & 0xFFFF0000) has_bones5 = 1; + has_bones5 = selectbuffer_has_bones(buffer + offs, hits5); } } @@ -1383,10 +1364,7 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2]) hits = mixed_bones_object_selectbuffer(&vc, buffer, mval); if (hits > 0) { - int a, has_bones = 0; - - for (a = 0; a < hits; a++) if (buffer[4 * a + 3] & 0xFFFF0000) has_bones = 1; - + const int has_bones = selectbuffer_has_bones(buffer, hits); basact = mouse_select_eval_buffer(&vc, buffer, hits, mval, vc.scene->base.first, has_bones); } @@ -1420,7 +1398,6 @@ static int mouse_select(bContext *C, const int mval[2], short extend, short dese View3D *v3d = CTX_wm_view3d(C); Scene *scene = CTX_data_scene(C); Base *base, *startbase = NULL, *basact = NULL, *oldbasact = NULL; - int a; float dist = 100.0f; int retval = 0; short hits; @@ -1473,10 +1450,8 @@ static int mouse_select(bContext *C, const int mval[2], short extend, short dese hits = mixed_bones_object_selectbuffer(&vc, buffer, mval); if (hits > 0) { - int has_bones = 0; - /* note: bundles are handling in the same way as bones */ - for (a = 0; a < hits; a++) if (buffer[4 * a + 3] & 0xFFFF0000) has_bones = 1; + const int has_bones = selectbuffer_has_bones(buffer, hits); /* note; shift+alt goes to group-flush-selecting */ if (has_bones == 0 && enumerate) { @@ -1502,7 +1477,7 @@ static int mouse_select(bContext *C, const int mval[2], short extend, short dese } /* index of bundle is 1<<16-based. if there's no "bone" index - * in height word, this buffer value belongs to camera,. not to bundle */ + * in height word, this buffer value belongs to camera. not to bundle */ if (buffer[4 * i + 3] & 0xFFFF0000) { MovieClip *clip = BKE_object_movieclip_get(scene, basact->object, 0); MovieTracking *tracking = &clip->tracking; @@ -1670,6 +1645,85 @@ int edge_inside_circle(const float cent[2], float radius, const float screen_co_ return FALSE; } +static void do_paintvert_box_select__doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index)) +{ + BoxSelectUserData *data = userData; + + if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) { + BKE_BIT_TEST_SET(mv->flag, data->select, SELECT); + } +} +static int do_paintvert_box_select(ViewContext *vc, rcti *rect, int select, int extend) +{ + const int use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT); + Mesh *me; + MVert *mvert; + struct ImBuf *ibuf; + unsigned int *rt; + int a, index; + char *selar; + int sx = BLI_rcti_size_x(rect) + 1; + int sy = BLI_rcti_size_y(rect) + 1; + + me = vc->obact->data; + + if (me == NULL || me->totvert == 0 || sx * sy <= 0) + return OPERATOR_CANCELLED; + + + if (extend == 0 && select) + paintvert_deselect_all_visible(vc->obact, SEL_DESELECT, FALSE); + + if (use_zbuf) { + selar = MEM_callocN(me->totvert + 1, "selar"); + view3d_validate_backbuf(vc); + + ibuf = IMB_allocImBuf(sx, sy, 32, IB_rect); + rt = ibuf->rect; + glReadPixels(rect->xmin + vc->ar->winrct.xmin, rect->ymin + vc->ar->winrct.ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect); + if (ENDIAN_ORDER == B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf); + + a = sx * sy; + while (a--) { + if (*rt) { + index = WM_framebuffer_to_index(*rt); + if (index <= me->totvert) selar[index] = 1; + } + rt++; + } + + mvert = me->mvert; + for (a = 1; a <= me->totvert; a++, mvert++) { + if (selar[a]) { + if ((mvert->flag & ME_HIDE) == 0) { + if (select) mvert->flag |= SELECT; + else mvert->flag &= ~SELECT; + } + } + } + + IMB_freeImBuf(ibuf); + MEM_freeN(selar); + +#ifdef __APPLE__ + glReadBuffer(GL_BACK); +#endif + } + else { + BoxSelectUserData data; + + view3d_userdata_boxselect_init(&data, vc, rect, select); + + ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); + + meshobject_foreachScreenVert(vc, do_paintvert_box_select__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT); + } + + paintvert_flush_flags(vc->obact); + + return OPERATOR_FINISHED; +} + static void do_nurbs_box_select__doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2]) { BoxSelectUserData *data = userData; @@ -2142,11 +2196,14 @@ void VIEW3D_OT_select_border(wmOperatorType *ot) /* gets called via generic mouse select operator */ static int mouse_weight_paint_vertex_select(bContext *C, const int mval[2], short extend, short deselect, short toggle, Object *obact) { + View3D *v3d = CTX_wm_view3d(C); + const int use_zbuf = (v3d->flag & V3D_ZBUF_SELECT); + Mesh *me = obact->data; /* already checked for NULL */ unsigned int index = 0; MVert *mv; - if (ED_mesh_pick_vert(C, me, mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE)) { + if (ED_mesh_pick_vert(C, obact, mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, use_zbuf)) { mv = &me->mvert[index]; if (extend) { mv->flag |= SELECT; @@ -2366,22 +2423,39 @@ static void paint_facesel_circle_select(ViewContext *vc, int select, const int m } } +static void paint_vertsel_circle_select_doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index)) +{ + CircleSelectUserData *data = userData; + if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) { + BKE_BIT_TEST_SET(mv->flag, data->select, SELECT); + } +} static void paint_vertsel_circle_select(ViewContext *vc, int select, const int mval[2], float rad) { + const int use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT); Object *ob = vc->obact; - Mesh *me = ob ? ob->data : NULL; + Mesh *me = ob->data; /* int bbsel; */ /* UNUSED */ /* CircleSelectUserData data = {NULL}; */ /* UNUSED */ - if (me) { + + if (use_zbuf) { bm_vertoffs = me->totvert + 1; /* max index array */ /* bbsel = */ /* UNUSED */ EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f)); edbm_backbuf_check_and_select_verts_obmode(me, select == LEFTMOUSE); EDBM_backbuf_free(); + } + else { + CircleSelectUserData data; - paintvert_flush_flags(ob); + ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); /* for foreach's screen/vert projection */ + + view3d_userdata_circleselect_init(&data, vc, select, mval, rad); + meshobject_foreachScreenVert(vc, paint_vertsel_circle_select_doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT); } + + paintvert_flush_flags(ob); } diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index b2ee17b8a8b..3b443e8bbac 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -686,6 +686,9 @@ static void view_editmove(unsigned short UNUSED(event)) #define TFM_MODAL_EDGESLIDE_UP 24 #define TFM_MODAL_EDGESLIDE_DOWN 25 +/* for analog input, like trackpad */ +#define TFM_MODAL_PROPSIZE 26 + /* called in transform_ops.c, on each regeneration of keymaps */ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf) { @@ -715,6 +718,7 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf) {TFM_MODAL_AUTOIK_LEN_DEC, "AUTOIK_CHAIN_LEN_DOWN", 0, "Decrease Max AutoIK Chain Length", ""}, {TFM_MODAL_EDGESLIDE_UP, "EDGESLIDE_EDGE_NEXT", 0, "Select next Edge Slide Edge", ""}, {TFM_MODAL_EDGESLIDE_DOWN, "EDGESLIDE_PREV_NEXT", 0, "Select previous Edge Slide Edge", ""}, + {TFM_MODAL_PROPSIZE, "PROPORTIONAL_SIZE", 0, "Adjust Proportional Influence", ""}, {0, NULL, 0, NULL, NULL} }; @@ -750,6 +754,7 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN); WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_UP); WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN); + WM_modalkeymap_add_item(keymap, MOUSEPAN, 0, 0, 0, TFM_MODAL_PROPSIZE); WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_ALT, 0, TFM_MODAL_EDGESLIDE_UP); WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_ALT, 0, TFM_MODAL_EDGESLIDE_DOWN); @@ -1024,6 +1029,19 @@ int transformEvent(TransInfo *t, wmEvent *event) removeSnapPoint(t); t->redraw |= TREDRAW_HARD; break; + + case TFM_MODAL_PROPSIZE: + /* MOUSEPAN usage... */ + if (t->flag & T_PROP_EDIT) { + float fac = 1.0f + 0.005f *(event->y - event->prevy); + t->prop_size *= fac; + if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) + t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far); + calculatePropRatio(t); + } + t->redraw |= TREDRAW_HARD; + break; + case TFM_MODAL_PROPSIZE_UP: if (t->flag & T_PROP_EDIT) { t->prop_size *= 1.1f; @@ -1500,7 +1518,6 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata) glTranslatef(mval[0], mval[1], 0); glLineWidth(3.0); - glBegin(GL_LINES); drawArrow(UP, 5, 10, 5); drawArrow(DOWN, 5, 10, 5); glLineWidth(1.0); @@ -2258,8 +2275,8 @@ static void protectedQuaternionBits(short protectflag, float *quat, float *oldqu static void constraintTransLim(TransInfo *t, TransData *td) { if (td->con) { - bConstraintTypeInfo *ctiLoc = get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT); - bConstraintTypeInfo *ctiDist = get_constraint_typeinfo(CONSTRAINT_TYPE_DISTLIMIT); + bConstraintTypeInfo *ctiLoc = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT); + bConstraintTypeInfo *ctiDist = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_DISTLIMIT); bConstraintOb cob = {NULL}; bConstraint *con; @@ -2309,7 +2326,7 @@ static void constraintTransLim(TransInfo *t, TransData *td) } /* get constraint targets if needed */ - get_constraint_targets_for_solving(con, &cob, &targets, ctime); + BKE_get_constraint_targets_for_solving(con, &cob, &targets, ctime); /* do constraint */ cti->evaluate_constraint(con, &cob, &targets); @@ -2361,7 +2378,7 @@ static void constraintob_from_transdata(bConstraintOb *cob, TransData *td) static void constraintRotLim(TransInfo *UNUSED(t), TransData *td) { if (td->con) { - bConstraintTypeInfo *cti = get_constraint_typeinfo(CONSTRAINT_TYPE_ROTLIMIT); + bConstraintTypeInfo *cti = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_ROTLIMIT); bConstraintOb cob; bConstraint *con; int do_limit = FALSE; @@ -2428,7 +2445,7 @@ static void constraintRotLim(TransInfo *UNUSED(t), TransData *td) static void constraintSizeLim(TransInfo *t, TransData *td) { if (td->con && td->ext) { - bConstraintTypeInfo *cti = get_constraint_typeinfo(CONSTRAINT_TYPE_SIZELIMIT); + bConstraintTypeInfo *cti = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_SIZELIMIT); bConstraintOb cob = {NULL}; bConstraint *con; float size_sign[3], size_abs[3]; @@ -2721,6 +2738,18 @@ int handleEventShear(TransInfo *t, wmEvent *event) status = 1; } + else if (event->type == XKEY && event->val == KM_PRESS) { + initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE); + t->customData = NULL; + + status = 1; + } + else if (event->type == YKEY && event->val == KM_PRESS) { + initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE); + t->customData = (void *)1; + + status = 1; + } return status; } @@ -2754,7 +2783,7 @@ int Shear(TransInfo *t, const int UNUSED(mval[2])) } else { /* default header print */ - sprintf(str, "Shear: %.3f %s", value, t->proptext); + sprintf(str, "Shear: %.3f %s (Press X or Y to set shear axis)", value, t->proptext); } t->values[0] = value; diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 7da47425370..12b0341d395 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -835,7 +835,7 @@ static short pose_grab_with_ik_add(bPoseChannel *pchan) } } - con = add_pose_constraint(NULL, pchan, "TempConstraint", CONSTRAINT_TYPE_KINEMATIC); + con = BKE_add_pose_constraint(NULL, pchan, "TempConstraint", CONSTRAINT_TYPE_KINEMATIC); pchan->constflag |= (PCHAN_HAS_IK | PCHAN_HAS_TARGET); /* for draw, but also for detecting while pose solving */ data = con->data; if (targetless) { @@ -4090,7 +4090,7 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *recursive, int *count /* Meta's can only directly be moved between channels since they * don't have their start and length set directly (children affect that) * since this Meta is nested we don't need any of its data in fact. - * calc_sequence() will update its settings when run on the toplevel meta */ + * BKE_sequence_calc() will update its settings when run on the toplevel meta */ *flag = 0; *count = 0; *recursive = TRUE; @@ -4268,8 +4268,8 @@ static void freeSeqData(TransInfo *t) { int overlap = 0; + seq_prev = NULL; for (a = 0; a < t->total; a++, td++) { - seq_prev = NULL; seq = ((TransDataSeq *)td->extra)->seq; if ((seq != seq_prev) && (seq->depth == 0) && (seq->flag & SEQ_OVERLAP)) { overlap = 1; diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 8f1d6a7b46e..2591c61c5ab 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -61,6 +61,8 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "BIK_api.h" + #include "BKE_animsys.h" #include "BKE_action.h" #include "BKE_armature.h" @@ -847,6 +849,8 @@ static void recalcData_view3d(TransInfo *t) /* old optimize trick... this enforces to bypass the depgraph */ if (!(arm->flag & ARM_DELAYDEFORM)) { DAG_id_tag_update(&ob->id, OB_RECALC_DATA); /* sets recalc flags */ + /* transformation of pose may affect IK tree, make sure it is rebuilt */ + BIK_clear_data(ob->pose); } else BKE_pose_where_is(t->scene, ob); diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index c9c4f7e2c7b..4bd6496e083 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -764,7 +764,7 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3], EditBone *ebone; int ok = FALSE; - /* grr,.but better then duplicate code */ + /* grr. but better then duplicate code */ #define EBONE_CALC_NORMAL_PLANE { \ float tmat[3][3]; \ float vec[3]; \ diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c index 1753a564a3c..1dc7e0c90e8 100644 --- a/source/blender/editors/util/undo.c +++ b/source/blender/editors/util/undo.c @@ -162,15 +162,18 @@ static int ed_undo_step(bContext *C, int step, const char *undoname) } } else { - int do_glob_undo = FALSE; - + /* Note: we used to do a fall-through here where if the + * mode-specific undo system had no more steps to undo (or + * redo), the global undo would run. + * + * That was inconsistent with editmode, and also makes for + * unecessarily tricky interaction with the other undo + * systems. */ if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) { - if (!ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname)) - do_glob_undo = TRUE; + ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname); } else if (obact && obact->mode & OB_MODE_SCULPT) { - if (!ED_undo_paint_step(C, UNDO_PAINT_MESH, step, undoname)) - do_glob_undo = TRUE; + ED_undo_paint_step(C, UNDO_PAINT_MESH, step, undoname); } else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) { if (step == 1) @@ -178,24 +181,17 @@ static int ed_undo_step(bContext *C, int step, const char *undoname) else PE_redo(CTX_data_scene(C)); } - else { - do_glob_undo = TRUE; - } - - if (do_glob_undo) { - if (U.uiflag & USER_GLOBALUNDO) { - // note python defines not valid here anymore. - //#ifdef WITH_PYTHON - // XXX BPY_scripts_clear_pyobjects(); - //#endif - if (undoname) - BKE_undo_name(C, undoname); - else - BKE_undo_step(C, step); + else if (U.uiflag & USER_GLOBALUNDO) { + // note python defines not valid here anymore. + //#ifdef WITH_PYTHON + // XXX BPY_scripts_clear_pyobjects(); + //#endif + if (undoname) + BKE_undo_name(C, undoname); + else + BKE_undo_step(C, step); - WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C)); - } - + WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C)); } } diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h index 27bbba11e75..4d52282d540 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -73,6 +73,7 @@ void uv_find_nearest_edge(struct Scene *scene, struct Image *ima, struct BMEditM /* utility tool functions */ void uvedit_live_unwrap_update(struct SpaceImage *sima, struct Scene *scene, struct Object *obedit); +void uvedit_get_aspect(struct Scene *scene, struct Object *ob, struct BMEditMesh *em, float *aspx, float *aspy); /* operators */ diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index bd50857c8b8..8c3eaa1192f 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -136,6 +136,7 @@ typedef struct UvEdge { /* stitch state object */ typedef struct StitchState { + float aspect; /* use limit flag */ char use_limit; /* limit to operator, same as original operator */ @@ -285,10 +286,12 @@ static int getNumOfIslandUvs(UvElementMap *elementMap, int island) } } -static void stitch_uv_rotate(float rotation, float medianPoint[2], float uv[2]) +static void stitch_uv_rotate(float rotation, float medianPoint[2], float uv[2], float aspect) { float uv_rotation_result[2]; + uv[1] /= aspect; + uv[0] -= medianPoint[0]; uv[1] -= medianPoint[1]; @@ -297,6 +300,8 @@ static void stitch_uv_rotate(float rotation, float medianPoint[2], float uv[2]) uv[0] = uv_rotation_result[0] + medianPoint[0]; uv[1] = uv_rotation_result[1] + medianPoint[1]; + + uv[1] *= aspect; } /* check if two uvelements are stitchable. This should only operate on -different- separate UvElements */ @@ -413,9 +418,11 @@ static void stitch_calculate_island_snapping(StitchState *state, PreviewPosition island_stitch_data[i].rotation /= island_stitch_data[i].num_rot_elements; island_stitch_data[i].medianPoint[0] /= island_stitch_data[i].numOfElements; island_stitch_data[i].medianPoint[1] /= island_stitch_data[i].numOfElements; + island_stitch_data[i].medianPoint[1] /= state->aspect; } island_stitch_data[i].translation[0] /= island_stitch_data[i].numOfElements; island_stitch_data[i].translation[1] /= island_stitch_data[i].numOfElements; + numOfIslandUVs = getNumOfIslandUvs(state->element_map, i); element = &state->element_map->buf[state->element_map->islandIndices[i]]; for (j = 0; j < numOfIslandUVs; j++, element++) { @@ -429,7 +436,7 @@ static void stitch_calculate_island_snapping(StitchState *state, PreviewPosition if (final) { - stitch_uv_rotate(island_stitch_data[i].rotation, island_stitch_data[i].medianPoint, luv->uv); + stitch_uv_rotate(island_stitch_data[i].rotation, island_stitch_data[i].medianPoint, luv->uv, state->aspect); add_v2_v2(luv->uv, island_stitch_data[i].translation); } @@ -438,7 +445,7 @@ static void stitch_calculate_island_snapping(StitchState *state, PreviewPosition int face_preview_pos = preview_position[BM_elem_index_get(element->l->f)].data_position; stitch_uv_rotate(island_stitch_data[i].rotation, island_stitch_data[i].medianPoint, - preview->preview_polys + face_preview_pos + 2 * element->tfindex); + preview->preview_polys + face_preview_pos + 2 * element->tfindex, state->aspect); add_v2_v2(preview->preview_polys + face_preview_pos + 2 * element->tfindex, island_stitch_data[i].translation); @@ -461,15 +468,12 @@ static void stitch_island_calculate_edge_rotation(UvEdge *edge, StitchState *sta int index1, index2; float rotation; MLoopUV *luv1, *luv2; - BMLoop *l1, *l2; element1 = state->uvs[edge->uv1]; element2 = state->uvs[edge->uv2]; - l1 = element1->l; - luv1 = CustomData_bmesh_get(&state->em->bm->ldata, l1->head.data, CD_MLOOPUV); - l2 = element2->l; - luv2 = CustomData_bmesh_get(&state->em->bm->ldata, l2->head.data, CD_MLOOPUV); + luv1 = CustomData_bmesh_get(&state->em->bm->ldata, element1->l->head.data, CD_MLOOPUV); + luv2 = CustomData_bmesh_get(&state->em->bm->ldata, element2->l->head.data, CD_MLOOPUV); if (state->mode == STITCH_VERT) { index1 = uvfinal_map[element1 - state->element_map->buf]; @@ -484,14 +488,18 @@ static void stitch_island_calculate_edge_rotation(UvEdge *edge, StitchState *sta uv1[0] = luv2->uv[0] - luv1->uv[0]; uv1[1] = luv2->uv[1] - luv1->uv[1]; + uv1[1] /= state->aspect; + uv2[0] = uv_average[index2].uv[0] - uv_average[index1].uv[0]; uv2[1] = uv_average[index2].uv[1] - uv_average[index1].uv[1]; + uv2[1] /= state->aspect; + normalize_v2(uv1); normalize_v2(uv2); - edgecos = uv1[0] * uv2[0] + uv1[1] * uv2[1]; - edgesin = uv1[0] * uv2[1] - uv2[0] * uv1[1]; + edgecos = dot_v2v2(uv1, uv2); + edgesin = cross_v2v2(uv1, uv2); rotation = (edgesin > 0.0f) ? +acosf(max_ff(-1.0f, min_ff(1.0f, edgecos))) : @@ -536,7 +544,9 @@ static void stitch_island_calculate_vert_rotation(UvElement *element, StitchStat negate_v2_v2(normal, state->normals + index_tmp2 * 2); edgecos = dot_v2v2(normal, state->normals + index_tmp1 * 2); edgesin = cross_v2v2(normal, state->normals + index_tmp1 * 2); - rotation += (edgesin > 0.0f) ? acosf(edgecos) : -acosf(edgecos); + rotation += (edgesin > 0.0f) ? + +acosf(max_ff(-1.0f, min_ff(1.0f, edgecos))) : + -acosf(max_ff(-1.0f, min_ff(1.0f, edgecos))); } } @@ -837,13 +847,13 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final) int previous_island = state->static_island; BMFace *efa; BMIter iter; - UVVertAverage *final_position; + UVVertAverage *final_position = NULL; char stitch_midpoints = state->midpoints; /* used to map uv indices to uvaverage indices for selection */ - unsigned int *uvfinal_map; + unsigned int *uvfinal_map = NULL; /* per face preview position in preview buffer */ - PreviewPosition *preview_position; + PreviewPosition *preview_position = NULL; /* cleanup previous preview */ stitch_preview_delete(state->stitch_preview); @@ -1157,6 +1167,14 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final) } } + /* take mean position here. For edge case, this can't be done inside the loop for shared uvverts */ + if (state->mode == STITCH_EDGE && stitch_midpoints) { + for (i = 0; i < state->total_separate_uvs; i++) { + final_position[i].uv[0] /= final_position[i].count; + final_position[i].uv[1] /= final_position[i].count; + } + } + /* second pass, calculate island rotation and translation before modifying any uvs */ if (state->snap_islands) { if (state->mode == STITCH_VERT) { @@ -1211,11 +1229,6 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final) for (i = 0; i < state->total_separate_uvs; i++) { UvElement *element = state->uvs[i]; - if (stitch_midpoints) { - final_position[i].uv[0] /= final_position[i].count; - final_position[i].uv[1] /= final_position[i].count; - } - if (element->flag & STITCH_STITCHABLE) { BMLoop *l; MLoopUV *luv; @@ -1419,18 +1432,19 @@ static void stitch_switch_selection_mode(StitchState *state) MEM_freeN(old_selection_stack); } -static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *normal) +static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *normal, float aspect) { BMLoop *l1 = edge->element->l; - BMLoop *l2 = l1->next; MLoopUV *luv1, *luv2; float tangent[2]; luv1 = CustomData_bmesh_get(&em->bm->ldata, l1->head.data, CD_MLOOPUV); - luv2 = CustomData_bmesh_get(&em->bm->ldata, l2->head.data, CD_MLOOPUV); + luv2 = CustomData_bmesh_get(&em->bm->ldata, l1->next->head.data, CD_MLOOPUV); sub_v2_v2v2(tangent, luv2->uv, luv1->uv); + tangent[1] /= aspect; + normal[0] = tangent[1]; normal[1] = -tangent[0]; @@ -1447,6 +1461,8 @@ static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *ar glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); glEnableClientState(GL_VERTEX_ARRAY); + glPointSize(pointsize * 2.0f); + glEnable(GL_BLEND); UI_ThemeColor4(TH_STITCH_PREVIEW_ACTIVE); @@ -1462,19 +1478,18 @@ static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *ar glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); UI_ThemeColor4(TH_STITCH_PREVIEW_EDGE); glDrawArrays(GL_POLYGON, index, stitch_preview->uvs_per_polygon[i]); + #if 0 + glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); + UI_ThemeColor4(TH_STITCH_PREVIEW_VERT); + glDrawArrays(GL_POLYGON, index, stitch_preview->uvs_per_polygon[i]); + #endif index += stitch_preview->uvs_per_polygon[i]; } - glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); -#if 0 - UI_ThemeColor4(TH_STITCH_PREVIEW_VERT); - glDrawArrays(GL_TRIANGLES, 0, stitch_preview->num_tris * 3); -#endif glDisable(GL_BLEND); /* draw vert preview */ if (state->mode == STITCH_VERT) { - glPointSize(pointsize * 2.0f); UI_ThemeColor4(TH_STITCH_PREVIEW_STITCHABLE); glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_stitchable); glDrawArrays(GL_POINTS, 0, stitch_preview->num_stitchable); @@ -1541,7 +1556,7 @@ static int stitch_init(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); ToolSettings *ts = scene->toolsettings; ARegion *ar = CTX_wm_region(C); - + float aspx, aspy; Object *obedit = CTX_data_edit_object(C); if (!ar) @@ -1595,6 +1610,9 @@ static int stitch_init(bContext *C, wmOperator *op) return 0; } + uvedit_get_aspect(scene, obedit, em, &aspx, &aspy); + state->aspect = aspx / aspy; + /* Entirely possible if redoing last operator that static island is bigger than total number of islands. * This ensures we get no hang in the island checking code in stitch_stitch_process_data. */ state->static_island %= state->element_map->totalIslands; @@ -1720,15 +1738,16 @@ static int stitch_init(bContext *C, wmOperator *op) * the winding of the polygon (assuming counter-clockwise flow). */ for (i = 0; i < total_edges; i++) { + UvEdge *edge = edges + i; float normal[2]; - if (edges[i].flag & STITCH_BOUNDARY) { - stitch_calculate_edge_normal(em, edges + i, normal); + if (edge->flag & STITCH_BOUNDARY) { + stitch_calculate_edge_normal(em, edge, normal, state->aspect); - add_v2_v2(state->normals + edges[i].uv1 * 2, normal); - add_v2_v2(state->normals + edges[i].uv2 * 2, normal); + add_v2_v2(state->normals + edge->uv1 * 2, normal); + add_v2_v2(state->normals + edge->uv2 * 2, normal); - normalize_v2(state->normals + edges[i].uv1 * 2); - normalize_v2(state->normals + edges[i].uv2 * 2); + normalize_v2(state->normals + edge->uv1 * 2); + normalize_v2(state->normals + edge->uv2 * 2); } } diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 2ca711a4a6a..81f548b2b5d 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -196,7 +196,7 @@ static int uvedit_have_selection(Scene *scene, BMEditMesh *em, short implicit) return 0; } -static void ED_uvedit_get_aspect(Scene *scene, Object *ob, BMEditMesh *em, float *aspx, float *aspy) +void uvedit_get_aspect(Scene *scene, Object *ob, BMEditMesh *em, float *aspx, float *aspy) { int sloppy = TRUE; int selected = FALSE; @@ -238,7 +238,7 @@ static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMEditMesh if (correct_aspect) { float aspx, aspy; - ED_uvedit_get_aspect(scene, ob, em, &aspx, &aspy); + uvedit_get_aspect(scene, ob, em, &aspx, &aspy); if (aspx != aspy) param_aspect_ratio(handle, aspx, aspy); @@ -423,7 +423,7 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B if (correct_aspect) { float aspx, aspy; - ED_uvedit_get_aspect(scene, ob, em, &aspx, &aspy); + uvedit_get_aspect(scene, ob, em, &aspx, &aspy); if (aspx != aspy) param_aspect_ratio(handle, aspx, aspy); @@ -1047,7 +1047,7 @@ static void correct_uv_aspect(Scene *scene, Object *ob, BMEditMesh *em) BMFace *efa; float scale, aspx, aspy; - ED_uvedit_get_aspect(scene, ob, em, &aspx, &aspy); + uvedit_get_aspect(scene, ob, em, &aspx, &aspy); if (aspx == aspy) return; @@ -1563,7 +1563,6 @@ static int cylinder_project_exec(bContext *C, wmOperator *op) uv_map_transform(C, op, center, rotmat); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) continue; @@ -1573,6 +1572,7 @@ static int cylinder_project_exec(bContext *C, wmOperator *op) uv_cylinder_project(luv->uv, l->v->co, center, rotmat); } + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); uv_map_mirror(em, efa, tf); } |