Example #1
0
/* This function is called when a modification to the node has been made (scripts, updates or events ...) */
void gf_smil_timing_modified(GF_Node *node, GF_FieldInfo *field)
{
	SMILTimingAttributesPointers *timingp = NULL;
	SMIL_Timing_RTI *rti;
	
	timingp = ((SVGTimedAnimBaseElement *)node)->timingp;
	
	if (!timingp) return;
	rti = timingp->runtime;
	if (!rti) return;

	GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing   ] Time %f - Timed element %s - Modification\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
	if (rti->current_interval->begin == -1) {
		gf_smil_timing_get_next_interval(rti, 1, rti->current_interval, gf_node_get_scene_time((GF_Node*)rti->timed_elt));
	} else {
		/* we don't have the right to modify the end of an element if it's not in unresolved state */
		if (rti->current_interval->end == -1) gf_smil_timing_get_interval_end(rti, rti->current_interval);
		if (0 && rti->current_interval->end == -2) {
			/* TODO: check if the interval can be discarded if end = -2,
			   probably no, because the interval is currently running*/
			GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing   ] Time %f - Timed element %s - Wrong Interval\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
			rti->current_interval->begin = -1;
			rti->current_interval->end = -1;
			return;
		}
		
		gf_smil_timing_compute_active_duration(rti, rti->current_interval);
		gf_smil_timing_print_interval(rti, 1, rti->current_interval);
	}
	gf_smil_timing_get_next_interval(rti, 0, rti->next_interval, gf_node_get_scene_time((GF_Node*)rti->timed_elt));

	/* mark that this element has been modified and 
	   need to be reinserted at its proper place in the list of timed elements in the scenegraph */
	gf_smil_mark_modified(rti, 0);
}
Example #2
0
Bool gf_smil_notify_timed_elements(GF_SceneGraph *sg)
{
	SMIL_Timing_RTI *rti;
	u32 active_count = 0, i = 0;
	s32 ret;
	if (!sg) return 0;

	sg->update_smil_timing = 0;
	while((rti = (SMIL_Timing_RTI *)gf_list_enum(sg->smil_timed_elements, &i))) {
		//scene_time = rti->timed_elt->sgprivate->scenegraph->GetSceneTime(rti->timed_elt->sgprivate->scenegraph->userpriv);
		ret = gf_smil_timing_notify_time(rti, gf_node_get_scene_time((GF_Node*)rti->timed_elt));
		if (ret == -1) {
			/* special case for discard element */
			i--;
		} else if (ret == -2) {
			/* special return value, -2 means that the tested timed element is waiting to begin
			   Assuming that the timed elements are sorted by begin order, 
			   the next ones don't need to be checked */
			break;
		} else {
			active_count += ret;
		}
	}

	/*in case an anim triggers another one previously inactivated...
	TODO FIXME: it would be much better to stack anim as active/inactive*/
	while (sg->update_smil_timing) {
		sg->update_smil_timing = 0;
		i = 0;
		while((rti = (SMIL_Timing_RTI *)gf_list_enum(sg->smil_timed_elements, &i))) {
			/*this means the anim has been, modified, re-evaluate it*/
			if (rti->scene_time==-1) {
				ret = gf_smil_timing_notify_time(rti, gf_node_get_scene_time((GF_Node*)rti->timed_elt) );
				if (ret == -1) {
					/* special case for discard element */
					i--;
				} else if (ret == -2) {
					/* special return value, -2 means that the tested timed element is waiting to begin
					   Assuming that the timed elements are sorted by begin order, 
					   the next ones don't need to be checked */
					break;
				} else {
					active_count += ret;
				}
			}
		}
	}
	return (active_count>0);
}
Example #3
0
static Bool OnProximitySensor2D(GF_SensorHandler *sh, Bool is_over, Bool is_cancel, GF_Event *ev, GF_Compositor *compositor)
{
	M_ProximitySensor2D *ps = (M_ProximitySensor2D *)sh->sensor;
	Prox2DStack *stack = (Prox2DStack *) gf_node_get_private(sh->sensor);

	assert(ps->enabled);

	if (is_over) {
		stack->last_time = gf_node_get_scene_time(sh->sensor);
		if (is_cancel) return 0;
		if (prox2D_is_in_sensor(stack, ps, compositor->hit_local_point.x, compositor->hit_local_point.y)) {
			ps->position_changed.x = compositor->hit_local_point.x;
			ps->position_changed.y = compositor->hit_local_point.y;
			gf_node_event_out(sh->sensor, 4/*"position_changed"*/);

			if (!ps->isActive) {
				ps->isActive = 1;
				gf_node_event_out(sh->sensor, 3/*"isActive"*/);
				ps->enterTime = stack->last_time;
				gf_node_event_out(sh->sensor, 6/*"enterTime"*/);
			}
			return 1;
		}
	}
	/*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(sh->sensor, 7/*"exitTime"*/);
		ps->isActive = 0;
		gf_node_event_out(sh->sensor, 3/*"isActive"*/);
		return 1;
	}
	return 0;
}
Example #4
0
static void animationstream_update_time(GF_TimeNode *st)
{
    Double time;
    M_AnimationStream *as = (M_AnimationStream *)st->udta;
    AnimationStreamStack *stack = (AnimationStreamStack *)gf_node_get_private(st->udta);

    /*not active, store start time and speed*/
    if ( ! as->isActive) {
        stack->start_time = as->startTime;
    }
    time = gf_node_get_scene_time(st->udta);

    if ((time < stack->start_time) || (stack->start_time < 0)) return;

    if (animationstream_get_speed(stack, as) && as->isActive) {
        //if stoptime is reached (>startTime) deactivate
        if ((as->stopTime > stack->start_time) && (time >= as->stopTime) ) {
            animationstream_deactivate(stack, as);
            return;
        }
        if (gf_mo_is_done(stack->stream)) {
            if (animationstream_get_loop(stack, as)) {
                gf_mo_restart(stack->stream);
            } else if (gf_mo_should_deactivate(stack->stream)) {
                animationstream_deactivate(stack, as);
            }
        }
    }

    /*we're (about to be) active: VRML:
    "A time-dependent node is inactive until its startTime is reached. When time now becomes greater than or
    equal to startTime, an isActive TRUE event is generated and the time-dependent node becomes active 	*/
    if (!as->isActive && !st->needs_unregister) animationstream_activate(stack, as);
}
Example #5
0
static void Conditional_execute(M_Conditional *node)
{
	char *buffer;
	u32 len;
	GF_BitStream *bs;
	GF_BifsDecoder *codec;
	GF_Proto *prevproto;
	GF_SceneGraph *prev_graph;
	ConditionalStack *priv = (ConditionalStack*)gf_node_get_private((GF_Node*)node);
	if (!priv) return;

	/*set the codec working graph to the node one (to handle conditional in protos)*/
	prev_graph = priv->codec->current_graph;
	priv->codec->current_graph = gf_node_get_graph((GF_Node*)node);
	assert(priv->codec->current_graph);

	priv->codec->info = priv->info;
	prevproto = priv->codec->pCurrentProto;
	priv->codec->pCurrentProto = NULL;
	if (priv->codec->current_graph->pOwningProto) priv->codec->pCurrentProto = priv->codec->current_graph->pOwningProto->proto_interface;

	/*set isActive - to clarify in the specs*/
	node->isActive = 1;
	gf_node_event_out((GF_Node *)node, 3/*"isActive"*/);
	if (!node->buffer.bufferSize) return;

	/*we may replace ourselves*/
	buffer = (char*)node->buffer.buffer;
	len = node->buffer.bufferSize;
	node->buffer.buffer = NULL;
	node->buffer.bufferSize = 0;
	bs = gf_bs_new(buffer, len, GF_BITSTREAM_READ);
	codec = priv->codec;
	codec->cts_offset = gf_node_get_scene_time((GF_Node*)node);
	/*a conditional may destroy/replace itself - to prevent that, protect node by a register/unregister ...*/
	gf_node_register((GF_Node*)node, NULL);
#ifdef GF_SELF_REPLACE_ENABLE
	/*and a conditional may destroy the entire scene!*/
	cur_graph->graph_has_been_reset = 0;
#endif
	gf_bifs_dec_command(codec, bs);
	gf_bs_del(bs);
#ifdef GF_SELF_REPLACE_ENABLE
	if (cur_graph->graph_has_been_reset) {
		return;
	}
#endif
	if (node->buffer.buffer) {
		gf_free(buffer);
	} else {
		node->buffer.buffer = (u8*)buffer;
		node->buffer.bufferSize = len;
	}
	//set isActive - to clarify in the specs
//	node->isActive = 0;
	gf_node_unregister((GF_Node*)node, NULL);
	codec->cts_offset = 0;
	codec->pCurrentProto = prevproto;
	codec->current_graph = prev_graph;
}
Example #6
0
static void audiobuffer_update_time(GF_TimeNode *tn)
{
	Double time;
	M_AudioBuffer *ab = (M_AudioBuffer *)tn->udta;
	AudioBufferStack *st = (AudioBufferStack *)gf_node_get_private(tn->udta);

	if (! ab->isActive) {
		st->start_time = ab->startTime;
	}
	time = gf_node_get_scene_time(tn->udta);
	if ((time<st->start_time) || (st->start_time<0)) return;
	
	if (ab->isActive) {
		if ( (ab->stopTime > st->start_time) && (time>=ab->stopTime)) {
			audiobuffer_deactivate(st, ab);
			return;
		}
		/*THIS IS NOT NORMATIVE*/
		if ( !ab->loop && st->done) {
			audiobuffer_deactivate(st, ab);
			return;
		}
	}
	if (!ab->isActive) audiobuffer_activate(st, ab);
}
Example #7
0
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");
	}
}
Example #8
0
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");
	}
}
Example #9
0
static Bool OnTouchSensor(GF_SensorHandler *sh, Bool is_over, Bool is_cancel, GF_Event *ev, GF_Compositor *compositor)
{
	Bool is_mouse = (ev->type<=GF_EVENT_MOUSEWHEEL);
	M_TouchSensor *ts = (M_TouchSensor *)sh->sensor;

	/*this is not specified in VRML, however we consider that a de-enabled sensor will not sent deactivation events*/
	if (!ts->enabled) {
		if (ts->isActive) {
			sh->grabbed = 0;
		}
		return 0;
	}

	/*isActive becomes false, send touch time*/
	if (ts->isActive) {
		if (
		    /*mouse*/ ((ev->type==GF_EVENT_MOUSEUP) && (ev->mouse.button==GF_MOUSE_LEFT) )
		    || /*keyboard*/ ((ev->type==GF_EVENT_KEYUP) && (ev->key.key_code==GF_KEY_ENTER) )
		) {
			ts->touchTime = gf_node_get_scene_time(sh->sensor);
			if (!is_cancel) gf_node_event_out(sh->sensor, 6/*"touchTime"*/);
			ts->isActive = 0;
			if (!is_cancel) gf_node_event_out(sh->sensor, 4/*"isActive"*/);
			sh->grabbed = 0;
			return is_cancel ? 0 : 1;
		}
	}
	if (is_over != ts->isOver) {
		ts->isOver = is_over;
		if (!is_cancel) gf_node_event_out(sh->sensor, 5/*"isOver"*/);
		return is_cancel ? 0 : 1;
	}
	if (!ts->isActive && is_over) {
		if (/*mouse*/ ((ev->type==GF_EVENT_MOUSEDOWN) && (ev->mouse.button==GF_MOUSE_LEFT))
		              || /*keyboard*/ ((ev->type==GF_EVENT_KEYDOWN) && (ev->key.key_code==GF_KEY_ENTER))
		   ) {
			ts->isActive = 1;
			gf_node_event_out(sh->sensor, 4/*"isActive"*/);
			sh->grabbed = 1;
			return 1;
		}
		if (ev->type==GF_EVENT_MOUSEUP) return 0;
	}
	if (is_over && is_mouse && (ev->type==GF_EVENT_MOUSEMOVE) ) {
		/*THIS IS NOT CONFORMANT, the hitpoint should be in the touchsensor coordinate system, eg we
		should store the matrix from TS -> shape and apply that ...*/
		ts->hitPoint_changed = compositor->hit_local_point;
		gf_node_event_out(sh->sensor, 1/*"hitPoint_changed"*/);
		ts->hitNormal_changed = compositor->hit_normal;
		gf_node_event_out(sh->sensor, 2/*"hitNormal_changed"*/);
		ts->hitTexCoord_changed = compositor->hit_texcoords;
		gf_node_event_out(sh->sensor, 3/*"hitTexCoord_changed"*/);
		return 1;
	}
	return 0;
}
Example #10
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"*/);
		}
	}
}
Example #11
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");
		}
	}
}
Example #12
0
GF_EXPORT
GF_Err gf_sc_texture_play(GF_TextureHandler *txh, MFURL *url)
{
	Double offset = 0;
	Bool loop = 0;
	if (txh->compositor->term && (txh->compositor->term->play_state!=GF_STATE_PLAYING)) {
		offset = gf_node_get_scene_time(txh->owner);
		loop = /*gf_mo_get_loop(gf_mo_register(txh->owner, url, 0, 0), 0)*/ 1;
	}
	return gf_sc_texture_play_from_to(txh, url, offset, -1, loop, 0);
}
Example #13
0
void TraverseCollision(GF_Node *node, void *rs, Bool is_destroy)
{
	u32 collide_flags;
	SFVec3f last_point;
	Fixed last_dist;
	M_Collision *col = (M_Collision *)node;
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;
	GroupingNode *group = (GroupingNode *) gf_node_get_private(node);

	if (is_destroy) {
		gf_sc_check_focus_upon_destroy(node);
		group_3d_delete(node);
		return;
	}

	if (tr_state->traversing_mode != TRAVERSE_COLLIDE) {
		group_3d_traverse(node, group, tr_state);
	} else if (col->collide) {

		collide_flags = tr_state->camera->collide_flags;
		last_dist = tr_state->camera->collide_dist;
		tr_state->camera->collide_flags &= 0;
		tr_state->camera->collide_dist = FIX_MAX;
		last_point = tr_state->camera->collide_point;

		if (col->proxy) {
			/*always check bounds to update any dirty node*/
			tr_state->traversing_mode = TRAVERSE_GET_BOUNDS;
			gf_node_traverse(col->proxy, rs);

			tr_state->traversing_mode = TRAVERSE_COLLIDE;
			gf_node_traverse(col->proxy, rs);
		} else {
			group_3d_traverse(node, group, (GF_TraverseState*)rs);
		}
		if (tr_state->camera->collide_flags & CF_COLLISION) {
			col->collideTime = gf_node_get_scene_time(node);
			gf_node_event_out(node, 5/*"collideTime"*/);
			/*if not closer restore*/
			if (collide_flags && (last_dist<tr_state->camera->collide_dist)) {
				tr_state->camera->collide_flags = collide_flags;
				tr_state->camera->collide_dist = last_dist;
				tr_state->camera->collide_point = last_point;
			}
		} else {
			tr_state->camera->collide_flags = collide_flags;
			tr_state->camera->collide_dist = last_dist;
		}
	}
}
Example #14
0
static void movietexture_update_time(GF_TimeNode *st)
{
	Double time;
	M_MovieTexture *mt = (M_MovieTexture *)st->udta;
	MovieTextureStack *stack = (MovieTextureStack *)gf_node_get_private(st->udta);

	/*not active, store start time and speed*/
	if ( ! mt->isActive) {
		stack->start_time = mt->startTime;
	}
	time = gf_node_get_scene_time(st->udta);

	if (time < stack->start_time ||
	        /*special case if we're getting active AFTER stoptime */
	        (!mt->isActive && (mt->stopTime > stack->start_time) && (time>=mt->stopTime))
//		|| (!stack->start_time && !stack->is_x3d && !mt->loop)
	   ) {
		/*opens stream only at first access to fetch first frame*/
		if (stack->fetch_first_frame) {
			stack->fetch_first_frame = 0;
			if (!stack->txh.is_open)
				gf_sc_texture_play(&stack->txh, &mt->url);
			else
				gf_mo_resume(stack->txh.stream);
		}
		return;
	}

	if (movietexture_get_speed(stack, mt) && mt->isActive) {
		/*if stoptime is reached (>startTime) deactivate*/
		if ((mt->stopTime > stack->start_time) && (time >= mt->stopTime) ) {
			movietexture_deactivate(stack, mt);
			return;
		}
	}

	/*we're (about to be) active: VRML:
	"A time-dependent node is inactive until its startTime is reached. When time now becomes greater than or
	equal to startTime, an isActive TRUE event is generated and the time-dependent node becomes active 	*/

	if (! mt->isActive) movietexture_activate(stack, mt, time);
	stack->txh.stream_finished = GF_FALSE;
}
Example #15
0
static void audiosource_update_time(GF_TimeNode *tn)
{
	Double time;
	M_AudioSource *as = (M_AudioSource *)tn->udta;
	AudioSourceStack *st = (AudioSourceStack *)gf_node_get_private(tn->udta);

	if (! st->is_active) {
		st->start_time = as->startTime;
		st->input.speed = as->speed;
	}
	time = gf_node_get_scene_time(tn->udta);
	if ((time<st->start_time) || (st->start_time<0)) return;
	
	if (st->input.input_ifce.GetSpeed(st->input.input_ifce.callback) && st->is_active) {
		if ( (as->stopTime > st->start_time) && (time>=as->stopTime)) {
			audiosource_deactivate(st, as);
			return;
		}
	}
	if (!st->is_active) audiosource_activate(st, as);
}
Example #16
0
static void audioclip_update_time(GF_TimeNode *tn)
{
	Double time;
	M_AudioClip *ac = (M_AudioClip *)tn->udta;
	AudioClipStack *st = (AudioClipStack *)gf_node_get_private(tn->udta);

	if (st->failure) return;
	if (! ac->isActive) {
		st->start_time = ac->startTime;
		st->input.speed = ac->pitch;
	}
	time = gf_node_get_scene_time(tn->udta);
	if ((time<st->start_time) || (st->start_time<0)) return;
	
	if (ac->isActive) {
		if ( (ac->stopTime > st->start_time) && (time>=ac->stopTime)) {
			audioclip_deactivate(st, ac);
			return;
		}
	}
	if (!ac->isActive) audioclip_activate(st, ac);
}
Example #17
0
static void TTD_ApplySample(TTDPriv *priv, GF_TextSample *txt, u32 sdi, Bool is_utf_16, u32 sample_duration)
{
	u32 i, nb_lines, start_idx, count;
	s32 *id, thw, thh, tw, th, offset;
	Bool vertical;
	MFInt32 idx;
	SFString *s;
	GF_BoxRecord br;
	M_Material2D *n;
	M_Form *form;
	u16 utf16_text[5000];
	u32 char_offset, char_count;
	GF_List *chunks;
	TTDTextChunk *tc;
	GF_Box *a;
	GF_TextSampleDescriptor *td = NULL;

	/*stop timer sensor*/
	if (gf_list_count(priv->blink_nodes)) {
		priv->ts_blink->stopTime = gf_node_get_scene_time((GF_Node *) priv->ts_blink);
		gf_node_changed((GF_Node *) priv->ts_blink, NULL);
	}
	priv->ts_scroll->stopTime = gf_node_get_scene_time((GF_Node *) priv->ts_scroll);
	gf_node_changed((GF_Node *) priv->ts_scroll, NULL);
	/*flush routes to avoid getting the set_fraction of the scroll sensor deactivation*/
	gf_sg_activate_routes(priv->inlineScene->graph);

	TTD_ResetDisplay(priv);
	if (!sdi || !txt || !txt->len) return;

	i=0;
	while ((td = (GF_TextSampleDescriptor *)gf_list_enum(priv->cfg->sample_descriptions, &i))) {
		if (td->sample_index==sdi) break;
		td = NULL;
	}
	if (!td) return;


	vertical = (td->displayFlags & GF_TXT_VERTICAL) ? 1 : 0;

	/*set back color*/
	/*do we fill the text box or the entire text track region*/
	if (td->displayFlags & GF_TXT_FILL_REGION) {
		priv->mat_box->transparency = FIX_ONE;
		n = priv->mat_track;
	} else {
		priv->mat_track->transparency = FIX_ONE;
		n = priv->mat_box;
	}

	n->transparency = FIX_ONE - INT2FIX((td->back_color>>24) & 0xFF) / 255;
	n->emissiveColor.red = INT2FIX((td->back_color>>16) & 0xFF) / 255;
	n->emissiveColor.green = INT2FIX((td->back_color>>8) & 0xFF) / 255;
	n->emissiveColor.blue = INT2FIX((td->back_color) & 0xFF) / 255;
	gf_node_changed((GF_Node *) n, NULL);

	if (txt->box) {
		br = txt->box->box;
	} else {
		br = td->default_pos;
	}
	if (!br.right || !br.bottom) {
		br.top = br.left = 0;
		br.right = priv->cfg->text_width;
		br.bottom = priv->cfg->text_height;
	}
	thw = br.right - br.left;
	thh = br.bottom - br.top;
	if (!thw || !thh) {
		br.top = br.left = 0;
		thw = priv->cfg->text_width;
		thh = priv->cfg->text_height;
	}

	priv->dlist->size.x = INT2FIX(thw);
	priv->dlist->size.y = INT2FIX(thh);

	/*disable backgrounds if not used*/
	if (priv->mat_track->transparency<FIX_ONE) {
		if (priv->rec_track->size.x != priv->cfg->text_width) {
			priv->rec_track->size.x = priv->cfg->text_width;
			priv->rec_track->size.y = priv->cfg->text_height;
			gf_node_changed((GF_Node *) priv->rec_track, NULL);
		}
	} else if (priv->rec_track->size.x) {
		priv->rec_track->size.x = priv->rec_track->size.y = 0;
		gf_node_changed((GF_Node *) priv->rec_box, NULL);
	}

	if (priv->mat_box->transparency<FIX_ONE) {
		if (priv->rec_box->size.x != priv->dlist->size.x) {
			priv->rec_box->size.x = priv->dlist->size.x;
			priv->rec_box->size.y = priv->dlist->size.y;
			gf_node_changed((GF_Node *) priv->rec_box, NULL);
		}
	} else if (priv->rec_box->size.x) {
		priv->rec_box->size.x = priv->rec_box->size.y = 0;
		gf_node_changed((GF_Node *) priv->rec_box, NULL);
	}

	form = (M_Form *) ttd_create_node(priv, TAG_MPEG4_Form, NULL);
	form->size.x = INT2FIX(thw);
	form->size.y = INT2FIX(thh);

	thw /= 2;
	thh /= 2;
	tw = priv->cfg->text_width;
	th = priv->cfg->text_height;

	/*check translation, we must not get out of scene size - not supported in GPAC*/
	offset = br.left - tw/2 + thw;
	if (offset + thw < - tw/2) offset = - tw/2 + thw;
	else if (offset - thw > tw/2) offset = tw/2 - thw;
	priv->tr_box->translation.x = INT2FIX(offset);

	offset = th/2 - br.top - thh;
	if (offset + thh > th/2) offset = th/2 - thh;
	else if (offset - thh < -th/2) offset = -th/2 + thh;
	priv->tr_box->translation.y = INT2FIX(offset);

	gf_node_dirty_set((GF_Node *)priv->tr_box, 0, 1);


	if (priv->scroll_type) {
		priv->ts_scroll->stopTime = gf_node_get_scene_time((GF_Node *) priv->ts_scroll);
		gf_node_changed((GF_Node *) priv->ts_scroll, NULL);
	}
	priv->scroll_mode = 0;
	if (td->displayFlags & GF_TXT_SCROLL_IN) priv->scroll_mode |= GF_TXT_SCROLL_IN;
	if (td->displayFlags & GF_TXT_SCROLL_OUT) priv->scroll_mode |= GF_TXT_SCROLL_OUT;

	priv->scroll_type = 0;
	if (priv->scroll_mode) {
		priv->scroll_type = (td->displayFlags & GF_TXT_SCROLL_DIRECTION)>>7;
		priv->scroll_type ++;
	}
Example #18
0
static void TimeTrigger_setTrigger(GF_Node *n, GF_Route *route)
{
	X_TimeTrigger *tt = (X_TimeTrigger *)n;
	tt->triggerTime = gf_node_get_scene_time(n);
	gf_node_event_out(n, 1/*"triggerTime"*/);
}
Example #19
0
/* Returns:
	0 if no rendering traversal is required, 
	1 if a rendering traversal is required!!!,
   -1 if the time node is a discard which has been deleted!! */
s32 gf_smil_timing_notify_time(SMIL_Timing_RTI *rti, Double scene_time)
{
	Fixed simple_time;
	s32 ret = 0;
	GF_DOM_Event evt;
	SMILTimingAttributesPointers *timingp = rti->timingp;

	if (!timingp) return 0;
	
	if (rti->scene_time == scene_time) return 0;
	rti->scene_time = scene_time;
	rti->cycle_number++;

	/* for fraction events, we indicate that the scene needs redraw */
	if (rti->evaluate_status == SMIL_TIMING_EVAL_FRACTION) 
		return 1;

	if (rti->evaluate_status == SMIL_TIMING_EVAL_DISCARD) {
		/* TODO: FIX ME discarding should send a begin event ? */
		/* -1 is a special case when the discard is evaluated */
		if (gf_smil_discard(rti, FLT2FIX(rti->scene_time))) return -1;
		else return 0;
	}

	gf_node_register(rti->timed_elt, NULL);

waiting_to_begin:
	if (rti->status == SMIL_STATUS_WAITING_TO_BEGIN) {
		if (rti->current_interval && scene_time >= rti->current_interval->begin) {			
			GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SMIL Timing   ] Time %f - Timed element %s - Activating\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_name((GF_Node *)rti->timed_elt)));
			rti->status = SMIL_STATUS_ACTIVE;

			memset(&evt, 0, sizeof(evt));
			evt.type = GF_EVENT_BEGIN_EVENT;
			evt.smil_event_time = rti->current_interval->begin;
			gf_dom_event_fire((GF_Node *)rti->timed_elt, NULL, &evt);

			if (rti->timed_elt->sgprivate->tag==TAG_SVG_conditional) {
				SVG_Element *e = (SVG_Element *)rti->timed_elt;
				/*activate conditional*/
				if (e->children) gf_node_render(e->children->node, NULL);
				rti->status = SMIL_STATUS_DONE;
			} else {
				gf_smil_reorder_anim(rti);
			}
		} else {
			GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SMIL Timing   ] Time %f - Timed element %s - Evaluating (Not starting)\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_name((GF_Node *)rti->timed_elt)));
			ret = -2;
			goto exit;
		}
	}

	if (rti->status == SMIL_STATUS_ACTIVE) {
		u32 cur_id;

		if (rti->current_interval->active_duration >= 0 
			&& scene_time >= (rti->current_interval->begin + rti->current_interval->active_duration)) {

			GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SMIL Timing   ] Time %f - Timed element %s - Stopping \n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_name((GF_Node *)rti->timed_elt)));
			memset(&evt, 0, sizeof(evt));
			evt.type = GF_EVENT_END_EVENT;
			evt.smil_event_time = rti->current_interval->begin + rti->current_interval->active_duration;
			gf_dom_event_fire((GF_Node *)rti->timed_elt, NULL, &evt);

			ret = rti->postpone;

			if (timingp->fill && *timingp->fill == SMIL_FILL_FREEZE) {
				rti->status = SMIL_STATUS_FROZEN;
				rti->first_frozen = rti->cycle_number;
				rti->evaluate_status = SMIL_TIMING_EVAL_FREEZE;
				if (!rti->postpone) {
					Fixed simple_time = gf_smil_timing_get_normalized_simple_time(rti, scene_time);
					rti->evaluate(rti, simple_time, rti->evaluate_status);
				}
			} else {
				rti->status = SMIL_STATUS_DONE;
				rti->first_frozen = rti->cycle_number;
				rti->evaluate_status = SMIL_TIMING_EVAL_REMOVE;
				if (!rti->postpone) {
					Fixed simple_time = gf_smil_timing_get_normalized_simple_time(rti, scene_time);
					rti->evaluate(rti, simple_time, rti->evaluate_status);
				}
			}

		}
		/*special case for unspecified simpleDur with animations (not with media timed elements)*/
		else if (0 && rti->postpone 
			&& (rti->current_interval->simple_duration==-1) 
			&& (rti->current_interval->active_duration<=0) 
		) {
			ret = 1;
			rti->status = SMIL_STATUS_FROZEN;
			rti->first_frozen = rti->cycle_number;
			rti->evaluate_status = SMIL_TIMING_EVAL_FREEZE;
		} else { // the animation is still active 
			if (!timingp->restart || *timingp->restart == SMIL_RESTART_ALWAYS) {
				s32 interval_index;
				interval_index = gf_smil_timing_find_interval_index(rti, scene_time);
				
				if (interval_index >= 0 &&
					interval_index != rti->current_interval_index) {
					/* intervals are different, use the new one */
					rti->current_interval_index = interval_index;
					rti->current_interval = (SMIL_Interval*)gf_list_get(rti->intervals, rti->current_interval_index);
					
					/* reinserting the new timed elements at its proper place in the list
					  of timed elements in the scenegraph */
					gf_smil_reorder_timing(rti);

					/* if this is animation, reinserting the animation in the list of animations 
				       that targets this attribute, so that it is the last one */
					gf_smil_reorder_anim(rti);

					memset(&evt, 0, sizeof(evt));
					evt.type = GF_EVENT_BEGIN_EVENT;
					evt.smil_event_time = rti->current_interval->begin;
					gf_dom_event_fire((GF_Node *)rti->timed_elt, NULL, &evt);

				
				} 
			}

			ret = rti->postpone;
			
			cur_id = rti->current_interval->nb_iterations;
			simple_time = gf_smil_timing_get_normalized_simple_time(rti, scene_time);
			if (cur_id < rti->current_interval->nb_iterations) {
				memset(&evt, 0, sizeof(evt));
				evt.type = GF_EVENT_REPEAT_EVENT;
				evt.smil_event_time = rti->current_interval->begin + rti->current_interval->nb_iterations*rti->current_interval->simple_duration;
				evt.detail = rti->current_interval->nb_iterations;
				gf_dom_event_fire((GF_Node *)rti->timed_elt, NULL, &evt);

				GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SMIL Timing   ] Time %f - Timed element %s - Repeating\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_name((GF_Node *)rti->timed_elt)));
				rti->evaluate_status = SMIL_TIMING_EVAL_REPEAT;		
			} else {
				GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SMIL Timing   ] Time %f - Timed element %s - Updating\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_name((GF_Node *)rti->timed_elt)));
				rti->evaluate_status = SMIL_TIMING_EVAL_UPDATE;
			}

			if (!rti->postpone) {
				rti->evaluate(rti, simple_time, rti->evaluate_status);
			}	
		}
	}

	if ((rti->status == SMIL_STATUS_DONE) || (rti->status == SMIL_STATUS_FROZEN)) {
		if (!timingp->restart || *timingp->restart != SMIL_RESTART_NEVER) { 
			/* Check changes in begin or end attributes */
			s32 interval_index;

			GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SMIL Timing   ] Time %f - Timed element %s - Checking for restart\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_name((GF_Node *)rti->timed_elt)));
			interval_index = gf_smil_timing_find_interval_index(rti, scene_time);
			if (interval_index >= 0 && interval_index != rti->current_interval_index) {
				/* intervals are different, use the new one */
				rti->current_interval_index = interval_index;
				rti->current_interval = (SMIL_Interval*)gf_list_get(rti->intervals, rti->current_interval_index);

				/* reinserting the new timed elements at its proper place in the list
				  of timed elements in the scenegraph */
				gf_smil_reorder_timing(rti);

				rti->status = SMIL_STATUS_WAITING_TO_BEGIN;
				rti->evaluate_status = SMIL_TIMING_EVAL_NONE;
				goto waiting_to_begin;
			} 
		} else if ((rti->status == SMIL_STATUS_DONE) && 
			        timingp->restart && (*timingp->restart == SMIL_RESTART_NEVER)) {
			/* the timed element is done and cannot restart, we don't need to evaluate it anymore */
			GF_SceneGraph * sg = rti->timed_elt->sgprivate->scenegraph;
			while (sg->parent_scene) sg = sg->parent_scene;
			gf_list_del_item(sg->smil_timed_elements, rti);
		}
	}

