Example #1
0
static void bvh_callback(void *userdata, int index, const BVHTreeRay *UNUSED(ray), BVHTreeRayHit *hit)
{
	BVHCallbackUserData *data = (struct BVHCallbackUserData*)userdata;
	MFace *mf = data->sys->heat.mface + index;
	float (*verts)[3] = data->sys->heat.verts;
	float lambda, uv[2], n[3], dir[3];

	mul_v3_v3fl(dir, data->vec, hit->dist);

	if(isect_ray_tri_v3(data->start, dir, verts[mf->v1], verts[mf->v2], verts[mf->v3], &lambda, uv)) {
		normal_tri_v3(n, verts[mf->v1], verts[mf->v2], verts[mf->v3]);
		if(lambda < 1.0f && dot_v3v3(n, data->vec) < -1e-5f) {
			hit->index = index;
			hit->dist *= lambda;
		}
	}

	mul_v3_v3fl(dir, data->vec, hit->dist);

	if(isect_ray_tri_v3(data->start, dir, verts[mf->v1], verts[mf->v3], verts[mf->v4], &lambda, uv)) {
		normal_tri_v3(n, verts[mf->v1], verts[mf->v3], verts[mf->v4]);
		if(lambda < 1.0f && dot_v3v3(n, data->vec) < -1e-5f) {
			hit->index = index;
			hit->dist *= lambda;
		}
	}
}
/**
 * finalize after accumulation.
 */
static void calc_tangent_ortho(float ts[3][3])
{
	float v_tan_a[3], v_tan_b[3];
	float t_vec_a[3], t_vec_b[3];

	normalize_v3(ts[2]);

	copy_v3_v3(v_tan_a, ts[0]);
	copy_v3_v3(v_tan_b, ts[1]);

	cross_v3_v3v3(ts[1], ts[2], v_tan_a);
	mul_v3_fl(ts[1], dot_v3v3(ts[1], v_tan_b) < 0.0f ? -1.0f : 1.0f);

	/* orthognalise tangent */
	mul_v3_v3fl(t_vec_a, ts[2], dot_v3v3(ts[2], v_tan_a));
	sub_v3_v3v3(ts[0], v_tan_a, t_vec_a);

	/* orthognalise bitangent */
	mul_v3_v3fl(t_vec_a, ts[2], dot_v3v3(ts[2], ts[1]));
	mul_v3_v3fl(t_vec_b, ts[0], dot_v3v3(ts[0], ts[1]) / dot_v3v3(v_tan_a, v_tan_a));
	sub_v3_v3(ts[1], t_vec_a);
	sub_v3_v3(ts[1], t_vec_b);

	normalize_v3(ts[0]);
	normalize_v3(ts[1]);
}
Example #3
0
/**
 * \param r_distance  Distance to the hit point
 */
static bool walk_floor_distance_get(bContext *C, RegionView3D *rv3d, WalkInfo *walk, const float dvec[3], float *r_distance)
{
	float dummy_dist_px = 0;
	float ray_normal[3] = {0, 0, -1}; /* down */
	float ray_start[3];
	float r_location[3];
	float r_normal[3];
	float dvec_tmp[3];
	bool ret;

	*r_distance = TRANSFORM_DIST_MAX_RAY;

	copy_v3_v3(ray_start, rv3d->viewinv[3]);

	mul_v3_v3fl(dvec_tmp, dvec, walk->grid);
	add_v3_v3(ray_start, dvec_tmp);

	ret = snapObjectsRayEx(CTX_data_scene(C), NULL, NULL, NULL, NULL, SCE_SNAP_MODE_FACE,
	                       NULL, NULL,
	                       ray_start, ray_normal, r_distance,
	                       NULL, &dummy_dist_px, r_location, r_normal, SNAP_ALL);

	/* artifically scale the distance to the scene size */
	*r_distance /= walk->grid;
	return ret;
}
Example #4
0
static int bake_intersect_tree(RayObject *raytree, Isect *isect, float *start, float *dir, float sign, float *hitco, float *dist)
{
	float maxdist;
	int hit;

	/* might be useful to make a user setting for maxsize*/
	if (R.r.bake_maxdist > 0.0f)
		maxdist = R.r.bake_maxdist;
	else
		maxdist = RE_RAYTRACE_MAXDIST + R.r.bake_biasdist;

	/* 'dir' is always normalized */
	madd_v3_v3v3fl(isect->start, start, dir, -R.r.bake_biasdist);

	mul_v3_v3fl(isect->dir, dir, sign);

	isect->dist = maxdist;

	hit = RE_rayobject_raycast(raytree, isect);
	if (hit) {
		madd_v3_v3v3fl(hitco, isect->start, isect->dir, isect->dist);

		*dist = isect->dist;
	}

	return hit;
}
Example #5
0
void sk_straightenStroke(SK_Stroke *stk, int start, int end, float p_start[3], float p_end[3])
{
	SK_Point pt1, pt2;
	SK_Point *prev, *next;
	float delta_p[3];
	int i, total;

	total = end - start;

	sub_v3_v3v3(delta_p, p_end, p_start);

	prev = stk->points + start;
	next = stk->points + end;

	copy_v3_v3(pt1.p, p_start);
	copy_v3_v3(pt1.no, prev->no);
	pt1.mode = prev->mode;
	pt1.type = prev->type;

	copy_v3_v3(pt2.p, p_end);
	copy_v3_v3(pt2.no, next->no);
	pt2.mode = next->mode;
	pt2.type = next->type;

	sk_insertStrokePoint(stk, &pt1, start + 1); /* insert after start */
	sk_insertStrokePoint(stk, &pt2, end + 1); /* insert before end (since end was pushed back already) */

	for (i = 1; i < total; i++) {
		float delta = (float)i / (float)total;
		float *p = stk->points[start + 1 + i].p;

		mul_v3_v3fl(p, delta_p, delta);
		add_v3_v3(p, p_start);
	}
}
Example #6
0
static void update_position(Object *ob, MirrorGpencilModifierData *mmd, bGPDstroke *gps, int axis)
{
  int i;
  bGPDspoint *pt;
  float factor[3] = {1.0f, 1.0f, 1.0f};
  factor[axis] = -1.0f;

  float clear[3] = {0.0f, 0.0f, 0.0f};
  clear[axis] = 1.0f;

  float ob_origin[3];
  float pt_origin[3];

  if (mmd->object) {
    float inv_mat[4][4];

    invert_m4_m4(inv_mat, mmd->object->obmat);
    mul_v3_m4v3(ob_origin, inv_mat, ob->obmat[3]);
  }
  else {
    copy_v3_v3(ob_origin, ob->obmat[3]);
  }

  /* only works with current axis */
  mul_v3_v3(ob_origin, clear);

  mul_v3_v3fl(pt_origin, ob_origin, -2.0f);

  for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
    mul_v3_v3(&pt->x, factor);
    if (mmd->object) {
      add_v3_v3(&pt->x, pt_origin);
    }
  }
}
Example #7
0
static void paint_2d_ibuf_rgb_set(ImBuf *ibuf, int x, int y, const bool is_torus, const float rgb[4])
{
    if (is_torus) {
        x %= ibuf->x;
        if (x < 0) x += ibuf->x;
        y %= ibuf->y;
        if (y < 0) y += ibuf->y;
    }

    if (ibuf->rect_float) {
        float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4;
        float map_alpha = (rgb[3] == 0.0f) ? rrgbf[3] : rrgbf[3] / rgb[3];

        mul_v3_v3fl(rrgbf, rgb, map_alpha);
    }
    else {
        unsigned char straight[4];
        unsigned char *rrgb = (unsigned char *)ibuf->rect + (ibuf->x * y + x) * 4;

        premul_float_to_straight_uchar(straight, rgb);
        rrgb[0] = straight[0];
        rrgb[1] = straight[1];
        rrgb[2] = straight[2];
    }
}
Example #8
0
/**
 * \param r_distance  Distance to the hit point
 */
