diff options
Diffstat (limited to 'source/blender/editors/transform')
-rw-r--r-- | source/blender/editors/transform/CMakeLists.txt | 6 | ||||
-rw-r--r-- | source/blender/editors/transform/transform.c | 377 | ||||
-rw-r--r-- | source/blender/editors/transform/transform.h | 19 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_constraints.c | 64 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_conversions.c | 223 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_generics.c | 122 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_manipulator.c | 2150 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_manipulator2d.c | 383 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_ops.c | 24 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_orientations.c | 114 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_snap.c | 90 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_snap_object.c | 32 |
12 files changed, 1855 insertions, 1749 deletions
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt index b7de49d8158..f38f6c064b8 100644 --- a/source/blender/editors/transform/CMakeLists.txt +++ b/source/blender/editors/transform/CMakeLists.txt @@ -29,6 +29,7 @@ set(INC ../../ikplugin ../../makesdna ../../makesrna + ../../render/extern/include ../../windowmanager ../../depsgraph ../../../../intern/guardedalloc @@ -46,6 +47,7 @@ set(SRC transform_generics.c transform_input.c transform_manipulator.c + transform_manipulator2d.c transform_ops.c transform_orientations.c transform_snap.c @@ -58,10 +60,6 @@ if(WITH_INTERNATIONAL) add_definitions(-DWITH_INTERNATIONAL) endif() -if(WITH_LEGACY_DEPSGRAPH) - add_definitions(-DWITH_LEGACY_DEPSGRAPH) -endif() - add_definitions(${GL_DEFINITIONS}) blender_add_lib(bf_editor_transform "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index b25ab1c6a89..e036ffd526c 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -43,6 +43,7 @@ #include "DNA_mask_types.h" #include "DNA_movieclip_types.h" #include "DNA_scene_types.h" /* PET modes */ +#include "DNA_workspace_types.h" #include "BLI_alloca.h" #include "BLI_utildefines.h" @@ -63,10 +64,16 @@ #include "BKE_unit.h" #include "BKE_mask.h" #include "BKE_report.h" +#include "BKE_workspace.h" + +#include "DEG_depsgraph.h" -#include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" +#include "GPU_matrix.h" + #include "ED_image.h" #include "ED_keyframing.h" #include "ED_screen.h" @@ -1598,8 +1605,16 @@ typedef enum { LEFT, RIGHT } ArrowDirection; + +#define POS_INDEX 0 +/* NOTE: this --^ is a bit hackish, but simplifies Gwn_VertFormat usage among functions + * private to this file - merwin + */ + static void drawArrow(ArrowDirection d, short offset, short length, short size) { + immBegin(GWN_PRIM_LINES, 6); + switch (d) { case LEFT: offset = -offset; @@ -1607,14 +1622,12 @@ static void drawArrow(ArrowDirection d, short offset, short length, short size) size = -size; ATTR_FALLTHROUGH; case RIGHT: - glBegin(GL_LINES); - glVertex2s(offset, 0); - glVertex2s(offset + length, 0); - glVertex2s(offset + length, 0); - glVertex2s(offset + length - size, -size); - glVertex2s(offset + length, 0); - glVertex2s(offset + length - size, size); - glEnd(); + immVertex2f(POS_INDEX, offset, 0); + immVertex2f(POS_INDEX, offset + length, 0); + immVertex2f(POS_INDEX, offset + length, 0); + immVertex2f(POS_INDEX, offset + length - size, -size); + immVertex2f(POS_INDEX, offset + length, 0); + immVertex2f(POS_INDEX, offset + length - size, size); break; case DOWN: @@ -1623,45 +1636,45 @@ static void drawArrow(ArrowDirection d, short offset, short length, short size) size = -size; ATTR_FALLTHROUGH; case UP: - glBegin(GL_LINES); - glVertex2s(0, offset); - glVertex2s(0, offset + length); - glVertex2s(0, offset + length); - glVertex2s(-size, offset + length - size); - glVertex2s(0, offset + length); - glVertex2s(size, offset + length - size); - glEnd(); + immVertex2f(POS_INDEX, 0, offset); + immVertex2f(POS_INDEX, 0, offset + length); + immVertex2f(POS_INDEX, 0, offset + length); + immVertex2f(POS_INDEX, -size, offset + length - size); + immVertex2f(POS_INDEX, 0, offset + length); + immVertex2f(POS_INDEX, size, offset + length - size); break; } + + immEnd(); } static void drawArrowHead(ArrowDirection d, short size) { + immBegin(GWN_PRIM_LINES, 4); + switch (d) { case LEFT: size = -size; ATTR_FALLTHROUGH; case RIGHT: - glBegin(GL_LINES); - glVertex2s(0, 0); - glVertex2s(-size, -size); - glVertex2s(0, 0); - glVertex2s(-size, size); - glEnd(); + immVertex2f(POS_INDEX, 0, 0); + immVertex2f(POS_INDEX, -size, -size); + immVertex2f(POS_INDEX, 0, 0); + immVertex2f(POS_INDEX, -size, size); break; case DOWN: size = -size; ATTR_FALLTHROUGH; case UP: - glBegin(GL_LINES); - glVertex2s(0, 0); - glVertex2s(-size, -size); - glVertex2s(0, 0); - glVertex2s(size, -size); - glEnd(); + immVertex2f(POS_INDEX, 0, 0); + immVertex2f(POS_INDEX, -size, -size); + immVertex2f(POS_INDEX, 0, 0); + immVertex2f(POS_INDEX, size, -size); break; } + + immEnd(); } static void drawArc(float size, float angle_start, float angle_end, int segments) @@ -1670,14 +1683,14 @@ static void drawArc(float size, float angle_start, float angle_end, int segments float angle; int a; - glBegin(GL_LINE_STRIP); + immBegin(GWN_PRIM_LINE_STRIP, segments + 1); for (angle = angle_start, a = 0; a < segments; angle += delta, a++) { - glVertex2f(cosf(angle) * size, sinf(angle) * size); + immVertex2f(POS_INDEX, cosf(angle) * size, sinf(angle) * size); } - glVertex2f(cosf(angle_end) * size, sinf(angle_end) * size); + immVertex2f(POS_INDEX, cosf(angle_end) * size, sinf(angle_end) * size); - glEnd(); + immEnd(); } static int helpline_poll(bContext *C) @@ -1693,12 +1706,9 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata) { TransInfo *t = (TransInfo *)customdata; - if (t->helpline != HLP_NONE && !(t->flag & T_USES_MANIPULATOR)) { + if (t->helpline != HLP_NONE) { float vecrot[3], cent[2]; - int mval[2]; - - mval[0] = x; - mval[1] = y; + float mval[3] = { x, y, 0.0f }; copy_v3_v3(vecrot, t->center); if (t->flag & T_EDIT) { @@ -1712,42 +1722,67 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata) projectFloatViewEx(t, vecrot, cent, V3D_PROJ_TEST_CLIP_ZERO); - glPushMatrix(); + gpuPushMatrix(); + + /* Dashed lines first. */ + if (ELEM(t->helpline, HLP_SPRING, HLP_ANGLE)) { + const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + UNUSED_VARS_NDEBUG(shdr_pos); /* silence warning */ + BLI_assert(shdr_pos == POS_INDEX); + + glLineWidth(1.0f); + + immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + + float viewport_size[4]; + glGetFloatv(GL_VIEWPORT, viewport_size); + immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); + + immUniform1i("num_colors", 0); /* "simple" mode */ + immUniformThemeColor(TH_VIEW_OVERLAY); + immUniform1f("dash_width", 6.0f); + immUniform1f("dash_factor", 0.5f); + + immBegin(GWN_PRIM_LINES, 2); + immVertex2fv(POS_INDEX, cent); + immVertex2f(POS_INDEX, (float)t->mval[0], (float)t->mval[1]); + immEnd(); + + immUnbindProgram(); + } + + /* And now, solid lines. */ + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + UNUSED_VARS_NDEBUG(pos); /* silence warning */ + BLI_assert(pos == POS_INDEX); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); switch (t->helpline) { case HLP_SPRING: - UI_ThemeColor(TH_VIEW_OVERLAY); - - setlinestyle(3); - glLineWidth(1); - glBegin(GL_LINES); - glVertex2iv(t->mval); - glVertex2fv(cent); - glEnd(); + immUniformThemeColor(TH_VIEW_OVERLAY); - glTranslate2iv(mval); - glRotatef(-RAD2DEGF(atan2f(cent[0] - t->mval[0], cent[1] - t->mval[1])), 0, 0, 1); + gpuTranslate3fv(mval); + gpuRotateAxis(-RAD2DEGF(atan2f(cent[0] - t->mval[0], cent[1] - t->mval[1])), 'Z'); - setlinestyle(0); - glLineWidth(3.0); + glLineWidth(3.0f); drawArrow(UP, 5, 10, 5); drawArrow(DOWN, 5, 10, 5); break; case HLP_HARROW: - UI_ThemeColor(TH_VIEW_OVERLAY); + immUniformThemeColor(TH_VIEW_OVERLAY); + gpuTranslate3fv(mval); - glTranslate2iv(mval); - - glLineWidth(3.0); + glLineWidth(3.0f); drawArrow(RIGHT, 5, 10, 5); drawArrow(LEFT, 5, 10, 5); break; case HLP_VARROW: - UI_ThemeColor(TH_VIEW_OVERLAY); + immUniformThemeColor(TH_VIEW_OVERLAY); - glTranslate2iv(mval); + gpuTranslate3fv(mval); - glLineWidth(3.0); + glLineWidth(3.0f); drawArrow(UP, 5, 10, 5); drawArrow(DOWN, 5, 10, 5); break; @@ -1758,33 +1793,26 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata) float dist = hypotf(dx, dy); float delta_angle = min_ff(15.0f / dist, (float)M_PI / 4.0f); float spacing_angle = min_ff(5.0f / dist, (float)M_PI / 12.0f); - UI_ThemeColor(TH_VIEW_OVERLAY); - setlinestyle(3); - glLineWidth(1); - glBegin(GL_LINES); - glVertex2iv(t->mval); - glVertex2fv(cent); - glEnd(); + immUniformThemeColor(TH_VIEW_OVERLAY); - glTranslatef(cent[0] - t->mval[0] + mval[0], cent[1] - t->mval[1] + mval[1], 0); + gpuTranslate3f(cent[0] - t->mval[0] + mval[0], cent[1] - t->mval[1] + mval[1], 0); - setlinestyle(0); - glLineWidth(3.0); + glLineWidth(3.0f); drawArc(dist, angle - delta_angle, angle - spacing_angle, 10); drawArc(dist, angle + spacing_angle, angle + delta_angle, 10); - glPushMatrix(); + gpuPushMatrix(); - glTranslatef(cosf(angle - delta_angle) * dist, sinf(angle - delta_angle) * dist, 0); - glRotatef(RAD2DEGF(angle - delta_angle), 0, 0, 1); + gpuTranslate3f(cosf(angle - delta_angle) * dist, sinf(angle - delta_angle) * dist, 0); + gpuRotateAxis(RAD2DEGF(angle - delta_angle), 'Z'); drawArrowHead(DOWN, 5); - glPopMatrix(); + gpuPopMatrix(); - glTranslatef(cosf(angle + delta_angle) * dist, sinf(angle + delta_angle) * dist, 0); - glRotatef(RAD2DEGF(angle + delta_angle), 0, 0, 1); + gpuTranslate3f(cosf(angle + delta_angle) * dist, sinf(angle + delta_angle) * dist, 0); + gpuRotateAxis(RAD2DEGF(angle + delta_angle), 'Z'); drawArrowHead(UP, 5); break; @@ -1794,18 +1822,18 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata) unsigned char col[3], col2[3]; UI_GetThemeColor3ubv(TH_GRID, col); - glTranslate2iv(mval); + gpuTranslate3fv(mval); - glLineWidth(3.0); + glLineWidth(3.0f); UI_make_axis_color(col, col2, 'X'); - glColor3ubv((GLubyte *)col2); + immUniformColor3ubv((GLubyte *)col2); drawArrow(RIGHT, 5, 10, 5); drawArrow(LEFT, 5, 10, 5); UI_make_axis_color(col, col2, 'Y'); - glColor3ubv((GLubyte *)col2); + immUniformColor3ubv((GLubyte *)col2); drawArrow(UP, 5, 10, 5); drawArrow(DOWN, 5, 10, 5); @@ -1813,7 +1841,8 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata) } } - glPopMatrix(); + immUnbindProgram(); + gpuPopMatrix(); } } @@ -1821,7 +1850,7 @@ static void drawTransformView(const struct bContext *C, ARegion *UNUSED(ar), voi { TransInfo *t = arg; - glLineWidth(1.0); + glLineWidth(1.0f); drawConstraint(t); drawPropCircle(C, t); @@ -1841,8 +1870,9 @@ static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar) int xco, yco; ED_region_visible_rect(ar, &rect); - - BLF_width_and_height_default(printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]); + + const int font_id = BLF_default(); + BLF_width_and_height(font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]); xco = (rect.xmax - U.widget_unit) - (int)printable_size[0]; yco = (rect.ymax - U.widget_unit); @@ -1850,7 +1880,9 @@ static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar) /* warning text (to clarify meaning of overlays) * - original color was red to match the icon, but that clashes badly with a less nasty border */ - UI_ThemeColorShade(TH_TEXT_HI, -50); + unsigned char color[3]; + UI_GetThemeColorShade3ubv(TH_TEXT_HI, -50, color); + BLF_color3ubv(font_id, color); #ifdef WITH_INTERNATIONAL BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX); #else @@ -1873,7 +1905,8 @@ static void drawTransformPixel(const struct bContext *UNUSED(C), ARegion *ar, vo { TransInfo *t = arg; Scene *scene = t->scene; - Object *ob = OBACT; + SceneLayer *sl = t->scene_layer; + Object *ob = OBACT(sl); /* draw autokeyframing hint in the corner * - only draw if enabled (advanced users may be distracted/annoyed), @@ -1984,6 +2017,10 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) View3D *v3d = t->view; v3d->twmode = t->current_orientation; + + BLI_assert(((v3d->custom_orientation_index == -1) && (t->custom_orientation == NULL)) || + (BKE_workspace_transform_orientation_get_index( + CTX_wm_workspace(C), t->custom_orientation) == v3d->custom_orientation_index)); } } } @@ -2003,15 +2040,20 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) { - /* constraint orientation can be global, event if user selects something else - * so use the orientation in the constraint if set - * */ - if (t->con.mode & CON_APPLY) { - RNA_enum_set(op->ptr, "constraint_orientation", t->con.orientation); - } - else { - RNA_enum_set(op->ptr, "constraint_orientation", t->current_orientation); + /* constraint orientation can be global, even if user selects something else + * so use the orientation in the constraint if set */ + short orientation = (t->con.mode & CON_APPLY) ? t->con.orientation : t->current_orientation; + + if (orientation == V3D_MANIP_CUSTOM) { + WorkSpace *workspace = CTX_wm_workspace(C); + const int custom_orientation_index = BKE_workspace_transform_orientation_get_index( + workspace, t->custom_orientation); + + /* Maybe we need a t->con.custom_orientation? Seems like it would always match t->custom_orientation. */ + orientation = V3D_MANIP_CUSTOM + custom_orientation_index; + BLI_assert(orientation >= V3D_MANIP_CUSTOM); } + RNA_enum_set(op->ptr, "constraint_orientation", orientation); if (t->con.mode & CON_APPLY) { if (t->con.mode & CON_AXIS0) { @@ -2583,6 +2625,9 @@ static void constraintTransLim(TransInfo *t, TransData *td) if (td->con) { const bConstraintTypeInfo *ctiLoc = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_LOCLIMIT); const bConstraintTypeInfo *ctiDist = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_DISTLIMIT); + EvaluationContext eval_ctx; + + CTX_data_eval_ctx(t->context, &eval_ctx); bConstraintOb cob = {NULL}; bConstraint *con; @@ -2632,7 +2677,7 @@ static void constraintTransLim(TransInfo *t, TransData *td) } /* get constraint targets if needed */ - BKE_constraint_targets_for_solving_get(con, &cob, &targets, ctime); + BKE_constraint_targets_for_solving_get(&eval_ctx, con, &cob, &targets, ctime); /* do constraint */ cti->evaluate_constraint(con, &cob, &targets); @@ -3402,7 +3447,7 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3]) constraintTransLim(t, td); } -static void applyResize(TransInfo *t, const int mval[2]) +static void applyResize(TransInfo *t, const int UNUSED(mval[2])) { TransData *td; float mat[3][3]; @@ -3413,15 +3458,7 @@ static void applyResize(TransInfo *t, const int mval[2]) copy_v3_v3(t->values, t->auto_values); } else { - float ratio; - - /* for manipulator, center handle, the scaling can't be done relative to center */ - if ((t->flag & T_USES_MANIPULATOR) && t->con.mode == 0) { - ratio = 1.0f - ((t->mouse.imval[0] - mval[0]) + (t->mouse.imval[1] - mval[1])) / 100.0f; - } - else { - ratio = t->values[0]; - } + float ratio = t->values[0]; copy_v3_fl(t->values, ratio); @@ -5248,23 +5285,14 @@ static void ElementBoneSize(TransInfo *t, TransData *td, float mat[3][3]) td->loc[1] = oldy; } -static void applyBoneSize(TransInfo *t, const int mval[2]) +static void applyBoneSize(TransInfo *t, const int UNUSED(mval[2])) { TransData *td = t->data; float size[3], mat[3][3]; - float ratio; + float ratio = t->values[0]; int i; char str[UI_MAX_DRAW_STR]; - - // TRANSFORM_FIX_ME MOVE TO MOUSE INPUT - /* for manipulator, center handle, the scaling can't be done relative to center */ - if ((t->flag & T_USES_MANIPULATOR) && t->con.mode == 0) { - ratio = 1.0f - ((t->mouse.imval[0] - mval[0]) + (t->mouse.imval[1] - mval[1])) / 100.0f; - } - else { - ratio = t->values[0]; - } - + copy_v3_fl(size, ratio); snapGridIncrement(t, size); @@ -6856,10 +6884,12 @@ static void drawEdgeSlide(TransInfo *t) glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glPushAttrib(GL_CURRENT_BIT | GL_LINE_BIT | GL_POINT_BIT); - glPushMatrix(); + gpuPushMatrix(); + gpuMultMatrix(t->obedit->obmat); - glMultMatrixf(t->obedit->obmat); + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); if (sld->use_even == true) { float co_a[3], co_b[3], co_mark[3]; @@ -6873,39 +6903,35 @@ static void drawEdgeSlide(TransInfo *t) add_v3_v3v3(co_b, curr_sv->v_co_orig, curr_sv->dir_side[1]); glLineWidth(line_size); - UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); - glBegin(GL_LINES); + immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); + immBeginAtMost(GWN_PRIM_LINES, 4); if (curr_sv->v_side[0]) { - glVertex3fv(curr_sv->v_side[0]->co); - glVertex3fv(curr_sv->v_co_orig); + immVertex3fv(pos, curr_sv->v_side[0]->co); + immVertex3fv(pos, curr_sv->v_co_orig); } if (curr_sv->v_side[1]) { - glVertex3fv(curr_sv->v_side[1]->co); - glVertex3fv(curr_sv->v_co_orig); + immVertex3fv(pos, curr_sv->v_side[1]->co); + immVertex3fv(pos, curr_sv->v_co_orig); } - glEnd(); + immEnd(); - UI_ThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade); + immUniformThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade); glPointSize(ctrl_size); - glBegin(GL_POINTS); + immBegin(GWN_PRIM_POINTS, 1); if (sld->flipped) { - if (curr_sv->v_side[1]) glVertex3fv(curr_sv->v_side[1]->co); + if (curr_sv->v_side[1]) immVertex3fv(pos, curr_sv->v_side[1]->co); } else { - if (curr_sv->v_side[0]) glVertex3fv(curr_sv->v_side[0]->co); + if (curr_sv->v_side[0]) immVertex3fv(pos, curr_sv->v_side[0]->co); } - glEnd(); + immEnd(); - UI_ThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade); + immUniformThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade); glPointSize(guide_size); - glBegin(GL_POINTS); -#if 0 - interp_v3_v3v3(co_mark, co_b, co_a, fac); - glVertex3fv(co_mark); -#endif + immBegin(GWN_PRIM_POINTS, 1); interp_line_v3_v3v3v3(co_mark, co_b, curr_sv->v_co_orig, co_a, fac); - glVertex3fv(co_mark); - glEnd(); + immVertex3fv(pos, co_mark); + immEnd(); } else { if (is_clamp == false) { @@ -6915,8 +6941,8 @@ static void drawEdgeSlide(TransInfo *t) const int alpha_shade = -160; glLineWidth(line_size); - UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); - glBegin(GL_LINES); + immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); + immBegin(GWN_PRIM_LINES, sld->totsv * 2); sv = sld->sv; for (i = 0; i < sld->totsv; i++, sv++) { @@ -6934,18 +6960,19 @@ static void drawEdgeSlide(TransInfo *t) add_v3_v3(a, sv->v_co_orig); add_v3_v3(b, sv->v_co_orig); - glVertex3fv(a); - glVertex3fv(b); + immVertex3fv(pos, a); + immVertex3fv(pos, b); } - glEnd(); + immEnd(); } else { BLI_assert(0); } } - glPopMatrix(); - glPopAttrib(); + immUnbindProgram(); + + gpuPopMatrix(); glDisable(GL_BLEND); @@ -7469,19 +7496,22 @@ static void drawVertSlide(TransInfo *t) glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glPushAttrib(GL_CURRENT_BIT | GL_LINE_BIT | GL_POINT_BIT); - glPushMatrix(); - - glMultMatrixf(t->obedit->obmat); + gpuPushMatrix(); + gpuMultMatrix(t->obedit->obmat); glLineWidth(line_size); - UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); - glBegin(GL_LINES); + + const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); + + immBegin(GWN_PRIM_LINES, sld->totsv * 2); if (is_clamp) { sv = sld->sv; for (i = 0; i < sld->totsv; i++, sv++) { - glVertex3fv(sv->co_orig_3d); - glVertex3fv(sv->co_link_orig_3d[sv->co_link_curr]); + immVertex3fv(shdr_pos, sv->co_orig_3d); + immVertex3fv(shdr_pos, sv->co_link_orig_3d[sv->co_link_curr]); } } else { @@ -7494,21 +7524,21 @@ static void drawVertSlide(TransInfo *t) add_v3_v3(a, sv->co_orig_3d); add_v3_v3(b, sv->co_orig_3d); - glVertex3fv(a); - glVertex3fv(b); + immVertex3fv(shdr_pos, a); + immVertex3fv(shdr_pos, b); } } - glEnd(); + immEnd(); glPointSize(ctrl_size); - glBegin(GL_POINTS); - glVertex3fv((sld->flipped && sld->use_even) ? + immBegin(GWN_PRIM_POINTS, 1); + immVertex3fv(shdr_pos, (sld->flipped && sld->use_even) ? curr_sv->co_link_orig_3d[curr_sv->co_link_curr] : curr_sv->co_orig_3d); - glEnd(); + immEnd(); - glDisable(GL_BLEND); + immUnbindProgram(); /* direction from active vertex! */ if ((t->mval[0] != t->mouse.imval[0]) || @@ -7532,19 +7562,28 @@ static void drawVertSlide(TransInfo *t) add_v3_v3(co_dest_3d, curr_sv->co_orig_3d); - glLineWidth(1); - setlinestyle(1); + glLineWidth(1.0f); + + immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); + + float viewport_size[4]; + glGetFloatv(GL_VIEWPORT, viewport_size); + immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); + + immUniform1i("num_colors", 0); /* "simple" mode */ + immUniformColor4f(1.0f, 1.0f, 1.0f, 1.0f); + immUniform1f("dash_width", 6.0f); + immUniform1f("dash_factor", 0.5f); - cpack(0xffffff); - glBegin(GL_LINES); - glVertex3fv(curr_sv->co_orig_3d); - glVertex3fv(co_dest_3d); + immBegin(GWN_PRIM_LINES, 2); + immVertex3fv(shdr_pos, curr_sv->co_orig_3d); + immVertex3fv(shdr_pos, co_dest_3d); + immEnd(); - glEnd(); + immUnbindProgram(); } - glPopMatrix(); - glPopAttrib(); + gpuPopMatrix(); if (v3d && v3d->zbuf) glEnable(GL_DEPTH_TEST); diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 06a60456cdb..60ad61e3475 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -37,6 +37,8 @@ #include "ED_numinput.h" #include "ED_view3d.h" +#include "RE_engine.h" + #include "DNA_listBase.h" /* ************************** Types ***************************** */ @@ -50,6 +52,7 @@ struct Object; struct View3D; struct ScrArea; struct Scene; +struct SceneLayer; struct bConstraint; struct wmKeyMap; struct wmKeyConfig; @@ -59,6 +62,7 @@ struct wmTimer; struct ARegion; struct ReportList; struct EditBone; +struct RenderEngineType; struct SnapObjectContext; /* transinfo->redraw */ @@ -446,6 +450,7 @@ typedef struct TransInfo { short launch_event; /* event type used to launch transform */ short current_orientation; + TransformOrientation *custom_orientation; /* this gets used when current_orientation is V3D_MANIP_CUSTOM */ short twtype; /* backup from view3d, to restore on end */ short prop_mode; @@ -464,6 +469,8 @@ typedef struct TransInfo { struct ScrArea *sa; struct ARegion *ar; struct Scene *scene; + struct SceneLayer *scene_layer; + struct RenderEngineType *engine; struct ToolSettings *settings; struct wmTimer *animtimer; struct wmKeyMap *keymap; /* so we can do lookups for header text */ @@ -496,8 +503,7 @@ typedef struct TransInfo { #define T_CAMERA (1 << 4) // trans on points, having no rotation/scale #define T_POINTS (1 << 6) - // for manipulator exceptions, like scaling using center point, drawing help lines -#define T_USES_MANIPULATOR (1 << 7) +/* empty slot - (1 << 7) */ /* restrictions flags */ #define T_ALL_RESTRICTIONS ((1 << 8)|(1 << 9)|(1 << 10)) @@ -637,7 +643,10 @@ void flushTransMasking(TransInfo *t); void flushTransPaintCurve(TransInfo *t); void restoreBones(TransInfo *t); -/*********************** exported from transform_manipulator.c ********** */ +/*********************** transform_manipulator.c ********** */ + +#define MANIPULATOR_AXIS_LINE_WIDTH 2.0f + bool gimbal_axis(struct Object *ob, float gmat[3][3]); /* return 0 when no gimbal for selection */ /*********************** TransData Creation and General Handling *********** */ @@ -652,7 +661,7 @@ bool transdata_check_local_islands(TransInfo *t, short around); int count_set_pose_transflags(int *out_mode, short around, struct Object *ob); /* auto-keying stuff used by special_aftertrans_update */ -void autokeyframe_ob_cb_func(struct bContext *C, struct Scene *scene, struct View3D *v3d, struct Object *ob, int tmode); +void autokeyframe_ob_cb_func(struct bContext *C, struct Scene *scene, struct SceneLayer *sl, struct View3D *v3d, struct Object *ob, int tmode); void autokeyframe_pose_cb_func(struct bContext *C, struct Scene *scene, struct View3D *v3d, struct Object *ob, int tmode, short targetless_ik); /*********************** Constraints *****************************/ @@ -787,7 +796,7 @@ bool createSpaceNormalTangent(float mat[3][3], const float normal[3], const floa struct TransformOrientation *addMatrixSpace(struct bContext *C, float mat[3][3], const char *name, const bool overwrite); -bool applyTransformOrientation(const struct bContext *C, float mat[3][3], char r_name[64], int index); +bool applyTransformOrientation(const struct TransformOrientation *ts, float r_mat[3][3], char r_name[64]); #define ORIENTATION_NONE 0 #define ORIENTATION_NORMAL 1 diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 5621eede543..4e409e7f77f 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -40,9 +40,11 @@ #include "DNA_space_types.h" #include "DNA_view3d_types.h" -#include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_immediate.h" +#include "GPU_matrix.h" + #include "BLI_math.h" #include "BLI_utildefines.h" #include "BLI_string.h" @@ -651,7 +653,7 @@ void setLocalConstraint(TransInfo *t, int mode, const char text[]) */ void setUserConstraint(TransInfo *t, short orientation, int mode, const char ftext[]) { - char text[40]; + char text[256]; switch (orientation) { case V3D_MANIP_GLOBAL: @@ -683,10 +685,15 @@ void setUserConstraint(TransInfo *t, short orientation, int mode, const char fte BLI_snprintf(text, sizeof(text), ftext, IFACE_("gimbal")); setConstraint(t, t->spacemtx, mode, text); break; - default: /* V3D_MANIP_CUSTOM */ - BLI_snprintf(text, sizeof(text), ftext, t->spacename); + case V3D_MANIP_CUSTOM: + { + char orientation_str[128]; + BLI_snprintf(orientation_str, sizeof(orientation_str), "%s \"%s\"", + IFACE_("custom orientation"), t->custom_orientation->name); + BLI_snprintf(text, sizeof(text), ftext, orientation_str); setConstraint(t, t->spacemtx, mode, text); break; + } } t->con.orientation = orientation; @@ -704,8 +711,6 @@ void drawConstraint(TransInfo *t) return; if (!(tc->mode & CON_APPLY)) return; - if (t->flag & T_USES_MANIPULATOR) - return; if (t->flag & T_NO_CONSTRAINT) return; @@ -715,7 +720,6 @@ void drawConstraint(TransInfo *t) else { if (tc->mode & CON_SELECT) { float vec[3]; - char col2[3] = {255, 255, 255}; int depth_test_enabled; convertViewVec(t, vec, (t->mval[0] - t->con.imval[0]), (t->mval[1] - t->con.imval[1])); @@ -725,18 +729,29 @@ void drawConstraint(TransInfo *t) drawLine(t, t->center_global, tc->mtx[1], 'Y', 0); drawLine(t, t->center_global, tc->mtx[2], 'Z', 0); - glColor3ubv((GLubyte *)col2); - depth_test_enabled = glIsEnabled(GL_DEPTH_TEST); if (depth_test_enabled) glDisable(GL_DEPTH_TEST); - setlinestyle(1); - glBegin(GL_LINES); - glVertex3fv(t->center_global); - glVertex3fv(vec); - glEnd(); - setlinestyle(0); + const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); + + float viewport_size[4]; + glGetFloatv(GL_VIEWPORT, viewport_size); + immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); + + immUniform1i("num_colors", 0); /* "simple" mode */ + immUniformColor4f(1.0f, 1.0f, 1.0f, 1.0f); + immUniform1f("dash_width", 2.0f); + immUniform1f("dash_factor", 0.5f); + + immBegin(GWN_PRIM_LINES, 2); + immVertex3fv(shdr_pos, t->center_global); + immVertex3fv(shdr_pos, vec); + immEnd(); + + immUnbindProgram(); if (depth_test_enabled) glEnable(GL_DEPTH_TEST); @@ -762,8 +777,6 @@ void drawPropCircle(const struct bContext *C, TransInfo *t) float tmat[4][4], imat[4][4]; int depth_test_enabled; - UI_ThemeColor(TH_GRID); - if (t->spacetype == SPACE_VIEW3D && rv3d != NULL) { copy_m4_m4(tmat, rv3d->viewmat); invert_m4_m4(imat, tmat); @@ -773,13 +786,13 @@ void drawPropCircle(const struct bContext *C, TransInfo *t) unit_m4(imat); } - glPushMatrix(); + gpuPushMatrix(); if (t->spacetype == SPACE_VIEW3D) { /* pass */ } else if (t->spacetype == SPACE_IMAGE) { - glScalef(1.0f / t->aspect[0], 1.0f / t->aspect[1], 1.0f); + gpuScale2f(1.0f / t->aspect[0], 1.0f / t->aspect[1]); } else if (ELEM(t->spacetype, SPACE_IPO, SPACE_ACTION)) { /* only scale y */ @@ -789,21 +802,28 @@ void drawPropCircle(const struct bContext *C, TransInfo *t) float ysize = BLI_rctf_size_y(datamask); float xmask = BLI_rcti_size_x(mask); float ymask = BLI_rcti_size_y(mask); - glScalef(1.0f, (ysize / xsize) * (xmask / ymask), 1.0f); + gpuScale2f(1.0f, (ysize / xsize) * (xmask / ymask)); } depth_test_enabled = glIsEnabled(GL_DEPTH_TEST); if (depth_test_enabled) glDisable(GL_DEPTH_TEST); + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformThemeColor(TH_GRID); + set_inverted_drawing(1); - drawcircball(GL_LINE_LOOP, t->center_global, t->prop_size, imat); + imm_drawcircball(t->center_global, t->prop_size, imat, pos); set_inverted_drawing(0); + immUnbindProgram(); + if (depth_test_enabled) glEnable(GL_DEPTH_TEST); - glPopMatrix(); + gpuPopMatrix(); } } diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index af83b666bba..0905e3785da 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -68,10 +68,10 @@ #include "BKE_context.h" #include "BKE_crazyspace.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" #include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_gpencil.h" +#include "BKE_layer.h" #include "BKE_key.h" #include "BKE_main.h" #include "BKE_mesh.h" @@ -118,6 +118,7 @@ #include "RNA_access.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" #include "transform.h" #include "bmesh.h" @@ -285,13 +286,13 @@ static void set_prop_dist(TransInfo *t, const bool with_dist) static void createTransTexspace(TransInfo *t) { - Scene *scene = t->scene; + SceneLayer *sl = t->scene_layer; TransData *td; Object *ob; ID *id; short *texflag; - ob = OBACT; + ob = OBACT(sl); if (ob == NULL) { // Shouldn't logically happen, but still... t->total = 0; @@ -836,14 +837,9 @@ void transform_autoik_update(TransInfo *t, short mode) changed |= pchan_autoik_adjust(pchan, *chainlen); } -#ifdef WITH_LEGACY_DEPSGRAPH - if (!DEG_depsgraph_use_legacy()) -#endif - { - if (changed) { - /* TODO(sergey): Consider doing partial update only. */ - DAG_relations_tag_update(G.main); - } + if (changed) { + /* TODO(sergey): Consider doing partial update only. */ + DEG_relations_tag_update(G.main); } } @@ -853,9 +849,7 @@ static void pose_grab_with_ik_clear(Object *ob) bKinematicConstraint *data; bPoseChannel *pchan; bConstraint *con, *next; -#ifdef WITH_LEGACY_DEPSGRAPH - bool need_dependency_update = false; -#endif + bool relations_changed = false; for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { /* clear all temporary lock flags */ @@ -869,10 +863,9 @@ static void pose_grab_with_ik_clear(Object *ob) if (con->type == CONSTRAINT_TYPE_KINEMATIC) { data = con->data; if (data->flag & CONSTRAINT_IK_TEMP) { + relations_changed = true; + /* iTaSC needs clear for removed constraints */ -#ifdef WITH_LEGACY_DEPSGRAPH - need_dependency_update = true; -#endif BIK_clear_data(ob->pose); BLI_remlink(&pchan->constraints, con); @@ -887,12 +880,9 @@ static void pose_grab_with_ik_clear(Object *ob) } } -#ifdef WITH_LEGACY_DEPSGRAPH - if (!DEG_depsgraph_use_legacy() && need_dependency_update) -#endif - { + if (relations_changed) { /* TODO(sergey): Consider doing partial update only. */ - DAG_relations_tag_update(G.main); + DEG_relations_tag_update(G.main); } } @@ -1046,13 +1036,8 @@ static short pose_grab_with_ik(Object *ob) /* iTaSC needs clear for new IK constraints */ if (tot_ik) { BIK_clear_data(ob->pose); -#ifdef WITH_LEGACY_DEPSGRAPH - if (!DEG_depsgraph_use_legacy()) -#endif - { - /* TODO(sergey): Consuder doing partial update only. */ - DAG_relations_tag_update(G.main); - } + /* TODO(sergey): Consuder doing partial update only. */ + DEG_relations_tag_update(G.main); } return (tot_ik) ? 1 : 0; @@ -1908,7 +1893,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t) Base *base = CTX_data_active_base(C); Object *ob = CTX_data_active_object(C); ParticleEditSettings *pset = PE_settings(t->scene); - PTCacheEdit *edit = PE_get_current(t->scene, ob); + PTCacheEdit *edit = PE_get_current(t->scene, t->scene_layer, ob); ParticleSystem *psys = NULL; ParticleSystemModifierData *psmd = NULL; PTCacheEditPoint *point; @@ -2025,8 +2010,9 @@ static void createTransParticleVerts(bContext *C, TransInfo *t) void flushTransParticles(TransInfo *t) { Scene *scene = t->scene; - Object *ob = OBACT; - PTCacheEdit *edit = PE_get_current(scene, ob); + SceneLayer *sl = t->scene_layer; + Object *ob = OBACT(sl); + PTCacheEdit *edit = PE_get_current(scene, sl, ob); ParticleSystem *psys = edit->psys; ParticleSystemModifierData *psmd = NULL; PTCacheEditPoint *point; @@ -2065,7 +2051,9 @@ void flushTransParticles(TransInfo *t) point->flag |= PEP_EDIT_RECALC; } - PE_update_object(scene, OBACT, 1); + EvaluationContext eval_ctx; + CTX_data_eval_ctx(t->context, &eval_ctx); + PE_update_object(&eval_ctx, scene, sl, OBACT(sl), 1); } /* ********************* mesh ****************** */ @@ -2477,6 +2465,7 @@ static void createTransEditVerts(TransInfo *t) { TransData *tob = NULL; TransDataExtension *tx = NULL; + EvaluationContext eval_ctx; BMEditMesh *em = BKE_editmesh_from_object(t->obedit); Mesh *me = t->obedit->data; BMesh *bm = em->bm; @@ -2495,6 +2484,10 @@ static void createTransEditVerts(TransInfo *t) int island_info_tot; int *island_vert_map = NULL; + DEG_evaluation_context_init_from_scene(&eval_ctx, + t->scene, t->scene_layer, t->engine, + DAG_EVAL_VIEWPORT); + /* Even for translation this is needed because of island-orientation, see: T51651. */ const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS); /* Original index of our connected vertex when connected distances are calculated. @@ -2578,7 +2571,7 @@ static void createTransEditVerts(TransInfo *t) if (modifiers_isCorrectableDeformed(t->scene, t->obedit)) { /* check if we can use deform matrices for modifier from the * start up to stack, they are more accurate than quats */ - totleft = BKE_crazyspace_get_first_deform_matrices_editbmesh(t->scene, t->obedit, em, &defmats, &defcos); + totleft = BKE_crazyspace_get_first_deform_matrices_editbmesh(&eval_ctx, t->scene, t->obedit, em, &defmats, &defcos); } /* if we still have more modifiers, also do crazyspace @@ -2591,7 +2584,7 @@ static void createTransEditVerts(TransInfo *t) if (totleft > 0) #endif { - mappedcos = BKE_crazyspace_get_mapped_editverts(t->scene, t->obedit); + mappedcos = BKE_crazyspace_get_mapped_editverts(&eval_ctx, t->scene, t->obedit); quats = MEM_mallocN(em->bm->totvert * sizeof(*quats), "crazy quats"); BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !prop_mode); if (mappedcos) @@ -2960,7 +2953,6 @@ static void createTransUVs(bContext *C, TransInfo *t) const bool is_prop_connected = (t->flag & T_PROP_CONNECTED) != 0; const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS); const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); if (!ED_space_image_show_uvedit(sima, t->obedit)) return; @@ -2984,10 +2976,9 @@ static void createTransUVs(bContext *C, TransInfo *t) } BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); BMLoop *l; - if (!uvedit_face_visible_test(scene, ima, efa, tf)) { + if (!uvedit_face_visible_test(scene, ima, efa)) { BM_elem_flag_disable(efa, BM_ELEM_TAG); continue; } @@ -5419,6 +5410,9 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) Scene *scene = t->scene; bool constinv; bool skip_invert = false; + EvaluationContext eval_ctx; + + CTX_data_eval_ctx(t->context, &eval_ctx); if (t->mode != TFM_DUMMY && ob->rigidbody_object) { float rot[3][3], scale[3]; @@ -5466,11 +5460,11 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) if (skip_invert == false && constinv == false) { ob->transflag |= OB_NO_CONSTRAINTS; /* BKE_object_where_is_calc_time checks this */ - BKE_object_where_is_calc(t->scene, ob); + BKE_object_where_is_calc(&eval_ctx, t->scene, ob); ob->transflag &= ~OB_NO_CONSTRAINTS; } else - BKE_object_where_is_calc(t->scene, ob); + BKE_object_where_is_calc(&eval_ctx, t->scene, ob); td->ob = ob; @@ -5542,12 +5536,15 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) /* it deselects Bases, so we have to call the clear function always after */ static void set_trans_object_base_flags(TransInfo *t) { + /* TODO(sergey): Get rid of global, use explicit main. */ + Main *bmain = G.main; + SceneLayer *sl = t->scene_layer; Scene *scene = t->scene; - View3D *v3d = t->view; + Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, sl, true); /* * if Base selected and has parent selected: - * base->flag = BA_WAS_SEL + * base->flag_legacy = BA_WAS_SEL */ Base *base; @@ -5556,32 +5553,36 @@ static void set_trans_object_base_flags(TransInfo *t) return; /* makes sure base flags and object flags are identical */ - BKE_scene_base_flag_to_objects(t->scene); + BKE_scene_base_flag_to_objects(t->scene_layer); /* Make sure depsgraph is here. */ - DAG_scene_relations_update(G.main, t->scene); + DEG_graph_relations_update(depsgraph, bmain, scene, sl); /* handle pending update events, otherwise they got copied below */ - for (base = scene->base.first; base; base = base->next) { + EvaluationContext eval_ctx; + DEG_evaluation_context_init_from_scene(&eval_ctx, + t->scene, t->scene_layer, t->engine, + DAG_EVAL_VIEWPORT); + for (base = sl->object_bases.first; base; base = base->next) { if (base->object->recalc & OB_RECALC_ALL) { /* TODO(sergey): Ideally, it's not needed. */ - BKE_object_handle_update(G.main->eval_ctx, t->scene, base->object); + BKE_object_handle_update(&eval_ctx, t->scene, base->object); } } - for (base = scene->base.first; base; base = base->next) { - base->flag &= ~BA_WAS_SEL; + for (base = sl->object_bases.first; base; base = base->next) { + base->flag_legacy &= ~BA_WAS_SEL; - if (TESTBASELIB_BGMODE(v3d, scene, base)) { + if (TESTBASELIB_BGMODE(base)) { Object *ob = base->object; Object *parsel = ob->parent; /* if parent selected, deselect */ while (parsel) { - if (parsel->flag & SELECT) { - Base *parbase = BKE_scene_base_find(scene, parsel); + if (parsel->base_flag & BASE_SELECTED) { + Base *parbase = BKE_scene_layer_base_find(sl, parsel); if (parbase) { /* in rare cases this can fail */ - if (TESTBASELIB_BGMODE(v3d, scene, parbase)) { + if (TESTBASELIB_BGMODE(parbase)) { break; } } @@ -5594,27 +5595,27 @@ static void set_trans_object_base_flags(TransInfo *t) if ((t->around == V3D_AROUND_LOCAL_ORIGINS) && (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL)) { - base->flag |= BA_TRANSFORM_CHILD; + base->flag_legacy |= BA_TRANSFORM_CHILD; } else { - base->flag &= ~SELECT; - base->flag |= BA_WAS_SEL; + base->flag &= ~BASE_SELECTED; + base->flag_legacy |= BA_WAS_SEL; } } - DAG_id_tag_update(&ob->id, OB_RECALC_OB); + DEG_id_tag_update(&ob->id, OB_RECALC_OB); } } /* all recalc flags get flushed to all layers, so a layer flip later on works fine */ - DAG_scene_flush_update(G.main, t->scene, -1, 0); + DEG_graph_flush_update(bmain, depsgraph); /* and we store them temporal in base (only used for transform code) */ /* this because after doing updates, the object->recalc is cleared */ - for (base = scene->base.first; base; base = base->next) { + for (base = sl->object_bases.first; base; base = base->next) { if (base->object->recalc & OB_RECALC_OB) - base->flag |= BA_HAS_RECALC_OB; + base->flag_legacy |= BA_HAS_RECALC_OB; if (base->object->recalc & OB_RECALC_DATA) - base->flag |= BA_HAS_RECALC_DATA; + base->flag_legacy |= BA_HAS_RECALC_DATA; } } @@ -5636,8 +5637,11 @@ static bool mark_children(Object *ob) static int count_proportional_objects(TransInfo *t) { int total = 0; + /* TODO(sergey): Get rid of global, use explicit main. */ + Main *bmain = G.main; + SceneLayer *sl = t->scene_layer; Scene *scene = t->scene; - View3D *v3d = t->view; + Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, sl, true); Base *base; /* rotations around local centers are allowed to propagate, so we take all objects */ @@ -5645,8 +5649,8 @@ static int count_proportional_objects(TransInfo *t) (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL))) { /* mark all parents */ - for (base = scene->base.first; base; base = base->next) { - if (TESTBASELIB_BGMODE(v3d, scene, base)) { + for (base = sl->object_bases.first; base; base = base->next) { + if (TESTBASELIB_BGMODE(base)) { Object *parent = base->object->parent; /* flag all parents */ @@ -5658,25 +5662,27 @@ static int count_proportional_objects(TransInfo *t) } /* mark all children */ - for (base = scene->base.first; base; base = base->next) { + for (base = sl->object_bases.first; base; base = base->next) { /* all base not already selected or marked that is editable */ - if ((base->object->flag & (SELECT | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 && - (BASE_EDITABLE_BGMODE(v3d, scene, base))) + if ((base->object->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 && + (base->flag & BASE_SELECTED) == 0 && + (BASE_EDITABLE_BGMODE(base))) { mark_children(base->object); } } } - for (base = scene->base.first; base; base = base->next) { + for (base = sl->object_bases.first; base; base = base->next) { Object *ob = base->object; /* if base is not selected, not a parent of selection or not a child of selection and it is editable */ - if ((ob->flag & (SELECT | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 && - (BASE_EDITABLE_BGMODE(v3d, scene, base))) + if ((ob->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 && + (base->flag & BASE_SELECTED) == 0 && + (BASE_EDITABLE_BGMODE(base))) { - DAG_id_tag_update(&ob->id, OB_RECALC_OB); + DEG_id_tag_update(&ob->id, OB_RECALC_OB); total += 1; } @@ -5684,16 +5690,16 @@ static int count_proportional_objects(TransInfo *t) /* all recalc flags get flushed to all layers, so a layer flip later on works fine */ - DAG_scene_relations_update(G.main, t->scene); - DAG_scene_flush_update(G.main, t->scene, -1, 0); + DEG_graph_relations_update(depsgraph, bmain, scene, sl); + DEG_graph_flush_update(bmain, depsgraph); /* and we store them temporal in base (only used for transform code) */ /* this because after doing updates, the object->recalc is cleared */ - for (base = scene->base.first; base; base = base->next) { + for (base = sl->object_bases.first; base; base = base->next) { if (base->object->recalc & OB_RECALC_OB) - base->flag |= BA_HAS_RECALC_OB; + base->flag_legacy |= BA_HAS_RECALC_OB; if (base->object->recalc & OB_RECALC_DATA) - base->flag |= BA_HAS_RECALC_DATA; + base->flag_legacy |= BA_HAS_RECALC_DATA; } return total; @@ -5701,14 +5707,15 @@ static int count_proportional_objects(TransInfo *t) static void clear_trans_object_base_flags(TransInfo *t) { - Scene *sce = t->scene; + SceneLayer *sl = t->scene_layer; Base *base; - for (base = sce->base.first; base; base = base->next) { - if (base->flag & BA_WAS_SEL) - base->flag |= SELECT; + for (base = sl->object_bases.first; base; base = base->next) { + if (base->flag_legacy & BA_WAS_SEL) { + base->flag |= BASE_SELECTED; + } - base->flag &= ~(BA_WAS_SEL | BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA | BA_TEMP_TAG | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT); + base->flag_legacy &= ~(BA_WAS_SEL | BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA | BA_TEMP_TAG | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT); } } @@ -5716,7 +5723,7 @@ static void clear_trans_object_base_flags(TransInfo *t) * tmode: should be a transform mode */ // NOTE: context may not always be available, so must check before using it as it's a luxury for a few cases -void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob, int tmode) +void autokeyframe_ob_cb_func(bContext *C, Scene *scene, SceneLayer *sl, View3D *v3d, Object *ob, int tmode) { ID *id = &ob->id; FCurve *fcu; @@ -5765,7 +5772,7 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob, } else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) { if (v3d->around == V3D_AROUND_ACTIVE) { - if (ob != OBACT) + if (ob != OBACT(sl)) do_loc = true; } else if (v3d->around == V3D_AROUND_CURSOR) @@ -5776,7 +5783,7 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob, } else if (tmode == TFM_RESIZE) { if (v3d->around == V3D_AROUND_ACTIVE) { - if (ob != OBACT) + if (ob != OBACT(sl)) do_loc = true; } else if (v3d->around == V3D_AROUND_CURSOR) @@ -5954,7 +5961,7 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o */ if (C && (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) { //ED_pose_clear_paths(C, ob); // XXX for now, don't need to clear - ED_pose_recalculate_paths(scene, ob); + ED_pose_recalculate_paths(C, scene, ob); } } else { @@ -6109,10 +6116,13 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t) * */ void special_aftertrans_update(bContext *C, TransInfo *t) { + EvaluationContext eval_ctx; Object *ob; // short redrawipo=0, resetslowpar=1; const bool canceled = (t->state == TRANS_CANCEL); const bool duplicate = (t->mode == TFM_TIME_DUPLICATE); + + CTX_data_eval_ctx(C, &eval_ctx); /* early out when nothing happened */ if (t->total == 0 || t->mode == TFM_DUMMY) @@ -6264,9 +6274,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t) // fixme... some of this stuff is not good if (ob) { if (ob->pose || BKE_key_from_object(ob)) - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); else - DAG_id_tag_update(&ob->id, OB_RECALC_OB); + DEG_id_tag_update(&ob->id, OB_RECALC_OB); } /* 3 cases here for curve cleanups: @@ -6452,7 +6462,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t) * we need to update the pose otherwise no updates get called during * transform and the auto-ik is not applied. see [#26164] */ struct Object *pose_ob = t->poseobj; - BKE_pose_where_is(t->scene, pose_ob); + BKE_pose_where_is(&eval_ctx, t->scene, pose_ob); } /* set BONE_TRANSFORM flags for autokey, manipulator draw might have changed them */ @@ -6476,24 +6486,24 @@ void special_aftertrans_update(bContext *C, TransInfo *t) /* automatic inserting of keys and unkeyed tagging - only if transform wasn't canceled (or TFM_DUMMY) */ if (!canceled && (t->mode != TFM_DUMMY)) { autokeyframe_pose_cb_func(C, t->scene, (View3D *)t->view, ob, t->mode, targetless_ik); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); } else if (arm->flag & ARM_DELAYDEFORM) { /* old optimize trick... this enforces to bypass the depgraph */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); ob->recalc = 0; // is set on OK position already by recalcData() } else - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); } else if (t->options & CTX_PAINT_CURVE) { /* pass */ } - else if ((t->scene->basact) && - (ob = t->scene->basact->object) && + else if ((t->scene_layer->basact) && + (ob = t->scene_layer->basact->object) && (ob->mode & OB_MODE_PARTICLE_EDIT) && - PE_get_current(t->scene, ob)) + PE_get_current(t->scene, t->scene_layer, ob)) { /* do nothing */ } @@ -6524,17 +6534,17 @@ void special_aftertrans_update(bContext *C, TransInfo *t) /* pointcache refresh */ if (BKE_ptcache_object_reset(t->scene, ob, PTCACHE_RESET_OUTDATED)) - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); /* Needed for proper updating of "quick cached" dynamics. */ /* Creates troubles for moving animated objects without */ /* autokey though, probably needed is an anim sys override? */ /* Please remove if some other solution is found. -jahka */ - DAG_id_tag_update(&ob->id, OB_RECALC_OB); + DEG_id_tag_update(&ob->id, OB_RECALC_OB); /* Set autokey if necessary */ if (!canceled) { - autokeyframe_ob_cb_func(C, t->scene, (View3D *)t->view, ob, t->mode); + autokeyframe_ob_cb_func(C, t->scene, t->scene_layer, (View3D *)t->view, ob, t->mode); } /* restore rigid body transform */ @@ -6569,8 +6579,6 @@ int special_transform_moving(TransInfo *t) static void createTransObject(bContext *C, TransInfo *t) { - Scene *scene = t->scene; - TransData *td = NULL; TransDataExtension *tx; const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; @@ -6620,15 +6628,16 @@ static void createTransObject(bContext *C, TransInfo *t) CTX_DATA_END; if (is_prop_edit) { - View3D *v3d = t->view; + SceneLayer *sl = t->scene_layer; Base *base; - for (base = scene->base.first; base; base = base->next) { + for (base = sl->object_bases.first; base; base = base->next) { Object *ob = base->object; /* if base is not selected, not a parent of selection or not a child of selection and it is editable */ - if ((ob->flag & (SELECT | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 && - BASE_EDITABLE_BGMODE(v3d, scene, base)) + if ((ob->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 && + (base->flag & BASE_SELECTED) == 0 && + BASE_EDITABLE_BGMODE(base)) { td->protectflag = ob->protectflag; td->ext = tx; @@ -8075,7 +8084,8 @@ static void createTransGPencil(bContext *C, TransInfo *t) void createTransData(bContext *C, TransInfo *t) { Scene *scene = t->scene; - Object *ob = OBACT; + SceneLayer *sl = t->scene_layer; + Object *ob = OBACT(sl); /* if tests must match recalcData for correct updates */ if (t->options & CTX_TEXTURE) { @@ -8240,17 +8250,16 @@ void createTransData(bContext *C, TransInfo *t) * lines below just check is also visible */ Object *ob_armature = modifiers_isDeformedByArmature(ob); if (ob_armature && ob_armature->mode & OB_MODE_POSE) { - Base *base_arm = BKE_scene_base_find(t->scene, ob_armature); + Base *base_arm = BKE_scene_layer_base_find(t->scene_layer, ob_armature); if (base_arm) { - View3D *v3d = t->view; - if (BASE_VISIBLE(v3d, base_arm)) { + if (BASE_VISIBLE(base_arm)) { createTransPose(t, ob_armature); } } } } - else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_start_edit(PE_get_current(scene, ob))) { + else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_start_edit(PE_get_current(scene, sl, ob))) { createTransParticleVerts(C, t); t->flag |= T_POINTS; diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 277e01d1e2b..8d2fb595e24 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -62,8 +62,8 @@ #include "RNA_access.h" -#include "BIF_gl.h" -#include "BIF_glutil.h" +#include "GPU_immediate.h" +#include "GPU_matrix.h" #include "BIK_api.h" @@ -71,7 +71,6 @@ #include "BKE_action.h" #include "BKE_armature.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" #include "BKE_fcurve.h" #include "BKE_lattice.h" #include "BKE_library.h" @@ -82,6 +81,9 @@ #include "BKE_editmesh.h" #include "BKE_tracking.h" #include "BKE_mask.h" +#include "BKE_workspace.h" + +#include "DEG_depsgraph.h" #include "ED_anim_api.h" #include "ED_armature.h" @@ -102,6 +104,8 @@ #include "WM_types.h" #include "WM_api.h" +#include "RE_engine.h" + #include "UI_resources.h" #include "UI_view2d.h" @@ -314,7 +318,7 @@ static bool fcu_test_selected(FCurve *fcu) /* helper for recalcData() - for Action Editor transforms */ static void recalcData_actedit(TransInfo *t) { - Scene *scene = t->scene; + SceneLayer *sl = t->scene_layer; SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first; bAnimContext ac = {NULL}; @@ -325,7 +329,8 @@ static void recalcData_actedit(TransInfo *t) /* initialize relevant anim-context 'context' data from TransInfo data */ /* NOTE: sync this with the code in ANIM_animdata_get_context() */ ac.scene = t->scene; - ac.obact = OBACT; + ac.scene_layer = t->scene_layer; + ac.obact = OBACT(sl); ac.sa = t->sa; ac.ar = t->ar; ac.sl = (t->sa) ? t->sa->spacedata.first : NULL; @@ -362,7 +367,7 @@ static void recalcData_actedit(TransInfo *t) static void recalcData_graphedit(TransInfo *t) { SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first; - Scene *scene; + SceneLayer *sl = t->scene_layer; ListBase anim_data = {NULL, NULL}; bAnimContext ac = {NULL}; @@ -373,8 +378,9 @@ static void recalcData_graphedit(TransInfo *t) /* initialize relevant anim-context 'context' data from TransInfo data */ /* NOTE: sync this with the code in ANIM_animdata_get_context() */ - scene = ac.scene = t->scene; - ac.obact = OBACT; + ac.scene = t->scene; + ac.scene_layer = t->scene_layer; + ac.obact = OBACT(sl); ac.sa = t->sa; ac.ar = t->ar; ac.sl = (t->sa) ? t->sa->spacedata.first : NULL; @@ -636,7 +642,7 @@ static void recalcData_mask_common(TransInfo *t) flushTransMasking(t); - DAG_id_tag_update(&mask->id, 0); + DEG_id_tag_update(&mask->id, 0); } /* helper for recalcData() - for Image Editor transforms */ @@ -655,7 +661,7 @@ static void recalcData_image(TransInfo *t) if (sima->flag & SI_LIVE_UNWRAP) ED_uvedit_live_unwrap_re_solve(); - DAG_id_tag_update(t->obedit->data, 0); + DEG_id_tag_update(t->obedit->data, 0); } } @@ -698,7 +704,7 @@ static void recalcData_spaceclip(TransInfo *t) track = track->next; } - DAG_id_tag_update(&clip->id, 0); + DEG_id_tag_update(&clip->id, 0); } else if (t->options & CTX_MASK) { recalcData_mask_common(t); @@ -708,7 +714,10 @@ static void recalcData_spaceclip(TransInfo *t) /* helper for recalcData() - for object transforms, typically in the 3D view */ static void recalcData_objects(TransInfo *t) { - Base *base = t->scene->basact; + Base *base = t->scene_layer->basact; + EvaluationContext eval_ctx; + + CTX_data_eval_ctx(t->context, &eval_ctx); if (t->obedit) { if (ELEM(t->obedit->type, OB_CURVE, OB_SURF)) { @@ -721,7 +730,7 @@ static void recalcData_objects(TransInfo *t) applyProject(t); } - DAG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */ + DEG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */ if (t->state == TRANS_CANCEL) { while (nu) { @@ -745,7 +754,7 @@ static void recalcData_objects(TransInfo *t) applyProject(t); } - DAG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */ + DEG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */ if (la->editlatt->latt->flag & LT_OUTSIDE) outside_lattice(la->editlatt->latt); } @@ -767,7 +776,7 @@ static void recalcData_objects(TransInfo *t) projectVertSlideData(t, false); } - DAG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */ + DEG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */ EDBM_mesh_normals_update(em); BKE_editmesh_tessface_calc(em); @@ -865,7 +874,7 @@ static void recalcData_objects(TransInfo *t) if (t->state != TRANS_CANCEL) { applyProject(t); } - DAG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */ + DEG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */ } } else if ((t->flag & T_POSE) && t->poseobj) { @@ -888,14 +897,14 @@ static void recalcData_objects(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 */ + DEG_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); + BKE_pose_where_is(&eval_ctx, t->scene, ob); } - else if (base && (base->object->mode & OB_MODE_PARTICLE_EDIT) && PE_get_current(t->scene, base->object)) { + else if (base && (base->object->mode & OB_MODE_PARTICLE_EDIT) && PE_get_current(t->scene, t->scene_layer, base->object)) { if (t->state != TRANS_CANCEL) { applyProject(t); } @@ -925,16 +934,16 @@ static void recalcData_objects(TransInfo *t) // TODO: autokeyframe calls need some setting to specify to add samples (FPoints) instead of keyframes? if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) { animrecord_check_state(t->scene, &ob->id, t->animtimer); - autokeyframe_ob_cb_func(t->context, t->scene, (View3D *)t->view, ob, t->mode); + autokeyframe_ob_cb_func(t->context, t->scene, t->scene_layer, (View3D *)t->view, ob, t->mode); } /* sets recalc flags fully, instead of flushing existing ones * otherwise proxies don't function correctly */ - DAG_id_tag_update(&ob->id, OB_RECALC_OB); + DEG_id_tag_update(&ob->id, OB_RECALC_OB); if (t->flag & T_TEXTURE) - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); } } } @@ -1031,11 +1040,10 @@ void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis if (t->spacetype == SPACE_VIEW3D) { View3D *v3d = t->view; - glPushMatrix(); - - //if (t->obedit) glLoadMatrixf(t->obedit->obmat); // sets opengl viewing - - + gpuPushMatrix(); + + // if (t->obedit) gpuLoadMatrix(t->obedit->obmat); // sets opengl viewing + copy_v3_v3(v3, dir); mul_v3_fl(v3, v3d->far); @@ -1049,15 +1057,20 @@ void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis UI_GetThemeColor3ubv(TH_GRID, col); } UI_make_axis_color(col, col2, axis); - glColor3ubv(col2); - - setlinestyle(0); - glBegin(GL_LINES); - glVertex3fv(v1); - glVertex3fv(v2); - glEnd(); - - glPopMatrix(); + + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor3ubv(col2); + + immBegin(GWN_PRIM_LINES, 2); + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); + immEnd(); + + immUnbindProgram(); + + gpuPopMatrix(); } } @@ -1103,15 +1116,19 @@ static int initTransInfo_edit_pet_to_flag(const int proportional) void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event) { Scene *sce = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); ToolSettings *ts = CTX_data_tool_settings(C); ARegion *ar = CTX_wm_region(C); ScrArea *sa = CTX_wm_area(C); Object *obedit = CTX_data_edit_object(C); Object *ob = CTX_data_active_object(C); bGPdata *gpd = CTX_data_gpencil_data(C); + RenderEngineType *engine = CTX_data_engine(C); PropertyRNA *prop; t->scene = sce; + t->scene_layer = sl; + t->engine = engine; t->sa = sa; t->ar = ar; t->obedit = obedit; @@ -1219,7 +1236,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->animtimer = (animscreen) ? animscreen->animtimer : NULL; /* turn manipulator off during transform */ - // FIXME: but don't do this when USING the manipulator... if (t->flag & T_MODAL) { t->twtype = v3d->twtype; v3d->twtype = 0; @@ -1234,6 +1250,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } t->current_orientation = v3d->twmode; + t->custom_orientation = BKE_workspace_transform_orientation_find( + CTX_wm_workspace(C), v3d->custom_orientation_index); /* exceptional case */ if (t->around == V3D_AROUND_LOCAL_ORIGINS) { @@ -1324,11 +1342,22 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve if (op && ((prop = RNA_struct_find_property(op->ptr, "constraint_orientation")) && RNA_property_is_set(op->ptr, prop))) { - t->current_orientation = RNA_property_enum_get(op->ptr, prop); + short orientation = RNA_property_enum_get(op->ptr, prop); + TransformOrientation *custom_orientation = NULL; - if (t->current_orientation >= V3D_MANIP_CUSTOM + BIF_countTransformOrientation(C)) { - t->current_orientation = V3D_MANIP_GLOBAL; + if (orientation >= V3D_MANIP_CUSTOM) { + if (orientation >= V3D_MANIP_CUSTOM + BIF_countTransformOrientation(C)) { + orientation = V3D_MANIP_GLOBAL; + } + else { + custom_orientation = BKE_workspace_transform_orientation_find( + CTX_wm_workspace(C), orientation - V3D_MANIP_CUSTOM); + orientation = V3D_MANIP_CUSTOM; + } } + + t->current_orientation = orientation; + t->custom_orientation = custom_orientation; } if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) && @@ -1773,8 +1802,8 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3]) } } else if (t->flag & T_POSE) { - Scene *scene = t->scene; - Object *ob = OBACT; + SceneLayer *sl = t->scene_layer; + Object *ob = OBACT(sl); if (ob) { bPoseChannel *pchan = BKE_pose_channel_active(ob); if (pchan && (!select_only || (pchan->bone->flag & BONE_SELECTED))) { @@ -1784,7 +1813,7 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3]) } } else if (t->options & CTX_PAINT_CURVE) { - Paint *p = BKE_paint_get_active(t->scene); + Paint *p = BKE_paint_get_active(t->scene, t->scene_layer); Brush *br = p->brush; PaintCurve *pc = br->paint_curve; copy_v3_v3(r_center, pc->points[pc->add_index - 1].bez.vec[1]); @@ -1793,9 +1822,10 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3]) } else { /* object mode */ - Scene *scene = t->scene; - Object *ob = OBACT; - if (ob && (!select_only || (ob->flag & SELECT))) { + SceneLayer *sl = t->scene_layer; + Object *ob = OBACT(sl); + Base *base = BASACT(sl); + if (ob && ((!select_only) || ((base->flag & BASE_SELECTED) != 0))) { copy_v3_v3(r_center, ob->obmat[3]); ok = true; } diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index 9a362ee609f..be33cb85f0e 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -59,6 +59,7 @@ #include "BKE_editmesh.h" #include "BKE_lattice.h" #include "BKE_gpencil.h" +#include "BKE_workspace.h" #include "BIF_gl.h" @@ -67,16 +68,25 @@ #include "ED_armature.h" #include "ED_curve.h" +#include "ED_object.h" #include "ED_particle.h" #include "ED_view3d.h" #include "ED_gpencil.h" +#include "ED_screen.h" +#include "ED_manipulator_library.h" #include "UI_resources.h" /* local module include */ #include "transform.h" +#include "MEM_guardedalloc.h" + #include "GPU_select.h" +#include "GPU_immediate.h" +#include "GPU_matrix.h" + +#define USE_AXIS_BOUNDS /* return codes for select, and drawing flags */ @@ -88,35 +98,348 @@ #define MAN_ROT_X (1 << 3) #define MAN_ROT_Y (1 << 4) #define MAN_ROT_Z (1 << 5) -#define MAN_ROT_V (1 << 6) -#define MAN_ROT_T (1 << 7) -#define MAN_ROT_C (MAN_ROT_X | MAN_ROT_Y | MAN_ROT_Z | MAN_ROT_V | MAN_ROT_T) +#define MAN_ROT_C (MAN_ROT_X | MAN_ROT_Y | MAN_ROT_Z) #define MAN_SCALE_X (1 << 8) #define MAN_SCALE_Y (1 << 9) #define MAN_SCALE_Z (1 << 10) #define MAN_SCALE_C (MAN_SCALE_X | MAN_SCALE_Y | MAN_SCALE_Z) -/* color codes */ - -#define MAN_RGB 0 -#define MAN_GHOST 1 -#define MAN_MOVECOL 2 - /* threshold for testing view aligned manipulator axis */ #define TW_AXIS_DOT_MIN 0.02f #define TW_AXIS_DOT_MAX 0.1f +/* axes as index */ +enum { + MAN_AXIS_TRANS_X = 0, + MAN_AXIS_TRANS_Y, + MAN_AXIS_TRANS_Z, + MAN_AXIS_TRANS_C, + + MAN_AXIS_TRANS_XY, + MAN_AXIS_TRANS_YZ, + MAN_AXIS_TRANS_ZX, +#define MAN_AXIS_RANGE_TRANS_START MAN_AXIS_TRANS_X +#define MAN_AXIS_RANGE_TRANS_END (MAN_AXIS_TRANS_ZX + 1) + + MAN_AXIS_ROT_X, + MAN_AXIS_ROT_Y, + MAN_AXIS_ROT_Z, + MAN_AXIS_ROT_C, + MAN_AXIS_ROT_T, /* trackball rotation */ +#define MAN_AXIS_RANGE_ROT_START MAN_AXIS_ROT_X +#define MAN_AXIS_RANGE_ROT_END (MAN_AXIS_ROT_T + 1) + + MAN_AXIS_SCALE_X, + MAN_AXIS_SCALE_Y, + MAN_AXIS_SCALE_Z, + MAN_AXIS_SCALE_C, + MAN_AXIS_SCALE_XY, + MAN_AXIS_SCALE_YZ, + MAN_AXIS_SCALE_ZX, +#define MAN_AXIS_RANGE_SCALE_START MAN_AXIS_SCALE_X +#define MAN_AXIS_RANGE_SCALE_END (MAN_AXIS_SCALE_ZX + 1) + + MAN_AXIS_LAST = MAN_AXIS_RANGE_SCALE_END, +}; + +/* axis types */ +enum { + MAN_AXES_ALL = 0, + MAN_AXES_TRANSLATE, + MAN_AXES_ROTATE, + MAN_AXES_SCALE, +}; + +typedef struct ManipulatorGroup { + bool all_hidden; + + struct wmManipulator *manipulators[MAN_AXIS_LAST]; +} ManipulatorGroup; + struct TransformBounds { float center[3]; /* Center for transform widget. */ float min[3], max[3]; /* Boundbox of selection for transform widget. */ + +#ifdef USE_AXIS_BOUNDS + /* Normalized axis */ + float axis[3][3]; + float axis_min[3], axis_max[3]; +#endif }; +/* -------------------------------------------------------------------- */ +/** \name Utilities + * \{ */ + +/* loop over axes */ +#define MAN_ITER_AXES_BEGIN(axis, axis_idx) \ + { \ + wmManipulator *axis; \ + int axis_idx; \ + for (axis_idx = 0; axis_idx < MAN_AXIS_LAST; axis_idx++) { \ + axis = manipulator_get_axis_from_index(man, axis_idx); + +#define MAN_ITER_AXES_END \ + } \ + } ((void)0) + +static wmManipulator *manipulator_get_axis_from_index(const ManipulatorGroup *man, const short axis_idx) +{ + BLI_assert(IN_RANGE_INCL(axis_idx, (float)MAN_AXIS_TRANS_X, (float)MAN_AXIS_LAST)); + return man->manipulators[axis_idx]; +} + +static short manipulator_get_axis_type(const int axis_idx) +{ + if (axis_idx >= MAN_AXIS_RANGE_TRANS_START && axis_idx < MAN_AXIS_RANGE_TRANS_END) { + return MAN_AXES_TRANSLATE; + } + if (axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) { + return MAN_AXES_ROTATE; + } + if (axis_idx >= MAN_AXIS_RANGE_SCALE_START && axis_idx < MAN_AXIS_RANGE_SCALE_END) { + return MAN_AXES_SCALE; + } + BLI_assert(0); + return -1; +} + +static uint manipulator_orientation_axis(const int axis_idx, bool *r_is_plane) +{ + switch (axis_idx) { + case MAN_AXIS_TRANS_YZ: + case MAN_AXIS_SCALE_YZ: + if (r_is_plane) { + *r_is_plane = true; + } + ATTR_FALLTHROUGH; + case MAN_AXIS_TRANS_X: + case MAN_AXIS_ROT_X: + case MAN_AXIS_SCALE_X: + return 0; + + case MAN_AXIS_TRANS_ZX: + case MAN_AXIS_SCALE_ZX: + if (r_is_plane) { + *r_is_plane = true; + } + ATTR_FALLTHROUGH; + case MAN_AXIS_TRANS_Y: + case MAN_AXIS_ROT_Y: + case MAN_AXIS_SCALE_Y: + return 1; + + case MAN_AXIS_TRANS_XY: + case MAN_AXIS_SCALE_XY: + if (r_is_plane) { + *r_is_plane = true; + } + ATTR_FALLTHROUGH; + case MAN_AXIS_TRANS_Z: + case MAN_AXIS_ROT_Z: + case MAN_AXIS_SCALE_Z: + return 2; + } + return 3; +} + +static bool manipulator_is_axis_visible( + const View3D *v3d, const RegionView3D *rv3d, + const float idot[3], const int axis_type, const int axis_idx) +{ + bool is_plane = false; + const uint aidx_norm = manipulator_orientation_axis(axis_idx, &is_plane); + /* don't draw axis perpendicular to the view */ + if (aidx_norm < 3) { + float idot_axis = idot[aidx_norm]; + if (is_plane) { + idot_axis = 1.0f - idot_axis; + } + if (idot_axis < TW_AXIS_DOT_MIN) { + return false; + } + } + + if ((axis_type == MAN_AXES_TRANSLATE && !(v3d->twtype & V3D_MANIP_TRANSLATE)) || + (axis_type == MAN_AXES_ROTATE && !(v3d->twtype & V3D_MANIP_ROTATE)) || + (axis_type == MAN_AXES_SCALE && !(v3d->twtype & V3D_MANIP_SCALE))) + { + return false; + } + + switch (axis_idx) { + case MAN_AXIS_TRANS_X: + return (rv3d->twdrawflag & MAN_TRANS_X); + case MAN_AXIS_TRANS_Y: + return (rv3d->twdrawflag & MAN_TRANS_Y); + case MAN_AXIS_TRANS_Z: + return (rv3d->twdrawflag & MAN_TRANS_Z); + case MAN_AXIS_TRANS_C: + return (rv3d->twdrawflag & MAN_TRANS_C); + case MAN_AXIS_ROT_X: + return (rv3d->twdrawflag & MAN_ROT_X); + case MAN_AXIS_ROT_Y: + return (rv3d->twdrawflag & MAN_ROT_Y); + case MAN_AXIS_ROT_Z: + return (rv3d->twdrawflag & MAN_ROT_Z); + case MAN_AXIS_ROT_C: + case MAN_AXIS_ROT_T: + return (rv3d->twdrawflag & MAN_ROT_C); + case MAN_AXIS_SCALE_X: + return (rv3d->twdrawflag & MAN_SCALE_X); + case MAN_AXIS_SCALE_Y: + return (rv3d->twdrawflag & MAN_SCALE_Y); + case MAN_AXIS_SCALE_Z: + return (rv3d->twdrawflag & MAN_SCALE_Z); + case MAN_AXIS_SCALE_C: + return (rv3d->twdrawflag & MAN_SCALE_C && (v3d->twtype & V3D_MANIP_TRANSLATE) == 0); + case MAN_AXIS_TRANS_XY: + return (rv3d->twdrawflag & MAN_TRANS_X && + rv3d->twdrawflag & MAN_TRANS_Y && + (v3d->twtype & V3D_MANIP_ROTATE) == 0); + case MAN_AXIS_TRANS_YZ: + return (rv3d->twdrawflag & MAN_TRANS_Y && + rv3d->twdrawflag & MAN_TRANS_Z && + (v3d->twtype & V3D_MANIP_ROTATE) == 0); + case MAN_AXIS_TRANS_ZX: + return (rv3d->twdrawflag & MAN_TRANS_Z && + rv3d->twdrawflag & MAN_TRANS_X && + (v3d->twtype & V3D_MANIP_ROTATE) == 0); + case MAN_AXIS_SCALE_XY: + return (rv3d->twdrawflag & MAN_SCALE_X && + rv3d->twdrawflag & MAN_SCALE_Y && + (v3d->twtype & V3D_MANIP_TRANSLATE) == 0 && + (v3d->twtype & V3D_MANIP_ROTATE) == 0); + case MAN_AXIS_SCALE_YZ: + return (rv3d->twdrawflag & MAN_SCALE_Y && + rv3d->twdrawflag & MAN_SCALE_Z && + (v3d->twtype & V3D_MANIP_TRANSLATE) == 0 && + (v3d->twtype & V3D_MANIP_ROTATE) == 0); + case MAN_AXIS_SCALE_ZX: + return (rv3d->twdrawflag & MAN_SCALE_Z && + rv3d->twdrawflag & MAN_SCALE_X && + (v3d->twtype & V3D_MANIP_TRANSLATE) == 0 && + (v3d->twtype & V3D_MANIP_ROTATE) == 0); + } + return false; +} + +static void manipulator_get_axis_color( + const int axis_idx, const float idot[3], + float r_col[4], float r_col_hi[4]) +{ + /* alpha values for normal/highlighted states */ + const float alpha = 0.6f; + const float alpha_hi = 1.0f; + float alpha_fac; + + bool is_plane = false; + const int axis_idx_norm = manipulator_orientation_axis(axis_idx, &is_plane); + /* get alpha fac based on axis angle, to fade axis out when hiding it because it points towards view */ + if (axis_idx_norm < 3) { + float idot_axis = idot[axis_idx_norm]; + if (is_plane) { + idot_axis = 1.0f - idot_axis; + } + alpha_fac = (idot_axis > TW_AXIS_DOT_MAX) ? + 1.0f : (idot_axis < TW_AXIS_DOT_MIN) ? + 0.0f : ((idot_axis - TW_AXIS_DOT_MIN) / (TW_AXIS_DOT_MAX - TW_AXIS_DOT_MIN)); + } + else { + /* trackball rotation axis is a special case, we only draw a slight overlay */ + alpha_fac = (axis_idx == MAN_AXIS_ROT_T) ? 0.1f : 1.0f; + } + + switch (axis_idx) { + case MAN_AXIS_TRANS_X: + case MAN_AXIS_ROT_X: + case MAN_AXIS_SCALE_X: + case MAN_AXIS_TRANS_YZ: + case MAN_AXIS_SCALE_YZ: + UI_GetThemeColor4fv(TH_AXIS_X, r_col); + break; + case MAN_AXIS_TRANS_Y: + case MAN_AXIS_ROT_Y: + case MAN_AXIS_SCALE_Y: + case MAN_AXIS_TRANS_ZX: + case MAN_AXIS_SCALE_ZX: + UI_GetThemeColor4fv(TH_AXIS_Y, r_col); + break; + case MAN_AXIS_TRANS_Z: + case MAN_AXIS_ROT_Z: + case MAN_AXIS_SCALE_Z: + case MAN_AXIS_TRANS_XY: + case MAN_AXIS_SCALE_XY: + UI_GetThemeColor4fv(TH_AXIS_Z, r_col); + break; + case MAN_AXIS_TRANS_C: + case MAN_AXIS_ROT_C: + case MAN_AXIS_SCALE_C: + case MAN_AXIS_ROT_T: + copy_v4_fl(r_col, 1.0f); + break; + } + + copy_v4_v4(r_col_hi, r_col); + + r_col[3] = alpha * alpha_fac; + r_col_hi[3] = alpha_hi * alpha_fac; +} + +static void manipulator_get_axis_constraint(const int axis_idx, int r_axis[3]) +{ + zero_v3_int(r_axis); + + switch (axis_idx) { + case MAN_AXIS_TRANS_X: + case MAN_AXIS_ROT_X: + case MAN_AXIS_SCALE_X: + r_axis[0] = 1; + break; + case MAN_AXIS_TRANS_Y: + case MAN_AXIS_ROT_Y: + case MAN_AXIS_SCALE_Y: + r_axis[1] = 1; + break; + case MAN_AXIS_TRANS_Z: + case MAN_AXIS_ROT_Z: + case MAN_AXIS_SCALE_Z: + r_axis[2] = 1; + break; + case MAN_AXIS_TRANS_XY: + case MAN_AXIS_SCALE_XY: + r_axis[0] = r_axis[1] = 1; + break; + case MAN_AXIS_TRANS_YZ: + case MAN_AXIS_SCALE_YZ: + r_axis[1] = r_axis[2] = 1; + break; + case MAN_AXIS_TRANS_ZX: + case MAN_AXIS_SCALE_ZX: + r_axis[2] = r_axis[0] = 1; + break; + default: + break; + } +} + + +/* **************** Preparation Stuff **************** */ + /* transform widget center calc helper for below */ static void calc_tw_center(struct TransformBounds *tbounds, const float co[3]) { minmax_v3v3_v3(tbounds->min, tbounds->max, co); add_v3_v3(tbounds->center, co); + +#ifdef USE_AXIS_BOUNDS + for (int i = 0; i < 3; i++) { + const float d = dot_v3v3(tbounds->axis[i], co); + tbounds->axis_min[i] = min_ff(d, tbounds->axis_min[i]); + tbounds->axis_max[i] = max_ff(d, tbounds->axis_max[i]); + } +#endif } static void protectflag_to_drawflags(short protectflag, short *drawflags) @@ -261,16 +584,19 @@ bool gimbal_axis(Object *ob, float gmat[3][3]) /* centroid, boundbox, of selection */ /* returns total items selected */ -static int calc_manipulator_stats(const bContext *C, struct TransformBounds *tbounds) +static int calc_manipulator_stats( + const bContext *C, bool use_only_center, + struct TransformBounds *tbounds) { ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); Object *obedit = CTX_data_edit_object(C); View3D *v3d = sa->spacedata.first; RegionView3D *rv3d = ar->regiondata; Base *base; - Object *ob = OBACT; + Object *ob = OBACT(sl); bGPdata *gpd = CTX_data_gpencil_data(C); const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)); int a, totsel = 0; @@ -278,12 +604,104 @@ static int calc_manipulator_stats(const bContext *C, struct TransformBounds *tbo /* transform widget matrix */ unit_m4(rv3d->twmat); +#ifdef USE_AXIS_BOUNDS + unit_m3(rv3d->tw_axis_matrix); + zero_v3(rv3d->tw_axis_min); + zero_v3(rv3d->tw_axis_max); +#endif + rv3d->twdrawflag = 0xFFFF; + /* global, local or normal orientation? + * if we could check 'totsel' now, this should be skipped with no selection. */ + if (ob && !is_gp_edit) { + + switch (v3d->twmode) { + + case V3D_MANIP_GLOBAL: + { + break; /* nothing to do */ + } + case V3D_MANIP_GIMBAL: + { + float mat[3][3]; + if (gimbal_axis(ob, mat)) { + copy_m4_m3(rv3d->twmat, mat); + break; + } + /* if not gimbal, fall through to normal */ + ATTR_FALLTHROUGH; + } + case V3D_MANIP_NORMAL: + { + if (obedit || ob->mode & OB_MODE_POSE) { + float mat[3][3]; + ED_getTransformOrientationMatrix(C, mat, v3d->around); + copy_m4_m3(rv3d->twmat, mat); + break; + } + /* no break we define 'normal' as 'local' in Object mode */ + ATTR_FALLTHROUGH; + } + case V3D_MANIP_LOCAL: + { + if (ob->mode & OB_MODE_POSE) { + /* each bone moves on its own local axis, but to avoid confusion, + * use the active pones axis for display [#33575], this works as expected on a single bone + * and users who select many bones will understand whats going on and what local means + * when they start transforming */ + float mat[3][3]; + ED_getTransformOrientationMatrix(C, mat, v3d->around); + copy_m4_m3(rv3d->twmat, mat); + break; + } + copy_m4_m4(rv3d->twmat, ob->obmat); + normalize_m4(rv3d->twmat); + break; + } + case V3D_MANIP_VIEW: + { + float mat[3][3]; + copy_m3_m4(mat, rv3d->viewinv); + normalize_m3(mat); + copy_m4_m3(rv3d->twmat, mat); + break; + } + case V3D_MANIP_CUSTOM: + { + TransformOrientation *custom_orientation = BKE_workspace_transform_orientation_find( + CTX_wm_workspace(C), v3d->custom_orientation_index); + float mat[3][3]; + + if (applyTransformOrientation(custom_orientation, mat, NULL)) { + copy_m4_m3(rv3d->twmat, mat); + } + break; + } + } + } + /* transform widget centroid/center */ INIT_MINMAX(tbounds->min, tbounds->max); zero_v3(tbounds->center); +#ifdef USE_AXIS_BOUNDS + copy_m3_m4(tbounds->axis, rv3d->twmat); + if (ob && ob->mode & OB_MODE_EDIT) { + float diff_mat[3][3]; + copy_m3_m4(diff_mat, ob->obmat); + normalize_m3(diff_mat); + invert_m3(diff_mat); + mul_m3_m3m3(tbounds->axis, tbounds->axis, diff_mat); + normalize_m3(tbounds->axis); + } + + for (int i = 0; i < 3; i++) { + tbounds->axis_min[i] = +FLT_MAX; + tbounds->axis_max[i] = -FLT_MAX; + } +#endif + if (is_gp_edit) { float diff_mat[4][4]; float fpt[3]; @@ -330,13 +748,11 @@ static int calc_manipulator_stats(const bContext *C, struct TransformBounds *tbo /* selection center */ if (totsel) { - mul_v3_fl(tbounds->center, 1.0f / (float)totsel); + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); /* centroid! */ } } else if (obedit) { ob = obedit; - if ((ob->lay & v3d->lay) == 0) return 0; - if (obedit->type == OB_MESH) { BMEditMesh *em = BKE_editmesh_from_object(obedit); BMEditSelection ese; @@ -442,15 +858,11 @@ static int calc_manipulator_stats(const bContext *C, struct TransformBounds *tbo } else { if (bezt->f1 & SELECT) { - calc_tw_center( - tbounds, - bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0]); + calc_tw_center(tbounds, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0]); totsel++; } if (bezt->f3 & SELECT) { - calc_tw_center( - tbounds, - bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2]); + calc_tw_center(tbounds, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2]); totsel++; } } @@ -512,7 +924,7 @@ static int calc_manipulator_stats(const bContext *C, struct TransformBounds *tbo /* selection center */ if (totsel) { - mul_v3_fl(tbounds->center, 1.0f / (float)totsel); + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid! mul_m4_v3(obedit->obmat, tbounds->center); mul_m4_v3(obedit->obmat, tbounds->min); mul_m4_v3(obedit->obmat, tbounds->max); @@ -523,8 +935,6 @@ static int calc_manipulator_stats(const bContext *C, struct TransformBounds *tbo int mode = TFM_ROTATION; // mislead counting bones... bah. We don't know the manipulator mode, could be mixed bool ok = false; - if ((ob->lay & v3d->lay) == 0) return 0; - if ((v3d->around == V3D_AROUND_ACTIVE) && (pchan = BKE_pose_channel_active(ob))) { /* doesn't check selection or visibility intentionally */ Bone *bone = pchan->bone; @@ -552,7 +962,7 @@ static int calc_manipulator_stats(const bContext *C, struct TransformBounds *tbo } if (ok) { - mul_v3_fl(tbounds->center, 1.0f / (float)totsel); + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid! mul_m4_v3(ob->obmat, tbounds->center); mul_m4_v3(ob->obmat, tbounds->min); mul_m4_v3(ob->obmat, tbounds->max); @@ -562,7 +972,7 @@ static int calc_manipulator_stats(const bContext *C, struct TransformBounds *tbo /* pass */ } else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) { - PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEdit *edit = PE_get_current(scene, sl, ob); PTCacheEditPoint *point; PTCacheEditKey *ek; int k; @@ -582,20 +992,30 @@ static int calc_manipulator_stats(const bContext *C, struct TransformBounds *tbo /* selection center */ if (totsel) - mul_v3_fl(tbounds->center, 1.0f / (float)totsel); + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid! } } else { /* we need the one selected object, if its not active */ - ob = OBACT; - if (ob && !(ob->flag & SELECT)) ob = NULL; + base = BASACT(sl); + ob = OBACT(sl); + if (base && ((base->flag & BASE_SELECTED) == 0)) ob = NULL; - for (base = scene->base.first; base; base = base->next) { - if (TESTBASELIB(v3d, base)) { + for (base = sl->object_bases.first; base; base = base->next) { + if (TESTBASELIB(base)) { if (ob == NULL) ob = base->object; - calc_tw_center(tbounds, base->object->obmat[3]); + if (use_only_center || base->object->bb == NULL) { + calc_tw_center(tbounds, base->object->obmat[3]); + } + else { + for (uint j = 0; j < 8; j++) { + float co[3]; + mul_v3_m4v3(co, base->object->obmat, base->object->bb->vec[j]); + calc_tw_center(tbounds, co); + } + } protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag); totsel++; } @@ -603,1378 +1023,598 @@ static int calc_manipulator_stats(const bContext *C, struct TransformBounds *tbo /* selection center */ if (totsel) { - mul_v3_fl(tbounds->center, 1.0f / (float)totsel); + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid! } } - /* global, local or normal orientation? */ - if (ob && totsel && !is_gp_edit) { - - switch (v3d->twmode) { - - case V3D_MANIP_GLOBAL: - { - break; /* nothing to do */ - } - case V3D_MANIP_GIMBAL: - { - float mat[3][3]; - if (gimbal_axis(ob, mat)) { - copy_m4_m3(rv3d->twmat, mat); - break; - } - /* if not gimbal, fall through to normal */ - ATTR_FALLTHROUGH; - } - case V3D_MANIP_NORMAL: - { - if (obedit || ob->mode & OB_MODE_POSE) { - float mat[3][3]; - ED_getTransformOrientationMatrix(C, mat, v3d->around); - copy_m4_m3(rv3d->twmat, mat); - break; - } - /* no break we define 'normal' as 'local' in Object mode */ - ATTR_FALLTHROUGH; - } - case V3D_MANIP_LOCAL: - { - if (ob->mode & OB_MODE_POSE) { - /* each bone moves on its own local axis, but to avoid confusion, - * use the active pones axis for display [#33575], this works as expected on a single bone - * and users who select many bones will understand whats going on and what local means - * when they start transforming */ - float mat[3][3]; - ED_getTransformOrientationMatrix(C, mat, v3d->around); - copy_m4_m3(rv3d->twmat, mat); - break; - } - copy_m4_m4(rv3d->twmat, ob->obmat); - normalize_m4(rv3d->twmat); - break; - } - case V3D_MANIP_VIEW: - { - float mat[3][3]; - copy_m3_m4(mat, rv3d->viewinv); - normalize_m3(mat); - copy_m4_m3(rv3d->twmat, mat); - break; - } - default: /* V3D_MANIP_CUSTOM */ - { - float mat[3][3]; - if (applyTransformOrientation(C, mat, NULL, v3d->twmode - V3D_MANIP_CUSTOM)) { - copy_m4_m3(rv3d->twmat, mat); - } - break; - } - } - + if (totsel == 0) { + unit_m4(rv3d->twmat); + } + else { +#ifdef USE_AXIS_BOUNDS + copy_v3_v3(rv3d->tw_axis_min, tbounds->axis_min); + copy_v3_v3(rv3d->tw_axis_max, tbounds->axis_max); + copy_m3_m3(rv3d->tw_axis_matrix, tbounds->axis); +#endif } return totsel; } -/* don't draw axis perpendicular to the view */ -static void test_manipulator_axis(const bContext *C) +static void manipulator_get_idot(RegionView3D *rv3d, float r_idot[3]) { - RegionView3D *rv3d = CTX_wm_region_view3d(C); float view_vec[3], axis_vec[3]; - float idot; - int i; - - const int twdrawflag_axis[3] = { - (MAN_TRANS_X | MAN_SCALE_X), - (MAN_TRANS_Y | MAN_SCALE_Y), - (MAN_TRANS_Z | MAN_SCALE_Z)}; - ED_view3d_global_to_vector(rv3d, rv3d->twmat[3], view_vec); - - for (i = 0; i < 3; i++) { + for (int i = 0; i < 3; i++) { normalize_v3_v3(axis_vec, rv3d->twmat[i]); - rv3d->tw_idot[i] = idot = 1.0f - fabsf(dot_v3v3(view_vec, axis_vec)); - if (idot < TW_AXIS_DOT_MIN) { - rv3d->twdrawflag &= ~twdrawflag_axis[i]; - } + r_idot[i] = 1.0f - fabsf(dot_v3v3(view_vec, axis_vec)); } } - -/* ******************** DRAWING STUFFIES *********** */ - -static float screen_aligned(RegionView3D *rv3d, float mat[4][4]) -{ - glTranslate3fv(mat[3]); - - /* sets view screen aligned */ - glRotatef(-360.0f * saacos(rv3d->viewquat[0]) / (float)M_PI, rv3d->viewquat[1], rv3d->viewquat[2], rv3d->viewquat[3]); - - return len_v3(mat[0]); /* draw scale */ -} - - -/* radring = radius of doughnut rings - * radhole = radius hole - * start = starting segment (based on nrings) - * end = end segment - * nsides = amount of points in ring - * nrigns = amount of rings - */ -static void partial_doughnut(float radring, float radhole, int start, int end, int nsides, int nrings) +static void manipulator_prepare_mat( + const bContext *C, View3D *v3d, RegionView3D *rv3d, const struct TransformBounds *tbounds) { - float theta, phi, theta1; - float cos_theta, sin_theta; - float cos_theta1, sin_theta1; - float ring_delta, side_delta; - int i, j, do_caps = true; - - if (start == 0 && end == nrings) do_caps = false; - - ring_delta = 2.0f * (float)M_PI / (float)nrings; - side_delta = 2.0f * (float)M_PI / (float)nsides; - - theta = (float)M_PI + 0.5f * ring_delta; - cos_theta = cosf(theta); - sin_theta = sinf(theta); - - for (i = nrings - 1; i >= 0; i--) { - theta1 = theta + ring_delta; - cos_theta1 = cosf(theta1); - sin_theta1 = sinf(theta1); - - if (do_caps && i == start) { // cap - glBegin(GL_POLYGON); - phi = 0.0; - for (j = nsides; j >= 0; j--) { - float cos_phi, sin_phi, dist; - - phi += side_delta; - cos_phi = cosf(phi); - sin_phi = sinf(phi); - dist = radhole + radring * cos_phi; - - glVertex3f(cos_theta1 * dist, -sin_theta1 * dist, radring * sin_phi); - } - glEnd(); - } - if (i >= start && i <= end) { - glBegin(GL_QUAD_STRIP); - phi = 0.0; - for (j = nsides; j >= 0; j--) { - float cos_phi, sin_phi, dist; - - phi += side_delta; - cos_phi = cosf(phi); - sin_phi = sinf(phi); - dist = radhole + radring * cos_phi; - - glVertex3f(cos_theta1 * dist, -sin_theta1 * dist, radring * sin_phi); - glVertex3f(cos_theta * dist, -sin_theta * dist, radring * sin_phi); + Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); + + switch (v3d->around) { + case V3D_AROUND_CENTER_BOUNDS: + case V3D_AROUND_ACTIVE: + { + bGPdata *gpd = CTX_data_gpencil_data(C); + Object *ob = OBACT(sl); + + if (((v3d->around == V3D_AROUND_ACTIVE) && (scene->obedit == NULL)) && + ((gpd == NULL) || !(gpd->flag & GP_DATA_STROKE_EDITMODE)) && + (!(ob->mode & OB_MODE_POSE))) + { + copy_v3_v3(rv3d->twmat[3], ob->obmat[3]); } - glEnd(); - } - - if (do_caps && i == end) { // cap - glBegin(GL_POLYGON); - phi = 0.0; - for (j = nsides; j >= 0; j--) { - float cos_phi, sin_phi, dist; - - phi -= side_delta; - cos_phi = cosf(phi); - sin_phi = sinf(phi); - dist = radhole + radring * cos_phi; - - glVertex3f(cos_theta * dist, -sin_theta * dist, radring * sin_phi); + else { + mid_v3_v3v3(rv3d->twmat[3], tbounds->min, tbounds->max); } - glEnd(); + break; } - - - theta = theta1; - cos_theta = cos_theta1; - sin_theta = sin_theta1; - } -} - -static char axisBlendAngle(float idot) -{ - if (idot > TW_AXIS_DOT_MAX) { - return 255; - } - else if (idot < TW_AXIS_DOT_MIN) { - return 0; - } - else { - return (char)(255.0f * (idot - TW_AXIS_DOT_MIN) / (TW_AXIS_DOT_MAX - TW_AXIS_DOT_MIN)); + case V3D_AROUND_LOCAL_ORIGINS: + case V3D_AROUND_CENTER_MEAN: + copy_v3_v3(rv3d->twmat[3], tbounds->center); + break; + case V3D_AROUND_CURSOR: + copy_v3_v3(rv3d->twmat[3], ED_view3d_cursor3d_get(scene, v3d)); + break; } } -/* three colors can be set: - * gray for ghosting - * moving: in transform theme color - * else the red/green/blue +/** + * Sets up \a r_start and \a r_len to define arrow line range. + * Needed to adjust line drawing for combined manipulator axis types. */ -static void manipulator_setcolor(View3D *v3d, char axis, int colcode, unsigned char alpha) -{ - unsigned char col[4] = {0}; - col[3] = alpha; - - if (colcode == MAN_GHOST) { - col[3] = 70; - } - else if (colcode == MAN_MOVECOL) { - UI_GetThemeColor3ubv(TH_TRANSFORM, col); - } - else { - switch (axis) { - case 'C': - UI_GetThemeColor3ubv(TH_TRANSFORM, col); - if (v3d->twmode == V3D_MANIP_LOCAL) { - col[0] = col[0] > 200 ? 255 : col[0] + 55; - col[1] = col[1] > 200 ? 255 : col[1] + 55; - col[2] = col[2] > 200 ? 255 : col[2] + 55; - } - else if (v3d->twmode == V3D_MANIP_NORMAL) { - col[0] = col[0] < 55 ? 0 : col[0] - 55; - col[1] = col[1] < 55 ? 0 : col[1] - 55; - col[2] = col[2] < 55 ? 0 : col[2] - 55; - } - break; - case 'X': - UI_GetThemeColor3ubv(TH_AXIS_X, col); - break; - case 'Y': - UI_GetThemeColor3ubv(TH_AXIS_Y, col); - break; - case 'Z': - UI_GetThemeColor3ubv(TH_AXIS_Z, col); - break; - default: - BLI_assert(0); - break; - } - } - - glColor4ubv(col); -} - -static void manipulator_axis_order(RegionView3D *rv3d, int r_axis_order[3]) +static void manipulator_line_range(const View3D *v3d, const short axis_type, float *r_start, float *r_len) { - float axis_values[3]; - float vec[3]; - - ED_view3d_global_to_vector(rv3d, rv3d->twmat[3], vec); + const float ofs = 0.2f; - axis_values[0] = -dot_v3v3(rv3d->twmat[0], vec); - axis_values[1] = -dot_v3v3(rv3d->twmat[1], vec); - axis_values[2] = -dot_v3v3(rv3d->twmat[2], vec); + *r_start = 0.2f; + *r_len = 1.0f; - axis_sort_v3(axis_values, r_axis_order); -} - -/* viewmatrix should have been set OK, also no shademode! */ -static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int colcode, - int flagx, int flagy, int flagz, int axis, - const bool is_picksel) -{ - switch (axis) { - case 0: - /* axes */ - if (flagx) { - if (is_picksel) { - if (flagx & MAN_SCALE_X) GPU_select_load_id(MAN_SCALE_X); - else if (flagx & MAN_TRANS_X) GPU_select_load_id(MAN_TRANS_X); - } - else { - manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0])); - } - glBegin(GL_LINES); - glVertex3f(0.2f, 0.0f, 0.0f); - glVertex3f(1.0f, 0.0f, 0.0f); - glEnd(); + switch (axis_type) { + case MAN_AXES_TRANSLATE: + if (v3d->twtype & V3D_MANIP_SCALE) { + *r_start = *r_len - ofs + 0.075f; } - break; - case 1: - if (flagy) { - if (is_picksel) { - if (flagy & MAN_SCALE_Y) GPU_select_load_id(MAN_SCALE_Y); - else if (flagy & MAN_TRANS_Y) GPU_select_load_id(MAN_TRANS_Y); - } - else { - manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1])); - } - glBegin(GL_LINES); - glVertex3f(0.0f, 0.2f, 0.0f); - glVertex3f(0.0f, 1.0f, 0.0f); - glEnd(); + if (v3d->twtype & V3D_MANIP_ROTATE) { + *r_len += ofs; } break; - case 2: - if (flagz) { - if (is_picksel) { - if (flagz & MAN_SCALE_Z) GPU_select_load_id(MAN_SCALE_Z); - else if (flagz & MAN_TRANS_Z) GPU_select_load_id(MAN_TRANS_Z); - } - else { - manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2])); - } - glBegin(GL_LINES); - glVertex3f(0.0f, 0.0f, 0.2f); - glVertex3f(0.0f, 0.0f, 1.0f); - glEnd(); + case MAN_AXES_SCALE: + if (v3d->twtype & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE)) { + *r_len -= ofs + 0.025f; } break; } -} -static void draw_manipulator_axes(View3D *v3d, RegionView3D *rv3d, int colcode, - int flagx, int flagy, int flagz, - const int axis_order[3], const bool is_picksel) -{ - int i; - for (i = 0; i < 3; i++) { - draw_manipulator_axes_single(v3d, rv3d, colcode, flagx, flagy, flagz, axis_order[i], is_picksel); - } -} - -static void preOrthoFront(const bool ortho, float twmat[4][4], int axis) -{ - if (ortho == false) { - float omat[4][4]; - copy_m4_m4(omat, twmat); - orthogonalize_m4(omat, axis); - glPushMatrix(); - glMultMatrixf(omat); - glFrontFace(is_negative_m4(omat) ? GL_CW : GL_CCW); - } -} - -static void postOrtho(const bool ortho) -{ - if (ortho == false) { - glPopMatrix(); - } -} -BLI_INLINE bool manipulator_rotate_is_visible(const int drawflags) -{ - return (drawflags & (MAN_ROT_X | MAN_ROT_Y | MAN_ROT_Z)); + *r_len -= *r_start; } -static void draw_manipulator_rotate( - View3D *v3d, RegionView3D *rv3d, const int drawflags, const int combo, - const bool is_moving, const bool is_picksel) -{ - double plane[4]; - float matt[4][4]; - float size, unitmat[4][4]; - float cywid = 0.33f * 0.01f * (float)U.tw_handlesize; - float cusize = cywid * 0.65f; - int arcs = (G.debug_value != 2); - const int colcode = (is_moving) ? MAN_MOVECOL : MAN_RGB; - bool ortho; - - /* skip drawing if all axes are locked */ - if (manipulator_rotate_is_visible(drawflags) == false) return; - - /* Init stuff */ - glDisable(GL_DEPTH_TEST); - unit_m4(unitmat); - - /* prepare for screen aligned draw */ - size = len_v3(rv3d->twmat[0]); - glPushMatrix(); - glTranslate3fv(rv3d->twmat[3]); - - if (arcs) { - /* clipplane makes nice handles, calc here because of multmatrix but with translate! */ - copy_v3db_v3fl(plane, rv3d->viewinv[2]); - plane[3] = -0.02f * size; // clip just a bit more - glClipPlane(GL_CLIP_PLANE0, plane); - } - /* sets view screen aligned */ - glRotatef(-360.0f * saacos(rv3d->viewquat[0]) / (float)M_PI, rv3d->viewquat[1], rv3d->viewquat[2], rv3d->viewquat[3]); - - /* Screen aligned help circle */ - if (arcs) { - if (is_picksel == false) { - UI_ThemeColorShade(TH_BACK, -30); - drawcircball(GL_LINE_LOOP, unitmat[3], size, unitmat); - } - } - - /* Screen aligned trackball rot circle */ - if (drawflags & MAN_ROT_T) { - if (is_picksel) GPU_select_load_id(MAN_ROT_T); - else UI_ThemeColor(TH_TRANSFORM); +/** \} */ - drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat); - } - /* Screen aligned view rot circle */ - if (drawflags & MAN_ROT_V) { - if (is_picksel) GPU_select_load_id(MAN_ROT_V); - else UI_ThemeColor(TH_TRANSFORM); - drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f * size, unitmat); - - if (is_moving) { - float vec[3]; - vec[0] = 0; // XXX (float)(t->mouse.imval[0] - t->center2d[0]); - vec[1] = 0; // XXX (float)(t->mouse.imval[1] - t->center2d[1]); - vec[2] = 0.0f; - normalize_v3_length(vec, 1.2f * size); - glBegin(GL_LINES); - glVertex3f(0.0f, 0.0f, 0.0f); - glVertex3fv(vec); - glEnd(); - } - } - glPopMatrix(); - - - ortho = is_orthogonal_m4(rv3d->twmat); - - /* apply the transform delta */ - if (is_moving) { - copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3] - // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat); - if (ortho) { - glMultMatrixf(matt); - glFrontFace(is_negative_m4(matt) ? GL_CW : GL_CCW); - } - } - else { - if (ortho) { - glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW : GL_CCW); - glMultMatrixf(rv3d->twmat); - } - } +/* -------------------------------------------------------------------- */ +/** \name Transform Manipulator + * \{ */ - /* axes */ - if (arcs == 0) { - if (!is_picksel) { - if ((combo & V3D_MANIP_SCALE) == 0) { - /* axis */ - if ((drawflags & MAN_ROT_X) || (is_moving && (drawflags & MAN_ROT_Z))) { - preOrthoFront(ortho, rv3d->twmat, 2); - manipulator_setcolor(v3d, 'X', colcode, 255); - glBegin(GL_LINES); - glVertex3f(0.2f, 0.0f, 0.0f); - glVertex3f(1.0f, 0.0f, 0.0f); - glEnd(); - postOrtho(ortho); - } - if ((drawflags & MAN_ROT_Y) || (is_moving && (drawflags & MAN_ROT_X))) { - preOrthoFront(ortho, rv3d->twmat, 0); - manipulator_setcolor(v3d, 'Y', colcode, 255); - glBegin(GL_LINES); - glVertex3f(0.0f, 0.2f, 0.0f); - glVertex3f(0.0f, 1.0f, 0.0f); - glEnd(); - postOrtho(ortho); - } - if ((drawflags & MAN_ROT_Z) || (is_moving && (drawflags & MAN_ROT_Y))) { - preOrthoFront(ortho, rv3d->twmat, 1); - manipulator_setcolor(v3d, 'Z', colcode, 255); - glBegin(GL_LINES); - glVertex3f(0.0f, 0.0f, 0.2f); - glVertex3f(0.0f, 0.0f, 1.0f); - glEnd(); - postOrtho(ortho); - } - } - } - } - - if (arcs == 0 && is_moving) { - - /* Z circle */ - if (drawflags & MAN_ROT_Z) { - preOrthoFront(ortho, matt, 2); - if (is_picksel) GPU_select_load_id(MAN_ROT_Z); - else manipulator_setcolor(v3d, 'Z', colcode, 255); - drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat); - postOrtho(ortho); - } - /* X circle */ - if (drawflags & MAN_ROT_X) { - preOrthoFront(ortho, matt, 0); - if (is_picksel) GPU_select_load_id(MAN_ROT_X); - else manipulator_setcolor(v3d, 'X', colcode, 255); - glRotatef(90.0, 0.0, 1.0, 0.0); - drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat); - glRotatef(-90.0, 0.0, 1.0, 0.0); - postOrtho(ortho); - } - /* Y circle */ - if (drawflags & MAN_ROT_Y) { - preOrthoFront(ortho, matt, 1); - if (is_picksel) GPU_select_load_id(MAN_ROT_Y); - else manipulator_setcolor(v3d, 'Y', colcode, 255); - glRotatef(-90.0, 1.0, 0.0, 0.0); - drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat); - glRotatef(90.0, 1.0, 0.0, 0.0); - postOrtho(ortho); - } - } - // donut arcs - if (arcs) { - glEnable(GL_CLIP_PLANE0); - - /* Z circle */ - if (drawflags & MAN_ROT_Z) { - preOrthoFront(ortho, rv3d->twmat, 2); - if (is_picksel) GPU_select_load_id(MAN_ROT_Z); - else manipulator_setcolor(v3d, 'Z', colcode, 255); - partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48); - postOrtho(ortho); - } - /* X circle */ - if (drawflags & MAN_ROT_X) { - preOrthoFront(ortho, rv3d->twmat, 0); - if (is_picksel) GPU_select_load_id(MAN_ROT_X); - else manipulator_setcolor(v3d, 'X', colcode, 255); - glRotatef(90.0, 0.0, 1.0, 0.0); - partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48); - glRotatef(-90.0, 0.0, 1.0, 0.0); - postOrtho(ortho); - } - /* Y circle */ - if (drawflags & MAN_ROT_Y) { - preOrthoFront(ortho, rv3d->twmat, 1); - if (is_picksel) GPU_select_load_id(MAN_ROT_Y); - else manipulator_setcolor(v3d, 'Y', colcode, 255); - glRotatef(-90.0, 1.0, 0.0, 0.0); - partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48); - glRotatef(90.0, 1.0, 0.0, 0.0); - postOrtho(ortho); - } - - glDisable(GL_CLIP_PLANE0); - } +static ManipulatorGroup *manipulatorgroup_init(wmManipulatorGroup *mgroup) +{ + ManipulatorGroup *man; - if (arcs == 0) { + man = MEM_callocN(sizeof(ManipulatorGroup), "manipulator_data"); - /* Z handle on X axis */ - if (drawflags & MAN_ROT_Z) { - preOrthoFront(ortho, rv3d->twmat, 2); - glPushMatrix(); - if (is_picksel) GPU_select_load_id(MAN_ROT_Z); - else manipulator_setcolor(v3d, 'Z', colcode, 255); + const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_3d", true); + const wmManipulatorType *wt_dial = WM_manipulatortype_find("MANIPULATOR_WT_dial_3d", true); + const wmManipulatorType *wt_prim = WM_manipulatortype_find("MANIPULATOR_WT_primitive_3d", true); - partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64); +#define MANIPULATOR_NEW_ARROW(v, draw_style) { \ + man->manipulators[v] = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); \ + RNA_enum_set(man->manipulators[v]->ptr, "draw_style", draw_style); \ +} ((void)0) +#define MANIPULATOR_NEW_DIAL(v, draw_options) { \ + man->manipulators[v] = WM_manipulator_new_ptr(wt_dial, mgroup, NULL); \ + RNA_enum_set(man->manipulators[v]->ptr, "draw_options", draw_options); \ +} ((void)0) +#define MANIPULATOR_NEW_PRIM(v, draw_style) { \ + man->manipulators[v] = WM_manipulator_new_ptr(wt_prim, mgroup, NULL); \ + RNA_enum_set(man->manipulators[v]->ptr, "draw_style", draw_style); \ +} ((void)0) - glPopMatrix(); - postOrtho(ortho); - } + /* add/init widgets - order matters! */ + MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_T, ED_MANIPULATOR_DIAL_DRAW_FLAG_FILL); - /* Y handle on X axis */ - if (drawflags & MAN_ROT_Y) { - preOrthoFront(ortho, rv3d->twmat, 1); - glPushMatrix(); - if (is_picksel) GPU_select_load_id(MAN_ROT_Y); - else manipulator_setcolor(v3d, 'Y', colcode, 255); + MANIPULATOR_NEW_DIAL(MAN_AXIS_SCALE_C, ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP); - glRotatef(90.0, 1.0, 0.0, 0.0); - glRotatef(90.0, 0.0, 0.0, 1.0); - partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64); + MANIPULATOR_NEW_ARROW(MAN_AXIS_SCALE_X, ED_MANIPULATOR_ARROW_STYLE_BOX); + MANIPULATOR_NEW_ARROW(MAN_AXIS_SCALE_Y, ED_MANIPULATOR_ARROW_STYLE_BOX); + MANIPULATOR_NEW_ARROW(MAN_AXIS_SCALE_Z, ED_MANIPULATOR_ARROW_STYLE_BOX); - glPopMatrix(); - postOrtho(ortho); - } + MANIPULATOR_NEW_PRIM(MAN_AXIS_SCALE_XY, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); + MANIPULATOR_NEW_PRIM(MAN_AXIS_SCALE_YZ, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); + MANIPULATOR_NEW_PRIM(MAN_AXIS_SCALE_ZX, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); - /* X handle on Z axis */ - if (drawflags & MAN_ROT_X) { - preOrthoFront(ortho, rv3d->twmat, 0); - glPushMatrix(); - if (is_picksel) GPU_select_load_id(MAN_ROT_X); - else manipulator_setcolor(v3d, 'X', colcode, 255); + MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_X, ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP); + MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_Y, ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP); + MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_Z, ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP); - glRotatef(-90.0, 0.0, 1.0, 0.0); - glRotatef(90.0, 0.0, 0.0, 1.0); - partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64); + /* init screen aligned widget last here, looks better, behaves better */ + MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_C, ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP); - glPopMatrix(); - postOrtho(ortho); - } + MANIPULATOR_NEW_DIAL(MAN_AXIS_TRANS_C, ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP); - } + MANIPULATOR_NEW_ARROW(MAN_AXIS_TRANS_X, ED_MANIPULATOR_ARROW_STYLE_NORMAL); + MANIPULATOR_NEW_ARROW(MAN_AXIS_TRANS_Y, ED_MANIPULATOR_ARROW_STYLE_NORMAL); + MANIPULATOR_NEW_ARROW(MAN_AXIS_TRANS_Z, ED_MANIPULATOR_ARROW_STYLE_NORMAL); - /* restore */ - glLoadMatrixf(rv3d->viewmat); - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); + MANIPULATOR_NEW_PRIM(MAN_AXIS_TRANS_XY, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); + MANIPULATOR_NEW_PRIM(MAN_AXIS_TRANS_YZ, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); + MANIPULATOR_NEW_PRIM(MAN_AXIS_TRANS_ZX, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); + return man; } -static void drawsolidcube(float size) -{ - const float cube[8][3] = { - {-1.0, -1.0, -1.0}, - {-1.0, -1.0, 1.0}, - {-1.0, 1.0, 1.0}, - {-1.0, 1.0, -1.0}, - { 1.0, -1.0, -1.0}, - { 1.0, -1.0, 1.0}, - { 1.0, 1.0, 1.0}, - { 1.0, 1.0, -1.0}, - }; - float n[3] = {0.0f}; - - glPushMatrix(); - glScalef(size, size, size); - - glBegin(GL_QUADS); - n[0] = -1.0; - glNormal3fv(n); - glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]); - n[0] = 0; - glEnd(); - - glBegin(GL_QUADS); - n[1] = -1.0; - glNormal3fv(n); - glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[1]); - n[1] = 0; - glEnd(); - - glBegin(GL_QUADS); - n[0] = 1.0; - glNormal3fv(n); - glVertex3fv(cube[4]); glVertex3fv(cube[7]); glVertex3fv(cube[6]); glVertex3fv(cube[5]); - n[0] = 0; - glEnd(); - - glBegin(GL_QUADS); - n[1] = 1.0; - glNormal3fv(n); - glVertex3fv(cube[7]); glVertex3fv(cube[3]); glVertex3fv(cube[2]); glVertex3fv(cube[6]); - n[1] = 0; - glEnd(); - - glBegin(GL_QUADS); - n[2] = 1.0; - glNormal3fv(n); - glVertex3fv(cube[1]); glVertex3fv(cube[5]); glVertex3fv(cube[6]); glVertex3fv(cube[2]); - n[2] = 0; - glEnd(); - - glBegin(GL_QUADS); - n[2] = -1.0; - glNormal3fv(n); - glVertex3fv(cube[7]); glVertex3fv(cube[4]); glVertex3fv(cube[0]); glVertex3fv(cube[3]); - glEnd(); - - glPopMatrix(); -} - - -static void draw_manipulator_scale( - View3D *v3d, RegionView3D *rv3d, const int drawflags, const int combo, const int colcode, - const bool is_moving, const bool is_picksel) +/** + * Custom handler for manipulator widgets + */ +static int manipulator_modal( + bContext *C, wmManipulator *widget, const wmEvent *UNUSED(event), + eWM_ManipulatorTweak UNUSED(tweak_flag)) { - float cywid = 0.25f * 0.01f * (float)U.tw_handlesize; - float cusize = cywid * 0.75f, dz; - int axis_order[3] = {2, 0, 1}; - int i; - - /* when called while moving in mixed mode, do not draw when... */ - if ((drawflags & MAN_SCALE_C) == 0) return; - - manipulator_axis_order(rv3d, axis_order); - - glDisable(GL_DEPTH_TEST); - - /* not in combo mode */ - if ((combo & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE)) == 0) { - float size, unitmat[4][4]; - int shift = 0; // XXX - - /* center circle, do not add to selection when shift is pressed (planar constraint) */ - if (is_picksel && shift == 0) GPU_select_load_id(MAN_SCALE_C); - else manipulator_setcolor(v3d, 'C', colcode, 255); + const ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + View3D *v3d = sa->spacedata.first; + RegionView3D *rv3d = ar->regiondata; + struct TransformBounds tbounds; - glPushMatrix(); - size = screen_aligned(rv3d, rv3d->twmat); - unit_m4(unitmat); - drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat); - glPopMatrix(); - dz = 1.0; - } - else { - dz = 1.0f - 4.0f * cusize; + if (calc_manipulator_stats(C, true, &tbounds)) { + manipulator_prepare_mat(C, v3d, rv3d, &tbounds); + WM_manipulator_set_matrix_location(widget, rv3d->twmat[3]); } - if (is_moving) { - float matt[4][4]; + ED_region_tag_redraw(ar); - copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3] - // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat); - glMultMatrixf(matt); - glFrontFace(is_negative_m4(matt) ? GL_CW : GL_CCW); - } - else { - glMultMatrixf(rv3d->twmat); - glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW : GL_CCW); - } + return OPERATOR_RUNNING_MODAL; +} - /* axis */ +static void WIDGETGROUP_manipulator_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) +{ + ManipulatorGroup *man = manipulatorgroup_init(mgroup); + struct { + wmOperatorType *translate, *rotate, *trackball, *resize; + } ot_store = {NULL}; - /* in combo mode, this is always drawn as first type */ - draw_manipulator_axes(v3d, rv3d, colcode, - drawflags & MAN_SCALE_X, drawflags & MAN_SCALE_Y, drawflags & MAN_SCALE_Z, - axis_order, is_picksel); + mgroup->customdata = man; + /* *** set properties for axes *** */ - for (i = 0; i < 3; i++) { - switch (axis_order[i]) { - case 0: /* X cube */ - if (drawflags & MAN_SCALE_X) { - glTranslatef(dz, 0.0, 0.0); - if (is_picksel) GPU_select_load_id(MAN_SCALE_X); - else manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0])); - drawsolidcube(cusize); - glTranslatef(-dz, 0.0, 0.0); - } + MAN_ITER_AXES_BEGIN(axis, axis_idx) + { + const short axis_type = manipulator_get_axis_type(axis_idx); + int constraint_axis[3] = {1, 0, 0}; + PointerRNA *ptr; + + manipulator_get_axis_constraint(axis_idx, constraint_axis); + + /* custom handler! */ + WM_manipulator_set_fn_custom_modal(axis, manipulator_modal); + + switch (axis_idx) { + case MAN_AXIS_TRANS_X: + case MAN_AXIS_TRANS_Y: + case MAN_AXIS_TRANS_Z: + case MAN_AXIS_SCALE_X: + case MAN_AXIS_SCALE_Y: + case MAN_AXIS_SCALE_Z: + WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH); break; - case 1: /* Y cube */ - if (drawflags & MAN_SCALE_Y) { - glTranslatef(0.0, dz, 0.0); - if (is_picksel) GPU_select_load_id(MAN_SCALE_Y); - else manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1])); - drawsolidcube(cusize); - glTranslatef(0.0, -dz, 0.0); - } + case MAN_AXIS_ROT_X: + case MAN_AXIS_ROT_Y: + case MAN_AXIS_ROT_Z: + /* increased line width for better display */ + WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH + 1.0f); + WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_VALUE, true); break; - case 2: /* Z cube */ - if (drawflags & MAN_SCALE_Z) { - glTranslatef(0.0, 0.0, dz); - if (is_picksel) GPU_select_load_id(MAN_SCALE_Z); - else manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2])); - drawsolidcube(cusize); - glTranslatef(0.0, 0.0, -dz); - } + case MAN_AXIS_TRANS_XY: + case MAN_AXIS_TRANS_YZ: + case MAN_AXIS_TRANS_ZX: + case MAN_AXIS_SCALE_XY: + case MAN_AXIS_SCALE_YZ: + case MAN_AXIS_SCALE_ZX: + { + const float ofs_ax = 11.0f; + const float ofs[3] = {ofs_ax, ofs_ax, 0.0f}; + WM_manipulator_set_scale(axis, 0.07f); + WM_manipulator_set_matrix_offset_location(axis, ofs); + WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_OFFSET_SCALE, true); break; - } - } - -#if 0 // XXX - /* if shiftkey, center point as last, for selectbuffer order */ - if (is_picksel) { - int shift = 0; // XXX - - if (shift) { - glTranslatef(0.0, -dz, 0.0); - GPU_select_load_id(MAN_SCALE_C); - /* TODO: set glPointSize before drawing center point */ - glBegin(GL_POINTS); - glVertex3f(0.0, 0.0, 0.0); - glEnd(); - } - } -#endif - - /* restore */ - glLoadMatrixf(rv3d->viewmat); - - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); - glFrontFace(GL_CCW); -} - - -static void draw_cone(GLUquadricObj *qobj, float len, float width) -{ - glTranslatef(0.0, 0.0, -0.5f * len); - gluCylinder(qobj, width, 0.0, len, 8, 1); - gluQuadricOrientation(qobj, GLU_INSIDE); - gluDisk(qobj, 0.0, width, 8, 1); - gluQuadricOrientation(qobj, GLU_OUTSIDE); - glTranslatef(0.0, 0.0, 0.5f * len); -} - -static void draw_cylinder(GLUquadricObj *qobj, float len, float width) -{ - - width *= 0.8f; // just for beauty - - glTranslatef(0.0, 0.0, -0.5f * len); - gluCylinder(qobj, width, width, len, 8, 1); - gluQuadricOrientation(qobj, GLU_INSIDE); - gluDisk(qobj, 0.0, width, 8, 1); - gluQuadricOrientation(qobj, GLU_OUTSIDE); - glTranslatef(0.0, 0.0, len); - gluDisk(qobj, 0.0, width, 8, 1); - glTranslatef(0.0, 0.0, -0.5f * len); -} - - -static void draw_manipulator_translate( - View3D *v3d, RegionView3D *rv3d, int drawflags, int combo, int colcode, - const bool UNUSED(is_moving), const bool is_picksel) -{ - GLUquadricObj *qobj; - float cylen = 0.01f * (float)U.tw_handlesize; - float cywid = 0.25f * cylen, dz, size; - float unitmat[4][4]; - int shift = 0; // XXX - int axis_order[3] = {0, 1, 2}; - int i; - - /* when called while moving in mixed mode, do not draw when... */ - if ((drawflags & MAN_TRANS_C) == 0) return; - - manipulator_axis_order(rv3d, axis_order); - - // XXX if (moving) glTranslate3fv(t->vec); - glDisable(GL_DEPTH_TEST); - - /* center circle, do not add to selection when shift is pressed (planar constraint) */ - if (is_picksel && shift == 0) GPU_select_load_id(MAN_TRANS_C); - else manipulator_setcolor(v3d, 'C', colcode, 255); - - glPushMatrix(); - size = screen_aligned(rv3d, rv3d->twmat); - unit_m4(unitmat); - drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat); - glPopMatrix(); - - /* and now apply matrix, we move to local matrix drawing */ - glMultMatrixf(rv3d->twmat); - - /* axis */ - GPU_select_load_id(-1); - - // translate drawn as last, only axis when no combo with scale, or for ghosting - if ((combo & V3D_MANIP_SCALE) == 0 || colcode == MAN_GHOST) { - draw_manipulator_axes(v3d, rv3d, colcode, - drawflags & MAN_TRANS_X, drawflags & MAN_TRANS_Y, drawflags & MAN_TRANS_Z, - axis_order, is_picksel); - } - - - /* offset in combo mode, for rotate a bit more */ - if (combo & (V3D_MANIP_ROTATE)) dz = 1.0f + 2.0f * cylen; - else if (combo & (V3D_MANIP_SCALE)) dz = 1.0f + 0.5f * cylen; - else dz = 1.0f; - - qobj = gluNewQuadric(); - gluQuadricDrawStyle(qobj, GLU_FILL); - - for (i = 0; i < 3; i++) { - switch (axis_order[i]) { - case 0: /* Z Cone */ - if (drawflags & MAN_TRANS_Z) { - glTranslatef(0.0, 0.0, dz); - if (is_picksel) GPU_select_load_id(MAN_TRANS_Z); - else manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2])); - draw_cone(qobj, cylen, cywid); - glTranslatef(0.0, 0.0, -dz); + } + case MAN_AXIS_TRANS_C: + case MAN_AXIS_ROT_C: + case MAN_AXIS_SCALE_C: + case MAN_AXIS_ROT_T: + WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH); + if (axis_idx == MAN_AXIS_ROT_T) { + WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_HOVER, true); } - break; - case 1: /* X Cone */ - if (drawflags & MAN_TRANS_X) { - glTranslatef(dz, 0.0, 0.0); - if (is_picksel) GPU_select_load_id(MAN_TRANS_X); - else manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0])); - glRotatef(90.0, 0.0, 1.0, 0.0); - draw_cone(qobj, cylen, cywid); - glRotatef(-90.0, 0.0, 1.0, 0.0); - glTranslatef(-dz, 0.0, 0.0); + else if (axis_idx == MAN_AXIS_ROT_C) { + WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_VALUE, true); } - break; - case 2: /* Y Cone */ - if (drawflags & MAN_TRANS_Y) { - glTranslatef(0.0, dz, 0.0); - if (is_picksel) GPU_select_load_id(MAN_TRANS_Y); - else manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1])); - glRotatef(-90.0, 1.0, 0.0, 0.0); - draw_cone(qobj, cylen, cywid); - glRotatef(90.0, 1.0, 0.0, 0.0); - glTranslatef(0.0, -dz, 0.0); + else { + WM_manipulator_set_scale(axis, 0.2f); } break; } - } - - gluDeleteQuadric(qobj); - glLoadMatrixf(rv3d->viewmat); - - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); - -} - -static void draw_manipulator_rotate_cyl( - View3D *v3d, RegionView3D *rv3d, int drawflags, const int combo, const int colcode, - const bool is_moving, const bool is_picksel) -{ - GLUquadricObj *qobj; - float size; - float cylen = 0.01f * (float)U.tw_handlesize; - float cywid = 0.25f * cylen; - int axis_order[3] = {2, 0, 1}; - int i; - - /* skip drawing if all axes are locked */ - if (manipulator_rotate_is_visible(drawflags) == false) return; - - manipulator_axis_order(rv3d, axis_order); - - /* prepare for screen aligned draw */ - glPushMatrix(); - size = screen_aligned(rv3d, rv3d->twmat); - - glDisable(GL_DEPTH_TEST); - - qobj = gluNewQuadric(); - - /* Screen aligned view rot circle */ - if (drawflags & MAN_ROT_V) { - float unitmat[4][4]; - - unit_m4(unitmat); - - if (is_picksel) GPU_select_load_id(MAN_ROT_V); - UI_ThemeColor(TH_TRANSFORM); - drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f * size, unitmat); - - if (is_moving) { - float vec[3]; - vec[0] = 0; // XXX (float)(t->mouse.imval[0] - t->center2d[0]); - vec[1] = 0; // XXX (float)(t->mouse.imval[1] - t->center2d[1]); - vec[2] = 0.0f; - normalize_v3_length(vec, 1.2f * size); - glBegin(GL_LINES); - glVertex3f(0.0, 0.0, 0.0); - glVertex3fv(vec); - glEnd(); - } - } - glPopMatrix(); - - /* apply the transform delta */ - if (is_moving) { - float matt[4][4]; - copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3] - // XXX if (t->flag & T_USES_MANIPULATOR) { - // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat); - // XXX } - glMultMatrixf(matt); - } - else { - glMultMatrixf(rv3d->twmat); - } - - glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW : GL_CCW); - - /* axis */ - if (is_picksel == false) { - - // only draw axis when combo didn't draw scale axes - if ((combo & V3D_MANIP_SCALE) == 0) { - draw_manipulator_axes(v3d, rv3d, colcode, - drawflags & MAN_ROT_X, drawflags & MAN_ROT_Y, drawflags & MAN_ROT_Z, - axis_order, is_picksel); - } - - /* only has to be set when not in picking */ - gluQuadricDrawStyle(qobj, GLU_FILL); - } - for (i = 0; i < 3; i++) { - switch (axis_order[i]) { - case 0: /* X cylinder */ - if (drawflags & MAN_ROT_X) { - glTranslatef(1.0, 0.0, 0.0); - if (is_picksel) GPU_select_load_id(MAN_ROT_X); - glRotatef(90.0, 0.0, 1.0, 0.0); - manipulator_setcolor(v3d, 'X', colcode, 255); - draw_cylinder(qobj, cylen, cywid); - glRotatef(-90.0, 0.0, 1.0, 0.0); - glTranslatef(-1.0, 0.0, 0.0); + switch (axis_type) { + case MAN_AXES_TRANSLATE: + if (ot_store.translate == NULL) { + ot_store.translate = WM_operatortype_find("TRANSFORM_OT_translate", true); } + ptr = WM_manipulator_operator_set(axis, 0, ot_store.translate, NULL); break; - case 1: /* Y cylinder */ - if (drawflags & MAN_ROT_Y) { - glTranslatef(0.0, 1.0, 0.0); - if (is_picksel) GPU_select_load_id(MAN_ROT_Y); - glRotatef(-90.0, 1.0, 0.0, 0.0); - manipulator_setcolor(v3d, 'Y', colcode, 255); - draw_cylinder(qobj, cylen, cywid); - glRotatef(90.0, 1.0, 0.0, 0.0); - glTranslatef(0.0, -1.0, 0.0); + case MAN_AXES_ROTATE: + { + wmOperatorType *ot_rotate; + if (axis_idx == MAN_AXIS_ROT_T) { + if (ot_store.trackball == NULL) { + ot_store.trackball = WM_operatortype_find("TRANSFORM_OT_trackball", true); + } + ot_rotate = ot_store.trackball; + } + else { + if (ot_store.rotate == NULL) { + ot_store.rotate = WM_operatortype_find("TRANSFORM_OT_rotate", true); + } + ot_rotate = ot_store.rotate; } + ptr = WM_manipulator_operator_set(axis, 0, ot_rotate, NULL); break; - case 2: /* Z cylinder */ - if (drawflags & MAN_ROT_Z) { - glTranslatef(0.0, 0.0, 1.0); - if (is_picksel) GPU_select_load_id(MAN_ROT_Z); - manipulator_setcolor(v3d, 'Z', colcode, 255); - draw_cylinder(qobj, cylen, cywid); - glTranslatef(0.0, 0.0, -1.0); + } + case MAN_AXES_SCALE: + { + if (ot_store.resize == NULL) { + ot_store.resize = WM_operatortype_find("TRANSFORM_OT_resize", true); } + ptr = WM_manipulator_operator_set(axis, 0, ot_store.resize, NULL); break; + } } - } - /* restore */ - - gluDeleteQuadric(qobj); - glLoadMatrixf(rv3d->viewmat); - - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); + { + PropertyRNA *prop; + if ((prop = RNA_struct_find_property(ptr, "constraint_axis"))) { + RNA_property_boolean_set_array(ptr, prop, constraint_axis); + } + } + RNA_boolean_set(ptr, "release_confirm", 1); + } + MAN_ITER_AXES_END; } - -/* ********************************************* */ - -/* main call, does calc centers & orientation too */ -static int drawflags = 0xFFFF; // only for the calls below, belongs in scene...? - -void BIF_draw_manipulator(const bContext *C) +static void WIDGETGROUP_manipulator_refresh(const bContext *C, wmManipulatorGroup *mgroup) { + ManipulatorGroup *man = mgroup->customdata; ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); - Scene *scene = CTX_data_scene(C); View3D *v3d = sa->spacedata.first; RegionView3D *rv3d = ar->regiondata; - int totsel; + struct TransformBounds tbounds; - const bool is_picksel = false; + /* skip, we don't draw anything anyway */ + if ((man->all_hidden = (calc_manipulator_stats(C, true, &tbounds) == 0))) + return; - if (!(v3d->twflag & V3D_USE_MANIPULATOR)) return; + manipulator_prepare_mat(C, v3d, rv3d, &tbounds); - if ((v3d->twtype & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE | V3D_MANIP_SCALE)) == 0) return; + /* *** set properties for axes *** */ + MAN_ITER_AXES_BEGIN(axis, axis_idx) { - struct TransformBounds tbounds; - v3d->twflag &= ~V3D_DRAW_MANIPULATOR; - - totsel = calc_manipulator_stats(C, &tbounds); - if (totsel == 0) return; - - v3d->twflag |= V3D_DRAW_MANIPULATOR; - - /* now we can define center */ - switch (v3d->around) { - case V3D_AROUND_CENTER_BOUNDS: - case V3D_AROUND_ACTIVE: + const short axis_type = manipulator_get_axis_type(axis_idx); + const int aidx_norm = manipulator_orientation_axis(axis_idx, NULL); + + WM_manipulator_set_matrix_location(axis, rv3d->twmat[3]); + + switch (axis_idx) { + case MAN_AXIS_TRANS_X: + case MAN_AXIS_TRANS_Y: + case MAN_AXIS_TRANS_Z: + case MAN_AXIS_SCALE_X: + case MAN_AXIS_SCALE_Y: + case MAN_AXIS_SCALE_Z: { - bGPdata *gpd = CTX_data_gpencil_data(C); - Object *ob = OBACT; + float start_co[3] = {0.0f, 0.0f, 0.0f}; + float len; - if (((v3d->around == V3D_AROUND_ACTIVE) && (scene->obedit == NULL)) && - ((gpd == NULL) || !(gpd->flag & GP_DATA_STROKE_EDITMODE)) && - (ob && !(ob->mode & OB_MODE_POSE))) - { - copy_v3_v3(rv3d->twmat[3], ob->obmat[3]); - } - else { - mid_v3_v3v3(rv3d->twmat[3], tbounds.min, tbounds.max); - } + manipulator_line_range(v3d, axis_type, &start_co[2], &len); + + WM_manipulator_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]); + RNA_float_set(axis->ptr, "length", len); + WM_manipulator_set_matrix_offset_location(axis, start_co); + WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_OFFSET_SCALE, true); break; } - case V3D_AROUND_LOCAL_ORIGINS: - case V3D_AROUND_CENTER_MEAN: - copy_v3_v3(rv3d->twmat[3], tbounds.center); + case MAN_AXIS_ROT_X: + case MAN_AXIS_ROT_Y: + case MAN_AXIS_ROT_Z: + WM_manipulator_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]); break; - case V3D_AROUND_CURSOR: - copy_v3_v3(rv3d->twmat[3], ED_view3d_cursor3d_get(scene, v3d)); + case MAN_AXIS_TRANS_XY: + case MAN_AXIS_TRANS_YZ: + case MAN_AXIS_TRANS_ZX: + case MAN_AXIS_SCALE_XY: + case MAN_AXIS_SCALE_YZ: + case MAN_AXIS_SCALE_ZX: + { + const float *y_axis = rv3d->twmat[aidx_norm - 1 < 0 ? 2 : aidx_norm - 1]; + const float *z_axis = rv3d->twmat[aidx_norm]; + WM_manipulator_set_matrix_rotation_from_yz_axis(axis, y_axis, z_axis); break; + } } - - mul_mat3_m4_fl(rv3d->twmat, ED_view3d_pixel_size(rv3d, rv3d->twmat[3]) * U.tw_size); } + MAN_ITER_AXES_END; +} + +static void WIDGETGROUP_manipulator_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) +{ + ManipulatorGroup *man = mgroup->customdata; + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + View3D *v3d = sa->spacedata.first; + RegionView3D *rv3d = ar->regiondata; + float idot[3]; /* when looking through a selected camera, the manipulator can be at the * exact same position as the view, skip so we don't break selection */ - if (fabsf(mat4_to_scale(rv3d->twmat)) < 1e-7f) + if (man->all_hidden || fabsf(ED_view3d_pixel_size(rv3d, rv3d->twmat[3])) < 1e-6f) { + MAN_ITER_AXES_BEGIN(axis, axis_idx) + { + WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, true); + } + MAN_ITER_AXES_END; return; + } + manipulator_get_idot(rv3d, idot); - test_manipulator_axis(C); - drawflags = rv3d->twdrawflag; /* set in calc_manipulator_stats */ - - if (v3d->twflag & V3D_DRAW_MANIPULATOR) { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - glLineWidth(1.0f); + /* *** set properties for axes *** */ - if (v3d->twtype & V3D_MANIP_ROTATE) { - if (G.debug_value == 3) { - if (G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) - draw_manipulator_rotate_cyl(v3d, rv3d, drawflags, v3d->twtype, MAN_MOVECOL, true, is_picksel); - else - draw_manipulator_rotate_cyl(v3d, rv3d, drawflags, v3d->twtype, MAN_RGB, false, is_picksel); - } - else { - draw_manipulator_rotate(v3d, rv3d, drawflags, v3d->twtype, false, is_picksel); - } - } - if (v3d->twtype & V3D_MANIP_SCALE) { - draw_manipulator_scale(v3d, rv3d, drawflags, v3d->twtype, MAN_RGB, false, is_picksel); + MAN_ITER_AXES_BEGIN(axis, axis_idx) + { + const short axis_type = manipulator_get_axis_type(axis_idx); + /* XXX maybe unset _HIDDEN flag on redraw? */ + if (manipulator_is_axis_visible(v3d, rv3d, idot, axis_type, axis_idx)) { + WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, false); } - if (v3d->twtype & V3D_MANIP_TRANSLATE) { - draw_manipulator_translate(v3d, rv3d, drawflags, v3d->twtype, MAN_RGB, false, is_picksel); + else { + WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, true); + continue; } - glDisable(GL_BLEND); + float color[4], color_hi[4]; + manipulator_get_axis_color(axis_idx, idot, color, color_hi); + WM_manipulator_set_color(axis, color); + WM_manipulator_set_color_highlight(axis, color_hi); + + switch (axis_idx) { + case MAN_AXIS_TRANS_C: + case MAN_AXIS_ROT_C: + case MAN_AXIS_SCALE_C: + case MAN_AXIS_ROT_T: + WM_manipulator_set_matrix_rotation_from_z_axis(axis, rv3d->viewinv[2]); + break; + } } + MAN_ITER_AXES_END; } -static int manipulator_selectbuf(Scene *scene, ScrArea *sa, ARegion *ar, const int mval[2], float hotspot) +static bool WIDGETGROUP_manipulator_poll(const struct bContext *C, struct wmManipulatorGroupType *UNUSED(wgt)) { - View3D *v3d = sa->spacedata.first; - RegionView3D *rv3d = ar->regiondata; - rcti rect; - GLuint buffer[64]; // max 4 items per select, so large enuf - short hits; - const bool is_picksel = true; - const bool do_passes = GPU_select_query_check_active(); + /* it's a given we only use this in 3D view */ + const ScrArea *sa = CTX_wm_area(C); + const View3D *v3d = sa->spacedata.first; - /* when looking through a selected camera, the manipulator can be at the - * exact same position as the view, skip so we don't break selection */ - if (fabsf(mat4_to_scale(rv3d->twmat)) < 1e-7f) - return 0; + if (((v3d->twflag & V3D_MANIPULATOR_DRAW) != 0) && + ((v3d->twtype & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE | V3D_MANIP_SCALE)) != 0)) + { + /* Don't show when tools have a manipulator. */ + WorkSpace *workspace = CTX_wm_workspace(C); + if (workspace->tool.manipulator_group[0] == '\0') { + return true; + } + } + return false; +} - rect.xmin = mval[0] - hotspot; - rect.xmax = mval[0] + hotspot; - rect.ymin = mval[1] - hotspot; - rect.ymax = mval[1] + hotspot; +void TRANSFORM_WGT_manipulator(wmManipulatorGroupType *wgt) +{ + wgt->name = "Transform Manipulator"; + wgt->idname = "TRANSFORM_WGT_manipulator"; - ED_view3d_draw_setup_view(NULL, scene, ar, v3d, NULL, NULL, &rect); + wgt->flag |= (WM_MANIPULATORGROUPTYPE_PERSISTENT | + WM_MANIPULATORGROUPTYPE_3D); - if (do_passes) - GPU_select_begin(buffer, 64, &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0); - else - GPU_select_begin(buffer, 64, &rect, GPU_SELECT_ALL, 0); + wgt->poll = WIDGETGROUP_manipulator_poll; + wgt->setup = WIDGETGROUP_manipulator_setup; + wgt->refresh = WIDGETGROUP_manipulator_refresh; + wgt->draw_prepare = WIDGETGROUP_manipulator_draw_prepare; +} - /* do the drawing */ - if (v3d->twtype & V3D_MANIP_ROTATE) { - if (G.debug_value == 3) draw_manipulator_rotate_cyl(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel); - else draw_manipulator_rotate(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, false, is_picksel); - } - if (v3d->twtype & V3D_MANIP_SCALE) - draw_manipulator_scale(v3d, rv3d, MAN_SCALE_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel); - if (v3d->twtype & V3D_MANIP_TRANSLATE) - draw_manipulator_translate(v3d, rv3d, MAN_TRANS_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel); +/** \} */ - hits = GPU_select_end(); - if (do_passes && (hits > 0)) { - GPU_select_begin(buffer, 64, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits); +/* -------------------------------------------------------------------- */ +/** \name Scale Cage Manipulator + * \{ */ - /* do the drawing */ - if (v3d->twtype & V3D_MANIP_ROTATE) { - if (G.debug_value == 3) draw_manipulator_rotate_cyl(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel); - else draw_manipulator_rotate(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, false, is_picksel); - } - if (v3d->twtype & V3D_MANIP_SCALE) - draw_manipulator_scale(v3d, rv3d, MAN_SCALE_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel); - if (v3d->twtype & V3D_MANIP_TRANSLATE) - draw_manipulator_translate(v3d, rv3d, MAN_TRANS_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel); +struct XFormCageWidgetGroup { + wmManipulator *manipulator; +}; - GPU_select_end(); +static bool WIDGETGROUP_xform_cage_poll(const bContext *C, wmManipulatorGroupType *wgt) +{ + WorkSpace *workspace = CTX_wm_workspace(C); + if (!STREQ(wgt->idname, workspace->tool.manipulator_group)) { + WM_manipulator_group_type_unlink_delayed_ptr(wgt); + return false; } + return true; +} - ED_view3d_draw_setup_view(NULL, scene, ar, v3d, NULL, NULL, NULL); +static void WIDGETGROUP_xform_cage_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) +{ + struct XFormCageWidgetGroup *xmgroup = MEM_mallocN(sizeof(struct XFormCageWidgetGroup), __func__); + const wmManipulatorType *wt_cage = WM_manipulatortype_find("MANIPULATOR_WT_cage_3d", true); + xmgroup->manipulator = WM_manipulator_new_ptr(wt_cage, mgroup, NULL); + wmManipulator *mpr = xmgroup->manipulator; - if (hits == 1) return buffer[3]; - else if (hits > 1) { - GLuint val, dep, mindep = 0, mindeprot = 0, minval = 0, minvalrot = 0; - int a; + RNA_enum_set(mpr->ptr, "transform", + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE | + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE); - /* we compare the hits in buffer, but value centers highest */ - /* we also store the rotation hits separate (because of arcs) and return hits on other widgets if there are */ + mpr->color[0] = 1; + mpr->color_hi[0]=1; - for (a = 0; a < hits; a++) { - dep = buffer[4 * a + 1]; - val = buffer[4 * a + 3]; + mgroup->customdata = xmgroup; - if (val == MAN_TRANS_C) { - return MAN_TRANS_C; - } - else if (val == MAN_SCALE_C) { - return MAN_SCALE_C; - } - else { - if (val & MAN_ROT_C) { - if (minvalrot == 0 || dep < mindeprot) { - mindeprot = dep; - minvalrot = val; - } - } - else { - if (minval == 0 || dep < mindep) { - mindep = dep; - minval = val; + { + wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true); + PointerRNA *ptr; + + /* assign operator */ + PropertyRNA *prop_release_confirm = NULL; + PropertyRNA *prop_constraint_axis = NULL; + + int i = ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z; + for (int x = 0; x < 3; x++) { + for (int y = 0; y < 3; y++) { + for (int z = 0; z < 3; z++) { + int constraint[3] = {x != 1, y != 1, z != 1}; + ptr = WM_manipulator_operator_set(mpr, i, ot_resize, NULL); + if (prop_release_confirm == NULL) { + prop_release_confirm = RNA_struct_find_property(ptr, "release_confirm"); + prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis"); } + RNA_property_boolean_set(ptr, prop_release_confirm, true); + RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint); + i++; } } } - - if (minval) - return minval; - else - return minvalrot; } - return 0; } -static const char *manipulator_get_operator_name(int man_val) +static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmManipulatorGroup *mgroup) { - if (man_val & MAN_TRANS_C) { - return "TRANSFORM_OT_translate"; - } - else if (man_val == MAN_ROT_T) { - return "TRANSFORM_OT_trackball"; - } - else if (man_val & MAN_ROT_C) { - return "TRANSFORM_OT_rotate"; - } - else if (man_val & MAN_SCALE_C) { - return "TRANSFORM_OT_resize"; - } - - return NULL; -} - -/* return 0; nothing happened */ -int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op) -{ - Scene *scene = CTX_data_scene(C); ScrArea *sa = CTX_wm_area(C); View3D *v3d = sa->spacedata.first; ARegion *ar = CTX_wm_region(C); - int constraint_axis[3] = {0, 0, 0}; - int val; - const bool use_planar = RNA_boolean_get(op->ptr, "use_planar_constraint"); - - if (!(v3d->twflag & V3D_USE_MANIPULATOR)) return 0; - if (!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return 0; - - /* Force orientation */ - RNA_enum_set(op->ptr, "constraint_orientation", v3d->twmode); - - // find the hotspots first test narrow hotspot - val = manipulator_selectbuf(scene, sa, ar, event->mval, 0.5f * (float)U.tw_hotspot); - if (val) { - wmOperatorType *ot; - PointerRNA props_ptr; - PropertyRNA *prop; - const char *opname; - - // drawflags still global, for drawing call above - drawflags = manipulator_selectbuf(scene, sa, ar, event->mval, 0.2f * (float)U.tw_hotspot); - if (drawflags == 0) drawflags = val; - - /* Planar constraint doesn't make sense for rotation, give other keymaps a chance */ - if ((drawflags & MAN_ROT_C) && use_planar) { - return 0; - } + RegionView3D *rv3d = ar->regiondata; - opname = manipulator_get_operator_name(drawflags); - ot = WM_operatortype_find(opname, true); - WM_operator_properties_create_ptr(&props_ptr, ot); + struct XFormCageWidgetGroup *xmgroup = mgroup->customdata; + wmManipulator *mpr = xmgroup->manipulator; - if (drawflags & MAN_TRANS_C) { - switch (drawflags) { - case MAN_TRANS_C: - break; - case MAN_TRANS_X: - if (use_planar) { - constraint_axis[1] = 1; - constraint_axis[2] = 1; - } - else - constraint_axis[0] = 1; - break; - case MAN_TRANS_Y: - if (use_planar) { - constraint_axis[0] = 1; - constraint_axis[2] = 1; - } - else - constraint_axis[1] = 1; - break; - case MAN_TRANS_Z: - if (use_planar) { - constraint_axis[0] = 1; - constraint_axis[1] = 1; - } - else - constraint_axis[2] = 1; - break; - } - RNA_boolean_set_array(&props_ptr, "constraint_axis", constraint_axis); - } - else if (drawflags & MAN_SCALE_C) { - switch (drawflags) { - case MAN_SCALE_X: - if (use_planar) { - constraint_axis[1] = 1; - constraint_axis[2] = 1; - } - else - constraint_axis[0] = 1; - break; - case MAN_SCALE_Y: - if (use_planar) { - constraint_axis[0] = 1; - constraint_axis[2] = 1; - } - else - constraint_axis[1] = 1; - break; - case MAN_SCALE_Z: - if (use_planar) { - constraint_axis[0] = 1; - constraint_axis[1] = 1; + struct TransformBounds tbounds; + + if ((calc_manipulator_stats(C, false, &tbounds) == 0) || + equals_v3v3(rv3d->tw_axis_min, rv3d->tw_axis_max)) + { + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true); + } + else { + manipulator_prepare_mat(C, v3d, rv3d, &tbounds); + + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + + float dims[3]; + sub_v3_v3v3(dims, rv3d->tw_axis_max, rv3d->tw_axis_min); + RNA_float_set_array(mpr->ptr, "dimensions", dims); + mul_v3_fl(dims, 0.5f); + + copy_m4_m3(mpr->matrix_offset, rv3d->tw_axis_matrix); + mid_v3_v3v3(mpr->matrix_offset[3], rv3d->tw_axis_max, rv3d->tw_axis_min); + mul_m3_v3(rv3d->tw_axis_matrix, mpr->matrix_offset[3]); + + PropertyRNA *prop_center_override = NULL; + float center[3]; + float center_global[3]; + int i = ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z; + for (int x = 0; x < 3; x++) { + center[0] = (float)(1 - x) * dims[0]; + for (int y = 0; y < 3; y++) { + center[1] = (float)(1 - y) * dims[1]; + for (int z = 0; z < 3; z++) { + center[2] = (float)(1 - z) * dims[2]; + struct wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, i); + if (prop_center_override == NULL) { + prop_center_override = RNA_struct_find_property(&mpop->ptr, "center_override"); } - else - constraint_axis[2] = 1; - break; - } - RNA_boolean_set_array(&props_ptr, "constraint_axis", constraint_axis); - } - else if (drawflags == MAN_ROT_T) { - /* pass */ - } - else if (drawflags & MAN_ROT_C) { - switch (drawflags) { - case MAN_ROT_X: - constraint_axis[0] = 1; - break; - case MAN_ROT_Y: - constraint_axis[1] = 1; - break; - case MAN_ROT_Z: - constraint_axis[2] = 1; - break; + mul_v3_m4v3(center_global, mpr->matrix_offset, center); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, center_global); + i++; + } } - RNA_boolean_set_array(&props_ptr, "constraint_axis", constraint_axis); } + } +} - /* pass operator properties on to transform operators */ - prop = RNA_struct_find_property(op->ptr, "use_accurate"); - if (RNA_property_is_set(op->ptr, prop)) { - RNA_property_boolean_set(&props_ptr, prop, RNA_property_boolean_get(op->ptr, prop)); - } - prop = RNA_struct_find_property(op->ptr, "release_confirm"); - if (RNA_property_is_set(op->ptr, prop)) { - RNA_property_boolean_set(&props_ptr, prop, RNA_property_boolean_get(op->ptr, prop)); - } - prop = RNA_struct_find_property(op->ptr, "constraint_orientation"); - if (RNA_property_is_set(op->ptr, prop)) { - RNA_property_enum_set(&props_ptr, prop, RNA_property_enum_get(op->ptr, prop)); - } +static void WIDGETGROUP_xform_cage_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) +{ + struct XFormCageWidgetGroup *xmgroup = mgroup->customdata; + wmManipulator *mpr = xmgroup->manipulator; - WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr); - WM_operator_properties_free(&props_ptr); + SceneLayer *sl = CTX_data_scene_layer(C); + Object *ob = OBACT(sl); + if (ob && ob->mode & OB_MODE_EDIT) { + copy_m4_m4(mpr->matrix_space, ob->obmat); + } + else { + unit_m4(mpr->matrix_space); } - /* after transform, restore drawflags */ - drawflags = 0xFFFF; +} + +void VIEW3D_WGT_xform_cage(wmManipulatorGroupType *wgt) +{ + wgt->name = "Transform Cage"; + wgt->idname = "VIEW3D_WGT_xform_cage"; + + wgt->flag |= (WM_MANIPULATORGROUPTYPE_3D | + WM_MANIPULATORGROUPTYPE_DEPTH_3D); + + wgt->mmap_params.spaceid = SPACE_VIEW3D; + wgt->mmap_params.regionid = RGN_TYPE_WINDOW; - return val; + wgt->poll = WIDGETGROUP_xform_cage_poll; + wgt->setup = WIDGETGROUP_xform_cage_setup; + wgt->refresh = WIDGETGROUP_xform_cage_refresh; + wgt->draw_prepare = WIDGETGROUP_xform_cage_draw_prepare; } +/** \} */ diff --git a/source/blender/editors/transform/transform_manipulator2d.c b/source/blender/editors/transform/transform_manipulator2d.c new file mode 100644 index 00000000000..6e2d0d8c5c0 --- /dev/null +++ b/source/blender/editors/transform/transform_manipulator2d.c @@ -0,0 +1,383 @@ +/* + * ***** 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) 2016 Blender Foundation. + * All rights reserved. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/transform/transform_manipulator2d.c + * \ingroup edtransform + * + * \name 2D Transform Manipulator + * + * Used for UV/Image Editor + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" + +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_view3d_types.h" + +#include "BKE_context.h" +#include "BKE_editmesh.h" + +#include "RNA_access.h" + +#include "UI_resources.h" +#include "UI_view2d.h" + +#include "WM_api.h" +#include "WM_types.h" +#include "wm.h" /* XXX */ + +#include "ED_image.h" +#include "ED_screen.h" +#include "ED_uvedit.h" +#include "ED_manipulator_library.h" + +#include "transform.h" /* own include */ + +/* axes as index */ +enum { + MAN2D_AXIS_TRANS_X = 0, + MAN2D_AXIS_TRANS_Y, + + MAN2D_AXIS_LAST, +}; + +typedef struct ManipulatorGroup2D { + wmManipulator *translate_x, + *translate_y; + + wmManipulator *cage; + + /* Current origin in view space, used to update widget origin for possible view changes */ + float origin[2]; + float min[2]; + float max[2]; + +} ManipulatorGroup2D; + + +/* **************** Utilities **************** */ + +/* loop over axes */ +#define MAN2D_ITER_AXES_BEGIN(axis, axis_idx) \ + { \ + wmManipulator *axis; \ + int axis_idx; \ + for (axis_idx = 0; axis_idx < MAN2D_AXIS_LAST; axis_idx++) { \ + axis = manipulator2d_get_axis_from_index(man, axis_idx); + +#define MAN2D_ITER_AXES_END \ + } \ + } ((void)0) + +static wmManipulator *manipulator2d_get_axis_from_index(const ManipulatorGroup2D *man, const short axis_idx) +{ + BLI_assert(IN_RANGE_INCL(axis_idx, (float)MAN2D_AXIS_TRANS_X, (float)MAN2D_AXIS_TRANS_Y)); + + switch (axis_idx) { + case MAN2D_AXIS_TRANS_X: + return man->translate_x; + case MAN2D_AXIS_TRANS_Y: + return man->translate_y; + } + + return NULL; +} + +static void manipulator2d_get_axis_color(const int axis_idx, float *r_col, float *r_col_hi) +{ + const float alpha = 0.6f; + const float alpha_hi = 1.0f; + int col_id; + + switch (axis_idx) { + case MAN2D_AXIS_TRANS_X: + col_id = TH_AXIS_X; + break; + case MAN2D_AXIS_TRANS_Y: + col_id = TH_AXIS_Y; + break; + } + + UI_GetThemeColor4fv(col_id, r_col); + + copy_v4_v4(r_col_hi, r_col); + r_col[3] *= alpha; + r_col_hi[3] *= alpha_hi; +} + +static ManipulatorGroup2D *manipulatorgroup2d_init(wmManipulatorGroup *mgroup) +{ + const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_2d", true); + const wmManipulatorType *wt_cage = WM_manipulatortype_find("MANIPULATOR_WT_cage_2d", true); + + ManipulatorGroup2D *man = MEM_callocN(sizeof(ManipulatorGroup2D), __func__); + + man->translate_x = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); + man->translate_y = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); + man->cage = WM_manipulator_new_ptr(wt_cage, mgroup, NULL); + + RNA_enum_set(man->cage->ptr, "transform", + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE | + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE | + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_ROTATE); + + return man; +} + +/** + * Calculates origin in view space, use with #manipulator2d_origin_to_region. + */ +static void manipulator2d_calc_bounds(const bContext *C, float *r_center, float *r_min, float *r_max) +{ + SpaceImage *sima = CTX_wm_space_image(C); + Image *ima = ED_space_image(sima); + + float min_buf[2], max_buf[2]; + if (r_min == NULL) { + r_min = min_buf; + } + if (r_max == NULL) { + r_max = max_buf; + } + + if (!ED_uvedit_minmax(CTX_data_scene(C), ima, CTX_data_edit_object(C), r_min, r_max)) { + zero_v2(r_min); + zero_v2(r_max); + } + mid_v2_v2v2(r_center, r_min, r_max); +} + +/** + * Convert origin (or any other point) from view to region space. + */ +BLI_INLINE void manipulator2d_origin_to_region(ARegion *ar, float *r_origin) +{ + UI_view2d_view_to_region_fl(&ar->v2d, r_origin[0], r_origin[1], &r_origin[0], &r_origin[1]); +} + +/** + * Custom handler for manipulator widgets + */ +static int manipulator2d_modal( + bContext *C, wmManipulator *widget, const wmEvent *UNUSED(event), + eWM_ManipulatorTweak UNUSED(tweak_flag)) +{ + ARegion *ar = CTX_wm_region(C); + float origin[3]; + + manipulator2d_calc_bounds(C, origin, NULL, NULL); + manipulator2d_origin_to_region(ar, origin); + WM_manipulator_set_matrix_location(widget, origin); + + ED_region_tag_redraw(ar); + + return OPERATOR_RUNNING_MODAL; +} + +void ED_widgetgroup_manipulator2d_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) +{ + wmOperatorType *ot_translate = WM_operatortype_find("TRANSFORM_OT_translate", true); + ManipulatorGroup2D *man = manipulatorgroup2d_init(mgroup); + mgroup->customdata = man; + + MAN2D_ITER_AXES_BEGIN(axis, axis_idx) + { + const float offset[3] = {0.0f, 0.2f}; + + float color[4], color_hi[4]; + manipulator2d_get_axis_color(axis_idx, color, color_hi); + + /* custom handler! */ + WM_manipulator_set_fn_custom_modal(axis, manipulator2d_modal); + /* set up widget data */ + RNA_float_set(axis->ptr, "angle", -M_PI_2 * axis_idx); + RNA_float_set(axis->ptr, "length", 0.8f); + WM_manipulator_set_matrix_offset_location(axis, offset); + WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH); + WM_manipulator_set_scale(axis, U.manipulator_size); + WM_manipulator_set_color(axis, color); + WM_manipulator_set_color_highlight(axis, color_hi); + + /* assign operator */ + PointerRNA *ptr = WM_manipulator_operator_set(axis, 0, ot_translate, NULL); + int constraint[3] = {0}; + constraint[(axis_idx + 1) % 2] = 1; + if (RNA_struct_find_property(ptr, "constraint_axis")) + RNA_boolean_set_array(ptr, "constraint_axis", constraint); + RNA_boolean_set(ptr, "release_confirm", 1); + } + MAN2D_ITER_AXES_END; + + { + wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true); + wmOperatorType *ot_rotate = WM_operatortype_find("TRANSFORM_OT_rotate", true); + PointerRNA *ptr; + + /* assign operator */ + ptr = WM_manipulator_operator_set(man->cage, 0, ot_translate, NULL); + RNA_boolean_set(ptr, "release_confirm", 1); + + int constraint_x[3] = {1, 0, 0}; + int constraint_y[3] = {0, 1, 0}; + + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X, ot_resize, NULL); + PropertyRNA *prop_release_confirm = RNA_struct_find_property(ptr, "release_confirm"); + PropertyRNA *prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis"); + RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X, ot_resize, NULL); + RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_Y, ot_resize, NULL); + RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_Y, ot_resize, NULL); + RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MIN_Y, ot_resize, NULL); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MAX_Y, ot_resize, NULL); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MIN_Y, ot_resize, NULL); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MAX_Y, ot_resize, NULL); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_ROTATE, ot_rotate, NULL); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + } +} + +void ED_widgetgroup_manipulator2d_refresh(const bContext *C, wmManipulatorGroup *mgroup) +{ + ManipulatorGroup2D *man = mgroup->customdata; + float origin[3]; + manipulator2d_calc_bounds(C, origin, man->min, man->max); + copy_v2_v2(man->origin, origin); + bool show_cage = !equals_v2v2(man->min, man->max); + + if (show_cage) { + man->cage->flag &= ~WM_MANIPULATOR_HIDDEN; + man->translate_x->flag |= WM_MANIPULATOR_HIDDEN; + man->translate_y->flag |= WM_MANIPULATOR_HIDDEN; + } + else { + man->cage->flag |= WM_MANIPULATOR_HIDDEN; + man->translate_x->flag &= ~WM_MANIPULATOR_HIDDEN; + man->translate_y->flag &= ~WM_MANIPULATOR_HIDDEN; + } + + if (show_cage) { + wmManipulatorOpElem *mpop; + float mid[2]; + const float *min = man->min; + const float *max = man->max; + mid_v2_v2v2(mid, min, max); + + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X); + PropertyRNA *prop_center_override = RNA_struct_find_property(&mpop->ptr, "center_override"); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){max[0], mid[1], 0.0f}); + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){min[0], mid[1], 0.0f}); + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_Y); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){mid[0], max[1], 0.0f}); + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_Y); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){mid[0], min[1], 0.0f}); + + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MIN_Y); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){max[0], max[1], 0.0f}); + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MAX_Y); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){max[0], min[1], 0.0f}); + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MIN_Y); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){min[0], max[1], 0.0f}); + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MAX_Y); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){min[0], min[1], 0.0f}); + + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_ROTATE); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){mid[0], mid[1], 0.0f}); + } +} + +void ED_widgetgroup_manipulator2d_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) +{ + ARegion *ar = CTX_wm_region(C); + ManipulatorGroup2D *man = mgroup->customdata; + float origin[3] = {UNPACK2(man->origin), 0.0f}; + float origin_aa[3] = {UNPACK2(man->origin), 0.0f}; + + manipulator2d_origin_to_region(ar, origin); + + MAN2D_ITER_AXES_BEGIN(axis, axis_idx) + { + WM_manipulator_set_matrix_location(axis, origin); + } + MAN2D_ITER_AXES_END; + + UI_view2d_view_to_region_m4(&ar->v2d, man->cage->matrix_space); + WM_manipulator_set_matrix_offset_location(man->cage, origin_aa); + man->cage->matrix_offset[0][0] = (man->max[0] - man->min[0]); + man->cage->matrix_offset[1][1] = (man->max[1] - man->min[1]); +} + +/* TODO (Julian) + * - Called on every redraw, better to do a more simple poll and check for selection in _refresh + * - UV editing only, could be expanded for other things. + */ +bool ED_widgetgroup_manipulator2d_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) +{ + SpaceImage *sima = CTX_wm_space_image(C); + Object *obedit = CTX_data_edit_object(C); + + if (ED_space_image_show_uvedit(sima, obedit)) { + Image *ima = ED_space_image(sima); + Scene *scene = CTX_data_scene(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + /* check if there's a selected poly */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, ima, efa)) + continue; + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + return true; + } + } + } + } + + return false; +} diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 46bd83b5d35..ad855427ff1 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -160,11 +160,12 @@ const EnumPropertyItem rna_enum_transform_mode_types[] = static int select_orientation_exec(bContext *C, wmOperator *op) { + View3D *v3d = CTX_wm_view3d(C); int orientation = RNA_enum_get(op->ptr, "orientation"); - BIF_selectTransformOrientationValue(C, orientation); + BIF_selectTransformOrientationValue(v3d, orientation); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C)); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); return OPERATOR_FINISHED; } @@ -206,10 +207,9 @@ static void TRANSFORM_OT_select_orientation(struct wmOperatorType *ot) static int delete_orientation_exec(bContext *C, wmOperator *UNUSED(op)) { View3D *v3d = CTX_wm_view3d(C); - int selected_index = (v3d->twmode - V3D_MANIP_CUSTOM); - BIF_removeTransformOrientationIndex(C, selected_index); - + BIF_removeTransformOrientationIndex(C, v3d->custom_orientation_index); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); WM_event_add_notifier(C, NC_SCENE | NA_EDITED, CTX_data_scene(C)); @@ -223,18 +223,12 @@ static int delete_orientation_invoke(bContext *C, wmOperator *op, const wmEvent static int delete_orientation_poll(bContext *C) { - int selected_index = -1; View3D *v3d = CTX_wm_view3d(C); - + if (ED_operator_areaactive(C) == 0) return 0; - - - if (v3d) { - selected_index = (v3d->twmode - V3D_MANIP_CUSTOM); - } - - return selected_index >= 0; + + return (v3d->twmode >= V3D_MANIP_CUSTOM) && (v3d->custom_orientation_index != -1); } static void TRANSFORM_OT_delete_orientation(struct wmOperatorType *ot) @@ -1066,6 +1060,8 @@ void transform_keymap_for_space(wmKeyConfig *keyconf, wmKeyMap *keymap, int spac kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", TABKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); RNA_string_set(kmi->ptr, "data_path", "tool_settings.snap_element"); + /* Will fall-through to texture-space transform. */ + kmi = WM_keymap_add_item(keymap, "OBJECT_OT_transform_axis_target", TKEY, KM_PRESS, KM_SHIFT, 0); kmi = WM_keymap_add_item(keymap, OP_TRANSLATION, TKEY, KM_PRESS, KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "texture_space", true); diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 54959304d72..86f99c4fed2 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -38,6 +38,7 @@ #include "DNA_screen_types.h" #include "DNA_space_types.h" #include "DNA_view3d_types.h" +#include "DNA_workspace_types.h" #include "BLI_math.h" #include "BLI_listbase.h" @@ -52,6 +53,7 @@ #include "BKE_report.h" #include "BKE_main.h" #include "BKE_screen.h" +#include "BKE_workspace.h" #include "BLT_translation.h" @@ -63,14 +65,16 @@ void BIF_clearTransformOrientation(bContext *C) { + WorkSpace *workspace = CTX_wm_workspace(C); + ListBase *transform_orientations = BKE_workspace_transform_orientations_get(workspace); View3D *v3d = CTX_wm_view3d(C); - ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces; - BLI_freelistN(transform_spaces); + BLI_freelistN(transform_orientations); // Need to loop over all view3d - if (v3d && v3d->twmode >= V3D_MANIP_CUSTOM) { - v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global */ + if (v3d && v3d->twmode == V3D_MANIP_CUSTOM) { + v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global */ + v3d->custom_orientation_index = -1; } } @@ -318,23 +322,24 @@ void BIF_createTransformOrientation(bContext *C, ReportList *reports, TransformOrientation *addMatrixSpace(bContext *C, float mat[3][3], const char *name, const bool overwrite) { - ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces; TransformOrientation *ts = NULL; + WorkSpace *workspace = CTX_wm_workspace(C); + ListBase *transform_orientations = BKE_workspace_transform_orientations_get(workspace); char name_unique[sizeof(ts->name)]; if (overwrite) { - ts = findOrientationName(transform_spaces, name); + ts = findOrientationName(transform_orientations, name); } else { BLI_strncpy(name_unique, name, sizeof(name_unique)); - uniqueOrientationName(transform_spaces, name_unique); + uniqueOrientationName(transform_orientations, name_unique); name = name_unique; } /* if not, create a new one */ if (ts == NULL) { ts = MEM_callocN(sizeof(TransformOrientation), "UserTransSpace from matrix"); - BLI_addtail(transform_spaces, ts); + BLI_addtail(transform_orientations, ts); BLI_strncpy(ts->name, name, sizeof(ts->name)); } @@ -346,70 +351,55 @@ TransformOrientation *addMatrixSpace(bContext *C, float mat[3][3], void BIF_removeTransformOrientation(bContext *C, TransformOrientation *target) { - Scene *scene = CTX_data_scene(C); - ListBase *transform_spaces = &scene->transform_spaces; - const int i = BLI_findindex(transform_spaces, target); - - if (i != -1) { - Main *bmain = CTX_data_main(C); - BKE_screen_view3d_main_twmode_remove(&bmain->screen, scene, i); - BLI_freelinkN(transform_spaces, target); - } + BKE_workspace_transform_orientation_remove(CTX_wm_workspace(C), target); } void BIF_removeTransformOrientationIndex(bContext *C, int index) { - ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces; - TransformOrientation *ts = BLI_findlink(transform_spaces, index); - - if (ts) { - BIF_removeTransformOrientation(C, ts); - } + TransformOrientation *target = BKE_workspace_transform_orientation_find(CTX_wm_workspace(C), index); + BIF_removeTransformOrientation(C, target); } void BIF_selectTransformOrientation(bContext *C, TransformOrientation *target) { - ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces; - const int i = BLI_findindex(transform_spaces, target); + int index = BKE_workspace_transform_orientation_get_index(CTX_wm_workspace(C), target); + View3D *v3d = CTX_wm_view3d(C); - if (i != -1) { - View3D *v3d = CTX_wm_view3d(C); - v3d->twmode = V3D_MANIP_CUSTOM + i; - } + BLI_assert(index != -1); + + v3d->twmode = V3D_MANIP_CUSTOM; + v3d->custom_orientation_index = index; } -void BIF_selectTransformOrientationValue(bContext *C, int orientation) +/** + * Activate a transform orientation in a 3D view based on an enum value. + * + * \param orientation: If this is #V3D_MANIP_CUSTOM or greater, the custom transform orientation + * with index \a orientation - #V3D_MANIP_CUSTOM gets activated. + */ +void BIF_selectTransformOrientationValue(View3D *v3d, int orientation) { - View3D *v3d = CTX_wm_view3d(C); - if (v3d) /* currently using generic poll */ - v3d->twmode = orientation; + const bool is_custom = orientation >= V3D_MANIP_CUSTOM; + + v3d->twmode = is_custom ? V3D_MANIP_CUSTOM : orientation; + v3d->custom_orientation_index = is_custom ? (orientation - V3D_MANIP_CUSTOM) : -1; } int BIF_countTransformOrientation(const bContext *C) { - ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces; - return BLI_listbase_count(transform_spaces); + WorkSpace *workspace = CTX_wm_workspace(C); + ListBase *transform_orientations = BKE_workspace_transform_orientations_get(workspace); + return BLI_listbase_count(transform_orientations); } -bool applyTransformOrientation(const bContext *C, float mat[3][3], char *r_name, int index) +bool applyTransformOrientation(const TransformOrientation *ts, float r_mat[3][3], char *r_name) { - ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces; - TransformOrientation *ts = BLI_findlink(transform_spaces, index); - - BLI_assert(index >= 0); - - if (ts) { - if (r_name) { - BLI_strncpy(r_name, ts->name, MAX_NAME); - } - - copy_m3_m3(mat, ts->mat); - return true; - } - else { - /* invalid index, can happen sometimes */ - return false; + if (r_name) { + BLI_strncpy(r_name, ts->name, MAX_NAME); } + copy_m3_m3(r_mat, ts->mat); + + return true; } static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it) @@ -492,8 +482,10 @@ void initTransformOrientation(bContext *C, TransInfo *t) unit_m3(t->spacemtx); } break; - default: /* V3D_MANIP_CUSTOM */ - if (applyTransformOrientation(C, t->spacemtx, t->spacename, t->current_orientation - V3D_MANIP_CUSTOM)) { + case V3D_MANIP_CUSTOM: + BLI_strncpy(t->spacename, t->custom_orientation->name, sizeof(t->spacename)); + + if (applyTransformOrientation(t->custom_orientation, t->spacemtx, t->spacename)) { /* pass */ } else { @@ -586,10 +578,10 @@ static unsigned int bm_mesh_faces_select_get_n(BMesh *bm, BMVert **elems, const int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3], const short around) { - Scene *scene = CTX_data_scene(C); + SceneLayer *sl = CTX_data_scene_layer(C); Object *obedit = CTX_data_edit_object(C); Base *base; - Object *ob = OBACT; + Object *ob = OBACT(sl); int result = ORIENTATION_NONE; const bool activeOnly = (around == V3D_AROUND_ACTIVE); @@ -1052,16 +1044,16 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3 } else { /* we need the one selected object, if its not active */ - View3D *v3d = CTX_wm_view3d(C); - ob = OBACT; - if (ob && (ob->flag & SELECT)) { + base = BASACT(sl); + ob = OBACT(sl); + if (base && ((base->flag & BASE_SELECTED) != 0)) { /* pass */ } else { /* first selected */ ob = NULL; - for (base = scene->base.first; base; base = base->next) { - if (TESTBASELIB(v3d, base)) { + for (base = sl->object_bases.first; base; base = base->next) { + if (TESTBASELIB(base)) { ob = base->object; break; } diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 45b8ca3749f..3a71800e9cd 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -49,7 +49,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" -#include "BIF_gl.h" +#include "GPU_immediate.h" #include "BKE_DerivedMesh.h" #include "BKE_global.h" @@ -163,36 +163,42 @@ void drawSnapping(const struct bContext *C, TransInfo *t) size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE); invert_m4_m4(imat, rv3d->viewmat); - + + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + for (p = t->tsnap.points.first; p; p = p->next) { if (p == t->tsnap.selectedPoint) { - glColor4ubv(selectedCol); + immUniformColor4ubv(selectedCol); } else { - glColor4ubv(col); + immUniformColor4ubv(col); } - drawcircball(GL_LINE_LOOP, p->co, ED_view3d_pixel_size(rv3d, p->co) * size * 0.75f, imat); + imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size * 0.75f, imat, pos); } if (t->tsnap.status & POINT_INIT) { - glColor4ubv(activeCol); + immUniformColor4ubv(activeCol); - drawcircball(GL_LINE_LOOP, t->tsnap.snapPoint, ED_view3d_pixel_size(rv3d, t->tsnap.snapPoint) * size, imat); + imm_drawcircball(t->tsnap.snapPoint, ED_view3d_pixel_size(rv3d, t->tsnap.snapPoint) * size, imat, pos); } /* draw normal if needed */ if (usingSnappingNormal(t) && validSnappingNormal(t)) { - glColor4ubv(activeCol); + immUniformColor4ubv(activeCol); - glBegin(GL_LINES); - glVertex3f(t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], t->tsnap.snapPoint[2]); - glVertex3f(t->tsnap.snapPoint[0] + t->tsnap.snapNormal[0], - t->tsnap.snapPoint[1] + t->tsnap.snapNormal[1], - t->tsnap.snapPoint[2] + t->tsnap.snapNormal[2]); - glEnd(); + immBegin(GWN_PRIM_LINES, 2); + immVertex3f(pos, t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], t->tsnap.snapPoint[2]); + immVertex3f(pos, t->tsnap.snapPoint[0] + t->tsnap.snapNormal[0], + t->tsnap.snapPoint[1] + t->tsnap.snapNormal[1], + t->tsnap.snapPoint[2] + t->tsnap.snapNormal[2]); + immEnd(); } - + + immUnbindProgram(); + if (v3d->zbuf) glEnable(GL_DEPTH_TEST); } @@ -200,35 +206,7 @@ void drawSnapping(const struct bContext *C, TransInfo *t) else if (t->spacetype == SPACE_IMAGE) { if (validSnap(t)) { /* This will not draw, and Im nor sure why - campbell */ -#if 0 - float xuser_asp, yuser_asp; - int wi, hi; - float w, h; - - calc_image_view(G.sima, 'f'); // float - myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax); - glLoadIdentity(); - - ED_space_image_get_aspect(t->sa->spacedata.first, &xuser_aspx, &yuser_asp); - ED_space_image_width(t->sa->spacedata.first, &wi, &hi); - w = (((float)wi) / IMG_SIZE_FALLBACK) * G.sima->zoom * xuser_asp; - h = (((float)hi) / IMG_SIZE_FALLBACK) * G.sima->zoom * yuser_asp; - - cpack(0xFFFFFF); - glTranslate2fv(t->tsnap.snapPoint); - - //glRectf(0, 0, 1, 1); - - setlinestyle(0); - cpack(0x0); - fdrawline(-0.020 / w, 0, -0.1 / w, 0); - fdrawline(0.1 / w, 0, 0.020 / w, 0); - fdrawline(0, -0.020 / h, 0, -0.1 / h); - fdrawline(0, 0.1 / h, 0, 0.020 / h); - - glTranslatef(-t->tsnap.snapPoint[0], -t->tsnap.snapPoint[1], 0.0f); - setlinestyle(0); -#endif + /* TODO: see 2.7x for non-working code */ } } else if (t->spacetype == SPACE_NODE) { @@ -241,23 +219,29 @@ void drawSnapping(const struct bContext *C, TransInfo *t) glEnable(GL_BLEND); + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + for (p = t->tsnap.points.first; p; p = p->next) { if (p == t->tsnap.selectedPoint) { - glColor4ubv(selectedCol); + immUniformColor4ubv(selectedCol); } else { - glColor4ubv(col); + immUniformColor4ubv(col); } - ED_node_draw_snap(&ar->v2d, p->co, size, 0); + ED_node_draw_snap(&ar->v2d, p->co, size, 0, pos); } if (t->tsnap.status & POINT_INIT) { - glColor4ubv(activeCol); + immUniformColor4ubv(activeCol); - ED_node_draw_snap(&ar->v2d, t->tsnap.snapPoint, size, t->tsnap.snapNodeBorder); + ED_node_draw_snap(&ar->v2d, t->tsnap.snapPoint, size, t->tsnap.snapNodeBorder, pos); } - + + immUnbindProgram(); + glDisable(GL_BLEND); } } @@ -519,8 +503,8 @@ static void initSnappingMode(TransInfo *t) { ToolSettings *ts = t->settings; Object *obedit = t->obedit; - Scene *scene = t->scene; - Base *base_act = scene->basact; + SceneLayer *sl = t->scene_layer; + Base *base_act = sl->basact; if (t->spacetype == SPACE_NODE) { /* force project off when not supported */ @@ -601,7 +585,7 @@ static void initSnappingMode(TransInfo *t) if (t->spacetype == SPACE_VIEW3D) { if (t->tsnap.object_context == NULL) { t->tsnap.object_context = ED_transform_snap_object_context_create_view3d( - G.main, t->scene, 0, + G.main, t->scene, t->scene_layer, t->engine, 0, t->ar, t->view); ED_transform_snap_object_context_set_editmesh_callbacks( diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 737005ccf8b..135ea406d60 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -51,6 +51,9 @@ #include "BKE_editmesh.h" #include "BKE_main.h" #include "BKE_tracking.h" +#include "BKE_context.h" + +#include "DEG_depsgraph.h" #include "ED_transform.h" #include "ED_transform_snap_object_context.h" @@ -101,6 +104,8 @@ typedef struct SnapObjectData_EditMesh { struct SnapObjectContext { Main *bmain; Scene *scene; + EvaluationContext eval_ctx; + int flag; /* Optional: when performing screen-space projection. @@ -155,7 +160,7 @@ static void iter_snap_objects( IterSnapObjsCallback sob_callback, void *data) { - Base *base_act = sctx->scene->basact; + Base *base_act = sctx->eval_ctx.scene_layer->basact; /* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA * which makes the loop skip it, even the derived mesh will never change * @@ -165,17 +170,16 @@ static void iter_snap_objects( sob_callback(sctx, false, base_act->object, base_act->object->obmat, data); } - for (Base *base = sctx->scene->base.first; base != NULL; base = base->next) { - if ((BASE_VISIBLE_BGMODE(sctx->v3d_data.v3d, sctx->scene, base)) && - (base->flag & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 && - !((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL))) || + for (Base *base = sctx->eval_ctx.scene_layer->object_bases.first; base != NULL; base = base->next) { + if ((BASE_VISIBLE(base)) && (base->flag_legacy & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 && + !((snap_select == SNAP_NOT_SELECTED && ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL))) || (snap_select == SNAP_NOT_ACTIVE && base == base_act))) { bool use_obedit; Object *obj = base->object; if (obj->transflag & OB_DUPLI) { DupliObject *dupli_ob; - ListBase *lb = object_duplilist(sctx->bmain->eval_ctx, sctx->scene, obj); + ListBase *lb = object_duplilist(&sctx->eval_ctx, sctx->scene, obj); for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { use_obedit = obedit && dupli_ob->ob->data == obedit->data; sob_callback(sctx, use_obedit, use_obedit ? obedit : dupli_ob->ob, dupli_ob->mat, data); @@ -734,10 +738,10 @@ static bool raycastObj( DerivedMesh *dm; em = BKE_editmesh_from_object(ob); if (em) { - editbmesh_get_derived_cage_and_final(sctx->scene, ob, em, CD_MASK_BAREMESH, &dm); + editbmesh_get_derived_cage_and_final(&sctx->eval_ctx, sctx->scene, ob, em, CD_MASK_BAREMESH, &dm); } else { - dm = mesh_get_derived_final(sctx->scene, ob, CD_MASK_BAREMESH); + dm = mesh_get_derived_final(&sctx->eval_ctx, sctx->scene, ob, CD_MASK_BAREMESH); } retval = raycastDerivedMesh( sctx, @@ -1947,10 +1951,10 @@ static bool snapObject( DerivedMesh *dm; em = BKE_editmesh_from_object(ob); if (em) { - editbmesh_get_derived_cage_and_final(sctx->scene, ob, em, CD_MASK_BAREMESH, &dm); + editbmesh_get_derived_cage_and_final(&sctx->eval_ctx, sctx->scene, ob, em, CD_MASK_BAREMESH, &dm); } else { - dm = mesh_get_derived_final(sctx->scene, ob, CD_MASK_BAREMESH); + dm = mesh_get_derived_final(&sctx->eval_ctx, sctx->scene, ob, CD_MASK_BAREMESH); } retval = snapDerivedMesh( sctx, snapdata, ob, dm, obmat, @@ -2092,7 +2096,7 @@ static bool snapObjectsRay( * \{ */ SnapObjectContext *ED_transform_snap_object_context_create( - Main *bmain, Scene *scene, int flag) + Main *bmain, Scene *scene, SceneLayer *sl, RenderEngineType *engine, int flag) { SnapObjectContext *sctx = MEM_callocN(sizeof(*sctx), __func__); @@ -2101,6 +2105,8 @@ SnapObjectContext *ED_transform_snap_object_context_create( sctx->bmain = bmain; sctx->scene = scene; + DEG_evaluation_context_init_from_scene(&sctx->eval_ctx, scene, sl, engine, DAG_EVAL_VIEWPORT); + sctx->cache.object_map = BLI_ghash_ptr_new(__func__); sctx->cache.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); @@ -2108,11 +2114,11 @@ SnapObjectContext *ED_transform_snap_object_context_create( } SnapObjectContext *ED_transform_snap_object_context_create_view3d( - Main *bmain, Scene *scene, int flag, + Main *bmain, Scene *scene, SceneLayer *sl, RenderEngineType *engine, int flag, /* extra args for view3d */ const ARegion *ar, const View3D *v3d) { - SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, flag); + SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, sl, engine, flag); sctx->use_v3d = true; sctx->v3d_data.ar = ar; |