exit:
	gf_node_unregister(rti->timed_elt, NULL);
	return ret;
}
Example #20
0
/* This function notifies the scene time to all the timed elements from the list in the given scene graph.
   It returns the number of active timed elements. If no timed element is active, this means that from the timing
   point of view, the scene has not changed and no rendering refresh is needed, even if the time has changed.
   It uses an additional list of modified timed elements to insure that no timing 
   element was modified by the begin/end/repeat of another timed element.
*/
Bool gf_smil_notify_timed_elements(GF_SceneGraph *sg)
{
	SMIL_Timing_RTI *rti;
	u32 active_count, i;
	s32 ret;
	Bool do_loop;
	if (!sg) return 0;

	active_count = 0;

	/*
		Note: whenever a timed element is active, we trigger a gf_node_dirty_parent_graph so that the parent graph 
		is aware that some modifications may happen in the subtree. This is needed for cases where the subtree
		is in an offscreen surface, to force retraversing of the subtree and thus apply the animation. 

	*/
	
	/* notify the new scene time to the register timed elements 
	   this might modify other timed elements or the element itself 
	   in which case it will be added to the list of modified elements */
	i = 0;
	do_loop = 1;
	while(do_loop && (rti = (SMIL_Timing_RTI *)gf_list_enum(sg->smil_timed_elements, &i))) {
		ret = gf_smil_timing_notify_time(rti, gf_node_get_scene_time((GF_Node*)rti->timed_elt) );
		switch (ret) {
		case -1:
			/* special case for discard element
			   when a discard element is executed, it automatically removes itself from the list of timed element 
			   in the scene graph, we need to fix the index i. */
			i--;
			break;
		case -2:
			/* special return value, -2 means that the tested timed element is waiting to begin
			   Assuming that the timed elements are sorted by begin order, 
			   the next ones don't need to be checked */
			do_loop = 0;
			break;
		case -3:
			/* special case for animation elements which do not need to be notified anymore, 
			   but which require a tree traversal */
			i--;
			active_count ++;
			gf_node_dirty_parent_graph(rti->timed_elt);
			break;
		case 1:
			active_count++;
			gf_node_dirty_parent_graph(rti->timed_elt);
			break;
		case 0:
		default:
			break;
		}
	}

	/* notify the timed elements which have been modified either since the previous frame (updates, scripts) or 
	   because of the start/end/repeat of the previous notifications */
	while (gf_list_count(sg->modified_smil_timed_elements)) {
		/* first remove the modified smil timed element */
		rti = gf_list_get(sg->modified_smil_timed_elements, 0);
		gf_list_rem(sg->modified_smil_timed_elements, 0);

		/* then remove it in the list of non modified (if it was there) */
		gf_list_del_item(sg->smil_timed_elements, rti);

		/* then insert it at its right position (in the sorted list of timed elements) */
		gf_smil_timing_add_to_sg(sg, rti);

		/* finally again notify this timed element */
		rti->force_reevaluation = 1;
		ret = gf_smil_timing_notify_time(rti, gf_node_get_scene_time((GF_Node*)rti->timed_elt) );
		switch (ret) {
		case -1:
			break;
		case -2:
			break;
		case -3:
			active_count++;
			gf_node_dirty_parent_graph(rti->timed_elt);
			break;
		case 1:
			active_count++;
			gf_node_dirty_parent_graph(rti->timed_elt);
			break;
		case 0:
		default:
			break;
		}

	}
	return (active_count>0);
}
Example #21
0
/* Notifies the scene time to a timed element, potentially changing its status and triggering its evaluation
   Returns:
	0 if no rendering traversal is required, 
	1 if a rendering traversal is required,
   -1 if the time node is a discard which has been deleted during this notification,
   -2 means that the timed element is waiting to begin,
   -3 means that the timed element is active but does not need further notifications (set without dur) 
             but still requires a rendering traversal */
