📄 sensor_stacks.c
字号:
}}SensorHandler *r3d_touch_sensor_get_handler(GF_Node *n){ TouchSensorStack *ts = (TouchSensorStack *)gf_node_get_private(n); return &ts->hdl;}void R3D_InitTouchSensor(Render3D *sr, GF_Node *node){ TouchSensorStack *st; GF_SAFEALLOC(st, TouchSensorStack); st->hdl.IsEnabled = ts_is_enabled; st->hdl.OnUserEvent = OnTouchSensor; st->hdl.owner = node; st->compositor = sr->compositor; st->compositor->interaction_sensors++; gf_node_set_private(node, st); gf_node_set_callback_function(node, DestroyTouchSensor);}void RenderProximitySensor(GF_Node *node, void *rs, Bool is_destroy){ SFVec3f user_pos, dist, up; SFRotation ori; GF_Matrix mx; RenderEffect3D *eff = (RenderEffect3D *)rs; M_ProximitySensor *ps = (M_ProximitySensor *)node; if (is_destroy) 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, ps->center, ps->size); gf_vec_diff(eff->bbox.min_edge, ps->center, ps->size); gf_bbox_refresh(&eff->bbox); return; } else if (!ps->enabled || (eff->traversing_mode != TRAVERSE_SORT) ) return; /*TODO FIXME - find a way to cache inverted matrix*/ gf_mx_copy(mx, eff->model_matrix); gf_mx_inverse(&mx); /*get use pos in local coord system*/ user_pos = eff->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_str(node, "isActive"); ps->enterTime = gf_node_get_scene_time(node); gf_node_event_out_str(node, "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_str(node, "position_changed"); } dist = eff->camera->target; gf_mx_apply_vec(&mx, &dist); up = eff->camera->up; gf_mx_apply_vec(&mx, &up); ori = camera_get_orientation(user_pos, dist, eff->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_str(node, "orientation_changed"); } } else if (ps->isActive) { ps->isActive = 0; gf_node_event_out_str(node, "isActive"); ps->exitTime = gf_node_get_scene_time(node); gf_node_event_out_str(node, "exitTime"); }}void R3D_InitProximitySensor(Render3D *sr, GF_Node *node){ gf_node_set_callback_function(node, RenderProximitySensor);}typedef struct { SFVec3f start_drag; GF_Plane tracker; GF_Matrix initial_matrix; GF_Renderer *compositor; SensorHandler hdl;} PSStack;static void DestroyPlaneSensor(GF_Node *node, void *rs, Bool is_destroy){ if (is_destroy) { PSStack *st = (PSStack *) gf_node_get_private(node); R3D_SensorDeleted(st->compositor, &st->hdl); free(st); }}static Bool ps_is_enabled(GF_Node *n){ M_PlaneSensor *ps = (M_PlaneSensor *)n; return (ps->enabled || ps->isActive);}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"); }}SensorHandler *r3d_ps_get_handler(GF_Node *n){ PSStack *st = (PSStack *)gf_node_get_private(n); return &st->hdl;}void R3D_InitPlaneSensor(Render3D *sr, GF_Node *node){ PSStack *st; GF_SAFEALLOC(st, PSStack); st->hdl.IsEnabled = ps_is_enabled; st->hdl.OnUserEvent = OnPlaneSensor; st->hdl.owner = node; st->compositor = sr->compositor; st->compositor->interaction_sensors++; gf_node_set_private(node, st); gf_node_set_callback_function(node, DestroyPlaneSensor);}typedef struct { SensorHandler hdl; GF_Renderer *compositor; GF_Matrix init_matrix; Bool disk_mode; SFVec3f grab_start; GF_Plane yplane, zplane, xplane;} CylinderSensorStack;static void DestroyCylinderSensor(GF_Node *node, void *rs, Bool is_destroy){ if (is_destroy) { CylinderSensorStack *st = (CylinderSensorStack *) gf_node_get_private(node); R3D_SensorDeleted(st->compositor, &st->hdl); free(st); }}static Bool cs_is_enabled(GF_Node *n){ M_CylinderSensor *cs = (M_CylinderSensor *)n; return (cs->enabled || cs->isActive);}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"); }}SensorHandler *r3d_cs_get_handler(GF_Node *n){ CylinderSensorStack *st = (CylinderSensorStack *)gf_node_get_private(n); return &st->hdl;}void R3D_InitCylinderSensor(Render3D *sr, GF_Node *node){ CylinderSensorStack *st; GF_SAFEALLOC(st, CylinderSensorStack); st->hdl.IsEnabled = cs_is_enabled; st->hdl.OnUserEvent = OnCylinderSensor; st->hdl.owner = node; st->compositor = sr->compositor; st->compositor->interaction_sensors++; gf_node_set_private(node, st); gf_node_set_callback_function(node, DestroyCylinderSensor);}typedef struct { SensorHandler hdl; GF_Renderer *compositor; Fixed radius; /*center in world coords */ SFVec3f grab_vec, center;} SphereSensorStack;static void DestroySphereSensor(GF_Node *node, void *rs, Bool is_destroy){ if (is_destroy) { SphereSensorStack *st = (SphereSensorStack *) gf_node_get_private(node); R3D_SensorDeleted(st->compositor, &st->hdl); free(st); }}static Bool sphere_is_enabled(GF_Node *n){ M_SphereSensor *ss = (M_SphereSensor *)n; return (ss->enabled || ss->isActive);}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"); }}SensorHandler *r3d_sphere_get_handler(GF_Node *n){ SphereSensorStack *st = (SphereSensorStack *)gf_node_get_private(n); return &st->hdl;}void R3D_InitSphereSensor(Render3D *sr, GF_Node *node){ SphereSensorStack *st; GF_SAFEALLOC(st, SphereSensorStack); st->hdl.IsEnabled = sphere_is_enabled; st->hdl.OnUserEvent = OnSphereSensor; st->hdl.owner = node; st->compositor = sr->compositor; st->compositor->interaction_sensors++; gf_node_set_private(node, st); gf_node_set_callback_function(node, DestroySphereSensor);}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"); } }}void R3D_InitVisibilitySensor(Render3D *sr, GF_Node *node){ gf_node_set_callback_function(node, RenderVisibilitySensor);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -