예제 #1
0
파일: navigate.c 프로젝트: Brilon314/gpac
static void view_translate_x(GF_Compositor *compositor, GF_Camera *cam, Fixed dx)
{
	SFVec3f v;
	if (!dx) return;
	if (cam->jumping) dx *= JUMP_SCALE_FACTOR;
	v = gf_vec_scale(camera_get_right_dir(cam), dx);
	gf_vec_add(cam->target, cam->target, v);
	gf_vec_add(cam->position, cam->position, v);
	camera_changed(compositor, cam);
}
예제 #2
0
파일: navigate.c 프로젝트: Brilon314/gpac
static void view_translate_y(GF_Compositor *compositor, GF_Camera *cam, Fixed dy)
{
	SFVec3f v;
	if (!dy) return;
	if (cam->jumping) dy *= JUMP_SCALE_FACTOR;
	v = gf_vec_scale(cam->up, dy);
	gf_vec_add(cam->target, cam->target, v);
	gf_vec_add(cam->position, cam->position, v);
	camera_changed(compositor, cam);
}
예제 #3
0
파일: navigate.c 프로젝트: Brilon314/gpac
static void view_translate_z(GF_Compositor *compositor, GF_Camera *cam, Fixed dz)
{
	SFVec3f v;
	if (!dz) return;
	if (cam->jumping) dz *= JUMP_SCALE_FACTOR;
	dz = gf_mulfix(dz, cam->speed);
	v = gf_vec_scale(camera_get_target_dir(cam), dz);
	gf_vec_add(cam->target, cam->target, v);
	gf_vec_add(cam->position, cam->position, v);
	camera_changed(compositor, cam);
}
예제 #4
0
파일: camera.c 프로젝트: Brilon314/gpac
void camera_set_vectors(GF_Camera *cam, SFVec3f pos, SFRotation ori, Fixed fov)
{
	Fixed sin_a, cos_a, icos_a, tmp;

	cam->fieldOfView = fov;
	cam->last_pos = cam->position;
	cam->position = pos;
	/*compute up & target vectors in local system*/
	sin_a = gf_sin(ori.q);
	cos_a = gf_cos(ori.q);
	icos_a = FIX_ONE - cos_a;
	tmp = gf_mulfix(icos_a, ori.z);
	cam->target.x = gf_mulfix(ori.x, tmp) + gf_mulfix(sin_a, ori.y);
	cam->target.y = gf_mulfix(ori.y, tmp) - gf_mulfix(sin_a, ori.x);
	cam->target.z = gf_mulfix(ori.z, tmp) + cos_a;
	gf_vec_norm(&cam->target);
	cam->target = gf_vec_scale(cam->target, -cam->vp_dist);
	gf_vec_add(cam->target, cam->target, pos);
	tmp = gf_mulfix(icos_a, ori.y);
	cam->up.x = gf_mulfix(ori.x, tmp) - gf_mulfix(sin_a, ori.z);
	cam->up.y = gf_mulfix(ori.y, tmp) + cos_a;
	cam->up.z = gf_mulfix(ori.z, tmp) + gf_mulfix(sin_a, ori.x);
	gf_vec_norm(&cam->up);
	cam->flags |= CAM_IS_DIRTY;
}
예제 #5
0
void RenderVisibilitySensor(GF_Node *node, void *rs, Bool is_destroy)
{
	RenderEffect3D *eff = (RenderEffect3D *)rs;
	M_VisibilitySensor *vs = (M_VisibilitySensor *)node;
	
	if (is_destroy || !vs->enabled) return;

	if (eff->traversing_mode==TRAVERSE_GET_BOUNDS) {
		/*work with twice bigger bbox to get sure we're notify when culled out*/
		gf_vec_add(eff->bbox.max_edge, vs->center, vs->size);
		gf_vec_diff(eff->bbox.min_edge, vs->center, vs->size);
		gf_bbox_refresh(&eff->bbox);

	} else if (eff->traversing_mode==TRAVERSE_SORT) {
		Bool visible;
		u32 cull_flag;
		GF_BBox bbox;
		SFVec3f s;
		s = gf_vec_scale(vs->size, FIX_ONE/2);
		/*cull with normal bbox*/
		gf_vec_add(bbox.max_edge, vs->center, s);
		gf_vec_diff(bbox.min_edge, vs->center, s);
		gf_bbox_refresh(&bbox);
		cull_flag = eff->cull_flag;
		eff->cull_flag = CULL_INTERSECTS;
		visible = node_cull(eff, &bbox, 0);
		eff->cull_flag = cull_flag;

		if (visible && !vs->isActive) {
			vs->isActive = 1;
			gf_node_event_out_str(node, "isActive");
			vs->enterTime = gf_node_get_scene_time(node);
			gf_node_event_out_str(node, "enterTime");
		}
		else if (!visible && vs->isActive) {
			vs->isActive = 0;
			gf_node_event_out_str(node, "isActive");
			vs->exitTime = gf_node_get_scene_time(node);
			gf_node_event_out_str(node, "exitTime");
		}
	}
}
예제 #6
0
void TraverseVisibilitySensor(GF_Node *node, void *rs, Bool is_destroy)
{
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;
	M_VisibilitySensor *vs = (M_VisibilitySensor *)node;

	if (is_destroy || !vs->enabled) return;

	if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
		/*work with twice bigger bbox to get sure we're notify when culled out*/
		gf_vec_add(tr_state->bbox.max_edge, vs->center, vs->size);
		gf_vec_diff(tr_state->bbox.min_edge, vs->center, vs->size);
		gf_bbox_refresh(&tr_state->bbox);

	} else if (tr_state->traversing_mode==TRAVERSE_SORT) {
		Bool visible;
		u32 cull_flag;
		GF_BBox bbox;
		SFVec3f s;
		s = gf_vec_scale(vs->size, FIX_ONE/2);
		/*cull with normal bbox*/
		gf_vec_add(bbox.max_edge, vs->center, s);
		gf_vec_diff(bbox.min_edge, vs->center, s);
		gf_bbox_refresh(&bbox);
		cull_flag = tr_state->cull_flag;
		tr_state->cull_flag = CULL_INTERSECTS;
		visible = visual_3d_node_cull(tr_state, &bbox, 0);
		tr_state->cull_flag = cull_flag;

		if (visible && !vs->isActive) {
			vs->isActive = 1;
			gf_node_event_out(node, 5/*"isActive"*/);
			vs->enterTime = gf_node_get_scene_time(node);
			gf_node_event_out(node, 3/*"enterTime"*/);
		}
		else if (!visible && vs->isActive) {
			vs->isActive = 0;
			gf_node_event_out(node, 5/*"isActive"*/);
			vs->exitTime = gf_node_get_scene_time(node);
			gf_node_event_out(node, 4/*"exitTime"*/);
		}
	}
}
예제 #7
0
파일: navigate.c 프로젝트: Brilon314/gpac
static void view_roll(GF_Compositor *compositor, GF_Camera *cam, Fixed dd)
{
	GF_Matrix mx;
	SFVec3f delta;
	if (!dd) return;
	gf_vec_add(delta, cam->target, cam->up);
	gf_mx_rotation_matrix(&mx, cam->target, camera_get_pos_dir(cam), dd);
	gf_mx_apply_vec(&mx, &delta);
	gf_vec_diff(cam->up, delta, cam->target);
	gf_vec_norm(&cam->up);
	camera_changed(compositor, cam);
}
예제 #8
0
static void TraverseSpotLight(GF_Node *n, void *rs, Bool is_destroy)
{
	M_SpotLight *sl = (M_SpotLight *)n;
	GF_TraverseState *tr_state = (GF_TraverseState *) rs;

	if (is_destroy) {
		Bool *vis = gf_node_get_private(n);
		gf_free(vis);
		return;
	}
	if (!sl->on) return;

	/*store local bounds for culling*/
	if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
		GF_BBox b;
		SFVec3f size;
		Bool *visible = gf_node_get_private(n);
		size.x = size.y = size.z = sl->radius;
		gf_vec_add(b.max_edge, sl->location, size);
		gf_vec_diff(b.min_edge, sl->location, size);
		gf_bbox_refresh(&b);
		*visible = visual_3d_node_cull(tr_state, &b, 0);
		/*if visible, disable culling on our parent branch - this is not very efficient but
		we only store one bound per grouping node, and we don't want the lights to interfere with it*/
		if (*visible) tr_state->disable_cull = 1;
		return;
	}
	else if (tr_state->traversing_mode == TRAVERSE_LIGHTING) {
		Bool *visible = gf_node_get_private(n);
		if (*visible) {

			visual_3d_matrix_push(tr_state->visual);
			visual_3d_matrix_add(tr_state->visual, tr_state->model_matrix.m);
			
			visual_3d_add_spot_light(tr_state->visual, sl->ambientIntensity, sl->attenuation, sl->beamWidth, 
						   sl->color, sl->cutOffAngle, sl->direction, sl->intensity, sl->location);
			
			visual_3d_matrix_pop(tr_state->visual);
		}
	}
}
예제 #9
0
Bool compositor_get_2d_plane_intersection(GF_Ray *ray, SFVec3f *res)
{
	GF_Plane p;
	Fixed t, t2;
	if (!ray->dir.x && !ray->dir.y) {
		res->x = ray->orig.x;
		res->y = ray->orig.y;
		res->z = 0;
		return 1;
	}
	p.normal.x = p.normal.y = 0;
	p.normal.z = FIX_ONE;
	p.d = 0;
	t2 = gf_vec_dot(p.normal, ray->dir);
	if (t2 == 0) return 0;
	t = - gf_divfix(gf_vec_dot(p.normal, ray->orig) + p.d, t2);
	if (t<0) return 0;
	*res = gf_vec_scale(ray->dir, t);
	gf_vec_add(*res, ray->orig, *res);
	return 1;
}
예제 #10
0
static void TraversePointLight(GF_Node *n, void *rs, Bool is_destroy)
{
	M_PointLight *pl = (M_PointLight *)n;
	GF_TraverseState *tr_state = (GF_TraverseState *) rs;

	if (is_destroy) {
		Bool *vis = gf_node_get_private(n);
		gf_free(vis);
		return;
	}
	if (!pl->on) return;

	/*store local bounds for culling*/
	if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
		SFVec3f size;
		GF_BBox b;
		Bool *visible = gf_node_get_private(n);
		size.x = size.y = size.z = pl->radius;
		gf_vec_add(b.max_edge, pl->location, size);
		gf_vec_diff(b.min_edge, pl->location, size);
		gf_bbox_refresh(&b);
		*visible = visual_3d_node_cull(tr_state, &b, 0);
		/*if visible, disable culling on our parent branch*/
		if (*visible) tr_state->disable_cull = 1;
		return;
	}
	else if (tr_state->traversing_mode == TRAVERSE_LIGHTING) {
		Bool *visible = gf_node_get_private(n);
		if (*visible) {
			visual_3d_matrix_push(tr_state->visual);
			visual_3d_matrix_add(tr_state->visual, tr_state->model_matrix.m);

			visual_3d_add_point_light(tr_state->visual, pl->ambientIntensity, pl->attenuation, pl->color, 
						pl->intensity, pl->location);

			visual_3d_matrix_pop(tr_state->visual);
		}
	}
}
예제 #11
0
파일: camera.c 프로젝트: Brilon314/gpac
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;
}
예제 #12
0
static void BuildTriangleFanSet(GF_Mesh *mesh, GF_Node *_coords, GF_Node *_color, GF_Node *_txcoords, GF_Node *_normal, MFInt32 *fanList, MFInt32 *indices, Bool normalPerVertex, Bool ccw, Bool solid)
{
	u32 fan, i, cur_idx, generate_tx;
	GF_Vertex vx;
	GenMFField *cols;
	MFVec3f *norms;
	MFVec2f *txcoords;
	Bool rgba_col;
	SFColorRGBA rgba;
	X_Coordinate *c = (X_Coordinate *) _coords;
	mesh_reset(mesh);

	cols = NULL;
	rgba_col = 0;
	if (_color) {
		if (gf_node_get_tag(_color)==TAG_X3D_ColorRGBA) {
			rgba_col = 1;
			cols = (GenMFField *) & ((X_ColorRGBA *) _color)->color;
		} else {
			cols = (GenMFField *) & ((M_Color *) _color)->color;
		}
	}
	norms = NULL;
	if (_normal) norms = & ((M_Normal *)_normal)->vector;
	txcoords = NULL;
	generate_tx = 0;
	/*FIXME - this can't work with multitexturing*/
	if (_txcoords) {
		switch (gf_node_get_tag(_txcoords)) {
		case TAG_X3D_TextureCoordinate:
		case TAG_MPEG4_TextureCoordinate:
			txcoords = & ((M_TextureCoordinate *)_txcoords)->point;
			break;
		case TAG_X3D_TextureCoordinateGenerator:
			generate_tx = 1;
			break;
		}
	}

	memset(&vx, 0, sizeof(GF_Vertex));
	cur_idx = 0;
	for (fan= 0; fan<fanList->count; fan++) {
		u32 start_idx = mesh->v_count;
		if (fanList->vals[fan] < 3) continue;

		for (i=0; i<(u32) fanList->vals[fan]; i++) {
			u32 idx;
			if (indices) {
				if (indices->count<=cur_idx) return;
				if (indices->vals[cur_idx] == -1) {
					GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[X3D] bad formatted X3D triangle set\n"));
					return;
				}
				idx = indices->vals[cur_idx];
			} else {
				idx = cur_idx;
			}
			vx.pos = c->point.vals[idx];

			if (cols && (cols->count>idx)) {
				if (rgba_col) {
					rgba = ((MFColorRGBA *)cols)->vals[idx];
				} else {
					rgba = gf_sg_sfcolor_to_rgba( ((MFColor *)cols)->vals[idx]);
				}
				vx.color = MESH_MAKE_COL(rgba);
			}
			/*according to X3D spec, if normal field is set, it is ALWAYS as normal per vertex*/
			if (norms && (norms->count>idx)) {
				SFVec3f n = norms->vals[idx];
				gf_vec_norm(&n);
				MESH_SET_NORMAL(vx, n);
			}
			if (txcoords) {
				if (txcoords->count>idx) vx.texcoords = txcoords->vals[idx];
			}
			/*X3D says nothing about default texture mapping here...*/
			else if (!generate_tx) {
				switch (idx%3) {
				case 2:
					vx.texcoords.x = FIX_ONE;
					vx.texcoords.y = 0;
					break;
				case 1:
					vx.texcoords.x = FIX_ONE/2;
					vx.texcoords.y = FIX_ONE;
					break;
				case 0:
					vx.texcoords.x = 0;
					vx.texcoords.y = 0;
					break;
				}
			}
			mesh_set_vertex_vx(mesh, &vx);

			cur_idx ++;
			if (indices) {
				if (cur_idx>=indices->count) break;
			} else if (cur_idx==c->point.count) break;

			if (i>1) {
				mesh_set_vertex_vx(mesh, &mesh->vertices[start_idx]);
				mesh_set_vertex_vx(mesh, &vx);
			}
		}
		for (i=start_idx; i<mesh->v_count; i+=3) {
			mesh_set_triangle(mesh, i, i+1, i+2);
		}
		/*get rid of -1*/
		if (indices && (cur_idx<indices->count) && (indices->vals[cur_idx]==-1)) cur_idx++;
	}
	if (generate_tx) mesh_generate_tex_coords(mesh, _txcoords);

	if (cols) mesh->flags |= MESH_HAS_COLOR;
	if (rgba_col) mesh->flags |= MESH_HAS_ALPHA;
	if (!ccw) mesh->flags |= MESH_IS_CW;
	if (!_normal) {
		mesh_recompute_normals(mesh);
		if (normalPerVertex) {
			u32 cur_face = 0;
			for (fan=0; fan<fanList->count; fan++) {
				SFVec3f n_0, n_1, n_avg, n_tot;
				u32 nb_face, start_face;
				if (fanList->vals[fan] < 3) continue;
				if (fanList->vals[fan] == 3) {
					cur_face++;
					continue;
				}

				start_face = cur_face;

				/*first face normal*/
				MESH_GET_NORMAL(n_0, mesh->vertices[mesh->indices[3*cur_face]]);
				n_tot = n_0;
				cur_face++;
				nb_face = fanList->vals[fan] - 2;
				for (i=1; i<nb_face; i++) {
					MESH_GET_NORMAL(n_1, mesh->vertices[mesh->indices[3*cur_face + 1]]);
					gf_vec_add(n_avg, n_0, n_1);
					gf_vec_norm(&n_avg);
					MESH_SET_NORMAL(mesh->vertices[mesh->indices[3*cur_face + 1]], n_avg);
					gf_vec_add(n_tot, n_tot, n_1);
					n_0 = n_1;
					cur_face++;
				}
				/*and assign center normal*/
				gf_vec_norm(&n_tot);
				for (i=0; i<nb_face; i++) {
					MESH_SET_NORMAL(mesh->vertices[mesh->indices[3*(i+start_face)]], n_tot);
				}
			}
		}
	}
	if (solid) mesh->flags |= MESH_IS_SOLID;
	mesh_update_bounds(mesh);
	gf_mesh_build_aabbtree(mesh);
}
예제 #13
0
static void BuildTriangleStripSet(GF_Mesh *mesh, GF_Node *_coords, GF_Node *_color, GF_Node *_txcoords, GF_Node *_normal, MFInt32 *stripList, MFInt32 *indices, Bool normalPerVertex, Bool ccw, Bool solid)
{
	u32 strip, i, cur_idx, generate_tx;
	GF_Vertex vx;
	GenMFField *cols;
	MFVec3f *norms;
	MFVec2f *txcoords;
	Bool rgba_col;
	SFColorRGBA rgba;
	X_Coordinate *c = (X_Coordinate *) _coords;

	mesh_reset(mesh);

	cols = NULL;
	rgba_col = 0;
	if (_color) {
		if (gf_node_get_tag(_color)==TAG_X3D_ColorRGBA) {
			rgba_col = 1;
			cols = (GenMFField *) & ((X_ColorRGBA *) _color)->color;
		} else {
			cols = (GenMFField *) & ((M_Color *) _color)->color;
		}
	}
	norms = NULL;
	if (_normal) norms = & ((M_Normal *)_normal)->vector;
	txcoords = NULL;
	generate_tx = 0;
	/*FIXME - this can't work with multitexturing*/
	if (_txcoords) {
		switch (gf_node_get_tag(_txcoords)) {
		case TAG_X3D_TextureCoordinate:
		case TAG_MPEG4_TextureCoordinate:
			txcoords = & ((M_TextureCoordinate *)_txcoords)->point;
			break;
		case TAG_X3D_TextureCoordinateGenerator:
			generate_tx = 1;
			break;
		}
	}
	memset(&vx, 0, sizeof(GF_Vertex));
	cur_idx = 0;
	for (strip= 0; strip<stripList->count; strip++) {
		u32 start_idx = mesh->v_count;
		if (stripList->vals[strip] < 3) continue;

		for (i=0; i<(u32) stripList->vals[strip]; i++) {
			u32 idx;
			if (indices) {
				if (indices->count<=cur_idx) return;
				if (indices->vals[cur_idx] == -1) {
					GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[X3D] bad formatted X3D triangle strip\n"));
					return;
				}
				idx = indices->vals[cur_idx];
			} else {
				idx = cur_idx;
			}

			vx.pos = c->point.vals[idx];

			if (cols && (cols->count>idx)) {
				if (rgba_col) {
					rgba = ((MFColorRGBA *)cols)->vals[idx];
				} else {
					rgba = gf_sg_sfcolor_to_rgba( ((MFColor *)cols)->vals[idx]);
				}
				vx.color = MESH_MAKE_COL(rgba);
			}
			/*according to X3D spec, if normal field is set, it is ALWAYS as normal per vertex*/
			if (norms && (norms->count>idx)) {
				SFVec3f n = norms->vals[idx];
				gf_vec_norm(&n);
				MESH_SET_NORMAL(vx, n);
			}
			if (txcoords) {
				if (txcoords->count>idx) vx.texcoords = txcoords->vals[idx];
			}
			/*X3D says nothing about default texture mapping here...*/
			else if (!generate_tx) {
				switch (idx%3) {
				case 2:
					vx.texcoords.x = FIX_ONE;
					vx.texcoords.y = 0;
					break;
				case 1:
					vx.texcoords.x = FIX_ONE/2;
					vx.texcoords.y = FIX_ONE;
					break;
				case 0:
					vx.texcoords.x = 0;
					vx.texcoords.y = 0;
					break;
				}
			}
			if (i>2) {
				/*duplicate last 2 vertices (we really need independent vertices to handle normals per face)*/
				mesh_set_vertex_vx(mesh, &mesh->vertices[mesh->v_count-2]);
				mesh_set_vertex_vx(mesh, &mesh->vertices[mesh->v_count-2]);
			}
			mesh_set_vertex_vx(mesh, &vx);

			cur_idx ++;
			if (indices) {
				if (cur_idx>=indices->count) break;
			} else if (cur_idx==c->point.count) break;

		}
		for (i=start_idx; i<mesh->v_count; i+=3) {
			mesh_set_triangle(mesh, i, i+1, i+2);
		}
		/*get rid of -1*/
		if (indices && (cur_idx<indices->count) && (indices->vals[cur_idx]==-1)) cur_idx++;
	}
	if (generate_tx) mesh_generate_tex_coords(mesh, _txcoords);

	if (cols) mesh->flags |= MESH_HAS_COLOR;
	if (rgba_col) mesh->flags |= MESH_HAS_ALPHA;
	if (_normal) {
		if (!ccw) mesh->flags |= MESH_IS_CW;
	}
	/*reorder everything to CCW*/
	else {
		u32 cur_face = 0;
		mesh_recompute_normals(mesh);
		for (i=0; i<mesh->i_count; i+= 3) {
			if ((ccw && (cur_face%2)) || (!ccw && !(cur_face%2))) {
				SFVec3f v;
				u32 idx;
				MESH_GET_NORMAL(v, mesh->vertices[mesh->indices[i]]);
				v = gf_vec_scale(v,-1);
				MESH_SET_NORMAL(mesh->vertices[mesh->indices[i]], v);
				mesh->vertices[mesh->indices[i+1]].normal = mesh->vertices[mesh->indices[i]].normal;
				mesh->vertices[mesh->indices[i+2]].normal = mesh->vertices[mesh->indices[i]].normal;
				idx = mesh->indices[i+2];
				mesh->indices[i+2] = mesh->indices[i+1];
				mesh->indices[i+1] = idx;
			}
			cur_face++;
		}
		if (normalPerVertex) {
			cur_face = 0;
			for (strip=0; strip<stripList->count; strip++) {
				SFVec3f n_0, n_1, n_2, n_avg;
				u32 nb_face;
				if (stripList->vals[strip] < 3) continue;
				if (stripList->vals[strip] <= 3) {
					cur_face ++;
					continue;
				}

				/*first face normal*/
				MESH_GET_NORMAL(n_0, mesh->vertices[mesh->indices[3*cur_face]]);
				/*second face normal*/
				MESH_GET_NORMAL(n_1, mesh->vertices[mesh->indices[3*(cur_face+1)]]);

				gf_vec_add(n_avg, n_0, n_1);
				gf_vec_norm(&n_avg);
				/*assign to second point of first face and first of second face*/
				MESH_SET_NORMAL(mesh->vertices[mesh->indices[3*cur_face+1]], n_avg);
				MESH_SET_NORMAL(mesh->vertices[mesh->indices[3*(cur_face+1)]], n_avg);
				nb_face = stripList->vals[strip] - 2;
				cur_face++;
				for (i=1; i<nb_face-1; i++) {
					/*get normal (use second pt of current face since first has been updated)*/
					MESH_GET_NORMAL(n_2, mesh->vertices[mesh->indices[3*cur_face + 1]]);
					gf_vec_add(n_avg, n_0, n_1);
					gf_vec_add(n_avg, n_avg, n_2);
					gf_vec_norm(&n_avg);
					/*last of prev face*/
					MESH_SET_NORMAL(mesh->vertices[mesh->indices[3*cur_face - 1]], n_avg);
					/*second of current face*/
					mesh->vertices[mesh->indices[3*cur_face + 1]].normal = mesh->vertices[mesh->indices[3*cur_face - 1]].normal;
					/*first of next face*/
					mesh->vertices[mesh->indices[3*cur_face + 3]].normal = mesh->vertices[mesh->indices[3*cur_face - 1]].normal;
					n_0 = n_1;
					n_1 = n_2;
					cur_face++;
				}
			}
		}
	}
	if (solid) mesh->flags |= MESH_IS_SOLID;
	mesh_update_bounds(mesh);
	gf_mesh_build_aabbtree(mesh);
}
예제 #14
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;
}
예제 #15
0
void TraverseProximitySensor(GF_Node *node, void *rs, Bool is_destroy)
{
	SFVec3f user_pos, dist, up;
	SFRotation ori;
	GF_Matrix mx;
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;
	M_ProximitySensor *ps = (M_ProximitySensor *)node;
	if (is_destroy) return;

	if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
		/*work with twice bigger bbox to get sure we're notify when culled out*/
		gf_vec_add(tr_state->bbox.max_edge, ps->center, ps->size);
		gf_vec_diff(tr_state->bbox.min_edge, ps->center, ps->size);
		gf_bbox_refresh(&tr_state->bbox);
		return;
	} else if (!ps->enabled || (tr_state->traversing_mode != TRAVERSE_SORT) ) return;

	/*TODO FIXME - find a way to cache inverted matrix*/
	gf_mx_copy(mx, tr_state->model_matrix);
	gf_mx_inverse(&mx);
	/*get use pos in local coord system*/
	user_pos = tr_state->camera->position;
	gf_mx_apply_vec(&mx, &user_pos);
	gf_vec_diff(dist, user_pos, ps->center);

	if (dist.x<0) dist.x *= -1;
	if (dist.y<0) dist.y *= -1;
	if (dist.z<0) dist.z *= -1;

	if ((2*dist.x <= ps->size.x)
	        && (2*dist.y <= ps->size.y)
	        && (2*dist.z <= ps->size.z) ) {

		if (!ps->isActive) {
			ps->isActive = 1;
			gf_node_event_out(node, 3/*"isActive"*/);
			ps->enterTime = gf_node_get_scene_time(node);
			gf_node_event_out(node, 6/*"enterTime"*/);
		}
		if ((ps->position_changed.x != user_pos.x)
		        || (ps->position_changed.y != user_pos.y)
		        || (ps->position_changed.z != user_pos.z) )
		{
			ps->position_changed = user_pos;
			gf_node_event_out(node, 4/*"position_changed"*/);
		}
		dist = tr_state->camera->target;
		gf_mx_apply_vec(&mx, &dist);
		up = tr_state->camera->up;
		gf_mx_apply_vec(&mx, &up);
		ori = camera_get_orientation(user_pos, dist, tr_state->camera->up);
		if ((ori.q != ps->orientation_changed.q)
		        || (ori.x != ps->orientation_changed.x)
		        || (ori.y != ps->orientation_changed.y)
		        || (ori.z != ps->orientation_changed.z) ) {
			ps->orientation_changed = ori;
			gf_node_event_out(node, 5/*"orientation_changed"*/);
		}
	} else if (ps->isActive) {
		ps->isActive = 0;
		gf_node_event_out(node, 3/*"isActive"*/);
		ps->exitTime = gf_node_get_scene_time(node);
		gf_node_event_out(node, 7/*"exitTime"*/);
	}
}
예제 #16
0
파일: navigate.c 프로젝트: Brilon314/gpac
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;
}
예제 #17
0
파일: camera.c 프로젝트: Brilon314/gpac
Bool camera_animate(GF_Camera *cam)
{
	u32 now;
	Fixed frac;
	if (!cam->anim_len) return GF_FALSE;

	if (cam->jumping) {
		if (!cam->anim_start) {
			cam->anim_start = gf_sys_clock();
			cam->dheight = 0;
			return GF_TRUE;
		}
		cam->position.y -= cam->dheight;
		cam->target.y -= cam->dheight;

		now = gf_sys_clock() - cam->anim_start;
		if (now > cam->anim_len) {
			cam->anim_len = 0;
			cam->jumping = GF_FALSE;
			cam->flags |= CAM_IS_DIRTY;
			return GF_TRUE;
		}
		frac = FLT2FIX ( ((Float) now) / cam->anim_len);
		if (frac>FIX_ONE / 2) frac = FIX_ONE - frac;
		cam->dheight = gf_mulfix(cam->avatar_size.y, frac);
		cam->position.y += cam->dheight;
		cam->target.y += cam->dheight;
		cam->flags |= CAM_IS_DIRTY;
		return GF_TRUE;
	}

	if (!cam->anim_start) {
		cam->anim_start = gf_sys_clock();
		now = 0;
		frac = 0;
	} else {
		now = gf_sys_clock() - cam->anim_start;
		if (now > cam->anim_len) {
			cam->anim_len = 0;
#ifndef FORCE_CAMERA_3D
			if (cam->is_3D)
#endif
			{
				camera_set_vectors(cam, cam->end_pos, cam->end_ori, cam->end_fov);
				cam->end_zoom = FIX_ONE;
			}
#ifndef FORCE_CAMERA_3D
			else {
				cam->flags |= CAM_IS_DIRTY;
			}
#endif

			if (cam->flags & CF_STORE_VP) {
				cam->flags &= ~CF_STORE_VP;
				cam->vp_position = cam->position;
				cam->vp_fov = cam->fieldOfView;
				cam->vp_orientation = camera_get_orientation(cam->position, cam->target, cam->up);
			}
			return GF_TRUE;
		} else {
			frac = FLT2FIX( ((Float) now) / cam->anim_len);
		}
	}

#ifndef FORCE_CAMERA_3D
	if (cam->is_3D)
#endif
	{
		SFVec3f pos, dif;
		SFRotation rot;
		Fixed fov;
		rot = gf_sg_sfrotation_interpolate(cam->start_ori, cam->end_ori, frac);
		gf_vec_diff(dif, cam->end_pos, cam->start_pos);
		dif = gf_vec_scale(dif, frac);
		gf_vec_add(pos, cam->start_pos, dif);
		fov = gf_mulfix(cam->end_fov - cam->start_fov, frac) + cam->start_fov;
		cam->end_zoom = frac + gf_mulfix((FIX_ONE-frac), cam->start_zoom);
		camera_set_vectors(cam, pos, rot, fov);
	}
	return GF_TRUE;
}
예제 #18
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);
}
예제 #19
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");
	}
}