s32 gf_smil_timing_notify_time(SMIL_Timing_RTI *rti, Double in_scene_time)
{
	s32 ret = 0;
	GF_DOM_Event evt;
	SMILTimingAttributesPointers *timingp = rti->timingp;
	Bool force_end = 0;

	if (!timingp) return 0;

	/* if the scene time is the same as it was during the previous notification, it means that the 
	   animations are paused and we don't need to evaluate it again unless the force_reevaluation flag is set */
	if ((rti->scene_time == in_scene_time) && (rti->force_reevaluation == 0)) return 0;
	if (!rti->paused) rti->scene_time = in_scene_time;
	rti->force_reevaluation = 0;

	/* for fraction events, in all cases we indicate that the scene needs redraw */
	if (rti->evaluate_status == SMIL_TIMING_EVAL_FRACTION) 
		return 1;

	if (rti->evaluate_status == SMIL_TIMING_EVAL_DISCARD) {
		/* TODO: FIX ME discarding should send a begin event ? */
		/* Since the discard can only be evaluated once, it unregisters itself 
		   from the list of timed elements to be notified, so for this special case 
		   we return -1 when the discard has actually been executed */
		if (gf_smil_discard(rti, FLT2FIX(rti->scene_time))) return -1;
		else return 0;
	}

	gf_node_register(rti->timed_elt, NULL);

waiting_to_begin:
	if (rti->status == SMIL_STATUS_WAITING_TO_BEGIN) {
		if (rti->current_interval->begin != -1 && rti->scene_time >= rti->current_interval->begin) {			
			/* if there is a computed interval with a definite begin value 
			   and if that value is lesser than the scene time, then the animation becomes active */
			GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing   ] Time %f - Timed element %s - Activating\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
			rti->status = SMIL_STATUS_ACTIVE;

			if (rti->timed_elt->sgprivate->tag==TAG_LSR_conditional) {
				SVG_Element *e = (SVG_Element *)rti->timed_elt;
				/*activate conditional*/
				if (e->children) gf_node_traverse(e->children->node, NULL);
				rti->status = SMIL_STATUS_DONE;
			} else {
				gf_smil_reorder_anim(rti);
			}

			memset(&evt, 0, sizeof(evt));
			evt.type = GF_EVENT_BEGIN_EVENT;
			evt.smil_event_time = rti->current_interval->begin;
			gf_dom_event_fire((GF_Node *)rti->timed_elt, &evt);				
		} else {
			GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing   ] Time %f - Timed element %s - Evaluating (Not starting)\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
			ret = -2;
			goto exit;
		}
	}

	if (rti->status == SMIL_STATUS_ACTIVE) {
		u32 cur_id;

		if (rti->current_interval->active_duration >= 0 
			&& rti->scene_time >= (rti->current_interval->begin + rti->current_interval->active_duration)) {
force_end:
			GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing   ] Time %f - Timed element %s - Stopping \n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));

			rti->normalized_simple_time = gf_smil_timing_get_normalized_simple_time(rti, rti->scene_time, NULL);
			ret = rti->postpone;

			if (timingp->fill && *timingp->fill == SMIL_FILL_FREEZE) {
				rti->status = SMIL_STATUS_FROZEN;
				rti->evaluate_status = SMIL_TIMING_EVAL_FREEZE;
				GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing   ] Time %f - Timed element %s - Preparing to freeze\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
				if (!rti->postpone) {
					rti->evaluate(rti, rti->normalized_simple_time, rti->evaluate_status);
				}
			} else {
				rti->status = SMIL_STATUS_DONE;
				rti->evaluate_status = SMIL_TIMING_EVAL_REMOVE;
				GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing   ] Time %f - Timed element %s - Preparing to remove\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
				if (!rti->postpone) {
					rti->evaluate(rti, rti->normalized_simple_time, rti->evaluate_status);
				}
			}

			memset(&evt, 0, sizeof(evt));
			evt.type = GF_EVENT_END_EVENT;
			/* WARNING: begin + active_duration may be greater than 'now' because of force_end cases */
			evt.smil_event_time = rti->current_interval->begin + rti->current_interval->active_duration;
			gf_dom_event_fire((GF_Node *)rti->timed_elt, &evt);

		} else { /* the animation is still active */

			if (!timingp->restart || *timingp->restart == SMIL_RESTART_ALWAYS) {
				GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing   ] Time %f - Timed element %s - Checking for restart (always)\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
			
				if (rti->next_interval->begin != -1 && rti->next_interval->begin < rti->scene_time) {
					*rti->current_interval = *rti->next_interval;
					gf_smil_timing_get_next_interval(rti, 0, rti->next_interval, rti->scene_time);

					/* mark that this element has been modified and 
					   need to be reinserted at its proper place in the list of timed elements in the scenegraph */
					gf_smil_mark_modified(rti, 0);

					/* if this is animation, reinserting the animation in the list of animations 
				       that targets this attribute, so that it is the last one */
					gf_smil_reorder_anim(rti);

					memset(&evt, 0, sizeof(evt));
					evt.type = GF_EVENT_BEGIN_EVENT;
					evt.smil_event_time = rti->current_interval->begin;
					gf_dom_event_fire((GF_Node *)rti->timed_elt, &evt);				
				} 
			}

			ret = rti->postpone;
			
			cur_id = rti->current_interval->nb_iterations;
			rti->normalized_simple_time = gf_smil_timing_get_normalized_simple_time(rti, rti->scene_time, &force_end);
			if (force_end) {
				GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing   ] Time %f - Timed element %s - Forcing end (fill or remove)\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
				goto force_end;
			}
			if (cur_id < rti->current_interval->nb_iterations) {
				GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("[SMIL Timing   ] Time %f - Timed element %s - Preparing to repeat\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
				memset(&evt, 0, sizeof(evt));
				evt.type = GF_EVENT_REPEAT_EVENT;
				evt.smil_event_time = rti->current_interval->begin + rti->current_interval->nb_iterations*rti->current_interval->simple_duration;
				evt.detail = rti->current_interval->nb_iterations;
				gf_dom_event_fire((GF_Node *)rti->timed_elt, &evt);

				rti->evaluate_status = SMIL_TIMING_EVAL_REPEAT;		
			} else {
				GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing   ] Time %f - Timed element %s - Preparing to update\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
				rti->evaluate_status = SMIL_TIMING_EVAL_UPDATE;
			}

			if (!rti->postpone) {
				rti->evaluate(rti, rti->normalized_simple_time, rti->evaluate_status);
			}

			/* special case for animations with unspecified simpleDur (not with media timed elements)
			   we need to indicate that this anim does not need to be notified anymore and that 
			   it does not require tree traversal */
			if (gf_svg_is_animation_tag(rti->timed_elt->sgprivate->tag)
				&& (rti->current_interval->simple_duration==-1) 
				&& (rti->current_interval->active_duration==-1) 
			) {
				/*GF_SceneGraph * sg = rti->timed_elt->sgprivate->scenegraph;
				while (sg->parent_scene) sg = sg->parent_scene;
				gf_list_del_item(sg->smil_timed_elements, rti);
				ret = -3;*/
				ret = 1;
			} 
		}
	}

	if ((rti->status == SMIL_STATUS_DONE) || (rti->status == SMIL_STATUS_FROZEN)) {
		if (!timingp->restart || *timingp->restart != SMIL_RESTART_NEVER) { 
			/* Check changes in begin or end attributes */
			GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing   ] Time %f - Timed element %s - Checking for restart when not active\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
			if (rti->next_interval->begin != -1) {
				Bool restart_timing = 0;
				/*next interval is right now*/
				if (rti->next_interval->begin == rti->current_interval->begin+rti->current_interval->active_duration)
					restart_timing = 1;

				/*switch intervals*/
				if (rti->next_interval->begin >= rti->current_interval->begin+rti->current_interval->active_duration) { 
					*rti->current_interval = *rti->next_interval;
				
					gf_smil_timing_print_interval(rti, 1, rti->current_interval);
					gf_smil_timing_get_next_interval(rti, 0, rti->next_interval, rti->scene_time);

					/* mark that this element has been modified and 
					   need to be reinserted at its proper place in the list of timed elements in the scenegraph */
					gf_smil_mark_modified(rti, 0);
				} else {
					rti->next_interval->begin = -1;
				}

				/*if chaining to new interval, go to wait_for begin right now*/
				if (restart_timing) {
					rti->status = SMIL_STATUS_WAITING_TO_BEGIN;
					rti->evaluate_status = SMIL_TIMING_EVAL_NONE;
					GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing   ] Time %f - Timed element %s - Returning to eval none status\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
					ret = 0;
					goto waiting_to_begin;
				}
				/*otherwise move state to waiting for begin for next smil_timing evaluation, but
				don't change evaluate status for next anim evaluation*/
				else {
					rti->status = SMIL_STATUS_WAITING_TO_BEGIN;
				}
			} else {
				/*??? what is this ???*/
				//ret = 0;
			}
		} else if ((rti->status == SMIL_STATUS_DONE) && 
			        timingp->restart && (*timingp->restart == SMIL_RESTART_NEVER)) {
			/* the timed element is done and cannot restart, we don't need to evaluate it anymore */
			GF_SceneGraph * sg = rti->timed_elt->sgprivate->scenegraph;
			while (sg->parent_scene) sg = sg->parent_scene;
			gf_list_del_item(sg->smil_timed_elements, rti);
			ret = -1;
		}
	}

