This source file includes following definitions.
- gf_sg_proto_new
- gf_sg_proto_set_in_graph
- gf_sg_proto_del
- gf_sg_proto_get_graph
- gf_sg_proto_set_private
- gf_sg_proto_get_private
- gf_sg_proto_get_extern_url
- gf_sg_proto_add_node_code
- gf_sg_proto_field_find_by_name
- gf_sg_proto_field_new
- gf_sg_proto_field_set_private
- gf_sg_proto_field_get_private
- gf_sg_proto_field_get_field
- gf_sg_proto_get_field
- gf_sg_proto_get_field_index_by_name
- gf_vrml_node_clone
- gf_sg_proto_get_field_ind_static
- is_same_proto
- find_proto_by_interface
- gf_sg_proto_instanciate
- gf_sg_proto_mark_field_loaded
- gf_sg_proto_create_node
- gf_sg_proto_create_instance
- gf_sg_proto_load_code
- gf_sg_proto_get_num_fields
- gf_sg_proto_del_instance
- gf_sg_proto_field_set_ised
- gf_sg_proto_instance_set_ised
- gf_bifs_proto_field_set_aq_info
- gf_sg_proto_get_field_index
- gf_sg_proto_get_field_count
- gf_sg_proto_field_find
- gf_sg_proto_propagate_event
- gf_sg_proto_get_aq_info
- gf_node_get_proto
- gf_sg_proto_get_id
- gf_sg_proto_get_class_name
- gf_sg_proto_get_root_tag
- gf_sg_proto_field_is_sftime_offset
- Node_GetExternProtoScene
- gf_node_proto_set_grouping
- gf_node_proto_is_grouping
- gf_node_get_proto_root
- gf_node_get_proto_parent
- gf_node_is_proto_root
- gf_node_set_proto_eventin_handler
#include <gpac/internal/scenegraph_dev.h>
#include <gpac/nodes_mpeg4.h>
#include <gpac/nodes_x3d.h>
#ifndef GPAC_DISABLE_VRML
GF_Proto *gf_sg_proto_new(GF_SceneGraph *inScene, u32 ProtoID, char *name, Bool unregistered)
{
GF_Proto *tmp;
if (!inScene) return NULL;
if (!unregistered) {
tmp = gf_sg_find_proto(inScene, ProtoID, name);
if (tmp) {
GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[Scenegraph] PROTO %s redefined - skipping loading\n", name));
return NULL;
}
}
GF_SAFEALLOC(tmp, GF_Proto)
if (!tmp) return NULL;
tmp->proto_fields = gf_list_new();
tmp->node_code = gf_list_new();
tmp->parent_graph = inScene;
tmp->sub_graph = gf_sg_new_subscene(inScene);
tmp->instances = gf_list_new();
if (name)
tmp->Name = gf_strdup(name);
else
tmp->Name = gf_strdup("Unnamed Proto");
tmp->ID = ProtoID;
if (!unregistered) {
gf_list_add(inScene->protos, tmp);
} else {
gf_list_add(inScene->unregistered_protos, tmp);
}
return tmp;
}
GF_Err gf_sg_proto_set_in_graph(GF_Proto *proto, GF_SceneGraph *inScene, Bool set_in)
{
u32 i;
GF_Proto *tmp;
GF_List *removeFrom;
GF_List *insertIn;
if (set_in) {
removeFrom = proto->parent_graph->unregistered_protos;
insertIn = proto->parent_graph->protos;
} else {
insertIn = proto->parent_graph->unregistered_protos;
removeFrom = proto->parent_graph->protos;
}
gf_list_del_item(removeFrom, proto);
i=0;
while ((tmp = (GF_Proto*)gf_list_enum(insertIn, &i))) {
if (tmp==proto) return GF_OK;
if (!set_in) continue;
if (tmp->ID==proto->ID) return GF_BAD_PARAM;
if (!stricmp(tmp->Name, proto->Name)) return GF_BAD_PARAM;
}
return gf_list_add(insertIn, proto);
}
GF_Err gf_sg_proto_del(GF_Proto *proto)
{
GF_Node *node;
GF_ProtoFieldInterface *field;
s32 i;
if (!proto) return GF_OK;
i = gf_list_del_item(proto->parent_graph->protos, proto);
if (i<0) {
gf_list_del_item(proto->parent_graph->unregistered_protos, proto);
}
if (proto->userpriv && proto->OnDelete) proto->OnDelete(proto->userpriv);
while (gf_list_count(proto->node_code)) {
node = (GF_Node*)gf_list_get(proto->node_code, 0);
gf_node_unregister(node, NULL);
gf_list_rem(proto->node_code, 0);
}
gf_list_del(proto->node_code);
while (gf_list_count(proto->proto_fields)) {
field = (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, 0);
if (field->userpriv && field->OnDelete) field->OnDelete(field->userpriv);
if (field->FieldType==GF_SG_VRML_SFNODE) {
if (field->def_sfnode_value)
gf_node_unregister(field->def_sfnode_value, NULL);
}
else if (field->FieldType==GF_SG_VRML_MFNODE) {
if (field->def_mfnode_value)
gf_node_unregister_children(NULL, field->def_mfnode_value);
}
else if (field->def_value)
gf_sg_vrml_field_pointer_del(field->def_value, field->FieldType);
if (field->FieldName) gf_free(field->FieldName);
if (field->qp_max_value) gf_free(field->qp_max_value);
if (field->qp_min_value) gf_free(field->qp_min_value);
gf_free(field);
gf_list_rem(proto->proto_fields, 0);
}
gf_list_del(proto->proto_fields);
while (gf_list_count(proto->instances)) {
GF_ProtoInstance *p = (GF_ProtoInstance *)gf_list_get(proto->instances, 0);
gf_list_rem(proto->instances, 0);
p->proto_interface = NULL;
}
gf_sg_del(proto->sub_graph);
if (proto->Name) gf_free(proto->Name);
gf_sg_mfurl_del(proto->ExternProto);
gf_list_del(proto->instances);
gf_free(proto);
return GF_OK;
}
GF_SceneGraph *gf_sg_proto_get_graph(GF_Proto *proto)
{
return proto ? proto->sub_graph : NULL;
}
void gf_sg_proto_set_private(GF_Proto *p, void *ptr, void (*OnDelete)(void *ptr) )
{
if (p) {
p->userpriv = ptr;
p->OnDelete = OnDelete;
}
}
void *gf_sg_proto_get_private(GF_Proto *p)
{
return p ? p->userpriv : NULL;
}
GF_EXPORT
MFURL *gf_sg_proto_get_extern_url(GF_Proto *proto)
{
return proto ? &proto->ExternProto : NULL;
}
GF_Err gf_sg_proto_add_node_code(GF_Proto *proto, GF_Node *pNode)
{
if (!proto) return GF_BAD_PARAM;
return gf_list_add(proto->node_code, pNode);
}
GF_ProtoFieldInterface *gf_sg_proto_field_find_by_name(GF_Proto *proto, char *fieldName)
{
GF_ProtoFieldInterface *ptr;
u32 i=0;
while ((ptr = (GF_ProtoFieldInterface*)gf_list_enum(proto->proto_fields, &i))) {
if (ptr->FieldName && !strcmp(ptr->FieldName, fieldName)) return ptr;
}
return NULL;
}
GF_ProtoFieldInterface *gf_sg_proto_field_new(GF_Proto *proto, u32 fieldType, u32 eventType, char *fieldName)
{
GF_ProtoFieldInterface *tmp;
if (fieldName) {
tmp = gf_sg_proto_field_find_by_name(proto, fieldName);
if (tmp) return NULL;
}
GF_SAFEALLOC(tmp, GF_ProtoFieldInterface)
if (!tmp) return NULL;
tmp->FieldType = fieldType;
tmp->EventType = eventType;
if ( fieldType == GF_SG_VRML_SFNODE) {
tmp->def_sfnode_value = NULL;
tmp->def_value = &tmp->def_sfnode_value;
} else if ( fieldType == GF_SG_VRML_MFNODE) {
tmp->def_mfnode_value = NULL;
tmp->def_value = &tmp->def_mfnode_value;
} else {
tmp->def_value = gf_sg_vrml_field_pointer_new(fieldType);
}
if (fieldName) tmp->FieldName = gf_strdup(fieldName);
tmp->ALL_index = gf_list_count(proto->proto_fields);
tmp->OUT_index = tmp->DEF_index = tmp->IN_index = (u32) -1;
switch (eventType) {
case GF_SG_EVENT_EXPOSED_FIELD:
tmp->IN_index = proto->NumIn;
proto->NumIn ++;
tmp->OUT_index = proto->NumOut;
proto->NumOut ++;
case GF_SG_EVENT_FIELD:
tmp->DEF_index = proto->NumDef;
proto->NumDef ++;
break;
case GF_SG_EVENT_IN:
tmp->IN_index = proto->NumIn;
proto->NumIn ++;
break;
case GF_SG_EVENT_OUT:
tmp->OUT_index = proto->NumOut;
proto->NumOut ++;
break;
}
gf_list_add(proto->proto_fields, tmp);
return tmp;
}
void gf_sg_proto_field_set_private(GF_ProtoFieldInterface *field, void *ptr, void (*OnDelete)(void *ptr))
{
if (field) {
field->userpriv = ptr;
field->OnDelete = OnDelete;
}
}
void *gf_sg_proto_field_get_private(GF_ProtoFieldInterface *field)
{
return field ? field->userpriv : NULL;
}
GF_Err gf_sg_proto_field_get_field(GF_ProtoFieldInterface *field, GF_FieldInfo *info)
{
if (!field || !info) return GF_BAD_PARAM;
memset(info, 0, sizeof(GF_FieldInfo));
info->fieldIndex = field->ALL_index;
info->fieldType = field->FieldType;
info->eventType = field->EventType;
info->far_ptr = field->def_value;
info->name = field->FieldName;
info->NDTtype = NDT_SFWorldNode;
return GF_OK;
}
GF_Err gf_sg_proto_get_field(GF_Proto *proto, GF_Node *node, GF_FieldInfo *info)
{
GF_ProtoFieldInterface *proto_field;
GF_ProtoInstance *inst;
GF_ProtoField *field;
if (!proto && !node) return GF_BAD_PARAM;
if (proto) {
proto_field = (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, info->fieldIndex);
if (!proto_field) return GF_BAD_PARAM;
info->fieldType = proto_field->FieldType;
info->eventType = proto_field->EventType;
info->fieldIndex = proto_field->ALL_index;
info->NDTtype = NDT_SFWorldNode;
info->far_ptr = proto_field->def_value;
info->name = proto_field->FieldName;
return GF_OK;
}
if (node->sgprivate->tag!=TAG_ProtoNode) return GF_BAD_PARAM;
inst = (GF_ProtoInstance *) node;
field = (GF_ProtoField*)gf_list_get(inst->fields, info->fieldIndex);
if (!field) return GF_BAD_PARAM;
info->fieldType = field->FieldType;
info->eventType = field->EventType;
info->on_event_in = field->on_event_in;
if (gf_sg_vrml_get_sf_type(field->FieldType) == GF_SG_VRML_SFNODE) {
info->far_ptr = &field->field_pointer;
} else {
info->far_ptr = field->field_pointer;
}
if (inst->proto_interface) {
proto_field = (GF_ProtoFieldInterface*)gf_list_get(inst->proto_interface->proto_fields, info->fieldIndex);
info->name = proto_field->FieldName;
} else {
info->name = "ProtoFieldDeleted";
}
info->NDTtype = NDT_SFWorldNode;
return GF_OK;
}
s32 gf_sg_proto_get_field_index_by_name(GF_Proto *proto, GF_Node *node, char *name)
{
u32 i;
GF_ProtoFieldInterface *proto_field;
GF_Proto *__proto;
if (!node && !proto) return -1;
if (node && (node->sgprivate->tag!=TAG_ProtoNode)) return -1;
__proto = proto ? proto : ((GF_ProtoInstance *) node)->proto_interface;
if (!__proto ) return -1;
for (i=0; i<gf_list_count(__proto->proto_fields); i++) {
proto_field = (GF_ProtoFieldInterface*)gf_list_get(__proto->proto_fields, i);
if (proto_field->FieldName && !strcmp(proto_field->FieldName, name)) return i;
}
return -1;
}
GF_Node *gf_vrml_node_clone(GF_SceneGraph *inScene, GF_Node *orig, GF_Node *cloned_parent, char *inst_id_suffix)
{
u32 i, count, id;
char *szNodeName;
Bool is_script;
GF_Node *node, *child;
GF_ChildNodeItem *list, *last;
GF_Route *r1, *r2;
#ifndef GPAC_DISABLE_BIFS
void BIFS_SetupConditionalClone(GF_Node *node, GF_Node *orig);
#endif
GF_ProtoInstance *proto;
GF_Proto *proto_node;
GF_FieldInfo field_orig, field;
if (!orig) return NULL;
szNodeName = NULL;
if (!inst_id_suffix) id = 0;
else {
const char *orig_name = gf_node_get_name_and_id(orig, &id);
if (inst_id_suffix[0] && id) {
id = gf_sg_get_next_available_node_id(inScene);
if (orig_name) {
szNodeName = gf_malloc(sizeof(char)*(strlen(orig_name)+strlen(inst_id_suffix)+1));
strcpy(szNodeName, orig_name);
strcat(szNodeName, inst_id_suffix);
}
}
else if (orig_name) szNodeName = gf_strdup(orig_name);
}
if (id) {
node = szNodeName ? gf_sg_find_node_by_name(inScene, szNodeName) : gf_sg_find_node(inScene, id);
if (node) {
gf_node_register(node, cloned_parent);
if (szNodeName) gf_free(szNodeName);
return node;
}
}
if (orig->sgprivate->tag == TAG_ProtoNode) {
proto_node = ((GF_ProtoInstance *)orig)->proto_interface;
node = gf_sg_proto_create_node(inScene, proto_node, (GF_ProtoInstance *) orig);
} else {
node = gf_node_new(inScene, orig->sgprivate->tag);
}
count = gf_node_get_field_count(orig);
is_script = 0;
if (orig->sgprivate->tag==TAG_MPEG4_Script) is_script = 1;
#ifndef GPAC_DISABLE_X3D
else if (orig->sgprivate->tag==TAG_X3D_Script) is_script = 1;
#endif
if (is_script) gf_sg_script_prepare_clone(node, orig);
if (id) {
gf_node_set_id(node, id, szNodeName);
if (szNodeName) gf_free(szNodeName);
}
gf_node_register(node, cloned_parent);
for (i=0; i<count; i++) {
gf_node_get_field(orig, i, &field_orig);
gf_node_get_field(node, i, &field);
assert(field.eventType==field_orig.eventType);
assert(field.fieldType==field_orig.fieldType);
switch (field.fieldType) {
case GF_SG_VRML_SFNODE:
child = gf_node_clone(inScene, (* ((GF_Node **) field_orig.far_ptr)), node, inst_id_suffix, 1);
*((GF_Node **) field.far_ptr) = child;
break;
case GF_SG_VRML_MFNODE:
last = NULL;
list = *( (GF_ChildNodeItem **) field_orig.far_ptr);
while (list) {
child = gf_node_clone(inScene, list->node, node, inst_id_suffix, 1);
gf_node_list_add_child_last((GF_ChildNodeItem **) field.far_ptr, child, &last);
list = list->next;
}
break;
case GF_SG_VRML_SFTIME:
gf_sg_vrml_field_copy(field.far_ptr, field_orig.far_ptr, field.fieldType);
if (!inScene->GetSceneTime) break;
if (orig->sgprivate->tag == TAG_ProtoNode) {
if (gf_sg_proto_field_is_sftime_offset(orig, &field_orig))
*((SFTime *)field.far_ptr) += inScene->GetSceneTime(inScene->userpriv);
} else if (!stricmp(field.name, "startTime") || !stricmp(field_orig.name, "startTime") ) {
*((SFTime *)field.far_ptr) += inScene->GetSceneTime(inScene->userpriv);
}
break;
default:
gf_sg_vrml_field_clone(field.far_ptr, field_orig.far_ptr, field.fieldType, inScene);
break;
}
}
#ifndef GPAC_DISABLE_BIFS
if (node->sgprivate->tag == TAG_MPEG4_Conditional)
BIFS_SetupConditionalClone(node, orig);
else
#endif
if (node->sgprivate->tag != TAG_ProtoNode) gf_node_init(node);
if (!inScene->pOwningProto) return node;
proto = inScene->pOwningProto;
i=0;
while ((r1 = (GF_Route*)gf_list_enum(proto->proto_interface->sub_graph->Routes, &i))) {
r2 = NULL;
if (!r1->IS_route) continue;
if (r1->FromNode == orig) {
r2 = gf_sg_route_new(inScene, node, r1->FromField.fieldIndex, (GF_Node *) proto, r1->ToField.fieldIndex);
r2->IS_route = 1;
}
else if (r1->ToNode == orig) {
r2 = gf_sg_route_new(inScene, (GF_Node *) proto, r1->FromField.fieldIndex, node, r1->ToField.fieldIndex);
r2->IS_route = 1;
gf_sg_route_activate(r2);
}
}
if (is_script) gf_list_add(proto->scripts_to_load, node);
if (node->sgprivate->tag == TAG_ProtoNode) {
node->sgprivate->UserCallback = NULL;
node->sgprivate->UserPrivate = NULL;
gf_sg_proto_instanciate((GF_ProtoInstance *)node);
}
return node;
}
GF_Err gf_sg_proto_get_field_ind_static(GF_Node *Node, u32 inField, u8 IndexMode, u32 *allField)
{
return gf_sg_proto_get_field_index((GF_ProtoInstance *)Node, inField, IndexMode, allField);
}
static Bool is_same_proto(GF_Proto *extern_proto, GF_Proto *proto)
{
u32 i, count;
if (gf_list_count(extern_proto->proto_fields) > gf_list_count(proto->proto_fields)) return 0;
count = gf_list_count(extern_proto->proto_fields);
for (i=0; i<count; i++) {
GF_ProtoFieldInterface *pf1 = (GF_ProtoFieldInterface*)gf_list_get(extern_proto->proto_fields, i);
GF_ProtoFieldInterface *pf2 = (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, i);
if (pf1->EventType != pf2->EventType) return 0;
if (pf1->FieldType != pf2->FieldType) return 0;
}
return 1;
}
static GF_Proto *find_proto_by_interface(GF_SceneGraph *sg, GF_Proto *extern_proto)
{
GF_Proto *proto;
u32 i, count;
assert(sg);
i=0;
while ((proto = (GF_Proto*)gf_list_enum(sg->protos, &i))) {
if (is_same_proto(proto, extern_proto)) return proto;
}
count = gf_list_count(sg->unregistered_protos);
for (i=count; i>0; i--) {
proto = (GF_Proto*)gf_list_get(sg->unregistered_protos, i-1);
if (is_same_proto(proto, extern_proto)) return proto;
}
return NULL;
}
void gf_sg_proto_instanciate(GF_ProtoInstance *proto_node)
{
GF_Node *node, *orig;
GF_Route *route, *r2;
u32 i, count;
GF_Proto *proto = proto_node->proto_interface;
GF_Proto *owner = proto;
if (!proto) return;
if (owner->ExternProto.count) {
GF_ProtoFieldInterface *pfi;
GF_SceneGraph *extern_lib;
if (!owner->parent_graph->GetExternProtoLib) return;
extern_lib = owner->parent_graph->GetExternProtoLib(proto->parent_graph->userpriv, &owner->ExternProto);
if (!extern_lib) return;
if (PTR_TO_U_CAST extern_lib == GF_SG_INTERNAL_PROTO) {
proto_node->sgprivate->flags |= GF_SG_NODE_DIRTY;
count = gf_list_count(owner->proto_fields);
for (i=0; i<count; i++) {
GF_ProtoField *pf = (GF_ProtoField *)gf_list_get(proto_node->fields, i);
if (!pf->has_been_accessed) {
pfi = (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, i);
gf_sg_vrml_field_copy(pf->field_pointer, pfi->def_value, pfi->FieldType);
}
}
owner->parent_graph->NodeCallback(owner->parent_graph->userpriv, GF_SG_CALLBACK_INIT, (GF_Node *) proto_node, NULL);
proto_node->flags |= GF_SG_PROTO_LOADED | GF_SG_PROTO_HARDCODED;
return;
}
if (!gf_list_count(extern_lib->protos)) return;
proto = NULL;
if (owner->ExternProto.vals[0].url) {
u32 ID = (u32) -1;
char *szName = strrchr(owner->ExternProto.vals[0].url, '#');
if (szName) {
szName++;
if (sscanf(szName, "%u", &ID)) ID = (u32) -1;
}
if (owner->Name) szName = owner->Name;
proto = gf_sg_find_proto(extern_lib, ID, szName);
}
if (!proto) proto = gf_sg_find_proto(extern_lib, owner->ID, owner->Name);
if (!proto) proto = find_proto_by_interface(extern_lib, owner);
if (proto && !is_same_proto(owner, proto)) {
proto = NULL;
GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[Scenegraph] fields/types mismatch for PROTO %s - skipping instantiation\n", owner->Name));
}
if (!proto) {
proto_node->flags |= GF_SG_PROTO_LOADED;
return;
}
count = gf_list_count(owner->proto_fields);
for (i=0; i<count; i++) {
GF_ProtoField *pf = (GF_ProtoField *)gf_list_get(proto_node->fields, i);
if (!pf->has_been_accessed) {
pfi = (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, i);
gf_sg_vrml_field_copy(pf->field_pointer, pfi->def_value, pfi->FieldType);
} else {
}
}
gf_list_del_item(owner->instances, proto_node);
gf_list_add(proto->instances, proto_node);
}
proto_node->proto_interface = proto;
i=0;
while ((orig = (GF_Node*)gf_list_enum(proto->node_code, &i))) {
node = gf_node_clone(proto_node->sgprivate->scenegraph, orig, NULL, "", 1);
assert(node);
if (i==1) proto_node->RenderingNode = node;
gf_list_add(proto_node->node_code, node);
}
i=0;
while ((route = (GF_Route*)gf_list_enum(proto->sub_graph->Routes, &i))) {
if (route->IS_route) continue;
r2 = gf_sg_route_new(proto_node->sgprivate->scenegraph,
gf_sg_find_node(proto_node->sgprivate->scenegraph, gf_node_get_id(route->FromNode) ),
route->FromField.fieldIndex,
gf_sg_find_node(proto_node->sgprivate->scenegraph, gf_node_get_id(route->ToNode) ),
route->ToField.fieldIndex);
if (route->ID) gf_sg_route_set_id(r2, route->ID);
if (route->name) gf_sg_route_set_name(r2, route->name);
}
i=0;
while ((route = (GF_Route*)gf_list_enum(proto_node->sgprivate->scenegraph->Routes, &i))) {
if (!route->IS_route) continue;
if (route->is_setup) {
if ((route->ToField.eventType == GF_SG_EVENT_IN) && (route->FromField.eventType == GF_SG_EVENT_IN) ) continue;
}
gf_sg_route_activate(route);
}
while (gf_list_count(proto_node->scripts_to_load)) {
node = (GF_Node*)gf_list_get(proto_node->scripts_to_load, 0);
gf_list_rem(proto_node->scripts_to_load, 0);
gf_sg_script_load(node);
}
i=0;
while ((route = (GF_Route*)gf_list_enum(proto_node->sgprivate->scenegraph->Routes, &i))) {
if (!route->IS_route || !route->ToNode) continue;
if (route->is_setup) {
if ((route->ToField.eventType == GF_SG_EVENT_IN) && (route->FromField.eventType == GF_SG_EVENT_IN) ) continue;
}
if (route->ToNode->sgprivate->tag==TAG_MPEG4_Script)
gf_sg_route_activate(route);
#ifndef GPAC_DISABLE_X3D
else if (route->ToNode->sgprivate->tag==TAG_X3D_Script)
gf_sg_route_activate(route);
#endif
}
#if 0
i=0;
while ((route = (GF_Route*)gf_list_enum(proto_node->sgprivate->scenegraph->Routes, &i))) {
if (!route->IS_route) {
route->lastActivateTime = 0;
}
}
#endif
proto_node->flags |= GF_SG_PROTO_LOADED;
}
void gf_sg_proto_mark_field_loaded(GF_Node *proto_inst, GF_FieldInfo *info)
{
GF_ProtoInstance *inst= (proto_inst->sgprivate->tag==TAG_ProtoNode) ? (GF_ProtoInstance *)proto_inst : NULL;
GF_ProtoField *pf = inst ? (GF_ProtoField *)gf_list_get(inst->fields, info->fieldIndex) : NULL;
if (pf) pf->has_been_accessed = 1;
}
GF_Node *gf_sg_proto_create_node(GF_SceneGraph *scene, GF_Proto *proto, GF_ProtoInstance *from_inst)
{
u32 i;
GF_ProtoField *inst, *from_field;
GF_ProtoFieldInterface *field;
GF_ProtoInstance *proto_node;
if (!proto) return NULL;
GF_SAFEALLOC(proto_node, GF_ProtoInstance)
if (!proto_node) return NULL;
gf_node_setup((GF_Node *)proto_node, TAG_ProtoNode);
proto_node->node_code = gf_list_new();
proto_node->fields = gf_list_new();
proto_node->scripts_to_load = gf_list_new();
proto_node->proto_interface = proto;
gf_list_add(proto->instances, proto_node);
proto_node->proto_name = gf_strdup(proto->Name);
proto_node->sgprivate->scenegraph = gf_sg_new_subscene(scene);
proto_node->sgprivate->scenegraph->pOwningProto = proto_node;
i=0;
while ((field = (GF_ProtoFieldInterface*)gf_list_enum(proto->proto_fields, &i))) {
GF_SAFEALLOC(inst, GF_ProtoField);
if (!inst) {
GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[VRML] Failed to allocate proto instance field\n]"));
continue;
}
inst->EventType = field->EventType;
inst->FieldType = field->FieldType;
inst->field_pointer = gf_sg_vrml_field_pointer_new(inst->FieldType);
if (gf_sg_vrml_get_sf_type(inst->FieldType) != GF_SG_VRML_SFNODE) {
if (from_inst) {
from_field = (GF_ProtoField *)gf_list_get(from_inst->fields, i-1);
gf_sg_vrml_field_copy(inst->field_pointer, from_field->field_pointer, inst->FieldType);
inst->has_been_accessed = from_field->has_been_accessed;
} else {
gf_sg_vrml_field_copy(inst->field_pointer, field->def_value, inst->FieldType);
}
}
gf_list_add(proto_node->fields, inst);
}
return (GF_Node *) proto_node;
}
GF_Node *gf_sg_proto_create_instance(GF_SceneGraph *sg, GF_Proto *proto)
{
return gf_sg_proto_create_node(sg, proto, NULL);
}
GF_Err gf_sg_proto_load_code(GF_Node *node)
{
GF_ProtoInstance *inst;
if (node->sgprivate->tag != TAG_ProtoNode) return GF_BAD_PARAM;
inst = (GF_ProtoInstance *) node;
if (!inst->proto_interface) return GF_BAD_PARAM;
if (inst->flags & GF_SG_PROTO_LOADED) return GF_OK;
gf_sg_proto_instanciate(inst);
return GF_OK;
}
u32 gf_sg_proto_get_num_fields(GF_Node *node, u8 code_mode)
{
GF_ProtoInstance *proto;
if (!node) return 0;
proto = (GF_ProtoInstance *)node;
switch (code_mode) {
case GF_SG_FIELD_CODING_IN:
return proto->proto_interface ? proto->proto_interface->NumIn : 0;
case GF_SG_FIELD_CODING_OUT:
return proto->proto_interface ? proto->proto_interface->NumOut : 0;
case GF_SG_FIELD_CODING_DEF:
return proto->proto_interface ? proto->proto_interface->NumDef : 0;
case GF_SG_FIELD_CODING_ALL:
return gf_list_count(proto->proto_interface ? proto->proto_interface->proto_fields : proto->fields);
case GF_SG_FIELD_CODING_DYN:
default:
return 0;
}
}
void gf_sg_proto_del_instance(GF_ProtoInstance *inst)
{
GF_SceneGraph *sg;
GF_ProtoField *field;
GF_Node *node;
u32 index;
index = 0;
while (gf_list_count(inst->fields)) {
field = (GF_ProtoField *)gf_list_get(inst->fields, 0);
gf_list_rem(inst->fields, 0);
if ( (field->FieldType!=GF_SG_VRML_SFNODE) && (field->FieldType!=GF_SG_VRML_MFNODE)) {
gf_sg_vrml_field_pointer_del(field->field_pointer, field->FieldType);
}
else if (field->field_pointer) {
if (field->FieldType == GF_SG_VRML_SFNODE) {
gf_node_unregister((GF_Node *) field->field_pointer, (GF_Node *) inst);
} else {
GF_ChildNodeItem *list = (GF_ChildNodeItem *)field->field_pointer;
while (list) {
GF_ChildNodeItem *cur = list;
gf_node_unregister(list->node, (GF_Node *) inst);
list = list->next;
gf_free(cur);
}
}
}
gf_free(field);
index++;
}
gf_list_del(inst->fields);
while (gf_list_count(inst->node_code)) {
node = (GF_Node*)gf_list_get(inst->node_code, 0);
gf_node_unregister(node, (GF_Node*) inst);
gf_list_rem(inst->node_code, 0);
}
sg = inst->sgprivate->scenegraph;
gf_sg_reset(sg);
sg->pOwningProto = NULL;
gf_free((char *) inst->proto_name);
gf_list_del(inst->node_code);
assert(!gf_list_count(inst->scripts_to_load));
gf_list_del(inst->scripts_to_load);
if (inst->proto_interface && inst->proto_interface->instances) gf_list_del_item(inst->proto_interface->instances, inst);
gf_node_free((GF_Node *)inst);
gf_sg_del(sg);
}
GF_Err gf_sg_proto_field_set_ised(GF_Proto *proto, u32 protoFieldIndex, GF_Node *node, u32 nodeFieldIndex)
{
GF_Err e;
GF_Route *r;
GF_FieldInfo field, nodeField;
field.fieldIndex = protoFieldIndex;
e = gf_sg_proto_get_field(proto, NULL, &field);
if (e) return e;
e = gf_node_get_field(node, nodeFieldIndex, &nodeField);
if (e) return e;
if (field.fieldType != nodeField.fieldType) {
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)) {
} 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)) {
} else {
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_by_name(field.fieldType), gf_sg_vrml_get_field_type_by_name(nodeField.fieldType)));
return GF_SG_INVALID_PROTO;
}
}
GF_SAFEALLOC(r, GF_Route)
if (!r) return GF_OUT_OF_MEM;
r->IS_route = 1;
if (nodeField.eventType==GF_SG_EVENT_OUT) {
r->FromField.fieldIndex = nodeFieldIndex;
r->FromNode = node;
r->ToField.fieldIndex = protoFieldIndex;
r->ToNode = NULL;
if (!node->sgprivate->interact) {
GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
if (!node->sgprivate->interact) {
return GF_OUT_OF_MEM;
}
}
if (!node->sgprivate->interact->routes) node->sgprivate->interact->routes = gf_list_new();
gf_list_add(node->sgprivate->interact->routes, r);
} else {
switch (field.eventType) {
case GF_SG_EVENT_FIELD:
case GF_SG_EVENT_EXPOSED_FIELD:
case GF_SG_EVENT_IN:
r->FromField.fieldIndex = protoFieldIndex;
r->FromNode = NULL;
r->ToField.fieldIndex = nodeFieldIndex;
r->ToNode = node;
if ((field.eventType==GF_SG_EVENT_EXPOSED_FIELD) && (nodeField.eventType==GF_SG_EVENT_EXPOSED_FIELD)) {
GF_Route *r2;
GF_SAFEALLOC(r2, GF_Route);
if (!r2) {
gf_free(r);
return GF_OUT_OF_MEM;
}
r2->IS_route = 1;
r2->FromField.fieldIndex = nodeFieldIndex;
r2->FromNode = node;
r2->ToField.fieldIndex = protoFieldIndex;
r2->ToNode = NULL;
r2->graph = proto->sub_graph;
if (!node->sgprivate->interact) {
GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
if (!node->sgprivate->interact) return GF_OUT_OF_MEM;
}
if (!node->sgprivate->interact->routes) node->sgprivate->interact->routes = gf_list_new();
gf_list_add(node->sgprivate->interact->routes, r2);
gf_list_add(proto->sub_graph->Routes, r2);
}
break;
case GF_SG_EVENT_OUT:
r->FromField.fieldIndex = nodeFieldIndex;
r->FromNode = node;
r->ToField.fieldIndex = protoFieldIndex;
r->ToNode = NULL;
if (!node->sgprivate->interact) {
GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
if (!node->sgprivate->interact) return GF_OUT_OF_MEM;
}
if (!node->sgprivate->interact->routes) node->sgprivate->interact->routes = gf_list_new();
break;
default:
gf_free(r);
return GF_BAD_PARAM;
}
}
r->graph = proto->sub_graph;
return gf_list_add(proto->sub_graph->Routes, r);
}
GF_Err gf_sg_proto_instance_set_ised(GF_Node *protoinst, u32 protoFieldIndex, GF_Node *node, u32 nodeFieldIndex)
{
GF_Err e;
GF_Route *r;
GF_FieldInfo field, nodeField;
if (protoinst->sgprivate->tag != TAG_ProtoNode) return GF_BAD_PARAM;
e = gf_node_get_field(protoinst, protoFieldIndex, &field);
if (e) return e;
e = gf_node_get_field(node, nodeFieldIndex, &nodeField);
if (e) return e;
if (field.fieldType != nodeField.fieldType) {
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)) {
} 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)) {
} else {
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_by_name(field.fieldType), gf_sg_vrml_get_field_type_by_name(nodeField.fieldType)));
return GF_SG_INVALID_PROTO;
}
}
GF_SAFEALLOC(r, GF_Route)
if (!r) return GF_OUT_OF_MEM;
r->IS_route = 1;
if (nodeField.eventType==GF_SG_EVENT_OUT) {
r->FromField.fieldIndex = nodeFieldIndex;
r->FromNode = node;
r->ToField.fieldIndex = protoFieldIndex;
r->ToNode = protoinst;
if (!node->sgprivate->interact) {
GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
if (!node->sgprivate->interact) return GF_OUT_OF_MEM;
}
if (!node->sgprivate->interact->routes) node->sgprivate->interact->routes = gf_list_new();
gf_list_add(node->sgprivate->interact->routes, r);
} else {
switch (field.eventType) {
case GF_SG_EVENT_FIELD:
case GF_SG_EVENT_EXPOSED_FIELD:
case GF_SG_EVENT_IN:
r->FromField.fieldIndex = protoFieldIndex;
r->FromNode = protoinst;
r->ToField.fieldIndex = nodeFieldIndex;
r->ToNode = node;
if ((field.eventType==GF_SG_EVENT_EXPOSED_FIELD) && (nodeField.eventType==GF_SG_EVENT_EXPOSED_FIELD)) {
GF_Route *r2;
GF_SAFEALLOC(r2, GF_Route);
if (!r2) {
gf_free(r);
return GF_OUT_OF_MEM;
}
r2->IS_route = 1;
r2->FromField.fieldIndex = nodeFieldIndex;
r2->FromNode = node;
r2->ToField.fieldIndex = protoFieldIndex;
r2->ToNode = protoinst;
r2->graph = node->sgprivate->scenegraph;
if (!node->sgprivate->interact) {
GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
if (!node->sgprivate->interact) return GF_OUT_OF_MEM;
}
if (!node->sgprivate->interact->routes) node->sgprivate->interact->routes = gf_list_new();
gf_list_add(node->sgprivate->interact->routes, r2);
gf_list_add(r->graph->Routes, r2);
}
break;
case GF_SG_EVENT_OUT:
r->FromField.fieldIndex = nodeFieldIndex;
r->FromNode = node;
r->ToField.fieldIndex = protoFieldIndex;
r->ToNode = protoinst;
if (!node->sgprivate->interact) {
GF_SAFEALLOC(node->sgprivate->interact, struct _node_interactive_ext);
if (!node->sgprivate->interact) return GF_OUT_OF_MEM;
}
if (!node->sgprivate->interact->routes) node->sgprivate->interact->routes = gf_list_new();
gf_list_add(node->sgprivate->interact->routes, r);
break;
default:
gf_free(r);
return GF_BAD_PARAM;
}
}
r->graph = node->sgprivate->scenegraph;
gf_sg_route_activate(r);
return gf_list_add(r->graph->Routes, r);
}
GF_Err gf_bifs_proto_field_set_aq_info(GF_ProtoFieldInterface *field,
u32 QP_Type,
u32 hasMinMax,
u32 QPSFType,
void *qp_min_value,
void *qp_max_value,
u32 QP13_NumBits)
{
if (!field) return GF_BAD_PARAM;
if (!QP_Type) return GF_OK;
if (!gf_sg_vrml_is_sf_field(QPSFType)) return GF_BAD_PARAM;
field->QP_Type = QP_Type;
field->hasMinMax = hasMinMax;
if (hasMinMax) {
if (qp_min_value) {
field->qp_min_value = gf_sg_vrml_field_pointer_new(QPSFType);
gf_sg_vrml_field_copy(field->qp_min_value, qp_min_value, QPSFType);
}
if (qp_max_value) {
field->qp_max_value = gf_sg_vrml_field_pointer_new(QPSFType);
gf_sg_vrml_field_copy(field->qp_max_value, qp_max_value, QPSFType);
}
}
field->NumBits = QP13_NumBits;
return GF_OK;
}
GF_Err gf_sg_proto_get_field_index(GF_ProtoInstance *proto, u32 index, u32 code_mode, u32 *all_index)
{
u32 i;
GF_ProtoFieldInterface *proto_field;
i=0;
while ((proto_field = (GF_ProtoFieldInterface*)gf_list_enum(proto->proto_interface->proto_fields, &i))) {
assert(proto_field);
switch (code_mode) {
case GF_SG_FIELD_CODING_IN:
if (proto_field->IN_index == index) {
*all_index = proto_field->ALL_index;
return GF_OK;
}
break;
case GF_SG_FIELD_CODING_OUT:
if (proto_field->OUT_index == index) {
*all_index = proto_field->ALL_index;
return GF_OK;
}
break;
case GF_SG_FIELD_CODING_DEF:
if (proto_field->DEF_index == index) {
*all_index = proto_field->ALL_index;
return GF_OK;
}
break;
case GF_SG_FIELD_CODING_ALL:
if (proto_field->ALL_index == index) {
*all_index = proto_field->ALL_index;
return GF_OK;
}
break;
case GF_SG_FIELD_CODING_DYN:
default:
return GF_BAD_PARAM;
}
}
return GF_BAD_PARAM;
}
u32 gf_sg_proto_get_field_count(GF_Proto *proto)
{
if (!proto) return 0;
return gf_list_count(proto->proto_fields);
}
GF_ProtoFieldInterface *gf_sg_proto_field_find(GF_Proto *proto, u32 fieldIndex)
{
if (!proto) return NULL;
return (GF_ProtoFieldInterface*)gf_list_get(proto->proto_fields, fieldIndex);
}
void gf_sg_proto_propagate_event(GF_Node *node, u32 fieldIndex, GF_Node *from_node)
{
u32 i;
GF_Route *r;
if (!node) return;
if (node->sgprivate->tag != TAG_ProtoNode) return;
if (!node->sgprivate->interact || !node->sgprivate->interact->routes) return;
if (from_node->sgprivate->scenegraph == node->sgprivate->scenegraph) return;
i=0;
while ((r = (GF_Route*)gf_list_enum(node->sgprivate->interact->routes, &i))) {
if (!r->IS_route) continue;
if ((r->FromNode == node) && (r->FromField.fieldIndex == fieldIndex) && (r->ToNode != from_node) ) {
if (gf_sg_route_activate(r))
gf_node_changed(r->ToNode, &r->ToField);
}
}
}
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)
{
GF_Proto *proto;
u32 i;
GF_ProtoFieldInterface *proto_field;
proto = ((GF_ProtoInstance *)Node)->proto_interface;
i=0;
while ((proto_field = (GF_ProtoFieldInterface*)gf_list_enum(proto->proto_fields, &i))) {
if (proto_field->ALL_index!=FieldIndex) continue;
*QType = proto_field->QP_Type;
*AType = proto_field->Anim_Type;
*b_min = FIX_MIN;
*b_max = FIX_MAX;
if (proto_field->hasMinMax) {
switch (gf_sg_vrml_get_sf_type(proto_field->FieldType)) {
case GF_SG_VRML_SFINT32:
*b_min = (SFFloat) * ( (SFInt32 *) proto_field->qp_min_value);
*b_max = (SFFloat) * ( (SFInt32 *) proto_field->qp_max_value);
break;
case GF_SG_VRML_SFTIME:
*b_min = (SFFloat) * ( (SFTime *) proto_field->qp_min_value);
*b_max = (SFFloat) * ( (SFTime *) proto_field->qp_max_value);
break;
default:
if (proto_field->qp_min_value)
*b_min = (SFFloat) * ( (SFFloat *) proto_field->qp_min_value);
if (proto_field->qp_max_value)
*b_max = (SFFloat) * ( (SFFloat *) proto_field->qp_max_value);
break;
}
}
*QT13_bits = proto_field->NumBits;
return 1;
}
return 0;
}
GF_EXPORT
GF_Proto *gf_node_get_proto(GF_Node *node)
{
GF_ProtoInstance *inst;
if (node->sgprivate->tag != TAG_ProtoNode) return NULL;
inst = (GF_ProtoInstance *) node;
return inst->proto_interface;
}
u32 gf_sg_proto_get_id(GF_Proto *proto)
{
return proto->ID;
}
const char *gf_sg_proto_get_class_name(GF_Proto *proto)
{
return (const char *) proto->Name;
}
u32 gf_sg_proto_get_root_tag(GF_Proto *proto)
{
GF_Node *n;
if (!proto) return TAG_UndefinedNode;
n = (GF_Node*)gf_list_get(proto->node_code, 0);
if (!n) return TAG_UndefinedNode;
if (n->sgprivate->tag == TAG_ProtoNode) return gf_sg_proto_get_root_tag(((GF_ProtoInstance *)n)->proto_interface);
return n->sgprivate->tag;
}
Bool gf_sg_proto_field_is_sftime_offset(GF_Node *node, GF_FieldInfo *field)
{
u32 i;
GF_Route *r;
GF_ProtoInstance *inst;
GF_FieldInfo inf;
if (node->sgprivate->tag != TAG_ProtoNode) return 0;
if (field->fieldType != GF_SG_VRML_SFTIME) return 0;
inst = (GF_ProtoInstance *) node;
i=0;
while ((r = (GF_Route*)gf_list_enum(inst->proto_interface->sub_graph->Routes, &i))) {
if (!r->IS_route) continue;
if (r->FromNode || (r->FromField.fieldIndex != field->fieldIndex)) continue;
gf_node_get_field(r->ToNode, r->ToField.fieldIndex, &inf);
if (r->ToNode->sgprivate->tag == TAG_ProtoNode) return gf_sg_proto_field_is_sftime_offset(r->ToNode, &inf);
if (!stricmp(inf.name, "startTime") || !stricmp(inf.name, "stopTime")) return 1;
}
return 0;
}
GF_SceneGraph *Node_GetExternProtoScene(GF_Node *node)
{
GF_SceneGraph *sg;
sg = node->sgprivate->scenegraph;
if (!sg->pOwningProto) return NULL;
if (!sg->pOwningProto->proto_interface->ExternProto.count) return NULL;
sg = sg->pOwningProto->proto_interface->parent_graph;
while (sg->parent_scene) sg = sg->parent_scene;
return sg;
}
GF_EXPORT
GF_Err gf_node_proto_set_grouping(GF_Node *node)
{
if (!node || (node->sgprivate->tag!=TAG_ProtoNode)) return GF_BAD_PARAM;
((GF_ProtoInstance *)node)->flags |= GF_SG_PROTO_IS_GROUPING;
return GF_OK;
}
GF_EXPORT
Bool gf_node_proto_is_grouping(GF_Node *node)
{
if (!node || (node->sgprivate->tag!=TAG_ProtoNode)) return 0;
if ( ((GF_ProtoInstance *)node)->flags & GF_SG_PROTO_IS_GROUPING) return 1;
return 0;
}
GF_EXPORT
GF_Node *gf_node_get_proto_root(GF_Node *node)
{
if (!node || (node->sgprivate->tag!=TAG_ProtoNode)) return NULL;
return ((GF_ProtoInstance *)node)->RenderingNode;
}
GF_EXPORT
GF_Node *gf_node_get_proto_parent(GF_Node *node)
{
if (!node) return NULL;
if (node->sgprivate->scenegraph->pOwningProto) {
GF_Node *the_node = (GF_Node *) node->sgprivate->scenegraph->pOwningProto;
if (the_node != node) return the_node;
}
return NULL;
}
GF_EXPORT
Bool gf_node_is_proto_root(GF_Node *node)
{
if (!node) return 0;
if (!node->sgprivate->scenegraph->pOwningProto) return 0;
if (gf_list_find(node->sgprivate->scenegraph->pOwningProto->node_code, node)>=0) return 1;
return 0;
}
GF_EXPORT
GF_Err gf_node_set_proto_eventin_handler(GF_Node *node, u32 fieldIndex, void (*event_in_cbk)(GF_Node *pThis, struct _route *route) )
{
GF_ProtoInstance *inst;
GF_ProtoField *field;
if (!node || (node->sgprivate->tag!=TAG_ProtoNode)) return GF_BAD_PARAM;
inst = (GF_ProtoInstance *) node;
field = (GF_ProtoField*)gf_list_get(inst->fields, fieldIndex);
if (!field) return GF_BAD_PARAM;
if (field->EventType!=GF_SG_EVENT_IN) return GF_BAD_PARAM;
field->on_event_in = event_in_cbk;
return GF_OK;
}
#endif