示例#1
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;
}
示例#2
0
文件: commands.c 项目: bigbensk/gpac
GF_EXPORT
GF_Err gf_sg_command_apply(GF_SceneGraph *graph, GF_Command *com, Double time_offset)
{
	GF_Err e;
	GF_CommandField *inf;
#ifndef GPAC_DISABLE_VRML
	GF_FieldInfo field;
	void *slot_ptr;
	GF_Node *def;
#endif
	GF_Node *node;

	if (!com || !graph) return GF_BAD_PARAM;

	if (com->never_apply) return GF_OK;

	e = GF_OK;
	switch (com->tag) {
#ifndef GPAC_DISABLE_VRML
	case GF_SG_SCENE_REPLACE:
		/*unregister root*/
		gf_node_unregister(graph->RootNode, NULL);
		/*remove all protos and routes*/
		while (gf_list_count(graph->routes_to_activate)) 
			gf_list_rem(graph->routes_to_activate, 0);

		if (!com->aggregated) {
			/*destroy all routes*/
			while (gf_list_count(graph->Routes)) {
				GF_Route *r = (GF_Route *)gf_list_get(graph->Routes, 0);
				/*this will unregister the route from the graph, so don't delete the chain entry*/
				gf_sg_route_del(r);
			}
			/*destroy all proto*/
			while (gf_list_count(graph->protos)) {
				GF_Proto *p = (GF_Proto*)gf_list_get(graph->protos, 0);
				/*this will unregister the proto from the graph, so don't delete the chain entry*/
				gf_sg_proto_del(p);
			}
		}
		/*DO NOT TOUCH node registry*/
		/*DO NOT TOUCH UNREGISTERED PROTOS*/

		/*if no protos (previously aggregated command) create proto list*/
		if (!graph->protos) graph->protos = gf_list_new();

		/*move all protos in graph*/
		while (gf_list_count(com->new_proto_list)) {
			GF_Proto *p = (GF_Proto*)gf_list_get(com->new_proto_list, 0);
			gf_list_rem(com->new_proto_list, 0);
			gf_list_del_item(graph->unregistered_protos, p);
			gf_list_add(graph->protos, p);
		}
		/*assign new root (no need to register/unregister)*/
		graph->RootNode = com->node;
		com->node = NULL;
		break;

	case GF_SG_NODE_REPLACE:
		if (!gf_list_count(com->command_fields)) return GF_OK;
		inf = (GF_CommandField*)gf_list_get(com->command_fields, 0);
		e = gf_node_replace(com->node, inf->new_node, 0);
		if (inf->new_node) gf_node_register(inf->new_node, NULL);
		break;

	case GF_SG_MULTIPLE_REPLACE:
	case GF_SG_FIELD_REPLACE:
	{
		u32 j;
		GF_ChildNodeItem *list, *cur, *prev;
		j=0;
		while ((inf = (GF_CommandField*)gf_list_enum(com->command_fields, &j))) {
			e = gf_node_get_field(com->node, inf->fieldIndex, &field);
			if (e) return e;

			switch (field.fieldType) {
			case GF_SG_VRML_SFNODE:
			{
				node = *((GF_Node **) field.far_ptr);
				e = gf_node_unregister(node, com->node);
				*((GF_Node **) field.far_ptr) = inf->new_node;
				if (!e) gf_node_register(inf->new_node, com->node);
				break;
			}
			case GF_SG_VRML_MFNODE:
				gf_node_unregister_children(com->node, * ((GF_ChildNodeItem **) field.far_ptr));
				* ((GF_ChildNodeItem **) field.far_ptr) = NULL;

				list = * ((GF_ChildNodeItem **) inf->field_ptr);
				prev=NULL;
				while (list) {
					cur = gf_malloc(sizeof(GF_ChildNodeItem));
					cur->next = NULL;
					cur->node = list->node;
					if (prev) {
						prev->next = cur;
					} else {
						* ((GF_ChildNodeItem **) field.far_ptr) = cur;
					}
					gf_node_register(list->node, com->node);
					prev = cur;
					list = list->next;
				}
				break;
			case GF_SG_VRML_SFCOMMANDBUFFER:
			{
				u32 i, count;
				GF_SceneGraph *sg;
				SFCommandBuffer *cb_dst = (SFCommandBuffer *)field.far_ptr;
				SFCommandBuffer *cb_src = (SFCommandBuffer *)inf->field_ptr;

				/*reset dest*/
				if (!cb_dst->commandList) cb_dst->commandList = gf_list_new();

				while (gf_list_count(cb_dst->commandList)) {
					GF_Command *sub_com = (GF_Command *)gf_list_get(cb_dst->commandList, 0);
					gf_sg_command_del(sub_com);
					gf_list_rem(cb_dst->commandList, 0);
				}
				if (cb_dst->buffer) {
					gf_free(cb_dst->buffer);
					cb_dst->buffer = NULL;
				}

				/*clone command list*/
				sg = gf_node_get_graph(com->node);
				count = gf_list_count(cb_src->commandList);
				for (i=0; i<count;i++) {
					GF_Command *sub_com = (GF_Command *)gf_list_get(cb_src->commandList, i);
					GF_Command *new_com = gf_sg_vrml_command_clone(sub_com, sg, 0);
					gf_list_add(cb_dst->commandList, new_com);
				}
			}
				break;

			default:
				/*this is a regular field, reset it and clone - we cannot switch pointers since the
				original fields are NOT pointers*/
				if (!gf_sg_vrml_is_sf_field(field.fieldType)) {
					e = gf_sg_vrml_mf_reset(field.far_ptr, field.fieldType);
				}
				if (e) return e;
				gf_sg_vrml_field_copy(field.far_ptr, inf->field_ptr, field.fieldType);
				
				if ((field.fieldType==GF_SG_VRML_SFTIME) && !strstr(field.name, "media"))
					*(SFTime *)field.far_ptr = *(SFTime *)field.far_ptr + time_offset;
				break;
			}
			SG_CheckFieldChange(com->node, &field);
		}
		break;
	}

	case GF_SG_MULTIPLE_INDEXED_REPLACE:
	case GF_SG_INDEXED_REPLACE:
	{
		u32 sftype, i=0;
		while ((inf = (GF_CommandField*)gf_list_enum(com->command_fields, &i))) {
			e = gf_node_get_field(com->node, inf->fieldIndex, &field);
			if (e) return e;

			/*if MFNode remove the child and set new node*/
			if (field.fieldType == GF_SG_VRML_MFNODE) {
				/*we must remove the node before in case the new node uses the same ID (not forbidden) and this
				command removes the last instance of the node with the same ID*/
				gf_node_replace_child(com->node, (GF_ChildNodeItem**) field.far_ptr, inf->pos, inf->new_node);
				if (inf->new_node) gf_node_register(inf->new_node, NULL);
			}
			/*erase the field item*/
			else {
				if ((inf->pos < 0) || ((u32) inf->pos >= ((GenMFField *) field.far_ptr)->count) ) {
					inf->pos = ((GenMFField *)field.far_ptr)->count - 1;
					/*may happen with text and default value*/
					if (inf->pos < 0) {
						inf->pos = 0;
						gf_sg_vrml_mf_alloc(field.far_ptr, field.fieldType, 1);
					}
				}
				e = gf_sg_vrml_mf_get_item(field.far_ptr, field.fieldType, & slot_ptr, inf->pos);
				if (e) return e;
				sftype = gf_sg_vrml_get_sf_type(field.fieldType);
				gf_sg_vrml_field_copy(slot_ptr, inf->field_ptr, sftype);
				/*note we don't add time offset, since there's no MFTime*/
			}
			SG_CheckFieldChange(com->node, &field);
		}
		break;
	}
	case GF_SG_ROUTE_REPLACE:
	{
		GF_Route *r;
		char *name;
		r = gf_sg_route_find(graph, com->RouteID);
		def = gf_sg_find_node(graph, com->fromNodeID);
		node = gf_sg_find_node(graph, com->toNodeID);
		if (!node || !def) return GF_SG_UNKNOWN_NODE;
		name = NULL;
		if (r) {
			name = r->name;
			r->name = NULL;
			gf_sg_route_del(r);
		}
		r = gf_sg_route_new(graph, def, com->fromFieldIndex, node, com->toFieldIndex);
		gf_sg_route_set_id(r, com->RouteID);
		if (name) {
			gf_sg_route_set_name(r, name);
			gf_free(name);
		}
		break;
	}
	case GF_SG_NODE_DELETE_EX:
	case GF_SG_NODE_DELETE:
	{
		if (com->node) gf_node_replace(com->node, NULL, (com->tag==GF_SG_NODE_DELETE_EX) ? 1 : 0);
		break;
	}
	case GF_SG_ROUTE_DELETE:
	{
		return gf_sg_route_del_by_id(graph, com->RouteID);
	}
	case GF_SG_INDEXED_DELETE:
	{
		if (!gf_list_count(com->command_fields)) return GF_OK;
		inf = (GF_CommandField*)gf_list_get(com->command_fields, 0);

		e = gf_node_get_field(com->node, inf->fieldIndex, &field);
		if (e) return e;
		if (gf_sg_vrml_is_sf_field(field.fieldType)) return GF_NON_COMPLIANT_BITSTREAM;

		/*then we need special handling in case of a node*/
		if (gf_sg_vrml_get_sf_type(field.fieldType) == GF_SG_VRML_SFNODE) {
			e = gf_node_replace_child(com->node, (GF_ChildNodeItem **) field.far_ptr, inf->pos, NULL);
		} else {
			if ((inf->pos < 0) || ((u32) inf->pos >= ((GenMFField *) field.far_ptr)->count) ) {
				inf->pos = ((GenMFField *)field.far_ptr)->count - 1;
			}
			/*this is a regular MFField, just remove the item (gf_realloc)*/
			e = gf_sg_vrml_mf_remove(field.far_ptr, field.fieldType, inf->pos);
		}
		/*deletion -> node has changed*/
		if (!e) SG_CheckFieldChange(com->node, &field);
		break;
	}
	case GF_SG_NODE_INSERT:
	{
		if (!gf_list_count(com->command_fields)) return GF_OK;
		inf = (GF_CommandField*)gf_list_get(com->command_fields, 0);

		e = gf_node_insert_child(com->node, inf->new_node, inf->pos);
		if (!e) gf_node_register(inf->new_node, com->node);
		if (!e) gf_node_event_out(com->node, inf->fieldIndex);
		if (!e) gf_node_changed(com->node, NULL);
		break;
	}
	case GF_SG_ROUTE_INSERT:
	{
		GF_Route *r;
		def = gf_sg_find_node(graph, com->fromNodeID);
		node = gf_sg_find_node(graph, com->toNodeID);
		if (!node || !def) return GF_SG_UNKNOWN_NODE;
		r = gf_sg_route_new(graph, def, com->fromFieldIndex, node, com->toFieldIndex);
		if (com->RouteID) gf_sg_route_set_id(r, com->RouteID);
		if (com->def_name) {
			gf_sg_route_set_name(r, com->def_name);
			gf_free(com->def_name);
			com->def_name = NULL;
		}
		break;
	}
	case GF_SG_INDEXED_INSERT:
	{
		u32 sftype;
		if (!gf_list_count(com->command_fields)) return GF_OK;
		inf = (GF_CommandField*)gf_list_get(com->command_fields, 0);
		e = gf_node_get_field(com->node, inf->fieldIndex, &field);
		if (e) return e;

		/*rescale the MFField and parse the SFField*/
		if (field.fieldType != GF_SG_VRML_MFNODE) {
			if (inf->pos == -1) {
				e = gf_sg_vrml_mf_append(field.far_ptr, field.fieldType, & slot_ptr);
			} else {
				e = gf_sg_vrml_mf_insert(field.far_ptr, field.fieldType, & slot_ptr, inf->pos);
			}
			if (e) return e;
			sftype = gf_sg_vrml_get_sf_type(field.fieldType);
			gf_sg_vrml_field_copy(slot_ptr, inf->field_ptr, sftype);
		} else {
			if (inf->new_node) {
				if (inf->pos == -1) {
					gf_node_list_add_child( (GF_ChildNodeItem **) field.far_ptr, inf->new_node);
				} else {
					gf_node_list_insert_child((GF_ChildNodeItem **) field.far_ptr, inf->new_node, inf->pos);
				}
				gf_node_register(inf->new_node, com->node);
			}
		}
		if (!e) SG_CheckFieldChange(com->node, &field);
		break;
	}
	case GF_SG_PROTO_INSERT:
		/*destroy all proto*/
		while (gf_list_count(com->new_proto_list)) {
			GF_Proto *p = (GF_Proto*)gf_list_get(com->new_proto_list, 0);
			gf_list_rem(com->new_proto_list, 0);
			gf_list_del_item(graph->unregistered_protos, p);
			gf_list_add(graph->protos, p);
		}
		return GF_OK;
	case GF_SG_PROTO_DELETE:
		{
			u32 i;
			for (i=0; i<com->del_proto_list_size; i++) {
				/*note this will check for unregistered protos, but since IDs are unique we are sure we will 
				not destroy an unregistered one*/
				GF_Proto *proto = gf_sg_find_proto(graph, com->del_proto_list[i], NULL);
				if (proto) gf_sg_proto_del(proto);
			}
		}
		return GF_OK;
	case GF_SG_PROTO_DELETE_ALL:
		/*destroy all proto*/
		while (gf_list_count(graph->protos)) {
			GF_Proto *p = (GF_Proto*)gf_list_get(graph->protos, 0);
			gf_list_rem(graph->protos, 0);
			/*this will unregister the proto from the graph, so don't delete the chain entry*/
			gf_sg_proto_del(p);
		}
		/*DO NOT TOUCH UNREGISTERED PROTOS*/
		return GF_OK;
	case GF_SG_XREPLACE:
	{
		s32 pos = -2; 
		GF_Node *target = NULL;
		GF_ChildNodeItem *list, *cur, *prev;
		GF_FieldInfo value;
		inf = (GF_CommandField*)gf_list_get(com->command_fields, 0);
		if (!inf) return GF_SG_UNKNOWN_NODE;

		e = gf_node_get_field(com->node, inf->fieldIndex, &field);
		if (e) return e;
		target = com->node;

		if (!gf_sg_vrml_is_sf_field(field.fieldType)) {
			GF_FieldInfo idxField;
			if ((inf->pos != -2) || com->toNodeID) {
				if (com->toNodeID) {
					GF_Node *idxNode = gf_sg_find_node(graph, com->toNodeID);
					if (!idxNode) return GF_SG_UNKNOWN_NODE;
				
					if (gf_node_get_field(idxNode, com->toFieldIndex, &idxField) != GF_OK) return GF_OK;
					pos = 0;
					switch (idxField.fieldType) {
					case GF_SG_VRML_SFBOOL:
						if (*(SFBool*)idxField.far_ptr) pos = 1;
						break;
					case GF_SG_VRML_SFINT32:
						if (*(SFInt32*)idxField.far_ptr >=0) pos = *(SFInt32*)idxField.far_ptr;
						break;
					case GF_SG_VRML_SFFLOAT:
						if ( (*(SFFloat *)idxField.far_ptr) >=0) pos = (s32) floor( FIX2FLT(*(SFFloat*)idxField.far_ptr) );
						break;
					case GF_SG_VRML_SFTIME:
						if ( (*(SFTime *)idxField.far_ptr) >=0) pos = (s32) floor( (*(SFTime *)idxField.far_ptr) );
						break;
					}
				} else {
					pos = inf->pos;
				}
			}
		}
		/*override target node*/
		if ((field.fieldType==GF_SG_VRML_MFNODE) && (pos>=-1) && com->ChildNodeTag) {
			target = gf_node_list_get_child(*(GF_ChildNodeItem **)field.far_ptr, pos);
			if (!target) return GF_SG_UNKNOWN_NODE;
			if (gf_node_get_field(target, com->child_field, &field) != GF_OK) return GF_SG_UNKNOWN_NODE;
			pos=-2;
		}

		if (com->fromNodeID) {
			GF_Node *fromNode = gf_sg_find_node(graph, com->fromNodeID);
			if (!fromNode) return GF_SG_UNKNOWN_NODE;
			e = gf_node_get_field(fromNode, com->fromFieldIndex, &value);
			if (e) return e;
		} else {
			value.far_ptr = inf->field_ptr;
			value.fieldType = inf->fieldType;
		}
		/*indexed replacement*/
		if (pos>=-1) {
			/*if MFNode remove the child and set new node*/
			if (field.fieldType == GF_SG_VRML_MFNODE) {
				GF_Node *nn = *(GF_Node**)value.far_ptr;
				gf_node_replace_child(target, (GF_ChildNodeItem**) field.far_ptr, pos, nn);
				if (nn) gf_node_register(nn, NULL);
			}
			/*erase the field item*/
			else {
				u32 sftype;
				if ((pos < 0) || ((u32) pos >= ((GenMFField *) field.far_ptr)->count) ) {
					pos = ((GenMFField *)field.far_ptr)->count - 1;
					/*may happen with text and default value*/
					if (pos < 0) {
						pos = 0;
						gf_sg_vrml_mf_alloc(field.far_ptr, field.fieldType, 1);
					}
				}
				e = gf_sg_vrml_mf_get_item(field.far_ptr, field.fieldType, & slot_ptr, pos);
				if (e) return e;
				sftype = gf_sg_vrml_get_sf_type(field.fieldType);
				gf_sg_vrml_field_copy(slot_ptr, value.far_ptr, sftype);
				/*note we don't add time offset, since there's no MFTime*/
			}
		} else {
			switch (field.fieldType) {
			case GF_SG_VRML_SFNODE:
			{
				node = *((GF_Node **) field.far_ptr);
				e = gf_node_unregister(node, target);
				*((GF_Node **) field.far_ptr) = *((GF_Node **) value.far_ptr) ;
				if (!e) gf_node_register(*(GF_Node **) value.far_ptr, target);
				break;
			}
			case GF_SG_VRML_MFNODE:
				gf_node_unregister_children(target, * ((GF_ChildNodeItem **) field.far_ptr));
				* ((GF_ChildNodeItem **) field.far_ptr) = NULL;

				list = * ((GF_ChildNodeItem **) value.far_ptr);
				prev=NULL;
				while (list) {
					cur = gf_malloc(sizeof(GF_ChildNodeItem));
					cur->next = NULL;
					cur->node = list->node;
					if (prev) {
						prev->next = cur;
					} else {
						* ((GF_ChildNodeItem **) field.far_ptr) = cur;
					}
					gf_node_register(list->node, target);
					prev = cur;
					list = list->next;
				}
				break;

			default:
				if (!gf_sg_vrml_is_sf_field(field.fieldType)) {
					e = gf_sg_vrml_mf_reset(field.far_ptr, field.fieldType);
				}
				if (e) return e;
				gf_sg_vrml_field_clone(field.far_ptr, value.far_ptr, field.fieldType, graph);
				
				if ((field.fieldType==GF_SG_VRML_SFTIME) && !strstr(field.name, "media"))
					*(SFTime *)field.far_ptr = *(SFTime *)field.far_ptr + time_offset;
				break;
			}
		}
		SG_CheckFieldChange(target, &field);
	}
		return GF_OK;
	/*only used by BIFS*/
	case GF_SG_GLOBAL_QUANTIZER:
		return GF_OK;

#endif /*GPAC_DISABLE_VRML*/


#ifndef GPAC_DISABLE_SVG
	/*laser commands*/
	case GF_SG_LSR_NEW_SCENE:
		/*DO NOT TOUCH node registry*/

		/*assign new root (no need to register/unregister)*/
		graph->RootNode = com->node;
		com->node = NULL;
		break;
	case GF_SG_LSR_DELETE:
		if (!com->node) return GF_NON_COMPLIANT_BITSTREAM;
		if (!gf_list_count(com->command_fields)) {
			gf_node_replace(com->node, NULL, 0);
			gf_node_deactivate(com->node);
			return GF_OK;
		}
		inf = (GF_CommandField*)gf_list_get(com->command_fields, 0);
		node = gf_node_list_get_child(((SVG_Element *)com->node)->children, inf->pos);
		if (node) {
			e = gf_node_replace_child(com->node, &((SVG_Element *)com->node)->children, inf->pos, NULL);
			gf_node_deactivate(node);
		}
		break;
	case GF_SG_LSR_INSERT:
		inf = (GF_CommandField*)gf_list_get(com->command_fields, 0);
		if (!com->node || !inf) return GF_NON_COMPLIANT_BITSTREAM;
		if (inf->new_node) {
			if (inf->pos<0) 
				gf_node_list_add_child(& ((SVG_Element *)com->node)->children, inf->new_node);
			else
				gf_node_list_insert_child(& ((SVG_Element *)com->node)->children, inf->new_node, inf->pos);

			gf_node_register(inf->new_node, com->node);
			gf_node_activate(inf->new_node);
			gf_node_changed(com->node, NULL);
		} else {
			/*NOT SUPPORTED*/
			GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[LASeR] VALUE INSERTION NOT SUPPORTED\n"));
		}
		break;
	case GF_SG_LSR_ADD:
	case GF_SG_LSR_REPLACE:
		inf = (GF_CommandField*)gf_list_get(com->command_fields, 0);
		if (!com->node || !inf) return GF_NON_COMPLIANT_BITSTREAM;
		if (inf->new_node) {
			if (inf->pos<0) {
				/*if fieldIndex (eg attributeName) is set, this is children replacement*/
				if (inf->fieldIndex>0) {
					gf_node_unregister_children_deactivate(com->node, ((SVG_Element *)com->node)->children);
					((SVG_Element *)com->node)->children = NULL;
					gf_node_list_add_child(& ((SVG_Element *)com->node)->children, inf->new_node);
					gf_node_register(inf->new_node, com->node);
					gf_node_activate(inf->new_node);
				} else {
					e = gf_node_replace(com->node, inf->new_node, 0);
					gf_node_activate(inf->new_node);
				}
			} else {
				node = gf_node_list_get_child( ((SVG_Element *)com->node)->children, inf->pos);
				gf_node_replace_child(com->node, & ((SVG_Element *)com->node)->children, inf->pos, inf->new_node);
				gf_node_register(inf->new_node, com->node);
				if (node) gf_node_deactivate(node);
				gf_node_activate(inf->new_node);
			}
			/*signal node modif*/
			gf_node_changed(com->node, NULL);
			return e;
		} else if (inf->node_list) {
			GF_ChildNodeItem *child, *cur, *prev;
			gf_node_unregister_children_deactivate(com->node, ((SVG_Element *)com->node)->children);
			((SVG_Element *)com->node)->children = NULL;

			prev = NULL;
			child = inf->node_list;
			while (child) {
				cur = (GF_ChildNodeItem*)gf_malloc(sizeof(GF_ChildNodeItem));
				cur->next = NULL;
				cur->node = child->node;
				gf_node_register(child->node, com->node);
				gf_node_activate(child->node);
				if (prev) prev->next = cur;
				else ((SVG_Element *)com->node)->children = cur;
				prev = cur;
				child = child->next;
			}
			/*signal node modif*/
			gf_node_changed(com->node, NULL);
			return GF_OK;
		}
		/*attribute modif*/
		else if (inf->field_ptr) {
			GF_FieldInfo a, b;
			if (inf->fieldIndex==(u32) -2) {
				GF_Point2D scale, translate;
				Fixed rotate;
				GF_Matrix2D *dest;
				gf_node_get_field_by_name(com->node, "transform", &a);
				dest = (GF_Matrix2D*)a.far_ptr;
				
				if (com->tag==GF_SG_LSR_REPLACE) {
					if (gf_mx2d_decompose(dest, &scale, &rotate, &translate)) {
						gf_mx2d_init(*dest);
						if (inf->fieldType==SVG_TRANSFORM_SCALE) scale = *(GF_Point2D *)inf->field_ptr;
						else if (inf->fieldType==SVG_TRANSFORM_TRANSLATE) translate = *(GF_Point2D *)inf->field_ptr;
						else if (inf->fieldType==SVG_TRANSFORM_ROTATE) rotate = ((SVG_Point_Angle*)inf->field_ptr)->angle;

						gf_mx2d_add_scale(dest, scale.x, scale.y);
						gf_mx2d_add_rotation(dest, 0, 0, rotate);
						gf_mx2d_add_translation(dest, translate.x, translate.y);
					}
				} else {
					GF_Point2D *pt = (GF_Point2D *)inf->field_ptr;
					if (inf->fieldType==SVG_TRANSFORM_SCALE) gf_mx2d_add_scale(dest, pt->x, pt->y);
					else if (inf->fieldType==SVG_TRANSFORM_TRANSLATE) gf_mx2d_add_translation(dest, pt->x, pt->y);
					else if (inf->fieldType == SVG_TRANSFORM_ROTATE) gf_mx2d_add_rotation(dest, 0, 0, ((SVG_Point_Angle*)inf->field_ptr)->angle);
				}
				/*signal node modif*/
				gf_node_changed(com->node, &a);
			} else {
				if ((inf->fieldIndex==(u32) -1) && (inf->fieldType==DOM_String_datatype)) {
					char *str = *(SVG_String*)inf->field_ptr;

					if (com->tag == GF_SG_LSR_REPLACE) {
						GF_DOMText *t = ((SVG_Element*)com->node)->children ? (GF_DOMText*) ((SVG_Element*)com->node)->children->node :NULL; 
						if (t && (t->sgprivate->tag==TAG_DOMText)) {
							if (t->textContent) gf_free(t->textContent);
							t->textContent = NULL;
							if (str) t->textContent = gf_strdup(str);
						}
					} else {
						if (str) gf_dom_add_text_node(com->node, gf_strdup(str));
					}
					/*signal node modif*/
					gf_node_changed(com->node, NULL);
				}
				else if ((inf->fieldIndex==TAG_LSR_ATT_scale) 
					|| (inf->fieldIndex==TAG_LSR_ATT_translation)
					|| (inf->fieldIndex==TAG_LSR_ATT_rotation)
				) {
					SVG_Transform *mx;
					gf_node_get_attribute_by_tag(com->node, TAG_SVG_ATT_transform, 1, 0, &a);
					mx = a.far_ptr;
					if (com->tag == GF_SG_LSR_REPLACE) {
						GF_Point2D scale, translate;
						SVG_Point_Angle rotate;
						if (gf_mx2d_decompose(&mx->mat, &scale, &rotate.angle, &translate)) {
							gf_mx2d_init(mx->mat);
							if (inf->fieldIndex==TAG_LSR_ATT_scale) scale = *(GF_Point2D *)inf->field_ptr;
							else if (inf->fieldIndex==TAG_LSR_ATT_translation) translate = *(GF_Point2D *)inf->field_ptr;
							else if (inf->fieldIndex==TAG_LSR_ATT_rotation) rotate = *(SVG_Point_Angle*)inf->field_ptr;

							gf_mx2d_add_scale(&mx->mat, scale.x, scale.y);
							gf_mx2d_add_rotation(&mx->mat, 0, 0, rotate.angle);
							gf_mx2d_add_translation(&mx->mat, translate.x, translate.y);
						}
					} else {
						if (inf->fieldIndex==TAG_LSR_ATT_scale) gf_mx2d_add_scale(&mx->mat, ((GF_Point2D*)inf->field_ptr)->x, ((GF_Point2D*)inf->field_ptr)->y);
						if (inf->fieldIndex==TAG_LSR_ATT_translation) gf_mx2d_add_translation(&mx->mat, ((GF_Point2D*)inf->field_ptr)->x, ((GF_Point2D*)inf->field_ptr)->y);
						if (inf->fieldIndex==TAG_LSR_ATT_rotation) gf_mx2d_add_rotation(&mx->mat, 0, 0, ((SVG_Point_Angle*)inf->field_ptr)->angle);
					}
					/*signal node modif*/
					gf_node_changed(com->node, &a);
				}
				else if (gf_node_get_attribute_by_tag(com->node, inf->fieldIndex, 1, 0, &a) == GF_OK) {
					b = a;
					b.far_ptr = inf->field_ptr;
					if (com->tag == GF_SG_LSR_REPLACE) {
						gf_svg_attributes_copy(&a, &b, 0);
					} else {
						gf_svg_attributes_add(&a, &b, &a, 0);
					}
					if (a.fieldType==XMLRI_datatype) {
						gf_node_dirty_set(com->node, GF_SG_SVG_XLINK_HREF_DIRTY, 0);
					}
					/*signal node modif*/
					gf_node_changed(com->node, &a);
				}
			}
		} else if (com->fromNodeID) {
			GF_FieldInfo a, b;
			GF_Node *fromNode = gf_sg_find_node(graph, com->fromNodeID);
			if (!fromNode) return GF_NON_COMPLIANT_BITSTREAM;
			if (gf_node_get_field(fromNode, com->fromFieldIndex, &b) != GF_OK) return GF_NON_COMPLIANT_BITSTREAM;

			if ((inf->fieldIndex==(u32) -1) && (inf->fieldType==DOM_String_datatype)) {
				char *str = *(SVG_String*)inf->field_ptr;

				if (com->tag == GF_SG_LSR_REPLACE) {
					GF_DOMText *t = ((SVG_Element*)com->node)->children ? (GF_DOMText*) ((SVG_Element*)com->node)->children->node :NULL; 
					if (t && (t->sgprivate->tag==TAG_DOMText)) {
						if (t->textContent) gf_free(t->textContent);
						t->textContent = NULL;
						if (str) t->textContent = gf_strdup(str);
					}
				} else {
					if (str) gf_dom_add_text_node(com->node, gf_strdup(str));
				}
			} else {
				gf_node_get_field(com->node, inf->fieldIndex, &a);
				if (com->tag == GF_SG_LSR_REPLACE) {
					e = gf_svg_attributes_copy(&a, &b, 0);
				} else {
					e = gf_svg_attributes_add(&a, &b, &a, 0);
				}
			}
			gf_node_changed(com->node, &a);
			return e;
		} else {
			return GF_NON_COMPLIANT_BITSTREAM;
		}
		break;
	case GF_SG_LSR_ACTIVATE:
		gf_node_activate(com->node);
		break;
	case GF_SG_LSR_DEACTIVATE:
		gf_node_deactivate(com->node);
		gf_node_changed(com->node, NULL);
		break;
	case GF_SG_LSR_SEND_EVENT:
	{
		GF_DOM_Event evt;
		memset(&evt, 0, sizeof(GF_DOM_Event));
		evt.type = com->send_event_name;
		evt.detail = com->send_event_integer;
		evt.clientX = com->send_event_x;
		evt.clientY = com->send_event_y;
		gf_dom_event_fire(com->node, &evt);
	}
		break;
#endif

	default:
		return GF_NOT_SUPPORTED;
	}
	if (e) return e;

#ifndef GPAC_DISABLE_VRML
	if (com->scripts_to_load) {
		while (gf_list_count(com->scripts_to_load)) {
			GF_Node *script = (GF_Node *)gf_list_get(com->scripts_to_load, 0);
			gf_list_rem(com->scripts_to_load, 0);
			gf_sg_script_load(script);
		}
		gf_list_del(com->scripts_to_load);
		com->scripts_to_load = NULL;
	}
#endif

	return GF_OK;
}
示例#3
0
static void svg_traverse_svg(GF_Node *node, void *rs, Bool is_destroy)
{
	Bool rootmost_svg, send_resize;
	u32 viewport_color;
	SVGsvgStack *stack;
	GF_Matrix2D backup_matrix, vb_bck;
#ifndef GPAC_DISABLE_3D
	GF_Matrix bck_mx;
#endif
	Bool is_dirty;
	GF_IRect top_clip;
	SFVec2f prev_vp;
	SVGPropertiesPointers backup_props, *prev_props;
	u32 backup_flags;
	Bool invalidate_flag;
	u32 styling_size = sizeof(SVGPropertiesPointers);
	GF_TraverseState *tr_state = (GF_TraverseState *) rs;
	SVGAllAttributes all_atts;
	stack = gf_node_get_private(node);

	if (is_destroy) {
		if (stack->svg_props) {
			gf_svg_properties_reset_pointers(stack->svg_props);
			gf_free(stack->svg_props);
		}
		gf_sc_check_focus_upon_destroy(node);
		if (stack->vp_fill) drawable_del(stack->vp_fill);
		gf_free(stack);
		return;
	}

	prev_props = tr_state->svg_props;
	/*SVG props not set: we are either the root-most <svg> of the compositor
	or an <svg> inside an <animation>*/
	if (!tr_state->svg_props) {
		tr_state->svg_props = stack->svg_props;
		if (!tr_state->svg_props) return;
	}
	
	gf_svg_flatten_attributes((SVG_Element *)node, &all_atts);
	if (!compositor_svg_traverse_base(node, &all_atts, tr_state, &backup_props, &backup_flags)) {
		tr_state->svg_props = prev_props;
		return;
	}

	/*enable or disable navigation*/
	tr_state->visual->compositor->navigation_disabled = (all_atts.zoomAndPan && *all_atts.zoomAndPan == SVG_ZOOMANDPAN_DISABLE) ? 1 : 0;

	if (compositor_svg_is_display_off(tr_state->svg_props)) {
		memcpy(tr_state->svg_props, &backup_props, styling_size);
		tr_state->svg_flags = backup_flags;
		return;
	}

	top_clip = tr_state->visual->top_clipper;
	gf_mx2d_copy(backup_matrix, tr_state->transform);
	gf_mx2d_copy(vb_bck, tr_state->vb_transform);

#ifndef GPAC_DISABLE_3D
	if (tr_state->visual->type_3d) gf_mx_copy(bck_mx, tr_state->model_matrix);
#endif
	
	invalidate_flag = tr_state->invalidate_all;

	is_dirty = gf_node_dirty_get(node);
	if (is_dirty  & GF_SG_CHILD_DIRTY) drawable_reset_group_highlight(tr_state, node);
	gf_node_dirty_clear(node, 0);

	send_resize = 0;
	if ((stack->parent_vp.x != tr_state->vp_size.x) || (stack->parent_vp.y != tr_state->vp_size.y)) {
		is_dirty = 1;
		send_resize = 1;
	}

	if (is_dirty || tr_state->visual->compositor->recompute_ar) {
		svg_recompute_viewport_transformation(node, stack, tr_state, &all_atts);
	}

	gf_mx2d_copy(tr_state->vb_transform, stack->viewbox_mx);

	rootmost_svg = (stack->root_svg && !tr_state->parent_anim_atts) ? 1 : 0;	
	if (tr_state->traversing_mode == TRAVERSE_SORT) {
		SVG_Paint *vp_fill = NULL;
		Fixed vp_opacity;

		if (tr_state->parent_anim_atts) {
			vp_fill = tr_state->parent_anim_atts->viewport_fill;
			vp_opacity = tr_state->parent_anim_atts->viewport_fill_opacity ? tr_state->parent_anim_atts->viewport_fill_opacity->value : FIX_ONE;
		} else {
			vp_fill = tr_state->svg_props->viewport_fill;
			vp_opacity = tr_state->svg_props->viewport_fill_opacity ? tr_state->svg_props->viewport_fill_opacity->value : FIX_ONE;
		} 

		if (vp_fill && (vp_fill->type != SVG_PAINT_NONE) && vp_opacity) {
			Bool col_dirty = 0;
			viewport_color = GF_COL_ARGB_FIXED(vp_opacity, vp_fill->color.red, vp_fill->color.green, vp_fill->color.blue);

			if (stack->prev_color != viewport_color) {
				stack->prev_color = viewport_color;
				col_dirty = 1;
			}

			if (!rootmost_svg) {
				DrawableContext *ctx;
				Fixed width = tr_state->parent_anim_atts->width->value;
				Fixed height = tr_state->parent_anim_atts->height->value;

				if (!stack->vp_fill) {
					stack->vp_fill = drawable_new();
					stack->vp_fill->node = node;
				}
				if ((width != stack->vp_fill->path->bbox.width) || (height != stack->vp_fill->path->bbox.height)) {
					drawable_reset_path(stack->vp_fill);
					gf_path_add_rect(stack->vp_fill->path, 0, 0, width, -height);
				}

				ctx = drawable_init_context_svg(stack->vp_fill, tr_state);
				if (ctx) {
					ctx->flags &= ~CTX_IS_TRANSPARENT;
					ctx->aspect.pen_props.width = 0;
					ctx->aspect.fill_color = viewport_color;
					ctx->aspect.fill_texture = NULL;
					if (col_dirty) ctx->flags |= CTX_APP_DIRTY;
					drawable_finalize_sort(ctx, tr_state, NULL);
				}

			} else if (col_dirty) {
				tr_state->visual->compositor->back_color = viewport_color;
				/*invalidate the entire visual*/
				tr_state->invalidate_all = 1;
			}
		}
	}


	if (!stack->root_svg && (all_atts.x || all_atts.y)) 
		gf_mx2d_add_translation(&tr_state->vb_transform, all_atts.x->value, all_atts.y->value);

#ifndef GPAC_DISABLE_3D
	if (tr_state->visual->type_3d) {
		if (tr_state->traversing_mode==TRAVERSE_SORT) {
			GF_Matrix tmp;
			visual_3d_matrix_push(tr_state->visual);

			gf_mx_from_mx2d(&tmp, &tr_state->vb_transform);
			visual_3d_matrix_add(tr_state->visual, tmp.m);
		} else {
			gf_mx_add_matrix_2d(&tr_state->model_matrix, &tr_state->vb_transform);
		}
	} else 
#endif
	{
		gf_mx2d_pre_multiply(&tr_state->transform, &tr_state->vb_transform);
	}

	/*store VP and move it to current VP (eg, the one used to compute the vb_transform)*/
	prev_vp = tr_state->vp_size;
	tr_state->vp_size = stack->vp;

	/*the event may trigger scripts which may delete nodes / modify the scene. We therefore send the resize event 
	before traversing the scene*/
	if (send_resize) {
		GF_DOM_Event evt;
		memset(&evt, 0, sizeof(GF_DOM_Event));
		evt.bubbles = 1;
		evt.type = GF_EVENT_RESIZE;
		gf_dom_event_fire(node, &evt);
	}
	if ((stack->vp.x != prev_vp.x) || (stack->vp.y != prev_vp.y)) {
		GF_Scene *scene = node->sgprivate->scenegraph->userpriv;
		
		if (scene) { 
			GF_DOM_Event evt;
			memset(&evt, 0, sizeof(GF_DOM_Event));
			evt.bubbles = 0;
			evt.screen_rect.width = stack->vpw;
			evt.screen_rect.height = stack->vph;
			evt.screen_rect.x = stack->dx;
			evt.screen_rect.y = stack->dy;
			evt.prev_translate.x = stack->vp.x;
			evt.prev_translate.y = stack->vp.y;
			evt.type = GF_EVENT_VP_RESIZE;
			gf_scene_notify_event(scene, 0, NULL, &evt, GF_OK);
		}
	}

	if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) {
		gf_sc_get_nodes_bounds(node, ((SVG_Element *)node)->children, tr_state, NULL);
	} else {
		compositor_svg_traverse_children(((SVG_Element *)node)->children, tr_state);
	}
	tr_state->vp_size = prev_vp;

