Esempio n. 1
0
/* helper call for drawing influence/time control curves for a given NLA-strip */
static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc)
{
	const float yheight = ymaxc - yminc;
	
	/* drawing color is simply a light-gray */
	// TODO: is this color suitable?
	// XXX nasty hacked color for now... which looks quite bad too...
	glColor3f(0.7f, 0.7f, 0.7f);
	
	/* draw with AA'd line */
	glEnable(GL_LINE_SMOOTH);
	glEnable(GL_BLEND);
	
	/* influence -------------------------- */
	if (strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) {
		FCurve *fcu = list_find_fcurve(&strip->fcurves, "influence", 0);
		float cfra;
		
		/* plot the curve (over the strip's main region) */
		glBegin(GL_LINE_STRIP);
		/* sample at 1 frame intervals, and draw
		 *	- min y-val is yminc, max is y-maxc, so clamp in those regions
		 */
		for (cfra = strip->start; cfra <= strip->end; cfra += 1.0f) {
			float y = evaluate_fcurve(fcu, cfra);
			CLAMP(y, 0.0f, 1.0f);
			glVertex2f(cfra, ((y * yheight) + yminc));
		}
		glEnd(); // GL_LINE_STRIP
	}
	else {
		/* use blend in/out values only if both aren't zero */
		if ((IS_EQF(strip->blendin, 0.0f) && IS_EQF(strip->blendout, 0.0f)) == 0) {
			glBegin(GL_LINE_STRIP);
			/* start of strip - if no blendin, start straight at 1, otherwise from 0 to 1 over blendin frames */
			if (IS_EQF(strip->blendin, 0.0f) == 0) {
				glVertex2f(strip->start,                    yminc);
				glVertex2f(strip->start + strip->blendin,   ymaxc);
			}
			else
				glVertex2f(strip->start, ymaxc);
					
			/* end of strip */
			if (IS_EQF(strip->blendout, 0.0f) == 0) {
				glVertex2f(strip->end - strip->blendout,    ymaxc);
				glVertex2f(strip->end,                      yminc);
			}
			else
				glVertex2f(strip->end, ymaxc);
			glEnd(); // GL_LINE_STRIP
		}
	}
	
	/* time -------------------------- */
	// XXX do we want to draw this curve? in a different color too?
	
	/* turn off AA'd lines */
	glDisable(GL_LINE_SMOOTH);
	glDisable(GL_BLEND);
}
static void gp_stroke_norm_curve_weights(Curve *cu, const float minmax_weights[2])
{
	Nurb *nu;
	const float delta = minmax_weights[0];
	float fac;
	int i;
	
	/* when delta == minmax_weights[0] == minmax_weights[1], we get div by zero [#35686] */
	if (IS_EQF(delta, minmax_weights[1]))
		fac = 1.0f;
	else
		fac = 1.0f / (minmax_weights[1] - delta);
	
	for (nu = cu->nurb.first; nu; nu = nu->next) {
		if (nu->bezt) {
			BezTriple *bezt = nu->bezt;
			for (i = 0; i < nu->pntsu; i++, bezt++) {
				bezt->weight = (bezt->weight - delta) * fac;
			}
		}
		else if (nu->bp) {
			BPoint *bp = nu->bp;
			for (i = 0; i < nu->pntsu; i++, bp++) {
				bp->weight = (bp->weight - delta) * fac;
			}
		}
	}
}
Esempio n. 3
0
static int poselib_remove_exec(bContext *C, wmOperator *op)
{
	Object *ob = get_poselib_object(C);
	bAction *act = (ob) ? ob->poselib : NULL;
	TimeMarker *marker;
	int marker_index;
	FCurve *fcu;
	PropertyRNA *prop;

	/* check if valid poselib */
	if (act == NULL) {
		BKE_report(op->reports, RPT_ERROR, "Object does not have pose lib data");
		return OPERATOR_CANCELLED;
	}

	prop = RNA_struct_find_property(op->ptr, "pose");
	if (RNA_property_is_set(op->ptr, prop)) {
		marker_index = RNA_property_enum_get(op->ptr, prop);
	}
	else {
		marker_index = act->active_marker - 1;
	}

	/* get index (and pointer) of pose to remove */
	marker = BLI_findlink(&act->markers, marker_index);
	if (marker == NULL) {
		BKE_reportf(op->reports, RPT_ERROR, "Invalid pose specified %d", marker_index);
		return OPERATOR_CANCELLED;
	}
	
	/* remove relevant keyframes */
	for (fcu = act->curves.first; fcu; fcu = fcu->next) {
		BezTriple *bezt;
		unsigned int i;
		
		if (fcu->bezt) {
			for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
				/* check if remove */
				if (IS_EQF(bezt->vec[1][0], (float)marker->frame)) {
					delete_fcurve_key(fcu, i, 1);
					break;
				}
			}
		}
	}
	
	/* remove poselib from list */
	BLI_freelinkN(&act->markers, marker);
	
	/* fix active pose number */
	act->active_marker = 0;
	
	/* send notifiers for this - using keyframe editing notifiers, since action 
	 * may be being shown in anim editors as active action 
	 */
	WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
	
	/* done */
	return OPERATOR_FINISHED;
}
Esempio n. 4
0
static void rna_NlaStrip_end_frame_set(PointerRNA *ptr, float value)
{
	NlaStrip *data = (NlaStrip *)ptr->data;
	
	/* clamp value to lie within valid limits
	 *	- must not have zero or negative length strip, so cannot start before the first frame
	 *	  + some minimum-strip-length threshold
	 *	- cannot end later than the start of the next strip (if present)
	 *		-> but if it was a transition, we could go up to the start of the end - some flexibility threshold
	 *		as long as we re-adjust the transition afterwards
	 */
	if (data->next) {
		if (data->next->type == NLASTRIP_TYPE_TRANSITION) {
			CLAMP(value, data->start + NLASTRIP_MIN_LEN_THRESH, data->next->end - NLASTRIP_MIN_LEN_THRESH);
			
			/* readjust the transition to stick to the endpoints of the action-clips */
			data->next->start = value;
		}
		else {
			CLAMP(value, data->start + NLASTRIP_MIN_LEN_THRESH, data->next->start);
		}
	}
	else {
		CLAMP(value, data->start + NLASTRIP_MIN_LEN_THRESH, MAXFRAME);
	}
	data->end = value;
	
	
	/* calculate the lengths the strip and its action (if applicable) */
	if (data->type == NLASTRIP_TYPE_CLIP) {
		float len, actlen;
		
		len = data->end - data->start;
		actlen = data->actend - data->actstart;
		if (IS_EQF(actlen, 0.0f)) actlen = 1.0f;
		
		/* now, adjust the 'scale' setting to reflect this (so that this change can be valid) */
		data->scale = len / ((actlen) * data->repeat);
	}
}
Esempio n. 5
0
/* main call for drawing a single NLA-strip */
static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStrip *strip, View2D *v2d, float yminc, float ymaxc)
{
	short nonSolo = ((adt && (adt->flag & ADT_NLA_SOLO_TRACK)) && (nlt->flag & NLATRACK_SOLO) == 0);
	float color[3];
	
	/* get color of strip */
	nla_strip_get_color_inside(adt, strip, color);
	
	/* draw extrapolation info first (as backdrop)
	 *	- but this should only be drawn if track has some contribution
	 */
	if ((strip->extendmode != NLASTRIP_EXTEND_NOTHING) && (nonSolo == 0)) {
		/* enable transparency... */
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glEnable(GL_BLEND);
		
		switch (strip->extendmode) {
			/* since this does both sides, only do the 'before' side, and leave the rest to the next case */
			case NLASTRIP_EXTEND_HOLD: 
				/* only need to draw here if there's no strip before since 
				 * it only applies in such a situation 
				 */
				if (strip->prev == NULL) {
					/* set the drawing color to the color of the strip, but with very faint alpha */
					glColor4f(color[0], color[1], color[2], 0.15f);
					
					/* draw the rect to the edge of the screen */
					glBegin(GL_QUADS);
					glVertex2f(v2d->cur.xmin, yminc);
					glVertex2f(v2d->cur.xmin, ymaxc);
					glVertex2f(strip->start, ymaxc);
					glVertex2f(strip->start, yminc);
					glEnd();
				}
				/* fall-through */

			/* this only draws after the strip */
			case NLASTRIP_EXTEND_HOLD_FORWARD: 
				/* only need to try and draw if the next strip doesn't occur immediately after */
				if ((strip->next == NULL) || (IS_EQF(strip->next->start, strip->end) == 0)) {
					/* set the drawing color to the color of the strip, but this time less faint */
					glColor4f(color[0], color[1], color[2], 0.3f);
					
					/* draw the rect to the next strip or the edge of the screen */
					glBegin(GL_QUADS);
					glVertex2f(strip->end, yminc);
					glVertex2f(strip->end, ymaxc);
						
					if (strip->next) {
						glVertex2f(strip->next->start, ymaxc);
						glVertex2f(strip->next->start, yminc);
					}
					else {
						glVertex2f(v2d->cur.xmax, ymaxc);
						glVertex2f(v2d->cur.xmax, yminc);
					}
					glEnd();
				}
				break;
		}
		
		glDisable(GL_BLEND);
	}
	
	
	/* draw 'inside' of strip itself */
	if (nonSolo == 0) {
		/* strip is in normal track */
		glColor3fv(color);
		UI_draw_roundbox_corner_set(UI_CNR_ALL); /* all corners rounded */
		
		UI_draw_roundbox_shade_x(GL_POLYGON, strip->start, yminc, strip->end, ymaxc, 0.0, 0.5, 0.1);
	}
	else {
		/* strip is in disabled track - make less visible */
		glColor4f(color[0], color[1], color[2], 0.1f);
		
		glEnable(GL_BLEND);
		glRectf(strip->start, yminc, strip->end, ymaxc);
		glDisable(GL_BLEND);
	}
	
	
	/* draw strip's control 'curves'
	 *	- only if user hasn't hidden them...
	 */
	if ((snla->flag & SNLA_NOSTRIPCURVES) == 0)
		nla_draw_strip_curves(strip, yminc, ymaxc);
	
	
	/* draw strip outline 
	 *	- color used here is to indicate active vs non-active
	 */
	if (strip->flag & NLASTRIP_FLAG_ACTIVE) {
		/* strip should appear 'sunken', so draw a light border around it */
		glColor3f(0.9f, 1.0f, 0.9f); // FIXME: hardcoded temp-hack colors
	}
	else {
		/* strip should appear to stand out, so draw a dark border around it */
		glColor3f(0.0f, 0.0f, 0.0f);
	}
	
	/* - line style: dotted for muted */
	if (strip->flag & NLASTRIP_FLAG_MUTED)
		setlinestyle(4);
		
	/* draw outline */
	UI_draw_roundbox_shade_x(GL_LINE_LOOP, strip->start, yminc, strip->end, ymaxc, 0.0, 0.0, 0.1);
	
	/* if action-clip strip, draw lines delimiting repeats too (in the same color as outline) */
	if ((strip->type == NLASTRIP_TYPE_CLIP) && IS_EQF(strip->repeat, 1.0f) == 0) {
		float repeatLen = (strip->actend - strip->actstart) * strip->scale;
		int i;
		
		/* only draw lines for whole-numbered repeats, starting from the first full-repeat
		 * up to the last full repeat (but not if it lies on the end of the strip)
		 */
		for (i = 1; i < strip->repeat; i++) {
			float repeatPos = strip->start + (repeatLen * i);
			
			/* don't draw if line would end up on or after the end of the strip */
			if (repeatPos < strip->end)
				fdrawline(repeatPos, yminc + 4, repeatPos, ymaxc - 4);
		}
	}
	/* or if meta-strip, draw lines delimiting extents of sub-strips (in same color as outline, if more than 1 exists) */
	else if ((strip->type == NLASTRIP_TYPE_META) && (strip->strips.first != strip->strips.last)) {
		NlaStrip *cs;
		float y = (ymaxc - yminc) / 2.0f + yminc;
		
		/* only draw first-level of child-strips, but don't draw any lines on the endpoints */
		for (cs = strip->strips.first; cs; cs = cs->next) {
			/* draw start-line if not same as end of previous (and only if not the first strip) 
			 *	- on upper half of strip
			 */
			if ((cs->prev) && IS_EQF(cs->prev->end, cs->start) == 0)
				fdrawline(cs->start, y, cs->start, ymaxc);
				
			/* draw end-line if not the last strip
			 *	- on lower half of strip
			 */
			if (cs->next) 
				fdrawline(cs->end, yminc, cs->end, y);
		}
	}
	
	/* reset linestyle */
	setlinestyle(0);
} 
Esempio n. 6
0
static void add_bezt_to_keyblocks_list(DLRBT_Tree *blocks, BezTriple *first_bezt, BezTriple *beztn)
{
	ActKeyBlock *new_ab = NULL;
	BezTriple *prev = NULL;
	
	/* get the BezTriple immediately before the given one which has the same value */
	if (beztn != first_bezt) {
		/* XXX: Unless I'm overlooking some details from the past, this should be sufficient? 
		 *      The old code did some elaborate stuff trying to find keyframe columns for
		 *      the given BezTriple, then step backwards to the column before that, and find
		 *      an appropriate BezTriple with matching values there. Maybe that was warranted
		 *      in the past, but now, that list is only ever filled with keyframes from the 
		 *      current FCurve.
		 *
		 *      -- Aligorith (20140415)
		 */
		prev = beztn - 1;
	}
	
	
	/* check if block needed - same value(s)?
	 *	-> firstly, handles must have same central value as each other
	 *	-> secondly, handles which control that section of the curve must be constant
	 */
	if (prev == NULL) return;
	if (IS_EQF(beztn->vec[1][1], prev->vec[1][1]) == 0) return;
	
	if (IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) == 0) return;
	if (IS_EQF(prev->vec[1][1], prev->vec[2][1]) == 0) return;
	
	
	/* if there are no blocks already, just add as root */
	if (blocks->root == NULL) {
		/* just add this as the root, then call the tree-balancing functions to validate */
		new_ab = bezts_to_new_actkeyblock(prev, beztn);
		blocks->root = (DLRBT_Node *)new_ab;
	}
	else {
		ActKeyBlock *ab, *abn = NULL;
		
		/* try to find a keyblock that starts on the previous beztriple, and add a new one if none start there
		 * Note: we perform a tree traversal here NOT a standard linked-list traversal...
		 * Note: we can't search from end to try to optimize this as it causes errors there's
		 *      an A ___ B |---| B situation
		 */
		// FIXME: here there is a bug where we are trying to get the summary for the following channels
		//		A|--------------|A ______________ B|--------------|B
		//		A|------------------------------------------------|A
		//		A|----|A|---|A|-----------------------------------|A
		for (ab = blocks->root; ab; ab = abn) {
			/* check if this is a match, or whether we go left or right 
			 * NOTE: we now use a float threshold to prevent precision errors causing problems with summaries
			 */
			if (IS_EQT(ab->start, prev->vec[1][0], BEZT_BINARYSEARCH_THRESH)) {
				/* set selection status and 'touched' status */
				if (BEZSELECTED(beztn)) ab->sel = SELECT;
				ab->modified++;
				
				/* done... no need to insert */
				return;
			}
			else {
				ActKeyBlock **abnp = NULL; /* branch to go down - used to hook new blocks to parents */
				
				/* check if go left or right, but if not available, add new node */
				if (ab->start < prev->vec[1][0]) 
					abnp = &ab->right;
				else
					abnp = &ab->left;
					
				/* if this does not exist, add a new node, otherwise continue... */
				if (*abnp == NULL) {
					/* add a new node representing this, and attach it to the relevant place */
					new_ab = bezts_to_new_actkeyblock(prev, beztn);
					new_ab->parent = ab;
					*abnp = new_ab;
					break;
				}
				else
					abn = *abnp;
			}
		}
	}
	
	/* now, balance the tree taking into account this newly added node */
	BLI_dlrbTree_insert(blocks, (DLRBT_Node *)new_ab);
}
Esempio n. 7
0
/* clear rotation of object */
static void object_clear_rot(Object *ob)
{
	/* clear rotations that aren't locked */
	if (ob->protectflag & (OB_LOCK_ROTX|OB_LOCK_ROTY|OB_LOCK_ROTZ|OB_LOCK_ROTW)) {
		if (ob->protectflag & OB_LOCK_ROT4D) {
			/* perform clamping on a component by component basis */
			if (ob->rotmode == ROT_MODE_AXISANGLE) {
				if ((ob->protectflag & OB_LOCK_ROTW) == 0)
					ob->rotAngle= ob->drotAngle= 0.0f;
				if ((ob->protectflag & OB_LOCK_ROTX) == 0)
					ob->rotAxis[0]= ob->drotAxis[0]= 0.0f;
				if ((ob->protectflag & OB_LOCK_ROTY) == 0)
					ob->rotAxis[1]= ob->drotAxis[1]= 0.0f;
				if ((ob->protectflag & OB_LOCK_ROTZ) == 0)
					ob->rotAxis[2]= ob->drotAxis[2]= 0.0f;
					
				/* check validity of axis - axis should never be 0,0,0 (if so, then we make it rotate about y) */
				if (IS_EQF(ob->rotAxis[0], ob->rotAxis[1]) && IS_EQF(ob->rotAxis[1], ob->rotAxis[2]))
					ob->rotAxis[1] = 1.0f;
				if (IS_EQF(ob->drotAxis[0], ob->drotAxis[1]) && IS_EQF(ob->drotAxis[1], ob->drotAxis[2]))
					ob->drotAxis[1]= 1.0f;
			}
			else if (ob->rotmode == ROT_MODE_QUAT) {
				if ((ob->protectflag & OB_LOCK_ROTW) == 0)
					ob->quat[0]= ob->dquat[0]= 1.0f;
				if ((ob->protectflag & OB_LOCK_ROTX) == 0)
					ob->quat[1]= ob->dquat[1]= 0.0f;
				if ((ob->protectflag & OB_LOCK_ROTY) == 0)
					ob->quat[2]= ob->dquat[2]= 0.0f;
				if ((ob->protectflag & OB_LOCK_ROTZ) == 0)
					ob->quat[3]= ob->dquat[3]= 0.0f;
					
				// TODO: does this quat need normalising now?
			}
			else {
				/* the flag may have been set for the other modes, so just ignore the extra flag... */
				if ((ob->protectflag & OB_LOCK_ROTX) == 0)
					ob->rot[0]= ob->drot[0]= 0.0f;
				if ((ob->protectflag & OB_LOCK_ROTY) == 0)
					ob->rot[1]= ob->drot[1]= 0.0f;
				if ((ob->protectflag & OB_LOCK_ROTZ) == 0)
					ob->rot[2]= ob->drot[2]= 0.0f;
			}
		}
		else {
			/* perform clamping using euler form (3-components) */
			// FIXME: deltas are not handled for these cases yet...
			float eul[3], oldeul[3], quat1[4] = {0};
			
			if (ob->rotmode == ROT_MODE_QUAT) {
				copy_qt_qt(quat1, ob->quat);
				quat_to_eul(oldeul, ob->quat);
			}
			else if (ob->rotmode == ROT_MODE_AXISANGLE) {
				axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, ob->rotAxis, ob->rotAngle);
			}
			else {
				copy_v3_v3(oldeul, ob->rot);
			}
			
			eul[0]= eul[1]= eul[2]= 0.0f;
			
			if (ob->protectflag & OB_LOCK_ROTX)
				eul[0]= oldeul[0];
			if (ob->protectflag & OB_LOCK_ROTY)
				eul[1]= oldeul[1];
			if (ob->protectflag & OB_LOCK_ROTZ)
				eul[2]= oldeul[2];
			
			if (ob->rotmode == ROT_MODE_QUAT) {
				eul_to_quat(ob->quat, eul);
				/* quaternions flip w sign to accumulate rotations correctly */
				if ((quat1[0]<0.0f && ob->quat[0]>0.0f) || (quat1[0]>0.0f && ob->quat[0]<0.0f)) {
					mul_qt_fl(ob->quat, -1.0f);
				}
			}
			else if (ob->rotmode == ROT_MODE_AXISANGLE) {
				eulO_to_axis_angle(ob->rotAxis, &ob->rotAngle,eul, EULER_ORDER_DEFAULT);
			}
			else {
				copy_v3_v3(ob->rot, eul);
			}
		}
	}						 // Duplicated in source/blender/editors/armature/editarmature.c
	else { 
		if (ob->rotmode == ROT_MODE_QUAT) {
			unit_qt(ob->quat);
			unit_qt(ob->dquat);
		}
		else if (ob->rotmode == ROT_MODE_AXISANGLE) {
			unit_axis_angle(ob->rotAxis, &ob->rotAngle);
			unit_axis_angle(ob->drotAxis, &ob->drotAngle);
		}
		else {
			zero_v3(ob->rot);
			zero_v3(ob->drot);
		}
	}
}
Esempio n. 8
0
/* draw a given stroke in 2d */
static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag,
                              bool debug, int offsx, int offsy, int winx, int winy)
{
	/* otherwise thickness is twice that of the 3D view */
	float thickness = (float)thickness_s * 0.5f;
	
	/* strokes in Image Editor need a scale factor, since units there are not pixels! */
	float scalefac  = 1.0f;
	if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) {
		scalefac = 0.001f;
	}
	
	/* tessellation code - draw stroke as series of connected quads with connection
	 * edges rotated to minimize shrinking artifacts, and rounded endcaps
	 */
	{
		bGPDspoint *pt1, *pt2;
		float pm[2];
		int i;
		
		glShadeModel(GL_FLAT);
		glBegin(GL_QUADS);
		
		for (i = 0, pt1 = points, pt2 = points + 1; i < (totpoints - 1); i++, pt1++, pt2++) {
			float s0[2], s1[2];     /* segment 'center' points */
			float t0[2], t1[2];     /* tessellated coordinates */
			float m1[2], m2[2];     /* gradient and normal */
			float mt[2], sc[2];     /* gradient for thickness, point for end-cap */
			float pthick;           /* thickness at segment point */
			
			/* get x and y coordinates from points */
			gp_calc_2d_stroke_xy(pt1, sflag, offsx, offsy, winx, winy, s0);
			gp_calc_2d_stroke_xy(pt2, sflag, offsx, offsy, winx, winy, s1);
			
			/* calculate gradient and normal - 'angle'=(ny/nx) */
			m1[1] = s1[1] - s0[1];
			m1[0] = s1[0] - s0[0];
			normalize_v2(m1);
			m2[1] = -m1[0];
			m2[0] = m1[1];
			
			/* always use pressure from first point here */
			pthick = (pt1->pressure * thickness * scalefac);
			
			/* if the first segment, start of segment is segment's normal */
			if (i == 0) {
				/* draw start cap first
				 *	- make points slightly closer to center (about halfway across)
				 */
				mt[0] = m2[0] * pthick * 0.5f;
				mt[1] = m2[1] * pthick * 0.5f;
				sc[0] = s0[0] - (m1[0] * pthick * 0.75f);
				sc[1] = s0[1] - (m1[1] * pthick * 0.75f);
				
				t0[0] = sc[0] - mt[0];
				t0[1] = sc[1] - mt[1];
				t1[0] = sc[0] + mt[0];
				t1[1] = sc[1] + mt[1];
				
				glVertex2fv(t0);
				glVertex2fv(t1);
				
				/* calculate points for start of segment */
				mt[0] = m2[0] * pthick;
				mt[1] = m2[1] * pthick;
				
				t0[0] = s0[0] - mt[0];
				t0[1] = s0[1] - mt[1];
				t1[0] = s0[0] + mt[0];
				t1[1] = s0[1] + mt[1];
				
				/* draw this line twice (first to finish off start cap, then for stroke) */
				glVertex2fv(t1);
				glVertex2fv(t0);
				glVertex2fv(t0);
				glVertex2fv(t1);
			}
			/* if not the first segment, use bisector of angle between segments */
			else {
				float mb[2];         /* bisector normal */
				float athick, dfac;  /* actual thickness, difference between thicknesses */
				
				/* calculate gradient of bisector (as average of normals) */
				mb[0] = (pm[0] + m2[0]) / 2;
				mb[1] = (pm[1] + m2[1]) / 2;
				normalize_v2(mb);
				
				/* calculate gradient to apply
				 *  - as basis, use just pthick * bisector gradient
				 *	- if cross-section not as thick as it should be, add extra padding to fix it
				 */
				mt[0] = mb[0] * pthick;
				mt[1] = mb[1] * pthick;
				athick = len_v2(mt);
				dfac = pthick - (athick * 2);
				
				if (((athick * 2.0f) < pthick) && (IS_EQF(athick, pthick) == 0)) {
					mt[0] += (mb[0] * dfac);
					mt[1] += (mb[1] * dfac);
				}
				
				/* calculate points for start of segment */
				t0[0] = s0[0] - mt[0];
				t0[1] = s0[1] - mt[1];
				t1[0] = s0[0] + mt[0];
				t1[1] = s0[1] + mt[1];
				
				/* draw this line twice (once for end of current segment, and once for start of next) */
				glVertex2fv(t1);
				glVertex2fv(t0);
				glVertex2fv(t0);
				glVertex2fv(t1);
			}
			
			/* if last segment, also draw end of segment (defined as segment's normal) */
			if (i == totpoints - 2) {
				/* for once, we use second point's pressure (otherwise it won't be drawn) */
				pthick = (pt2->pressure * thickness * scalefac);
				
				/* calculate points for end of segment */
				mt[0] = m2[0] * pthick;
				mt[1] = m2[1] * pthick;
				
				t0[0] = s1[0] - mt[0];
				t0[1] = s1[1] - mt[1];
				t1[0] = s1[0] + mt[0];
				t1[1] = s1[1] + mt[1];
				
				/* draw this line twice (once for end of stroke, and once for endcap)*/
				glVertex2fv(t1);
				glVertex2fv(t0);
				glVertex2fv(t0);
				glVertex2fv(t1);
				
				
				/* draw end cap as last step
				 *	- make points slightly closer to center (about halfway across)
				 */
				mt[0] = m2[0] * pthick * 0.5f;
				mt[1] = m2[1] * pthick * 0.5f;
				sc[0] = s1[0] + (m1[0] * pthick * 0.75f);
				sc[1] = s1[1] + (m1[1] * pthick * 0.75f);
				
				t0[0] = sc[0] - mt[0];
				t0[1] = sc[1] - mt[1];
				t1[0] = sc[0] + mt[0];
				t1[1] = sc[1] + mt[1];
				
				glVertex2fv(t1);
				glVertex2fv(t0);
			}
			
			/* store stroke's 'natural' normal for next stroke to use */
			copy_v2_v2(pm, m2);
		}
		
		glEnd();
	}
	
	/* draw debug points of curve on top? (original stroke points) */
	if (debug) {
		bGPDspoint *pt;
		int i;
		
		glPointSize((float)(thickness_s + 2));
		
		glBegin(GL_POINTS);
		for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
			float co[2];
			
			gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co);
			glVertex2fv(co);
		}
		glEnd();
	}
}
Esempio n. 9
0
/* draw a given stroke in 2d */
static void gp_draw_stroke (bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag,
                            short debug, int offsx, int offsy, int winx, int winy)
{
    /* otherwise thickness is twice that of the 3D view */
    float thickness= (float)thickness_s * 0.5f;

    /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, 'smooth' opengl lines look better
     * 	- 'smooth' opengl lines are also required if Image Editor 'image-based' stroke
     */
    if ( (thickness < GP_DRAWTHICKNESS_SPECIAL) ||
            ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) )
    {
        bGPDspoint *pt;
        int i;

        glBegin(GL_LINE_STRIP);
        for (i=0, pt=points; i < totpoints && pt; i++, pt++) {
            if (sflag & GP_STROKE_2DSPACE) {
                glVertex2f(pt->x, pt->y);
            }
            else if (sflag & GP_STROKE_2DIMAGE) {
                const float x= (pt->x * winx) + offsx;
                const float y= (pt->y * winy) + offsy;

                glVertex2f(x, y);
            }
            else {
                const float x= (pt->x / 100 * winx) + offsx;
                const float y= (pt->y / 100 * winy) + offsy;

                glVertex2f(x, y);
            }
        }
        glEnd();
    }

    /* tessellation code - draw stroke as series of connected quads with connection
     * edges rotated to minimise shrinking artifacts, and rounded endcaps
     */
    else {
        bGPDspoint *pt1, *pt2;
        float pm[2];
        int i;

        glShadeModel(GL_FLAT);
        glBegin(GL_QUADS);

        for (i=0, pt1=points, pt2=points+1; i < (totpoints-1); i++, pt1++, pt2++) {
            float s0[2], s1[2];		/* segment 'center' points */
            float t0[2], t1[2];		/* tessellated coordinates */
            float m1[2], m2[2];		/* gradient and normal */
            float mt[2], sc[2];		/* gradient for thickness, point for end-cap */
            float pthick;			/* thickness at segment point */

            /* get x and y coordinates from points */
            if (sflag & GP_STROKE_2DSPACE) {
                s0[0]= pt1->x;
                s0[1]= pt1->y;
                s1[0]= pt2->x;
                s1[1]= pt2->y;
            }
            else if (sflag & GP_STROKE_2DIMAGE) {
                s0[0]= (pt1->x * winx) + offsx;
                s0[1]= (pt1->y * winy) + offsy;
                s1[0]= (pt2->x * winx) + offsx;
                s1[1]= (pt2->y * winy) + offsy;
            }
            else {
                s0[0]= (pt1->x / 100 * winx) + offsx;
                s0[1]= (pt1->y / 100 * winy) + offsy;
                s1[0]= (pt2->x / 100 * winx) + offsx;
                s1[1]= (pt2->y / 100 * winy) + offsy;
            }

            /* calculate gradient and normal - 'angle'=(ny/nx) */
            m1[1]= s1[1] - s0[1];
            m1[0]= s1[0] - s0[0];
            normalize_v2(m1);
            m2[1]= -m1[0];
            m2[0]= m1[1];

            /* always use pressure from first point here */
            pthick= (pt1->pressure * thickness);

            /* if the first segment, start of segment is segment's normal */
            if (i == 0) {
                /* draw start cap first
                 *	- make points slightly closer to center (about halfway across)
                 */
                mt[0]= m2[0] * pthick * 0.5f;
                mt[1]= m2[1] * pthick * 0.5f;
                sc[0]= s0[0] - (m1[0] * pthick * 0.75f);
                sc[1]= s0[1] - (m1[1] * pthick * 0.75f);

                t0[0]= sc[0] - mt[0];
                t0[1]= sc[1] - mt[1];
                t1[0]= sc[0] + mt[0];
                t1[1]= sc[1] + mt[1];

                glVertex2fv(t0);
                glVertex2fv(t1);

                /* calculate points for start of segment */
                mt[0]= m2[0] * pthick;
                mt[1]= m2[1] * pthick;

                t0[0]= s0[0] - mt[0];
                t0[1]= s0[1] - mt[1];
                t1[0]= s0[0] + mt[0];
                t1[1]= s0[1] + mt[1];

                /* draw this line twice (first to finish off start cap, then for stroke) */
                glVertex2fv(t1);
                glVertex2fv(t0);
                glVertex2fv(t0);
                glVertex2fv(t1);
            }
            /* if not the first segment, use bisector of angle between segments */
            else {
                float mb[2]; 		/* bisector normal */
                float athick, dfac;		/* actual thickness, difference between thicknesses */

                /* calculate gradient of bisector (as average of normals) */
                mb[0]= (pm[0] + m2[0]) / 2;
                mb[1]= (pm[1] + m2[1]) / 2;
                normalize_v2(mb);

                /* calculate gradient to apply
                 * 	- as basis, use just pthick * bisector gradient
                 *	- if cross-section not as thick as it should be, add extra padding to fix it
                 */
                mt[0]= mb[0] * pthick;
                mt[1]= mb[1] * pthick;
                athick= len_v2(mt);
                dfac= pthick - (athick * 2);

                if (((athick * 2.0f) < pthick) && (IS_EQF(athick, pthick)==0)) {
                    mt[0] += (mb[0] * dfac);
                    mt[1] += (mb[1] * dfac);
                }

                /* calculate points for start of segment */
                t0[0]= s0[0] - mt[0];
                t0[1]= s0[1] - mt[1];
                t1[0]= s0[0] + mt[0];
                t1[1]= s0[1] + mt[1];

                /* draw this line twice (once for end of current segment, and once for start of next) */
                glVertex2fv(t1);
                glVertex2fv(t0);
                glVertex2fv(t0);
                glVertex2fv(t1);
            }

            /* if last segment, also draw end of segment (defined as segment's normal) */
            if (i == totpoints-2) {
                /* for once, we use second point's pressure (otherwise it won't be drawn) */
                pthick= (pt2->pressure * thickness);

                /* calculate points for end of segment */
                mt[0]= m2[0] * pthick;
                mt[1]= m2[1] * pthick;

                t0[0]= s1[0] - mt[0];
                t0[1]= s1[1] - mt[1];
                t1[0]= s1[0] + mt[0];
                t1[1]= s1[1] + mt[1];

                /* draw this line twice (once for end of stroke, and once for endcap)*/
                glVertex2fv(t1);
                glVertex2fv(t0);
                glVertex2fv(t0);
                glVertex2fv(t1);


                /* draw end cap as last step
                 *	- make points slightly closer to center (about halfway across)
                 */
                mt[0]= m2[0] * pthick * 0.5f;
                mt[1]= m2[1] * pthick * 0.5f;
                sc[0]= s1[0] + (m1[0] * pthick * 0.75f);
                sc[1]= s1[1] + (m1[1] * pthick * 0.75f);

                t0[0]= sc[0] - mt[0];
                t0[1]= sc[1] - mt[1];
                t1[0]= sc[0] + mt[0];
                t1[1]= sc[1] + mt[1];

                glVertex2fv(t1);
                glVertex2fv(t0);
            }

            /* store stroke's 'natural' normal for next stroke to use */
            copy_v2_v2(pm, m2);
        }

        glEnd();
    }

    /* draw debug points of curve on top? (original stroke points) */
    if (debug) {
        bGPDspoint *pt;
        int i;

        glBegin(GL_POINTS);
        for (i=0, pt=points; i < totpoints && pt; i++, pt++) {
            if (sflag & GP_STROKE_2DSPACE) {
                glVertex2fv(&pt->x);
            }
            else if (sflag & GP_STROKE_2DIMAGE) {
                const float x= (float)((pt->x * winx) + offsx);
                const float y= (float)((pt->y * winy) + offsy);

                glVertex2f(x, y);
            }
            else {
                const float x= (float)(pt->x / 100 * winx) + offsx;
                const float y= (float)(pt->y / 100 * winy) + offsy;

                glVertex2f(x, y);
            }
        }
        glEnd();
    }
}
Esempio n. 10
0
/* main call for drawing a single NLA-strip */
static void nla_draw_strip(SpaceNla *snla,
                           AnimData *adt,
                           NlaTrack *nlt,
                           NlaStrip *strip,
                           View2D *v2d,
                           float yminc,
                           float ymaxc)
{
  const bool non_solo = ((adt && (adt->flag & ADT_NLA_SOLO_TRACK)) &&
                         (nlt->flag & NLATRACK_SOLO) == 0);
  const bool muted = ((nlt->flag & NLATRACK_MUTED) || (strip->flag & NLASTRIP_FLAG_MUTED));
  float color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
  uint shdr_pos;

  /* get color of strip */
  nla_strip_get_color_inside(adt, strip, color);

  shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
  immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);

  /* draw extrapolation info first (as backdrop)
   * - but this should only be drawn if track has some contribution
   */
  if ((strip->extendmode != NLASTRIP_EXTEND_NOTHING) && (non_solo == 0)) {
    /* enable transparency... */
    GPU_blend_set_func_separate(
        GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
    GPU_blend(true);

    switch (strip->extendmode) {
      /* since this does both sides,
       * only do the 'before' side, and leave the rest to the next case */
      case NLASTRIP_EXTEND_HOLD:
        /* only need to draw here if there's no strip before since
         * it only applies in such a situation
         */
        if (strip->prev == NULL) {
          /* set the drawing color to the color of the strip, but with very faint alpha */
          immUniformColor3fvAlpha(color, 0.15f);

          /* draw the rect to the edge of the screen */
          immRectf(shdr_pos, v2d->cur.xmin, yminc, strip->start, ymaxc);
        }
        ATTR_FALLTHROUGH;

      /* this only draws after the strip */
      case NLASTRIP_EXTEND_HOLD_FORWARD:
        /* only need to try and draw if the next strip doesn't occur immediately after */
        if ((strip->next == NULL) || (IS_EQF(strip->next->start, strip->end) == 0)) {
          /* set the drawing color to the color of the strip, but this time less faint */
          immUniformColor3fvAlpha(color, 0.3f);

          /* draw the rect to the next strip or the edge of the screen */
          float x2 = strip->next ? strip->next->start : v2d->cur.xmax;
          immRectf(shdr_pos, strip->end, yminc, x2, ymaxc);
        }
        break;
    }

    GPU_blend(false);
  }

  /* draw 'inside' of strip itself */
  if (non_solo == 0) {
    immUnbindProgram();

    /* strip is in normal track */
    UI_draw_roundbox_corner_set(UI_CNR_ALL); /* all corners rounded */
    UI_draw_roundbox_shade_x(true, strip->start, yminc, strip->end, ymaxc, 0.0, 0.5, 0.1, color);

    /* restore current vertex format & program (roundbox trashes it) */
    shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
    immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
  }
  else {
    /* strip is in disabled track - make less visible */
    immUniformColor3fvAlpha(color, 0.1f);

    GPU_blend(true);
    immRectf(shdr_pos, strip->start, yminc, strip->end, ymaxc);
    GPU_blend(false);
  }

  /* draw strip's control 'curves'
   * - only if user hasn't hidden them...
   */
  if ((snla->flag & SNLA_NOSTRIPCURVES) == 0) {
    nla_draw_strip_curves(strip, yminc, ymaxc, shdr_pos);
  }

  immUnbindProgram();

  /* draw markings indicating locations of local markers
   * (useful for lining up different actions) */
  if ((snla->flag & SNLA_NOLOCALMARKERS) == 0) {
    nla_strip_draw_markers(strip, yminc, ymaxc);
  }

  /* draw strip outline
   * - color used here is to indicate active vs non-active
   */
  if (strip->flag & NLASTRIP_FLAG_ACTIVE) {
    /* strip should appear 'sunken', so draw a light border around it */
    color[0] = 0.9f; /* FIXME: hardcoded temp-hack colors */
    color[1] = 1.0f;
    color[2] = 0.9f;
  }
  else {
    /* strip should appear to stand out, so draw a dark border around it */
    color[0] = color[1] = color[2] = 0.0f; /* FIXME: or 1.0f ?? */
  }

  /* draw outline
   * - dashed-line shader is loaded after this block
   */
  if (muted) {
    /* muted - draw dotted, squarish outline (for simplicity) */
    shdr_pos = nla_draw_use_dashed_outlines(color, muted);
    imm_draw_box_wire_2d(shdr_pos, strip->start, yminc, strip->end, ymaxc);
  }
  else {
    /* non-muted - draw solid, rounded outline */
    UI_draw_roundbox_shade_x(false, strip->start, yminc, strip->end, ymaxc, 0.0, 0.0, 0.1, color);

    /* restore current vertex format & program (roundbox trashes it) */
    shdr_pos = nla_draw_use_dashed_outlines(color, muted);
  }

  /* if action-clip strip, draw lines delimiting repeats too (in the same color as outline) */
  if ((strip->type == NLASTRIP_TYPE_CLIP) && strip->repeat > 1.0f) {
    float repeatLen = (strip->actend - strip->actstart) * strip->scale;

    /* only draw lines for whole-numbered repeats, starting from the first full-repeat
     * up to the last full repeat (but not if it lies on the end of the strip)
     */
    immBeginAtMost(GPU_PRIM_LINES, 2 * floorf(strip->repeat));
    for (int i = 1; i < strip->repeat; i++) {
      float repeatPos = strip->start + (repeatLen * i);

      /* don't draw if line would end up on or after the end of the strip */
      if (repeatPos < strip->end) {
        immVertex2f(shdr_pos, repeatPos, yminc + 4);
        immVertex2f(shdr_pos, repeatPos, ymaxc - 4);
      }
    }
    immEnd();
  }
  /* or if meta-strip, draw lines delimiting extents of sub-strips
   * (in same color as outline, if more than 1 exists) */
  else if ((strip->type == NLASTRIP_TYPE_META) && (strip->strips.first != strip->strips.last)) {
    const float y = (ymaxc - yminc) * 0.5f + yminc;

    /* up to 2 lines per strip */
    immBeginAtMost(GPU_PRIM_LINES, 4 * BLI_listbase_count(&strip->strips));

    /* only draw first-level of child-strips, but don't draw any lines on the endpoints */
    for (NlaStrip *cs = strip->strips.first; cs; cs = cs->next) {
      /* draw start-line if not same as end of previous (and only if not the first strip)
       * - on upper half of strip
       */
      if ((cs->prev) && IS_EQF(cs->prev->end, cs->start) == 0) {
        immVertex2f(shdr_pos, cs->start, y);
        immVertex2f(shdr_pos, cs->start, ymaxc);
      }

      /* draw end-line if not the last strip
       * - on lower half of strip
       */
      if (cs->next) {
        immVertex2f(shdr_pos, cs->end, yminc);
        immVertex2f(shdr_pos, cs->end, y);
      }
    }

    immEnd();
  }

  immUnbindProgram();
}
Esempio n. 11
0
/* helper call for drawing influence/time control curves for a given NLA-strip */
static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc, unsigned int pos)
{
  const float yheight = ymaxc - yminc;

  immUniformColor3f(0.7f, 0.7f, 0.7f);

  /* draw with AA'd line */
  GPU_line_smooth(true);
  GPU_blend(true);

  /* influence -------------------------- */
  if (strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) {
    FCurve *fcu = list_find_fcurve(&strip->fcurves, "influence", 0);
    float cfra;

    /* plot the curve (over the strip's main region) */
    if (fcu) {
      immBegin(GPU_PRIM_LINE_STRIP, abs((int)(strip->end - strip->start) + 1));

      /* sample at 1 frame intervals, and draw
       * - min y-val is yminc, max is y-maxc, so clamp in those regions
       */
      for (cfra = strip->start; cfra <= strip->end; cfra += 1.0f) {
        float y = evaluate_fcurve(fcu, cfra); /* assume this to be in 0-1 range */
        CLAMP(y, 0.0f, 1.0f);
        immVertex2f(pos, cfra, ((y * yheight) + yminc));
      }

      immEnd();
    }
  }
  else {
    /* use blend in/out values only if both aren't zero */
    if ((IS_EQF(strip->blendin, 0.0f) && IS_EQF(strip->blendout, 0.0f)) == 0) {
      immBeginAtMost(GPU_PRIM_LINE_STRIP, 4);

      /* start of strip - if no blendin, start straight at 1,
       * otherwise from 0 to 1 over blendin frames */
      if (IS_EQF(strip->blendin, 0.0f) == 0) {
        immVertex2f(pos, strip->start, yminc);
        immVertex2f(pos, strip->start + strip->blendin, ymaxc);
      }
      else {
        immVertex2f(pos, strip->start, ymaxc);
      }

      /* end of strip */
      if (IS_EQF(strip->blendout, 0.0f) == 0) {
        immVertex2f(pos, strip->end - strip->blendout, ymaxc);
        immVertex2f(pos, strip->end, yminc);
      }
      else {
        immVertex2f(pos, strip->end, ymaxc);
      }

      immEnd();
    }
  }

  /* turn off AA'd lines */
  GPU_line_smooth(false);
  GPU_blend(false);
}
Esempio n. 12
0
/* helper for apply() - perform sliding for some value */
static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, float *val)
{
	float cframe = (float)pso->cframe;
	float sVal, eVal;
	float w1, w2;
	
	/* get keyframe values for endpoint poses to blend with */
	/* previous/start */
	sVal = evaluate_fcurve(fcu, (float)pso->prevFrame);
	/* next/end */
	eVal = evaluate_fcurve(fcu, (float)pso->nextFrame);
	
	/* if both values are equal, don't do anything */
	if (IS_EQF(sVal, eVal)) {
		(*val) = sVal;
		return;
	}
	
	/* calculate the relative weights of the endpoints */
	if (pso->mode == POSESLIDE_BREAKDOWN) {
		/* get weights from the percentage control */
		w1 = pso->percentage;    /* this must come second */
		w2 = 1.0f - w1;          /* this must come first */
	}
	else {
		/*	- these weights are derived from the relative distance of these 
		 *	  poses from the current frame
		 *	- they then get normalized so that they only sum up to 1
		 */
		float wtot; 
		
		w1 = cframe - (float)pso->prevFrame;
		w2 = (float)pso->nextFrame - cframe;
		
		wtot = w1 + w2;
		w1 = (w1 / wtot);
		w2 = (w2 / wtot);
	}
	
	/* depending on the mode, calculate the new value
	 *	- in all of these, the start+end values are multiplied by w2 and w1 (respectively),
	 *	  since multiplication in another order would decrease the value the current frame is closer to
	 */
	switch (pso->mode) {
		case POSESLIDE_PUSH: /* make the current pose more pronounced */
		{
			/* perform a weighted average here, favoring the middle pose
			 *	- numerator should be larger than denominator to 'expand' the result
			 *	- perform this weighting a number of times given by the percentage...
			 */
			int iters = (int)ceil(10.0f * pso->percentage); /* TODO: maybe a sensitivity ctrl on top of this is needed */
			
			while (iters-- > 0) {
				(*val) = (-((sVal * w2) + (eVal * w1)) + ((*val) * 6.0f) ) / 5.0f;
			}
			break;
		}
		case POSESLIDE_RELAX: /* make the current pose more like its surrounding ones */
		{
			/* perform a weighted average here, favoring the middle pose
			 *	- numerator should be smaller than denominator to 'relax' the result
			 *	- perform this weighting a number of times given by the percentage...
			 */
			int iters = (int)ceil(10.0f * pso->percentage); /* TODO: maybe a sensitivity ctrl on top of this is needed */
			
			while (iters-- > 0) {
				(*val) = ( ((sVal * w2) + (eVal * w1)) + ((*val) * 5.0f) ) / 6.0f;
			}
			break;
		}
		case POSESLIDE_BREAKDOWN: /* make the current pose slide around between the endpoints */
		{
			/* perform simple linear interpolation - coefficient for start must come from pso->percentage... */
			/* TODO: make this use some kind of spline interpolation instead? */
			(*val) = ((sVal * w2) + (eVal * w1));
			break;
		}
	}
}