/*hardcoded proto loading - this is mainly used for module development and testing...*/ void compositor_init_hardcoded_proto(GF_Compositor *compositor, GF_Node *node) { MFURL *proto_url; GF_Proto *proto; u32 i; proto = gf_node_get_proto(node); if (!proto) return; proto_url = gf_sg_proto_get_extern_url(proto); for (i=0; i<proto_url->count; i++) { const char *url = proto_url->vals[0].url; #ifndef GPAC_DISABLE_3D if (!strcmp(url, "urn:inet:gpac:builtin:PathExtrusion")) { compositor_init_path_extrusion(compositor, node); return; } if (!strcmp(url, "urn:inet:gpac:builtin:PlanarExtrusion")) { compositor_init_planar_extrusion(compositor, node); return; } if (!strcmp(url, "urn:inet:gpac:builtin:PlaneClipper")) { compositor_init_plane_clipper(compositor, node); return; } #endif if (!strcmp(url, "urn:inet:gpac:builtin:TextureText")) { compositor_init_texture_text(compositor, node); return; } if (!strcmp(url, "urn:inet:gpac:builtin:OffscreenGroup")) { compositor_init_offscreen_group(compositor, node); return; } if (!strcmp(url, "urn:inet:gpac:builtin:DepthGroup")) { compositor_init_depth_group(compositor, node); return; } if (!strcmp(url, "urn:inet:gpac:builtin:DepthViewPoint")) { compositor_init_depth_viewpoint(compositor, node); return; } if (!strcmp(url, "urn:inet:gpac:builtin:IndexedCurve2D")) { compositor_init_idx_curve2d(compositor, node); return; } if (!strcmp(url, "urn:inet:gpac:builtin:Untransform")) { compositor_init_untransform(compositor, node); return; } if (!strcmp(url, "urn:inet:gpac:builtin:FlashShape")) { compositor_init_hc_flashshape(compositor, node); return; } } }
GF_Node *gf_bifs_dec_node(GF_BifsDecoder * codec, GF_BitStream *bs, u32 NDT_Tag) { u32 nodeID, NDTBits, node_type, node_tag, ProtoID, BVersion; Bool skip_init, reset_qp14; GF_Node *new_node; GF_Err e; GF_Proto *proto; void SetupConditional(GF_BifsDecoder *codec, GF_Node *node); //to store the UseName char name[1000]; #if 0 /*should only happen with inputSensor, in which case this is BAAAAD*/ if (!codec->info) { codec->LastError = GF_BAD_PARAM; return NULL; } #endif BVersion = GF_BIFS_V1; /*this is a USE statement*/ if (gf_bs_read_int(bs, 1)) { nodeID = 1 + gf_bs_read_int(bs, codec->info->config.NodeIDBits); /*NULL node is encoded as USE with ID = all bits to 1*/ if (nodeID == (u32) (1<<codec->info->config.NodeIDBits)) return NULL; //find node and return it new_node = gf_sg_find_node(codec->current_graph, nodeID); if (!new_node) { codec->LastError = GF_SG_UNKNOWN_NODE; } else { /*restore QP14 length*/ switch (gf_node_get_tag(new_node)) { case TAG_MPEG4_Coordinate: { u32 nbCoord = ((M_Coordinate *)new_node)->point.count; gf_bifs_dec_qp14_enter(codec, 1); gf_bifs_dec_qp14_set_length(codec, nbCoord); gf_bifs_dec_qp14_enter(codec, 0); } break; case TAG_MPEG4_Coordinate2D: { u32 nbCoord = ((M_Coordinate2D *)new_node)->point.count; gf_bifs_dec_qp14_enter(codec, 1); gf_bifs_dec_qp14_set_length(codec, nbCoord); gf_bifs_dec_qp14_enter(codec, 0); } break; } } return new_node; } //this is a new node nodeID = 0; name[0] = 0; node_tag = 0; proto = NULL; //browse all node groups while (1) { NDTBits = gf_bifs_get_ndt_bits(NDT_Tag, BVersion); /*this happens in replacescene where no top-level node is present (externProto)*/ if ((BVersion==1) && (NDTBits > 8 * gf_bs_available(bs)) ) { codec->LastError = GF_OK; return NULL; } node_type = gf_bs_read_int(bs, NDTBits); if (node_type) break; //increment BIFS version BVersion += 1; //not supported if (BVersion > GF_BIFS_NUM_VERSION) { codec->LastError = GF_BIFS_UNKNOWN_VERSION; return NULL; } } if (BVersion==2 && node_type==1) { ProtoID = gf_bs_read_int(bs, codec->info->config.ProtoIDBits); /*look in current graph for the proto - this may be a proto graph*/ proto = gf_sg_find_proto(codec->current_graph, ProtoID, NULL); /*this was in proto so look in main scene*/ if (!proto && codec->current_graph != codec->scenegraph) proto = gf_sg_find_proto(codec->scenegraph, ProtoID, NULL); if (!proto) { codec->LastError = GF_SG_UNKNOWN_NODE; return NULL; } } else { node_tag = gf_bifs_ndt_get_node_type(NDT_Tag, node_type, BVersion); } /*special handling of 3D mesh*/ if ((node_tag == TAG_MPEG4_IndexedFaceSet) && codec->info->config.Use3DMeshCoding) { if (gf_bs_read_int(bs, 1)) { nodeID = 1 + gf_bs_read_int(bs, codec->info->config.NodeIDBits); if (codec->UseName) gf_bifs_dec_name(bs, name); } /*parse the 3DMesh node*/ return NULL; } /*unknow node*/ if (!node_tag && !proto) { codec->LastError = GF_SG_UNKNOWN_NODE; return NULL; } /*DEF'd flag*/ if (gf_bs_read_int(bs, 1)) { if (!codec->info->config.NodeIDBits) { codec->LastError = GF_NON_COMPLIANT_BITSTREAM; return NULL; } nodeID = 1 + gf_bs_read_int(bs, codec->info->config.NodeIDBits); if (codec->UseName) gf_bifs_dec_name(bs, name); } new_node = NULL; skip_init = 0; /*don't check node IDs duplicate since VRML may use them...*/ #if 0 /*if a node with same DEF is already in the scene, use it we don't do that in memory mode because commands may force replacement of a node with a new node with same ID, and we want to be able to dump it (otherwise we would dump a USE)*/ if (nodeID && !codec->dec_memory_mode) { new_node = gf_sg_find_node(codec->current_graph, nodeID); if (new_node) { if (proto) { if ((gf_node_get_tag(new_node) != TAG_ProtoNode) || (gf_node_get_proto(new_node) != proto)) { codec->LastError = GF_NON_COMPLIANT_BITSTREAM; return NULL; } skip_init = 1; } else { if (gf_node_get_tag(new_node) != node_tag) { codec->LastError = GF_NON_COMPLIANT_BITSTREAM; return NULL; } skip_init = 1; } } } #endif if (!new_node) { if (proto) { skip_init = 1; /*create proto interface*/ new_node = gf_sg_proto_create_instance(codec->current_graph, proto); } else { new_node = gf_node_new(codec->current_graph, node_tag); } } if (!new_node) { codec->LastError = GF_NOT_SUPPORTED; return NULL; } /*VRML: "The transformation hierarchy shall be a directed acyclic graph; results are undefined if a node in the transformation hierarchy is its own ancestor" that's good, because the scene graph can't handle cyclic graphs (destroy will never be called). We therefore only register the node once parsed*/ if (nodeID) { if (strlen(name)) { gf_node_set_id(new_node, nodeID, name); } else { gf_node_set_id(new_node, nodeID, NULL); } } /*update default time fields except in proto parsing*/ if (!codec->pCurrentProto) UpdateTimeNode(codec, new_node); /*nodes are only init outside protos */ else skip_init = 1; /*if coords were not stored for QP14 before coding this node, reset QP14 it when leaving*/ reset_qp14 = !codec->coord_stored; /*QP 14 is a special quant mode for IndexFace/Line(2D)Set to quantize the coordonate(2D) child, based on the first field parsed we must check the type of the node and notfy the QP*/ switch (node_tag) { case TAG_MPEG4_Coordinate: case TAG_MPEG4_Coordinate2D: gf_bifs_dec_qp14_enter(codec, 1); } if (gf_bs_read_int(bs, 1)) { e = gf_bifs_dec_node_mask(codec, bs, new_node, proto ? 1 : 0); } else { e = gf_bifs_dec_node_list(codec, bs, new_node, proto ? 1 : 0); } if (codec->coord_stored && reset_qp14) gf_bifs_dec_qp14_reset(codec); if (e) { codec->LastError = e; /*register*/ gf_node_register(new_node, NULL); /*unregister (deletes)*/ gf_node_unregister(new_node, NULL); return NULL; } if (!skip_init) gf_node_init(new_node); switch (node_tag) { case TAG_MPEG4_Coordinate: case TAG_MPEG4_Coordinate2D: gf_bifs_dec_qp14_enter(codec, 0); break; case TAG_MPEG4_Script: /*load script if in main graph (useless to load in proto declaration)*/ if (codec->scenegraph == codec->current_graph) { gf_sg_script_load(new_node); } break; /*conditionals must be init*/ case TAG_MPEG4_Conditional: SetupConditional(codec, new_node); break; } /*proto is initialized upon the first traversal to have the same behavior as wth BT/XMT loading*/ #if 0 /*if new node is a proto and we're in the top scene, load proto code*/ if (proto && (codec->scenegraph == codec->current_graph)) { codec->LastError = gf_sg_proto_load_code(new_node); } #endif return new_node; }
static GF_Err BM_XReplace(GF_BifsDecoder *codec, GF_BitStream *bs, GF_List *com_list) { GF_FieldInfo targetField, fromField, decfield; GF_Node *target, *n, *fromNode; s32 pos = -2; u32 id, nbBits, ind, aind; GF_Err e; GF_Command *com; GF_CommandField *inf; id = 1 + gf_bs_read_int(bs, codec->info->config.NodeIDBits); target = gf_sg_find_node(codec->current_graph, id); if (!target) return GF_SG_UNKNOWN_NODE; e = GF_OK; com = gf_sg_command_new(codec->current_graph, GF_SG_XREPLACE); BM_SetCommandNode(com, target); nbBits = gf_get_bit_size(gf_node_get_num_fields_in_mode(target, GF_SG_FIELD_CODING_IN)-1); ind = gf_bs_read_int(bs, nbBits); e = gf_bifs_get_field_index(target, ind, GF_SG_FIELD_CODING_IN, &aind); if (e) return e; e = gf_node_get_field(target, aind, &targetField); if (e) return e; inf = gf_sg_command_field_new(com); inf->fieldIndex = aind; if (!gf_sg_vrml_is_sf_field(targetField.fieldType)) { /*this is indexed replacement*/ if (gf_bs_read_int(bs, 1)) { /*index is dynamic*/ if (gf_bs_read_int(bs, 1)) { id = 1 + gf_bs_read_int(bs, codec->info->config.NodeIDBits); n = gf_sg_find_node(codec->current_graph, id); if (!n) return GF_SG_UNKNOWN_NODE; com->toNodeID = id; nbBits = gf_get_bit_size(gf_node_get_num_fields_in_mode(n, GF_SG_FIELD_CODING_DEF)-1); ind = gf_bs_read_int(bs, nbBits); e = gf_bifs_get_field_index(n, ind, GF_SG_FIELD_CODING_DEF, &aind); if (e) return e; e = gf_node_get_field(n, aind, &fromField); if (e) return e; com->toFieldIndex = aind; } else { u32 type = gf_bs_read_int(bs, 2); switch (type) { case 0: pos = gf_bs_read_int(bs, 16); break; case 2: pos = 0; break; case 3: pos = -1; break; } } } if (targetField.fieldType==GF_SG_VRML_MFNODE) { if (gf_bs_read_int(bs, 1)) { target = gf_node_list_get_child(*(GF_ChildNodeItem **)targetField.far_ptr, pos); if (!target) return GF_SG_UNKNOWN_NODE; nbBits = gf_get_bit_size(gf_node_get_num_fields_in_mode(target, GF_SG_FIELD_CODING_IN)-1); ind = gf_bs_read_int(bs, nbBits); e = gf_bifs_get_field_index(target, ind, GF_SG_FIELD_CODING_IN, &aind); if (e) return e; e = gf_node_get_field(target, aind, &targetField); if (e) return e; pos = -2; com->child_field = aind; com->ChildNodeTag = gf_node_get_tag(target); if (com->ChildNodeTag == TAG_ProtoNode) { s32 p_id = gf_sg_proto_get_id(gf_node_get_proto(target)); com->ChildNodeTag = -p_id; } } } inf->pos = pos; } fromNode = NULL; if (gf_bs_read_int(bs, 1)) { id = 1 + gf_bs_read_int(bs, codec->info->config.NodeIDBits); fromNode = gf_sg_find_node(codec->current_graph, id); if (!fromNode) return GF_SG_UNKNOWN_NODE; com->fromNodeID = id; nbBits = gf_get_bit_size(gf_node_get_num_fields_in_mode(fromNode, GF_SG_FIELD_CODING_DEF)-1); ind = gf_bs_read_int(bs, nbBits); e = gf_bifs_get_field_index(fromNode, ind, GF_SG_FIELD_CODING_DEF, &aind); if (e) return e; e = gf_node_get_field(fromNode, aind, &fromField); if (e) return e; com->fromFieldIndex = aind; return GF_OK; } if (pos>= -1) { inf->fieldType = gf_sg_vrml_get_sf_type(targetField.fieldType); } else { inf->fieldType = targetField.fieldType; } decfield.fieldIndex = inf->fieldIndex; decfield.fieldType = inf->fieldType; if (inf->fieldType==GF_SG_VRML_SFNODE) { decfield.far_ptr = inf->field_ptr = &inf->new_node; } else if (inf->fieldType==GF_SG_VRML_MFNODE) { decfield.far_ptr = inf->field_ptr = &inf->node_list; } else { decfield.far_ptr = inf->field_ptr = gf_sg_vrml_field_pointer_new(inf->fieldType); } e = gf_bifs_dec_sf_field(codec, bs, target, &decfield, 1); if (e) return e; gf_list_add(com_list, com); return GF_OK; }
/*hardcoded proto loading - this is mainly used for module development and testing...*/ void compositor_init_hardcoded_proto(GF_Compositor *compositor, GF_Node *node) { MFURL *proto_url; GF_Proto *proto; u32 i, j; GF_HardcodedProto *ifce; proto = gf_node_get_proto(node); if (!proto) return; proto_url = gf_sg_proto_get_extern_url(proto); for (i=0; i<proto_url->count; i++) { const char *url = proto_url->vals[0].url; #ifndef GPAC_DISABLE_3D if (!strcmp(url, "urn:inet:gpac:builtin:PathExtrusion")) { compositor_init_path_extrusion(compositor, node); return; } if (!strcmp(url, "urn:inet:gpac:builtin:PlanarExtrusion")) { compositor_init_planar_extrusion(compositor, node); return; } if (!strcmp(url, "urn:inet:gpac:builtin:PlaneClipper")) { compositor_init_plane_clipper(compositor, node); return; } #endif if (!strcmp(url, "urn:inet:gpac:builtin:TextureText")) { compositor_init_texture_text(compositor, node); return; } if (!strcmp(url, "urn:inet:gpac:builtin:OffscreenGroup")) { compositor_init_offscreen_group(compositor, node); return; } if (!strcmp(url, "urn:inet:gpac:builtin:DepthGroup")) { compositor_init_depth_group(compositor, node); return; } if (!strcmp(url, "urn:inet:gpac:builtin:DepthViewPoint")) { compositor_init_depth_viewpoint(compositor, node); return; } if (!strcmp(url, "urn:inet:gpac:builtin:IndexedCurve2D")) { compositor_init_idx_curve2d(compositor, node); return; } if (!strcmp(url, "urn:inet:gpac:builtin:Untransform")) { compositor_init_untransform(compositor, node); return; } if (!strcmp(url, "urn:inet:gpac:builtin:FlashShape")) { compositor_init_hc_flashshape(compositor, node); return; } if (!strcmp(url, "urn:inet:gpac:builtin:StyleGroup")) { compositor_init_style_group(compositor, node); return; } if (!strcmp(url, "urn:inet:gpac:builtin:TestSensor")) { compositor_init_test_sensor(compositor, node); return; } /*check proto modules*/ if (compositor->proto_modules) { j = 0; while ( (ifce = (GF_HardcodedProto *)gf_list_enum(compositor->proto_modules, &j) )) { if ( ifce->can_load_proto(url) && ifce->init(ifce, compositor, node, url) ) { return; } } } } }