static bool walk_floor_distance_get(
        RegionView3D *rv3d, WalkInfo *walk, const float dvec[3],
        float *r_distance)
{
	float ray_normal[3] = {0, 0, -1}; /* down */
	float ray_start[3];
	float r_location[3];
	float r_normal_dummy[3];
	float dvec_tmp[3];
	bool ret;

	*r_distance = BVH_RAYCAST_DIST_MAX;

	copy_v3_v3(ray_start, rv3d->viewinv[3]);

	mul_v3_v3fl(dvec_tmp, dvec, walk->grid);
	add_v3_v3(ray_start, dvec_tmp);

	ret = ED_transform_snap_object_project_ray(
	        walk->snap_context,
	        ray_start, ray_normal, r_distance,
	        r_location, r_normal_dummy);

	/* artifically scale the distance to the scene size */
	*r_distance /= walk->grid;
	return ret;
}
Example #9
0
static void rotate(float new_co[3], float a, float ax[3], float co[3])
{
	float para[3];
	float perp[3];
	float cp[3];
	
	float cos_a = cos(a * 2 * M_PI);
	float sin_a = sin(a * 2 * M_PI);
	
	// x' = xcosa + n(n.x)(1-cosa) + (x*n)sina
	
	mul_v3_v3fl(perp, co, cos_a);
	mul_v3_v3fl(para, ax, dot_v3v3(co, ax)*(1 - cos_a));
	
	cross_v3_v3v3(cp, ax, co);
	mul_v3_fl(cp, sin_a);
	
	new_co[0] = para[0] + perp[0] + cp[0];
	new_co[1] = para[1] + perp[1] + cp[1];
	new_co[2] = para[2] + perp[2] + cp[2];
}
Example #10
0
/* project a vector on a plane defined by normal and a plane point p */
void project_v3_plane(float v[3], const float n[3], const float p[3])
{
	float vector[3];
	float mul;

	sub_v3_v3v3(vector, v, p);
	mul = dot_v3v3(vector, n) / len_squared_v3(n);

	mul_v3_v3fl(vector, n, mul);

	sub_v3_v3(v, vector);
}
void ConvertRGBToYCCOperation::executePixel(float output[4], float x, float y, PixelSampler sampler)
{
	float inputColor[4];
	float color[3];

	this->m_inputOperation->read(inputColor, x, y, sampler);
	rgb_to_ycc(inputColor[0], inputColor[1], inputColor[2], &color[0], &color[1], &color[2], this->m_mode);

	/* divided by 255 to normalize for viewing in */
	/* R,G,B --> Y,Cb,Cr */
	mul_v3_v3fl(output, color, 1.0f / 255.0f);
	output[3] = inputColor[3];
}
void ConvertStraightToPremulOperation::executePixel(float output[4], float x, float y, PixelSampler sampler)
{
	float inputValue[4];
	float alpha;

	this->m_inputOperation->read(inputValue, x, y, sampler);
	alpha = inputValue[3];

	mul_v3_v3fl(output, inputValue, alpha);

	/* never touches the alpha */
	output[3] = alpha;
}
Example #13
0
static void do_kink_spiral_deform(ParticleKey *state, const float dir[3], const float kink[3],
                                  float time, float freq, float shape, float amplitude,
                                  const float spiral_start[3])
{
	float result[3];

	CLAMP(time, 0.f, 1.f);

	copy_v3_v3(result, state->co);

	{
		/* Creates a logarithmic spiral:
		 *   r(theta) = a * exp(b * theta)
		 *
		 * The "density" parameter b is defined by the shape parameter
		 * and goes up to the Golden Spiral for 1.0
		 * https://en.wikipedia.org/wiki/Golden_spiral
		 */
		const float b = shape * (1.0f + sqrtf(5.0f)) / (float)M_PI * 0.25f;
		/* angle of the spiral against the curve (rotated opposite to make a smooth transition) */
		const float start_angle = ((b != 0.0f) ? atanf(1.0f / b) :
		                           (float)-M_PI_2) + (b > 0.0f ? -(float)M_PI_2 : (float)M_PI_2);

		float spiral_axis[3], rot[3][3];
		float vec[3];

		float theta = freq * time * 2.0f * (float)M_PI;
		float radius = amplitude * expf(b * theta);

		/* a bit more intuitive than using negative frequency for this */
		if (amplitude < 0.0f)
			theta = -theta;

		cross_v3_v3v3(spiral_axis, dir, kink);
		normalize_v3(spiral_axis);

		mul_v3_v3fl(vec, kink, -radius);

		axis_angle_normalized_to_mat3(rot, spiral_axis, theta);
		mul_m3_v3(rot, vec);

		madd_v3_v3fl(vec, kink, amplitude);

		axis_angle_normalized_to_mat3(rot, spiral_axis, -start_angle);
		mul_m3_v3(rot, vec);

		add_v3_v3v3(result, spiral_start, vec);
	}

	copy_v3_v3(state->co, result);
}
/**
 * This function returns the coordinate and normal of a barycentric u,v for a face defined by the primitive_id index.
 * The returned coordinate is extruded along the normal by cage_extrusion
 */