exit:
	gf_node_unregister(rti->timed_elt, NULL);
	return ret;
}
Example #22
0
static void gf_smil_timing_print_interval(SMIL_Timing_RTI *rti, Bool current, SMIL_Interval *interval)
{
	GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing   ] Time %f - Timed element %s - ", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
	GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, (current ? "Current " : "   Next "));
	GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("Interval - "));
	GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("begin: %.2f", interval->begin));
	GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, (" - end: %.2f", interval->end));
	GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, (" - simple dur: %.2f - active dur: %.2f\n",interval->simple_duration, interval->active_duration));
}
Example #23
0
void gf_smil_timing_delete_runtime_info(GF_Node *timed_elt, SMIL_Timing_RTI *rti)
{
	GF_SceneGraph *sg;

	if (!rti || !timed_elt) return;

	GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing   ] Time %f - Timed element %s - Destruction\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
	gf_free(rti->current_interval);
	gf_free(rti->next_interval);

	/* we inform the rootmost scene graph that this node will not need notification of the scene time anymore */
	sg = timed_elt->sgprivate->scenegraph;
	while (sg->parent_scene) sg = sg->parent_scene;
	gf_list_del_item(sg->smil_timed_elements, rti);
	gf_list_del_item(sg->modified_smil_timed_elements, rti);

	/*remove all associated listeners*/
	if (rti->timingp->begin) gf_smil_timing_reset_time_list(* rti->timingp->begin);
	if (rti->timingp->end) gf_smil_timing_reset_time_list(* rti->timingp->end);
	
	gf_free(rti);
}
Example #24
0
static Bool gf_smil_timing_get_next_interval(SMIL_Timing_RTI *rti, Bool current, SMIL_Interval *interval, Double scene_time)
{
	u32 i, count;

	memset(interval, 0, sizeof(SMIL_Interval));
	interval->begin = -1;
	
	count = (rti->timingp->begin ? gf_list_count(*rti->timingp->begin) : 0);
	for (i = 0; i < count; i ++) {
		SMIL_Time *begin = (SMIL_Time*)gf_list_get(*rti->timingp->begin, i);
		if (GF_SMIL_TIME_IS_CLOCK(begin->type)) {
			if (rti->current_interval->begin != -1 && begin->clock <= rti->current_interval->begin) continue;
//			if (rti->current_interval->begin == -1 || begin->clock <= scene_time) {
				interval->begin = begin->clock;
				break;
//			}
		}
	}
	if (interval->begin != -1) {
		gf_smil_timing_get_interval_end(rti, interval);
		if (interval->end == -2) {
			/* this is a wrong interval see first animation in animate-elem-201-t.svg */
			GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing   ] Time %f - Timed element %s - Wrong Interval\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
			interval->begin = -1;
			interval->end = -1;
			return 0;
		}
		gf_smil_timing_compute_active_duration(rti, interval);
		gf_smil_timing_print_interval(rti, current, interval);
		return 1;
	} else {
		return 0;
	}
}
Example #25
0
/* Attributes from the timed elements are not easy to use during runtime, 
   the runtime info is a set of easy to use structures. 
   This function initializes them (intervals, status ...) 
   and registers the element with the scenegraph */
