static void OnPlaneSensor(SensorHandler *sh, Bool is_over, GF_Event *ev, RayHitInfo *hit_info) { M_PlaneSensor *ps = (M_PlaneSensor *)sh->owner; PSStack *stack = (PSStack *) gf_node_get_private(sh->owner); if (ps->isActive && (!ps->enabled || ((ev->type==GF_EVENT_MOUSEUP) && (ev->mouse.button==GF_MOUSE_LEFT)) )) { if (ps->autoOffset) { ps->offset = ps->translation_changed; gf_node_event_out_str(sh->owner, "offset"); } ps->isActive = 0; gf_node_event_out_str(sh->owner, "isActive"); R3D_SetGrabbed(stack->compositor, 0); } else if (!ps->isActive && (ev->type==GF_EVENT_MOUSEDOWN) && (ev->mouse.button==GF_MOUSE_LEFT)) { gf_mx_copy(stack->initial_matrix, hit_info->local_to_world); gf_vec_diff(stack->start_drag, hit_info->local_point, ps->offset); stack->tracker.normal.x = stack->tracker.normal.y = 0; stack->tracker.normal.z = FIX_ONE; stack->tracker.d = - gf_vec_dot(stack->start_drag, stack->tracker.normal); ps->isActive = 1; gf_node_event_out_str(sh->owner, "isActive"); R3D_SetGrabbed(stack->compositor, 1); } else if (ps->isActive) { GF_Ray loc_ray; SFVec3f res; loc_ray = hit_info->world_ray; gf_mx_apply_ray(&stack->initial_matrix, &loc_ray); gf_plane_intersect_line(&stack->tracker, &loc_ray.orig, &loc_ray.dir, &res); ps->trackPoint_changed = res; gf_node_event_out_str(sh->owner, "trackPoint_changed"); gf_vec_diff(res, res, stack->start_drag); /*clip*/ if (ps->minPosition.x <= ps->maxPosition.x) { if (res.x < ps->minPosition.x) res.x = ps->minPosition.x; if (res.x > ps->maxPosition.x) res.x = ps->maxPosition.x; } if (ps->minPosition.y <= ps->maxPosition.y) { if (res.y < ps->minPosition.y) res.y = ps->minPosition.y; if (res.y > ps->maxPosition.y) res.y = ps->maxPosition.y; } ps->translation_changed = res; gf_node_event_out_str(sh->owner, "translation_changed"); } }
static void OnPlaneSensor2D(SensorHandler *sh, Bool is_over, GF_Event *ev, RayHitInfo *hit_info) { M_PlaneSensor2D *ps = (M_PlaneSensor2D *)sh->owner; PS2DStack *stack = (PS2DStack *) gf_node_get_private(sh->owner); if (ps->isActive && (!ps->enabled || ((ev->type==GF_EVENT_MOUSEUP) && (ev->mouse.button==GF_MOUSE_LEFT)) )) { if (ps->autoOffset) { ps->offset = ps->translation_changed; gf_node_event_out_str(sh->owner, "offset"); } ps->isActive = 0; gf_node_event_out_str(sh->owner, "isActive"); R3D_SetGrabbed(stack->compositor, 0); } else if (!ps->isActive && (ev->type==GF_EVENT_MOUSEDOWN) && (ev->mouse.button==GF_MOUSE_LEFT)) { gf_mx_copy(stack->initial_matrix, hit_info->local_to_world); stack->start_drag.x = hit_info->local_point.x - ps->offset.x; stack->start_drag.y = hit_info->local_point.y - ps->offset.y; ps->isActive = 1; gf_node_event_out_str(sh->owner, "isActive"); R3D_SetGrabbed(stack->compositor, 1); } else if (ps->isActive) { GF_Ray loc_ray; SFVec3f res; loc_ray = hit_info->world_ray; gf_mx_apply_ray(&stack->initial_matrix, &loc_ray); R3D_Get2DPlaneIntersection(&loc_ray, &res); ps->trackPoint_changed.x = res.x; ps->trackPoint_changed.y = res.y; gf_node_event_out_str(sh->owner, "trackPoint_changed"); res.x -= stack->start_drag.x; res.y -= stack->start_drag.y; /*clip*/ if (ps->minPosition.x <= ps->maxPosition.x) { if (res.x < ps->minPosition.x) res.x = ps->minPosition.x; if (res.x > ps->maxPosition.x) res.x = ps->maxPosition.x; } if (ps->minPosition.y <= ps->maxPosition.y) { if (res.y < ps->minPosition.y) res.y = ps->minPosition.y; if (res.y > ps->maxPosition.y) res.y = ps->maxPosition.y; } ps->translation_changed.x = res.x; ps->translation_changed.y = res.y; gf_node_event_out_str(sh->owner, "translation_changed"); } }
static void OnDiscSensor(SensorHandler *sh, Bool is_over, GF_Event *ev, RayHitInfo *hit_info) { M_DiscSensor *ds = (M_DiscSensor *)sh->owner; DiscSensorStack *stack = (DiscSensorStack *) gf_node_get_private(sh->owner); if (ds->isActive && (!ds->enabled || ((ev->type==GF_EVENT_MOUSEUP) && (ev->mouse.button==GF_MOUSE_LEFT) ) ) ) { if (ds->autoOffset) { ds->offset = ds->rotation_changed; /*that's an exposedField*/ gf_node_event_out_str(sh->owner, "offset"); } ds->isActive = 0; gf_node_event_out_str(sh->owner, "isActive"); R3D_SetGrabbed(stack->compositor, 0); } else if (!ds->isActive && (ev->type==GF_EVENT_MOUSEDOWN) && (ev->mouse.button==GF_MOUSE_LEFT)) { /*store inverse matrix*/ gf_mx_copy(stack->initial_matrix, hit_info->local_to_world); stack->start_angle = gf_atan2(hit_info->local_point.y, hit_info->local_point.x); ds->isActive = 1; gf_node_event_out_str(sh->owner, "isActive"); R3D_SetGrabbed(stack->compositor, 1); } else if (ds->isActive) { GF_Ray loc_ray; Fixed rot; SFVec3f res; loc_ray = hit_info->world_ray; gf_mx_apply_ray(&stack->initial_matrix, &loc_ray); R3D_Get2DPlaneIntersection(&loc_ray, &res); rot = gf_atan2(res.y, res.x) - stack->start_angle + ds->offset; if (ds->minAngle < ds->maxAngle) { /*FIXME this doesn't work properly*/ if (rot < ds->minAngle) rot = ds->minAngle; if (rot > ds->maxAngle) rot = ds->maxAngle; } ds->rotation_changed = rot; gf_node_event_out_str(sh->owner, "rotation_changed"); ds->trackPoint_changed.x = res.x; ds->trackPoint_changed.y = res.y; gf_node_event_out_str(sh->owner, "trackPoint_changed"); } }
void svg_drawable_3d_pick(Drawable *drawable, GF_TraverseState *tr_state, DrawAspect2D *asp) { SFVec3f local_pt, world_pt, vdiff; SFVec3f hit_normal; SFVec2f text_coords; u32 i, count; Fixed sqdist; Bool node_is_over; GF_Compositor *compositor; GF_Matrix mx; GF_Ray r; compositor = tr_state->visual->compositor; node_is_over = 0; r = tr_state->ray; gf_mx_copy(mx, tr_state->model_matrix); gf_mx_inverse(&mx); gf_mx_apply_ray(&mx, &r); /*if we already have a hit point don't check anything below...*/ if (compositor->hit_square_dist && !compositor->grabbed_sensor && !tr_state->layer3d) { GF_Plane p; GF_BBox box; SFVec3f hit = compositor->hit_world_point; gf_mx_apply_vec(&mx, &hit); p.normal = r.dir; p.d = -1 * gf_vec_dot(p.normal, hit); gf_bbox_from_rect(&box, &drawable->path->bbox); if (gf_bbox_plane_relation(&box, &p) == GF_BBOX_FRONT) { GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SVG Picking] bounding box of node %s (DEF %s) below current hit point - skipping\n", gf_node_get_class_name(drawable->node), gf_node_get_name(drawable->node))); return; } } node_is_over = 0; if (compositor_get_2d_plane_intersection(&r, &local_pt)) { node_is_over = svg_drawable_is_over(drawable, local_pt.x, local_pt.y, asp, tr_state, NULL); } if (!node_is_over) return; hit_normal.x = hit_normal.y = 0; hit_normal.z = FIX_ONE; text_coords.x = gf_divfix(local_pt.x, drawable->path->bbox.width) + FIX_ONE/2; text_coords.y = gf_divfix(local_pt.y, drawable->path->bbox.height) + FIX_ONE/2; /*check distance from user and keep the closest hitpoint*/ world_pt = local_pt; gf_mx_apply_vec(&tr_state->model_matrix, &world_pt); for (i=0; i<tr_state->num_clip_planes; i++) { if (gf_plane_get_distance(&tr_state->clip_planes[i], &world_pt) < 0) { GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SVG Picking] node %s (def %s) is not in clipper half space\n", gf_node_get_class_name(drawable->node), gf_node_get_name(drawable->node))); return; } } gf_vec_diff(vdiff, world_pt, tr_state->ray.orig); sqdist = gf_vec_lensq(vdiff); if (compositor->hit_square_dist && (compositor->hit_square_dist+FIX_EPSILON<sqdist)) { GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SVG Picking] node %s (def %s) is farther (%g) than current pick (%g)\n", gf_node_get_class_name(drawable->node), gf_node_get_name(drawable->node), FIX2FLT(sqdist), FIX2FLT(compositor->hit_square_dist))); return; } compositor->hit_square_dist = sqdist; /*also stack any VRML sensors present at the current level. If the event is not catched by a listener in the SVG tree, the event will be forwarded to the VRML tree*/ gf_list_reset(compositor->sensors); count = gf_list_count(tr_state->vrml_sensors); for (i=0; i<count; i++) { gf_list_add(compositor->sensors, gf_list_get(tr_state->vrml_sensors, i)); } gf_mx_copy(compositor->hit_world_to_local, tr_state->model_matrix); gf_mx_copy(compositor->hit_local_to_world, mx); compositor->hit_local_point = local_pt; compositor->hit_world_point = world_pt; compositor->hit_world_ray = tr_state->ray; compositor->hit_normal = hit_normal; compositor->hit_texcoords = text_coords; svg_clone_use_stack(compositor, tr_state); /*not use in SVG patterns*/ compositor->hit_appear = NULL; compositor->hit_node = drawable->node; compositor->hit_text = NULL; compositor->hit_use_dom_events = 1; GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SVG Picking] node %s (def %s) is under mouse - hit %g %g %g\n", gf_node_get_class_name(drawable->node), gf_node_get_name(drawable->node), FIX2FLT(world_pt.x), FIX2FLT(world_pt.y), FIX2FLT(world_pt.z))); }
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; }
static Bool OnPlaneSensor(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_PlaneSensor *ps = (M_PlaneSensor *)sh->sensor; PSStack *stack = (PSStack *) gf_node_get_private(sh->sensor); if (ps->isActive && ( /*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 (ps->autoOffset) { ps->offset = ps->translation_changed; if (!is_cancel) gf_node_event_out(sh->sensor, 4/*"offset"*/); } ps->isActive = 0; if (!is_cancel) gf_node_event_out(sh->sensor, 5/*"isActive"*/); sh->grabbed = 0; return is_cancel ? 0 : 1; } /*mouse*/ else if (is_mouse) { if (!ps->isActive && (ev->type==GF_EVENT_MOUSEDOWN) && (ev->mouse.button==GF_MOUSE_LEFT) ) { gf_mx_copy(stack->initial_matrix, compositor->hit_local_to_world); gf_vec_diff(stack->start_drag, compositor->hit_local_point, ps->offset); stack->tracker.normal.x = stack->tracker.normal.y = 0; stack->tracker.normal.z = FIX_ONE; stack->tracker.d = - gf_vec_dot(stack->start_drag, stack->tracker.normal); ps->isActive = 1; gf_node_event_out(sh->sensor, 5/*"isActive"*/); sh->grabbed = 1; return 1; } else if (ps->isActive) { GF_Ray loc_ray; SFVec3f res; loc_ray = compositor->hit_world_ray; gf_mx_apply_ray(&stack->initial_matrix, &loc_ray); gf_plane_intersect_line(&stack->tracker, &loc_ray.orig, &loc_ray.dir, &res); ps->trackPoint_changed = res; gf_node_event_out(sh->sensor, 6/*"trackPoint_changed"*/); gf_vec_diff(res, res, stack->start_drag); /*clip*/ if (ps->minPosition.x <= ps->maxPosition.x) { if (res.x < ps->minPosition.x) res.x = ps->minPosition.x; if (res.x > ps->maxPosition.x) res.x = ps->maxPosition.x; } if (ps->minPosition.y <= ps->maxPosition.y) { if (res.y < ps->minPosition.y) res.y = ps->minPosition.y; if (res.y > ps->maxPosition.y) res.y = ps->maxPosition.y; } ps->translation_changed = res; gf_node_event_out(sh->sensor, 7/*"translation_changed"*/); return 1; } } else { if (!ps->isActive && is_over && (ev->type==GF_EVENT_KEYDOWN) && (ev->key.key_code==GF_KEY_ENTER)) { ps->isActive = 1; stack->start_drag = ps->offset; gf_node_event_out(sh->sensor, 5/*"isActive"*/); return 1; } else if (ps->isActive && (ev->type==GF_EVENT_KEYDOWN)) { SFVec3f res; Fixed diff = (ev->key.flags & GF_KEY_MOD_SHIFT) ? 5*FIX_ONE : FIX_ONE; if (!gf_sg_use_pixel_metrics(gf_node_get_graph(sh->sensor))) diff = gf_divfix(diff, INT2FIX(compositor->vp_width/2)); res = stack->start_drag; switch (ev->key.key_code) { case GF_KEY_LEFT: res.x -= diff; break; case GF_KEY_RIGHT: res.x += diff; break; case GF_KEY_UP: res.y += diff; break; case GF_KEY_DOWN: res.y -= diff; break; case GF_KEY_HOME: res = ps->offset; break; default: return 0; } /*clip*/ if (ps->minPosition.x <= ps->maxPosition.x) { if (res.x < ps->minPosition.x) res.x = ps->minPosition.x; if (res.x > ps->maxPosition.x) res.x = ps->maxPosition.x; } if (ps->minPosition.y <= ps->maxPosition.y) { if (res.y < ps->minPosition.y) res.y = ps->minPosition.y; if (res.y > ps->maxPosition.y) res.y = ps->maxPosition.y; } stack->start_drag = res; ps->translation_changed = res; gf_node_event_out(sh->sensor, 7/*"translation_changed"*/); return 1; } } return 0; }
static Bool OnDiscSensor(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_DiscSensor *ds = (M_DiscSensor *)sh->sensor; DiscSensorStack *stack = (DiscSensorStack *) gf_node_get_private(sh->sensor); if (ds->isActive && (!ds->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 (ds->autoOffset) { ds->offset = ds->rotation_changed; /*that's an exposedField*/ if (!is_cancel) gf_node_event_out(sh->sensor, 4/*"offset"*/); } ds->isActive = 0; if (!is_cancel) gf_node_event_out(sh->sensor, 5/*"isActive"*/); sh->grabbed = 0; return is_cancel ? 0 : 1; } else if (is_mouse) { if (!ds->isActive && (ev->type==GF_EVENT_MOUSEDOWN) && (ev->mouse.button==GF_MOUSE_LEFT)) { /*store inverse matrix*/ gf_mx_copy(stack->initial_matrix, compositor->hit_local_to_world); stack->start_angle = gf_atan2(compositor->hit_local_point.y, compositor->hit_local_point.x); ds->isActive = 1; gf_node_event_out(sh->sensor, 5/*"isActive"*/); sh->grabbed = 1; return 1; } else if (ds->isActive) { GF_Ray loc_ray; Fixed rot; SFVec3f res; loc_ray = compositor->hit_world_ray; gf_mx_apply_ray(&stack->initial_matrix, &loc_ray); compositor_get_2d_plane_intersection(&loc_ray, &res); rot = gf_atan2(res.y, res.x) - stack->start_angle + ds->offset; if (ds->minAngle < ds->maxAngle) { /*FIXME this doesn't work properly*/ if (rot < ds->minAngle) rot = ds->minAngle; if (rot > ds->maxAngle) rot = ds->maxAngle; } ds->rotation_changed = rot; gf_node_event_out(sh->sensor, 6/*"rotation_changed"*/); ds->trackPoint_changed.x = res.x; ds->trackPoint_changed.y = res.y; gf_node_event_out(sh->sensor, 7/*"trackPoint_changed"*/); return 1; } } else { if (!ds->isActive && is_over && (ev->type==GF_EVENT_KEYDOWN) && (ev->key.key_code==GF_KEY_ENTER)) { ds->isActive = 1; stack->start_angle = ds->offset; gf_node_event_out(sh->sensor, 5/*"isActive"*/); return 1; } else if (ds->isActive && (ev->type==GF_EVENT_KEYDOWN)) { Fixed res; Fixed diff = (ev->key.flags & GF_KEY_MOD_SHIFT) ? GF_PI/8 : GF_PI/64; res = stack->start_angle; switch (ev->key.key_code) { case GF_KEY_LEFT: case GF_KEY_UP: res += -diff; break; case GF_KEY_RIGHT: case GF_KEY_DOWN: res += diff; break; case GF_KEY_HOME: res = ds->offset; break; default: return 0; } if (ds->minAngle < ds->maxAngle) { /*FIXME this doesn't work properly*/ if (res < ds->minAngle) res = ds->minAngle; if (res > ds->maxAngle) res = ds->maxAngle; } stack->start_angle = res; ds->rotation_changed = res; gf_node_event_out(sh->sensor, 6/*"rotation_changed"*/); return 1; } } return 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; }
static Bool OnPlaneSensor2D(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_PlaneSensor2D *ps = (M_PlaneSensor2D *)sh->sensor; PS2DStack *stack = (PS2DStack *) gf_node_get_private(sh->sensor); if (ps->isActive && (!ps->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 (ps->autoOffset) { ps->offset = ps->translation_changed; if (!is_cancel) gf_node_event_out_str(sh->sensor, "offset"); } ps->isActive = 0; if (!is_cancel) gf_node_event_out_str(sh->sensor, "isActive"); sh->grabbed = 0; return is_cancel ? 0 : 1; } else if (is_mouse) { if (!ps->isActive && (ev->type==GF_EVENT_MOUSEDOWN) && (ev->mouse.button==GF_MOUSE_LEFT)) { gf_mx_copy(stack->initial_matrix, compositor->hit_local_to_world); stack->start_drag.x = compositor->hit_local_point.x - ps->offset.x; stack->start_drag.y = compositor->hit_local_point.y - ps->offset.y; ps->isActive = 1; gf_node_event_out_str(sh->sensor, "isActive"); sh->grabbed = 1; /*fallthrough to fire mouse coords*/ //return 1; } if (ps->isActive) { SFVec3f res; GF_Ray loc_ray; loc_ray = compositor->hit_world_ray; gf_mx_apply_ray(&stack->initial_matrix, &loc_ray); compositor_get_2d_plane_intersection(&loc_ray, &res); ps->trackPoint_changed.x = res.x; ps->trackPoint_changed.y = res.y; gf_node_event_out_str(sh->sensor, "trackPoint_changed"); res.x -= stack->start_drag.x; res.y -= stack->start_drag.y; /*clip*/ if (ps->minPosition.x <= ps->maxPosition.x) { if (res.x < ps->minPosition.x) res.x = ps->minPosition.x; if (res.x > ps->maxPosition.x) res.x = ps->maxPosition.x; } if (ps->minPosition.y <= ps->maxPosition.y) { if (res.y < ps->minPosition.y) res.y = ps->minPosition.y; if (res.y > ps->maxPosition.y) res.y = ps->maxPosition.y; } ps->translation_changed.x = res.x; ps->translation_changed.y = res.y; gf_node_event_out_str(sh->sensor, "translation_changed"); return 1; } } else { if (!ps->isActive && is_over && (ev->type==GF_EVENT_KEYDOWN) && (ev->key.key_code==GF_KEY_ENTER)) { ps->isActive = 1; stack->start_drag = ps->offset; gf_node_event_out_str(sh->sensor, "isActive"); return 1; } else if (ps->isActive && (ev->type==GF_EVENT_KEYDOWN)) { SFVec2f res; Fixed diff = (ev->key.flags & GF_KEY_MOD_SHIFT) ? 5*FIX_ONE : FIX_ONE; if (!gf_sg_use_pixel_metrics(gf_node_get_graph(sh->sensor))) diff = gf_divfix(diff, compositor->vp_width/2); res = stack->start_drag; switch (ev->key.key_code) { case GF_KEY_LEFT: res.x += -diff; break; case GF_KEY_RIGHT: res.x += diff; break; case GF_KEY_UP: res.y += diff; break; case GF_KEY_DOWN: res.y += -diff; break; case GF_KEY_HOME: res = ps->offset; break; default: return 0; } /*clip*/ if (ps->minPosition.x <= ps->maxPosition.x) { if (res.x < ps->minPosition.x) res.x = ps->minPosition.x; if (res.x > ps->maxPosition.x) res.x = ps->maxPosition.x; } if (ps->minPosition.y <= ps->maxPosition.y) { if (res.y < ps->minPosition.y) res.y = ps->minPosition.y; if (res.y > ps->maxPosition.y) res.y = ps->maxPosition.y; } ps->translation_changed = res; gf_node_event_out_str(sh->sensor, "translation_changed"); ps->trackPoint_changed.x = res.x + stack->start_drag.x; ps->trackPoint_changed.y = res.y + stack->start_drag.y; gf_node_event_out_str(sh->sensor, "trackPoint_changed"); stack->start_drag = res; return 1; } } return 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"); } }
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"); } }