static void calc_point_from_barycentric_extrusion(
        TriTessFace *triangles,
        float mat[4][4], float imat[4][4],
        int primitive_id, float u, float v,
        float cage_extrusion,
        float r_co[3], float r_dir[3],
        const bool is_cage)
{
	float data[3][3];
	float coord[3];
	float dir[3];
	float cage[3];
	bool is_smooth;

	TriTessFace *triangle = &triangles[primitive_id];
	is_smooth = triangle->is_smooth || is_cage;

	copy_v3_v3(data[0], triangle->mverts[0]->co);
	copy_v3_v3(data[1], triangle->mverts[1]->co);
	copy_v3_v3(data[2], triangle->mverts[2]->co);

	interp_barycentric_tri_v3(data, u, v, coord);

	if (is_smooth) {
		normal_short_to_float_v3(data[0], triangle->mverts[0]->no);
		normal_short_to_float_v3(data[1], triangle->mverts[1]->no);
		normal_short_to_float_v3(data[2], triangle->mverts[2]->no);

		interp_barycentric_tri_v3(data, u, v, dir);
		normalize_v3(dir);
	}
	else {
		copy_v3_v3(dir, triangle->normal);
	}

	mul_v3_v3fl(cage, dir, cage_extrusion);
	add_v3_v3(coord, cage);

	normalize_v3(dir);
	negate_v3(dir);

	/* convert from local to world space */
	mul_m4_v3(mat, coord);
	mul_transposed_mat3_m4_v3(imat, dir);
	normalize_v3(dir);

	copy_v3_v3(r_co, coord);
	copy_v3_v3(r_dir, dir);
}
void ScreenLensDistortionOperation::updateVariables(float distortion, float dispersion)
{
	m_k[1] = max_ff(min_ff(distortion, 1.0f), -0.999f);
	// smaller dispersion range for somewhat more control
	float d = 0.25f * max_ff(min_ff(dispersion, 1.0f), 0.0f);
	m_k[0] = max_ff(min_ff((m_k[1] + d), 1.0f), -0.999f);
	m_k[2] = max_ff(min_ff((m_k[1] - d), 1.0f), -0.999f);
	m_maxk = max_fff(m_k[0], m_k[1], m_k[2]);
	m_sc = (m_fit && (m_maxk > 0.0f)) ? (1.0f / (1.0f + 2.0f * m_maxk)) :
	                                    (1.0f / (1.0f +        m_maxk));
	m_dk4[0] = 4.0f * (m_k[1] - m_k[0]);
	m_dk4[1] = 4.0f * (m_k[2] - m_k[1]);
	m_dk4[2] = 0.0f; /* unused */

	mul_v3_v3fl(m_k4, m_k, 4.0f);
}
MINLINE float normalize_v3_v3(float r[3], const float a[3])
{
	float d = dot_v3v3(a, a);

	/* a larger value causes normalize errors in a
	 * scaled down models with camera extreme close */
	if (d > 1.0e-35f) {
		d = sqrtf(d);
		mul_v3_v3fl(r, a, 1.0f / d);
	}
	else {
		zero_v3(r);
		d = 0.0f;
	}

	return d;
}
Example #17
0
static int pointdensity_color(PointDensity *pd, TexResult *texres, float age, const float vec[3])
{
	int retval = 0;
	float col[4];

	retval |= TEX_RGB;

	switch (pd->color_source) {
		case TEX_PD_COLOR_PARTAGE:
			if (pd->coba) {
				if (do_colorband(pd->coba, age, col)) {
					texres->talpha = true;
					copy_v3_v3(&texres->tr, col);
					texres->tin *= col[3];
					texres->ta = texres->tin;
				}
			}
			break;
		case TEX_PD_COLOR_PARTSPEED:
		{
			float speed = len_v3(vec) * pd->speed_scale;

			if (pd->coba) {
				if (do_colorband(pd->coba, speed, col)) {
					texres->talpha = true;
					copy_v3_v3(&texres->tr, col);
					texres->tin *= col[3];
					texres->ta = texres->tin;
				}
			}
			break;
		}
		case TEX_PD_COLOR_PARTVEL:
			texres->talpha = true;
			mul_v3_v3fl(&texres->tr, vec, pd->speed_scale);
			texres->ta = texres->tin;
			break;
		case TEX_PD_COLOR_CONSTANT:
		default:
			texres->tr = texres->tg = texres->tb = texres->ta = 1.0f;
			break;
	}
	
	return retval;
}
void ConvertPremulToStraightOperation::executePixel(float output[4], float x, float y, PixelSampler sampler)
{
	float inputValue[4];
	float alpha;

	this->m_inputOperation->read(inputValue, x, y, sampler);
	alpha = inputValue[3];

	if (fabsf(alpha) < 1e-5f) {
		zero_v3(output);
	}
	else {
		mul_v3_v3fl(output, inputValue, 1.0f / alpha);
	}

	/* never touches the alpha */
	output[3] = alpha;
}
Example #19
0
static void track_colors(MovieTrackingTrack *track, int act, float col[3], float scol[3])
{
	if (track->flag & TRACK_CUSTOMCOLOR) {
		if (act)
			UI_GetThemeColor3fv(TH_ACT_MARKER, scol);
		else
			copy_v3_v3(scol, track->color);

		mul_v3_v3fl(col, track->color, 0.5f);
	}
	else {
		UI_GetThemeColor3fv(TH_MARKER, col);

		if (act)
			UI_GetThemeColor3fv(TH_ACT_MARKER, scol);
		else
			UI_GetThemeColor3fv(TH_SEL_MARKER, scol);
	}
}
Example #20
0
float do_clump(ParticleKey *state, const float par_co[3], float time, const float orco_offset[3], float clumpfac, float clumppow, float pa_clump,
               bool use_clump_noise, float clump_noise_size, CurveMapping *clumpcurve)
{
	float clump;

	if (use_clump_noise && clump_noise_size != 0.0f) {
		float center[3], noisevec[3];
		float da[4], pa[12];

		mul_v3_v3fl(noisevec, orco_offset, 1.0f / clump_noise_size);
		voronoi(noisevec[0], noisevec[1], noisevec[2], da, pa, 1.0f, 0);
		mul_v3_fl(&pa[0], clump_noise_size);
		add_v3_v3v3(center, par_co, &pa[0]);

		do_clump_level(state->co, state->co, center, time, clumpfac, clumppow, pa_clump, clumpcurve);
	}

	clump = do_clump_level(state->co, state->co, par_co, time, clumpfac, clumppow, pa_clump, clumpcurve);

	return clump;
}
Example #21
0
/**
 * \param r_distance: Distance to the hit point
 */