GF_EXPORT
void gf_smil_timing_init_runtime_info(GF_Node *timed_elt)
{
	GF_SceneGraph *sg;
	SMIL_Timing_RTI *rti;
	SMILTimingAttributesPointers *timingp = NULL;
	u32 tag = gf_node_get_tag(timed_elt);
	SVGAllAttributes all_atts;
	SVGTimedAnimBaseElement *e = (SVGTimedAnimBaseElement *)timed_elt;

	gf_svg_flatten_attributes((SVG_Element *)e, &all_atts);
	e->timingp = gf_malloc(sizeof(SMILTimingAttributesPointers));
	e->timingp->begin		= all_atts.begin;
	e->timingp->clipBegin	= all_atts.clipBegin;
	e->timingp->clipEnd		= all_atts.clipEnd;
	e->timingp->dur			= all_atts.dur;
	e->timingp->end			= all_atts.end;
	e->timingp->fill		= all_atts.smil_fill;
	e->timingp->max			= all_atts.max;
	e->timingp->min			= all_atts.min;
	e->timingp->repeatCount = all_atts.repeatCount;
	e->timingp->repeatDur	= all_atts.repeatDur;
	e->timingp->restart		= all_atts.restart;
	timingp = e->timingp;
	if (!timingp) return;

	if (tag == TAG_SVG_audio || tag == TAG_SVG_video) {
		/* if the dur attribute is not set, then it should be set to media 
		   as this is the default for media elements see 
		   http://www.w3.org/TR/2005/REC-SMIL2-20051213/smil-timing.html#Timing-DurValueSemantics
		   "For simple media elements that specify continuous media (i.e. media with an inherent notion of time), 
		   the implicit duration is the intrinsic duration of the media itself - e.g. video and audio files 
		   have a defined duration."
		TODO: Check if this should work with the animation element */
		if (!e->timingp->dur) {
			GF_FieldInfo info;
			gf_node_get_attribute_by_tag((GF_Node *)e, TAG_SVG_ATT_dur, 1, 0, &info);
			e->timingp->dur = (SMIL_Duration *)info.far_ptr;
			e->timingp->dur->type = SMIL_DURATION_MEDIA;
		}
	}

	GF_SAFEALLOC(rti, SMIL_Timing_RTI)
	timingp->runtime = rti;
	rti->timed_elt = timed_elt;
	GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing   ] Time %f - Timed element %s - Initialization\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));

	rti->timingp = timingp;
	rti->status = SMIL_STATUS_WAITING_TO_BEGIN;
	rti->evaluate_status = SMIL_TIMING_EVAL_NONE;	
	rti->evaluate = gf_smil_timing_null_timed_function;
	rti->scene_time = -1;
	rti->force_reevaluation = 0;
	rti->media_duration = -1;

	GF_SAFEALLOC(rti->current_interval, SMIL_Interval);
	gf_smil_timing_get_first_interval(rti);
	GF_SAFEALLOC(rti->next_interval, SMIL_Interval);
	gf_smil_timing_get_next_interval(rti, 0, rti->next_interval, rti->current_interval->begin);

	/* Now that the runtime info for this timed element is initialized, we can tell the scene graph that it can start
	   notifying the scene time to this element. Because of the 'animation' element, we can have many scene graphs
	   sharing the same scene time, we therefore add this timed element to the rootmost scene graph. */
	sg = timed_elt->sgprivate->scenegraph;
	while (sg->parent_scene) sg = sg->parent_scene;
	gf_smil_timing_add_to_sg(sg, rti);
}
Example #26
0
static void gf_smil_timing_get_first_interval(SMIL_Timing_RTI *rti)
{
	u32 i, count;
	memset(rti->current_interval, 0, sizeof(SMIL_Interval));
	rti->current_interval->begin = -1;
	count = (rti->timingp->begin ? gf_list_count(*rti->timingp->begin) : 0);
	for (i = 0; i < count; i ++) {
		SMIL_Time *begin = (SMIL_Time*)gf_list_get(*rti->timingp->begin, i);
		if (GF_SMIL_TIME_IS_CLOCK(begin->type)) {
			rti->current_interval->begin = begin->clock;
			break;
		}
	}
	/*In SVG, if no 'begin' is specified, the default timing of the time container 
	is equivalent to an offset value of '0'.*/
	if (rti->current_interval->begin == -1 && count == 0) {
		/* except for LASeR Conditional element*/
		if (rti->timed_elt->sgprivate->tag != TAG_LSR_conditional) {
			rti->current_interval->begin = 0;
		} else {
			return;
		}
	}
	
	/* this is the first time we check the interval */
	gf_smil_timing_get_interval_end(rti, rti->current_interval);
	if (0 && rti->current_interval->end == -2) {
		/* TODO: check if the interval can be discarded (i.e. if end is specified with an invalid end value (return -2)),
		   probably yes, but next time we call the evaluation of interval, we should call get_first_interval */
		GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing   ] Time %f - Timed element %s - Wrong Interval\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
		rti->current_interval->begin = -1;
		rti->current_interval->end = -1;
		return;
	}

	gf_smil_timing_compute_active_duration(rti, rti->current_interval);
	gf_smil_timing_print_interval(rti, 1, rti->current_interval);
}
Example #27
0
static void svg_sani_a_HandleEvent(GF_Node *handler, GF_DOM_Event *event)
{
	GF_Renderer *compositor;
	GF_Event evt;
	SVG_SANI_aElement *a;

	assert(gf_node_get_tag(event->currentTarget)==TAG_SVG_SANI_a);

	a = (SVG_SANI_aElement *) event->currentTarget;
	compositor = (GF_Renderer *)gf_node_get_private(handler);

	if (!compositor->user->EventProc) return;

	evt.type = GF_EVENT_NAVIGATE;
	
	if (a->xlink->href.type == XMLRI_STRING) {
		evt.navigate.to_url = a->xlink->href.iri;
		if (evt.navigate.to_url) {
			evt.navigate.param_count = 1;
			evt.navigate.parameters = (const char **) &a->target;
			compositor->user->EventProc(compositor->user->opaque, &evt);
		}
	} else {
		u32 tag;
		if (!a->xlink->href.target) {
			/* TODO: check if href can be resolved */
			return;
		} 
		tag = gf_node_get_tag((GF_Node *)a->xlink->href.target);
		if (tag == TAG_SVG_SANI_set ||
			tag == TAG_SVG_SANI_animate ||
			tag == TAG_SVG_SANI_animateColor ||
			tag == TAG_SVG_SANI_animateTransform ||
			tag == TAG_SVG_SANI_animateMotion || 
			tag == TAG_SVG_SANI_discard) {
			u32 i, count, found;
			SVG_SANI_setElement *set = (SVG_SANI_setElement *)a->xlink->href.target;
			SMIL_Time *begin;
			GF_SAFEALLOC(begin, SMIL_Time);
			begin->type = GF_SMIL_TIME_EVENT_RESOLVED;
			begin->clock = gf_node_get_scene_time((GF_Node *)set);

			found = 0;
			count = gf_list_count(set->timing->begin);
			for (i=0; i<count; i++) {
				SMIL_Time *first = (SMIL_Time *)gf_list_get(set->timing->begin, i);
				/*remove past instanciations*/
				if ((first->type==GF_SMIL_TIME_EVENT_RESOLVED) && (first->clock < begin->clock)) {
					gf_list_rem(set->timing->begin, i);
					free(first);
					i--;
					count--;
					continue;
				}
				if ( (first->type == GF_SMIL_TIME_INDEFINITE) 
					|| ( (first->type == GF_SMIL_TIME_CLOCK) && (first->clock > begin->clock) ) 
				) {
					gf_list_insert(set->timing->begin, begin, i);
					found = 1;
					break;
				}
			}
			if (!found) gf_list_add(set->timing->begin, begin);
			gf_node_changed((GF_Node *)a->xlink->href.target, NULL);
		}
	}
	return;
}
Example #28
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"*/);
	}
}
Example #29
0
File: bindable.c Project: zsuo/gpac
void Bindable_SetIsBound(GF_Node *bindable, Bool val)
{
	Bool has_bind_time = GF_FALSE;
	if (!bindable) return;
	switch (gf_node_get_tag(bindable)) {
	case TAG_MPEG4_Background2D:
		if ( ((M_Background2D*)bindable)->isBound == val) return;
		((M_Background2D*)bindable)->isBound = val;
		break;
	case TAG_MPEG4_Viewport:
		if ( ((M_Viewport*)bindable)->isBound == val) return;
		((M_Viewport*)bindable)->isBound = val;
		((M_Viewport*)bindable)->bindTime = gf_node_get_scene_time(bindable);
		has_bind_time = GF_TRUE;
		break;
#ifndef GPAC_DISABLE_X3D
	case TAG_X3D_Background:
		if ( ((X_Background*)bindable)->isBound == val) return;
		((X_Background*)bindable)->isBound = val;
		((X_Background*)bindable)->bindTime = gf_node_get_scene_time(bindable);
		has_bind_time = GF_TRUE;
		break;
#endif
	case TAG_MPEG4_Background:
		if ( ((M_Background*)bindable)->isBound == val) return;
		((M_Background*)bindable)->isBound = val;
		break;
#ifndef GPAC_DISABLE_X3D
	case TAG_X3D_NavigationInfo:
		if ( ((X_NavigationInfo*)bindable)->isBound == val) return;
		((X_NavigationInfo*)bindable)->isBound = val;
		((X_NavigationInfo*)bindable)->bindTime = gf_node_get_scene_time(bindable);
		has_bind_time = GF_TRUE;
		break;
#endif
	case TAG_MPEG4_NavigationInfo:
		if ( ((M_NavigationInfo*)bindable)->isBound == val) return;
		((M_NavigationInfo*)bindable)->isBound = val;
		break;
	case TAG_MPEG4_Viewpoint:
#ifndef GPAC_DISABLE_X3D
	case TAG_X3D_Viewpoint:
#endif
		if ( ((M_Viewpoint*)bindable)->isBound == val) return;
		((M_Viewpoint*)bindable)->isBound = val;
		((M_Viewpoint*)bindable)->bindTime = gf_node_get_scene_time(bindable);
		has_bind_time = GF_TRUE;
		break;
#ifndef GPAC_DISABLE_X3D
	case TAG_X3D_Fog:
		if ( ((X_Fog*)bindable)->isBound == val) return;
		((X_Fog*)bindable)->isBound = val;
		((X_Fog*)bindable)->bindTime = gf_node_get_scene_time(bindable);
		has_bind_time = GF_TRUE;
		break;
#endif
	case TAG_MPEG4_Fog:
		if ( ((M_Fog*)bindable)->isBound == val) return;
		((M_Fog*)bindable)->isBound = val;
		break;
	default:
		return;
	}
	gf_node_event_out_str(bindable, "isBound");
	if (has_bind_time) gf_node_event_out_str(bindable, "bindTime");
	/*force invalidate of the bindable stack's owner*/
	gf_node_dirty_set(bindable, 0, GF_TRUE);
}
Example #30
0
static
void UpdateTimeSensor(GF_TimeNode *st)
{
    Double currentTime, cycleTime;
    Fixed newFraction;
    u32 inc;
    M_TimeSensor *TS = (M_TimeSensor *)st->obj;
    TimeSensorStack *stack = (TimeSensorStack *)gf_node_get_private(st->obj);

    if (! TS->enabled) {
        if (TS->isActive) {
            TS->cycleTime = gf_node_get_scene_time(st->obj);
            gf_node_event_out_str(st->obj, "cycleTime");
            ts_deactivate(stack, TS);
        }
        return;
    }

    if (stack->store_info) {
        stack->store_info = 0;
        stack->start_time = TS->startTime;
        stack->cycle_interval = TS->cycleInterval;
    }

    currentTime = gf_node_get_scene_time(st->obj);
    if (!TS->isActive) {
        if (currentTime < stack->start_time) return;
        /*special case: if we're greater than both start and stop time don't activate*/
        if (!TS->isActive && (TS->stopTime > stack->start_time) && (currentTime >= TS->stopTime)) {
            stack->time_handle.needs_unregister = 1;
            return;
        }
        if (stack->is_x3d && !TS->loop) {
            if (!stack->start_time) return;
            if (currentTime >= TS->startTime+stack->cycle_interval) return;
        }
    }

    cycleTime = currentTime - stack->start_time - stack->num_cycles * stack->cycle_interval;
    newFraction = FLT2FIX ( fmod(cycleTime, stack->cycle_interval) / stack->cycle_interval );

    if (TS->isActive) {
        TS->time = currentTime;
        gf_node_event_out_str(st->obj, "time");

        /*VRML:
        	"f = fmod( (now - startTime) , cycleInterval) / cycleInterval
        	if (f == 0.0 && now > startTime) fraction_changed = 1.0
        	else fraction_changed = f"
        */
        if (!newFraction && (currentTime > stack->start_time ) ) newFraction = FIX_ONE;

        /*check for deactivation - if so generate a fraction_changed AS IF NOW WAS EXACTLY STOPTIME*/
        if ((TS->stopTime > stack->start_time) && (currentTime >= TS->stopTime) ) {
            cycleTime = TS->stopTime - stack->start_time - stack->num_cycles * stack->cycle_interval;
            TS->fraction_changed = FLT2FIX( fmod(cycleTime, stack->cycle_interval) / stack->cycle_interval );
            /*cf above*/
            if (TS->fraction_changed < FIX_EPSILON) TS->fraction_changed = FIX_ONE;
            gf_node_event_out_str(st->obj, "fraction_changed");
            ts_deactivate(stack, TS);
            return;
        }
        if (! TS->loop) {
            if (cycleTime >= stack->cycle_interval) {
                TS->fraction_changed = FIX_ONE;
                gf_node_event_out_str(st->obj, "fraction_changed");
                ts_deactivate(stack, TS);
                return;
            }
        }
        TS->fraction_changed = newFraction;
        gf_node_event_out_str(st->obj, "fraction_changed");
    }

    /*we're (about to be) active: VRML:
    "A time-dependent node is inactive until its startTime is reached. When time now becomes greater than or
    equal to startTime, an isActive TRUE event is generated and the time-dependent node becomes active 	*/

    if (!TS->isActive) {
        st->needs_unregister = 0;
        TS->isActive = 1;
        gf_node_event_out_str(st->obj, "isActive");
        TS->cycleTime = currentTime;
        gf_node_event_out_str(st->obj, "cycleTime");
        TS->fraction_changed = newFraction;
        gf_node_event_out_str(st->obj, "fraction_changed");
    }

    //compute cycle time
    if (TS->loop && (cycleTime >= stack->cycle_interval) ) {
        inc = 1 + (u32) ( (cycleTime - stack->cycle_interval ) / stack->cycle_interval );
        stack->num_cycles += inc;
        cycleTime -= inc*stack->cycle_interval;
        TS->cycleTime = currentTime - cycleTime;
        gf_node_event_out_str(st->obj, "cycleTime");
    }
}