#ifndef GPAC_DISABLE_3D
	if (tr_state->visual->type_3d) {
		if (tr_state->traversing_mode==TRAVERSE_SORT) visual_3d_matrix_pop(tr_state->visual);
		gf_mx_copy(tr_state->model_matrix, bck_mx);
	}
#endif
	gf_mx2d_copy(tr_state->transform, backup_matrix);  
	gf_mx2d_copy(tr_state->vb_transform, vb_bck);
	memcpy(tr_state->svg_props, &backup_props, styling_size);
	tr_state->svg_flags = backup_flags;
	tr_state->visual->top_clipper = top_clip;
	if (!stack->root_svg) {
		tr_state->invalidate_all = invalidate_flag;
	}
	tr_state->svg_props = prev_props;
}
示例#4
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;
}
示例#5
0
void gf_sr_simulation_tick(GF_Renderer *sr)
{	
	u32 in_time, end_time, i, count;

	/*lock renderer for the whole render cycle*/
	gf_sr_lock(sr, 1);

	/*first thing to do, let the video output handle user event if it is not threaded*/
	sr->video_out->ProcessEvent(sr->video_out, NULL);

	if (sr->freeze_display) {
		gf_sr_lock(sr, 0);
		gf_sleep(sr->frame_duration);
		return;
	}

	gf_sr_reconfig_task(sr);

	/* if there is no scene, we draw a black screen to flush the screen */
	if (!sr->scene) {
		sr->visual_renderer->DrawScene(sr->visual_renderer);
		gf_sr_lock(sr, 0);
		gf_sleep(sr->frame_duration);
		return;
	}

//	GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[General] Time %f - Composing new frame #%d\n", gf_node_get_scene_time(gf_sg_get_root_node(sr->scene)), sr->frame_number));

	in_time = gf_sys_clock();
	if (sr->reset_graphics) sr->draw_next_frame = 1;

#ifdef GF_SR_EVENT_QUEUE
	/*process pending user events*/
	gf_mx_p(sr->ev_mx);
	while (gf_list_count(sr->events)) {
		GF_Event *ev = (GF_Event*)gf_list_get(sr->events, 0);
		gf_list_rem(sr->events, 0);
		if (!sr->visual_renderer->ExecuteEvent(sr->visual_renderer, ev)) {
			SR_ForwardUserEvent(sr, ev);
		}
		free(ev);
	}
	gf_mx_v(sr->ev_mx);
#endif


#if 0
	if (sr->frame_number == 0 && sr->user->EventProc) {
		GF_Event evt;
		evt.type = GF_EVENT_UPDATE_RTI;
		evt.caption.caption = "UPDATE - Before first call to draw scene";
		sr->user->EventProc(sr->user->opaque, &evt);
	}
#endif

	/*execute all routes before updating textures, otherwise nodes inside composite texture may never see their
	dirty flag set*/
	gf_sg_activate_routes(sr->scene);

#ifndef GPAC_DISABLE_SVG
#if SVG_FIXME
	{ /* Experimental (Not SVG compliant system events (i.e. battery, cpu ...) triggered to the root node)*/
		GF_Node *root = gf_sg_get_root_node(sr->scene);
		GF_DOM_Event evt;
		if (gf_dom_listener_count(root)) {
			u32 i, count;
			count = gf_dom_listener_count(root);
			for (i=0;i<count; i++) {
				SVG_SA_listenerElement *l = gf_dom_listener_get(root, i);
				if (l->event.type == GF_EVENT_CPU) {
					GF_SystemRTInfo sys_rti;
					if (gf_sys_get_rti(500, &sys_rti, GF_RTI_ALL_PROCESSES_TIMES)) {
						evt.type = GF_EVENT_CPU;
						evt.cpu_percentage = sys_rti.total_cpu_usage;
						//printf("%d\n",sys_rti.total_cpu_usage);
						gf_dom_event_fire(root, NULL, &evt);
					} 
				} else if (l->event.type == GF_EVENT_BATTERY) { //&& l->observer.target == (SVG_SA_Element *)node) {
					evt.type = GF_EVENT_BATTERY;
					gf_sys_get_battery_state(&evt.onBattery, &evt.batteryState, &evt.batteryLevel);
					gf_dom_event_fire(root, NULL, &evt);
				}
			}
		}
	}
#endif

	if (gf_smil_notify_timed_elements(sr->scene)) {
		sr->draw_next_frame = 1;
	}
#if 0
	for (i=0; i<gf_list_count(sr->secondary_scenes); i++) {
		if (gf_smil_notify_timed_elements(gf_list_get(sr->secondary_scenes, i))) {
			sr->draw_next_frame = 1;
		}
	}
#endif

#endif

	/*update all textures*/
	count = gf_list_count(sr->textures);
	for (i=0; i<count; i++) {
		GF_TextureHandler *st = (GF_TextureHandler *)gf_list_get(sr->textures, i);
		/*signal graphics reset before updating*/
		if (sr->reset_graphics && st->hwtx) sr->visual_renderer->TextureHWReset(st);
		st->update_texture_fcnt(st);
	}

	/*if invalidated, draw*/
	if (sr->draw_next_frame) {
		/*video flush only*/
		if (sr->draw_next_frame==2) {
			GF_Window rc;
			rc.x = rc.y = 0; 
			rc.w = sr->width;	
			rc.h = sr->height;		
			sr->draw_next_frame = 0;
			sr->video_out->Flush(sr->video_out, &rc);
		} else {
			sr->draw_next_frame = 0;
			GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render] Redrawing scene\n"));
			sr->visual_renderer->DrawScene(sr->visual_renderer);
#if 0
			if (sr->frame_number == 0 && sr->user->EventProc) {
				GF_Event evt;
				evt.type = GF_EVENT_UPDATE_RTI;
				evt.caption.caption = "Before first call to draw scene";
				sr->user->EventProc(sr->user->opaque, &evt);
			}
#endif
		}
		sr->reset_graphics = 0;

		GF_LOG(GF_LOG_INFO, GF_LOG_RENDER, ("[Render] Scene drawn in %d ms\n", gf_sys_clock() - in_time));

		if (sr->stress_mode) {
			sr->draw_next_frame = 1;
			sr->reset_graphics = 1;
		}
	}

	/*release all textures - we must release them to handle a same OD being used by several textures*/
	count = gf_list_count(sr->textures);
	for (i=0; i<count; i++) {
		GF_TextureHandler *st = (GF_TextureHandler *)gf_list_get(sr->textures, i);
		gf_sr_texture_release_stream(st);
	}

	/*update all timed nodes */
	for (i=0; i<gf_list_count(sr->time_nodes); i++) {
		GF_TimeNode *tn = (GF_TimeNode *)gf_list_get(sr->time_nodes, i);
		if (!tn->needs_unregister) tn->UpdateTimeNode(tn);
		if (tn->needs_unregister) {
			tn->is_registered = 0;
			tn->needs_unregister = 0;
			gf_list_rem(sr->time_nodes, i);
			i--;
			continue;
		}
	}

	end_time = gf_sys_clock() - in_time;

	gf_sr_lock(sr, 0);

	sr->current_frame = (sr->current_frame+1) % GF_SR_FPS_COMPUTE_SIZE;
	sr->frame_time[sr->current_frame] = end_time;

	sr->frame_number++;
#if 0
	if (sr->user->EventProc) {
		char legend[100];
		GF_Event evt;
		evt.type = GF_EVENT_UPDATE_RTI;
		sprintf(legend, "After rendering of frame %d", sr->frame_number);
		evt.caption.caption = legend;
		sr->user->EventProc(sr->user->opaque, &evt);
	}
#endif

	/*step mode on, pause and return*/
	if (sr->step_mode) {
		sr->step_mode = 0;
		if (sr->term) gf_term_set_option(sr->term, GF_OPT_PLAY_STATE, GF_STATE_PAUSED);
		return;
	}
	/*not threaded, let the owner decide*/
	if ((sr->user->init_flags & GF_TERM_NO_VISUAL_THREAD) || !sr->frame_duration) return;

	/*compute sleep time till next frame, otherwise we'll kill the CPU*/
	i=1;
	while (i * sr->frame_duration < end_time) i++;
	in_time = i * sr->frame_duration - end_time;
	gf_sleep(in_time);
}