static bool walk_floor_distance_get(RegionView3D *rv3d,
                                    WalkInfo *walk,
                                    const float dvec[3],
                                    float *r_distance)
{
  float ray_normal[3] = {0, 0, -1}; /* down */
  float ray_start[3];
  float r_location[3];
  float r_normal_dummy[3];
  float dvec_tmp[3];
  bool ret;

  *r_distance = BVH_RAYCAST_DIST_MAX;

  copy_v3_v3(ray_start, rv3d->viewinv[3]);

  mul_v3_v3fl(dvec_tmp, dvec, walk->grid);
  add_v3_v3(ray_start, dvec_tmp);

  ret = ED_transform_snap_object_project_ray(walk->snap_context,
                                             &(const struct SnapObjectParams){
                                                 .snap_select = SNAP_ALL,
                                             },
Example #22
0
static void cloth_continuum_fill_grid(HairGrid *grid, Cloth *cloth)
{
#if 0
	Implicit_Data *data = cloth->implicit;
	int mvert_num = cloth->mvert_num;
	ClothVertex *vert;
	int i;
	
	for (i = 0, vert = cloth->verts; i < mvert_num; i++, vert++) {
		float x[3], v[3];
		
		cloth_get_vertex_motion_state(data, vert, x, v);
		BPH_hair_volume_add_vertex(grid, x, v);
	}
#else
	LinkNode *link;
	float cellsize, gmin[3], cell_scale, cell_offset[3];
	
	/* scale and offset for transforming vertex locations into grid space
	 * (cell size is 0..1, gmin becomes origin)
	 */
	BPH_hair_volume_grid_geometry(grid, &cellsize, NULL, gmin, NULL);
	cell_scale = cellsize > 0.0f ? 1.0f / cellsize : 0.0f;
	mul_v3_v3fl(cell_offset, gmin, cell_scale);
	negate_v3(cell_offset);
	
	link = cloth->springs;
	while (link) {
		ClothSpring *spring = (ClothSpring *)link->link;
		if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL)
			link = cloth_continuum_add_hair_segments(grid, cell_scale, cell_offset, cloth, link);
		else
			link = link->next;
	}
#endif
	BPH_hair_volume_normalize_vertex_grid(grid);
}
Example #23
0
/* update rectangular section of the brush image */
static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf,
                                       int origx, int origy, int w, int h, int xt, int yt)
{
    Scene *scene = painter->scene;
    Brush *brush = painter->brush;

    rctf tex_mapping = painter->tex_mapping;
    rctf mask_mapping = painter->mask_mapping;
    struct ImagePool *pool = painter->pool;

    bool use_masking = painter->cache.use_masking;
    bool use_color_correction = painter->cache.use_color_correction;
    bool use_float = painter->cache.use_float;
    bool is_texbrush = painter->cache.is_texbrush;
    bool is_maskbrush = painter->cache.is_maskbrush;
    bool use_texture_old = (oldtexibuf != NULL);

    int x, y, thread = 0;
    float brush_rgb[3];

    ImBuf *ibuf = painter->cache.ibuf;
    ImBuf *texibuf = painter->cache.texibuf;
    unsigned short *mask = painter->cache.mask;

    /* get brush color */
    if (brush->imagepaint_tool == PAINT_TOOL_DRAW) {
        copy_v3_v3(brush_rgb, brush->rgb);

        if (use_color_correction)
            srgb_to_linearrgb_v3_v3(brush_rgb, brush_rgb);
    }
    else {
        brush_rgb[0] = 1.0f;
        brush_rgb[1] = 1.0f;
        brush_rgb[2] = 1.0f;
    }

    /* fill pixes */
    for (y = origy; y < h; y++) {
        for (x = origx; x < w; x++) {
            /* sample texture and multiply with brush color */
            float texco[3], rgba[4];

            if (!use_texture_old) {
                if (is_texbrush) {
                    brush_imbuf_tex_co(&tex_mapping, x, y, texco);
                    BKE_brush_sample_tex_3D(scene, brush, texco, rgba, thread, pool);
                    /* TODO(sergey): Support texture paint color space. */
                    if (!use_float) {
                        linearrgb_to_srgb_v3_v3(rgba, rgba);
                    }
                    mul_v3_v3(rgba, brush_rgb);
                }
                else {
                    copy_v3_v3(rgba, brush_rgb);
                    rgba[3] = 1.0f;
                }

                if (is_maskbrush) {
                    brush_imbuf_tex_co(&mask_mapping, x, y, texco);
                    rgba[3] *= BKE_brush_sample_masktex(scene, brush, texco, thread, pool);
                }
            }

            if (use_float) {
                /* handle float pixel */
                float *bf = ibuf->rect_float + (y * ibuf->x + x) * 4;
                float *tf = texibuf->rect_float + (y * texibuf->x + x) * 4;

                /* read from old texture buffer */
                if (use_texture_old) {
                    float *otf = oldtexibuf->rect_float + ((y - origy + yt) * oldtexibuf->x + (x - origx + xt)) * 4;
                    copy_v4_v4(rgba, otf);
                }

                /* write to new texture buffer */
                copy_v4_v4(tf, rgba);

                /* if not using masking, multiply in the mask now */
                if (!use_masking) {
                    unsigned short *m = mask + (y * ibuf->x + x);
                    rgba[3] *= *m * (1.0f / 65535.0f);
                }

                /* output premultiplied float image, mf was already premultiplied */
                mul_v3_v3fl(bf, rgba, rgba[3]);
                bf[3] = rgba[3];
            }
            else {
                unsigned char crgba[4];

                /* handle byte pixel */
                unsigned char *b = (unsigned char *)ibuf->rect + (y * ibuf->x + x) * 4;
                unsigned char *t = (unsigned char *)texibuf->rect + (y * texibuf->x + x) * 4;

                /* read from old texture buffer */
                if (use_texture_old) {
                    unsigned char *ot = (unsigned char *)oldtexibuf->rect + ((y - origy + yt) * oldtexibuf->x + (x - origx + xt)) * 4;
                    crgba[0] = ot[0];
                    crgba[1] = ot[1];
                    crgba[2] = ot[2];
                    crgba[3] = ot[3];
                }
                else
                    rgba_float_to_uchar(crgba, rgba);

                /* write to new texture buffer */
                t[0] = crgba[0];
                t[1] = crgba[1];
                t[2] = crgba[2];
                t[3] = crgba[3];

                /* if not using masking, multiply in the mask now */
                if (!use_masking) {
                    unsigned short *m = mask + (y * ibuf->x + x);
                    crgba[3] = (crgba[3] * (*m)) / 65535;
                }

                /* write to brush image buffer */
                b[0] = crgba[0];
                b[1] = crgba[1];
                b[2] = crgba[2];
                b[3] = crgba[3];
            }
        }
    }
}
Example #24
0
/* create imbuf with brush color */
static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size)
{
    Scene *scene = painter->scene;
    Brush *brush = painter->brush;

    rctf tex_mapping = painter->tex_mapping;
    rctf mask_mapping = painter->mask_mapping;
    struct ImagePool *pool = painter->pool;

    bool use_masking = painter->cache.use_masking;
    bool use_color_correction = painter->cache.use_color_correction;
    bool use_float = painter->cache.use_float;
    bool is_texbrush = painter->cache.is_texbrush;
    bool is_maskbrush = painter->cache.is_maskbrush;

    float alpha = (use_masking) ? 1.0f : BKE_brush_alpha_get(scene, brush);
    int radius = BKE_brush_size_get(scene, brush);
    int xoff = -size * 0.5f + 0.5f;
    int yoff = -size * 0.5f + 0.5f;

    int x, y, thread = 0;
    float brush_rgb[3];

    /* allocate image buffer */
    ImBuf *ibuf = IMB_allocImBuf(size, size, 32, (use_float) ? IB_rectfloat : IB_rect);

    /* get brush color */
    if (brush->imagepaint_tool == PAINT_TOOL_DRAW) {
        copy_v3_v3(brush_rgb, brush->rgb);

        if (use_color_correction)
            srgb_to_linearrgb_v3_v3(brush_rgb, brush_rgb);
    }
    else {
        brush_rgb[0] = 1.0f;
        brush_rgb[1] = 1.0f;
        brush_rgb[2] = 1.0f;
    }

    /* fill image buffer */
    for (y = 0; y < size; y++) {
        for (x = 0; x < size; x++) {
            /* sample texture and multiply with brush color */
            float texco[3], rgba[4];

            if (is_texbrush) {
                brush_imbuf_tex_co(&tex_mapping, x, y, texco);
                BKE_brush_sample_tex_3D(scene, brush, texco, rgba, thread, pool);
                /* TODO(sergey): Support texture paint color space. */
                if (!use_float) {
                    linearrgb_to_srgb_v3_v3(rgba, rgba);
                }
                mul_v3_v3(rgba, brush_rgb);
            }
            else {
                copy_v3_v3(rgba, brush_rgb);
                rgba[3] = 1.0f;
            }

            if (is_maskbrush) {
                brush_imbuf_tex_co(&mask_mapping, x, y, texco);
                rgba[3] *= BKE_brush_sample_masktex(scene, brush, texco, thread, pool);
            }

            /* when not using masking, multiply in falloff and strength */
            if (!use_masking) {
                float xy[2] = {x + xoff, y + yoff};
                float len = len_v2(xy);

                rgba[3] *= alpha * BKE_brush_curve_strength_clamp(brush, len, radius);
            }

            if (use_float) {
                /* write to float pixel */
                float *dstf = ibuf->rect_float + (y * size + x) * 4;
                mul_v3_v3fl(dstf, rgba, rgba[3]); /* premultiply */
                dstf[3] = rgba[3];
            }
            else {
                /* write to byte pixel */
                unsigned char *dst = (unsigned char *)ibuf->rect + (y * size + x) * 4;

                rgb_float_to_uchar(dst, rgba);
                dst[3] = FTOCHAR(rgba[3]);
            }
        }
    }

    return ibuf;
}
Example #25
0
/* old collision stuff for cloth, use for continuity
 * until a good replacement is ready
 */
