[Bf-blender-cvs] [9d8b034] wiggly-widgets: Transform Manipulator: Rotation indicator (arc overlay)

Julian Eisel noreply at git.blender.org
Fri Apr 1 17:13:44 CEST 2016


Commit: 9d8b0348b794a63ddaefa2012f9005b24133f64d
Author: Julian Eisel
Date:   Fri Apr 1 17:08:57 2016 +0200
Branches: wiggly-widgets
https://developer.blender.org/rB9d8b0348b794a63ddaefa2012f9005b24133f64d

Transform Manipulator: Rotation indicator (arc overlay)

Adds a arc shaped overlay indicating the current rotation value for the rotation transform manipulator.

This is still ignoring constraints, which can be fixed by calculating angle using object matrices instead of cursor position.
Seems like we could also use BLI_dial_angle here, but will check on that at some other point.
Visual design is a subject to change of course. Will add screenshots to T47032.

===================================================================

M	source/blender/editors/transform/transform_manipulator.c
M	source/blender/windowmanager/widgets/WM_widget_types.h
M	source/blender/windowmanager/widgets/intern/widget_library/dial_widget.c
M	source/blender/windowmanager/widgets/intern/wm_widgetmap.c

===================================================================

diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index eeddfb8..2a8a21f 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -1198,6 +1198,7 @@ void WIDGETGROUP_manipulator_create(const struct bContext *C, struct wmWidgetGro
 				WIDGET_dial_set_up_vector(axis, rv3d->twmat[aidx_norm]);
 				/* increased line width for better display */
 				WM_widget_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH + 1.0f);
+				WM_widget_set_flag(axis, WM_WIDGET_DRAW_VALUE, true);
 				break;
 			case MAN_AXIS_TRANS_XY:
 			case MAN_AXIS_TRANS_YZ:
@@ -1229,7 +1230,10 @@ void WIDGETGROUP_manipulator_create(const struct bContext *C, struct wmWidgetGro
 				if (axis_idx == MAN_AXIS_ROT_T) {
 					WM_widget_set_flag(axis, WM_WIDGET_DRAW_HOVER, true);
 				}
-				else if (axis_idx != MAN_AXIS_ROT_C) {
+				else if (axis_idx == MAN_AXIS_ROT_C) {
+					WM_widget_set_flag(axis, WM_WIDGET_DRAW_VALUE, true);
+				}
+				else {
 					WM_widget_set_scale(axis, 0.2f);
 				}
 				break;
diff --git a/source/blender/windowmanager/widgets/WM_widget_types.h b/source/blender/windowmanager/widgets/WM_widget_types.h
index 40ce762..75f5cf1 100644
--- a/source/blender/windowmanager/widgets/WM_widget_types.h
+++ b/source/blender/windowmanager/widgets/WM_widget_types.h
@@ -126,10 +126,11 @@ enum eWidgetFlag {
 	/* settings */
 	WM_WIDGET_DRAW_HOVER  = (1 << 3),
 	WM_WIDGET_DRAW_ACTIVE = (1 << 4), /* draw while dragging */
-	WM_WIDGET_SCALE_3D    = (1 << 5),
-	WM_WIDGET_SCENE_DEPTH = (1 << 6), /* widget is depth culled with scene objects*/
-	WM_WIDGET_HIDDEN      = (1 << 7),
-	WM_WIDGET_SELECTABLE  = (1 << 8),
+	WM_WIDGET_DRAW_VALUE  = (1 << 5), /* draw a indicator for the current value while dragging */
+	WM_WIDGET_SCALE_3D    = (1 << 6),
+	WM_WIDGET_SCENE_DEPTH = (1 << 7), /* widget is depth culled with scene objects*/
+	WM_WIDGET_HIDDEN      = (1 << 8),
+	WM_WIDGET_SELECTABLE  = (1 << 9),
 };
 
 /* wmWidgetMapType->flag */
diff --git a/source/blender/windowmanager/widgets/intern/widget_library/dial_widget.c b/source/blender/windowmanager/widgets/intern/widget_library/dial_widget.c
index b2fb114..e6ea331 100644
--- a/source/blender/windowmanager/widgets/intern/widget_library/dial_widget.c
+++ b/source/blender/windowmanager/widgets/intern/widget_library/dial_widget.c
@@ -41,17 +41,22 @@
 #include "BLI_math.h"
 
 #include "ED_screen.h"
+#include "ED_view3d.h"
 
 #include "GPU_select.h"
 
 #include "MEM_guardedalloc.h"
 
+#include "WM_api.h"
+#include "WM_types.h"
+
 /* own includes */
 #include "WM_widget_types.h"
 #include "WM_widget_library.h"
 #include "wm_widget_wmapi.h"
 #include "wm_widget_intern.h"
 #include "widget_geometry.h"
+#include "widget_library_intern.h"
 
 
 /* to use custom dials exported to dial_widget.c */
@@ -67,53 +72,155 @@ typedef struct DialWidget {
 	float direction[3];
 } DialWidget;
 
+typedef struct DialInteraction {
+	float init_mval[2];
+
+	/* cache the last angle to detect rotations bigger than -/+ PI */
+	float last_angle;
+	/* number of full rotations */
+	int rotations;
+} DialInteraction;
+
+#define DIAL_WIDTH       1.0f
+#define DIAL_RESOLUTION 32
+
 
 /* -------------------------------------------------------------------- */
 
-static void dial_draw_geom(const DialWidget *dial, const bool select)
+static void dial_geom_draw(const DialWidget *dial, const float col[4], const bool select)
 {
 #ifdef WIDGET_USE_CUSTOM_DIAS
 	widget_draw_intern(&dial_draw_info, select);
 #else
-	const float width = 1.0f;
-	const int resol = 32;
 	const bool filled = (dial->style == WIDGET_DIAL_STYLE_RING_FILLED);
 
 	glLineWidth(dial->widget.line_width);
+	glColor4fv(col);
 
 	GLUquadricObj *qobj = gluNewQuadric();
 	gluQuadricDrawStyle(qobj, filled ? GLU_FILL : GLU_SILHOUETTE);
 	/* inner at 0.0 with silhouette drawing confuses OGL selection, so draw it at width */
-	gluDisk(qobj, filled ? 0.0 : width, width, resol, 1);
+	gluDisk(qobj, filled ? 0.0 : DIAL_WIDTH, DIAL_WIDTH, DIAL_RESOLUTION, 1);
 	gluDeleteQuadric(qobj);
 
-	glLineWidth(1.0);
-
 	UNUSED_VARS(select);
 #endif
 }
 
-static void dial_draw_intern(DialWidget *dial, const bool select, const bool highlight, const float scale)
+/**
+ * Draws a line from (0, 0, 0) to \a co_outer, at \a angle.
+ */
+static void dial_ghostarc_draw_helpline(const float angle, const float co_outer[3])
+{
+	glLineWidth(1.0f);
+
+	glPushMatrix();
+	glRotatef(RAD2DEGF(angle), 0.0f, 0.0f, -1.0f);
+//	glScalef(0.0f, DIAL_WIDTH - dial->widget.line_width * 0.5f / U.widget_scale, 0.0f);
+	glBegin(GL_LINE_STRIP);
+	glVertex3f(0.0f, 0.0f, 0.0f);
+	glVertex3fv(co_outer);
+	glEnd();
+	glPopMatrix();
+}
+
+static void dial_ghostarc_draw(const DialWidget *dial, const float ofs_angle, const float angle)
+{
+	GLUquadricObj *qobj = gluNewQuadric();
+	const float width_inner = DIAL_WIDTH - dial->widget.line_width * 0.5f / U.widget_scale;
+
+	gluQuadricDrawStyle(qobj, GLU_FILL);
+	gluPartialDisk(qobj, 0.0, width_inner, DIAL_RESOLUTION, 1, RAD2DEGF(ofs_angle), RAD2DEGF(angle));
+	gluDeleteQuadric(qobj);
+}
+
+static void dial_ghostarc_get_angles(
+        const DialWidget *dial, const wmEvent *event, const ARegion *ar,
+        float mat[4][4], const float co_outer[3],
+        float *r_start, float *r_angle)
+{
+	DialInteraction *inter = dial->widget.interaction_data;
+	const RegionView3D *rv3d = ar->regiondata;
+	const float mval[2] = {event->x - ar->winrct.xmin, event->y - ar->winrct.ymin};
+	bool inv = false;
+
+	/* we might need to invert the direction of the angles */
+	float view_vec[3], axis_vec[3];
+	ED_view3d_global_to_vector(rv3d, rv3d->twmat[3], view_vec);
+	normalize_v3_v3(axis_vec, dial->direction);
+	if (dot_v3v3(view_vec, axis_vec) < 0.0f) {
+		inv = true;
+	}
+
+	float co[3], origin2d[2], co2d[2];
+	mul_v3_project_m4_v3(co, mat, co_outer);
+	/* project 3d coordinats to 2d viewplane */
+	ED_view3d_project_float_global(ar, dial->widget.origin, origin2d, V3D_PROJ_TEST_NOP);
+	ED_view3d_project_float_global(ar, co, co2d, V3D_PROJ_TEST_NOP);
+
+	/* convert to widget relative space */
+	float rel_initmval[2], rel_mval[2], rel_co[2];
+	sub_v2_v2v2(rel_initmval, inter->init_mval, origin2d);
+	sub_v2_v2v2(rel_mval, mval, origin2d);
+	sub_v2_v2v2(rel_co, co2d, origin2d);
+
+	/* return angles */
+	const float start = angle_signed_v2v2(rel_co, rel_initmval) * (inv ? -1 : 1);
+	const float angle = angle_signed_v2v2(rel_initmval, rel_mval) * (inv ? -1 : 1);
+
+	/* Change of sign, we passed the 180 degree threshold. This means we need to add a turn
+	 * to distinguish between transition from 0 to -1 and -PI to +PI, use comparison with PI/2.
+	 * Logic taken from BLI_dial_angle */
+	if ((angle * inter->last_angle < 0.0f) &&
+	    (fabsf(inter->last_angle) > (float)M_PI_2))
+	{
+		if (inter->last_angle < 0.0f)
+			inter->rotations--;
+		else
+			inter->rotations++;
+	}
+	inter->last_angle = angle;
+
+	*r_start = start;
+	*r_angle = fmod(angle + 2.0f * (float)M_PI * inter->rotations, 2 * (float)M_PI);
+}
+
+static void dial_draw_intern(const bContext *C, DialWidget *dial, const bool select, const bool highlight)
 {
 	float rot[3][3];
 	float mat[4][4];
 	const float up[3] = {0.0f, 0.0f, 1.0f};
+	const float *col = widget_color_get(&dial->widget, highlight);
+
+	BLI_assert(CTX_wm_area(C)->spacetype == SPACE_VIEW3D);
 
 	rotation_between_vecs_to_mat3(rot, up, dial->direction);
 	copy_m4_m3(mat, rot);
 	copy_v3_v3(mat[3], dial->widget.origin);
-	mul_mat3_m4_fl(mat, scale);
+	mul_mat3_m4_fl(mat, dial->widget.scale);
 
 	glPushMatrix();
 	glMultMatrixf(mat);
+	glTranslate3fv(dial->widget.offset);
 
-	if (highlight)
-		glColor4fv(dial->widget.col_hi);
-	else
-		glColor4fv(dial->widget.col);
+	/* draw rotation indicator arc first */
+	if ((dial->widget.flag & WM_WIDGET_DRAW_VALUE) && (dial->widget.flag & WM_WIDGET_ACTIVE)) {
+		wmWindow *win = CTX_wm_window(C);
+		const float co_outer[4] = {0.0f, DIAL_WIDTH, 0.0f}; /* coordinate at which the arc drawing will be started */
+		float angle_ofs, angle;
 
-	glTranslate3fv(dial->widget.offset);
-	dial_draw_geom(dial, select);
+		dial_ghostarc_get_angles(dial, win->eventstate, CTX_wm_region(C), mat, co_outer, &angle_ofs, &angle);
+		/* draw! */
+		glColor4f(0.8f, 0.8f, 0.8f, 0.4f);
+		dial_ghostarc_draw(dial, angle_ofs, angle);
+
+		glColor4fv(col);
+		dial_ghostarc_draw_helpline(angle_ofs, co_outer); /* starting position */
+		dial_ghostarc_draw_helpline(angle_ofs + angle, co_outer); /* starting position + current value */
+	}
+
+	/* draw actual dial widget */
+	dial_geom_draw(dial, col, select);
 
 	glPopMatrix();
 
@@ -136,7 +243,7 @@ static void widget_dial_render_3d_intersect(const bContext *C, wmWidget *widget,
 	}
 
 	GPU_select_load_id(selectionbase);
-	dial_draw_intern(dial, true, false, dial->widget.scale);
+	dial_draw_intern(C, dial, true, false);
 
 	if (dial->style == WIDGET_DIAL_STYLE_RING_CLIPPED) {
 		glDisable(GL_CLIP_PLANE0);
@@ -146,9 +253,10 @@ static void widget_dial_render_3d_intersect(const bContext *C, wmWidget *widget,
 static void widget_dial_draw(const bContext *C, wmWidget *widget)
 {
 	DialWidget *dial = (DialWidget *)widget;
+	const bool active = widget->flag & WM_WIDGET_ACTIVE;
 
 	/* enable clipping if needed */
-	if (dial->style == WIDGET_DIAL_STYLE_RING_CLIPPED) {
+	if (!active && dial->style == WIDGET_DIAL_STYLE_RING_CLIPPED) {
 		double plane[4];
 		ARegion *ar = CTX_wm_region(C);
 		RegionView3D *rv3d = ar->regiondata;
@@ -160,14 +268,26 @@ static void widget_dial_draw(const bContext *C, wmWidget *widget)
 	}
 
 	glEnable(GL_BLEND);
-	dial_draw_intern(dial, false, (widget->flag & WM_WIDGET_HIGHLIGHT) != 0, widget->scale);
+	dial_draw_intern(C, dial, false, (widget->flag & WM_WIDGET_HIGHLIGHT) != 0);
 	glDisable(GL_BLEND);
 
-	if (dial->style == WIDGET_DIAL_STYLE_RING_CLIPPED) {
+	if (!active && dial->style == WIDGET_DIAL_STYLE_RING_CLIPPED) {
 		glDisable(GL_CLIP_PLANE0);
 	}
 }
 
+static int widget_dial_invoke(bContext *UNUSED(C), const wmEvent *event, wmWidget *widget)
+{
+	DialInteraction *inter = MEM_callocN(sizeof(DialInteraction), __func__);
+
+	inter->init_mval[0] = event->mval[0];
+	inter->init_mval[1] = event->

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list