LCOV - code coverage report
Current view: top level - scenegraph - vrml_proto.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 503 644 78.1 %
Date: 2021-04-29 23:48:07 Functions: 34 38 89.5 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2012
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / Scene Graph sub-project
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : 
      27             : #include <gpac/internal/scenegraph_dev.h>
      28             : /*MPEG4 & X3D tags (for node tables & script handling)*/
      29             : #include <gpac/nodes_mpeg4.h>
      30             : #include <gpac/nodes_x3d.h>
      31             : 
      32             : #ifndef GPAC_DISABLE_VRML
      33             : 
      34             : GF_EXPORT
      35         159 : GF_Proto *gf_sg_proto_new(GF_SceneGraph *inScene, u32 ProtoID, char *name, Bool unregistered)
      36             : {
      37             :         GF_Proto *tmp;
      38         159 :         if (!inScene) return NULL;
      39             : 
      40             :         /*make sure we don't define a proto already defined in this scope*/
      41         159 :         if (!unregistered) {
      42          17 :                 tmp = gf_sg_find_proto(inScene, ProtoID, name);
      43          17 :                 if (tmp) {
      44           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[Scenegraph] PROTO %s redefined - skipping loading\n", name));
      45             :                         return NULL;
      46             :                 }
      47             :         }
      48             : 
      49         159 :         GF_SAFEALLOC(tmp, GF_Proto)
      50         159 :         if (!tmp) return NULL;
      51             : 
      52         159 :         tmp->proto_fields = gf_list_new();
      53         159 :         tmp->node_code = gf_list_new();
      54         159 :         tmp->parent_graph = inScene;
      55         159 :         tmp->sub_graph = gf_sg_new_subscene(inScene);
      56         159 :         tmp->instances = gf_list_new();
      57             : 
      58         159 :         if (name)
      59         159 :                 tmp->Name = gf_strdup(name);
      60             :         else
      61           0 :                 tmp->Name = gf_strdup("Unnamed Proto");
      62         159 :         tmp->ID = ProtoID;
      63         159 :         if (!unregistered) {
      64          17 :                 gf_list_add(inScene->protos, tmp);
      65             :         } else {
      66         142 :                 gf_list_add(inScene->unregistered_protos, tmp);
      67             :         }
      68             :         return tmp;
      69             : }
      70             : 
      71             : #if 0
      72             : /*used for memory handling of scene graph only. move proto from off-graph to in-graph or reverse*/
      73             : GF_Err gf_sg_proto_set_in_graph(GF_Proto *proto, GF_SceneGraph *inScene, Bool set_in)
      74             : {
      75             :         u32 i;
      76             :         GF_Proto *tmp;
      77             :         GF_List *removeFrom;
      78             :         GF_List *insertIn;
      79             : 
      80             :         if (set_in) {
      81             :                 removeFrom = proto->parent_graph->unregistered_protos;
      82             :                 insertIn = proto->parent_graph->protos;
      83             :         } else {
      84             :                 insertIn = proto->parent_graph->unregistered_protos;
      85             :                 removeFrom = proto->parent_graph->protos;
      86             :         }
      87             : 
      88             :         gf_list_del_item(removeFrom, proto);
      89             : 
      90             :         i=0;
      91             :         while ((tmp = (GF_Proto*)gf_list_enum(insertIn, &i))) {
      92             :                 if (tmp==proto) return GF_OK;
      93             :                 if (!set_in) continue;
      94             :                 /*if registering, make sure no other proto has the same ID/name*/
      95             :                 if (tmp->ID==proto->ID) return GF_BAD_PARAM;
      96             :                 if (!stricmp(tmp->Name, proto->Name)) return GF_BAD_PARAM;
      97             :         }
      98             :         return gf_list_add(insertIn, proto);
      99             : }
     100             : #endif
     101             : 
     102             : GF_EXPORT
     103         159 : GF_Err gf_sg_proto_del(GF_Proto *proto)
     104             : {
     105             :         s32 i;
     106             : 
     107         159 :         if (!proto) return GF_OK;
     108         159 :         i = gf_list_del_item(proto->parent_graph->protos, proto);
     109         159 :         if (i<0) {
     110          77 :                 gf_list_del_item(proto->parent_graph->unregistered_protos, proto);
     111             :         }
     112         159 :         if (proto->userpriv && proto->OnDelete) proto->OnDelete(proto->userpriv);
     113             : 
     114             :         /*first destroy the code*/
     115         344 :         while (gf_list_count(proto->node_code)) {
     116         185 :                 GF_Node *node = (GF_Node*)gf_list_get(proto->node_code, 0);
     117         185 :                 gf_node_unregister(node, NULL);
     118         185 :                 gf_list_rem(proto->node_code, 0);
     119             :         }
     120         159 :         gf_list_del(proto->node_code);
     121             : 
     122             :         /*delete interface*/
     123        1260 :         while (gf_list_count(proto->proto_fields)) {
     124         942 :                 GF_ProtoFieldInterface *field = (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, 0);
     125         942 :                 if (field->userpriv && field->OnDelete) field->OnDelete(field->userpriv);
     126             : 
     127         942 :                 if (field->FieldType==GF_SG_VRML_SFNODE) {
     128          97 :                         if (field->def_sfnode_value)
     129           0 :                                 gf_node_unregister(field->def_sfnode_value, NULL);
     130             :                 }
     131         845 :                 else if (field->FieldType==GF_SG_VRML_MFNODE) {
     132          15 :                         if (field->def_mfnode_value)
     133           0 :                                 gf_node_unregister_children(NULL, field->def_mfnode_value);
     134             :                 }
     135         830 :                 else if (field->def_value)
     136         830 :                         gf_sg_vrml_field_pointer_del(field->def_value, field->FieldType);
     137             : 
     138         942 :                 if (field->FieldName) gf_free(field->FieldName);
     139             : 
     140             :                 /*QP fields are SF fields, we can safely gf_free() them*/
     141         942 :                 if (field->qp_max_value) gf_free(field->qp_max_value);
     142         942 :                 if (field->qp_min_value) gf_free(field->qp_min_value);
     143         942 :                 gf_free(field);
     144         942 :                 gf_list_rem(proto->proto_fields, 0);
     145             :         }
     146         159 :         gf_list_del(proto->proto_fields);
     147             : 
     148         437 :         while (gf_list_count(proto->instances)) {
     149         119 :                 GF_ProtoInstance *p = (GF_ProtoInstance *)gf_list_get(proto->instances, 0);
     150         119 :                 gf_list_rem(proto->instances, 0);
     151         119 :                 p->proto_interface = NULL;
     152             :         }
     153             : 
     154             :         /*delete sub graph*/
     155         159 :         gf_sg_del(proto->sub_graph);
     156             : 
     157             : 
     158         159 :         if (proto->Name) gf_free(proto->Name);
     159         159 :         gf_sg_mfurl_del(proto->ExternProto);
     160         159 :         gf_list_del(proto->instances);
     161         159 :         gf_free(proto);
     162         159 :         return GF_OK;
     163             : }
     164             : 
     165             : GF_EXPORT
     166         232 : GF_SceneGraph *gf_sg_proto_get_graph(GF_Proto *proto)
     167             : {
     168         232 :         return proto ? proto->sub_graph : NULL;
     169             : }
     170             : 
     171             : 
     172             : #if 0
     173             : void gf_sg_proto_set_private(GF_Proto *p, void *ptr, void (*OnDelete)(void *ptr) )
     174             : {
     175             :         if (p) {
     176             :                 p->userpriv = ptr;
     177             :                 p->OnDelete = OnDelete;
     178             :         }
     179             : }
     180             : 
     181             : void *gf_sg_proto_get_private(GF_Proto *p)
     182             : {
     183             :         return p ? p->userpriv : NULL;
     184             : }
     185             : #endif
     186             : 
     187             : GF_EXPORT
     188         679 : MFURL *gf_sg_proto_get_extern_url(GF_Proto *proto)
     189             : {
     190         679 :         return proto ? &proto->ExternProto : NULL;
     191             : }
     192             : 
     193             : GF_EXPORT
     194         185 : GF_Err gf_sg_proto_add_node_code(GF_Proto *proto, GF_Node *pNode)
     195             : {
     196         185 :         if (!proto) return GF_BAD_PARAM;
     197         185 :         return gf_list_add(proto->node_code, pNode);
     198             : }
     199             : 
     200             : GF_EXPORT
     201        1313 : GF_ProtoFieldInterface *gf_sg_proto_field_find_by_name(GF_Proto *proto, char *fieldName)
     202             : {
     203             :         GF_ProtoFieldInterface *ptr;
     204        1313 :         u32 i=0;
     205        7601 :         while ((ptr = (GF_ProtoFieldInterface*)gf_list_enum(proto->proto_fields, &i))) {
     206        5346 :                 if (ptr->FieldName && !strcmp(ptr->FieldName, fieldName)) return ptr;
     207             :         }
     208             :         return NULL;
     209             : }
     210             : 
     211             : GF_EXPORT
     212         942 : GF_ProtoFieldInterface *gf_sg_proto_field_new(GF_Proto *proto, u32 fieldType, u32 eventType, char *fieldName)
     213             : {
     214             :         GF_ProtoFieldInterface *tmp;
     215             : 
     216         942 :         if (fieldName) {
     217         942 :                 tmp = gf_sg_proto_field_find_by_name(proto, fieldName);
     218         942 :                 if (tmp) return NULL;
     219             :         }
     220         942 :         GF_SAFEALLOC(tmp, GF_ProtoFieldInterface)
     221         942 :         if (!tmp) return NULL;
     222             : 
     223         942 :         tmp->FieldType = fieldType;
     224         942 :         tmp->EventType = eventType;
     225             : 
     226             :         /*create container - can be NULL if SF node*/
     227         942 :         if ( fieldType == GF_SG_VRML_SFNODE) {
     228          97 :                 tmp->def_sfnode_value = NULL;
     229          97 :                 tmp->def_value = &tmp->def_sfnode_value;
     230         845 :         } else if ( fieldType == GF_SG_VRML_MFNODE) {
     231          15 :                 tmp->def_mfnode_value = NULL;
     232          15 :                 tmp->def_value = &tmp->def_mfnode_value;
     233             :         } else {
     234         830 :                 tmp->def_value = gf_sg_vrml_field_pointer_new(fieldType);
     235             :         }
     236             : 
     237         942 :         if (fieldName) tmp->FieldName = gf_strdup(fieldName);
     238             : 
     239         942 :         tmp->ALL_index = gf_list_count(proto->proto_fields);
     240         942 :         tmp->OUT_index = tmp->DEF_index = tmp->IN_index = (u32) -1;
     241             : 
     242         942 :         switch (eventType) {
     243         868 :         case GF_SG_EVENT_EXPOSED_FIELD:
     244         868 :                 tmp->IN_index = proto->NumIn;
     245         868 :                 proto->NumIn ++;
     246         868 :                 tmp->OUT_index = proto->NumOut;
     247         868 :                 proto->NumOut ++;
     248         870 :         case GF_SG_EVENT_FIELD:
     249         870 :                 tmp->DEF_index = proto->NumDef;
     250         870 :                 proto->NumDef ++;
     251         870 :                 break;
     252          63 :         case GF_SG_EVENT_IN:
     253          63 :                 tmp->IN_index = proto->NumIn;
     254          63 :                 proto->NumIn ++;
     255          63 :                 break;
     256           9 :         case GF_SG_EVENT_OUT:
     257           9 :                 tmp->OUT_index = proto->NumOut;
     258           9 :                 proto->NumOut ++;
     259           9 :                 break;
     260             :         }
     261             : 
     262         942 :         gf_list_add(proto->proto_fields, tmp);
     263         942 :         return tmp;
     264             : }
     265             : 
     266             : #if 0 //unused
     267             : void gf_sg_proto_field_set_private(GF_ProtoFieldInterface *field, void *ptr, void (*OnDelete)(void *ptr))
     268             : {
     269             :         if (field) {
     270             :                 field->userpriv = ptr;
     271             :                 field->OnDelete = OnDelete;
     272             :         }
     273             : }
     274             : 
     275             : void *gf_sg_proto_field_get_private(GF_ProtoFieldInterface *field)
     276             : {
     277             :         return field ? field->userpriv : NULL;
     278             : }
     279             : #endif
     280             : 
     281             : GF_EXPORT
     282        1981 : GF_Err gf_sg_proto_field_get_field(GF_ProtoFieldInterface *field, GF_FieldInfo *info)
     283             : {
     284        1981 :         if (!field || !info) return GF_BAD_PARAM;
     285             :         memset(info, 0, sizeof(GF_FieldInfo));
     286        1981 :         info->fieldIndex = field->ALL_index;
     287        1981 :         info->fieldType = field->FieldType;
     288        1981 :         info->eventType = field->EventType;
     289        1981 :         info->far_ptr = field->def_value;
     290        1981 :         info->name = field->FieldName;
     291        1981 :         info->NDTtype = NDT_SFWorldNode;
     292        1981 :         return GF_OK;
     293             : }
     294             : 
     295       46686 : GF_Err gf_sg_proto_get_field(GF_Proto *proto, GF_Node *node, GF_FieldInfo *info)
     296             : {
     297             :         GF_ProtoFieldInterface *proto_field;
     298             :         GF_ProtoInstance *inst;
     299             :         GF_ProtoField *field;
     300             : 
     301       46686 :         if (!proto && !node) return GF_BAD_PARAM;
     302             : 
     303       46686 :         if (proto) {
     304         651 :                 proto_field = (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, info->fieldIndex);
     305         651 :                 if (!proto_field) return GF_BAD_PARAM;
     306             : 
     307         651 :                 info->fieldType = proto_field->FieldType;
     308         651 :                 info->eventType = proto_field->EventType;
     309         651 :                 info->fieldIndex = proto_field->ALL_index;
     310         651 :                 info->NDTtype = NDT_SFWorldNode;
     311         651 :                 info->far_ptr = proto_field->def_value;
     312         651 :                 info->name = proto_field->FieldName;
     313         651 :                 return GF_OK;
     314             :         }
     315             : 
     316             :         /*otherwise this is an instantiated proto*/
     317       46035 :         if (node->sgprivate->tag!=TAG_ProtoNode) return GF_BAD_PARAM;
     318             : 
     319             :         inst = (GF_ProtoInstance *) node;
     320       46035 :         field = (GF_ProtoField*)gf_list_get(inst->fields, info->fieldIndex);
     321       46035 :         if (!field) return GF_BAD_PARAM;
     322             : 
     323       46035 :         info->fieldType = field->FieldType;
     324       46035 :         info->eventType = field->EventType;
     325       46035 :         info->on_event_in = field->on_event_in;
     326             :         /*SF/MF nodes need pointers to field object - cf gf_sg_proto_create_node*/
     327       46035 :         if (gf_sg_vrml_get_sf_type(field->FieldType) == GF_SG_VRML_SFNODE) {
     328        4469 :                 info->far_ptr = &field->field_pointer;
     329             :         } else {
     330       41566 :                 info->far_ptr = field->field_pointer;
     331             :         }
     332             :         /*set the name - watchout for deletion case*/
     333       46035 :         if (inst->proto_interface) {
     334       45978 :                 proto_field = (GF_ProtoFieldInterface*)gf_list_get(inst->proto_interface->proto_fields, info->fieldIndex);
     335       45978 :                 info->name = proto_field->FieldName;
     336             :         } else {
     337          57 :                 info->name = "ProtoFieldDeleted";
     338             :         }
     339       46035 :         info->NDTtype = NDT_SFWorldNode;
     340       46035 :         return GF_OK;
     341             : }
     342             : 
     343       24847 : s32 gf_sg_proto_get_field_index_by_name(GF_Proto *proto, GF_Node *node, char *name)
     344             : {
     345             :         u32 i;
     346             :         GF_Proto *__proto=NULL;
     347             : 
     348       24847 :         if (!node && !proto) return -1;
     349       24847 :         if (node && (node->sgprivate->tag!=TAG_ProtoNode)) return -1;
     350             : 
     351       24847 :         if (proto)
     352             :                 __proto = proto;
     353       24847 :         else if (node)
     354       24847 :                 __proto = ((GF_ProtoInstance *) node)->proto_interface;
     355             : 
     356       24847 :         if (!__proto ) return -1;
     357             : 
     358      150341 :         for (i=0; i<gf_list_count(__proto->proto_fields); i++) {
     359      174966 :                 GF_ProtoFieldInterface *proto_field = (GF_ProtoFieldInterface*)gf_list_get(__proto->proto_fields, i);
     360      174966 :                 if (proto_field->FieldName && !strcmp(proto_field->FieldName, name)) return i;
     361             :         }
     362             :         return -1;
     363             : }
     364             : 
     365             : 
     366       13514 : GF_Node *gf_vrml_node_clone(GF_SceneGraph *inScene, GF_Node *orig, GF_Node *cloned_parent, char *inst_id_suffix)
     367             : {
     368             :         u32 i, count, id;
     369             :         char *szNodeName;
     370             :         Bool is_script;
     371             :         GF_Node *node, *child;
     372             :         GF_ChildNodeItem *list, *last;
     373             :         GF_Route *r1;
     374             : #ifndef GPAC_DISABLE_BIFS
     375             :         void BIFS_SetupConditionalClone(GF_Node *node, GF_Node *orig);
     376             : #endif
     377             :         GF_ProtoInstance *proto;
     378             :         GF_FieldInfo field_orig, field;
     379             : 
     380             :         /*this is not a mistake*/
     381       13514 :         if (!orig) return NULL;
     382             : 
     383             :         /*check for DEF/USE*/
     384             :         szNodeName = NULL;
     385       13514 :         if (!inst_id_suffix) id = 0;
     386             :         else {
     387       13514 :                 const char *orig_name = gf_node_get_name_and_id(orig, &id);
     388             :                 /*generate clone IDs based on original one*/
     389       13514 :                 if (inst_id_suffix[0] && id) {
     390           0 :                         id = gf_sg_get_next_available_node_id(inScene);
     391           0 :                         if (orig_name) {
     392           0 :                                 szNodeName = gf_malloc(sizeof(char)*(strlen(orig_name)+strlen(inst_id_suffix)+1));
     393             :                                 strcpy(szNodeName, orig_name);
     394             :                                 strcat(szNodeName, inst_id_suffix);
     395             :                         }
     396             :                 }
     397       13514 :                 else if (orig_name) szNodeName = gf_strdup(orig_name);
     398             :         }
     399             : 
     400       13514 :         if (id) {
     401        5717 :                 node = szNodeName ? gf_sg_find_node_by_name(inScene, szNodeName) : gf_sg_find_node(inScene, id);
     402             :                 /*node already created, USE*/
     403        5717 :                 if (node) {
     404        1430 :                         gf_node_register(node, cloned_parent);
     405        1430 :                         if (szNodeName) gf_free(szNodeName);
     406             :                         return node;
     407             :                 }
     408             :         }
     409             :         /*create a node*/
     410       12084 :         if (orig->sgprivate->tag == TAG_ProtoNode) {
     411         366 :                 GF_Proto *proto_node = ((GF_ProtoInstance *)orig)->proto_interface;
     412             :                 /*create the instance but don't load the code -c we MUST wait for ISed routes to be cloned before*/
     413         366 :                 node = gf_sg_proto_create_node(inScene, proto_node, (GF_ProtoInstance *) orig);
     414             :         } else {
     415       11718 :                 node = gf_node_new(inScene, orig->sgprivate->tag);
     416             :         }
     417             : 
     418       12084 :         count = gf_node_get_field_count(orig);
     419             : 
     420             :         is_script = 0;
     421       12084 :         if (orig->sgprivate->tag==TAG_MPEG4_Script) is_script = 1;
     422             : #ifndef GPAC_DISABLE_X3D
     423       11719 :         else if (orig->sgprivate->tag==TAG_X3D_Script) is_script = 1;
     424             : #endif
     425             : 
     426         365 :         if (is_script) gf_sg_script_prepare_clone(node, orig);
     427             : 
     428             : 
     429             :         /*register node*/
     430       12084 :         if (id) {
     431        4287 :                 gf_node_set_id(node, id, szNodeName);
     432        4287 :                 if (szNodeName) gf_free(szNodeName);
     433             :         }
     434       12084 :         gf_node_register(node, cloned_parent);
     435             : 
     436             :         /*copy each field*/
     437      118879 :         for (i=0; i<count; i++) {
     438      106795 :                 gf_node_get_field(orig, i, &field_orig);
     439             : 
     440             :                 /*get target ptr*/
     441      106795 :                 gf_node_get_field(node, i, &field);
     442             : 
     443             :                 assert(field.eventType==field_orig.eventType);
     444             :                 assert(field.fieldType==field_orig.fieldType);
     445             : 
     446             :                 /*duplicate it*/
     447      106795 :                 switch (field.fieldType) {
     448       10113 :                 case GF_SG_VRML_SFNODE:
     449       10113 :                         child = gf_node_clone(inScene, (* ((GF_Node **) field_orig.far_ptr)), node, inst_id_suffix, 1);
     450       10113 :                         *((GF_Node **) field.far_ptr) = child;
     451       10113 :                         break;
     452        5567 :                 case GF_SG_VRML_MFNODE:
     453        5567 :                         last = NULL;
     454        5567 :                         list = *( (GF_ChildNodeItem **) field_orig.far_ptr);
     455       16550 :                         while (list) {
     456        5416 :                                 child = gf_node_clone(inScene, list->node, node, inst_id_suffix, 1);
     457        5416 :                                 gf_node_list_add_child_last((GF_ChildNodeItem **) field.far_ptr, child, &last);
     458        5416 :                                 list = list->next;
     459             :                         }
     460             :                         break;
     461        5023 :                 case GF_SG_VRML_SFTIME:
     462        5023 :                         gf_sg_vrml_field_copy(field.far_ptr, field_orig.far_ptr, field.fieldType);
     463        5023 :                         if (!inScene->GetSceneTime) break;
     464             :                         /*update SFTime that must be updated when cloning the node*/
     465        5023 :                         if (orig->sgprivate->tag == TAG_ProtoNode) {
     466           0 :                                 if (gf_sg_proto_field_is_sftime_offset(orig, &field_orig))
     467           0 :                                         *((SFTime *)field.far_ptr) += inScene->GetSceneTime(inScene->userpriv);
     468        5023 :                         } else if (!stricmp(field.name, "startTime") || !stricmp(field_orig.name, "startTime") ) {
     469         379 :                                 *((SFTime *)field.far_ptr) += inScene->GetSceneTime(inScene->userpriv);
     470             :                         }
     471             :                         break;
     472       86092 :                 default:
     473       86092 :                         gf_sg_vrml_field_clone(field.far_ptr, field_orig.far_ptr, field.fieldType, inScene);
     474       86092 :                         break;
     475             :                 }
     476           0 :         }
     477             : 
     478             : #ifndef GPAC_DISABLE_BIFS
     479             :         /*init node before creating ISed routes so the eventIn handler are in place*/
     480       12084 :         if (node->sgprivate->tag == TAG_MPEG4_Conditional)
     481          39 :                 BIFS_SetupConditionalClone(node, orig);
     482             :         else
     483             : #endif
     484       12045 :                 if (node->sgprivate->tag != TAG_ProtoNode) gf_node_init(node);
     485             : 
     486       12084 :         if (!inScene->pOwningProto) return node;
     487             :         proto = inScene->pOwningProto;
     488             : 
     489             :         /*create Routes for ISed fields*/
     490       11903 :         i=0;
     491      213797 :         while ((r1 = (GF_Route*)gf_list_enum(proto->proto_interface->sub_graph->Routes, &i))) {
     492             :                 GF_Route *r2 = NULL;
     493             :                 /*locate only ISed routes*/
     494      189991 :                 if (!r1->IS_route) continue;
     495             : 
     496             :                 /*eventOut*/
     497      142901 :                 if (r1->FromNode == orig) {
     498        4248 :                         r2 = gf_sg_route_new(inScene, node, r1->FromField.fieldIndex, (GF_Node *) proto, r1->ToField.fieldIndex);
     499        4248 :                         r2->IS_route = 1;
     500             :                 }
     501             :                 /*eventIn or exposedField*/
     502      138653 :                 else if (r1->ToNode == orig) {
     503        4258 :                         r2 = gf_sg_route_new(inScene, (GF_Node *) proto, r1->FromField.fieldIndex, node, r1->ToField.fieldIndex);
     504        4258 :                         r2->IS_route = 1;
     505             : 
     506             :                         /*activate the route now so that proto instanciation works properly, otherwise we may load scripts with wrong field values
     507             :                         Note: we don't activate eventOut routes upon instanciation since no event has been triggered yet*/
     508        4258 :                         gf_sg_route_activate(r2);
     509             :                 }
     510             :         }
     511             : 
     512             :         /*remember scripts*/
     513       11903 :         if (is_script) gf_list_add(proto->scripts_to_load, node);
     514             : 
     515             :         /*this is a proto node, init our internal stuff*/
     516       11903 :         if (node->sgprivate->tag == TAG_ProtoNode) {
     517         366 :                 node->sgprivate->UserCallback = NULL;
     518         366 :                 node->sgprivate->UserPrivate = NULL;
     519             :                 /*NO RENDER, this is filtered at the generic gf_node_traverse to cope with instanciations and externProto*/
     520             :                 /*load code*/
     521         366 :                 gf_sg_proto_instantiate((GF_ProtoInstance *)node);
     522             :         }
     523             :         return node;
     524             : }
     525             : 
     526        2651 : GF_Err gf_sg_proto_get_field_ind_static(GF_Node *Node, u32 inField, u8 IndexMode, u32 *allField)
     527             : {
     528        2651 :         return gf_sg_proto_get_field_index((GF_ProtoInstance *)Node, inField, IndexMode, allField);
     529             : }
     530             : 
     531             : 
     532          12 : static Bool is_same_proto(GF_Proto *extern_proto, GF_Proto *proto)
     533             : {
     534             :         u32 i, count;
     535             :         /*VRML allows external protos to have more fields defined that the externProto referencing them*/
     536          12 :         if (gf_list_count(extern_proto->proto_fields) > gf_list_count(proto->proto_fields)) return 0;
     537          12 :         count = gf_list_count(extern_proto->proto_fields);
     538          84 :         for (i=0; i<count; i++) {
     539          84 :                 GF_ProtoFieldInterface *pf1 = (GF_ProtoFieldInterface*)gf_list_get(extern_proto->proto_fields, i);
     540          84 :                 GF_ProtoFieldInterface *pf2 = (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, i);
     541          84 :                 if (pf1->EventType != pf2->EventType) return 0;
     542          84 :                 if (pf1->FieldType != pf2->FieldType) return 0;
     543             :                 /*note we don't check names since we're not sure both protos use name coding (MPEG4 only)*/
     544             :         }
     545             :         return 1;
     546             : }
     547             : 
     548           6 : static GF_Proto *find_proto_by_interface(GF_SceneGraph *sg, GF_Proto *extern_proto)
     549             : {
     550             :         GF_Proto *proto;
     551             :         u32 i, count;
     552             : 
     553             :         assert(sg);
     554             : 
     555             :         /*browse all top-level */
     556           6 :         i=0;
     557           6 :         while ((proto = (GF_Proto*)gf_list_enum(sg->protos, &i))) {
     558           6 :                 if (is_same_proto(proto, extern_proto)) return proto;
     559             :         }
     560             :         /*browse all top-level unregistered in reverse order*/
     561           0 :         count = gf_list_count(sg->unregistered_protos);
     562           0 :         for (i=count; i>0; i--) {
     563           0 :                 proto = (GF_Proto*)gf_list_get(sg->unregistered_protos, i-1);
     564           0 :                 if (is_same_proto(proto, extern_proto)) return proto;
     565             :         }
     566             :         return NULL;
     567             : }
     568             : 
     569             : /*performs common initialization of routes ISed fields and protos once everything is loaded*/
     570        1098 : void gf_sg_proto_instantiate(GF_ProtoInstance *proto_node)
     571             : {
     572             :         GF_Node *node, *orig;
     573             :         GF_Route *route, *r2;
     574             :         u32 i, count;
     575        1098 :         GF_Proto *proto = proto_node->proto_interface;
     576             :         GF_Proto *owner = proto;
     577             : 
     578        1372 :         if (!proto) return;
     579             : 
     580        1098 :         if (owner->ExternProto.count) {
     581             :                 GF_ProtoFieldInterface *pfi;
     582             :                 GF_SceneGraph *extern_lib;
     583         280 :                 if (!owner->parent_graph->GetExternProtoLib) return;
     584         280 :                 extern_lib = owner->parent_graph->GetExternProtoLib(proto->parent_graph->userpriv, &owner->ExternProto);
     585         280 :                 if (!extern_lib) return;
     586             : 
     587             :                 /*this is an hardcoded proto - all routes, node modifications and co are handled internally*/
     588         100 :                 if (PTR_TO_U_CAST extern_lib == GF_SG_INTERNAL_PROTO) {
     589          87 :                         proto_node->sgprivate->flags |= GF_SG_NODE_DIRTY;
     590             :                         // take default values
     591          87 :                         count = gf_list_count(owner->proto_fields);
     592         279 :                         for (i=0; i<count; i++) {
     593         192 :                                 GF_ProtoField *pf = (GF_ProtoField *)gf_list_get(proto_node->fields, i);
     594         192 :                                 if (!pf->has_been_accessed) {
     595         167 :                                         pfi = (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, i);
     596         167 :                                         gf_sg_vrml_field_copy(pf->field_pointer, pfi->def_value, pfi->FieldType);
     597             :                                 }
     598             :                         }
     599          87 :                         owner->parent_graph->NodeCallback(owner->parent_graph->userpriv, GF_SG_CALLBACK_INIT, (GF_Node *) proto_node, NULL);
     600          87 :                         proto_node->flags |= GF_SG_PROTO_LOADED | GF_SG_PROTO_HARDCODED;
     601          87 :                         return;
     602             :                 }
     603             :                 /*not loaded yet*/
     604          13 :                 if (!gf_list_count(extern_lib->protos)) return;
     605             : 
     606             :                 /*overwrite this proto by external one*/
     607             :                 proto = NULL;
     608             :                 /*start with proto v2 addressing*/
     609           6 :                 if (owner->ExternProto.vals[0].url) {
     610           0 :                         u32 ID = (u32) -1;
     611           0 :                         char *szName = strrchr(owner->ExternProto.vals[0].url, '#');
     612           0 :                         if (szName) {
     613           0 :                                 szName++;
     614           0 :                                 if (sscanf(szName, "%u", &ID)) ID = (u32) -1;
     615             :                         }
     616             :                         /*if we have the proto name, use it*/
     617           0 :                         if (owner->Name) szName = owner->Name;
     618           0 :                         proto = gf_sg_find_proto(extern_lib, ID, szName);
     619             :                 }
     620           0 :                 if (!proto) proto = gf_sg_find_proto(extern_lib, owner->ID, owner->Name);
     621           6 :                 if (!proto) proto = find_proto_by_interface(extern_lib, owner);
     622             : 
     623           6 :                 if (proto && !is_same_proto(owner, proto)) {
     624             :                         proto = NULL;
     625           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[Scenegraph] fields/types mismatch for PROTO %s - skipping instantiation\n", owner->Name));
     626             :                 }
     627             :                 /*couldn't find proto in the given lib, consider the proto as loaded (give up)*/
     628           6 :                 if (!proto) {
     629           0 :                         proto_node->flags |= GF_SG_PROTO_LOADED;
     630           0 :                         return;
     631             :                 }
     632             :                 /*cf VRML: once an external proto is loaded, copy back the default field values of the external proto*/
     633           6 :                 count = gf_list_count(owner->proto_fields);
     634          48 :                 for (i=0; i<count; i++) {
     635          42 :                         GF_ProtoField *pf = (GF_ProtoField *)gf_list_get(proto_node->fields, i);
     636          42 :                         if (!pf->has_been_accessed) {
     637          18 :                                 pfi = (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, i);
     638          18 :                                 gf_sg_vrml_field_copy(pf->field_pointer, pfi->def_value, pfi->FieldType);
     639             :                         } else {
     640             :                                 //pfi = (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, i);
     641             :                         }
     642             :                 }
     643             : 
     644             :                 /*unregister from prev and reg with real proto*/
     645           6 :                 gf_list_del_item(owner->instances, proto_node);
     646           6 :                 gf_list_add(proto->instances, proto_node);
     647             :         }
     648             : 
     649             :         /*OVERRIDE the proto instance (eg don't instantiate an empty externproto...)*/
     650         824 :         proto_node->proto_interface = proto;
     651             : 
     652             :         /*clone all nodes*/
     653         824 :         i=0;
     654        3266 :         while ((orig = (GF_Node*)gf_list_enum(proto->node_code, &i))) {
     655             :                 /*node is cloned in the new scenegraph and its parent is NULL */
     656        1618 :                 node = gf_node_clone(proto_node->sgprivate->scenegraph, orig, NULL, "", 1);
     657             :                 assert(node);
     658             : 
     659             :                 /*assign first rendering node*/
     660        1618 :                 if (i==1) proto_node->RenderingNode = node;
     661        1618 :                 gf_list_add(proto_node->node_code, node);
     662             :         }
     663             : 
     664             :         /*instantiate routes (not ISed ones)*/
     665         824 :         i=0;
     666       13570 :         while ((route = (GF_Route*)gf_list_enum(proto->sub_graph->Routes, &i))) {
     667       11922 :                 if (route->IS_route) continue;
     668             : 
     669       10248 :                 r2 = gf_sg_route_new(proto_node->sgprivate->scenegraph,
     670        3416 :                                      gf_sg_find_node(proto_node->sgprivate->scenegraph, gf_node_get_id(route->FromNode) ),
     671             :                                      route->FromField.fieldIndex,
     672        3416 :                                      gf_sg_find_node(proto_node->sgprivate->scenegraph, gf_node_get_id(route->ToNode) ),
     673             :                                      route->ToField.fieldIndex);
     674             : 
     675        3416 :                 if (route->ID) gf_sg_route_set_id(r2, route->ID);
     676        3416 :                 if (route->name) gf_sg_route_set_name(r2, route->name);
     677             :         }
     678             :         /*activate all ISed fields so that inits on events is properly done*/
     679         824 :         i=0;
     680       13570 :         while ((route = (GF_Route*)gf_list_enum(proto_node->sgprivate->scenegraph->Routes, &i))) {
     681       11922 :                 if (!route->IS_route) continue;
     682             :                 /*do not activate eventIn to eventIn routes*/
     683        8506 :                 if (route->is_setup) {
     684        4258 :                         if ((route->ToField.eventType == GF_SG_EVENT_IN) && (route->FromField.eventType == GF_SG_EVENT_IN) ) continue;
     685             :                 }
     686        8478 :                 gf_sg_route_activate(route);
     687             :         }
     688             :         /*and load all scripts (this must be done once all fields are routed for the "initialize" method)*/
     689        1189 :         while (gf_list_count(proto_node->scripts_to_load)) {
     690         365 :                 node = (GF_Node*)gf_list_get(proto_node->scripts_to_load, 0);
     691         365 :                 gf_list_rem(proto_node->scripts_to_load, 0);
     692         365 :                 gf_sg_script_load(node);
     693             :         }
     694             :         /*re-activate all ISed fields pointing to scripts once scripts are loaded (eventIns)*/
     695         824 :         i=0;
     696       13570 :         while ((route = (GF_Route*)gf_list_enum(proto_node->sgprivate->scenegraph->Routes, &i))) {
     697       11922 :                 if (!route->IS_route || !route->ToNode) continue;
     698             :                 /*              assert(route->is_setup);
     699             :                                 if ((route->FromField.eventType == GF_SG_EVENT_OUT) || (route->FromField.eventType == GF_SG_EVENT_IN) ) continue;
     700             :                 */
     701             : 
     702        8506 :                 if (route->is_setup) {
     703        8506 :                         if ((route->ToField.eventType == GF_SG_EVENT_IN) && (route->FromField.eventType == GF_SG_EVENT_IN) ) continue;
     704             :                 }
     705             : 
     706        8478 :                 if (route->ToNode->sgprivate->tag==TAG_MPEG4_Script)
     707           0 :                         gf_sg_route_activate(route);
     708             : #ifndef GPAC_DISABLE_X3D
     709        8478 :                 else if (route->ToNode->sgprivate->tag==TAG_X3D_Script)
     710           0 :                         gf_sg_route_activate(route);
     711             : #endif
     712             :         }
     713             : 
     714             : #if 0
     715             :         /*reset all regular route activation times - if we don't do so, creating a proto by script and then manipulating one of its
     716             :         ISed field may not trigger the proper routes*/
     717             :         i=0;
     718             :         while ((route = (GF_Route*)gf_list_enum(proto_node->sgprivate->scenegraph->Routes, &i))) {
     719             :                 if (!route->IS_route) {
     720             :                         route->lastActivateTime = 0;
     721             :                 }
     722             :         }
     723             : #endif
     724         824 :         proto_node->flags |= GF_SG_PROTO_LOADED;
     725             : }
     726             : 
     727       18637 : void gf_sg_proto_mark_field_loaded(GF_Node *proto_inst, GF_FieldInfo *info)
     728             : {
     729       18637 :         GF_ProtoInstance *inst= (proto_inst->sgprivate->tag==TAG_ProtoNode) ? (GF_ProtoInstance *)proto_inst : NULL;
     730       18637 :         GF_ProtoField *pf = inst ? (GF_ProtoField *)gf_list_get(inst->fields, info->fieldIndex) : NULL;
     731       18637 :         if (pf) pf->has_been_accessed = 1;
     732       18637 : }
     733             : 
     734        1959 : GF_Node *gf_sg_proto_create_node(GF_SceneGraph *scene, GF_Proto *proto, GF_ProtoInstance *from_inst)
     735             : {
     736             :         u32 i;
     737             :         GF_ProtoField *inst, *from_field;
     738             :         GF_ProtoFieldInterface *field;
     739             :         GF_ProtoInstance *proto_node;
     740        1959 :         if (!proto) return NULL;
     741             :         
     742        1959 :         GF_SAFEALLOC(proto_node, GF_ProtoInstance)
     743        1959 :         if (!proto_node) return NULL;
     744             : 
     745        1959 :         gf_node_setup((GF_Node *)proto_node, TAG_ProtoNode);
     746        1959 :         proto_node->node_code = gf_list_new();
     747        1959 :         proto_node->fields = gf_list_new();
     748        1959 :         proto_node->scripts_to_load = gf_list_new();
     749             : 
     750        1959 :         proto_node->proto_interface = proto;
     751        1959 :         gf_list_add(proto->instances, proto_node);
     752             : 
     753        1959 :         proto_node->proto_name = gf_strdup(proto->Name);
     754             : 
     755             :         /*create the namespace*/
     756        1959 :         proto_node->sgprivate->scenegraph = gf_sg_new_subscene(scene);
     757             :         /*set this proto as owner of the new graph*/
     758        1959 :         proto_node->sgprivate->scenegraph->pOwningProto = proto_node;
     759             : 
     760             :         /*instantiate fields*/
     761        1959 :         i=0;
     762       15314 :         while ((field = (GF_ProtoFieldInterface*)gf_list_enum(proto->proto_fields, &i))) {
     763       11396 :                 GF_SAFEALLOC(inst, GF_ProtoField);
     764       11396 :                 if (!inst) {
     765           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[VRML] Failed to allocate proto instance field\n]"));
     766           0 :                         continue;
     767             :                 }
     768             :                 
     769       11396 :                 inst->EventType = field->EventType;
     770       11396 :                 inst->FieldType = field->FieldType;
     771             : 
     772             :                 /*this is OK to call on GF_Node (returns NULL) and MFNode (returns gf_list_new() )*/
     773       11396 :                 inst->field_pointer = gf_sg_vrml_field_pointer_new(inst->FieldType);
     774             : 
     775             :                 /*regular field, duplicate from default value or instantiated one if specified (since
     776             :                 a proto may be partially instantiated when used in another proto)*/
     777       11396 :                 if (gf_sg_vrml_get_sf_type(inst->FieldType) != GF_SG_VRML_SFNODE) {
     778       10242 :                         if (from_inst) {
     779         387 :                                 from_field = (GF_ProtoField *)gf_list_get(from_inst->fields, i-1);
     780         387 :                                 gf_sg_vrml_field_copy(inst->field_pointer, from_field->field_pointer, inst->FieldType);
     781         387 :                                 inst->has_been_accessed = from_field->has_been_accessed;
     782             :                         } else {
     783        9855 :                                 gf_sg_vrml_field_copy(inst->field_pointer, field->def_value, inst->FieldType);
     784             :                         }
     785             :                 }
     786             :                 /*No default values for SFNodes as interfaces ...*/
     787       11396 :                 gf_list_add(proto_node->fields, inst);
     788             :         }
     789             :         return (GF_Node *) proto_node;
     790             : }
     791             : 
     792             : 
     793             : GF_EXPORT
     794        1569 : GF_Node *gf_sg_proto_create_instance(GF_SceneGraph *sg, GF_Proto *proto)
     795             : {
     796        1569 :         return gf_sg_proto_create_node(sg, proto, NULL);
     797             : }
     798             : 
     799             : GF_EXPORT
     800         541 : GF_Err gf_sg_proto_load_code(GF_Node *node)
     801             : {
     802             :         GF_ProtoInstance *inst;
     803         541 :         if (node->sgprivate->tag != TAG_ProtoNode) return GF_BAD_PARAM;
     804             :         inst = (GF_ProtoInstance *) node;
     805         541 :         if (!inst->proto_interface) return GF_BAD_PARAM;
     806         541 :         if (inst->flags & GF_SG_PROTO_LOADED) return GF_OK;
     807         541 :         gf_sg_proto_instantiate(inst);
     808         541 :         return GF_OK;
     809             : }
     810             : 
     811             : 
     812        2264 : u32 gf_sg_proto_get_num_fields(GF_Node *node, u8 code_mode)
     813             : {
     814             :         GF_ProtoInstance *proto;
     815        2264 :         if (!node) return 0;
     816             : 
     817             :         proto = (GF_ProtoInstance *)node;
     818             :         /*watchout for deletion case*/
     819        2264 :         switch (code_mode) {
     820         153 :         case GF_SG_FIELD_CODING_IN:
     821         153 :                 return proto->proto_interface ? proto->proto_interface->NumIn : 0;
     822           0 :         case GF_SG_FIELD_CODING_OUT:
     823           0 :                 return proto->proto_interface ? proto->proto_interface->NumOut : 0;
     824         989 :         case GF_SG_FIELD_CODING_DEF:
     825         989 :                 return proto->proto_interface ? proto->proto_interface->NumDef : 0;
     826        1122 :         case GF_SG_FIELD_CODING_ALL:
     827        1122 :                 return gf_list_count(proto->proto_interface ? proto->proto_interface->proto_fields : proto->fields);
     828             :         /*BIFS-ANIM not supported*/
     829             :         case GF_SG_FIELD_CODING_DYN:
     830             :         default:
     831             :                 return 0;
     832             :         }
     833             : }
     834             : 
     835             : 
     836        1959 : void gf_sg_proto_del_instance(GF_ProtoInstance *inst)
     837             : {
     838             :         GF_SceneGraph *sg;
     839             : 
     840       15314 :         while (gf_list_count(inst->fields)) {
     841       11396 :                 GF_ProtoField *field = (GF_ProtoField *)gf_list_get(inst->fields, 0);
     842       11396 :                 gf_list_rem(inst->fields, 0);
     843             : 
     844             :                 /*regular type*/
     845       11396 :                 if ( (field->FieldType!=GF_SG_VRML_SFNODE) && (field->FieldType!=GF_SG_VRML_MFNODE)) {
     846       10242 :                         gf_sg_vrml_field_pointer_del(field->field_pointer, field->FieldType);
     847             :                 }
     848             :                 /*node types: delete instances*/
     849        1154 :                 else if (field->field_pointer) {
     850         495 :                         if (field->FieldType == GF_SG_VRML_SFNODE) {
     851         422 :                                 gf_node_unregister((GF_Node *) field->field_pointer, (GF_Node *) inst);
     852             :                         } else {
     853             :                                 GF_ChildNodeItem *list = (GF_ChildNodeItem *)field->field_pointer;
     854         146 :                                 while (list) {
     855             :                                         GF_ChildNodeItem *cur = list;
     856          73 :                                         gf_node_unregister(list->node, (GF_Node *) inst);
     857          73 :                                         list = list->next;
     858          73 :                                         gf_free(cur);
     859             :                                 }
     860             :                         }
     861             :                 }
     862             : 
     863       11396 :                 gf_free(field);
     864             :         }
     865        1959 :         gf_list_del(inst->fields);
     866             : 
     867             :         /*destroy the code*/
     868        5536 :         while (gf_list_count(inst->node_code)) {
     869        1618 :                 GF_Node *node = (GF_Node*)gf_list_get(inst->node_code, 0);
     870        1618 :                 gf_node_unregister(node, (GF_Node*) inst);
     871        1618 :                 gf_list_rem(inst->node_code, 0);
     872             :         }
     873             : 
     874        1959 :         sg = inst->sgprivate->scenegraph;
     875             : 
     876             :         /*reset the scene graph before destroying the node code list, as unregistering nodes
     877             :         not destroyed in the previous phase (eg, cyclic references such as script and co) will
     878             :         refer to the node-code list*/
     879        1959 :         gf_sg_reset(sg);
     880        1959 :         sg->pOwningProto = NULL;
     881             : 
     882        1959 :         gf_free((char *) inst->proto_name);
     883        1959 :         gf_list_del(inst->node_code);
     884             :         assert(!gf_list_count(inst->scripts_to_load));
     885        1959 :         gf_list_del(inst->scripts_to_load);
     886             : 
     887        1959 :         if (inst->proto_interface && inst->proto_interface->instances) gf_list_del_item(inst->proto_interface->instances, inst);
     888             : 
     889        1959 :         gf_node_free((GF_Node *)inst);
     890        1959 :         gf_sg_del(sg);
     891        1959 : }
     892             : 
     893             : /*Note on ISed fields: we cannot support fan-in on proto, eg we assume only one eventIn field can receive events
     894             : thus situations where a proto receives eventIn from outside and the node with ISed eventIn receives event
     895             : from inside the proto are undefined*/
     896             : GF_EXPORT
     897         552 : GF_Err gf_sg_proto_field_set_ised(GF_Proto *proto, u32 protoFieldIndex, GF_Node *node, u32 nodeFieldIndex)
     898             : {
     899             :         GF_Err e;
     900             :         GF_Route *r;
     901             :         GF_FieldInfo field, nodeField;
     902         552 :         field.fieldIndex = protoFieldIndex;
     903         552 :         e = gf_sg_proto_get_field(proto, NULL, &field);
     904         552 :         if (e) return e;
     905         552 :         e = gf_node_get_field(node, nodeFieldIndex, &nodeField);
     906         552 :         if (e) return e;
     907         552 :         if (field.fieldType != nodeField.fieldType) {
     908           5 :                 if ((gf_sg_vrml_get_sf_type(field.fieldType)==GF_SG_VRML_SFSTRING) && (gf_sg_vrml_get_sf_type(nodeField.fieldType) == GF_SG_VRML_SFURL)) {
     909             : //                      e = GF_OK;
     910           0 :                 } else if ((gf_sg_vrml_get_sf_type(field.fieldType)==GF_SG_VRML_SFURL) && (gf_sg_vrml_get_sf_type(nodeField.fieldType) == GF_SG_VRML_SFSTRING)) {
     911             : //                      e = GF_OK;
     912             :                 } else {
     913           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[VRML] error in IS - node field %s.%s - inType %s - outType %s\n", gf_node_get_class_name(node) , nodeField.name, gf_sg_vrml_get_field_type_name(field.fieldType), gf_sg_vrml_get_field_type_name(nodeField.fieldType)));
     914             :                         return GF_SG_INVALID_PROTO;
     915             :                 }
     916             :         }
     917             : 
     918         552 :         GF_SAFEALLOC(r, GF_Route)
     919         552 :         if (!r) return GF_OUT_OF_MEM;
     920         552 :         r->IS_route = 1;
     921             : 
     922         552 :         if (nodeField.eventType==GF_SG_EVENT_OUT) {
     923           8 :                 r->FromField.fieldIndex = nodeFieldIndex;
     924           8 :                 r->FromNode = node;
     925           8 :                 r->ToField.fieldIndex = protoFieldIndex;
     926           8 :                 r->ToNode = NULL;
     927           8 :                 if (!node->sgprivate->interact) {
     928           8 :                         GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
     929           8 :                         if (!node->sgprivate->interact) {
     930             :                                 return GF_OUT_OF_MEM;
     931             :                         }
     932             :                 }
     933           8 :                 if (!node->sgprivate->interact->routes) node->sgprivate->interact->routes = gf_list_new();
     934           8 :                 gf_list_add(node->sgprivate->interact->routes, r);
     935             :         } else {
     936         544 :                 switch (field.eventType) {
     937         544 :                 case GF_SG_EVENT_FIELD:
     938             :                 case GF_SG_EVENT_EXPOSED_FIELD:
     939             :                 case GF_SG_EVENT_IN:
     940         544 :                         r->FromField.fieldIndex = protoFieldIndex;
     941         544 :                         r->FromNode = NULL;
     942         544 :                         r->ToField.fieldIndex = nodeFieldIndex;
     943         544 :                         r->ToNode = node;
     944             :                         /*create an ISed route for the eventOut part of the exposedFIeld*/
     945         544 :                         if ((field.eventType==GF_SG_EVENT_EXPOSED_FIELD) && (nodeField.eventType==GF_SG_EVENT_EXPOSED_FIELD)) {
     946             :                                 GF_Route *r2;
     947         478 :                                 GF_SAFEALLOC(r2, GF_Route);
     948         478 :                                 if (!r2) {
     949           0 :                                         gf_free(r);
     950           0 :                                         return GF_OUT_OF_MEM;
     951             :                                 }
     952         478 :                                 r2->IS_route = 1;
     953         478 :                                 r2->FromField.fieldIndex = nodeFieldIndex;
     954         478 :                                 r2->FromNode = node;
     955         478 :                                 r2->ToField.fieldIndex = protoFieldIndex;
     956         478 :                                 r2->ToNode = NULL;
     957         478 :                                 r2->graph =  proto->sub_graph;
     958         478 :                                 if (!node->sgprivate->interact) {
     959         268 :                                         GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
     960         268 :                                         if (!node->sgprivate->interact) return GF_OUT_OF_MEM;
     961             :                                 }
     962         478 :                                 if (!node->sgprivate->interact->routes) node->sgprivate->interact->routes = gf_list_new();
     963         478 :                                 gf_list_add(node->sgprivate->interact->routes, r2);
     964         478 :                                 gf_list_add(proto->sub_graph->Routes, r2);
     965             :                         }
     966             :                         break;
     967           0 :                 case GF_SG_EVENT_OUT:
     968           0 :                         r->FromField.fieldIndex = nodeFieldIndex;
     969           0 :                         r->FromNode = node;
     970           0 :                         r->ToField.fieldIndex = protoFieldIndex;
     971           0 :                         r->ToNode = NULL;
     972           0 :                         if (!node->sgprivate->interact) {
     973           0 :                                 GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
     974           0 :                                 if (!node->sgprivate->interact) return GF_OUT_OF_MEM;
     975             :                         }
     976           0 :                         if (!node->sgprivate->interact->routes) node->sgprivate->interact->routes = gf_list_new();
     977             :                         break;
     978           0 :                 default:
     979           0 :                         gf_free(r);
     980           0 :                         return GF_BAD_PARAM;
     981             :                 }
     982             :         }
     983         552 :         r->graph = proto->sub_graph;
     984         552 :         return gf_list_add(proto->sub_graph->Routes, r);
     985             : }
     986             : 
     987             : GF_EXPORT
     988           0 : GF_Err gf_sg_proto_instance_set_ised(GF_Node *protoinst, u32 protoFieldIndex, GF_Node *node, u32 nodeFieldIndex)
     989             : {
     990             :         GF_Err e;
     991             :         GF_Route *r;
     992             :         GF_FieldInfo field, nodeField;
     993           0 :         if (protoinst->sgprivate->tag != TAG_ProtoNode) return GF_BAD_PARAM;
     994             : 
     995           0 :         e = gf_node_get_field(protoinst, protoFieldIndex, &field);
     996           0 :         if (e) return e;
     997           0 :         e = gf_node_get_field(node, nodeFieldIndex, &nodeField);
     998           0 :         if (e) return e;
     999           0 :         if (field.fieldType != nodeField.fieldType) {
    1000           0 :                 if ((gf_sg_vrml_get_sf_type(field.fieldType)==GF_SG_VRML_SFSTRING) && (gf_sg_vrml_get_sf_type(nodeField.fieldType) == GF_SG_VRML_SFURL)) {
    1001             : //                      e = GF_OK;
    1002           0 :                 } else if ((gf_sg_vrml_get_sf_type(field.fieldType)==GF_SG_VRML_SFURL) && (gf_sg_vrml_get_sf_type(nodeField.fieldType) == GF_SG_VRML_SFSTRING)) {
    1003             : //                      e = GF_OK;
    1004             :                 } else {
    1005           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[VRML] error in IS - node field %s.%s - inType %s - outType %s\n", gf_node_get_class_name(node) , nodeField.name, gf_sg_vrml_get_field_type_name(field.fieldType), gf_sg_vrml_get_field_type_name(nodeField.fieldType)));
    1006             :                         return GF_SG_INVALID_PROTO;
    1007             :                 }
    1008             :         }
    1009             : 
    1010           0 :         GF_SAFEALLOC(r, GF_Route)
    1011           0 :         if (!r) return GF_OUT_OF_MEM;
    1012           0 :         r->IS_route = 1;
    1013             : 
    1014           0 :         if (nodeField.eventType==GF_SG_EVENT_OUT) {
    1015           0 :                 r->FromField.fieldIndex = nodeFieldIndex;
    1016           0 :                 r->FromNode = node;
    1017           0 :                 r->ToField.fieldIndex = protoFieldIndex;
    1018           0 :                 r->ToNode = protoinst;
    1019           0 :                 if (!node->sgprivate->interact) {
    1020           0 :                         GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
    1021           0 :                         if (!node->sgprivate->interact) return GF_OUT_OF_MEM;
    1022             :                 }
    1023           0 :                 if (!node->sgprivate->interact->routes) node->sgprivate->interact->routes = gf_list_new();
    1024           0 :                 gf_list_add(node->sgprivate->interact->routes, r);
    1025             :         } else {
    1026           0 :                 switch (field.eventType) {
    1027           0 :                 case GF_SG_EVENT_FIELD:
    1028             :                 case GF_SG_EVENT_EXPOSED_FIELD:
    1029             :                 case GF_SG_EVENT_IN:
    1030           0 :                         r->FromField.fieldIndex = protoFieldIndex;
    1031           0 :                         r->FromNode = protoinst;
    1032           0 :                         r->ToField.fieldIndex = nodeFieldIndex;
    1033           0 :                         r->ToNode = node;
    1034             : 
    1035             :                         /*create an ISed route for the eventOut part of the exposedFIeld*/
    1036           0 :                         if ((field.eventType==GF_SG_EVENT_EXPOSED_FIELD) && (nodeField.eventType==GF_SG_EVENT_EXPOSED_FIELD)) {
    1037             :                                 GF_Route *r2;
    1038           0 :                                 GF_SAFEALLOC(r2, GF_Route);
    1039           0 :                                 if (!r2) {
    1040           0 :                                         gf_free(r);
    1041           0 :                                         return GF_OUT_OF_MEM;
    1042             :                                 }
    1043           0 :                                 r2->IS_route = 1;
    1044           0 :                                 r2->FromField.fieldIndex = nodeFieldIndex;
    1045           0 :                                 r2->FromNode = node;
    1046           0 :                                 r2->ToField.fieldIndex = protoFieldIndex;
    1047           0 :                                 r2->ToNode = protoinst;
    1048           0 :                                 r2->graph =  node->sgprivate->scenegraph;
    1049           0 :                                 if (!node->sgprivate->interact) {
    1050           0 :                                         GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
    1051           0 :                                         if (!node->sgprivate->interact) return GF_OUT_OF_MEM;
    1052             :                                 }
    1053           0 :                                 if (!node->sgprivate->interact->routes) node->sgprivate->interact->routes = gf_list_new();
    1054           0 :                                 gf_list_add(node->sgprivate->interact->routes, r2);
    1055           0 :                                 gf_list_add(r->graph->Routes, r2);
    1056             :                         }
    1057             :                         break;
    1058           0 :                 case GF_SG_EVENT_OUT:
    1059           0 :                         r->FromField.fieldIndex = nodeFieldIndex;
    1060           0 :                         r->FromNode = node;
    1061           0 :                         r->ToField.fieldIndex = protoFieldIndex;
    1062           0 :                         r->ToNode = protoinst;
    1063           0 :                         if (!node->sgprivate->interact) {
    1064           0 :                                 GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
    1065           0 :                                 if (!node->sgprivate->interact) return GF_OUT_OF_MEM;
    1066             :                         }
    1067           0 :                         if (!node->sgprivate->interact->routes) node->sgprivate->interact->routes = gf_list_new();
    1068           0 :                         gf_list_add(node->sgprivate->interact->routes, r);
    1069           0 :                         break;
    1070           0 :                 default:
    1071           0 :                         gf_free(r);
    1072           0 :                         return GF_BAD_PARAM;
    1073             :                 }
    1074             :         }
    1075           0 :         r->graph = node->sgprivate->scenegraph;
    1076           0 :         gf_sg_route_activate(r);
    1077           0 :         return gf_list_add(r->graph->Routes, r);
    1078             : }
    1079             : 
    1080             : 
    1081           4 : GF_Err gf_bifs_proto_field_set_aq_info(GF_ProtoFieldInterface *field,
    1082             :                                        u32 QP_Type,
    1083             :                                        u32 hasMinMax,
    1084             :                                        u32 QPSFType,
    1085             :                                        void *qp_min_value,
    1086             :                                        void *qp_max_value,
    1087             :                                        u32 QP13_NumBits)
    1088             : {
    1089             : 
    1090           4 :         if (!field) return GF_BAD_PARAM;
    1091           4 :         if (!QP_Type) return GF_OK;
    1092           4 :         if (!gf_sg_vrml_is_sf_field(QPSFType)) return GF_BAD_PARAM;
    1093             : 
    1094           4 :         field->QP_Type = QP_Type;
    1095           4 :         field->hasMinMax = hasMinMax;
    1096           4 :         if (hasMinMax) {
    1097           4 :                 if (qp_min_value) {
    1098           4 :                         field->qp_min_value = gf_sg_vrml_field_pointer_new(QPSFType);
    1099           4 :                         gf_sg_vrml_field_copy(field->qp_min_value, qp_min_value, QPSFType);
    1100             :                 }
    1101           4 :                 if (qp_max_value) {
    1102           4 :                         field->qp_max_value = gf_sg_vrml_field_pointer_new(QPSFType);
    1103           4 :                         gf_sg_vrml_field_copy(field->qp_max_value, qp_max_value, QPSFType);
    1104             :                 }
    1105             :         }
    1106           4 :         field->NumBits = QP13_NumBits;
    1107           4 :         return GF_OK;
    1108             : }
    1109             : 
    1110             : 
    1111        2651 : GF_Err gf_sg_proto_get_field_index(GF_ProtoInstance *proto, u32 index, u32 code_mode, u32 *all_index)
    1112             : {
    1113             :         u32 i;
    1114             :         GF_ProtoFieldInterface *proto_field;
    1115             : 
    1116        2651 :         i=0;
    1117       11508 :         while ((proto_field = (GF_ProtoFieldInterface*)gf_list_enum(proto->proto_interface->proto_fields, &i))) {
    1118             :                 assert(proto_field);
    1119        8857 :                 switch (code_mode) {
    1120         197 :                 case GF_SG_FIELD_CODING_IN:
    1121         197 :                         if (proto_field->IN_index == index) {
    1122         133 :                                 *all_index = proto_field->ALL_index;
    1123         133 :                                 return GF_OK;
    1124             :                         }
    1125             :                         break;
    1126           0 :                 case GF_SG_FIELD_CODING_OUT:
    1127           0 :                         if (proto_field->OUT_index == index) {
    1128           0 :                                 *all_index = proto_field->ALL_index;
    1129           0 :                                 return GF_OK;
    1130             :                         }
    1131             :                         break;
    1132        8660 :                 case GF_SG_FIELD_CODING_DEF:
    1133        8660 :                         if (proto_field->DEF_index == index) {
    1134        2518 :                                 *all_index = proto_field->ALL_index;
    1135        2518 :                                 return GF_OK;
    1136             :                         }
    1137             :                         break;
    1138           0 :                 case GF_SG_FIELD_CODING_ALL:
    1139           0 :                         if (proto_field->ALL_index == index) {
    1140           0 :                                 *all_index = proto_field->ALL_index;
    1141           0 :                                 return GF_OK;
    1142             :                         }
    1143             :                         break;
    1144             :                 /*BIFS-ANIM not supported*/
    1145             :                 case GF_SG_FIELD_CODING_DYN:
    1146             :                 default:
    1147             :                         return GF_BAD_PARAM;
    1148             :                 }
    1149             :         }
    1150             :         return GF_BAD_PARAM;
    1151             : }
    1152             : 
    1153             : GF_EXPORT
    1154         710 : u32 gf_sg_proto_get_field_count(GF_Proto *proto)
    1155             : {
    1156         710 :         if (!proto) return 0;
    1157         710 :         return gf_list_count(proto->proto_fields);
    1158             : }
    1159             : 
    1160             : GF_EXPORT
    1161         326 : GF_ProtoFieldInterface *gf_sg_proto_field_find(GF_Proto *proto, u32 fieldIndex)
    1162             : {
    1163         326 :         if (!proto) return NULL;
    1164         326 :         return (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, fieldIndex);
    1165             : }
    1166             : 
    1167       61686 : void gf_sg_proto_propagate_event(GF_Node *node, u32 fieldIndex, GF_Node *from_node)
    1168             : {
    1169             :         u32 i;
    1170             :         GF_Route *r;
    1171      106222 :         if (!node) return;
    1172             :         /*propagation only for proto*/
    1173       61686 :         if (node->sgprivate->tag != TAG_ProtoNode) return;
    1174             :         /*with ISed fields*/
    1175       21955 :         if (!node->sgprivate->interact || !node->sgprivate->interact->routes) return;
    1176             :         /*we only need to propagate ISed for eventIn/exposedField. This means that if the event comes from
    1177             :         the same scene graph as the proto (eg from the proto code) we don't propagate the event*/
    1178       21056 :         if (from_node->sgprivate->scenegraph == node->sgprivate->scenegraph) return;
    1179             : 
    1180             :         /*for all ISed routes*/
    1181       17150 :         i=0;
    1182      214342 :         while ((r = (GF_Route*)gf_list_enum(node->sgprivate->interact->routes, &i))) {
    1183      180042 :                 if (!r->IS_route) continue;
    1184             :                 /*connecting from this node && field to a destination node other than the event source (this will break loops due to exposedFields)*/
    1185      154378 :                 if ((r->FromNode == node) && (r->FromField.fieldIndex == fieldIndex) && (r->ToNode != from_node) ) {
    1186        9600 :                         if (gf_sg_route_activate(r))
    1187        2201 :                                 gf_node_changed(r->ToNode, &r->ToField);
    1188             :                 }
    1189             :         }
    1190             : }
    1191             : 
    1192             : 
    1193          73 : Bool gf_sg_proto_get_aq_info(GF_Node *Node, u32 FieldIndex, u8 *QType, u8 *AType, Fixed *b_min, Fixed *b_max, u32 *QT13_bits)
    1194             : {
    1195             :         GF_Proto *proto;
    1196             :         u32 i;
    1197             :         GF_ProtoFieldInterface *proto_field;
    1198             : 
    1199          73 :         proto = ((GF_ProtoInstance *)Node)->proto_interface;
    1200             : 
    1201          73 :         i=0;
    1202         426 :         while ((proto_field = (GF_ProtoFieldInterface*)gf_list_enum(proto->proto_fields, &i))) {
    1203         353 :                 if (proto_field->ALL_index!=FieldIndex) continue;
    1204             : 
    1205          73 :                 *QType = proto_field->QP_Type;
    1206          73 :                 *AType = proto_field->Anim_Type;
    1207          73 :                 *b_min = FIX_MIN;
    1208          73 :                 *b_max = FIX_MAX;
    1209             : 
    1210          73 :                 if (proto_field->hasMinMax) {
    1211             : 
    1212             :                         /*translate our bounds*/
    1213           0 :                         switch (gf_sg_vrml_get_sf_type(proto_field->FieldType)) {
    1214           0 :                         case GF_SG_VRML_SFINT32:
    1215           0 :                                 *b_min = (SFFloat) * ( (SFInt32 *) proto_field->qp_min_value);
    1216           0 :                                 *b_max = (SFFloat) * ( (SFInt32 *) proto_field->qp_max_value);
    1217           0 :                                 break;
    1218             :                         /*TO DO EVERYWHERE: check on field translation from double to float
    1219             :                         during quant bounds*/
    1220           0 :                         case GF_SG_VRML_SFTIME:
    1221           0 :                                 *b_min = (SFFloat) * ( (SFTime *) proto_field->qp_min_value);
    1222           0 :                                 *b_max = (SFFloat) * ( (SFTime *) proto_field->qp_max_value);
    1223           0 :                                 break;
    1224           0 :                         default:
    1225           0 :                                 if (proto_field->qp_min_value)
    1226           0 :                                         *b_min = (SFFloat) * ( (SFFloat *) proto_field->qp_min_value);
    1227           0 :                                 if (proto_field->qp_max_value)
    1228           0 :                                         *b_max = (SFFloat) * ( (SFFloat *) proto_field->qp_max_value);
    1229             :                                 break;
    1230             :                         }
    1231             : 
    1232          73 :                 }
    1233          73 :                 *QT13_bits = proto_field->NumBits;
    1234          73 :                 return 1;
    1235             :         }
    1236             :         return 0;
    1237             : }
    1238             : 
    1239             : 
    1240             : GF_EXPORT
    1241         661 : GF_Proto *gf_node_get_proto(GF_Node *node)
    1242             : {
    1243             :         GF_ProtoInstance *inst;
    1244         661 :         if (node->sgprivate->tag != TAG_ProtoNode) return NULL;
    1245             :         inst = (GF_ProtoInstance *) node;
    1246         661 :         return inst->proto_interface;
    1247             : }
    1248             : 
    1249             : /*returns the ID of the proto*/
    1250             : GF_EXPORT
    1251           0 : u32 gf_sg_proto_get_id(GF_Proto *proto)
    1252             : {
    1253           0 :         return proto->ID;
    1254             : }
    1255             : 
    1256             : GF_EXPORT
    1257          18 : const char *gf_sg_proto_get_class_name(GF_Proto *proto)
    1258             : {
    1259          18 :         return (const char *) proto->Name;
    1260             : }
    1261             : 
    1262         131 : u32 gf_sg_proto_get_root_tag(GF_Proto *proto)
    1263             : {
    1264             :         GF_Node *n;
    1265         131 :         if (!proto) return TAG_UndefinedNode;
    1266         131 :         n = (GF_Node*)gf_list_get(proto->node_code, 0);
    1267         131 :         if (!n) return TAG_UndefinedNode;
    1268          98 :         if (n->sgprivate->tag == TAG_ProtoNode) return gf_sg_proto_get_root_tag(((GF_ProtoInstance *)n)->proto_interface);
    1269          98 :         return n->sgprivate->tag;
    1270             : }
    1271             : 
    1272             : GF_EXPORT
    1273          31 : Bool gf_sg_proto_field_is_sftime_offset(GF_Node *node, GF_FieldInfo *field)
    1274             : {
    1275             :         u32 i;
    1276             :         GF_Route *r;
    1277             :         GF_ProtoInstance *inst;
    1278             :         GF_FieldInfo inf;
    1279          31 :         if (node->sgprivate->tag != TAG_ProtoNode) return 0;
    1280          31 :         if (field->fieldType != GF_SG_VRML_SFTIME) return 0;
    1281             : 
    1282             :         inst = (GF_ProtoInstance *) node;
    1283             :         /*check in interface if this is ISed */
    1284          31 :         i=0;
    1285         344 :         while ((r = (GF_Route*)gf_list_enum(inst->proto_interface->sub_graph->Routes, &i))) {
    1286         292 :                 if (!r->IS_route) continue;
    1287             :                 /*only check eventIn/field/exposedField*/
    1288         278 :                 if (r->FromNode || (r->FromField.fieldIndex != field->fieldIndex)) continue;
    1289             : 
    1290          17 :                 gf_node_get_field(r->ToNode, r->ToField.fieldIndex, &inf);
    1291             :                 /*IS to another proto*/
    1292          17 :                 if (r->ToNode->sgprivate->tag == TAG_ProtoNode) return gf_sg_proto_field_is_sftime_offset(r->ToNode, &inf);
    1293             :                 /*IS to a startTime/stopTime field*/
    1294          17 :                 if (!stricmp(inf.name, "startTime") || !stricmp(inf.name, "stopTime")) return 1;
    1295             :         }
    1296             :         return 0;
    1297             : }
    1298             : 
    1299             : GF_EXPORT
    1300          84 : GF_Err gf_node_proto_set_grouping(GF_Node *node)
    1301             : {
    1302          84 :         if (!node || (node->sgprivate->tag!=TAG_ProtoNode)) return GF_BAD_PARAM;
    1303          84 :         ((GF_ProtoInstance *)node)->flags |= GF_SG_PROTO_IS_GROUPING;
    1304          84 :         return GF_OK;
    1305             : }
    1306             : 
    1307             : GF_EXPORT
    1308           0 : Bool gf_node_proto_is_grouping(GF_Node *node)
    1309             : {
    1310           0 :         if (!node || (node->sgprivate->tag!=TAG_ProtoNode)) return 0;
    1311           0 :         if ( ((GF_ProtoInstance *)node)->flags & GF_SG_PROTO_IS_GROUPING) return 1;
    1312           0 :         return 0;
    1313             : }
    1314             : 
    1315             : GF_EXPORT
    1316           0 : GF_Node *gf_node_get_proto_root(GF_Node *node)
    1317             : {
    1318           0 :         if (!node || (node->sgprivate->tag!=TAG_ProtoNode)) return NULL;
    1319           0 :         return ((GF_ProtoInstance *)node)->RenderingNode;
    1320             : }
    1321             : 
    1322             : #if 0 //unused
    1323             : GF_Node *gf_node_get_proto_parent(GF_Node *node)
    1324             : {
    1325             :         if (!node) return NULL;
    1326             :         if (node->sgprivate->scenegraph->pOwningProto) {
    1327             :                 GF_Node *the_node = (GF_Node *) node->sgprivate->scenegraph->pOwningProto;
    1328             :                 if (the_node != node) return the_node;
    1329             :         }
    1330             :         return NULL;
    1331             : }
    1332             : 
    1333             : Bool gf_node_is_proto_root(GF_Node *node)
    1334             : {
    1335             :         if (!node) return 0;
    1336             :         if (!node->sgprivate->scenegraph->pOwningProto) return 0;
    1337             : 
    1338             :         if (gf_list_find(node->sgprivate->scenegraph->pOwningProto->node_code, node)>=0) return 1;
    1339             :         return 0;
    1340             : }
    1341             : #endif
    1342             : 
    1343             : 
    1344             : GF_EXPORT
    1345           1 : GF_Err gf_node_set_proto_eventin_handler(GF_Node *node, u32 fieldIndex, void (*event_in_cbk)(GF_Node *pThis, struct _route *route) )
    1346             : {
    1347             :         GF_ProtoInstance *inst;
    1348             :         GF_ProtoField *field;
    1349           1 :         if (!node || (node->sgprivate->tag!=TAG_ProtoNode)) return GF_BAD_PARAM;
    1350             : 
    1351             :         inst = (GF_ProtoInstance *) node;
    1352           1 :         field = (GF_ProtoField*)gf_list_get(inst->fields, fieldIndex);
    1353           1 :         if (!field) return GF_BAD_PARAM;
    1354             : 
    1355           1 :         if (field->EventType!=GF_SG_EVENT_IN) return GF_BAD_PARAM;
    1356           1 :         field->on_event_in = event_in_cbk;
    1357           1 :         return GF_OK;
    1358             : }
    1359             : 
    1360             : 
    1361             : 
    1362             : #endif  /*GPAC_DISABLE_VRML*/

Generated by: LCOV version 1.13