static void cloth_collision_solve_extra(Object *ob, ClothModifierData *clmd, ListBase *effectors, float frame, float step, float dt)
{
	Cloth *cloth = clmd->clothObject;
	Implicit_Data *id = cloth->implicit;
	ClothVertex *verts = cloth->verts;
	int mvert_num = cloth->mvert_num;
	const float spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale;
	
	bool do_extra_solve;
	int i;
	
	if (!(clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED))
		return;
	if (!clmd->clothObject->bvhtree)
		return;
	
	// update verts to current positions
	for (i = 0; i < mvert_num; i++) {
		BPH_mass_spring_get_new_position(id, i, verts[i].tx);
		
		sub_v3_v3v3(verts[i].tv, verts[i].tx, verts[i].txold);
		copy_v3_v3(verts[i].v, verts[i].tv);
	}
	
#if 0 /* unused */
	for (i=0, cv=cloth->verts; i<cloth->mvert_num; i++, cv++) {
		copy_v3_v3(initial_cos[i], cv->tx);
	}
#endif
	
	// call collision function
	// TODO: check if "step" or "step+dt" is correct - dg
	do_extra_solve = cloth_bvh_objcollision(ob, clmd, step / clmd->sim_parms->timescale, dt / clmd->sim_parms->timescale);
	
	// copy corrected positions back to simulation
	for (i = 0; i < mvert_num; i++) {
		float curx[3];
		BPH_mass_spring_get_position(id, i, curx);
		// correct velocity again, just to be sure we had to change it due to adaptive collisions
		sub_v3_v3v3(verts[i].tv, verts[i].tx, curx);
	}
	
	if (do_extra_solve) {
//		cloth_calc_helper_forces(ob, clmd, initial_cos, step/clmd->sim_parms->timescale, dt/clmd->sim_parms->timescale);
		
		for (i = 0; i < mvert_num; i++) {
		
			float newv[3];
			
			if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) && (verts [i].flags & CLOTH_VERT_FLAG_PINNED))
				continue;
			
			BPH_mass_spring_set_new_position(id, i, verts[i].tx);
			mul_v3_v3fl(newv, verts[i].tv, spf);
			BPH_mass_spring_set_new_velocity(id, i, newv);
		}
	}
	
	// X = Xnew;
	BPH_mass_spring_apply_result(id);
	
	if (do_extra_solve) {
		ImplicitSolverResult result;
		
		/* initialize forces to zero */
		BPH_mass_spring_clear_forces(id);
		
		// calculate forces
		cloth_calc_force(clmd, frame, effectors, step);
		
		// calculate new velocity and position
		BPH_mass_spring_solve_velocities(id, dt, &result);
//		cloth_record_result(clmd, &result, clmd->sim_parms->stepsPerFrame);
		
		/* note: positions are advanced only once in the main solver step! */
		
		BPH_mass_spring_apply_result(id);
	}
}
Example #26
0
static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListBase *effectors, float time)
{
	/* Collect forces and derivatives:  F, dFdX, dFdV */
	Cloth *cloth = clmd->clothObject;
	Implicit_Data *data = cloth->implicit;
	unsigned int i	= 0;
	float 		drag 	= clmd->sim_parms->Cvi * 0.01f; /* viscosity of air scaled in percent */
	float 		gravity[3] = {0.0f, 0.0f, 0.0f};
	const MVertTri *tri 	= cloth->tri;
	unsigned int mvert_num = cloth->mvert_num;
	ClothVertex *vert;
	
#ifdef CLOTH_FORCE_GRAVITY
	/* global acceleration (gravitation) */
	if (clmd->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
		/* scale gravity force */
		mul_v3_v3fl(gravity, clmd->scene->physics_settings.gravity, 0.001f * clmd->sim_parms->effector_weights->global_gravity);
	}
	vert = cloth->verts;
	for (i = 0; i < cloth->mvert_num; i++, vert++) {
		BPH_mass_spring_force_gravity(data, i, vert->mass, gravity);
	}
#endif

	/* cloth_calc_volume_force(clmd); */

#ifdef CLOTH_FORCE_DRAG
	BPH_mass_spring_force_drag(data, drag);
#endif
	
	/* handle external forces like wind */
	if (effectors) {
		/* cache per-vertex forces to avoid redundant calculation */
		float (*winvec)[3] = (float (*)[3])MEM_callocN(sizeof(float[3]) * mvert_num, "effector forces");
		for (i = 0; i < cloth->mvert_num; i++) {
			float x[3], v[3];
			EffectedPoint epoint;
			
			BPH_mass_spring_get_motion_state(data, i, x, v);
			pd_point_from_loc(clmd->scene, x, v, i, &epoint);
			pdDoEffectors(effectors, NULL, clmd->sim_parms->effector_weights, &epoint, winvec[i], NULL);
		}
		
		for (i = 0; i < cloth->tri_num; i++) {
			const MVertTri *vt = &tri[i];
			BPH_mass_spring_force_face_wind(data, vt->tri[0], vt->tri[1], vt->tri[2], winvec);
		}

		/* Hair has only edges */
		if (cloth->tri_num == 0) {
#if 0
			ClothHairData *hairdata = clmd->hairdata;
			ClothHairData *hair_ij, *hair_kl;
			
			for (LinkNode *link = cloth->springs; link; link = link->next) {
				ClothSpring *spring = (ClothSpring *)link->link;
				if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL) {
					if (hairdata) {
						hair_ij = &hairdata[spring->ij];
						hair_kl = &hairdata[spring->kl];
						BPH_mass_spring_force_edge_wind(data, spring->ij, spring->kl, hair_ij->radius, hair_kl->radius, winvec);
					}
					else
						BPH_mass_spring_force_edge_wind(data, spring->ij, spring->kl, 1.0f, 1.0f, winvec);
				}
			}
#else
			ClothHairData *hairdata = clmd->hairdata;
			
			vert = cloth->verts;
			for (i = 0; i < cloth->mvert_num; i++, vert++) {
				if (hairdata) {
					ClothHairData *hair = &hairdata[i];
					BPH_mass_spring_force_vertex_wind(data, i, hair->radius, winvec);
				}
				else
					BPH_mass_spring_force_vertex_wind(data, i, 1.0f, winvec);
			}
		}
#endif

		MEM_freeN(winvec);
	}
	
	// calculate spring forces
	for (LinkNode *link = cloth->springs; link; link = link->next) {
		ClothSpring *spring = (ClothSpring *)link->link;
		// only handle active springs
		if (!(spring->flags & CLOTH_SPRING_FLAG_DEACTIVATE))
			cloth_calc_spring_force(clmd, spring, time);
	}
}
Example #27
0
static bool collision_response(ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, float dt, float restitution, float r_impulse[3])
{
	Cloth *cloth = clmd->clothObject;
	int index = collpair->ap1;
	bool result = false;
	
	float v1[3], v2_old[3], v2_new[3], v_rel_old[3], v_rel_new[3];
	float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree);

	float margin_distance = (float)collpair->distance - epsilon2;
	float mag_v_rel;
	
	zero_v3(r_impulse);
	
	if (margin_distance > 0.0f)
		return false; /* XXX tested before already? */
	
	/* only handle static collisions here */
	if ( collpair->flag & COLLISION_IN_FUTURE )
		return false;
	
	/* velocity */
	copy_v3_v3(v1, cloth->verts[index].v);
	collision_get_collider_velocity(v2_old, v2_new, collmd, collpair);
	/* relative velocity = velocity of the cloth point relative to the collider */
	sub_v3_v3v3(v_rel_old, v1, v2_old);
	sub_v3_v3v3(v_rel_new, v1, v2_new);
	/* normal component of the relative velocity */
	mag_v_rel = dot_v3v3(v_rel_old, collpair->normal);
	
	/* only valid when moving toward the collider */
	if (mag_v_rel < -ALMOST_ZERO) {
		float v_nor_old, v_nor_new;
		float v_tan_old[3], v_tan_new[3];
		float bounce, repulse;
		
		/* Collision response based on
		 * "Simulating Complex Hair with Robust Collision Handling" (Choe, Choi, Ko, ACM SIGGRAPH 2005)
		 * http://graphics.snu.ac.kr/publications/2005-choe-HairSim/Choe_2005_SCA.pdf
		 */
		
		v_nor_old = mag_v_rel;
		v_nor_new = dot_v3v3(v_rel_new, collpair->normal);
		
		madd_v3_v3v3fl(v_tan_old, v_rel_old, collpair->normal, -v_nor_old);
		madd_v3_v3v3fl(v_tan_new, v_rel_new, collpair->normal, -v_nor_new);
		
		bounce = -v_nor_old * restitution;
		
		repulse = -margin_distance / dt; /* base repulsion velocity in normal direction */
		/* XXX this clamping factor is quite arbitrary ...
		 * not sure if there is a more scientific approach, but seems to give good results
		 */
		CLAMP(repulse, 0.0f, 4.0f * bounce);
		
		if (margin_distance < -epsilon2) {
			mul_v3_v3fl(r_impulse, collpair->normal, max_ff(repulse, bounce) - v_nor_new);
		}
		else {
			bounce = 0.0f;
			mul_v3_v3fl(r_impulse, collpair->normal, repulse - v_nor_new);
		}
		
		result = true;
	}
	
	return result;
}
static int  RE_rayobject_instance_intersect(RayObject *o, Isect *isec)
{
    InstanceRayObject *obj = (InstanceRayObject *)o;
    float start[3], dir[3], idot_axis[3], dist;
    int changed = 0, i, res;

    // TODO - this is disabling self intersection on instances
    if (isec->orig.ob == obj->ob && obj->ob) {
        changed = 1;
        isec->orig.ob = obj->target_ob;
    }

    // backup old values
    copy_v3_v3(start, isec->start);
    copy_v3_v3(dir, isec->dir);
    copy_v3_v3(idot_axis, isec->idot_axis);
    dist = isec->dist;

    // transform to target coordinates system
    mul_m4_v3(obj->global2target, isec->start);
    mul_mat3_m4_v3(obj->global2target, isec->dir);
    isec->dist *= normalize_v3(isec->dir);

    // update idot_axis and bv_index
    for (i = 0; i < 3; i++) {
        isec->idot_axis[i]        = 1.0f / isec->dir[i];

        isec->bv_index[2 * i]     = isec->idot_axis[i] < 0.0f ? 1 : 0;
        isec->bv_index[2 * i + 1] = 1 - isec->bv_index[2 * i];

        isec->bv_index[2 * i]     = i + 3 * isec->bv_index[2 * i];
        isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1];
    }

    // raycast
    res = RE_rayobject_intersect(obj->target, isec);

    // map dist into original coordinate space
    if (res == 0) {
        isec->dist = dist;
    }
    else {
        // note we don't just multiply dist, because of possible
        // non-uniform scaling in the transform matrix
        float vec[3];

        mul_v3_v3fl(vec, isec->dir, isec->dist);
        mul_mat3_m4_v3(obj->target2global, vec);

        isec->dist = len_v3(vec);
        isec->hit.ob = obj->ob;

#ifdef RT_USE_LAST_HIT
        // TODO support for last hit optimization in instances that can jump
        // directly to the last hit face.
        // For now it jumps directly to the last-hit instance root node.
        isec->last_hit = RE_rayobject_unalignRayAPI((RayObject *) obj);
#endif
    }

    // restore values
    copy_v3_v3(isec->start, start);
    copy_v3_v3(isec->dir, dir);
    copy_v3_v3(isec->idot_axis, idot_axis);

    if (changed)
        isec->orig.ob = obj->ob;

    // restore bv_index
    for (i = 0; i < 3; i++) {
        isec->bv_index[2 * i]     = isec->idot_axis[i] < 0.0f ? 1 : 0;
        isec->bv_index[2 * i + 1] = 1 - isec->bv_index[2 * i];

        isec->bv_index[2 * i]     = i + 3 * isec->bv_index[2 * i];
        isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1];
    }

    return res;
}
Example #29
0
/* calculates offset for co, based on fractal, sphere or smooth settings  */
static void alter_co(BMVert *v, BMEdge *UNUSED(origed), const SubDParams *params, float perc,
                     BMVert *vsta, BMVert *vend)
{
	float tvec[3], fac;
	float *co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp);
	int i;

	copy_v3_v3(co, v->co);

	if (UNLIKELY(params->use_sphere)) { /* subdivide sphere */
		normalize_v3(co);
		mul_v3_fl(co, params->smooth);
	}
	else if (params->use_smooth) {
		/* we calculate an offset vector vec1[], to be added to *co */
		float len, nor[3], nor1[3], nor2[3], val;

		sub_v3_v3v3(nor, vsta->co, vend->co);
		len = 0.5f * normalize_v3(nor);

		copy_v3_v3(nor1, vsta->no);
		copy_v3_v3(nor2, vend->no);

		/* cosine angle */
		fac = dot_v3v3(nor, nor1);
		mul_v3_v3fl(tvec, nor1, fac);

		/* cosine angle */
		fac = -dot_v3v3(nor, nor2);
		madd_v3_v3fl(tvec, nor2, fac);

		/* falloff for multi subdivide */
		val = fabsf(1.0f - 2.0f * fabsf(0.5f - perc));
		val = bmesh_subd_falloff_calc(params->smooth_falloff, val);

		if (params->use_smooth_even) {
			val *= BM_vert_calc_shell_factor(v);
		}

		mul_v3_fl(tvec, params->smooth * val * len);

		add_v3_v3(co, tvec);
	}

	if (params->use_fractal) {
		const float len = len_v3v3(vsta->co, vend->co);
		float normal[3], co2[3], base1[3], base2[3];

		fac = params->fractal * len;

		mid_v3_v3v3(normal, vsta->no, vend->no);
		ortho_basis_v3v3_v3(base1, base2, normal);

		add_v3_v3v3(co2, v->co, params->fractal_ofs);
		mul_v3_fl(co2, 10.0f);

		tvec[0] = fac * (BLI_gTurbulence(1.0, co2[0], co2[1], co2[2], 15, 0, 2) - 0.5f);
		tvec[1] = fac * (BLI_gTurbulence(1.0, co2[1], co2[0], co2[2], 15, 0, 2) - 0.5f);
		tvec[2] = fac * (BLI_gTurbulence(1.0, co2[1], co2[2], co2[0], 15, 0, 2) - 0.5f);

		/* add displacement */
		madd_v3_v3fl(co, normal, tvec[0]);
		madd_v3_v3fl(co, base1, tvec[1] * (1.0f - params->along_normal));
		madd_v3_v3fl(co, base2, tvec[2] * (1.0f - params->along_normal));
	}

	/* apply the new difference to the rest of the shape keys,
	 * note that this doesn't take rotations into account, we _could_ support
	 * this by getting the normals and coords for each shape key and
	 * re-calculate the smooth value for each but this is quite involved.
	 * for now its ok to simply apply the difference IMHO - campbell */
	sub_v3_v3v3(tvec, v->co, co);

	if (params->shape_info.totlayer > 1) {
		/* skip the last layer since its the temp */
		i = params->shape_info.totlayer - 1;
		co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset);
		while (i--) {
			BLI_assert(co != BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp));
			sub_v3_v3(co += 3, tvec);
		}
	}
}
Example #30
0
/* only valid for perspective cameras */
int camera_view_frame_fit_to_scene(Scene *scene, struct View3D *v3d, Object *camera_ob, float r_co[3])
{
	float shift[2];
	float plane_tx[4][3];
	float rot_obmat[3][3];
	const float zero[3]= {0,0,0};
	CameraViewFrameData data_cb;

	unsigned int i;

	camera_view_frame(scene, camera_ob->data, data_cb.frame_tx);

	copy_m3_m4(rot_obmat, camera_ob->obmat);
	normalize_m3(rot_obmat);

	for (i= 0; i < 4; i++) {
		/* normalize so Z is always 1.0f*/
		mul_v3_fl(data_cb.frame_tx[i], 1.0f/data_cb.frame_tx[i][2]);
	}

	/* get the shift back out of the frame */
	shift[0]= (data_cb.frame_tx[0][0] +
	           data_cb.frame_tx[1][0] +
	           data_cb.frame_tx[2][0] +
	           data_cb.frame_tx[3][0]) / 4.0f;
	shift[1]= (data_cb.frame_tx[0][1] +
	           data_cb.frame_tx[1][1] +
	           data_cb.frame_tx[2][1] +
	           data_cb.frame_tx[3][1]) / 4.0f;

	for (i= 0; i < 4; i++) {
		mul_m3_v3(rot_obmat, data_cb.frame_tx[i]);
	}

	for (i= 0; i < 4; i++) {
		normal_tri_v3(data_cb.normal_tx[i],
		              zero, data_cb.frame_tx[i], data_cb.frame_tx[(i + 1) % 4]);
	}

	/* initialize callback data */
	data_cb.dist_vals[0]=
	data_cb.dist_vals[1]=
	data_cb.dist_vals[2]=
	data_cb.dist_vals[3]= FLT_MAX;
	data_cb.tot= 0;
	/* run callback on all visible points */
	BKE_scene_foreach_display_point(scene, v3d, BA_SELECT,
	                                camera_to_frame_view_cb, &data_cb);

	if (data_cb.tot <= 1) {
		return FALSE;
	}
	else {
		float plane_isect_1[3], plane_isect_1_no[3], plane_isect_1_other[3];
		float plane_isect_2[3], plane_isect_2_no[3], plane_isect_2_other[3];

		float plane_isect_pt_1[3], plane_isect_pt_2[3];

		/* apply the dist-from-plane's to the transformed plane points */
		for (i= 0; i < 4; i++) {
			mul_v3_v3fl(plane_tx[i], data_cb.normal_tx[i], data_cb.dist_vals[i]);
		}

		isect_plane_plane_v3(plane_isect_1, plane_isect_1_no,
		                     plane_tx[0], data_cb.normal_tx[0],
		                     plane_tx[2], data_cb.normal_tx[2]);
		isect_plane_plane_v3(plane_isect_2, plane_isect_2_no,
		                     plane_tx[1], data_cb.normal_tx[1],
		                     plane_tx[3], data_cb.normal_tx[3]);

		add_v3_v3v3(plane_isect_1_other, plane_isect_1, plane_isect_1_no);
		add_v3_v3v3(plane_isect_2_other, plane_isect_2, plane_isect_2_no);

		if (isect_line_line_v3(plane_isect_1, plane_isect_1_other,
		                       plane_isect_2, plane_isect_2_other,
		                       plane_isect_pt_1, plane_isect_pt_2) == 0)
		{
			return FALSE;
		}
		else {
			float cam_plane_no[3]= {0.0f, 0.0f, -1.0f};
			float plane_isect_delta[3];
			float plane_isect_delta_len;

			mul_m3_v3(rot_obmat, cam_plane_no);

			sub_v3_v3v3(plane_isect_delta, plane_isect_pt_2, plane_isect_pt_1);
			plane_isect_delta_len= len_v3(plane_isect_delta);

			if (dot_v3v3(plane_isect_delta, cam_plane_no) > 0.0f) {
				copy_v3_v3(r_co, plane_isect_pt_1);

				/* offset shift */
				normalize_v3(plane_isect_1_no);
				madd_v3_v3fl(r_co, plane_isect_1_no, shift[1] * -plane_isect_delta_len);
			}
			else {
				copy_v3_v3(r_co, plane_isect_pt_2);

				/* offset shift */
				normalize_v3(plane_isect_2_no);
				madd_v3_v3fl(r_co, plane_isect_2_no, shift[0] * -plane_isect_delta_len);
			}


			return TRUE;
		}
	}
}