Exemple #1
0
static Bool NLD_GetMatrix(M_NonLinearDeformer *nld, GF_Matrix *mx)
{
	SFVec3f v1, v2;
	SFRotation r;
	Fixed l1, l2, dot;

	/*compute rotation matrix from NLD axis to 0 0 1*/
	v1 = nld->axis;
	gf_vec_norm(&v1);
	v2.x = v2.y = 0;
	v2.z = FIX_ONE;
	if (gf_vec_equal(v1, v2)) return 0;

	l1 = gf_vec_len(v1);
	l2 = gf_vec_len(v2);
	dot = gf_divfix(gf_vec_dot(v1, v2), gf_mulfix(l1, l2));

	r.x = gf_mulfix(v1.y, v2.z) - gf_mulfix(v2.y, v1.z);
	r.y = gf_mulfix(v1.z, v2.x) - gf_mulfix(v2.z, v1.x);
	r.z = gf_mulfix(v1.x, v2.y) - gf_mulfix(v2.x, v1.y);
	r.q = gf_atan2(gf_sqrt(FIX_ONE - gf_mulfix(dot, dot)), dot);
	gf_mx_init(*mx);
	gf_mx_add_rotation(mx, r.q, r.x, r.y, r.z);
	return 1;
}
Exemple #2
0
static void camera_frustum_from_matrix(GF_Camera *cam, GF_Matrix *mx)
{
	u32 i;

	cam->planes[FRUS_LEFT_PLANE].normal.x = mx->m[3] + mx->m[0];
	cam->planes[FRUS_LEFT_PLANE].normal.y = mx->m[7] + mx->m[4];
	cam->planes[FRUS_LEFT_PLANE].normal.z = mx->m[11] + mx->m[8];
	cam->planes[FRUS_LEFT_PLANE].d = mx->m[15] + mx->m[12];

	cam->planes[FRUS_RIGHT_PLANE].normal.x = mx->m[3] - mx->m[0];
	cam->planes[FRUS_RIGHT_PLANE].normal.y = mx->m[7] - mx->m[4];
	cam->planes[FRUS_RIGHT_PLANE].normal.z = mx->m[11] - mx->m[8];
	cam->planes[FRUS_RIGHT_PLANE].d = mx->m[15] - mx->m[12];

	cam->planes[FRUS_BOTTOM_PLANE].normal.x = mx->m[3] + mx->m[1];
	cam->planes[FRUS_BOTTOM_PLANE].normal.y = mx->m[7] + mx->m[5];
	cam->planes[FRUS_BOTTOM_PLANE].normal.z = mx->m[11] + mx->m[9];
	cam->planes[FRUS_BOTTOM_PLANE].d = mx->m[15] + mx->m[13];

	cam->planes[FRUS_TOP_PLANE].normal.x = mx->m[3] - mx->m[1];
	cam->planes[FRUS_TOP_PLANE].normal.y = mx->m[7] - mx->m[5];
	cam->planes[FRUS_TOP_PLANE].normal.z = mx->m[11] - mx->m[9];
	cam->planes[FRUS_TOP_PLANE].d = mx->m[15] - mx->m[13];

	cam->planes[FRUS_FAR_PLANE].normal.x = mx->m[3] - mx->m[2];
	cam->planes[FRUS_FAR_PLANE].normal.y = mx->m[7] - mx->m[6];
	cam->planes[FRUS_FAR_PLANE].normal.z = mx->m[11] - mx->m[10];
	cam->planes[FRUS_FAR_PLANE].d = mx->m[15] - mx->m[14];

	cam->planes[FRUS_NEAR_PLANE].normal.x = mx->m[3] + mx->m[2];
	cam->planes[FRUS_NEAR_PLANE].normal.y = mx->m[7] + mx->m[6];
	cam->planes[FRUS_NEAR_PLANE].normal.z = mx->m[11] + mx->m[10];
	cam->planes[FRUS_NEAR_PLANE].d = mx->m[15] + mx->m[14];

	for (i=0; i<6; ++i) {
#ifdef GPAC_FIXED_POINT
		/*after some testing, it's just safer to move back to float here, the smallest drift will
		result in completely wrong culling...*/
		Float vx, vy, vz, nor;
		vx = FIX2FLT(cam->planes[i].normal.x);
		vy = FIX2FLT(cam->planes[i].normal.y);
		vz = FIX2FLT(cam->planes[i].normal.z);
		nor = (Float) sqrt(vx*vx + vy*vy + vz*vz);
		vx /= nor;
		vy /= nor;
		vz /= nor;
		cam->planes[i].d = FLT2FIX (FIX2FLT(cam->planes[i].d) / nor);
		cam->planes[i].normal.x = FLT2FIX(vx);
		cam->planes[i].normal.y = FLT2FIX(vy);
		cam->planes[i].normal.z = FLT2FIX(vz);
#else
		Float len = (Float)(1.0f / gf_vec_len(cam->planes[i].normal));
		cam->planes[i].normal = gf_vec_scale(cam->planes[i].normal, len);
		cam->planes[i].d *= len;
#endif

		/*compute p-vertex idx*/
		cam->p_idx[i] = gf_plane_get_p_vertex_idx(&cam->planes[i]);
	}
}
Exemple #3
0
static void TraverseFog(GF_Node *node, void *rs, Bool is_destroy)
{
	Fixed density, vrange;
	SFVec3f start, end;
	ViewStack *vp_st;
	M_Viewpoint *vp;
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;
	M_Fog *fog = (M_Fog *) node;
	ViewStack *st = (ViewStack *) gf_node_get_private(node);

	if (is_destroy) {
		DestroyViewStack(node);
		return;
	}

	if (!tr_state->fogs) return;

	/*first traverse, bound if needed*/
	if (gf_list_find(tr_state->fogs, node) < 0) {
		gf_list_add(tr_state->fogs, node);
		if (gf_list_get(tr_state->fogs, 0) == fog) {
			if (!fog->isBound) Bindable_SetIsBound(node, 1);
		}
		assert(gf_list_find(st->reg_stacks, tr_state->fogs)==-1);
		gf_list_add(st->reg_stacks, tr_state->fogs);

		gf_mx_copy(st->world_view_mx, tr_state->model_matrix);
		/*in any case don't draw the first time*/
		gf_sc_invalidate(tr_state->visual->compositor, NULL);
		return;
	}
	/*not evaluating, return*/
	if (tr_state->traversing_mode != TRAVERSE_BINDABLE) {
		if ((tr_state->traversing_mode==TRAVERSE_SORT) || (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) )
			gf_mx_copy(st->world_view_mx, tr_state->model_matrix);
		return;
	}
	/*not bound*/
	if (!fog->isBound || !fog->visibilityRange) return;

	/*fog visibility is expressed in current bound VP so get its matrix*/
	vp = (M_Viewpoint*)gf_list_get(tr_state->viewpoints, 0);
	vp_st = NULL;
	if (vp && vp->isBound) vp_st = (ViewStack *) gf_node_get_private((GF_Node *)vp);

	start.x = start.y = start.z = 0;
	end.x = end.y = 0;
	end.z = fog->visibilityRange;
	if (vp_st) {
		gf_mx_apply_vec(&vp_st->world_view_mx, &start);
		gf_mx_apply_vec(&vp_st->world_view_mx, &end);
	}
	gf_mx_apply_vec(&st->world_view_mx, &start);
	gf_mx_apply_vec(&st->world_view_mx, &end);
	gf_vec_diff(end, end, start);
	vrange = gf_vec_len(end);

	density = gf_invfix(vrange);
	visual_3d_set_fog(tr_state->visual, fog->fogType.buffer, fog->color, density, vrange);
}
Exemple #4
0
static void TraverseNavigationInfo(GF_Node *node, void *rs, Bool is_destroy)
{
	u32 i;
#ifndef GPAC_DISABLE_3D
	u32 nb_select_mode;
	SFVec3f start, end;
	Fixed scale;
	ViewStack *st = (ViewStack *) gf_node_get_private(node);
#endif
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;
	M_NavigationInfo *ni = (M_NavigationInfo *) node;

	if (is_destroy) {
		DestroyViewStack(node);
		return;
	}
#ifdef GPAC_DISABLE_3D

	/*FIXME, we only deal with one node, no bind stack for the current time*/
	for (i=0; i<ni->type.count; i++) {
		if (ni->type.vals[i] && !stricmp(ni->type.vals[i], "NONE")) {
			tr_state->visual->compositor->navigation_disabled = 1;
		}
	}
#else

	if (!tr_state->navigations) return;

	/*first traverse, bound if needed*/
	if (gf_list_find(tr_state->navigations, node) < 0) {
		gf_list_add(tr_state->navigations, node);
		if (gf_list_get(tr_state->navigations, 0) == ni) {
			if (!ni->isBound) Bindable_SetIsBound(node, 1);
		}
		assert(gf_list_find(st->reg_stacks, tr_state->navigations)==-1);
		gf_list_add(st->reg_stacks, tr_state->navigations);
		gf_mx_copy(st->world_view_mx, tr_state->model_matrix);
		/*in any case don't draw the first time*/
		gf_sc_invalidate(tr_state->visual->compositor, NULL);
		return;
	}
	/*not bound*/
	if (!ni->isBound) return;
	/*not evaluating, return*/
	if (tr_state->traversing_mode != TRAVERSE_BINDABLE) {
		if ((tr_state->traversing_mode==TRAVERSE_SORT) || (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) ) {
			if (!gf_mx_equal(&st->world_view_mx, &tr_state->model_matrix)) {
				gf_mx_copy(st->world_view_mx, tr_state->model_matrix);
				gf_node_dirty_set(node, 0, 0);
			}
		}
		return;
	}

	if (!gf_node_dirty_get(node)) return;
	gf_node_dirty_clear(node, 0);

	nb_select_mode = 0;
	tr_state->camera->navigation_flags = 0;
	tr_state->camera->navigate_mode = 0;
	for (i=0; i<ni->type.count; i++) {
		if (ni->type.vals[i] && !stricmp(ni->type.vals[i], "ANY")) tr_state->camera->navigation_flags |= NAV_ANY;
		else {
			nb_select_mode++;
		}

		if (!tr_state->camera->navigate_mode) {
			if (ni->type.vals[i] && !stricmp(ni->type.vals[i], "NONE")) tr_state->camera->navigate_mode = GF_NAVIGATE_NONE;
			else if (ni->type.vals[i] && !stricmp(ni->type.vals[i], "WALK")) tr_state->camera->navigate_mode = GF_NAVIGATE_WALK;
			else if (ni->type.vals[i] && !stricmp(ni->type.vals[i], "EXAMINE")) tr_state->camera->navigate_mode = GF_NAVIGATE_EXAMINE;
			else if (ni->type.vals[i] && !stricmp(ni->type.vals[i], "FLY")) tr_state->camera->navigate_mode = GF_NAVIGATE_FLY;
			else if (ni->type.vals[i] && !stricmp(ni->type.vals[i], "VR")) tr_state->camera->navigate_mode = GF_NAVIGATE_VR;
		}
	}
	if (nb_select_mode>1) tr_state->camera->navigation_flags |= NAV_SELECTABLE;

	if (ni->headlight) tr_state->camera->navigation_flags |= NAV_HEADLIGHT;

	start.x = start.y = start.z = 0;
	end.x = end.y = 0;
	end.z = FIX_ONE;
	gf_mx_apply_vec(&st->world_view_mx, &start);
	gf_mx_apply_vec(&st->world_view_mx, &end);
	gf_vec_diff(end, end, start);
	scale = gf_vec_len(end);

	tr_state->camera->speed = gf_mulfix(scale, ni->speed);
	tr_state->camera->visibility = gf_mulfix(scale, ni->visibilityLimit);
	if (ni->avatarSize.count) tr_state->camera->avatar_size.x = gf_mulfix(scale, ni->avatarSize.vals[0]);
	if (ni->avatarSize.count>1) tr_state->camera->avatar_size.y = gf_mulfix(scale, ni->avatarSize.vals[1]);
	if (ni->avatarSize.count>2) tr_state->camera->avatar_size.z = gf_mulfix(scale, ni->avatarSize.vals[2]);

	if (0 && tr_state->pixel_metrics) {
		u32 s = MAX(tr_state->visual->width, tr_state->visual->height);
		s /= 2;
//		tr_state->camera->speed = ni->speed;
		tr_state->camera->visibility *= s;
		tr_state->camera->avatar_size.x *= s;
		tr_state->camera->avatar_size.y *= s;
		tr_state->camera->avatar_size.z *= s;
	}
#endif

}
Exemple #5
0
static void TraverseLOD(GF_Node *node, void *rs, Bool is_destroy)
{
	GF_ChildNodeItem *children;
	MFFloat *ranges;
	SFVec3f pos, usr;
	u32 which_child, nb_children;
	Fixed dist;
	Bool do_all;
	GF_Matrix mx;
	SFVec3f center;
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;
	s32 *prev_child = (s32 *)gf_node_get_private(node);

	if (is_destroy) {
		gf_free(prev_child);
		gf_sc_check_focus_upon_destroy(node);
		return;
	}

	/*WARNING: X3D/MPEG4 NOT COMPATIBLE*/
	if (gf_node_get_tag(node) == TAG_MPEG4_LOD) {
		children = ((M_LOD *) node)->level;
		ranges = &((M_LOD *) node)->range;
		center = ((M_LOD *) node)->center;
#ifndef GPAC_DISABLE_X3D
	} else {
		children = ((X_LOD *) node)->children;
		ranges = &((X_LOD *) node)->range;
		center = ((X_LOD *) node)->center;
#endif
	}

	if (!children) return;
	nb_children = gf_node_list_get_count(children);

	if (!tr_state->camera) {
		do_all = 1;
		which_child = 0;
	} else {
		/*can't cache the matrix here*/
		usr = tr_state->camera->position;
		pos = center;
		gf_mx_copy(mx, tr_state->model_matrix);
		gf_mx_inverse(&mx);
		gf_mx_apply_vec(&mx, &usr);
		gf_vec_diff(pos, pos, usr);
		dist = gf_vec_len(pos);
		for (which_child=0; which_child<ranges->count; which_child++) {
			if (dist<ranges->vals[which_child]) break;
		}
		if (which_child>=nb_children) which_child = nb_children-1;

		/*check if we're traversing the same child or not for audio rendering*/
		do_all = 0;
		if (gf_node_dirty_get(node)) {
			gf_node_dirty_clear(node, 0);
			do_all = 1;
		} else if ((s32) which_child != *prev_child) {
			*prev_child = which_child;
			do_all = 1;
		}
	}

	if (do_all) {
		u32 i;
		Bool prev_switch = tr_state->switched_off;
		GF_ChildNodeItem *l = children;
		tr_state->switched_off = 1;
		i=0;
		while (l) {
			if (i!=which_child) gf_node_traverse(l->node, rs);
			l = l->next;
		}
		tr_state->switched_off = prev_switch;
	}
	gf_node_traverse(gf_node_list_get_child(children, which_child), rs);
}
Exemple #6
0
static void TraverseBillboard(GF_Node *n, void *rs, Bool is_destroy)
{
	GF_Matrix gf_mx_bckup;
	TransformStack *st = (TransformStack *)gf_node_get_private(n);
	M_Billboard *bb = (M_Billboard *)n;
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;

	if (is_destroy) {
		DestroyTransform(n);
		return;
	}
	if (! tr_state->camera) return;

	/*can't cache the matrix here*/
	gf_mx_init(st->mx);
	if (tr_state->camera->is_3D) {
		SFVec3f z, axis;
		Fixed axis_len;
		SFVec3f user_pos = tr_state->camera->position;

		gf_mx_apply_vec(&tr_state->model_matrix, &user_pos);
		gf_vec_norm(&user_pos);
		axis = bb->axisOfRotation;
		axis_len = gf_vec_len(axis);
		if (axis_len<FIX_EPSILON) {
			SFVec3f x, y, t;
			/*get user's right in local coord*/
			gf_vec_diff(t, tr_state->camera->position, tr_state->camera->target);
			gf_vec_norm(&t);
			x = gf_vec_cross(tr_state->camera->up, t);
			gf_vec_norm(&x);
			gf_mx_rotate_vector(&tr_state->model_matrix, &x);
			gf_vec_norm(&x);
			/*get user's up in local coord*/
			y = tr_state->camera->up;
			gf_mx_rotate_vector(&tr_state->model_matrix, &y);
			gf_vec_norm(&y);
			z = gf_vec_cross(x, y);
			gf_vec_norm(&z);

			gf_mx_rotation_matrix_from_vectors(&st->mx, x, y, z);
			gf_mx_inverse(&st->mx);
		} else {
			SFVec3f tmp;
			Fixed d, cosw, sinw, angle;
			gf_vec_norm(&axis);
			/*map eye & z into plane with normal axis through 0.0*/
			d = -gf_vec_dot(axis, user_pos);
			tmp = gf_vec_scale(axis, d);
			gf_vec_add(user_pos, user_pos, tmp);
			gf_vec_norm(&user_pos);

			z.x = z.y = 0;
			z.z = FIX_ONE;
			d = -gf_vec_dot(axis, z);
			tmp = gf_vec_scale(axis, d);
			gf_vec_add(z, z, tmp);
			gf_vec_norm(&z);

			cosw = gf_vec_dot(user_pos, z);
			tmp = gf_vec_cross(user_pos, z);
			sinw = gf_vec_len(tmp);
			angle = gf_acos(cosw);
			gf_vec_norm(&tmp);
			if ((sinw>0) && (gf_vec_dot(axis, tmp) > 0)) gf_vec_rev(axis);
			gf_mx_add_rotation(&st->mx, angle, axis.x, axis.y, axis.z);
		}
	}

	gf_mx_copy(gf_mx_bckup, tr_state->model_matrix);
	gf_mx_add_matrix(&tr_state->model_matrix, &st->mx);

	/*note we don't clear dirty flag, this is done in traversing*/
	group_3d_traverse(n, (GroupingNode *) st, tr_state);

	gf_mx_copy(tr_state->model_matrix, gf_mx_bckup);

	if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) gf_mx_apply_bbox(&st->mx, &tr_state->bbox);
}
Exemple #7
0
Bool gf_sc_fit_world_to_screen(GF_Compositor *compositor)
{
	GF_TraverseState tr_state;
	SFVec3f pos, diff;
	Fixed dist, d;
	GF_Camera *cam;
	GF_Node *top;

#ifndef GPAC_DISABLE_VRML
//	if (gf_list_count(compositor->visual->back_stack)) return;
	if (gf_list_count(compositor->visual->view_stack)) return 0;
#endif

	gf_mx_p(compositor->mx);
	top = gf_sg_get_root_node(compositor->scene);
	if (!top) {
		gf_mx_v(compositor->mx);
		return 0;
	}
	memset(&tr_state, 0, sizeof(GF_TraverseState));
	gf_mx_init(tr_state.model_matrix);
	tr_state.traversing_mode = TRAVERSE_GET_BOUNDS;
	tr_state.visual = compositor->visual;
	gf_node_traverse(top, &tr_state);
	if (gf_node_dirty_get(top)) {
		tr_state.bbox.is_set = 0;
	}

	if (!tr_state.bbox.is_set) {
		gf_mx_v(compositor->mx);
		/*empty world ...*/
		if (tr_state.bbox.radius==-1) return 1;
		/*2D world with 3D camera forced*/
		if (tr_state.bounds.width&&tr_state.bounds.height) return 1;
		return 0;
	}

	cam = &compositor->visual->camera;

	cam->world_bbox = tr_state.bbox;
	/*fit is based on bounding sphere*/
	dist = gf_divfix(tr_state.bbox.radius, gf_sin(cam->fieldOfView/2) );
	gf_vec_diff(diff, cam->center, tr_state.bbox.center);
	/*do not update if camera is outside the scene bounding sphere and dist is too close*/
	if (gf_vec_len(diff) > tr_state.bbox.radius + cam->radius) {
		gf_vec_diff(diff, cam->vp_position, tr_state.bbox.center);
		d = gf_vec_len(diff);
		if (d<dist) {
			gf_mx_v(compositor->mx);
			return 1;
		}
	}

	diff = gf_vec_scale(camera_get_pos_dir(cam), dist);
	gf_vec_add(pos, tr_state.bbox.center, diff);
	diff = cam->position;
	camera_set_vectors(cam, pos, cam->vp_orientation, cam->fieldOfView);
	cam->position = diff;
	camera_move_to(cam, pos, cam->target, cam->up);
	cam->examine_center = tr_state.bbox.center;
	cam->flags |= CF_STORE_VP;
	if (cam->z_far < dist) cam->z_far = 10*dist;
	camera_changed(compositor, cam);
	gf_mx_v(compositor->mx);
	return 1;
}
Exemple #8
0
static void TraversePlanarExtrusion(GF_Node *node, void *rs, Bool is_destroy)
{
    PlanarExtrusion plane_ext;
    Drawable *stack_2d;
    u32 i, j, k;
    MFVec3f spine_vec;
    SFVec3f d;
    Fixed spine_len;
    GF_Rect bounds;
    GF_Path *geo, *spine;
    GF_TraverseState *tr_state = (GF_TraverseState *)rs;
    Drawable3D *stack = (Drawable3D *)gf_node_get_private(node);

    if (is_destroy) {
        drawable_3d_del(node);
        return;
    }

    if (!PlanarExtrusion_GetNode(node, &plane_ext)) return;
    if (!plane_ext.geometry || !plane_ext.spine) return;


    if (gf_node_dirty_get(node)) {
        u32 cur, nb_pts;
        u32 mode = tr_state->traversing_mode;
        geo = spine = NULL;

        tr_state->traversing_mode = TRAVERSE_GET_BOUNDS;
        gf_node_traverse(plane_ext.geometry, tr_state);
        gf_node_traverse(plane_ext.spine, tr_state);
        tr_state->traversing_mode = mode;

        switch (gf_node_get_tag(plane_ext.geometry) ) {
        case TAG_MPEG4_Circle:
        case TAG_MPEG4_Ellipse:
        case TAG_MPEG4_Rectangle:
        case TAG_MPEG4_Curve2D:
        case TAG_MPEG4_XCurve2D:
        case TAG_MPEG4_IndexedFaceSet2D:
        case TAG_MPEG4_IndexedLineSet2D:
            stack_2d = (Drawable*)gf_node_get_private(plane_ext.geometry);
            if (stack_2d) geo = stack_2d->path;
            break;
        default:
            return;
        }
        switch (gf_node_get_tag(plane_ext.spine) ) {
        case TAG_MPEG4_Circle:
        case TAG_MPEG4_Ellipse:
        case TAG_MPEG4_Rectangle:
        case TAG_MPEG4_Curve2D:
        case TAG_MPEG4_XCurve2D:
        case TAG_MPEG4_IndexedFaceSet2D:
        case TAG_MPEG4_IndexedLineSet2D:
            stack_2d = (Drawable*)gf_node_get_private(plane_ext.spine);
            if (stack_2d) spine = stack_2d->path;
            break;
        default:
            return;
        }
        if (!geo || !spine) return;

        mesh_reset(stack->mesh);
        gf_path_flatten(spine);
        gf_path_get_bounds(spine, &bounds);
        gf_path_flatten(geo);
        gf_path_get_bounds(geo, &bounds);

        cur = 0;
        for (i=0; i<spine->n_contours; i++) {
            nb_pts = 1 + spine->contours[i] - cur;
            spine_vec.vals = NULL;
            gf_sg_vrml_mf_alloc(&spine_vec, GF_SG_VRML_MFVEC3F, nb_pts);
            spine_len = 0;
            for (j=cur; j<nb_pts; j++) {
                spine_vec.vals[j].x = spine->points[j].x;
                spine_vec.vals[j].y = spine->points[j].y;
                spine_vec.vals[j].z = 0;
                if (j) {
                    gf_vec_diff(d, spine_vec.vals[j], spine_vec.vals[j-1]);
                    spine_len += gf_vec_len(d);
                }
            }
            cur += nb_pts;
            if (!plane_ext.orientation->count && !plane_ext.scale->count) {
                mesh_extrude_path_ext(stack->mesh, geo, &spine_vec, plane_ext.creaseAngle,
                                      bounds.x, bounds.y-bounds.height, bounds.width, bounds.height,
                                      plane_ext.beginCap, plane_ext.endCap, NULL, NULL, plane_ext.txAlongSpine);
            }
            /*interpolate orientation and scale along subpath line*/
            else {
                MFRotation ori;
                MFVec2f scale;
                Fixed cur_len, frac;

                ori.vals = NULL;
                gf_sg_vrml_mf_alloc(&ori, GF_SG_VRML_MFROTATION, nb_pts);
                scale.vals = NULL;
                gf_sg_vrml_mf_alloc(&scale, GF_SG_VRML_MFVEC2F, nb_pts);
                cur_len = 0;
                if (!plane_ext.orientation->count) ori.vals[0].y = FIX_ONE;
                if (!plane_ext.scale->count) scale.vals[0].x = scale.vals[0].y = FIX_ONE;
                for (j=0; j<nb_pts; j++) {
                    if (j) {
                        gf_vec_diff(d, spine_vec.vals[j], spine_vec.vals[j-1]);
                        cur_len += gf_vec_len(d);
                        ori.vals[j] = ori.vals[j-1];
                        scale.vals[j] = scale.vals[j-1];
                    }

                    if (plane_ext.orientation->count && (plane_ext.orientation->count == plane_ext.orientationKeys->count)) {

                        frac = gf_divfix(cur_len , spine_len);
                        if (frac < plane_ext.orientationKeys->vals[0]) ori.vals[j] = plane_ext.orientation->vals[0];
                        else if (frac >= plane_ext.orientationKeys->vals[plane_ext.orientationKeys->count-1]) ori.vals[j] = plane_ext.orientation->vals[plane_ext.orientationKeys->count-1];
                        else {
                            for (k=1; k<plane_ext.orientationKeys->count; k++) {
                                Fixed kDiff = plane_ext.orientationKeys->vals[k] - plane_ext.orientationKeys->vals[k-1];
                                if (!kDiff) continue;
                                if (frac < plane_ext.orientationKeys->vals[k-1]) continue;
                                if (frac > plane_ext.orientationKeys->vals[k]) continue;
                                frac = gf_divfix(frac - plane_ext.orientationKeys->vals[k-1], kDiff);
                                break;
                            }
                            ori.vals[j] = gf_sg_sfrotation_interpolate(plane_ext.orientation->vals[k-1], plane_ext.orientation->vals[k], frac);
                        }
                    }

                    if (plane_ext.scale->count == plane_ext.scaleKeys->count) {
                        frac = gf_divfix(cur_len , spine_len);
                        if (frac <= plane_ext.scaleKeys->vals[0]) scale.vals[j] = plane_ext.scale->vals[0];
                        else if (frac >= plane_ext.scaleKeys->vals[plane_ext.scaleKeys->count-1]) scale.vals[j] = plane_ext.scale->vals[plane_ext.scale->count-1];
                        else {
                            for (k=1; k<plane_ext.scaleKeys->count; k++) {
                                Fixed kDiff = plane_ext.scaleKeys->vals[k] - plane_ext.scaleKeys->vals[k-1];
                                if (!kDiff) continue;
                                if (frac < plane_ext.scaleKeys->vals[k-1]) continue;
                                if (frac > plane_ext.scaleKeys->vals[k]) continue;
                                frac = gf_divfix(frac - plane_ext.scaleKeys->vals[k-1], kDiff);
                                break;
                            }
                            scale.vals[j].x = gf_mulfix(plane_ext.scale->vals[k].x - plane_ext.scale->vals[k-1].x, frac) + plane_ext.scale->vals[k-1].x;
                            scale.vals[j].y = gf_mulfix(plane_ext.scale->vals[k].y - plane_ext.scale->vals[k-1].y, frac) + plane_ext.scale->vals[k-1].y;
                        }
                    }
                }

                mesh_extrude_path_ext(stack->mesh, geo, &spine_vec, plane_ext.creaseAngle,
                                      bounds.x, bounds.y-bounds.height, bounds.width, bounds.height,
                                      plane_ext.beginCap, plane_ext.endCap, &ori, &scale, plane_ext.txAlongSpine);

                gf_sg_vrml_mf_reset(&ori, GF_SG_VRML_MFROTATION);
                gf_sg_vrml_mf_reset(&scale, GF_SG_VRML_MFVEC2F);
            }

            gf_sg_vrml_mf_reset(&spine_vec, GF_SG_VRML_MFVEC3F);
        }
        mesh_update_bounds(stack->mesh);
        gf_mesh_build_aabbtree(stack->mesh);
    }

    if (tr_state->traversing_mode==TRAVERSE_DRAW_3D) {
        visual_3d_draw(tr_state, stack->mesh);
    } else if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
        tr_state->bbox = stack->mesh->bounds;
    }
}
Exemple #9
0
void camera_update_stereo(GF_Camera *cam, GF_Matrix2D *user_transform, Bool center_coords, Fixed horizontal_shift, Fixed nominal_view_distance, Fixed view_distance_offset, u32 camera_layout)
{
	Fixed vlen, h, w, ar;
	SFVec3f corner, center;
	GF_Matrix post_model_view;

	if (! (cam->flags & CAM_IS_DIRTY)) return;

	ar = gf_divfix(cam->width, cam->height);
	gf_mx_init(post_model_view);

	if (cam->is_3D) {
		/*setup perspective*/
		if (camera_layout==GF_3D_CAMERA_OFFAXIS) {
			Fixed left, right, top, bottom, shift, wd2, ndfl, viewing_distance;
			SFVec3f eye, pos, tar, disp;

			viewing_distance = nominal_view_distance;

			wd2 = gf_mulfix(cam->z_near, gf_tan(cam->fieldOfView/2));
			ndfl = gf_divfix(cam->z_near, viewing_distance);
			/*compute h displacement*/
			shift = gf_mulfix(horizontal_shift, ndfl);

			top = wd2;
			bottom = -top;
			left = -gf_mulfix(ar, wd2) - shift;
			right = gf_mulfix(ar, wd2) - shift;

			gf_mx_init(cam->projection);
			cam->projection.m[0] = gf_divfix(2*cam->z_near, (right-left));
			cam->projection.m[5] = gf_divfix(2*cam->z_near, (top-bottom));
			cam->projection.m[8] = gf_divfix(right+left, right-left);
			cam->projection.m[9] = gf_divfix(top+bottom, top-bottom);
			cam->projection.m[10] = gf_divfix(cam->z_far+cam->z_near, cam->z_near-cam->z_far);
			cam->projection.m[11] = -FIX_ONE;
			cam->projection.m[14] = 2*gf_muldiv(cam->z_near, cam->z_far, cam->z_near-cam->z_far);
			cam->projection.m[15] = 0;

			gf_vec_diff(eye, cam->target, cam->position);
			gf_vec_norm(&eye);
			disp = gf_vec_cross(eye, cam->up);
			gf_vec_norm(&disp);

			gf_vec_diff(center, cam->world_bbox.center, cam->position);
			vlen = gf_vec_len(center);
			shift = gf_mulfix(horizontal_shift, gf_divfix(vlen, viewing_distance));

			pos = gf_vec_scale(disp, shift);
			gf_vec_add(pos, pos, cam->position);
			gf_vec_add(tar, pos, eye);

			/*setup modelview*/
			gf_mx_lookat(&cam->modelview, pos, tar, cam->up);
		} else {
			gf_mx_perspective(&cam->projection, cam->fieldOfView, ar, cam->z_near, cam->z_far);

			/*setup modelview*/
			gf_mx_lookat(&cam->modelview, cam->position, cam->target, cam->up);
		}

		if (!center_coords) {
			gf_mx_add_scale(&post_model_view, FIX_ONE, -FIX_ONE, FIX_ONE);
			gf_mx_add_translation(&post_model_view, -cam->width / 2, -cam->height / 2, 0);
		}

		/*compute center and radius - CHECK ME!*/
		vlen = cam->z_far - cam->z_near;
		h = gf_mulfix(vlen , gf_tan(cam->fieldOfView / 2));
		w = gf_mulfix(h, ar);
		center.x = 0;
		center.y = 0;
		center.z = cam->z_near + vlen / 2;
		corner.x = w;
		corner.y = h;
		corner.z = vlen;
		gf_vec_diff(corner, corner, center);
		cam->radius = gf_vec_len(corner);
		gf_vec_diff(cam->center, cam->target, cam->position);
		gf_vec_norm(&cam->center);
		cam->center = gf_vec_scale(cam->center, cam->z_near + vlen/2);
		gf_vec_add(cam->center, cam->center, cam->position);
	} else {
		GF_BBox b;
		Fixed hw, hh;
		hw = cam->width / 2;
		hh = cam->height / 2;
		cam->z_near = INT2FIX(NEAR_PLANE_2D);
		cam->z_far = INT2FIX(FAR_PLANE_2D);

		/*setup ortho*/
		gf_mx_ortho(&cam->projection, -hw, hw, -hh, hh, cam->z_near, cam->z_far);

		/*setup modelview*/
		gf_mx_init(cam->modelview);
#ifdef FORCE_CAMERA_3D
		if (! (cam->flags & CAM_NO_LOOKAT))
			gf_mx_lookat(&cam->modelview, cam->position, cam->target, cam->up);
#endif

		if (!center_coords) {
			gf_mx_add_scale(&post_model_view, FIX_ONE, -FIX_ONE, FIX_ONE);
			gf_mx_add_translation(&post_model_view, -hw, -hh, 0);
		}
		if (user_transform) {
#ifdef FORCE_CAMERA_3D
			if (! (cam->flags & CAM_NO_LOOKAT)) {
				GF_Matrix mx;
				gf_mx_from_mx2d(&mx, user_transform);
				mx.m[10] = mx.m[0];
				gf_mx_add_matrix(&post_model_view, &mx);
			} else
#endif
				gf_mx_add_matrix_2d(&post_model_view, user_transform);
		}
		if (cam->end_zoom != FIX_ONE) gf_mx_add_scale(&post_model_view, cam->end_zoom, cam->end_zoom, cam->end_zoom);
		if (cam->flags & CAM_HAS_VIEWPORT) gf_mx_add_matrix(&post_model_view, &cam->viewport);

		/*compute center & radius*/
		b.max_edge.x = hw;
		b.max_edge.y = hh;
		b.min_edge.x = -hw;
		b.min_edge.y = -hh;
		b.min_edge.z = b.max_edge.z = (cam->z_near+cam->z_far) / 2;
		gf_bbox_refresh(&b);
		cam->center = b.center;
		cam->radius = b.radius;

		if (camera_layout==GF_3D_CAMERA_OFFAXIS)
			camera_layout=GF_3D_CAMERA_LINEAR;
	}

	if (camera_layout == GF_3D_CAMERA_CIRCULAR) {
		GF_Matrix mx;
		Fixed viewing_distance = nominal_view_distance;
		SFVec3f pos, target;
		Fixed angle;

		gf_vec_diff(center, cam->world_bbox.center, cam->position);
		vlen = gf_vec_len(center);
		vlen += gf_mulfix(view_distance_offset, gf_divfix(vlen, nominal_view_distance));

		gf_vec_diff(pos, cam->target, cam->position);
		gf_vec_norm(&pos);
		pos = gf_vec_scale(pos, vlen);
		gf_vec_add(target, pos, cam->position);

		gf_mx_init(mx);
		gf_mx_add_translation(&mx, target.x, target.y, target.z);
		angle = gf_atan2(horizontal_shift, viewing_distance);
		gf_mx_add_rotation(&mx, angle, cam->up.x, cam->up.y, cam->up.z);
		gf_mx_add_translation(&mx, -target.x, -target.y, -target.z);

		pos = cam->position;
		gf_mx_apply_vec(&mx, &pos);

		gf_mx_lookat(&cam->modelview, pos, target, cam->up);
	} else if (camera_layout == GF_3D_CAMERA_LINEAR) {
		Fixed viewing_distance = nominal_view_distance + view_distance_offset;
		GF_Vec eye, disp, pos, tar;

		gf_vec_diff(center, cam->world_bbox.center, cam->position);
		vlen = gf_vec_len(center);
		vlen += gf_mulfix(view_distance_offset, gf_divfix(vlen, nominal_view_distance));

		gf_vec_diff(eye, cam->target, cam->position);
		gf_vec_norm(&eye);
		tar = gf_vec_scale(eye, vlen);
		gf_vec_add(tar, tar, cam->position);

		disp = gf_vec_cross(eye, cam->up);
		gf_vec_norm(&disp);

		disp= gf_vec_scale(disp, gf_divfix(gf_mulfix(vlen, horizontal_shift), viewing_distance));
		gf_vec_add(pos, cam->position, disp);

		gf_mx_lookat(&cam->modelview, pos, tar, cam->up);
	}
	gf_mx_add_matrix(&cam->modelview, &post_model_view);

	/*compute frustum planes*/
	gf_mx_copy(cam->unprojection, cam->projection);
	gf_mx_add_matrix_4x4(&cam->unprojection, &cam->modelview);
	camera_frustum_from_matrix(cam, &cam->unprojection);
	/*also compute reverse PM for unprojections*/
	gf_mx_inverse_4x4(&cam->unprojection);
	cam->flags &= ~CAM_IS_DIRTY;
}
Exemple #10
0
static void TraverseSound(GF_Node *node, void *rs, Bool is_destroy)
{
	GF_TraverseState *tr_state = (GF_TraverseState*) rs;
	M_Sound *snd = (M_Sound *)node;
	SoundStack *st = (SoundStack *)gf_node_get_private(node);

	if (is_destroy) {
		gf_free(st);
		return;
	}
	if (!snd->source) return;

	tr_state->sound_holder = &st->snd_ifce;

	/*forward in case we're switched off*/
	if (tr_state->switched_off) {
		gf_node_traverse((GF_Node *) snd->source, tr_state);
	}
	else if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
		/*we can't cull sound since*/
		tr_state->disable_cull = 1;
	} else if (tr_state->traversing_mode==TRAVERSE_SORT) {
		GF_Matrix mx;
		SFVec3f usr, snd_dir, pos;
		Fixed mag, ang;
		/*this implies no DEF/USE for real location...*/
		gf_mx_copy(st->mx, tr_state->model_matrix);
		gf_mx_copy(mx, tr_state->model_matrix);
		gf_mx_inverse(&mx);

		snd_dir = snd->direction;
		gf_vec_norm(&snd_dir);

		/*get user location*/
		usr = tr_state->camera->position;
		gf_mx_apply_vec(&mx, &usr);

		/*recenter to ellipse focal*/
		gf_vec_diff(usr, usr, snd->location);
		mag = gf_vec_len(usr);
		if (!mag) mag = FIX_ONE/10;
		ang = gf_divfix(gf_vec_dot(snd_dir, usr), mag);
	
		usr.z = gf_mulfix(ang, mag);
		usr.x = gf_sqrt(gf_mulfix(mag, mag) - gf_mulfix(usr.z, usr.z));
		usr.y = 0;
		if (!gf_vec_equal(usr, st->last_pos)) {
			st->intensity = snd_compute_gain(snd->minBack, snd->minFront, snd->maxBack, snd->maxFront, usr);
			st->intensity = gf_mulfix(st->intensity, snd->intensity);
			st->last_pos = usr;
		}
		st->identity = (st->intensity==FIX_ONE) ? 1 : 0;

		if (snd->spatialize) {
			Fixed ang, sign;
			SFVec3f cross;
			pos = snd->location;
			gf_mx_apply_vec(&tr_state->model_matrix, &pos);
			gf_vec_diff(pos, pos, tr_state->camera->position);
			gf_vec_diff(usr, tr_state->camera->target, tr_state->camera->position);
			gf_vec_norm(&pos);
			gf_vec_norm(&usr);

			ang = gf_acos(gf_vec_dot(usr, pos));
			/*get orientation*/
			cross = gf_vec_cross(usr, pos);
			sign = gf_vec_dot(cross, tr_state->camera->up);
			if (sign>0) ang *= -1;
			ang = (FIX_ONE + gf_sin(ang)) / 2;
			st->lgain = (FIX_ONE - gf_mulfix(ang, ang));
			st->rgain = FIX_ONE - gf_mulfix(FIX_ONE - ang, FIX_ONE - ang);
			/*renorm between 0 and 1*/
			st->lgain = gf_mulfix(st->lgain, 4*st->intensity/3);
			st->rgain = gf_mulfix(st->rgain, 4*st->intensity/3);

			if (st->identity && ((st->lgain!=FIX_ONE) || (st->rgain!=FIX_ONE))) st->identity = 0;
		} else {
			st->lgain = st->rgain = FIX_ONE;
		}
		gf_node_traverse((GF_Node *) snd->source, tr_state);
	}

	tr_state->sound_holder = NULL;
}
Exemple #11
0
static Bool OnCylinderSensor(GF_SensorHandler *sh, Bool is_over, Bool is_cancel, GF_Event *ev, GF_Compositor *compositor)
{
	Bool is_mouse = (ev->type<=GF_EVENT_MOUSEWHEEL) ? 1 : 0;
	M_CylinderSensor *cs = (M_CylinderSensor *)sh->sensor;
	CylinderSensorStack *st = (CylinderSensorStack *) gf_node_get_private(sh->sensor);

	if (cs->isActive && (!cs->enabled
	                     || /*mouse*/((ev->type==GF_EVENT_MOUSEUP) && (ev->mouse.button==GF_MOUSE_LEFT))
	                     || /*keyboar*/(!is_mouse && (!is_over|| ((ev->type==GF_EVENT_KEYDOWN) && (ev->key.key_code==GF_KEY_ENTER))))
	                    ) ) {
		if (cs->autoOffset) {
			cs->offset = cs->rotation_changed.q;
			if (!is_cancel) gf_node_event_out(sh->sensor, 5/*"offset"*/);
		}
		cs->isActive = 0;
		if (!is_cancel) gf_node_event_out(sh->sensor, 6/*"isActive"*/);
		sh->grabbed = 0;
		return is_cancel ? 0 : 1;
	}
	else if (is_mouse) {
		if (!cs->isActive && (ev->type==GF_EVENT_MOUSEDOWN) && (ev->mouse.button==GF_MOUSE_LEFT)) {
			GF_Ray r;
			SFVec3f yaxis;
			Fixed acute, reva;
			SFVec3f bearing;

			gf_mx_copy(st->init_matrix, compositor->hit_world_to_local);
			/*get initial angle & check disk mode*/
			r = compositor->hit_world_ray;
			gf_vec_add(r.dir, r.orig, r.dir);
			gf_mx_apply_vec(&compositor->hit_world_to_local, &r.orig);
			gf_mx_apply_vec(&compositor->hit_world_to_local, &r.dir);
			gf_vec_diff(bearing, r.orig, r.dir);
			gf_vec_norm(&bearing);
			yaxis.x = yaxis.z = 0;
			yaxis.y = FIX_ONE;
			acute = gf_vec_dot(bearing, yaxis);
			if (acute < -FIX_ONE) acute = -FIX_ONE;
			else if (acute > FIX_ONE) acute = FIX_ONE;
			acute = gf_acos(acute);
			reva = ABS(GF_PI - acute);
			if (reva<acute) acute = reva;
			st->disk_mode = (acute < cs->diskAngle) ? 1 : 0;

			st->grab_start = compositor->hit_local_point;
			/*cos we're lazy*/
			st->yplane.d = 0;
			st->yplane.normal.x = st->yplane.normal.z = st->yplane.normal.y = 0;
			st->zplane = st->xplane = st->yplane;
			st->xplane.normal.x = FIX_ONE;
			st->yplane.normal.y = FIX_ONE;
			st->zplane.normal.z = FIX_ONE;

			cs->rotation_changed.x = 0;
			cs->rotation_changed.y = FIX_ONE;
			cs->rotation_changed.z = 0;

			cs->isActive = 1;
			gf_node_event_out(sh->sensor, 6/*"isActive"*/);
			sh->grabbed = 1;
			return 1;
		}
		else if (cs->isActive) {
			GF_Ray r;
			Fixed radius, rot;
			SFVec3f dir1, dir2, cx;

			if (is_over) {
				cs->trackPoint_changed = compositor->hit_local_point;
				gf_node_event_out(sh->sensor, 8/*"trackPoint_changed"*/);
			} else {
				GF_Plane project_to;
				r = compositor->hit_world_ray;
				gf_mx_apply_ray(&st->init_matrix, &r);

				/*no intersection, use intersection with "main" fronting plane*/
				if ( ABS(r.dir.z) > ABS(r.dir.y)) {
					if (ABS(r.dir.z) > ABS(r.dir.x)) project_to = st->xplane;
					else project_to = st->yplane;
				} else {
					if (ABS(r.dir.z) > ABS(r.dir.x)) project_to = st->xplane;
					else project_to = st->zplane;
				}
				if (!gf_plane_intersect_line(&project_to, &r.orig, &r.dir, &compositor->hit_local_point)) return 0;
			}

			dir1.x = compositor->hit_local_point.x;
			dir1.y = 0;
			dir1.z = compositor->hit_local_point.z;
			if (st->disk_mode) {
				radius = FIX_ONE;
			} else {
				radius = gf_vec_len(dir1);
			}
			gf_vec_norm(&dir1);
			dir2.x = st->grab_start.x;
			dir2.y = 0;
			dir2.z = st->grab_start.z;
			gf_vec_norm(&dir2);
			cx = gf_vec_cross(dir2, dir1);
			gf_vec_norm(&cx);
			if (gf_vec_len(cx)<FIX_EPSILON) return 0;
			rot = gf_mulfix(radius, gf_acos(gf_vec_dot(dir2, dir1)) );
			if (fabs(cx.y + FIX_ONE) < FIX_EPSILON) rot = -rot;
			if (cs->autoOffset) rot += cs->offset;

			if (cs->minAngle < cs->maxAngle) {
				if (rot < cs->minAngle) rot = cs->minAngle;
				else if (rot > cs->maxAngle) rot = cs->maxAngle;
			}
			cs->rotation_changed.q = rot;
			gf_node_event_out(sh->sensor, 7/*"rotation_changed"*/);
			return 1;
		}
	} else {
		if (!cs->isActive && is_over && (ev->type==GF_EVENT_KEYDOWN) && (ev->key.key_code==GF_KEY_ENTER)) {
			cs->isActive = 1;
			cs->rotation_changed.q = cs->offset;
			cs->rotation_changed.x = cs->rotation_changed.z = 0;
			cs->rotation_changed.y = FIX_ONE;
			gf_node_event_out(sh->sensor, 6/*"isActive"*/);
			return 1;
		}
		else if (cs->isActive && (ev->type==GF_EVENT_KEYDOWN)) {
			SFFloat res;
			Fixed diff = (ev->key.flags & GF_KEY_MOD_SHIFT) ? GF_PI/8 : GF_PI/64;

			res = cs->rotation_changed.q;
			switch (ev->key.key_code) {
			case GF_KEY_LEFT:
				res -= diff;
				break;
			case GF_KEY_RIGHT:
				res += diff;
				break;
			case GF_KEY_HOME:
				res = cs->offset;
				break;
			default:
				return 0;
			}
			/*clip*/
			if (cs->minAngle <= cs->maxAngle) {
				if (res < cs->minAngle) res = cs->minAngle;
				if (res > cs->maxAngle) res = cs->maxAngle;
			}
			cs->rotation_changed.q = res;
			gf_node_event_out(sh->sensor, 7/*"rotation_changed"*/);
			return 1;
		}
	}
	return 0;
}
Exemple #12
0
static Bool OnSphereSensor(GF_SensorHandler *sh, Bool is_over, Bool is_cancel, GF_Event *ev, GF_Compositor *compositor)
{
	Bool is_mouse = (ev->type<=GF_EVENT_MOUSEWHEEL) ? 1 : 0;
	M_SphereSensor *sphere = (M_SphereSensor *)sh->sensor;
	SphereSensorStack *st = (SphereSensorStack *) gf_node_get_private(sh->sensor);


	if (sphere->isActive && (!sphere->enabled
	                         || /*mouse*/((ev->type==GF_EVENT_MOUSEUP) && (ev->mouse.button==GF_MOUSE_LEFT))
	                         || /*keyboar*/(!is_mouse && (!is_over|| ((ev->type==GF_EVENT_KEYDOWN) && (ev->key.key_code==GF_KEY_ENTER))))
	                        ) ) {
		if (sphere->autoOffset) {
			sphere->offset = sphere->rotation_changed;
			if (!is_cancel) gf_node_event_out(sh->sensor, 2/*"offset"*/);
		}
		sphere->isActive = 0;
		if (!is_cancel) gf_node_event_out(sh->sensor, 3/*"isActive"*/);
		sh->grabbed = 0;
		return is_cancel ? 0 : 1;
	}
	else if (is_mouse) {
		if (!sphere->isActive && (ev->type==GF_EVENT_MOUSEDOWN) && (ev->mouse.button==GF_MOUSE_LEFT)) {
			st->center.x = st->center.y = st->center.z = 0;
			gf_mx_apply_vec(&compositor->hit_local_to_world, &st->center);
			st->radius = gf_vec_len(compositor->hit_local_point);
			if (!st->radius) st->radius = FIX_ONE;
			st->grab_vec = gf_vec_scale(compositor->hit_local_point, gf_invfix(st->radius));

			sphere->isActive = 1;
			gf_node_event_out(sh->sensor, 3/*"isActive"*/);
			sh->grabbed = 1;
			return 1;
		}
		else if (sphere->isActive) {
			SFVec3f vec, axis;
			SFVec4f q1, q2;
			SFRotation r;
			Fixed cl;
			if (is_over) {
				sphere->trackPoint_changed = compositor->hit_local_point;
				gf_node_event_out(sh->sensor, 5/*"trackPoint_changed"*/);
			} else {
				GF_Ray r;
				r = compositor->hit_world_ray;
				gf_mx_apply_ray(&compositor->hit_world_to_local, &r);
				if (!gf_ray_hit_sphere(&r, NULL, st->radius, &compositor->hit_local_point)) {
					vec.x = vec.y = vec.z = 0;
					/*doesn't work properly...*/
					compositor->hit_local_point = gf_closest_point_to_line(r.orig, r.dir, vec);
				}
			}

			vec = gf_vec_scale(compositor->hit_local_point, gf_invfix(st->radius));
			axis = gf_vec_cross(st->grab_vec, vec);
			cl = gf_vec_len(axis);

			if (cl < -FIX_ONE) cl = -FIX_ONE;
			else if (cl > FIX_ONE) cl = FIX_ONE;
			r.q = gf_asin(cl);
			if (gf_vec_dot(st->grab_vec, vec) < 0) r.q += GF_PI / 2;

			gf_vec_norm(&axis);
			r.x = axis.x;
			r.y = axis.y;
			r.z = axis.z;
			q1 = gf_quat_from_rotation(r);
			if (sphere->autoOffset) {
				q2 = gf_quat_from_rotation(sphere->offset);
				q1 = gf_quat_multiply(&q1, &q2);
			}
			sphere->rotation_changed = gf_quat_to_rotation(&q1);
			gf_node_event_out(sh->sensor, 4/*"rotation_changed"*/);
			return 1;
		}
	} else {
		if (!sphere->isActive && is_over && (ev->type==GF_EVENT_KEYDOWN) && (ev->key.key_code==GF_KEY_ENTER)) {
			sphere->isActive = 1;
			sphere->rotation_changed = sphere->offset;
			gf_node_event_out(sh->sensor, 3/*"isActive"*/);
			return 1;
		}
		else if (sphere->isActive && (ev->type==GF_EVENT_KEYDOWN)) {
			SFVec4f res, rot;
			Fixed diff = GF_PI/64;

			res = sphere->rotation_changed;
			switch (ev->key.key_code) {
			case GF_KEY_LEFT:
				diff = -diff;
			case GF_KEY_RIGHT:
				rot.x = 0;
				rot.y = FIX_ONE;
				rot.z = 0;
				rot.q = diff;
				res = gf_quat_from_rotation(res);
				rot = gf_quat_from_rotation(rot);
				rot = gf_quat_multiply(&rot, &res);
				res = gf_quat_to_rotation(&rot);
				break;
			case GF_KEY_DOWN:
				diff = -diff;
			case GF_KEY_UP:
				if (ev->key.flags & GF_KEY_MOD_SHIFT) {
					rot.x = 0;
					rot.z = FIX_ONE;
				} else {
					rot.x = FIX_ONE;
					rot.z = 0;
				}
				rot.y = 0;
				rot.q = diff;
				res = gf_quat_from_rotation(res);
				rot = gf_quat_from_rotation(rot);
				rot = gf_quat_multiply(&rot, &res);
				res = gf_quat_to_rotation(&rot);
				break;
			case GF_KEY_HOME:
				res = sphere->offset;
				break;
			default:
				return 0;
			}
			sphere->rotation_changed = res;
			gf_node_event_out(sh->sensor, 4/*"rotation_changed"*/);
			return 1;
		}
	}
	return 0;
}
Exemple #13
0
static void OnSphereSensor(SensorHandler *sh, Bool is_over, GF_Event *ev, RayHitInfo *hit_info)
{
	M_SphereSensor *sphere = (M_SphereSensor *)sh->owner;
	SphereSensorStack *st = (SphereSensorStack *) gf_node_get_private(sh->owner);

	if (sphere->isActive && (!sphere->enabled || ((ev->type==GF_EVENT_MOUSEUP) && (ev->mouse.button==GF_MOUSE_LEFT)) ) ) {
		if (sphere->autoOffset) {
			sphere->offset = sphere->rotation_changed;
			gf_node_event_out_str(sh->owner, "offset");
		}
		sphere->isActive = 0;
		gf_node_event_out_str(sh->owner, "isActive");
		R3D_SetGrabbed(st->compositor, 0);
	}
	else if (!sphere->isActive && (ev->type==GF_EVENT_MOUSEDOWN) && (ev->mouse.button==GF_MOUSE_LEFT)) {
		st->center.x = st->center.y = st->center.z = 0;
		gf_mx_apply_vec(&hit_info->local_to_world, &st->center);
		st->radius = gf_vec_len(hit_info->local_point);
		if (!st->radius) st->radius = FIX_ONE;
		st->grab_vec = gf_vec_scale(hit_info->local_point, gf_invfix(st->radius));

		sphere->isActive = 1;
		gf_node_event_out_str(sh->owner, "isActive");
		R3D_SetGrabbed(st->compositor, 1);
	}
	else if (sphere->isActive) {
		SFVec3f vec, axis;
		SFVec4f q1, q2;
		SFRotation r;
		Fixed cl;
		if (is_over) {
			sphere->trackPoint_changed = hit_info->local_point;
			gf_node_event_out_str(sh->owner, "trackPoint_changed");
		} else {
			GF_Ray r;
			r = hit_info->world_ray;
			gf_mx_apply_ray(&hit_info->world_to_local, &r);
			if (!gf_ray_hit_sphere(&r, NULL, st->radius, &hit_info->local_point)) {
				vec.x = vec.y = vec.z = 0;
				/*doesn't work properly...*/
				hit_info->local_point = gf_closest_point_to_line(r.orig, r.dir, vec);
			}
		}

		vec = gf_vec_scale(hit_info->local_point, gf_invfix(st->radius));
		axis = gf_vec_cross(st->grab_vec, vec);
		cl = gf_vec_len(axis);

		if (cl < -FIX_ONE) cl = -FIX_ONE;
		else if (cl > FIX_ONE) cl = FIX_ONE;
		r.q = gf_asin(cl);
		if (gf_vec_dot(st->grab_vec, vec) < 0) r.q += GF_PI / 2;

		gf_vec_norm(&axis);
		r.x = axis.x; r.y = axis.y; r.z = axis.z;
		q1 = gf_quat_from_rotation(r);
		if (sphere->autoOffset) {
			q2 = gf_quat_from_rotation(sphere->offset);
			q1 = gf_quat_multiply(&q1, &q2);
		}
		sphere->rotation_changed = gf_quat_to_rotation(&q1);
		gf_node_event_out_str(sh->owner, "rotation_changed");
	}
}
Exemple #14
0
static void OnCylinderSensor(SensorHandler *sh, Bool is_over, GF_Event *ev, RayHitInfo *hit_info)
{
	M_CylinderSensor *cs = (M_CylinderSensor *)sh->owner;
	CylinderSensorStack *st = (CylinderSensorStack *) gf_node_get_private(sh->owner);

	if (cs->isActive && (!cs->enabled || ((ev->type==GF_EVENT_MOUSEUP) && (ev->mouse.button==GF_MOUSE_LEFT))) ) {
		if (cs->autoOffset) {
			cs->offset = cs->rotation_changed.q;
			gf_node_event_out_str(sh->owner, "offset");
		}
		cs->isActive = 0;
		gf_node_event_out_str(sh->owner, "isActive");
		R3D_SetGrabbed(st->compositor, 0);
	}
	else if (!cs->isActive && (ev->type==GF_EVENT_MOUSEDOWN) && (ev->mouse.button==GF_MOUSE_LEFT)) {
		GF_Ray r;
		SFVec3f yaxis;
		Fixed acute, reva;
		SFVec3f bearing;

		gf_mx_copy(st->init_matrix, hit_info->world_to_local);
		/*get initial angle & check disk mode*/
		r = hit_info->world_ray;
		gf_vec_add(r.dir, r.orig, r.dir);
		gf_mx_apply_vec(&hit_info->world_to_local, &r.orig);
		gf_mx_apply_vec(&hit_info->world_to_local, &r.dir);
		gf_vec_diff(bearing, r.orig, r.dir);
		gf_vec_norm(&bearing);
		yaxis.x = yaxis.z = 0;
		yaxis.y = FIX_ONE;
		acute = gf_vec_dot(bearing, yaxis);
		if (acute < -FIX_ONE) acute = -FIX_ONE; 
		else if (acute > FIX_ONE) acute = FIX_ONE;
		acute = gf_acos(acute);
		reva = ABS(GF_PI - acute);
		if (reva<acute) acute = reva;
		st->disk_mode = (acute < cs->diskAngle) ? 1 : 0;

		st->grab_start = hit_info->local_point;
		/*cos we're lazy*/
		st->yplane.d = 0; st->yplane.normal.x = st->yplane.normal.z = st->yplane.normal.y = 0;
		st->zplane = st->xplane = st->yplane;
		st->xplane.normal.x = FIX_ONE;
		st->yplane.normal.y = FIX_ONE;
		st->zplane.normal.z = FIX_ONE;

		cs->rotation_changed.x = 0;
		cs->rotation_changed.y = FIX_ONE;
		cs->rotation_changed.z = 0;

		cs->isActive = 1;
		gf_node_event_out_str(sh->owner, "isActive");
		R3D_SetGrabbed(st->compositor, 1);
	}
	else if (cs->isActive) {
		GF_Ray r;
		Fixed radius, rot;
		SFVec3f dir1, dir2, cx;

		if (is_over) {
			cs->trackPoint_changed = hit_info->local_point;
			gf_node_event_out_str(sh->owner, "trackPoint_changed");
		} else {
			GF_Plane project_to;
			r = hit_info->world_ray;
			gf_mx_apply_ray(&st->init_matrix, &r);

			/*no intersection, use intersection with "main" fronting plane*/
			if ( ABS(r.dir.z) > ABS(r.dir.y)) {
				if (ABS(r.dir.x) > ABS(r.dir.x)) project_to = st->xplane;
				else project_to = st->zplane;
			} else project_to = st->yplane;
			if (!gf_plane_intersect_line(&project_to, &r.orig, &r.dir, &hit_info->local_point)) return;
		}

  		dir1.x = hit_info->local_point.x; dir1.y = 0; dir1.z = hit_info->local_point.z;
		if (st->disk_mode) {
			radius = FIX_ONE;
		} else {
			radius = gf_vec_len(dir1);
		}
		gf_vec_norm(&dir1);
       	dir2.x = st->grab_start.x; dir2.y = 0; dir2.z = st->grab_start.z;
		gf_vec_norm(&dir2);
		cx = gf_vec_cross(dir2, dir1);
		gf_vec_norm(&cx);
		if (gf_vec_len(cx)<FIX_EPSILON) return;
		rot = gf_mulfix(radius, gf_acos(gf_vec_dot(dir2, dir1)) );
		if (fabs(cx.y + FIX_ONE) < FIX_EPSILON) rot = -rot;
		if (cs->autoOffset) rot += cs->offset;

		if (cs->minAngle < cs->maxAngle) {
			if (rot < cs->minAngle) rot = cs->minAngle;
			else if (rot > cs->maxAngle) rot = cs->maxAngle;
		}
		cs->rotation_changed.q = rot;
		gf_node_event_out_str(sh->owner, "rotation_changed");
	}
}