📄 sensor_stacks.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / 3D rendering module * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include "render3d_nodes.h"/*for anchor*/#include "grouping.h"/*for anchor processing, which needs to be filtered at the inline scene level*/#include <gpac/internal/terminal_dev.h>typedef struct{ GF_Node *owner; GF_Renderer *compositor; GROUPINGNODESTACK Bool enabled, active; SensorHandler hdl;} AnchorStack;static void RenderAnchor(GF_Node *node, void *rs, Bool is_destroy){ AnchorStack *st = (AnchorStack *) gf_node_get_private(node); RenderEffect3D *eff = (RenderEffect3D *)rs; if (is_destroy) { R3D_SensorDeleted(st->compositor, &st->hdl); DeleteGroupingNode((GroupingNode *)st); free(st); return; } if (!st->compositor->user->EventProc) { st->enabled = 0; return; } /*note we don't clear dirty flag, this is done in traversing*/ if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) { MFURL *url; if (gf_node_get_tag(node)==TAG_MPEG4_Anchor) { url = & ((M_Anchor *)node)->url; } else { url = & ((X_Anchor *)node)->url; } st->enabled = 0; if (url->count && url->vals[0].url && strlen(url->vals[0].url) ) st->enabled = 1; } grouping_traverse((GroupingNode*)st, eff, NULL);}static void OnAnchor(SensorHandler *sh, Bool is_over, GF_Event *ev, RayHitInfo *hit_info){ GF_Event evt; MFURL *url; AnchorStack *st = (AnchorStack *) gf_node_get_private(sh->owner); if ((ev->type==GF_EVENT_MOUSEDOWN) && (ev->mouse.button==GF_MOUSE_LEFT)) st->active = 1; else if (st->active && (ev->type==GF_EVENT_MOUSEUP) && (ev->mouse.button==GF_MOUSE_LEFT) ) { u32 i; if (gf_node_get_tag(sh->owner)==TAG_MPEG4_Anchor) { url = & ((M_Anchor *)sh->owner)->url; evt.navigate.param_count = ((M_Anchor *)sh->owner)->parameter.count; evt.navigate.parameters = (const char **) ((M_Anchor *)sh->owner)->parameter.vals; } else { url = & ((X_Anchor *)sh->owner)->url; evt.navigate.param_count = ((X_Anchor *)sh->owner)->parameter.count; evt.navigate.parameters = (const char **) ((X_Anchor *)sh->owner)->parameter.vals; } evt.type = GF_EVENT_NAVIGATE; i=0; while (i<url->count) { evt.navigate.to_url = url->vals[i].url; if (!evt.navigate.to_url) break; /*current scene navigation*/ if (evt.navigate.to_url[0] == '#') { GF_Node *bindable; evt.navigate.to_url++; bindable = gf_sg_find_node_by_name(gf_node_get_graph(sh->owner), (char *) evt.navigate.to_url); if (bindable) { Bindable_SetSetBind(bindable, 1); break; } } else if (st->compositor->term) { if (gf_is_process_anchor(sh->owner, &evt)) break; } else if (st->compositor->user->EventProc) { if (st->compositor->user->EventProc(st->compositor->user->opaque, &evt)) break; } i++; } } else if (ev->type==GF_EVENT_MOUSEMOVE) { if (st->compositor->user->EventProc) { evt.type = GF_EVENT_NAVIGATE_INFO; if (gf_node_get_tag(sh->owner)==TAG_MPEG4_Anchor) { evt.navigate.to_url = ((M_Anchor *)sh->owner)->description.buffer; url = & ((M_Anchor *)sh->owner)->url; } else { evt.navigate.to_url = ((X_Anchor *)sh->owner)->description.buffer; url = & ((X_Anchor *)sh->owner)->url; } if (!evt.navigate.to_url || !strlen(evt.navigate.to_url)) evt.navigate.to_url = url->vals[0].url; st->compositor->user->EventProc(st->compositor->user->opaque, &evt); } }}static Bool anchor_is_enabled(GF_Node *node){ AnchorStack *st = (AnchorStack *) gf_node_get_private(node); return st->enabled;}static void on_activate_anchor(GF_Node *node){ GF_Event ev; AnchorStack *st = (AnchorStack *) gf_node_get_private(node); if (!((M_Anchor *)node)->on_activate) return; ev.type = GF_EVENT_MOUSEUP; ev.mouse.x = ev.mouse.y = 0; ev.mouse.button = GF_MOUSE_LEFT; OnAnchor(&st->hdl, 0, &ev, NULL);}SensorHandler *r3d_anchor_get_handler(GF_Node *n){ AnchorStack *st = (AnchorStack *) gf_node_get_private(n); return &st->hdl;}void R3D_InitAnchor(Render3D *sr, GF_Node *node){ AnchorStack *stack; GF_SAFEALLOC(stack, AnchorStack); stack->hdl.IsEnabled = anchor_is_enabled; stack->hdl.OnUserEvent = OnAnchor; stack->hdl.owner = node; if (gf_node_get_tag(node)==TAG_MPEG4_Anchor) { ((M_Anchor *)node)->on_activate = on_activate_anchor; SetupGroupingNode((GroupingNode*)stack, sr->compositor, node, & ((M_Anchor *)node)->children); } else { SetupGroupingNode((GroupingNode*)stack, sr->compositor, node, & ((X_Anchor *)node)->children); } sr->compositor->interaction_sensors++; gf_node_set_private(node, stack); gf_node_set_callback_function(node, RenderAnchor);}typedef struct { SensorHandler hdl; GF_Renderer *compositor; Fixed start_angle; GF_Matrix initial_matrix;} DiscSensorStack;static void DestroyDiscSensor(GF_Node *node, void *rs, Bool is_destroy){ if (is_destroy) { DiscSensorStack *st = (DiscSensorStack *) gf_node_get_private(node); R3D_SensorDeleted(st->compositor, &st->hdl); free(st); }}static Bool ds_is_enabled(GF_Node *n){ M_DiscSensor *ds = (M_DiscSensor *)n; return (ds->enabled || ds->isActive);}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"); }}SensorHandler *r3d_ds_get_handler(GF_Node *n){ DiscSensorStack *st = (DiscSensorStack *)gf_node_get_private(n); return &st->hdl;}void R3D_InitDiscSensor(Render3D *sr, GF_Node *node){ DiscSensorStack *st; GF_SAFEALLOC(st, DiscSensorStack); st->hdl.IsEnabled = ds_is_enabled; st->hdl.OnUserEvent = OnDiscSensor; st->hdl.owner = node; st->compositor = sr->compositor; sr->compositor->interaction_sensors++; gf_node_set_private(node, st); gf_node_set_callback_function(node, DestroyDiscSensor);}typedef struct { SFVec2f start_drag; GF_Matrix initial_matrix; GF_Renderer *compositor; SensorHandler hdl;} PS2DStack;static void DestroyPlaneSensor2D(GF_Node *node, void *rs, Bool is_destroy){ if (is_destroy) { PS2DStack *st = (PS2DStack *) gf_node_get_private(node); R3D_SensorDeleted(st->compositor, &st->hdl); free(st); }}static Bool ps2D_is_enabled(GF_Node *n){ M_PlaneSensor2D *ps2d = (M_PlaneSensor2D *)n; return (ps2d->enabled || ps2d->isActive);}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"); }}SensorHandler *r3d_ps2D_get_handler(GF_Node *n){ PS2DStack *st = (PS2DStack *)gf_node_get_private(n); return &st->hdl;}void R3D_InitPlaneSensor2D(Render3D *sr, GF_Node *node){ PS2DStack *st; GF_SAFEALLOC(st, PS2DStack); st->hdl.IsEnabled = ps2D_is_enabled; st->hdl.OnUserEvent = OnPlaneSensor2D; st->hdl.owner = node; st->compositor = sr->compositor; st->compositor->interaction_sensors++; gf_node_set_private(node, st); gf_node_set_callback_function(node, DestroyPlaneSensor2D);}typedef struct { Double last_time; GF_Renderer *compositor; SensorHandler hdl;} Prox2DStack;static void DestroyProximitySensor2D(GF_Node *node, void *rs, Bool is_destroy){ if (is_destroy) { Prox2DStack *st = (Prox2DStack *) gf_node_get_private(node); R3D_SensorDeleted(st->compositor, &st->hdl); free(st); }}static Bool prox2D_is_enabled(GF_Node *n){ return ((M_ProximitySensor2D *) n)->enabled;}static Bool prox2D_is_in_sensor(Prox2DStack *st, M_ProximitySensor2D *ps, Fixed X, Fixed Y){ if (X < ps->center.x - ps->size.x/2) return 0; if (X > ps->center.x + ps->size.x/2) return 0; if (Y < ps->center.y - ps->size.y/2) return 0; if (Y > ps->center.y + ps->size.y/2) return 0; return 1;}static void OnProximitySensor2D(SensorHandler *sh, Bool is_over, GF_Event *ev, RayHitInfo *hit_info){ M_ProximitySensor2D *ps = (M_ProximitySensor2D *)sh->owner; Prox2DStack *stack = (Prox2DStack *) gf_node_get_private(sh->owner); assert(ps->enabled); if (is_over) { stack->last_time = gf_node_get_scene_time(sh->owner); if (prox2D_is_in_sensor(stack, ps, hit_info->local_point.x, hit_info->local_point.y)) { ps->position_changed.x = hit_info->local_point.x; ps->position_changed.y = hit_info->local_point.y; gf_node_event_out_str(sh->owner, "position_changed"); if (!ps->isActive) { ps->isActive = 1; gf_node_event_out_str(sh->owner, "isActive"); ps->enterTime = stack->last_time; gf_node_event_out_str(sh->owner, "enterTime"); } return; } } /*either we're not over the shape or we're not in sensor*/ if (ps->isActive) { ps->exitTime = stack->last_time; gf_node_event_out_str(sh->owner, "exitTime"); ps->isActive = 0; gf_node_event_out_str(sh->owner, "isActive"); }}SensorHandler *r3d_prox2D_get_handler(GF_Node *n){ Prox2DStack *st = (Prox2DStack *)gf_node_get_private(n); return &st->hdl;}void R3D_InitProximitySensor2D(Render3D *sr, GF_Node *node){ Prox2DStack *st; GF_SAFEALLOC(st, Prox2DStack); st->hdl.IsEnabled = prox2D_is_enabled; st->hdl.OnUserEvent = OnProximitySensor2D; st->hdl.owner = node; st->compositor = sr->compositor; st->compositor->interaction_sensors++; gf_node_set_private(node, st); gf_node_set_callback_function(node, DestroyProximitySensor2D);}typedef struct { SensorHandler hdl; Bool mouse_down; GF_Renderer *compositor;} TouchSensorStack;static void DestroyTouchSensor(GF_Node *node, void *rs, Bool is_destroy){ if (is_destroy) { TouchSensorStack *st = (TouchSensorStack *) gf_node_get_private(node); R3D_SensorDeleted(st->compositor, &st->hdl); free(st); }}static Bool ts_is_enabled(GF_Node *n){ return ((M_TouchSensor *) n)->enabled;}static void OnTouchSensor(SensorHandler *sh, Bool is_over, GF_Event *ev, RayHitInfo *hit_info){ M_TouchSensor *ts = (M_TouchSensor *)sh->owner; TouchSensorStack *st = (TouchSensorStack *) gf_node_get_private(sh->owner); //assert(ts->enabled); /*isActive becomes false, send touch time*/ if ((ev->type==GF_EVENT_MOUSEUP) && (ev->mouse.button==GF_MOUSE_LEFT) && ts->isActive) { ts->touchTime = gf_node_get_scene_time(sh->owner); gf_node_event_out_str(sh->owner, "touchTime"); ts->isActive = 0; gf_node_event_out_str(sh->owner, "isActive"); R3D_SetGrabbed(st->compositor, 0); } if (is_over != ts->isOver) { ts->isOver = is_over; gf_node_event_out_str(sh->owner, "isOver"); } if (!ts->isActive && (ev->type==GF_EVENT_MOUSEDOWN) && (ev->mouse.button==GF_MOUSE_LEFT)) { ts->isActive = 1; gf_node_event_out_str(sh->owner, "isActive"); R3D_SetGrabbed(st->compositor, 1); } if (is_over) { ts->hitPoint_changed = hit_info->local_point; gf_node_event_out_str(sh->owner, "hitPoint_changed"); ts->hitNormal_changed = hit_info->hit_normal; gf_node_event_out_str(sh->owner, "hitNormal_changed"); ts->hitTexCoord_changed = hit_info->hit_texcoords; gf_node_event_out_str(sh->owner, "hitTexCoord_changed");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -