| /* | |
| * GPAC - Multimedia Framework C SDK | |
| * | |
| * Authors: Jean Le Feuvre | |
| * Copyright (c) Telecom ParisTech 2000-2026 | |
| * All rights reserved | |
| * | |
| * This file is part of GPAC / Scene Management sub-project | |
| * | |
| * GPAC is free software; you can redistribute it and/or modify | |
| * it under the terms of the GNU Lesser General Public License as published by | |
| * the Free Software Foundation; either version 2, or (at your option) | |
| * any later version. | |
| * | |
| * GPAC is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| * GNU Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; see the file COPYING. If not, write to | |
| * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
| * | |
| */ | |
| #include <gpac/scene_manager.h> | |
| #include <gpac/constants.h> | |
| #include <gpac/utf.h> | |
| #include <gpac/internal/scenegraph_dev.h> | |
| #include <gpac/nodes_x3d.h> | |
| #include <gpac/nodes_svg.h> | |
| #include <gpac/events.h> | |
| #include <gpac/base_coding.h> | |
| #ifndef __SYMBIAN32__ | |
| #include <wchar.h> | |
| #endif | |
| #ifndef GPAC_DISABLE_SCENE_DUMP | |
| /*for QP types*/ | |
| #include "../bifs/quant.h" | |
| struct _scenedump | |
| { | |
| /*the scene we're dumping - set at each SceneReplace or mannually*/ | |
| GF_SceneGraph *sg; | |
| #ifndef GPAC_DISABLE_VRML | |
| /*the proto we're dumping*/ | |
| GF_Proto *current_proto; | |
| #endif | |
| FILE *trace; | |
| u32 indent; | |
| char *filename; | |
| GF_SceneDumpFormat dump_mode; | |
| u16 CurrentESID; | |
| u8 ind_char; | |
| Bool XMLDump, X3DDump, LSRDump; | |
| GF_List *dump_nodes; | |
| /*nodes created through conditionals while parsing but not applied*/ | |
| GF_List *mem_def_nodes; | |
| Bool skip_scene_replace; | |
| /*for route insert/replace in conditionals in current scene replace*/ | |
| GF_List *current_com_list; | |
| GF_List *inserted_routes; | |
| Bool in_text; | |
| }; | |
| static GF_Err gf_dump_vrml_route(GF_SceneDumper *sdump, GF_Route *r, u32 dump_type); | |
| static void gf_dump_vrml_node(GF_SceneDumper *sdump, GF_Node *node, Bool in_list, char *fieldContainer); | |
| #ifndef GPAC_DISABLE_SVG | |
| void gf_dump_svg_element(GF_SceneDumper *sdump, GF_Node *n, GF_Node *parent, Bool is_root); | |
| #endif | |
| GF_EXPORT | |
| GF_SceneDumper *gf_sm_dumper_new(GF_SceneGraph *graph, char *_rad_name, Bool is_final_name, char indent_char, GF_SceneDumpFormat dump_mode) | |
| { | |
| GF_SceneDumper *tmp; | |
| if (!graph) return NULL; | |
| GF_SAFEALLOC(tmp, GF_SceneDumper); | |
| if (!tmp) return NULL; | |
| /*store original*/ | |
| tmp->dump_mode = dump_mode; | |
| #ifndef GPAC_DISABLE_SVG | |
| if ((graph->RootNode && (graph->RootNode->sgprivate->tag>=GF_NODE_RANGE_LAST_VRML) ) | |
| || (dump_mode==GF_SM_DUMP_LASER) || (dump_mode==GF_SM_DUMP_SVG)) { | |
| tmp->XMLDump = GF_TRUE; | |
| if (dump_mode==GF_SM_DUMP_LASER) { | |
| tmp->LSRDump = GF_TRUE; | |
| } | |
| if (_rad_name) { | |
| const char* ext_name = tmp->LSRDump ? ".xsr" : ".svg"; | |
| tmp->filename = gf_strdup(_rad_name); | |
| if (!is_final_name) gf_dynstrcat(&tmp->filename, ext_name, NULL); | |
| tmp->trace = gf_fopen(tmp->filename, "wt"); | |
| if (!tmp->trace) { | |
| gf_free(tmp); | |
| return NULL; | |
| } | |
| } else { | |
| tmp->trace = stdout; | |
| } | |
| } else | |
| #endif | |
| { | |
| if (dump_mode==GF_SM_DUMP_AUTO_TXT) { | |
| if (!graph->RootNode || (graph->RootNode->sgprivate->tag<=GF_NODE_RANGE_LAST_MPEG4) ) { | |
| dump_mode = GF_SM_DUMP_BT; | |
| } else if (graph->RootNode->sgprivate->tag<=GF_NODE_RANGE_LAST_X3D) { | |
| dump_mode = GF_SM_DUMP_X3D_VRML; | |
| } | |
| } | |
| else if (dump_mode==GF_SM_DUMP_AUTO_XML) { | |
| if (!graph->RootNode || (graph->RootNode->sgprivate->tag<=GF_NODE_RANGE_LAST_MPEG4) ) { | |
| dump_mode = GF_SM_DUMP_XMTA; | |
| } else { | |
| dump_mode = GF_SM_DUMP_X3D_XML; | |
| } | |
| } | |
| if (_rad_name) { | |
| const char* ext_name; | |
| switch (dump_mode) { | |
| case GF_SM_DUMP_X3D_XML: | |
| ext_name = ".x3d"; | |
| tmp->XMLDump = GF_TRUE; | |
| tmp->X3DDump = GF_TRUE; | |
| break; | |
| case GF_SM_DUMP_XMTA: | |
| ext_name = ".xmt"; | |
| tmp->XMLDump = GF_TRUE; | |
| break; | |
| case GF_SM_DUMP_X3D_VRML: | |
| ext_name = ".x3dv"; | |
| tmp->X3DDump = GF_TRUE; | |
| break; | |
| case GF_SM_DUMP_VRML: | |
| ext_name = ".wrl"; | |
| break; | |
| default: | |
| ext_name = ".bt"; | |
| break; | |
| } | |
| tmp->filename = NULL; | |
| if (_rad_name) tmp->filename = gf_strdup(_rad_name); | |
| if (!is_final_name) gf_dynstrcat(&tmp->filename, ext_name, NULL); | |
| tmp->trace = gf_fopen(tmp->filename, "wt"); | |
| if (!tmp->trace) { | |
| gf_free(tmp->filename); | |
| gf_free(tmp); | |
| return NULL; | |
| } | |
| } else { | |
| tmp->trace = stdout; | |
| switch (dump_mode) { | |
| case GF_SM_DUMP_X3D_XML: | |
| tmp->XMLDump = GF_TRUE; | |
| tmp->X3DDump = GF_TRUE; | |
| break; | |
| case GF_SM_DUMP_XMTA: | |
| tmp->XMLDump = GF_TRUE; | |
| break; | |
| case GF_SM_DUMP_X3D_VRML: | |
| tmp->X3DDump = GF_TRUE; | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| } | |
| tmp->ind_char = indent_char; | |
| tmp->dump_nodes = gf_list_new(); | |
| tmp->mem_def_nodes = gf_list_new(); | |
| tmp->inserted_routes = gf_list_new(); | |
| tmp->sg = graph; | |
| return tmp; | |
| } | |
| GF_EXPORT | |
| void gf_sm_dumper_set_extra_graph(GF_SceneDumper *sdump, GF_SceneGraph *extra) | |
| { | |
| sdump->sg = extra; | |
| } | |
| GF_EXPORT | |
| void gf_sm_dumper_del(GF_SceneDumper *sdump) | |
| { | |
| gf_list_del(sdump->dump_nodes); | |
| while (gf_list_count(sdump->mem_def_nodes)) { | |
| GF_Node *tmp = (GF_Node *)gf_list_get(sdump->mem_def_nodes, 0); | |
| gf_list_rem(sdump->mem_def_nodes, 0); | |
| gf_node_unregister(tmp, NULL); | |
| } | |
| gf_list_del(sdump->mem_def_nodes); | |
| gf_list_del(sdump->inserted_routes); | |
| if (sdump->trace != stdout) gf_fclose(sdump->trace); | |
| if (sdump->filename) { | |
| gf_free(sdump->filename); | |
| sdump->filename = NULL; | |
| } | |
| gf_free(sdump); | |
| } | |
| char *gf_sm_dump_get_name(GF_SceneDumper *bd) | |
| { | |
| if (!bd) return NULL; | |
| return bd->filename; | |
| } | |
| static void gf_dump_setup(GF_SceneDumper *sdump, GF_Descriptor *root_od) | |
| { | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); | |
| if (sdump->dump_mode==GF_SM_DUMP_XML) return; | |
| gf_fprintf(sdump->trace, "<!-- %s Scene Dump -->\n", | |
| (sdump->dump_mode==GF_SM_DUMP_SVG) ? "SVG" : | |
| (sdump->dump_mode==GF_SM_DUMP_LASER) ? "LASeR" : | |
| sdump->X3DDump ? "X3D" : "XMT-A" | |
| ); | |
| } | |
| if (sdump->dump_mode==GF_SM_DUMP_SVG) return; | |
| if (sdump->LSRDump) { | |
| gf_fprintf(sdump->trace, "<saf:SAFSession xmlns:saf=\"urn:mpeg:mpeg4:SAF:2005\" >\n"); | |
| #ifndef GPAC_DISABLE_OD_DUMP | |
| if (root_od) { | |
| GF_ObjectDescriptor *iod = (GF_ObjectDescriptor *)root_od; | |
| u32 i, count; | |
| gf_fprintf(sdump->trace, "<saf:sceneHeader>\n"); | |
| count = gf_list_count(iod->ESDescriptors); | |
| for (i=0; i<count; i++) { | |
| GF_LASERConfig lsrcfg; | |
| GF_ESD *esd = (GF_ESD *)gf_list_get(iod->ESDescriptors, i); | |
| if (!esd || !esd->decoderConfig) continue; | |
| if (esd->decoderConfig->streamType != GF_STREAM_SCENE) continue; | |
| if (esd->decoderConfig->objectTypeIndication != 0x09) continue; | |
| if (!esd->decoderConfig->decoderSpecificInfo || !esd->decoderConfig->decoderSpecificInfo->data) continue; | |
| gf_odf_get_laser_config(esd->decoderConfig->decoderSpecificInfo, &lsrcfg); | |
| gf_odf_dump_desc((GF_Descriptor*)&lsrcfg, sdump->trace, 1, 1); | |
| } | |
| gf_fprintf(sdump->trace, "</saf:sceneHeader>\n"); | |
| } | |
| #endif | |
| return; | |
| } | |
| if (!sdump->X3DDump) { | |
| /*setup XMT*/ | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "<XMT-A xmlns=\"urn:mpeg:mpeg4:xmta:schema:2002\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:mpeg:mpeg4:xmta:schema:2002 xmt-a.xsd\">\n"); | |
| gf_fprintf(sdump->trace, " <Header>\n"); | |
| #ifndef GPAC_DISABLE_OD_DUMP | |
| if (root_od) gf_odf_dump_desc(root_od, sdump->trace, 1, 1); | |
| #endif | |
| gf_fprintf(sdump->trace, " </Header>\n"); | |
| gf_fprintf(sdump->trace, " <Body>\n"); | |
| if (!root_od) { | |
| gf_fprintf(sdump->trace, " <Replace>\n"); | |
| } | |
| } else { | |
| if (sdump->dump_mode==GF_SM_DUMP_VRML) { | |
| gf_fprintf(sdump->trace, "#VRML V2.0\n"); | |
| } else { | |
| /*dump root OD*/ | |
| #ifndef GPAC_DISABLE_OD_DUMP | |
| if (root_od) gf_odf_dump_desc(root_od, sdump->trace, 0, 0); | |
| #endif | |
| } | |
| gf_fprintf(sdump->trace, "\n"); | |
| } | |
| } else { | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "<!DOCTYPE X3D PUBLIC \"ISO//Web3D//DTD X3D 3.0//EN\" \"http://www.web3d.org/specifications/x3d-3.0.dtd\">\n"); | |
| gf_fprintf(sdump->trace, "<X3D xmlns:xsd=\"http://www.w3.org/2001/XMLSchema-instance\" xsd:noNamespaceSchemaLocation=\"http://www.web3d.org/specifications/x3d-3.0.xsd\" version=\"3.0\">\n"); | |
| gf_fprintf(sdump->trace, "<head>\n"); | |
| gf_fprintf(sdump->trace, "<meta content=\"X3D File Converted/Dumped by GPAC Version %s - %s\" name=\"generator\"/>\n", gf_gpac_version(), gf_gpac_copyright() ); | |
| gf_fprintf(sdump->trace, "</head>\n"); | |
| gf_fprintf(sdump->trace, " <Scene>\n"); | |
| } else { | |
| gf_fprintf(sdump->trace, "#X3D V3.0\n\n"); | |
| } | |
| } | |
| } | |
| static void gf_dump_finalize(GF_SceneDumper *sdump, GF_Descriptor *root_od) | |
| { | |
| if (sdump->dump_mode==GF_SM_DUMP_SVG) return; | |
| if (sdump->LSRDump) { | |
| gf_fprintf(sdump->trace, "<saf:endOfSAFSession/>\n</saf:SAFSession>\n"); | |
| return; | |
| } | |
| if (!sdump->XMLDump) return; | |
| if (!sdump->X3DDump) { | |
| if (!root_od) { | |
| gf_fprintf(sdump->trace, " </Replace>\n"); | |
| } | |
| gf_fprintf(sdump->trace, " </Body>\n"); | |
| gf_fprintf(sdump->trace, "</XMT-A>\n"); | |
| } else { | |
| gf_fprintf(sdump->trace, " </Scene>\n"); | |
| gf_fprintf(sdump->trace, "</X3D>\n"); | |
| } | |
| } | |
| static Bool gf_dump_vrml_is_def_node(GF_SceneDumper *sdump, GF_Node *node) | |
| { | |
| s32 i = gf_list_find(sdump->dump_nodes, node); | |
| if (i>=0) return 0; | |
| gf_list_add(sdump->dump_nodes, node); | |
| return 1; | |
| } | |
| static GF_Node *gf_dump_find_node(GF_SceneDumper *sdump, u32 ID) | |
| { | |
| GF_Node *ret = gf_sg_find_node(sdump->sg, ID); | |
| if (ret) return ret; | |
| return NULL; | |
| } | |
| #define DUMP_IND(sdump) \ | |
| if (sdump->trace) { \ | |
| u32 z; \ | |
| for (z=0; z<sdump->indent; z++) gf_fprintf(sdump->trace, "%c", sdump->ind_char); \ | |
| } | |
| static void StartElement(GF_SceneDumper *sdump, const char *name) | |
| { | |
| if (!sdump->trace) return; | |
| DUMP_IND(sdump); | |
| if (!sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "%s {\n", name); | |
| } else { | |
| gf_fprintf(sdump->trace, "<%s", name); | |
| } | |
| } | |
| static void EndElementHeader(GF_SceneDumper *sdump, Bool has_sub_el) | |
| { | |
| if (!sdump->trace) return; | |
| if (sdump->XMLDump) { | |
| if (has_sub_el) { | |
| gf_fprintf(sdump->trace, ">\n"); | |
| } else { | |
| gf_fprintf(sdump->trace, "/>\n"); | |
| } | |
| } | |
| } | |
| static void EndElement(GF_SceneDumper *sdump, const char *name, Bool had_sub_el) | |
| { | |
| if (!sdump->trace) return; | |
| if (!sdump->XMLDump) { | |
| DUMP_IND(sdump); | |
| gf_fprintf(sdump->trace, "}\n"); | |
| } else { | |
| if (had_sub_el) { | |
| DUMP_IND(sdump); | |
| gf_fprintf(sdump->trace, "</%s>\n", name); | |
| } | |
| } | |
| } | |
| static void StartAttribute(GF_SceneDumper *sdump, const char *name) | |
| { | |
| if (!sdump->trace) return; | |
| if (!sdump->XMLDump) { | |
| DUMP_IND(sdump); | |
| gf_fprintf(sdump->trace, "%s ", name); | |
| } else { | |
| gf_fprintf(sdump->trace, " %s=\"", name); | |
| } | |
| } | |
| static void EndAttribute(GF_SceneDumper *sdump) | |
| { | |
| if (!sdump->trace) return; | |
| if (!sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "\n"); | |
| } else { | |
| gf_fprintf(sdump->trace, "\""); | |
| } | |
| } | |
| static void StartList(GF_SceneDumper *sdump, const char *name) | |
| { | |
| if (!sdump->trace) return; | |
| DUMP_IND(sdump); | |
| if (!sdump->XMLDump) { | |
| if (name) | |
| gf_fprintf(sdump->trace, "%s [\n", name); | |
| else | |
| gf_fprintf(sdump->trace, "[\n"); | |
| } else { | |
| gf_fprintf(sdump->trace, "<%s>\n", name); | |
| } | |
| } | |
| static void EndList(GF_SceneDumper *sdump, const char *name) | |
| { | |
| if (!sdump->trace) return; | |
| DUMP_IND(sdump); | |
| if (!sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "]\n"); | |
| } else { | |
| gf_fprintf(sdump->trace, "</%s>\n", name); | |
| } | |
| } | |
| static void scene_dump_utf_string(GF_SceneDumper *sdump, Bool escape_xml, char *str) | |
| { | |
| u32 len, i; | |
| u16 *uniLine; | |
| if (!str) return; | |
| len = 1 + (u32) strlen(str); | |
| if (!len) return; | |
| uniLine = (u16*)gf_malloc(sizeof(u16) * len*4); | |
| len = gf_utf8_mbstowcs(uniLine, len, (const char **) &str); | |
| if (len != GF_UTF8_FAIL) { | |
| for (i=0; i<len; i++) { | |
| //if (uniLine[i] == (u16) '\"') gf_fprintf(sdump->trace, "\\"); | |
| switch (uniLine[i]) { | |
| case '\'': | |
| if (escape_xml) gf_fprintf(sdump->trace, "'"); | |
| else gf_fprintf(sdump->trace, "'"); | |
| break; | |
| case '\"': | |
| if (escape_xml) gf_fprintf(sdump->trace, """); | |
| else gf_fprintf(sdump->trace, "\""); | |
| break; | |
| case '&': | |
| gf_fprintf(sdump->trace, "&"); | |
| break; | |
| case '>': | |
| gf_fprintf(sdump->trace, ">"); | |
| break; | |
| case '<': | |
| gf_fprintf(sdump->trace, "<"); | |
| break; | |
| case '\r': | |
| case '\n': | |
| /* Does nothing : gf_fprintf(sdump->trace, "");, fflush instead ?*/ | |
| break; | |
| default: | |
| if (uniLine[i]<128) { | |
| gf_fprintf(sdump->trace, "%c", (u8) uniLine[i]); | |
| } else { | |
| gf_fprintf(sdump->trace, "&#%d;", uniLine[i]); | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| gf_free(uniLine); | |
| } | |
| #ifndef GPAC_DISABLE_VRML | |
| static void scene_dump_vrml_id(GF_SceneDumper *sdump, GF_Node *node) | |
| { | |
| u32 id; | |
| const char *node_name; | |
| if (!sdump->trace) return; | |
| /*FIXME - optimize id/name fetch*/ | |
| node_name = gf_node_get_name_and_id(node, &id); | |
| if (node_name) | |
| gf_fprintf(sdump->trace, "%s", node_name); | |
| else | |
| gf_fprintf(sdump->trace, "N%d", id - 1); | |
| } | |
| static Bool scene_dump_vrml_find_route_name(GF_SceneDumper *sdump, u32 ID, const char **outName) | |
| { | |
| GF_Route *r; | |
| u32 i; | |
| GF_Command *com; | |
| r = gf_sg_route_find(sdump->sg, ID); | |
| if (r) { | |
| (*outName) = r->name; | |
| return 1; | |
| } | |
| i=0; | |
| while ((com = (GF_Command *)gf_list_enum(sdump->inserted_routes, &i))) { | |
| if (com->tag == GF_SG_ROUTE_INSERT) { | |
| if (com->RouteID==ID) { | |
| (*outName) = com->def_name; | |
| return 1; | |
| } | |
| } | |
| } | |
| if (!sdump->current_com_list) return 0; | |
| i=1; | |
| while ((com = (GF_Command *)gf_list_enum(sdump->current_com_list, &i))) { | |
| if ((com->tag == GF_SG_ROUTE_INSERT) || (com->tag == GF_SG_ROUTE_REPLACE)) { | |
| if (com->RouteID==ID) { | |
| (*outName) = com->def_name; | |
| return 1; | |
| } | |
| } else return 0; | |
| } | |
| return 0; | |
| } | |
| static void scene_dump_vrml_route_id(GF_SceneDumper *sdump, u32 routeID, char *rName) | |
| { | |
| if (!sdump->trace) return; | |
| if (!rName) scene_dump_vrml_find_route_name(sdump, routeID, (const char **) &rName); | |
| if (rName) | |
| gf_fprintf(sdump->trace, "%s", rName); | |
| else | |
| gf_fprintf(sdump->trace, "R%d", routeID - 1); | |
| } | |
| static void gf_dump_vrml_sffield(GF_SceneDumper *sdump, u32 type, void *ptr, Bool is_mf, GF_Node *node) | |
| { | |
| switch (type) { | |
| case GF_SG_VRML_SFBOOL: | |
| gf_fprintf(sdump->trace, "%s", * ((SFBool *)ptr) ? "true" : "false"); | |
| break; | |
| case GF_SG_VRML_SFINT32: | |
| gf_fprintf(sdump->trace, "%d", * ((SFInt32 *)ptr) ); | |
| break; | |
| case GF_SG_VRML_SFFLOAT: | |
| gf_fprintf(sdump->trace, "%g", FIX2FLT( * ((SFFloat *)ptr) ) ); | |
| break; | |
| case GF_SG_VRML_SFDOUBLE: | |
| gf_fprintf(sdump->trace, "%g", * ((SFDouble *)ptr) ); | |
| break; | |
| case GF_SG_VRML_SFTIME: | |
| gf_fprintf(sdump->trace, "%g", * ((SFTime *)ptr) ); | |
| break; | |
| case GF_SG_VRML_SFCOLOR: | |
| gf_fprintf(sdump->trace, "%g %g %g", FIX2FLT( ((SFColor *)ptr)->red ), FIX2FLT( ((SFColor *)ptr)->green ), FIX2FLT( ((SFColor *)ptr)->blue )); | |
| break; | |
| case GF_SG_VRML_SFCOLORRGBA: | |
| gf_fprintf(sdump->trace, "%g %g %g %g", FIX2FLT( ((SFColorRGBA *)ptr)->red ), FIX2FLT( ((SFColorRGBA *)ptr)->green ), FIX2FLT( ((SFColorRGBA *)ptr)->blue ), FIX2FLT( ((SFColorRGBA *)ptr)->alpha )); | |
| break; | |
| case GF_SG_VRML_SFVEC2F: | |
| gf_fprintf(sdump->trace, "%g %g", FIX2FLT( ((SFVec2f *)ptr)->x ), FIX2FLT( ((SFVec2f *)ptr)->y )); | |
| break; | |
| case GF_SG_VRML_SFVEC2D: | |
| gf_fprintf(sdump->trace, "%g %g", ((SFVec2d *)ptr)->x, ((SFVec2d *)ptr)->y); | |
| break; | |
| case GF_SG_VRML_SFVEC3F: | |
| gf_fprintf(sdump->trace, "%g %g %g", FIX2FLT( ((SFVec3f *)ptr)->x ), FIX2FLT( ((SFVec3f *)ptr)->y ), FIX2FLT( ((SFVec3f *)ptr)->z )); | |
| break; | |
| case GF_SG_VRML_SFVEC3D: | |
| gf_fprintf(sdump->trace, "%g %g %g", ((SFVec3d *)ptr)->x, ((SFVec3d *)ptr)->y, ((SFVec3d *)ptr)->z); | |
| break; | |
| case GF_SG_VRML_SFROTATION: | |
| gf_fprintf(sdump->trace, "%g %g %g %g", FIX2FLT( ((SFRotation *)ptr)->x ), FIX2FLT( ((SFRotation *)ptr)->y ), FIX2FLT( ((SFRotation *)ptr)->z ), FIX2FLT( ((SFRotation *)ptr)->q ) ); | |
| break; | |
| case GF_SG_VRML_SFATTRREF: | |
| { | |
| SFAttrRef *ar = (SFAttrRef *)ptr; | |
| if (ar->node) { | |
| GF_FieldInfo pinfo; | |
| gf_node_get_field(ar->node, ar->fieldIndex, &pinfo); | |
| scene_dump_vrml_id(sdump, ar->node); | |
| gf_fprintf(sdump->trace, ".%s", pinfo.name); | |
| } | |
| } | |
| break; | |
| case GF_SG_VRML_SFSCRIPT: | |
| { | |
| u32 len, i; | |
| char *str; | |
| str = (char*)((SFScript *)ptr)->script_text; | |
| if (!str) { | |
| if (!sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "\"\""); | |
| } | |
| break; | |
| } | |
| len = (u32)strlen(str); | |
| if (!sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "\"%s\"", str); | |
| } | |
| else { | |
| u16 *uniLine = (u16*)gf_malloc(sizeof(u16) * ((len/2)*2 + 2)); | |
| len = gf_utf8_mbstowcs(uniLine, len+1, (const char **)&str); | |
| if (len != GF_UTF8_FAIL) { | |
| for (i = 0; i<len; i++) { | |
| switch (uniLine[i]) { | |
| case '&': | |
| gf_fprintf(sdump->trace, "&"); | |
| break; | |
| case '<': | |
| gf_fprintf(sdump->trace, "<"); | |
| break; | |
| case '>': | |
| gf_fprintf(sdump->trace, ">"); | |
| break; | |
| case '\'': | |
| case '"': | |
| gf_fprintf(sdump->trace, "'"); | |
| break; | |
| case 0: | |
| break; | |
| /*FIXME: how the heck can we preserve newlines and spaces of JavaScript in | |
| an XML attribute in any viewer ? */ | |
| default: | |
| if (uniLine[i]<128) { | |
| gf_fprintf(sdump->trace, "%c", (u8)uniLine[i]); | |
| } | |
| else { | |
| gf_fprintf(sdump->trace, "&#%d;", uniLine[i]); | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| gf_free(uniLine); | |
| } | |
| DUMP_IND(sdump); | |
| } | |
| break; | |
| case GF_SG_VRML_SFSTRING: | |
| { | |
| char *str; | |
| if (sdump->XMLDump) { | |
| if (is_mf) gf_fprintf(sdump->trace, sdump->X3DDump ? "\"" : """); | |
| } else { | |
| gf_fprintf(sdump->trace, "\""); | |
| } | |
| /*dump in unicode*/ | |
| str = ((SFString *)ptr)->buffer; | |
| if (node && (gf_node_get_tag(node)==TAG_MPEG4_BitWrapper)) { | |
| u32 bufsize = 37 + ((M_BitWrapper*)node)->buffer_len * 2 + 3; | |
| str = gf_malloc(sizeof(char) * bufsize); | |
| if (str) { | |
| s32 res; | |
| gf_strlcpy(str, "data:application/octet-string;base64,", bufsize); | |
| res = gf_base64_encode(((M_BitWrapper*)node)->buffer.buffer, ((M_BitWrapper*)node)->buffer_len, str+37, bufsize-37); | |
| if (res<0) { | |
| gf_free(str); | |
| str = NULL; | |
| } else { | |
| str[res+37] = 0; | |
| } | |
| } | |
| } | |
| if (str && str[0]) { | |
| if (sdump->XMLDump) { | |
| scene_dump_utf_string(sdump, 1, str); | |
| } else if (!strchr(str, '\"')) { | |
| gf_fprintf(sdump->trace, "%s", str); | |
| } else { | |
| u32 i, len = (u32)strlen(str); | |
| for (i=0; i<len; i++) { | |
| if (str[i]=='\"') gf_fputc('\\', sdump->trace); | |
| gf_fputc(str[i], sdump->trace); | |
| } | |
| } | |
| } | |
| if (node && (gf_node_get_tag(node)==TAG_MPEG4_BitWrapper)) { | |
| if (str) gf_free(str); | |
| } | |
| if (sdump->XMLDump) { | |
| if (is_mf) gf_fprintf(sdump->trace, sdump->X3DDump ? "\"" : """); | |
| } else { | |
| gf_fprintf(sdump->trace, "\""); | |
| } | |
| } | |
| break; | |
| case GF_SG_VRML_SFURL: | |
| if (((SFURL *)ptr)->url) { | |
| #if 0 | |
| u32 len; | |
| char *str; | |
| short uniLine[5000]; | |
| str = ((SFURL *)ptr)->url; | |
| len = gf_utf8_mbstowcs(uniLine, 5000, (const char **) &str); | |
| if (len != GF_UTF8_FAIL) { | |
| gf_fprintf(sdump->trace, sdump->XMLDump ? (sdump->X3DDump ? "'" : """) : "\""); | |
| fwprintf(sdump->trace, (unsigned short *) uniLine); | |
| gf_fprintf(sdump->trace, sdump->XMLDump ? (sdump->X3DDump ? "'" : """) : "\""); | |
| } | |
| #else | |
| gf_fprintf(sdump->trace, sdump->XMLDump ? (sdump->X3DDump ? "'" : """) : "\""); | |
| gf_fprintf(sdump->trace, "%s", ((SFURL *)ptr)->url); | |
| gf_fprintf(sdump->trace, sdump->XMLDump ? (sdump->X3DDump ? "'" : """) : "\""); | |
| #endif | |
| } else { | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, ""od://od%d"", ((SFURL *)ptr)->OD_ID); | |
| } else { | |
| gf_fprintf(sdump->trace, "od:%d", ((SFURL *)ptr)->OD_ID); | |
| } | |
| } | |
| break; | |
| case GF_SG_VRML_SFIMAGE: | |
| { | |
| u32 i, count; | |
| SFImage *img = (SFImage *)ptr; | |
| gf_fprintf(sdump->trace, "%d %d %d", img->width, img->height, img->numComponents); | |
| count = img->width * img->height * img->numComponents; | |
| for (i=0; i<count; ) { | |
| switch (img->numComponents) { | |
| case 1: | |
| gf_fprintf(sdump->trace, " 0x%02X", img->pixels[i]); | |
| i++; | |
| break; | |
| case 2: | |
| gf_fprintf(sdump->trace, " 0x%02X%02X", img->pixels[i], img->pixels[i+1]); | |
| i+=2; | |
| break; | |
| case 3: | |
| gf_fprintf(sdump->trace, " 0x%02X%02X%02X", img->pixels[i], img->pixels[i+1], img->pixels[i+2]); | |
| i+=3; | |
| break; | |
| case 4: | |
| gf_fprintf(sdump->trace, " 0x%02X%02X%02X%02X", img->pixels[i], img->pixels[i+1], img->pixels[i+2], img->pixels[i+3]); | |
| i+=4; | |
| break; | |
| } | |
| } | |
| } | |
| break; | |
| } | |
| } | |
| static void gf_dump_vrml_simple_field(GF_SceneDumper *sdump, GF_FieldInfo field, GF_Node *parent) | |
| { | |
| u32 i, sf_type; | |
| GF_ChildNodeItem *list; | |
| void *slot_ptr; | |
| switch (field.fieldType) { | |
| case GF_SG_VRML_SFNODE: | |
| gf_dump_vrml_node(sdump, field.far_ptr ? *(GF_Node **)field.far_ptr : NULL, 0, NULL); | |
| return; | |
| case GF_SG_VRML_MFNODE: | |
| list = * ((GF_ChildNodeItem **) field.far_ptr); | |
| gf_assert( list ); | |
| sdump->indent++; | |
| while (list) { | |
| gf_dump_vrml_node(sdump, list->node, 1, NULL); | |
| list = list->next; | |
| } | |
| sdump->indent--; | |
| return; | |
| case GF_SG_VRML_SFCOMMANDBUFFER: | |
| return; | |
| } | |
| if (gf_sg_vrml_is_sf_field(field.fieldType)) { | |
| if (sdump->XMLDump) StartAttribute(sdump, "value"); | |
| if (field.far_ptr) | |
| gf_dump_vrml_sffield(sdump, field.fieldType, field.far_ptr, 0, parent); | |
| if (sdump->XMLDump) EndAttribute(sdump); | |
| } else { | |
| GenMFField *mffield; | |
| mffield = (GenMFField *) field.far_ptr; | |
| sf_type = gf_sg_vrml_get_sf_type(field.fieldType); | |
| if (!sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "["); | |
| } else if (sf_type==GF_SG_VRML_SFSTRING) { | |
| gf_fprintf(sdump->trace, " value=\'"); | |
| } else { | |
| StartAttribute(sdump, "value"); | |
| } | |
| for (i=0; mffield && (i<mffield->count); i++) { | |
| if (i) gf_fprintf(sdump->trace, " "); | |
| gf_sg_vrml_mf_get_item(field.far_ptr, field.fieldType, &slot_ptr, i); | |
| /*this is to cope with single MFString which shall appear as SF in XMT*/ | |
| gf_dump_vrml_sffield(sdump, sf_type, slot_ptr, 1, parent); | |
| } | |
| if (!sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "]"); | |
| } else if (sf_type==GF_SG_VRML_SFSTRING) { | |
| gf_fprintf(sdump->trace, "\'"); | |
| } else { | |
| EndAttribute(sdump); | |
| } | |
| } | |
| } | |
| static void gf_dump_vrml_field(GF_SceneDumper *sdump, GF_Node *node, GF_FieldInfo field) | |
| { | |
| u32 i, sf_type; | |
| Bool needs_field_container; | |
| GF_ChildNodeItem *list; | |
| void *slot_ptr; | |
| switch (field.fieldType) { | |
| case GF_SG_VRML_SFNODE: | |
| assert ( *(GF_Node **)field.far_ptr); | |
| if (sdump->XMLDump) { | |
| if (!sdump->X3DDump) { | |
| StartElement(sdump, (char *) field.name); | |
| EndElementHeader(sdump, 1); | |
| sdump->indent++; | |
| } | |
| } else { | |
| StartAttribute(sdump, field.name); | |
| } | |
| gf_dump_vrml_node(sdump, *(GF_Node **)field.far_ptr, 0, NULL); | |
| if (sdump->XMLDump) { | |
| if (!sdump->X3DDump) { | |
| sdump->indent--; | |
| EndElement(sdump, (char *) field.name, 1); | |
| } | |
| } else { | |
| EndAttribute(sdump); | |
| } | |
| return; | |
| case GF_SG_VRML_MFNODE: | |
| needs_field_container = 0; | |
| if (sdump->XMLDump && sdump->X3DDump) { | |
| u32 count, nb_ndt; | |
| GF_FieldInfo info; | |
| if (!strcmp(field.name, "children")) { | |
| needs_field_container = 0; | |
| } else { | |
| nb_ndt = 0; | |
| count = gf_node_get_field_count(node); | |
| for (i=0; i<count; i++) { | |
| gf_node_get_field(node, i, &info); | |
| if ((info.eventType==GF_SG_EVENT_IN) || (info.eventType==GF_SG_EVENT_OUT)) continue; | |
| if (info.NDTtype==field.NDTtype) nb_ndt++; | |
| } | |
| needs_field_container = (nb_ndt>1) ? 1 : 0; | |
| } | |
| } | |
| #ifndef GPAC_DISABLE_X3D | |
| if (!sdump->X3DDump) { | |
| if (gf_node_get_tag(node)==TAG_X3D_Switch) field.name = "choice"; | |
| } | |
| #endif | |
| list = * ((GF_ChildNodeItem **) field.far_ptr); | |
| gf_assert(list); | |
| if (!sdump->XMLDump || !sdump->X3DDump) StartList(sdump, field.name); | |
| sdump->indent++; | |
| while (list) { | |
| gf_dump_vrml_node(sdump, list->node, 1, needs_field_container ? (char *) field.name : NULL); | |
| list = list->next; | |
| } | |
| sdump->indent--; | |
| if (!sdump->XMLDump || !sdump->X3DDump) EndList(sdump, field.name); | |
| return; | |
| case GF_SG_VRML_SFCOMMANDBUFFER: | |
| { | |
| SFCommandBuffer *cb = (SFCommandBuffer *)field.far_ptr; | |
| StartElement(sdump, (char *) field.name); | |
| EndElementHeader(sdump, 1); | |
| sdump->indent++; | |
| if (!gf_list_count(cb->commandList)) { | |
| /*the arch does not allow for that (we would need a codec and so on, or decompress the command list | |
| in all cases...)*/ | |
| if (sdump->trace && cb->bufferSize) { | |
| if (sdump->XMLDump) gf_fprintf(sdump->trace, "<!--SFCommandBuffer cannot be dumped while playing - use MP4Box instead-->\n"); | |
| else gf_fprintf(sdump->trace, "#SFCommandBuffer cannot be dumped while playing - use MP4Box instead\n"); | |
| } | |
| } else { | |
| gf_sm_dump_command_list(sdump, cb->commandList, sdump->indent, 0); | |
| } | |
| sdump->indent--; | |
| EndElement(sdump, (char *) field.name, 1); | |
| } | |
| return; | |
| case GF_SG_VRML_MFATTRREF: | |
| if (sdump->XMLDump) { | |
| MFAttrRef *ar = (MFAttrRef *)field.far_ptr; | |
| StartElement(sdump, (char *) field.name); | |
| EndElementHeader(sdump, 1); | |
| sdump->indent++; | |
| for (i=0; i<ar->count; i++) { | |
| if (ar->vals[i].node) { | |
| GF_FieldInfo pinfo; | |
| DUMP_IND(sdump); | |
| gf_node_get_field(ar->vals[i].node, ar->vals[i].fieldIndex, &pinfo); | |
| gf_fprintf(sdump->trace, "<store node=\""); | |
| scene_dump_vrml_id(sdump, ar->vals[i].node); | |
| gf_fprintf(sdump->trace, "\" field=\"%s\"/>\n", pinfo.name); | |
| } | |
| } | |
| sdump->indent--; | |
| EndElement(sdump, (char *) field.name, 1); | |
| return; | |
| } | |
| break; | |
| } | |
| if (gf_sg_vrml_is_sf_field(field.fieldType)) { | |
| StartAttribute(sdump, field.name); | |
| if (field.far_ptr) | |
| gf_dump_vrml_sffield(sdump, field.fieldType, field.far_ptr, 0, node); | |
| EndAttribute(sdump); | |
| } else { | |
| GenMFField *mffield = (GenMFField *) field.far_ptr; | |
| sf_type = gf_sg_vrml_get_sf_type(field.fieldType); | |
| if (sdump->XMLDump && sdump->X3DDump) { | |
| switch (sf_type) { | |
| case GF_SG_VRML_SFSTRING: | |
| case GF_SG_VRML_SFSCRIPT: | |
| case GF_SG_VRML_SFURL: | |
| gf_fprintf(sdump->trace, " %s=\'", (char *) field.name); | |
| break; | |
| default: | |
| StartAttribute(sdump, field.name); | |
| break; | |
| } | |
| } else { | |
| StartAttribute(sdump, field.name); | |
| } | |
| if (!sdump->XMLDump) gf_fprintf(sdump->trace, "["); | |
| for (i=0; mffield && (i<mffield->count); i++) { | |
| if (i) gf_fprintf(sdump->trace, " "); | |
| gf_sg_vrml_mf_get_item(field.far_ptr, field.fieldType, &slot_ptr, i); | |
| gf_dump_vrml_sffield(sdump, sf_type, slot_ptr, 1, node); | |
| } | |
| if (!sdump->XMLDump) gf_fprintf(sdump->trace, "]"); | |
| if (sdump->XMLDump && sdump->X3DDump) { | |
| switch (sf_type) { | |
| case GF_SG_VRML_SFSTRING: | |
| case GF_SG_VRML_SFSCRIPT: | |
| case GF_SG_VRML_SFURL: | |
| gf_fprintf(sdump->trace, "\'"); | |
| break; | |
| default: | |
| EndAttribute(sdump); | |
| break; | |
| } | |
| } else { | |
| EndAttribute(sdump); | |
| } | |
| } | |
| } | |
| static const char *GetXMTFieldTypeName(u32 fieldType) | |
| { | |
| switch (fieldType) { | |
| case GF_SG_VRML_SFBOOL: | |
| return "Boolean"; | |
| case GF_SG_VRML_SFINT32: | |
| return "Integer"; | |
| case GF_SG_VRML_SFCOLOR: | |
| return "Color"; | |
| case GF_SG_VRML_SFVEC2F: | |
| return "Vector2"; | |
| case GF_SG_VRML_SFIMAGE: | |
| return "Image"; | |
| case GF_SG_VRML_SFTIME: | |
| return "Time"; | |
| case GF_SG_VRML_SFFLOAT: | |
| return "Float"; | |
| case GF_SG_VRML_SFVEC3F: | |
| return "Vector3"; | |
| case GF_SG_VRML_SFROTATION: | |
| return "Rotation"; | |
| case GF_SG_VRML_SFSTRING: | |
| return "String"; | |
| case GF_SG_VRML_SFNODE: | |
| return "Node"; | |
| case GF_SG_VRML_MFBOOL: | |
| return "Booleans"; | |
| case GF_SG_VRML_MFINT32: | |
| return "Integers"; | |
| case GF_SG_VRML_MFCOLOR: | |
| return "Colors"; | |
| case GF_SG_VRML_MFVEC2F: | |
| return "Vector2Array"; | |
| case GF_SG_VRML_MFIMAGE: | |
| return "Images"; | |
| case GF_SG_VRML_MFTIME: | |
| return "Times"; | |
| case GF_SG_VRML_MFFLOAT: | |
| return "Floats"; | |
| case GF_SG_VRML_MFVEC3F: | |
| return "Vector3Array"; | |
| case GF_SG_VRML_MFROTATION: | |
| return "Rotations"; | |
| case GF_SG_VRML_MFSTRING: | |
| return "Strings"; | |
| case GF_SG_VRML_MFNODE: | |
| return "Nodes"; | |
| default: | |
| return "unknown"; | |
| } | |
| } | |
| static const char *GetXMTFieldTypeValueName(u32 fieldType) | |
| { | |
| switch (fieldType) { | |
| case GF_SG_VRML_SFBOOL: | |
| return "booleanValue"; | |
| case GF_SG_VRML_SFINT32: | |
| return "intValue"; | |
| case GF_SG_VRML_SFCOLOR: | |
| return "colorValue"; | |
| case GF_SG_VRML_SFVEC2F: | |
| return "vector2Value"; | |
| case GF_SG_VRML_SFIMAGE: | |
| return "imageValue"; | |
| case GF_SG_VRML_SFTIME: | |
| return "timeValue"; | |
| case GF_SG_VRML_SFFLOAT: | |
| return "floatValue"; | |
| case GF_SG_VRML_SFVEC3F: | |
| return "vector3Value"; | |
| case GF_SG_VRML_SFROTATION: | |
| return "rotationValue"; | |
| case GF_SG_VRML_SFSTRING: | |
| return "stringValue"; | |
| case GF_SG_VRML_MFBOOL: | |
| return "booleanArrayValue"; | |
| case GF_SG_VRML_MFINT32: | |
| return "intArrayValue"; | |
| case GF_SG_VRML_MFCOLOR: | |
| return "colorArrayValue"; | |
| case GF_SG_VRML_MFVEC2F: | |
| return "vector2ArrayValue"; | |
| case GF_SG_VRML_MFIMAGE: | |
| return "imageArrayValue"; | |
| case GF_SG_VRML_MFTIME: | |
| return "timeArrayValue"; | |
| case GF_SG_VRML_MFFLOAT: | |
| return "floatArrayValue"; | |
| case GF_SG_VRML_MFVEC3F: | |
| return "vector3ArrayValue"; | |
| case GF_SG_VRML_MFROTATION: | |
| return "rotationArrayValue"; | |
| case GF_SG_VRML_MFSTRING: | |
| return "stringArrayValue"; | |
| default: | |
| return "unknown"; | |
| } | |
| } | |
| /*field dumping for proto declaration and Script*/ | |
| static void gf_dump_vrml_dyn_field(GF_SceneDumper *sdump, GF_Node *node, GF_FieldInfo field, Bool has_sublist) | |
| { | |
| u32 i, sf_type; | |
| void *slot_ptr; | |
| if (gf_sg_vrml_is_sf_field(field.fieldType)) { | |
| DUMP_IND(sdump); | |
| if (sdump->XMLDump) { | |
| if (sdump->X3DDump) { | |
| gf_fprintf(sdump->trace, "<field name=\"%s\" type=\"%s\" accessType=\"%s\"", | |
| field.name, gf_sg_vrml_get_field_type_name(field.fieldType), gf_sg_vrml_get_event_type_name(field.eventType, 1)); | |
| } else { | |
| gf_fprintf(sdump->trace, "<field name=\"%s\" type=\"%s\" vrml97Hint=\"%s\"", | |
| field.name, GetXMTFieldTypeName(field.fieldType), gf_sg_vrml_get_event_type_name(field.eventType, 0)); | |
| } | |
| if ((field.eventType == GF_SG_EVENT_FIELD) || (field.eventType == GF_SG_EVENT_EXPOSED_FIELD)) { | |
| if (field.fieldType == GF_SG_VRML_SFNODE) { | |
| if (!sdump->X3DDump) { | |
| gf_fprintf(sdump->trace, ">\n"); | |
| sdump->indent++; | |
| gf_fprintf(sdump->trace, "<node>"); | |
| gf_dump_vrml_node(sdump, field.far_ptr ? *(GF_Node **)field.far_ptr : NULL, 0, NULL); | |
| gf_fprintf(sdump->trace, "</node>"); | |
| sdump->indent--; | |
| if (!has_sublist) | |
| gf_fprintf(sdump->trace, "</field>\n"); | |
| } else { | |
| if (field.far_ptr) { | |
| gf_fprintf(sdump->trace, ">\n"); | |
| gf_dump_vrml_node(sdump, *(GF_Node **)field.far_ptr, 0, NULL); | |
| gf_fprintf(sdump->trace, "</field>\n"); | |
| } else { | |
| gf_fprintf(sdump->trace, "/>\n"); | |
| } | |
| } | |
| DUMP_IND(sdump); | |
| } else { | |
| if (sdump->X3DDump) { | |
| gf_fprintf(sdump->trace, " value=\""); | |
| } else { | |
| gf_fprintf(sdump->trace, " %s=\"", GetXMTFieldTypeValueName(field.fieldType)); | |
| } | |
| if (field.far_ptr) | |
| gf_dump_vrml_sffield(sdump, field.fieldType, field.far_ptr, 0, node); | |
| if (has_sublist) | |
| gf_fprintf(sdump->trace, "\">\n"); | |
| else | |
| gf_fprintf(sdump->trace, "\"/>\n"); | |
| } | |
| } else { | |
| gf_fprintf(sdump->trace, "/>\n"); | |
| } | |
| } else { | |
| gf_fprintf(sdump->trace, "%s %s %s", gf_sg_vrml_get_event_type_name(field.eventType, sdump->X3DDump), gf_sg_vrml_get_field_type_name(field.fieldType), field.name); | |
| if ((field.eventType==GF_SG_EVENT_FIELD) || (field.eventType==GF_SG_EVENT_EXPOSED_FIELD)) { | |
| gf_fprintf(sdump->trace, " "); | |
| if (field.fieldType == GF_SG_VRML_SFNODE) { | |
| gf_dump_vrml_node(sdump, field.far_ptr ? *(GF_Node **)field.far_ptr : NULL, 0, NULL); | |
| } else if (field.far_ptr) { | |
| gf_dump_vrml_simple_field(sdump, field, node); | |
| } | |
| } | |
| gf_fprintf(sdump->trace, "\n"); | |
| } | |
| } else if (field.far_ptr) { | |
| GenMFField *mffield = (GenMFField *) field.far_ptr; | |
| sf_type = gf_sg_vrml_get_sf_type(field.fieldType); | |
| DUMP_IND(sdump); | |
| if (!sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "%s %s %s", gf_sg_vrml_get_event_type_name(field.eventType, sdump->X3DDump), gf_sg_vrml_get_field_type_name(field.fieldType), field.name); | |
| if ((field.eventType==GF_SG_EVENT_FIELD) || (field.eventType==GF_SG_EVENT_EXPOSED_FIELD)) { | |
| gf_fprintf(sdump->trace, " ["); | |
| if (sf_type == GF_SG_VRML_SFNODE) { | |
| GF_ChildNodeItem *l = *(GF_ChildNodeItem **)field.far_ptr; | |
| gf_fprintf(sdump->trace, "\n"); | |
| sdump->indent++; | |
| while (l) { | |
| gf_dump_vrml_node(sdump, l->node, 1, NULL); | |
| l = l->next; | |
| } | |
| sdump->indent--; | |
| DUMP_IND(sdump); | |
| } else { | |
| for (i=0; mffield && (i<mffield->count); i++) { | |
| if (i) gf_fprintf(sdump->trace, " "); | |
| if (field.fieldType != GF_SG_VRML_MFNODE) { | |
| gf_sg_vrml_mf_get_item(field.far_ptr, field.fieldType, &slot_ptr, i); | |
| gf_dump_vrml_sffield(sdump, sf_type, slot_ptr, (mffield->count>1) ? 1 : 0, node); | |
| } | |
| } | |
| } | |
| gf_fprintf(sdump->trace, "]"); | |
| } | |
| gf_fprintf(sdump->trace, "\n"); | |
| } else { | |
| if (sdump->X3DDump) { | |
| gf_fprintf(sdump->trace, "<field name=\"%s\" type=\"%s\" accessType=\"%s\"", | |
| field.name, gf_sg_vrml_get_field_type_name(field.fieldType), gf_sg_vrml_get_event_type_name(field.eventType, 1)); | |
| } else { | |
| gf_fprintf(sdump->trace, "<field name=\"%s\" type=\"%s\" vrml97Hint=\"%s\"", | |
| field.name, GetXMTFieldTypeName(field.fieldType), gf_sg_vrml_get_event_type_name(field.eventType, 0)); | |
| } | |
| if ((field.eventType==GF_SG_EVENT_FIELD) || (field.eventType==GF_SG_EVENT_EXPOSED_FIELD)) { | |
| if (sf_type == GF_SG_VRML_SFNODE) { | |
| GF_ChildNodeItem *list = *(GF_ChildNodeItem **)field.far_ptr; | |
| gf_fprintf(sdump->trace, ">\n"); | |
| sdump->indent++; | |
| if (!sdump->X3DDump) gf_fprintf(sdump->trace, "<nodes>"); | |
| while (list) { | |
| gf_dump_vrml_node(sdump, list->node, 1, NULL); | |
| list = list->next; | |
| } | |
| if (!sdump->X3DDump) gf_fprintf(sdump->trace, "</nodes>"); | |
| sdump->indent++; | |
| DUMP_IND(sdump); | |
| if (!has_sublist) | |
| gf_fprintf(sdump->trace, "</field>\n"); | |
| } else { | |
| if (sdump->X3DDump) { | |
| gf_fprintf(sdump->trace, " value=\""); | |
| } else { | |
| gf_fprintf(sdump->trace, " %s=\"", GetXMTFieldTypeValueName(field.fieldType)); | |
| } | |
| for (i=0; mffield && (i<mffield->count); i++) { | |
| if (i) gf_fprintf(sdump->trace, " "); | |
| if (field.fieldType != GF_SG_VRML_MFNODE) { | |
| gf_sg_vrml_mf_get_item(field.far_ptr, field.fieldType, &slot_ptr, i); | |
| gf_dump_vrml_sffield(sdump, sf_type, slot_ptr, (mffield->count>1) ? 1 : 0, node); | |
| } | |
| } | |
| if (has_sublist) | |
| gf_fprintf(sdump->trace, "\">\n"); | |
| else | |
| gf_fprintf(sdump->trace, "\"/>\n"); | |
| } | |
| } else { | |
| gf_fprintf(sdump->trace, "/>\n"); | |
| } | |
| } | |
| } | |
| } | |
| /*field dumping for proto instance*/ | |
| static void gf_dump_vrml_proto_field(GF_SceneDumper *sdump, GF_Node *node, GF_FieldInfo field) | |
| { | |
| u32 i, sf_type; | |
| void *slot_ptr; | |
| DUMP_IND(sdump); | |
| gf_fprintf(sdump->trace, "<fieldValue name=\"%s\" ", field.name); | |
| if (gf_sg_vrml_is_sf_field(field.fieldType)) { | |
| if (field.fieldType == GF_SG_VRML_SFNODE) { | |
| gf_fprintf(sdump->trace, ">\n"); | |
| sdump->indent++; | |
| if (!sdump->X3DDump) gf_fprintf(sdump->trace, "<node>"); | |
| gf_dump_vrml_node(sdump, field.far_ptr ? *(GF_Node **)field.far_ptr : NULL, 0, NULL); | |
| if (!sdump->X3DDump) gf_fprintf(sdump->trace, "</node>"); | |
| sdump->indent--; | |
| DUMP_IND(sdump); | |
| gf_fprintf(sdump->trace, "</fieldValue>\n"); | |
| } else { | |
| if (sdump->X3DDump) { | |
| gf_fprintf(sdump->trace, " value=\""); | |
| } else { | |
| gf_fprintf(sdump->trace, " %s=\"", GetXMTFieldTypeValueName(field.fieldType)); | |
| } | |
| if (field.far_ptr) | |
| gf_dump_vrml_sffield(sdump, field.fieldType, field.far_ptr, 0, node); | |
| gf_fprintf(sdump->trace, "\"/>\n"); | |
| } | |
| } else { | |
| GenMFField *mffield = (GenMFField *) field.far_ptr; | |
| sf_type = gf_sg_vrml_get_sf_type(field.fieldType); | |
| if ((field.eventType==GF_SG_EVENT_FIELD) || (field.eventType==GF_SG_EVENT_EXPOSED_FIELD)) { | |
| if (sf_type == GF_SG_VRML_SFNODE) { | |
| GF_ChildNodeItem *list = *(GF_ChildNodeItem **)field.far_ptr; | |
| gf_fprintf(sdump->trace, ">\n"); | |
| sdump->indent++; | |
| if (!sdump->X3DDump) gf_fprintf(sdump->trace, "<nodes>"); | |
| while (list) { | |
| gf_dump_vrml_node(sdump, list->node, 1, NULL); | |
| list = list->next; | |
| } | |
| if (!sdump->X3DDump) gf_fprintf(sdump->trace, "</nodes>"); | |
| sdump->indent--; | |
| DUMP_IND(sdump); | |
| gf_fprintf(sdump->trace, "</fieldValue>\n"); | |
| } else { | |
| if (sdump->X3DDump) { | |
| gf_fprintf(sdump->trace, " value=\""); | |
| } else { | |
| gf_fprintf(sdump->trace, " %s=\"", GetXMTFieldTypeValueName(field.fieldType)); | |
| } | |
| for (i=0; mffield && (i<mffield->count); i++) { | |
| if (i) gf_fprintf(sdump->trace, " "); | |
| if (field.fieldType != GF_SG_VRML_MFNODE) { | |
| gf_sg_vrml_mf_get_item(field.far_ptr, field.fieldType, &slot_ptr, i); | |
| gf_dump_vrml_sffield(sdump, sf_type, slot_ptr, (mffield->count>1) ? 1 : 0, node); | |
| } | |
| } | |
| gf_fprintf(sdump->trace, "\"/>\n"); | |
| } | |
| } | |
| } | |
| } | |
| static GF_Route *gf_dump_vrml_get_IS(GF_SceneDumper *sdump, GF_Node *node, GF_FieldInfo *field) | |
| { | |
| u32 i; | |
| GF_Route *r; | |
| i=0; | |
| while ((r = (GF_Route*)gf_list_enum(sdump->current_proto->sub_graph->Routes, &i))) { | |
| if (!r->IS_route) continue; | |
| if ((r->ToNode==node) && (r->ToField.fieldIndex==field->fieldIndex)) return r; | |
| } | |
| if (!node || !node->sgprivate->interact || !node->sgprivate->interact->routes) return NULL; | |
| i=0; | |
| while ((r = (GF_Route*)gf_list_enum(node->sgprivate->interact->routes, &i))) { | |
| if (!r->IS_route) continue; | |
| if (r->FromField.fieldIndex == field->fieldIndex) return r; | |
| } | |
| return NULL; | |
| } | |
| static void gf_dump_vrml_IS_field(GF_SceneDumper *sdump, GF_Node *node, GF_FieldInfo field, Bool isScript, Bool skip_is) | |
| { | |
| GF_FieldInfo pfield; | |
| GF_Route *r = gf_dump_vrml_get_IS(sdump, node, &field); | |
| if (r->FromNode) { | |
| pfield.fieldIndex = r->ToField.fieldIndex; | |
| gf_sg_proto_get_field(sdump->current_proto, NULL, &pfield); | |
| } else { | |
| pfield.fieldIndex = r->FromField.fieldIndex; | |
| gf_sg_proto_get_field(sdump->current_proto, NULL, &pfield); | |
| } | |
| if (!sdump->XMLDump) { | |
| DUMP_IND(sdump); | |
| if (isScript) gf_fprintf(sdump->trace, "%s %s ", gf_sg_vrml_get_event_type_name(field.eventType, sdump->X3DDump), gf_sg_vrml_get_field_type_name(field.fieldType)); | |
| gf_fprintf(sdump->trace, "%s IS %s\n", field.name, pfield.name); | |
| } else { | |
| if (!skip_is) { | |
| StartElement(sdump, "IS"); | |
| EndElementHeader(sdump, 1); | |
| sdump->indent++; | |
| } | |
| DUMP_IND(sdump); | |
| gf_fprintf(sdump->trace, "<connect nodeField=\"%s\" protoField=\"%s\"/>\n", field.name, pfield.name); | |
| if (!skip_is) { | |
| sdump->indent--; | |
| EndElement(sdump, "IS", 1); | |
| } | |
| } | |
| } | |
| static Bool scene_dump_vrml_can_dump(GF_SceneDumper *sdump, GF_Node *node) | |
| { | |
| #ifndef GPAC_DISABLE_VRML | |
| u32 tag; | |
| if (node->sgprivate->tag==TAG_ProtoNode) return 1; | |
| if (sdump->X3DDump || (sdump->dump_mode==GF_SM_DUMP_VRML)) { | |
| if (node->sgprivate->tag>=GF_NODE_RANGE_FIRST_X3D) return 1; | |
| if (node->sgprivate->tag==TAG_MPEG4_Rectangle) return 1; | |
| if (node->sgprivate->tag==TAG_MPEG4_Circle) return 1; | |
| #ifndef GPAC_DISABLE_X3D | |
| tag = gf_node_x3d_type_by_class_name(gf_node_get_class_name(node)); | |
| return tag ? 1 : 0; | |
| #else | |
| return 0; | |
| #endif | |
| } else { | |
| if (node->sgprivate->tag<=GF_NODE_RANGE_LAST_MPEG4) return 1; | |
| #ifndef GPAC_DISABLE_X3D | |
| if (node->sgprivate->tag==TAG_X3D_Rectangle2D) return 1; | |
| if (node->sgprivate->tag==TAG_X3D_Circle2D) return 1; | |
| #endif | |
| tag = gf_node_mpeg4_type_by_class_name(gf_node_get_class_name(node)); | |
| return tag ? 1 : 0; | |
| } | |
| #else | |
| return 1; | |
| #endif | |
| } | |
| static void gf_dump_vrml_node(GF_SceneDumper *sdump, GF_Node *node, Bool in_list, char *fieldContainer) | |
| { | |
| u32 i, count, to_dump, sub_el, ID; | |
| u32 *def_fields; | |
| Bool isDEF, isScript, isProto, hasISed; | |
| char *name; | |
| GF_Node *base; | |
| GF_FieldInfo field, base_field; | |
| if (!node) { | |
| gf_fprintf(sdump->trace, "NULL"); | |
| return; | |
| } | |
| /*this dumper works only for VRML like graphs*/ | |
| if (node->sgprivate->tag>GF_NODE_RANGE_LAST_X3D) return; | |
| if (!scene_dump_vrml_can_dump(sdump, node)) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[Scene Dump] node %s not part of %s standard - removing\n", gf_node_get_class_name(node), sdump->X3DDump ? "X3D" : (sdump->dump_mode==GF_SM_DUMP_VRML) ? "VRML" : "MPEG4")); | |
| if (!in_list) gf_fprintf(sdump->trace, "NULL"); | |
| return; | |
| } | |
| /*convert whatever possible*/ | |
| name = (char*)gf_node_get_class_name(node); | |
| #ifndef GPAC_DISABLE_VRML | |
| if (sdump->X3DDump) { | |
| if (node->sgprivate->tag == TAG_MPEG4_Circle) name = "Circle2D"; | |
| else if (node->sgprivate->tag == TAG_MPEG4_Rectangle) name = "Rectangle2D"; | |
| #ifndef GPAC_DISABLE_X3D | |
| } else { | |
| if (node->sgprivate->tag == TAG_X3D_Circle2D) name = "Circle"; | |
| else if (node->sgprivate->tag == TAG_X3D_Rectangle2D) name = "Rectangle"; | |
| #endif | |
| } | |
| #endif | |
| isProto = (gf_node_get_tag(node) == TAG_ProtoNode) ? 1 : 0; | |
| ID = gf_node_get_id(node); | |
| isDEF = 0; | |
| if (ID) { | |
| isDEF = gf_dump_vrml_is_def_node(sdump, node); | |
| if (!isDEF) { | |
| if (!sdump->XMLDump) { | |
| if (in_list) DUMP_IND(sdump); | |
| gf_fprintf(sdump->trace, "USE "); | |
| scene_dump_vrml_id(sdump, node); | |
| if (in_list) gf_fprintf(sdump->trace, "\n"); | |
| } else { | |
| if (isProto) { | |
| StartElement(sdump, "ProtoInstance"); | |
| StartAttribute(sdump, "name"); | |
| gf_fprintf(sdump->trace, "%s", name); | |
| EndAttribute(sdump); | |
| } else { | |
| StartElement(sdump, name); | |
| } | |
| StartAttribute(sdump, "USE"); | |
| scene_dump_vrml_id(sdump, node); | |
| EndAttribute(sdump); | |
| EndElementHeader(sdump, 0); | |
| } | |
| return; | |
| } | |
| } | |
| /*get all fields*/ | |
| count = gf_node_get_field_count(node); | |
| def_fields = (u32*)gf_malloc(sizeof(u32) * count); | |
| base = NULL; | |
| switch (gf_node_get_tag(node)) { | |
| #ifndef GPAC_DISABLE_VRML | |
| #ifndef GPAC_DISABLE_X3D | |
| case TAG_X3D_Script: | |
| #endif | |
| case TAG_MPEG4_Script: | |
| isScript = 1; | |
| break; | |
| #endif | |
| default: | |
| isScript = 0; | |
| break; | |
| } | |
| if (!isScript) { | |
| if (isProto) { | |
| base = gf_sg_proto_create_instance(node->sgprivate->scenegraph, ((GF_ProtoInstance *)node)->proto_interface); | |
| } else { | |
| base = gf_node_new(node->sgprivate->scenegraph, node->sgprivate->tag); | |
| } | |
| } | |
| if (base) gf_node_register(base, NULL); | |
| hasISed = 0; | |
| to_dump = sub_el = 0; | |
| for (i=0; i<count; i++) { | |
| if (isScript) { | |
| /*dyn script fields are complex types*/ | |
| def_fields[i] = (i>2) ? 2 : 1; | |
| } else { | |
| def_fields[i] = 0; | |
| } | |
| gf_node_get_field(node, i, &field); | |
| if (sdump->current_proto) { | |
| if (gf_dump_vrml_get_IS(sdump, node, &field) != NULL) { | |
| def_fields[i] = 3; | |
| if ((field.fieldType == GF_SG_VRML_SFNODE) || (field.fieldType == GF_SG_VRML_MFNODE)) | |
| def_fields[i] = sdump->XMLDump ? 4 : 3; | |
| /*in XMT the ISed is not an attribute*/ | |
| if (sdump->XMLDump) sub_el++; | |
| to_dump++; | |
| hasISed = 1; | |
| continue; | |
| } | |
| } | |
| if (!isScript && ((field.eventType == GF_SG_EVENT_IN) || (field.eventType == GF_SG_EVENT_OUT)) ) { | |
| continue; | |
| } | |
| /*proto instance in XMT lists all fields as elements*/ | |
| if (sdump->XMLDump && isProto) { | |
| def_fields[i] = 2; | |
| to_dump++; | |
| sub_el++; | |
| continue; | |
| } | |
| switch (field.fieldType) { | |
| case GF_SG_VRML_SFNODE: | |
| if (* (GF_Node **) field.far_ptr) { | |
| def_fields[i] = 2; | |
| to_dump++; | |
| sub_el++; | |
| } | |
| break; | |
| case GF_SG_VRML_MFNODE: | |
| if (* (GF_ChildNodeItem**) field.far_ptr) { | |
| def_fields[i] = 2; | |
| to_dump++; | |
| sub_el++; | |
| } | |
| break; | |
| case GF_SG_VRML_SFCOMMANDBUFFER: | |
| { | |
| SFCommandBuffer *p = (SFCommandBuffer *)field.far_ptr; | |
| if (p->bufferSize || gf_list_count(p->commandList)) { | |
| def_fields[i] = 2; | |
| to_dump++; | |
| sub_el++; | |
| } | |
| } | |
| break; | |
| case GF_SG_VRML_MFATTRREF: | |
| { | |
| MFAttrRef *p = (MFAttrRef*)field.far_ptr; | |
| if (p->count) { | |
| def_fields[i] = 2; | |
| to_dump++; | |
| sub_el++; | |
| } | |
| } | |
| break; | |
| default: | |
| if (isScript) { | |
| to_dump++; | |
| } else { | |
| gf_node_get_field(base, i, &base_field); | |
| if (!gf_sg_vrml_field_equal(base_field.far_ptr, field.far_ptr, field.fieldType)) { | |
| def_fields[i] = 1; | |
| to_dump++; | |
| } | |
| } | |
| break; | |
| } | |
| } | |
| if (base) gf_node_unregister(base, NULL); | |
| if (!to_dump) { | |
| if (in_list) DUMP_IND(sdump); | |
| if (!sdump->XMLDump) { | |
| if (isDEF) { | |
| gf_fprintf(sdump->trace, "DEF "); | |
| scene_dump_vrml_id(sdump, node); | |
| gf_fprintf(sdump->trace, " "); | |
| } | |
| gf_fprintf(sdump->trace, "%s {}\n", name); | |
| } else { | |
| if (isDEF) { | |
| if (isProto) { | |
| gf_fprintf(sdump->trace, "<ProtoInstance name=\"%s\" DEF=\"", name); | |
| } else { | |
| gf_fprintf(sdump->trace, "<%s DEF=\"", name); | |
| } | |
| scene_dump_vrml_id(sdump, node); | |
| gf_fprintf(sdump->trace, "\"/>\n"); | |
| } else { | |
| if (isProto) { | |
| gf_fprintf(sdump->trace, "<ProtoInstance name=\"%s\"/>\n", name); | |
| } else { | |
| gf_fprintf(sdump->trace, "<%s/>\n", name); | |
| } | |
| } | |
| } | |
| gf_free(def_fields); | |
| return; | |
| } | |
| if (!sdump->XMLDump) { | |
| if (in_list) DUMP_IND(sdump); | |
| if (isDEF) { | |
| gf_fprintf(sdump->trace, "DEF "); | |
| scene_dump_vrml_id(sdump, node); | |
| gf_fprintf(sdump->trace, " "); | |
| } | |
| gf_fprintf(sdump->trace, "%s {\n", name); | |
| } else { | |
| if (isProto) { | |
| StartElement(sdump, "ProtoInstance"); | |
| StartAttribute(sdump, "name"); | |
| gf_fprintf(sdump->trace, "%s", name); | |
| EndAttribute(sdump); | |
| } else { | |
| StartElement(sdump, name); | |
| } | |
| if (isDEF) { | |
| StartAttribute(sdump, "DEF"); | |
| scene_dump_vrml_id(sdump, node); | |
| EndAttribute(sdump); | |
| } | |
| } | |
| sdump->indent ++; | |
| for (i=0; i<count; i++) { | |
| switch (def_fields[i]) { | |
| /*regular field*/ | |
| case 1: | |
| gf_node_get_field(node, i, &field); | |
| if (!isScript) { | |
| gf_dump_vrml_field(sdump, node, field); | |
| } | |
| /*special script dump case, static fields except url*/ | |
| else if (i==1 || i==2) { | |
| if (*((SFBool *)field.far_ptr)) gf_dump_vrml_field(sdump, node, field); | |
| } | |
| /*in bt first dump fields - in XMT first dump url*/ | |
| else if (i && !sdump->XMLDump) { | |
| gf_dump_vrml_dyn_field(sdump, node, field, 0); | |
| } else if (!i && sdump->XMLDump) { | |
| gf_dump_vrml_field(sdump, node, field); | |
| } | |
| break; | |
| /*IS field*/ | |
| case 3: | |
| if (sdump->XMLDump) break; | |
| gf_node_get_field(node, i, &field); | |
| gf_dump_vrml_IS_field(sdump, node, field, isScript, 0); | |
| def_fields[i] = 0; | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| if (fieldContainer) gf_fprintf(sdump->trace, " fieldContainer=\"%s\"", fieldContainer); | |
| if (isScript) sub_el = 1; | |
| EndElementHeader(sdump, sub_el ? 1 : 0); | |
| if (sub_el) { | |
| /*dump all normal IS elements for XMT*/ | |
| if (hasISed && sdump->XMLDump) { | |
| StartElement(sdump, "IS"); | |
| EndElementHeader(sdump, 1); | |
| sdump->indent++; | |
| } | |
| for (i=0; i<count; i++) { | |
| if (def_fields[i]==3) { | |
| gf_node_get_field(node, i, &field); | |
| gf_dump_vrml_IS_field(sdump, node, field, isScript, 1); | |
| } | |
| } | |
| if (hasISed && sdump->XMLDump) { | |
| sdump->indent--; | |
| EndElement(sdump, "IS", 1); | |
| } | |
| /*dump all sub elements and complex IS*/ | |
| for (i=0; i<count; i++) { | |
| switch (def_fields[i]) { | |
| case 2: | |
| gf_node_get_field(node, i, &field); | |
| if (!isScript) { | |
| if (isProto && sdump->XMLDump) { | |
| gf_dump_vrml_proto_field(sdump, node, field); | |
| } else { | |
| gf_dump_vrml_field(sdump, node, field); | |
| } | |
| } else { | |
| #ifndef GPAC_DISABLE_X3D | |
| /*X3D script metadata, NOT DYN*/ | |
| if ((i==3) && (node->sgprivate->tag==TAG_X3D_Script) ) { | |
| if (*((GF_Node **)field.far_ptr)) gf_dump_vrml_field(sdump, node, field); | |
| } else | |
| #endif | |
| { | |
| gf_dump_vrml_dyn_field(sdump, node, field, 0); | |
| } | |
| } | |
| break; | |
| case 4: | |
| gf_node_get_field(node, i, &field); | |
| gf_dump_vrml_IS_field(sdump, node, field, isScript, 0); | |
| break; | |
| } | |
| } | |
| } | |
| /*finally dump script - XMT dumping is broken!!*/ | |
| if (isScript && !sdump->XMLDump) { | |
| gf_node_get_field(node, 0, &field); | |
| gf_dump_vrml_field(sdump, node, field); | |
| } | |
| sdump->indent --; | |
| if (!sdump->XMLDump && !in_list) { | |
| DUMP_IND(sdump); | |
| gf_fprintf(sdump->trace, "}"); | |
| } else { | |
| EndElement(sdump, isProto ? "ProtoInstance" : name, sub_el); | |
| } | |
| gf_free(def_fields); | |
| } | |
| static GF_Err DumpMultipleIndexedReplace(GF_SceneDumper *sdump, GF_Command *com) | |
| { | |
| u32 i; | |
| GF_FieldInfo field; | |
| GF_CommandField *inf; | |
| if (!gf_list_count(com->command_fields)) return GF_OK; | |
| inf = (GF_CommandField *) gf_list_get(com->command_fields, 0); | |
| gf_node_get_field(com->node, inf->fieldIndex, &field); | |
| field.fieldType = inf->fieldType; | |
| DUMP_IND(sdump); | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "<Replace extended=\"indices\" atNode=\""); | |
| scene_dump_vrml_id(sdump, com->node); | |
| gf_fprintf(sdump->trace, "\" atField=\"%s\">\n", field.name); | |
| } else { | |
| gf_fprintf(sdump->trace, "MULTIPLEINDREPLACE "); | |
| scene_dump_vrml_id(sdump, com->node); | |
| gf_fprintf(sdump->trace, ".%s [\n", field.name); | |
| } | |
| sdump->indent++; | |
| i=0; | |
| while ((inf = (GF_CommandField *) gf_list_enum(com->command_fields, &i))) { | |
| field.far_ptr = inf->field_ptr; | |
| DUMP_IND(sdump); | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "<repValue position=\"%d\" ", inf->pos); | |
| } else { | |
| gf_fprintf(sdump->trace, "%d BY ", inf->pos); | |
| } | |
| gf_dump_vrml_simple_field(sdump, field, com->node); | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "/>"); | |
| } else { | |
| gf_fprintf(sdump->trace, "\n"); | |
| } | |
| } | |
| sdump->indent--; | |
| DUMP_IND(sdump); | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "</Replace>\n"); | |
| } else { | |
| gf_fprintf(sdump->trace, "]\n"); | |
| } | |
| return GF_OK; | |
| } | |
| static GF_Err DumpMultipleReplace(GF_SceneDumper *sdump, GF_Command *com) | |
| { | |
| u32 i; | |
| GF_FieldInfo info; | |
| GF_CommandField *inf; | |
| if (!gf_list_count(com->command_fields)) return GF_OK; | |
| DUMP_IND(sdump); | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "<Replace extended=\"fields\" atNode=\""); | |
| scene_dump_vrml_id(sdump, com->node); | |
| gf_fprintf(sdump->trace, "\">\n"); | |
| sdump->indent++; | |
| i=0; | |
| while ((inf = (GF_CommandField *) gf_list_enum(com->command_fields, &i))) { | |
| gf_node_get_field(com->node, inf->fieldIndex, &info); | |
| info.far_ptr = inf->field_ptr; | |
| DUMP_IND(sdump); | |
| if (gf_sg_vrml_get_sf_type(info.fieldType) != GF_SG_VRML_SFNODE) { | |
| gf_fprintf(sdump->trace, "<repField atField=\"%s\" ", info.name); | |
| gf_dump_vrml_simple_field(sdump, info, com->node); | |
| gf_fprintf(sdump->trace, "/>\n"); | |
| } else { | |
| gf_fprintf(sdump->trace, "<repField>"); | |
| gf_dump_vrml_field(sdump, com->node, info); | |
| gf_fprintf(sdump->trace, "</repField>\n"); | |
| } | |
| } | |
| sdump->indent--; | |
| DUMP_IND(sdump); | |
| gf_fprintf(sdump->trace, "</Replace>\n"); | |
| } else { | |
| gf_fprintf(sdump->trace, "MULTIPLEREPLACE "); | |
| scene_dump_vrml_id(sdump, com->node); | |
| gf_fprintf(sdump->trace, " {\n"); | |
| sdump->indent++; | |
| i=0; | |
| while ((inf = (GF_CommandField *) gf_list_enum(com->command_fields, &i))) { | |
| gf_node_get_field(com->node, inf->fieldIndex, &info); | |
| info.far_ptr = inf->field_ptr; | |
| gf_dump_vrml_field(sdump, com->node, info); | |
| } | |
| sdump->indent--; | |
| DUMP_IND(sdump); | |
| gf_fprintf(sdump->trace, "}\n"); | |
| } | |
| return GF_OK; | |
| } | |
| static GF_Err DumpGlobalQP(GF_SceneDumper *sdump, GF_Command *com) | |
| { | |
| GF_CommandField *inf; | |
| if (!gf_list_count(com->command_fields)) return GF_OK; | |
| inf = (GF_CommandField *) gf_list_get(com->command_fields, 0); | |
| DUMP_IND(sdump); | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "<Replace extended=\"globalQuant\">\n"); | |
| } else { | |
| gf_fprintf(sdump->trace, "GLOBALQP "); | |
| } | |
| gf_dump_vrml_node(sdump, inf->new_node, 0, NULL); | |
| if (sdump->XMLDump) gf_fprintf(sdump->trace, "</Replace>\n"); | |
| else gf_fprintf(sdump->trace, "\n"); | |
| return GF_OK; | |
| } | |
| static GF_Err DumpNodeInsert(GF_SceneDumper *sdump, GF_Command *com) | |
| { | |
| GF_CommandField *inf; | |
| char posname[20]; | |
| if (!gf_list_count(com->command_fields)) return GF_OK; | |
| inf = (GF_CommandField *) gf_list_get(com->command_fields, 0); | |
| switch (inf->pos) { | |
| case 0: | |
| gf_strcpy(posname, "BEGIN"); | |
| break; | |
| case -1: | |
| gf_strcpy(posname, "END"); | |
| break; | |
| default: | |
| sprintf(posname, "%d", inf->pos); | |
| break; | |
| } | |
| DUMP_IND(sdump); | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "<Insert atNode=\""); | |
| scene_dump_vrml_id(sdump, com->node); | |
| gf_fprintf(sdump->trace, "\" position=\"%s\">", posname); | |
| } else { | |
| if (inf->pos==-1) { | |
| gf_fprintf(sdump->trace, "APPEND TO "); | |
| } | |
| else gf_fprintf(sdump->trace, "INSERT AT "); | |
| scene_dump_vrml_id(sdump, com->node); | |
| gf_fprintf(sdump->trace, ".children"); | |
| if (inf->pos!=-1) gf_fprintf(sdump->trace, "[%d]", inf->pos); | |
| gf_fprintf(sdump->trace, " "); | |
| } | |
| gf_dump_vrml_node(sdump, inf->new_node, 0, NULL); | |
| if (sdump->XMLDump) gf_fprintf(sdump->trace, "</Insert>"); | |
| gf_fprintf(sdump->trace, "\n"); | |
| return GF_OK; | |
| } | |
| static GF_Err DumpRouteInsert(GF_SceneDumper *sdump, GF_Command *com, Bool is_scene_replace) | |
| { | |
| GF_Route r; | |
| memset(&r, 0, sizeof(GF_Route)); | |
| r.ID = com->RouteID; | |
| r.name = com->def_name; | |
| r.FromNode = gf_dump_find_node(sdump, com->fromNodeID); | |
| r.FromField.fieldIndex = com->fromFieldIndex; | |
| r.ToNode = gf_dump_find_node(sdump, com->toNodeID); | |
| r.ToField.fieldIndex = com->toFieldIndex; | |
| gf_list_add(sdump->inserted_routes, com); | |
| if (is_scene_replace) { | |
| gf_dump_vrml_route(sdump, &r, 0); | |
| } else { | |
| DUMP_IND(sdump); | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "<Insert>\n"); | |
| } else { | |
| gf_fprintf(sdump->trace, "INSERT "); | |
| } | |
| gf_dump_vrml_route(sdump, &r, 2); | |
| if (sdump->XMLDump) gf_fprintf(sdump->trace, "</Insert>"); | |
| } | |
| return GF_OK; | |
| } | |
| static GF_Err DumpIndexInsert(GF_SceneDumper *sdump, GF_Command *com) | |
| { | |
| GF_Err e; | |
| GF_FieldInfo field, sffield; | |
| GF_CommandField *inf; | |
| char posname[20]; | |
| if (!gf_list_count(com->command_fields)) return GF_OK; | |
| inf = (GF_CommandField *) gf_list_get(com->command_fields, 0); | |
| switch (inf->pos) { | |
| case 0: | |
| gf_strcpy(posname, "BEGIN"); | |
| break; | |
| case -1: | |
| gf_strcpy(posname, "END"); | |
| break; | |
| default: | |
| sprintf(posname, "%d", inf->pos); | |
| break; | |
| } | |
| e = gf_node_get_field(com->node, inf->fieldIndex, &field); | |
| if (e) return e; | |
| if (gf_sg_vrml_is_sf_field(field.fieldType)) return GF_NON_COMPLIANT_BITSTREAM; | |
| DUMP_IND(sdump); | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "<Insert atNode=\""); | |
| scene_dump_vrml_id(sdump, com->node); | |
| gf_fprintf(sdump->trace, "\" atField=\"%s\" position=\"%s\"", field.name, posname); | |
| } else { | |
| if (inf->pos==-1) { | |
| gf_fprintf(sdump->trace, "APPEND TO "); | |
| } | |
| else gf_fprintf(sdump->trace, "INSERT AT "); | |
| scene_dump_vrml_id(sdump, com->node); | |
| gf_fprintf(sdump->trace, ".%s", field.name); | |
| if (inf->pos!=-1) gf_fprintf(sdump->trace, "[%d]", inf->pos); | |
| gf_fprintf(sdump->trace, " "); | |
| } | |
| memcpy(&sffield, &field, sizeof(GF_FieldInfo)); | |
| sffield.fieldType = gf_sg_vrml_get_sf_type(field.fieldType); | |
| if (field.fieldType==GF_SG_VRML_MFNODE) { | |
| if (sdump->XMLDump) gf_fprintf(sdump->trace, ">\n"); | |
| gf_dump_vrml_node(sdump, inf->new_node, 0, NULL); | |
| if (sdump->XMLDump) gf_fprintf(sdump->trace, "</Insert>"); | |
| gf_fprintf(sdump->trace, "\n"); | |
| } else { | |
| sffield.far_ptr = inf->field_ptr; | |
| gf_dump_vrml_simple_field(sdump, sffield, com->node); | |
| if (sdump->XMLDump) gf_fprintf(sdump->trace, "/>"); | |
| gf_fprintf(sdump->trace, "\n"); | |
| } | |
| return e; | |
| } | |
| static GF_Err DumpIndexDelete(GF_SceneDumper *sdump, GF_Command *com) | |
| { | |
| char posname[20]; | |
| GF_FieldInfo field; | |
| GF_CommandField *inf; | |
| if (!gf_list_count(com->command_fields)) return GF_OK; | |
| inf = (GF_CommandField *) gf_list_get(com->command_fields, 0); | |
| switch (inf->pos) { | |
| case -1: | |
| gf_strcpy(posname, sdump->XMLDump ? "END" : "LAST"); | |
| break; | |
| case 0: | |
| gf_strcpy(posname, "BEGIN"); | |
| break; | |
| default: | |
| sprintf(posname, "%d", inf->pos); | |
| break; | |
| } | |
| gf_node_get_field(com->node, inf->fieldIndex, &field); | |
| DUMP_IND(sdump); | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "<Delete atNode=\""); | |
| scene_dump_vrml_id(sdump, com->node); | |
| gf_fprintf(sdump->trace, "\" atField=\"%s\" position=\"%s\"/>", field.name, posname); | |
| } else { | |
| gf_fprintf(sdump->trace, "DELETE "); | |
| if (inf->pos==-1) gf_fprintf(sdump->trace, "%s ", posname); | |
| scene_dump_vrml_id(sdump, com->node); | |
| gf_fprintf(sdump->trace, ".%s", field.name); | |
| if (inf->pos!=-1) gf_fprintf(sdump->trace, "[%d]", inf->pos); | |
| gf_fprintf(sdump->trace, "\n"); | |
| } | |
| return GF_OK; | |
| } | |
| static GF_Err DumpNodeDelete(GF_SceneDumper *sdump, GF_Command *com) | |
| { | |
| DUMP_IND(sdump); | |
| if (sdump->XMLDump) { | |
| if (com->tag==GF_SG_NODE_DELETE_EX) { | |
| gf_fprintf(sdump->trace, "<Delete extended=\"deleteOrder\" atNode=\""); | |
| } else { | |
| gf_fprintf(sdump->trace, "<Delete atNode=\""); | |
| } | |
| scene_dump_vrml_id(sdump, com->node); | |
| gf_fprintf(sdump->trace, "\"/>\n"); | |
| } else { | |
| if (com->tag==GF_SG_NODE_DELETE_EX) gf_fprintf(sdump->trace, "X"); | |
| gf_fprintf(sdump->trace, "DELETE "); | |
| scene_dump_vrml_id(sdump, com->node); | |
| gf_fprintf(sdump->trace, "\n"); | |
| } | |
| return GF_OK; | |
| } | |
| static GF_Err DumpRouteDelete(GF_SceneDumper *sdump, GF_Command *com) | |
| { | |
| DUMP_IND(sdump); | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "<Delete atRoute=\""); | |
| scene_dump_vrml_route_id(sdump, com->RouteID, com->def_name); | |
| gf_fprintf(sdump->trace, "\"/>\n"); | |
| } else { | |
| gf_fprintf(sdump->trace, "DELETE ROUTE "); | |
| scene_dump_vrml_route_id(sdump, com->RouteID, com->def_name); | |
| gf_fprintf(sdump->trace, "\n"); | |
| } | |
| return GF_OK; | |
| } | |
| static GF_Err DumpNodeReplace(GF_SceneDumper *sdump, GF_Command *com) | |
| { | |
| GF_CommandField *inf; | |
| if (!gf_list_count(com->command_fields)) return GF_OK; | |
| inf = (GF_CommandField *) gf_list_get(com->command_fields, 0); | |
| DUMP_IND(sdump); | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "<Replace atNode=\""); | |
| scene_dump_vrml_id(sdump, com->node); | |
| gf_fprintf(sdump->trace, "\">"); | |
| gf_dump_vrml_node(sdump, inf->new_node, 0, NULL); | |
| gf_fprintf(sdump->trace, "</Replace>\n"); | |
| } else { | |
| gf_fprintf(sdump->trace, "REPLACE "); | |
| scene_dump_vrml_id(sdump, com->node); | |
| gf_fprintf(sdump->trace, " BY "); | |
| gf_dump_vrml_node(sdump, inf->new_node, 0, NULL); | |
| gf_fprintf(sdump->trace, "\n"); | |
| } | |
| return GF_OK; | |
| } | |
| static GF_Err DumpFieldReplace(GF_SceneDumper *sdump, GF_Command *com) | |
| { | |
| GF_Err e; | |
| GF_FieldInfo field; | |
| GF_CommandField *inf; | |
| if (!gf_list_count(com->command_fields)) return GF_OK; | |
| inf = (GF_CommandField *) gf_list_get(com->command_fields, 0); | |
| e = gf_node_get_field(com->node, inf->fieldIndex, &field); | |
| DUMP_IND(sdump); | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "<Replace atNode=\""); | |
| scene_dump_vrml_id(sdump, com->node); | |
| gf_fprintf(sdump->trace, "\" atField=\"%s\" ", field.name); | |
| } else { | |
| gf_fprintf(sdump->trace, "REPLACE "); | |
| scene_dump_vrml_id(sdump, com->node); | |
| gf_fprintf(sdump->trace, ".%s BY ", field.name); | |
| } | |
| switch (field.fieldType) { | |
| case GF_SG_VRML_SFNODE: | |
| if (sdump->XMLDump) gf_fprintf(sdump->trace, ">"); | |
| gf_dump_vrml_node(sdump, inf->new_node, 0, NULL); | |
| if (sdump->XMLDump) gf_fprintf(sdump->trace, "</Replace>"); | |
| else gf_fprintf(sdump->trace, "\n"); | |
| break; | |
| case GF_SG_VRML_MFNODE: | |
| { | |
| GF_ChildNodeItem *tmp; | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, ">"); | |
| } else { | |
| gf_fprintf(sdump->trace, " [\n"); | |
| } | |
| sdump->indent++; | |
| tmp = inf->node_list; | |
| while (tmp) { | |
| gf_dump_vrml_node(sdump, tmp->node, 1, NULL); | |
| tmp = tmp->next; | |
| } | |
| sdump->indent--; | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "</Replace>"); | |
| } else { | |
| EndList(sdump, NULL); | |
| } | |
| } | |
| break; | |
| case GF_SG_VRML_SFCOMMANDBUFFER: | |
| if (sdump->XMLDump) { | |
| SFCommandBuffer *cb = (SFCommandBuffer*)inf->field_ptr; | |
| gf_fprintf(sdump->trace, ">\n"); | |
| gf_sm_dump_command_list(sdump, cb->commandList, sdump->indent+1, 0); | |
| DUMP_IND(sdump); | |
| gf_fprintf(sdump->trace, "</Replace>\n"); | |
| } else { | |
| SFCommandBuffer *cb = (SFCommandBuffer*)inf->field_ptr; | |
| gf_fprintf(sdump->trace, " {\n"); | |
| gf_sm_dump_command_list(sdump, cb->commandList, sdump->indent+1, 0); | |
| DUMP_IND(sdump); | |
| gf_fprintf(sdump->trace, "}\n"); | |
| } | |
| break; | |
| default: | |
| field.far_ptr = inf->field_ptr; | |
| gf_dump_vrml_simple_field(sdump, field, com->node); | |
| if (sdump->XMLDump) gf_fprintf(sdump->trace, "/>"); | |
| gf_fprintf(sdump->trace, "\n"); | |
| } | |
| return e; | |
| } | |
| static GF_Err DumpIndexReplace(GF_SceneDumper *sdump, GF_Command *com) | |
| { | |
| char posname[20]; | |
| GF_Err e; | |
| GF_FieldInfo field; | |
| GF_CommandField *inf; | |
| if (!gf_list_count(com->command_fields)) return GF_OK; | |
| inf = (GF_CommandField *) gf_list_get(com->command_fields, 0); | |
| e = gf_node_get_field(com->node, inf->fieldIndex, &field); | |
| if (e) return e; | |
| if (gf_sg_vrml_is_sf_field(field.fieldType)) return GF_NON_COMPLIANT_BITSTREAM; | |
| switch (inf->pos) { | |
| case 0: | |
| gf_strcpy(posname, "BEGIN"); | |
| break; | |
| case -1: | |
| gf_strcpy(posname, sdump->XMLDump ? "END" : "LAST"); | |
| break; | |
| default: | |
| sprintf(posname, "%d", inf->pos); | |
| break; | |
| } | |
| DUMP_IND(sdump); | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "<Replace atNode=\""); | |
| scene_dump_vrml_id(sdump, com->node); | |
| gf_fprintf(sdump->trace, "\" atField=\"%s\" position=\"%s\"", field.name, posname); | |
| } else { | |
| gf_fprintf(sdump->trace, "REPLACE "); | |
| if (inf->pos==-1) gf_fprintf(sdump->trace, "%s ", posname); | |
| scene_dump_vrml_id(sdump, com->node); | |
| gf_fprintf(sdump->trace, ".%s", field.name); | |
| if (inf->pos!=-1) gf_fprintf(sdump->trace, "[%d]", inf->pos); | |
| gf_fprintf(sdump->trace, " BY "); | |
| } | |
| if (field.fieldType == GF_SG_VRML_MFNODE) { | |
| if (sdump->XMLDump) gf_fprintf(sdump->trace, ">\n"); | |
| gf_dump_vrml_node(sdump, inf->new_node, 0, NULL); | |
| gf_fprintf(sdump->trace, (sdump->XMLDump) ? "</Replace>\n" : "\n"); | |
| } else { | |
| field.fieldType = gf_sg_vrml_get_sf_type(field.fieldType); | |
| field.far_ptr = inf->field_ptr; | |
| gf_dump_vrml_simple_field(sdump, field, com->node); | |
| gf_fprintf(sdump->trace, sdump->XMLDump ? "/>\n" : "\n"); | |
| } | |
| return GF_OK; | |
| } | |
| static GF_Err DumpXReplace(GF_SceneDumper *sdump, GF_Command *com) | |
| { | |
| char posname[20]; | |
| GF_Err e; | |
| GF_FieldInfo field, idxField; | |
| GF_Node *toNode, *target; | |
| GF_CommandField *inf; | |
| if (!gf_list_count(com->command_fields)) return GF_OK; | |
| inf = (GF_CommandField *) gf_list_get(com->command_fields, 0); | |
| e = gf_node_get_field(com->node, inf->fieldIndex, &field); | |
| if (e) return e; | |
| toNode = target = NULL; | |
| /*indexed replacement with index given by other node field*/ | |
| if (com->toNodeID) { | |
| toNode = gf_sg_find_node(com->in_scene, com->toNodeID); | |
| if (!toNode) return GF_NON_COMPLIANT_BITSTREAM; | |
| e = gf_node_get_field(toNode, com->toFieldIndex, &idxField); | |
| if (e) return e; | |
| } | |
| else { | |
| /*indexed replacement */ | |
| if (inf->pos>=-1) { | |
| if (gf_sg_vrml_is_sf_field(field.fieldType)) return GF_NON_COMPLIANT_BITSTREAM; | |
| switch (inf->pos) { | |
| case 0: | |
| gf_strcpy(posname, "BEGIN"); | |
| break; | |
| case -1: | |
| gf_strcpy(posname, sdump->XMLDump ? "END" : "LAST"); | |
| break; | |
| default: | |
| sprintf(posname, "%d", inf->pos); | |
| break; | |
| } | |
| field.fieldType = gf_sg_vrml_get_sf_type(field.fieldType); | |
| } | |
| } | |
| field.far_ptr = inf->field_ptr; | |
| DUMP_IND(sdump); | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "<Replace atNode=\""); | |
| scene_dump_vrml_id(sdump, com->node); | |
| gf_fprintf(sdump->trace, "\" atField=\"%s\"", field.name); | |
| if (toNode) { | |
| gf_fprintf(sdump->trace, " atIndexNode=\""); | |
| scene_dump_vrml_id(sdump, toNode); | |
| gf_fprintf(sdump->trace, "\" atIndexField=\"%s\"", idxField.name); | |
| field.fieldType = gf_sg_vrml_get_sf_type(field.fieldType); | |
| } | |
| if (com->ChildNodeTag) { | |
| GF_FieldInfo cfield; | |
| GF_Node *cnode; | |
| if (com->ChildNodeTag>0) { | |
| cnode = gf_node_new(com->in_scene, com->ChildNodeTag); | |
| } else { | |
| GF_Proto *proto = gf_sg_find_proto(com->in_scene, -com->ChildNodeTag , NULL); | |
| if (!proto) return GF_SG_UNKNOWN_NODE; | |
| cnode = gf_sg_proto_create_instance(com->in_scene, proto); | |
| } | |
| if (!cnode) return GF_SG_UNKNOWN_NODE; | |
| gf_node_register(cnode, NULL); | |
| gf_node_get_field(cnode, com->child_field, &cfield); | |
| gf_fprintf(sdump->trace, " atChildField=\"%s\"", cfield.name); | |
| gf_node_unregister(cnode, NULL); | |
| field.fieldType = cfield.fieldType; | |
| } | |
| if (com->fromNodeID) { | |
| target = gf_sg_find_node(com->in_scene, com->fromNodeID); | |
| if (!target) return GF_NON_COMPLIANT_BITSTREAM; | |
| e = gf_node_get_field(target, com->fromFieldIndex, &idxField); | |
| if (e) return e; | |
| gf_fprintf(sdump->trace, " fromNode=\""); | |
| scene_dump_vrml_id(sdump, target); | |
| gf_fprintf(sdump->trace, "\" fromField=\"%s\">\n", idxField.name); | |
| return GF_OK; | |
| } else { | |
| if (inf->pos>=-1) gf_fprintf(sdump->trace, " position=\"%s\"", posname); | |
| } | |
| } else { | |
| gf_fprintf(sdump->trace, "XREPLACE "); | |
| if (inf->pos==-1) gf_fprintf(sdump->trace, "%s ", posname); | |
| scene_dump_vrml_id(sdump, com->node); | |
| gf_fprintf(sdump->trace, ".%s", field.name); | |
| if (toNode) { | |
| gf_fprintf(sdump->trace, "["); | |
| scene_dump_vrml_id(sdump, toNode); | |
| gf_fprintf(sdump->trace, ".%s]", idxField.name); | |
| field.fieldType = gf_sg_vrml_get_sf_type(field.fieldType); | |
| } | |
| else if (inf->pos!=-1) gf_fprintf(sdump->trace, "[%d]", inf->pos); | |
| if (com->ChildNodeTag) { | |
| GF_FieldInfo cfield; | |
| GF_Node *cnode; | |
| if (com->ChildNodeTag>0) { | |
| cnode = gf_node_new(com->in_scene, com->ChildNodeTag); | |
| } else { | |
| GF_Proto *proto = gf_sg_find_proto(com->in_scene, -com->ChildNodeTag , NULL); | |
| if (!proto) return GF_SG_UNKNOWN_NODE; | |
| cnode = gf_sg_proto_create_instance(com->in_scene, proto); | |
| } | |
| if (!cnode) return GF_SG_UNKNOWN_NODE; | |
| gf_node_register(cnode, NULL); | |
| gf_node_get_field(cnode, com->child_field, &cfield); | |
| gf_fprintf(sdump->trace, ".%s", cfield.name); | |
| gf_node_unregister(cnode, NULL); | |
| field.fieldType = cfield.fieldType; | |
| } | |
| gf_fprintf(sdump->trace, " BY "); | |
| } | |
| if (field.fieldType == GF_SG_VRML_MFNODE) { | |
| if (sdump->XMLDump) gf_fprintf(sdump->trace, ">\n"); | |
| gf_dump_vrml_node(sdump, inf->new_node, 0, NULL); | |
| gf_fprintf(sdump->trace, (sdump->XMLDump) ? "</Replace>\n" : "\n"); | |
| } else { | |
| gf_dump_vrml_simple_field(sdump, field, com->node); | |
| gf_fprintf(sdump->trace, sdump->XMLDump ? "/>\n" : "\n"); | |
| } | |
| return GF_OK; | |
| } | |
| static GF_Err DumpRouteReplace(GF_SceneDumper *sdump, GF_Command *com) | |
| { | |
| const char *name; | |
| GF_Route r2; | |
| if (!scene_dump_vrml_find_route_name(sdump, com->RouteID, &name)) return GF_BAD_PARAM; | |
| memset(&r2, 0, sizeof(GF_Route)); | |
| r2.FromNode = gf_dump_find_node(sdump, com->fromNodeID); | |
| r2.FromField.fieldIndex = com->fromFieldIndex; | |
| r2.ToNode = gf_dump_find_node(sdump, com->toNodeID); | |
| r2.ToField.fieldIndex = com->toFieldIndex; | |
| DUMP_IND(sdump); | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "<Replace atRoute=\""); | |
| scene_dump_vrml_route_id(sdump, com->RouteID, (char *) name); | |
| gf_fprintf(sdump->trace, "\">\n"); | |
| } else { | |
| gf_fprintf(sdump->trace, "REPLACE ROUTE "); | |
| scene_dump_vrml_route_id(sdump, com->RouteID, (char *) name); | |
| gf_fprintf(sdump->trace, " BY "); | |
| } | |
| gf_dump_vrml_route(sdump, &r2, 1); | |
| if (sdump->XMLDump ) gf_fprintf(sdump->trace, "</Replace>"); | |
| return GF_OK; | |
| } | |
| static GF_Err gf_dump_vrml_route(GF_SceneDumper *sdump, GF_Route *r, u32 dump_type) | |
| { | |
| char toNodeBuf[100], fromNodeBuf[100], *to_node_p, *from_node_p; | |
| const char *node_name; | |
| u32 id; | |
| if (!r->is_setup) { | |
| gf_node_get_field(r->FromNode, r->FromField.fieldIndex, &r->FromField); | |
| gf_node_get_field(r->ToNode, r->ToField.fieldIndex, &r->ToField); | |
| r->is_setup = 1; | |
| } | |
| if (!r->FromNode || !r->ToNode) return GF_BAD_PARAM; | |
| if (sdump->XMLDump || !dump_type) DUMP_IND(sdump); | |
| to_node_p = toNodeBuf; | |
| from_node_p = fromNodeBuf; | |
| node_name = gf_node_get_name_and_id(r->FromNode, &id); | |
| if (node_name) { | |
| const char *to_name; | |
| from_node_p = (char *)node_name; | |
| to_name = gf_node_get_name(r->ToNode); | |
| if (to_name) { | |
| to_node_p = (char *) to_name; | |
| } else { | |
| id = gf_node_get_id(r->ToNode); | |
| sprintf(toNodeBuf, "node_%d", id); | |
| } | |
| } else { | |
| sprintf(fromNodeBuf, "N%d", id-1); | |
| sprintf(toNodeBuf, "N%d", gf_node_get_id(r->ToNode) - 1); | |
| } | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "<ROUTE"); | |
| if (r->ID) { | |
| StartAttribute(sdump, "DEF"); | |
| scene_dump_vrml_route_id(sdump, r->ID, r->name); | |
| EndAttribute(sdump); | |
| } | |
| gf_fprintf(sdump->trace, " fromNode=\"%s\" fromField=\"%s\" toNode=\"%s\" toField=\"%s\"/>\n", from_node_p, r->FromField.name, to_node_p, r->ToField.name); | |
| } else { | |
| if (dump_type==2) gf_fprintf(sdump->trace, "ROUTE "); | |
| if (r->ID) { | |
| gf_fprintf(sdump->trace, "DEF "); | |
| scene_dump_vrml_route_id(sdump, r->ID, r->name); | |
| gf_fprintf(sdump->trace, " "); | |
| } | |
| if (dump_type==1) { | |
| gf_fprintf(sdump->trace, "%s.%s TO %s.%s\n", from_node_p, r->FromField.name, to_node_p, r->ToField.name); | |
| } else { | |
| if (dump_type!=2) gf_fprintf(sdump->trace, "ROUTE "); | |
| gf_fprintf(sdump->trace, "%s.%s TO %s.%s\n", from_node_p, r->FromField.name, to_node_p, r->ToField.name); | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| static GF_Err DumpProtos(GF_SceneDumper *sdump, GF_List *protoList) | |
| { | |
| #ifdef GPAC_DISABLE_VRML | |
| return GF_OK; | |
| #else | |
| u32 i, j, count; | |
| GF_FieldInfo field; | |
| GF_Err e; | |
| GF_SceneGraph *prev_sg; | |
| GF_Proto *proto, *prev_proto; | |
| prev_proto = sdump->current_proto; | |
| i=0; | |
| while ((proto = (GF_Proto*)gf_list_enum(protoList, &i))) { | |
| sdump->current_proto = proto; | |
| DUMP_IND(sdump); | |
| if (!sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, proto->ExternProto.count ? "EXTERNPROTO " : "PROTO "); | |
| gf_fprintf(sdump->trace, "%s [\n", proto->Name); | |
| } else { | |
| gf_fprintf(sdump->trace, "<ProtoDeclare name=\"%s\" protoID=\"%d\"", proto->Name, proto->ID); | |
| if (proto->ExternProto.count) { | |
| gf_fprintf(sdump->trace, " locations=\""); | |
| gf_dump_vrml_sffield(sdump, GF_SG_VRML_SFURL, &proto->ExternProto.vals[0], 0, NULL); | |
| gf_fprintf(sdump->trace, "\""); | |
| } | |
| gf_fprintf(sdump->trace, ">\n"); | |
| } | |
| if (sdump->XMLDump && sdump->X3DDump) gf_fprintf(sdump->trace, "<ProtoInterface>"); | |
| sdump->indent++; | |
| count = gf_list_count(proto->proto_fields); | |
| for (j=0; j<count; j++) { | |
| GF_ProtoFieldInterface *pf = (GF_ProtoFieldInterface *)gf_list_get(proto->proto_fields, j); | |
| field.fieldIndex = pf->ALL_index; | |
| field.eventType = pf->EventType; | |
| field.far_ptr = pf->def_value; | |
| field.fieldType = pf->FieldType; | |
| field.name = pf->FieldName; | |
| field.NDTtype = NDT_SFWorldNode; | |
| field.on_event_in = NULL; | |
| gf_dump_vrml_dyn_field(sdump, NULL, field, pf->QP_Type ? 1 : 0); | |
| if (!pf->QP_Type) continue; | |
| /*dump interface coding - BT/TXT extensions, not supported by any other tool*/ | |
| sdump->indent++; | |
| DUMP_IND(sdump); | |
| if (sdump->XMLDump) { | |
| const char *quant_catname = "unknown"; | |
| #ifndef GPAC_DISABLE_BIFS | |
| switch (pf->QP_Type) { | |
| case QC_3DPOS: quant_catname = "position3D"; break; | |
| case QC_2DPOS: quant_catname = "position2D"; break; | |
| case QC_ORDER: quant_catname = "drawingOrder"; break; | |
| case QC_COLOR: quant_catname = "color"; break; | |
| case QC_TEXTURE_COORD: quant_catname = "textureCoordinate"; break; | |
| case QC_ANGLE: quant_catname = "angle"; break; | |
| case QC_SCALE: quant_catname = "scale"; break; | |
| case QC_INTERPOL_KEYS: quant_catname = "keys"; break; | |
| case QC_NORMALS: quant_catname = "normals"; break; | |
| case QC_ROTATION: quant_catname = "rotations"; break; | |
| case QC_SIZE_3D: quant_catname = "size3D"; break; | |
| case QC_SIZE_2D: quant_catname = "size2D"; break; | |
| case QC_LINEAR_SCALAR: quant_catname = "linear"; break; | |
| case QC_COORD_INDEX:quant_catname = "coordIndex"; break; | |
| } | |
| #endif | |
| gf_fprintf(sdump->trace, "<InterfaceCodingParameters quantCategoy=\"%s\"", quant_catname); | |
| } else { | |
| gf_fprintf(sdump->trace, "{QP %d", pf->QP_Type); | |
| } | |
| #ifndef GPAC_DISABLE_BIFS | |
| if (pf->QP_Type==QC_LINEAR_SCALAR) gf_fprintf(sdump->trace, sdump->XMLDump ? " nbBits=\"%d\"" : " nbBits %d", pf->NumBits); | |
| if (pf->hasMinMax) { | |
| switch (pf->QP_Type) { | |
| case QC_LINEAR_SCALAR: | |
| case QC_COORD_INDEX: | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, " intMin=\"%d\" intMax=\"%d\"", *((SFInt32 *)pf->qp_min_value), *((SFInt32 *)pf->qp_max_value)); | |
| } else { | |
| gf_fprintf(sdump->trace, " b {%d %d}", *((SFInt32 *)pf->qp_min_value), *((SFInt32 *)pf->qp_max_value)); | |
| } | |
| break; | |
| default: | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, " floatMin=\"%g\" floatMax=\"%g\"", FIX2FLT( *((SFFloat *)pf->qp_min_value) ), FIX2FLT( *((SFFloat *)pf->qp_max_value) )); | |
| } else { | |
| gf_fprintf(sdump->trace, " b {%g %g}", FIX2FLT( *((SFFloat *)pf->qp_min_value) ), FIX2FLT( *((SFFloat *)pf->qp_max_value) ) ); | |
| } | |
| break; | |
| } | |
| } | |
| #endif | |
| gf_fprintf(sdump->trace, sdump->XMLDump ? "/>\n" : "}\n"); | |
| sdump->indent--; | |
| if (sdump->XMLDump) { | |
| DUMP_IND(sdump); | |
| gf_fprintf(sdump->trace, "</field>\n"); | |
| } | |
| } | |
| sdump->indent--; | |
| DUMP_IND(sdump); | |
| if (!sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "]"); | |
| } else if (sdump->X3DDump) gf_fprintf(sdump->trace, "</ProtoInterface>\n"); | |
| if (proto->ExternProto.count) { | |
| if (!sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, " \""); | |
| gf_dump_vrml_sffield(sdump, GF_SG_VRML_SFURL, &proto->ExternProto.vals[0], 0, NULL); | |
| gf_fprintf(sdump->trace, "\"\n\n"); | |
| } else { | |
| gf_fprintf(sdump->trace, "</ProtoDeclare>\n"); | |
| } | |
| continue; | |
| } | |
| if (!sdump->XMLDump) gf_fprintf(sdump->trace, " {\n"); | |
| sdump->indent++; | |
| if (sdump->XMLDump && sdump->X3DDump) gf_fprintf(sdump->trace, "<ProtoBody>\n"); | |
| e = DumpProtos(sdump, proto->sub_graph->protos); | |
| if (e) return e; | |
| /*set namespace to the proto one*/ | |
| prev_sg = sdump->sg; | |
| sdump->sg = gf_sg_proto_get_graph(proto); | |
| count = gf_list_count(proto->node_code); | |
| for (j=0; j<count; j++) { | |
| GF_Node *n = (GF_Node*)gf_list_get(proto->node_code, j); | |
| gf_dump_vrml_node(sdump, n, 1, NULL); | |
| } | |
| count = gf_list_count(proto->sub_graph->Routes); | |
| for (j=0; j<count; j++) { | |
| GF_Route *r = (GF_Route *)gf_list_get(proto->sub_graph->Routes, j); | |
| if (r->IS_route) continue; | |
| gf_dump_vrml_route(sdump, r, 0); | |
| } | |
| if (sdump->XMLDump && sdump->X3DDump) gf_fprintf(sdump->trace, "</ProtoBody>\n"); | |
| /*restore namespace*/ | |
| sdump->sg = prev_sg; | |
| sdump->indent--; | |
| DUMP_IND(sdump); | |
| if (!sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "}\n"); | |
| } else { | |
| gf_fprintf(sdump->trace, "</ProtoDeclare>\n"); | |
| } | |
| } | |
| sdump->current_proto = prev_proto; | |
| return GF_OK; | |
| #endif | |
| } | |
| static GF_Err DumpSceneReplace(GF_SceneDumper *sdump, GF_Command *com) | |
| { | |
| if (sdump->XMLDump) { | |
| if (!sdump->X3DDump) { | |
| StartElement(sdump, "Replace"); | |
| EndElementHeader(sdump, 1); | |
| sdump->indent++; | |
| } | |
| //scene tag is already dumped with X3D header | |
| if (!sdump->X3DDump) StartElement(sdump, "Scene"); | |
| if (!sdump->X3DDump && com->use_names) { | |
| StartAttribute(sdump, "USENAMES"); | |
| gf_fprintf(sdump->trace, "%s", com->use_names ? "true" : "false"); | |
| EndAttribute(sdump); | |
| } | |
| if (!sdump->X3DDump) EndElementHeader(sdump, 1); | |
| sdump->indent++; | |
| } else { | |
| if (!sdump->skip_scene_replace) { | |
| DUMP_IND(sdump); | |
| gf_fprintf(sdump->trace, "REPLACE SCENE BY "); | |
| } | |
| } | |
| DumpProtos(sdump, com->new_proto_list); | |
| gf_dump_vrml_node(sdump, com->node, 0, NULL); | |
| if (!sdump->XMLDump) gf_fprintf(sdump->trace, "\n\n"); | |
| if (com->aggregated) { | |
| u32 i, count; | |
| count = gf_list_count(com->node->sgprivate->scenegraph->Routes); | |
| for (i=0; i<count; i++) { | |
| GF_Route *r = (GF_Route *)gf_list_get(com->node->sgprivate->scenegraph->Routes, i); | |
| if (r->IS_route) continue; | |
| gf_dump_vrml_route(sdump, r, 0); | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| static GF_Err DumpProtoInsert(GF_SceneDumper *sdump, GF_Command *com) | |
| { | |
| DUMP_IND(sdump); | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "<Insert extended=\"proto\">\n"); | |
| } else { | |
| gf_fprintf(sdump->trace, "INSERTPROTO [\n"); | |
| } | |
| sdump->indent++; | |
| DumpProtos(sdump, com->new_proto_list); | |
| sdump->indent--; | |
| DUMP_IND(sdump); | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "</Insert>\n"); | |
| } else { | |
| gf_fprintf(sdump->trace, "]\n"); | |
| } | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_DISABLE_VRML*/ | |
| #ifndef GPAC_DISABLE_SVG | |
| static char *lsr_format_node_id(GF_Node *n, u32 NodeID, char *str) | |
| { | |
| if (!n) sprintf(str, "N%d", NodeID-1); | |
| else { | |
| const char *name = gf_node_get_name_and_id(n, &NodeID); | |
| if (name) sprintf(str, "%s", name); | |
| else sprintf(str, "N%d", NodeID - 1); | |
| } | |
| return str; | |
| } | |
| static char szLSRName[1024]; | |
| static char *sd_get_lsr_namespace(GF_SceneGraph *sg) | |
| { | |
| char *lsrns = (char *) gf_sg_get_namespace_qname(sg, GF_XMLNS_LASER); | |
| if (lsrns) { | |
| sprintf(szLSRName, "%s:", lsrns); | |
| return szLSRName; | |
| } | |
| return ""; | |
| } | |
| static GF_Err DumpLSRNewScene(GF_SceneDumper *sdump, GF_Command *com) | |
| { | |
| char *lsrns = sd_get_lsr_namespace(com->in_scene); | |
| gf_fprintf(sdump->trace, "<%sNewScene>\n", lsrns); | |
| gf_dump_svg_element(sdump, com->node, NULL, 0); | |
| gf_fprintf(sdump->trace, "</%sNewScene>\n", lsrns); | |
| return GF_OK; | |
| } | |
| static GF_Err DumpLSRAddReplaceInsert(GF_SceneDumper *sdump, GF_Command *com) | |
| { | |
| char szID[100]; | |
| Bool is_text = 0; | |
| GF_CommandField *f; | |
| char *lsrns = sd_get_lsr_namespace(com->in_scene); | |
| const char *com_name = (com->tag==GF_SG_LSR_REPLACE) ? "Replace" : ( (com->tag==GF_SG_LSR_ADD) ? "Add" : "Insert" ); | |
| DUMP_IND(sdump); | |
| gf_fprintf(sdump->trace, "<%s%s ref=\"%s\" ", lsrns, com_name, lsr_format_node_id(com->node, com->RouteID, szID)); | |
| f = (GF_CommandField *) gf_list_get(com->command_fields, 0); | |
| if (f && (f->pos>=0) ) gf_fprintf(sdump->trace, "index=\"%d\" ", f->pos); | |
| if (f) { | |
| GF_FieldInfo info; | |
| if (!f->new_node && !f->node_list) { | |
| char *att_name = NULL; | |
| if (f->fieldType==SVG_Transform_Scale_datatype) att_name = "scale"; | |
| else if (f->fieldType==SVG_Transform_Rotate_datatype) att_name = "rotation"; | |
| else if (f->fieldType==SVG_Transform_Translate_datatype) att_name = "translation"; | |
| else if (f->fieldIndex==(u32) -1) att_name = "textContent"; | |
| else { | |
| if (!com->node) return GF_NON_COMPLIANT_BITSTREAM; | |
| att_name = (char*) gf_svg_get_attribute_name(com->node, f->fieldIndex); | |
| } | |
| gf_fprintf(sdump->trace, "attributeName=\"%s\" ", att_name); | |
| if (f->field_ptr) { | |
| char *att; | |
| info.far_ptr = f->field_ptr; | |
| info.fieldIndex = f->fieldIndex; | |
| info.fieldType = f->fieldType; | |
| info.name = att_name; | |
| if ((s32) f->pos >= 0) { | |
| att = gf_svg_dump_attribute_indexed(com->node, &info); | |
| } else { | |
| att = gf_svg_dump_attribute(com->node, &info); | |
| } | |
| gf_fprintf(sdump->trace, "value=\"%s\" ", att ? att : ""); | |
| if (att) gf_free(att); | |
| } | |
| if (com->fromNodeID) { | |
| GF_FieldInfo op_info; | |
| GF_Node *op = gf_sg_find_node(sdump->sg, com->fromNodeID); | |
| gf_fprintf(sdump->trace, "operandElementId=\"%s\" ", lsr_format_node_id(op, com->RouteID, szID)); | |
| gf_node_get_field(op, com->fromFieldIndex, &op_info); | |
| gf_fprintf(sdump->trace, "operandAttributeName=\"%s\" ", op_info.name); | |
| } | |
| gf_fprintf(sdump->trace, "/>\n"); | |
| return GF_OK; | |
| } | |
| if (f->new_node && f->new_node->sgprivate->tag==TAG_DOMText) is_text = 1; | |
| /*if fieldIndex (eg attributeName) is set, this is children replacement*/ | |
| if (f->fieldIndex>0) | |
| gf_fprintf(sdump->trace, "attributeName=\"children\" "); | |
| } | |
| gf_fprintf(sdump->trace, ">"); | |
| if (!is_text) { | |
| gf_fprintf(sdump->trace, "\n"); | |
| sdump->indent++; | |
| } | |
| if (f) { | |
| if (f->new_node) { | |
| gf_dump_svg_element(sdump, f->new_node, com->node, 0); | |
| } else if (f->node_list) { | |
| GF_ChildNodeItem *list = f->node_list; | |
| while (list) { | |
| gf_dump_svg_element(sdump, list->node, com->node, 0); | |
| list = list->next; | |
| } | |
| } | |
| } | |
| if (!is_text) { | |
| sdump->indent--; | |
| DUMP_IND(sdump); | |
| } | |
| gf_fprintf(sdump->trace, "</%s%s>\n", lsrns, com_name); | |
| return GF_OK; | |
| } | |
| static GF_Err DumpLSRDelete(GF_SceneDumper *sdump, GF_Command *com) | |
| { | |
| char szID[1024]; | |
| GF_CommandField *f; | |
| char *lsrns = sd_get_lsr_namespace(com->in_scene); | |
| DUMP_IND(sdump); | |
| gf_fprintf(sdump->trace, "<%sDelete ref=\"%s\" ", lsrns, lsr_format_node_id(com->node, com->RouteID, szID)); | |
| f = (GF_CommandField *) gf_list_get(com->command_fields, 0); | |
| if (f && (f->pos>=0) ) gf_fprintf(sdump->trace, "index=\"%d\" ", f->pos); | |
| gf_fprintf(sdump->trace, "/>\n"); | |
| return GF_OK; | |
| } | |
| #ifdef GPAC_UNUSED_FUNC | |
| static GF_Err DumpLSRInsert(GF_SceneDumper *sdump, GF_Command *com) | |
| { | |
| return GF_OK; | |
| } | |
| static GF_Err SD_SetSceneGraph(GF_SceneDumper *sdump, GF_SceneGraph *sg) | |
| { | |
| if (sdump) sdump->sg = sg; | |
| return GF_OK; | |
| } | |
| static GF_Err DumpLSRClean(GF_SceneDumper *sdump, GF_Command *com) | |
| { | |
| return GF_OK; | |
| } | |
| static GF_Err DumpLSRRestore(GF_SceneDumper *sdump, GF_Command *com) | |
| { | |
| return GF_OK; | |
| } | |
| static GF_Err DumpLSRSave(GF_SceneDumper *sdump, GF_Command *com) | |
| { | |
| return GF_OK; | |
| } | |
| #endif /*GPAC_UNUSED_FUNC*/ | |
| static GF_Err DumpLSRSendEvent(GF_SceneDumper *sdump, GF_Command *com) | |
| { | |
| char szID[1024]; | |
| char *lsrns = sd_get_lsr_namespace(com->in_scene); | |
| DUMP_IND(sdump); | |
| gf_fprintf(sdump->trace, "<%sSendEvent ref=\"%s\" event=\"%s\"", lsrns, | |
| lsr_format_node_id(com->node, com->RouteID, szID), | |
| gf_dom_event_get_name(com->send_event_name) | |
| ); | |
| if ((com->send_event_name <= GF_EVENT_MOUSEWHEEL) | |
| || (com->send_event_name == GF_EVENT_MOUSEOUT) | |
| || (com->send_event_name == GF_EVENT_MOUSEOVER) | |
| ) { | |
| gf_fprintf(sdump->trace, " pointvalue=\"%g %g\"", FIX2FLT(com->send_event_x), FIX2FLT(com->send_event_y) ); | |
| } | |
| switch (com->send_event_name) { | |
| case GF_EVENT_KEYDOWN: | |
| case GF_EVENT_LONGKEYPRESS: | |
| case GF_EVENT_REPEAT_KEY: | |
| case GF_EVENT_SHORT_ACCESSKEY: | |
| if (com->send_event_integer) { | |
| gf_fprintf(sdump->trace, " stringvalue=\"%s\"", gf_dom_get_key_name(com->send_event_integer) ); | |
| break; | |
| } | |
| default: | |
| if (com->send_event_integer) | |
| gf_fprintf(sdump->trace, " intvalue=\"%d\"", com->send_event_integer); | |
| if (com->send_event_string) | |
| gf_fprintf(sdump->trace, " stringvalue=\"%s\"", com->send_event_string); | |
| break; | |
| } | |
| gf_fprintf(sdump->trace, "/>\n"); | |
| return GF_OK; | |
| } | |
| static GF_Err DumpLSRActivate(GF_SceneDumper *sdump, GF_Command *com) | |
| { | |
| char szID[1024]; | |
| char *lsrns = sd_get_lsr_namespace(com->in_scene); | |
| DUMP_IND(sdump); | |
| if (com->tag==GF_SG_LSR_ACTIVATE) { | |
| gf_fprintf(sdump->trace, "<%sActivate ref=\"%s\" />\n", lsrns, lsr_format_node_id(com->node, com->RouteID, szID)); | |
| } else { | |
| gf_fprintf(sdump->trace, "<%sDeactivate ref=\"%s\" />\n", lsrns, lsr_format_node_id(com->node, com->RouteID, szID)); | |
| } | |
| return GF_OK; | |
| } | |
| #endif | |
| GF_EXPORT | |
| GF_Err gf_sm_dump_command_list(GF_SceneDumper *sdump, GF_List *comList, u32 indent, Bool skip_first_replace) | |
| { | |
| GF_Err e; | |
| u32 i, count; | |
| u32 prev_ind; | |
| #ifndef GPAC_DISABLE_VRML | |
| u32 remain = 0, has_scene_replace = 0; | |
| #endif | |
| Bool prev_skip; | |
| if (!sdump || !sdump->trace|| !comList || !sdump->sg) return GF_BAD_PARAM; | |
| prev_skip = sdump->skip_scene_replace; | |
| sdump->skip_scene_replace = skip_first_replace; | |
| prev_ind = sdump->indent; | |
| sdump->indent = indent; | |
| e = GF_OK; | |
| count = gf_list_count(comList); | |
| for (i=0; i<count; i++) { | |
| GF_Command *com = (GF_Command *) gf_list_get(comList, i); | |
| if (i | |
| #ifndef GPAC_DISABLE_VRML | |
| && !remain | |
| #endif | |
| && (sdump->X3DDump || (sdump->dump_mode==GF_SM_DUMP_VRML)) | |
| ) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[Scene Dump] MPEG-4 Commands found, not supported in %s - skipping\n", sdump->X3DDump ? "X3D" : "VRML")); | |
| break; | |
| } | |
| #ifndef GPAC_DISABLE_VRML | |
| if (has_scene_replace && (com->tag != GF_SG_ROUTE_INSERT)) { | |
| has_scene_replace = 0; | |
| if (sdump->XMLDump) { | |
| sdump->indent--; | |
| EndElement(sdump, "Scene", 1); | |
| sdump->indent--; | |
| EndElement(sdump, "Replace", 1); | |
| } else { | |
| DUMP_IND(sdump); | |
| gf_fprintf(sdump->trace, "\nAT 0 {\n"); | |
| sdump->indent++; | |
| } | |
| } | |
| #endif | |
| switch (com->tag) { | |
| #ifndef GPAC_DISABLE_VRML | |
| /*insert commands*/ | |
| case GF_SG_NODE_INSERT: | |
| e = DumpNodeInsert(sdump, com); | |
| break; | |
| case GF_SG_INDEXED_INSERT: | |
| e = DumpIndexInsert(sdump, com); | |
| break; | |
| case GF_SG_ROUTE_INSERT: | |
| e = DumpRouteInsert(sdump, com, has_scene_replace); | |
| if (remain) remain--; | |
| break; | |
| /*delete commands*/ | |
| case GF_SG_NODE_DELETE: | |
| e = DumpNodeDelete(sdump, com); | |
| break; | |
| case GF_SG_INDEXED_DELETE: | |
| e = DumpIndexDelete(sdump, com); | |
| break; | |
| case GF_SG_ROUTE_DELETE: | |
| e = DumpRouteDelete(sdump, com); | |
| break; | |
| /*replace commands*/ | |
| case GF_SG_NODE_REPLACE: | |
| e = DumpNodeReplace(sdump, com); | |
| break; | |
| case GF_SG_FIELD_REPLACE: | |
| e = DumpFieldReplace(sdump, com); | |
| break; | |
| case GF_SG_INDEXED_REPLACE: | |
| e = DumpIndexReplace(sdump, com); | |
| break; | |
| case GF_SG_ROUTE_REPLACE: | |
| e = DumpRouteReplace(sdump, com); | |
| break; | |
| case GF_SG_XREPLACE: | |
| e = DumpXReplace(sdump, com); | |
| break; | |
| case GF_SG_SCENE_REPLACE: | |
| /*we don't support replace scene in conditional*/ | |
| if (sdump->current_com_list) | |
| return GF_NOT_SUPPORTED; | |
| sdump->current_com_list = comList; | |
| e = DumpSceneReplace(sdump, com); | |
| sdump->current_com_list = NULL; | |
| has_scene_replace = 1; | |
| remain = count - i - 1; | |
| break; | |
| /*extended commands*/ | |
| case GF_SG_PROTO_INSERT: | |
| e = DumpProtoInsert(sdump, com); | |
| break; | |
| case GF_SG_PROTO_DELETE_ALL: | |
| DUMP_IND(sdump); | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "<Delete extended=\"allProtos\"/>\n"); | |
| } else { | |
| gf_fprintf(sdump->trace, "DELETEPROTO ALL\n"); | |
| } | |
| e = GF_OK; | |
| break; | |
| case GF_SG_PROTO_DELETE: | |
| { | |
| u32 j; | |
| DUMP_IND(sdump); | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "<Delete extended=\"protos\" value=\""); | |
| } else { | |
| gf_fprintf(sdump->trace, "DELETEPROTO ["); | |
| } | |
| for (j=0; j<com->del_proto_list_size; j++) { | |
| if (j) gf_fprintf(sdump->trace, " "); | |
| gf_fprintf(sdump->trace, "%d", com->del_proto_list[j]); | |
| } | |
| if (sdump->XMLDump) { | |
| gf_fprintf(sdump->trace, "\"/>\n"); | |
| } else { | |
| gf_fprintf(sdump->trace, "]\n"); | |
| } | |
| e = GF_OK; | |
| } | |
| break; | |
| case GF_SG_GLOBAL_QUANTIZER: | |
| e = DumpGlobalQP(sdump, com); | |
| break; | |
| case GF_SG_MULTIPLE_REPLACE: | |
| e = DumpMultipleReplace(sdump, com); | |
| break; | |
| case GF_SG_MULTIPLE_INDEXED_REPLACE: | |
| e = DumpMultipleIndexedReplace(sdump, com); | |
| break; | |
| case GF_SG_NODE_DELETE_EX: | |
| e = DumpNodeDelete(sdump, com); | |
| break; | |
| #endif | |
| #ifndef GPAC_DISABLE_SVG | |
| /*laser commands*/ | |
| case GF_SG_LSR_NEW_SCENE: | |
| e = DumpLSRNewScene(sdump, com); | |
| break; | |
| case GF_SG_LSR_ADD: | |
| e = DumpLSRAddReplaceInsert(sdump, com); | |
| break; | |
| case GF_SG_LSR_CLEAN: | |
| //e = DumpLSRClean(sdump, com); | |
| break; | |
| case GF_SG_LSR_REPLACE: | |
| e = DumpLSRAddReplaceInsert(sdump, com); | |
| break; | |
| case GF_SG_LSR_DELETE: | |
| e = DumpLSRDelete(sdump, com); | |
| break; | |
| case GF_SG_LSR_INSERT: | |
| e = DumpLSRAddReplaceInsert(sdump, com); | |
| break; | |
| case GF_SG_LSR_RESTORE: | |
| //e = DumpLSRRestore(sdump, com); | |
| break; | |
| case GF_SG_LSR_SAVE: | |
| //e = DumpLSRSave(sdump, com); | |
| break; | |
| case GF_SG_LSR_SEND_EVENT: | |
| e = DumpLSRSendEvent(sdump, com); | |
| break; | |
| case GF_SG_LSR_ACTIVATE: | |
| case GF_SG_LSR_DEACTIVATE: | |
| e = DumpLSRActivate(sdump, com); | |
| break; | |
| #endif | |
| } | |
| if (e) break; | |
| if (sdump->skip_scene_replace | |
| #ifndef GPAC_DISABLE_VRML | |
| && !has_scene_replace | |
| #endif | |
| ) { | |
| sdump->skip_scene_replace = 0; | |
| if (!sdump->XMLDump && (i+1<count)) { | |
| DUMP_IND(sdump); | |
| gf_fprintf(sdump->trace, "\nAT 0 {\n"); | |
| sdump->indent++; | |
| } | |
| } | |
| } | |
| #ifndef GPAC_DISABLE_VRML | |
| if (remain && !sdump->XMLDump) { | |
| sdump->indent--; | |
| DUMP_IND(sdump); | |
| gf_fprintf(sdump->trace, "}\n"); | |
| } | |
| if (has_scene_replace && sdump->XMLDump) { | |
| sdump->indent--; | |
| if (!sdump->X3DDump) { | |
| EndElement(sdump, "Scene", 1); | |
| sdump->indent--; | |
| EndElement(sdump, "Replace", 1); | |
| } | |
| } | |
| #endif | |
| sdump->indent = prev_ind; | |
| sdump->skip_scene_replace = prev_skip; | |
| return e; | |
| } | |
| #ifndef GPAC_DISABLE_SVG | |
| void gf_dump_svg_element(GF_SceneDumper *sdump, GF_Node *n, GF_Node *parent, Bool is_root) | |
| { | |
| GF_ChildNodeItem *list; | |
| char attName[100], *attValue; | |
| u32 nID; | |
| SVG_Element *svg = (SVG_Element *)n; | |
| GF_FieldInfo info; | |
| SVGAttribute *att; | |
| u32 tag, ns; | |
| if (!n) return; | |
| nID = gf_node_get_id(n); | |
| tag = n->sgprivate->tag; | |
| /*remove undef listener/handlers*/ | |
| if (!nID) { | |
| switch (tag) { | |
| case TAG_SVG_listener: | |
| if ((0) && gf_node_get_attribute_by_tag(n, TAG_XMLEV_ATT_handler, 0, 0, &info)==GF_OK) { | |
| if (((XMLRI*)info.far_ptr)->target && !gf_node_get_id(((XMLRI*)info.far_ptr)->target) ) | |
| return; | |
| } | |
| break; | |
| case TAG_SVG_handler: | |
| /*this handler was not declared in the graph*/ | |
| if (!n->sgprivate->parents || (n->sgprivate->parents->node != parent)) | |
| return; | |
| break; | |
| case TAG_DOMText: | |
| { | |
| GF_DOMText *txt = (GF_DOMText *)n; | |
| if (txt->textContent) { | |
| if ((txt->type==GF_DOM_TEXT_CDATA) | |
| || (parent && (parent->sgprivate->tag == TAG_SVG_script)) | |
| || (parent && (parent->sgprivate->tag == TAG_SVG_handler)) | |
| ) { | |
| gf_fprintf(sdump->trace, "<![CDATA["); | |
| gf_fprintf(sdump->trace, "%s", txt->textContent); | |
| gf_fprintf(sdump->trace, "]]>"); | |
| } else if (txt->type==GF_DOM_TEXT_REGULAR) { | |
| scene_dump_utf_string(sdump, 0, txt->textContent); | |
| } | |
| } | |
| } | |
| return; | |
| } | |
| } | |
| if (!sdump->in_text) { | |
| DUMP_IND(sdump); | |
| } | |
| /*register all namespaces specified on this element */ | |
| gf_xml_push_namespaces((GF_DOMNode *)n); | |
| gf_fprintf(sdump->trace, "<%s", gf_node_get_class_name(n)); | |
| ns = gf_xml_get_element_namespace(n); | |
| if (nID) { | |
| char attID[100]; | |
| gf_fprintf(sdump->trace, " id=\"%s\"", lsr_format_node_id(n, 0, attID)); | |
| } | |
| att = svg->attributes; | |
| while (att) { | |
| if (att->data_type==SVG_ID_datatype) { | |
| att = att->next; | |
| continue; | |
| } | |
| info.fieldIndex = att->tag; | |
| info.fieldType = att->data_type; | |
| if (att->tag==TAG_DOM_ATT_any) { | |
| u32 att_ns = ((GF_DOMFullAttribute*)att)->xmlns; | |
| info.name = ((GF_DOMFullAttribute*)att)->name; | |
| if ((att_ns != ns) && strncmp(info.name, "xmlns", 5)) { | |
| sprintf(attName, "%s:%s", gf_sg_get_namespace_qname(gf_node_get_graph(n), att_ns), ((GF_DOMFullAttribute*)att)->name); | |
| info.name = attName; | |
| } | |
| } else { | |
| info.name = gf_svg_get_attribute_name(n, att->tag); | |
| } | |
| if (att->data_type==XMLRI_datatype) { | |
| XMLRI *xlink = (XMLRI *)att->data; | |
| if (xlink->type==XMLRI_ELEMENTID) { | |
| if (!xlink->target || !gf_node_get_id((GF_Node*)xlink->target) ) { | |
| att = att->next; | |
| continue; | |
| } | |
| if (parent && (parent == (GF_Node *) xlink->target)) { | |
| att = att->next; | |
| continue; | |
| } | |
| } | |
| else if (xlink->type==XMLRI_STREAMID) { | |
| gf_fprintf(sdump->trace, " %s=\"#stream%d\"", info.name, xlink->lsr_stream_id); | |
| att = att->next; | |
| continue; | |
| } else { | |
| gf_fprintf(sdump->trace, " %s=\"%s\"", info.name, xlink->string); | |
| att = att->next; | |
| continue; | |
| } | |
| } | |
| info.far_ptr = att->data; | |
| attValue = gf_svg_dump_attribute((GF_Node*)svg, &info); | |
| if (attValue) { | |
| if (/*strcmp(info.name, "xmlns") &&*/ (info.fieldType = (u32) strlen(attValue))) | |
| gf_fprintf(sdump->trace, " %s=\"%s\"", info.name, attValue); | |
| gf_free(attValue); | |
| } | |
| att = att->next; | |
| } | |
| gf_dom_event_dump_listeners(n, sdump->trace); | |
| if (svg->children) { | |
| gf_fprintf(sdump->trace, ">"); | |
| } else { | |
| gf_fprintf(sdump->trace, "/>"); | |
| return; | |
| } | |
| if (n->sgprivate->tag==TAG_LSR_conditional) { | |
| GF_DOMUpdates *up = svg->children ? (GF_DOMUpdates *)svg->children->node : NULL; | |
| sdump->indent++; | |
| if (up && (up->sgprivate->tag==TAG_DOMUpdates)) { | |
| if (gf_list_count(up->updates)) { | |
| gf_fprintf(sdump->trace, "\n"); | |
| gf_sm_dump_command_list(sdump, up->updates, sdump->indent, 0); | |
| } else if (up->data) { | |
| gf_fprintf(sdump->trace, "<!-- WARNING: LASeR scripts cannot be dumped at run-time -->\n"); | |
| } | |
| } | |
| sdump->indent--; | |
| DUMP_IND(sdump); | |
| gf_fprintf(sdump->trace, "</%s>\n", gf_node_get_class_name(n)); | |
| return; | |
| } | |
| if (tag==TAG_SVG_text || tag==TAG_SVG_textArea) sdump->in_text = 1; | |
| sdump->indent++; | |
| list = svg->children; | |
| while (list) { | |
| if (!sdump->in_text) gf_fprintf(sdump->trace, "\n"); | |
| gf_dump_svg_element(sdump, list->node, n, 0); | |
| list = list->next; | |
| } | |
| if (!sdump->in_text) gf_fprintf(sdump->trace, "\n"); | |
| sdump->indent--; | |
| if (!sdump->in_text) DUMP_IND(sdump); | |
| gf_fprintf(sdump->trace, "</%s>", gf_node_get_class_name(n)); | |
| if (tag==TAG_SVG_text || tag==TAG_SVG_textArea) sdump->in_text = 0; | |
| /*removes all namespaces specified on this element */ | |
| gf_xml_pop_namespaces((GF_DOMNode *)n); | |
| } | |
| #endif | |
| static void gf_sm_dump_saf_hdr(GF_SceneDumper *dumper, char *unit_name, u64 au_time, Bool is_rap) | |
| { | |
| gf_fprintf(dumper->trace, "<saf:%s", unit_name); | |
| if (au_time) gf_fprintf(dumper->trace, " time=\""LLD"\"", au_time); | |
| if (is_rap) gf_fprintf(dumper->trace, " rap=\"true\""); | |
| gf_fprintf(dumper->trace, ">\n"); | |
| } | |
| static void dump_od_to_saf(GF_SceneDumper *dumper, GF_AUContext *au, u32 indent) | |
| { | |
| u32 i, count; | |
| count = gf_list_count(au->commands); | |
| for (i=0; i<count; i++) { | |
| u32 j, c2; | |
| GF_ODUpdate *com = (GF_ODUpdate *)gf_list_get(au->commands, i); | |
| if (com->tag != GF_ODF_OD_UPDATE_TAG) continue; | |
| c2 = gf_list_count(com->objectDescriptors); | |
| for (j=0; j<c2; j++) { | |
| GF_ObjectDescriptor *od = (GF_ObjectDescriptor *)gf_list_get(com->objectDescriptors, j); | |
| GF_ESD *esd = (GF_ESD *) gf_list_get(od->ESDescriptors, 0); | |
| GF_MuxInfo *mux; | |
| if (!esd || (esd->tag != GF_ODF_ESD_TAG)) { | |
| if (od->URLString) { | |
| gf_fprintf(dumper->trace, "<saf:RemoteStreamHeader streamID=\"stream%d\" url=\"%s\"", au->owner->ESID, od->URLString); | |
| if (au->timing) gf_fprintf(dumper->trace, " time=\""LLD"\"", au->timing); | |
| gf_fprintf(dumper->trace, "/>\n"); | |
| } | |
| continue; | |
| } | |
| mux = (GF_MuxInfo *)gf_list_get(esd->extensionDescriptors, 0); | |
| if (!mux || (mux->tag!=GF_ODF_MUXINFO_TAG)) mux = NULL; | |
| gf_fprintf(dumper->trace, "<saf:mediaHeader streamID=\"stream%d\"", esd->ESID); | |
| if (esd->decoderConfig) { | |
| gf_fprintf(dumper->trace, " streamType=\"%d\" objectTypeIndication=\"%d\" timeStampResolution=\"%d\"", esd->decoderConfig->streamType, esd->decoderConfig->objectTypeIndication, au->owner->timeScale); | |
| } | |
| if (au->timing) gf_fprintf(dumper->trace, " time=\""LLD"\"", au->timing); | |
| if (mux && mux->file_name) gf_fprintf(dumper->trace, " source=\"%s\"", mux->file_name); | |
| gf_fprintf(dumper->trace, "/>\n"); | |
| } | |
| } | |
| gf_fprintf(dumper->trace, "</saf:mediaUnit>\n"); | |
| } | |
| #ifndef GPAC_DISABLE_SVG | |
| static GF_Err SD_DumpDOMElement(GF_SceneDumper *sdump, GF_DOMFullNode *node) | |
| { | |
| const char *ns; | |
| u32 child_type = 0; | |
| GF_DOMFullAttribute *att; | |
| GF_ChildNodeItem *child; | |
| GF_DOMText *txt; | |
| ns = gf_sg_get_namespace_qname(node->sgprivate->scenegraph, node->ns); | |
| DUMP_IND(sdump); | |
| if (ns) gf_fprintf(sdump->trace, "<%s:%s", ns, node->name); | |
| else gf_fprintf(sdump->trace, "<%s", node->name); | |
| att = (GF_DOMFullAttribute *)node->attributes; | |
| while (att) { | |
| gf_fprintf(sdump->trace, " %s=\"%s\"", att->name, (char *) att->data); | |
| att = (GF_DOMFullAttribute *)att->next; | |
| } | |
| if (!node->children) { | |
| gf_fprintf(sdump->trace, "/>\n"); | |
| return GF_OK; | |
| } | |
| gf_fprintf(sdump->trace, ">"); | |
| sdump->indent++; | |
| child = node->children; | |
| while (child) { | |
| switch(child->node->sgprivate->tag) { | |
| case TAG_DOMFullNode: | |
| if (!child_type) gf_fprintf(sdump->trace, "\n"); | |
| child_type = 1; | |
| SD_DumpDOMElement(sdump, (GF_DOMFullNode*)child->node); | |
| break; | |
| case TAG_DOMText: | |
| child_type = 2; | |
| txt = (GF_DOMText *)child->node; | |
| if (txt->type==GF_DOM_TEXT_REGULAR) { | |
| scene_dump_utf_string(sdump, 0, txt->textContent); | |
| } else if (txt->type==GF_DOM_TEXT_CDATA) { | |
| gf_fprintf(sdump->trace, "<![CDATA["); | |
| gf_fprintf(sdump->trace, "%s", txt->textContent); | |
| gf_fprintf(sdump->trace, "]]>"); | |
| } | |
| break; | |
| } | |
| child = child->next; | |
| } | |
| sdump->indent--; | |
| if (child_type!=2) { | |
| DUMP_IND(sdump); | |
| } | |
| if (ns) gf_fprintf(sdump->trace, "</%s:%s>\n", ns, node->name); | |
| else gf_fprintf(sdump->trace, "</%s>\n", node->name); | |
| return GF_OK; | |
| } | |
| #endif | |
| GF_EXPORT | |
| GF_Err gf_sm_dump_graph(GF_SceneDumper *sdump, Bool skip_proto, Bool skip_routes) | |
| { | |
| u32 tag; | |
| if (!sdump->trace || !sdump->sg || !sdump->sg->RootNode) return GF_BAD_PARAM; | |
| tag = sdump->sg->RootNode->sgprivate->tag; | |
| if (tag<=GF_NODE_RANGE_LAST_X3D) { | |
| gf_dump_setup(sdump, NULL); | |
| if (sdump->XMLDump) { | |
| StartElement(sdump, "Scene"); | |
| EndElementHeader(sdump, 1); | |
| sdump->indent++; | |
| } | |
| #ifndef GPAC_DISABLE_VRML | |
| GF_Err e; | |
| if (!skip_proto) { | |
| e = DumpProtos(sdump, sdump->sg->protos); | |
| if (e) return e; | |
| } | |
| if (sdump->X3DDump) { | |
| GF_ChildNodeItem *list = ((GF_ParentNode *)sdump->sg->RootNode)->children; | |
| while (list) { | |
| gf_dump_vrml_node(sdump, list->node, 0, NULL); | |
| list = list->next; | |
| } | |
| } else { | |
| gf_dump_vrml_node(sdump, sdump->sg->RootNode, 0, NULL); | |
| } | |
| if (!sdump->XMLDump) gf_fprintf(sdump->trace, "\n\n"); | |
| if (!skip_routes) { | |
| GF_Route *r; | |
| u32 i=0; | |
| while ((r = (GF_Route*)gf_list_enum(sdump->sg->Routes, &i))) { | |
| if (r->IS_route || (r->graph!=sdump->sg)) continue; | |
| e = gf_dump_vrml_route(sdump, r, 0); | |
| if (e) return e; | |
| } | |
| } | |
| if (sdump->XMLDump) { | |
| sdump->indent--; | |
| EndElement(sdump, "Scene", 1); | |
| } | |
| #endif /*GPAC_DISABLE_VRML*/ | |
| gf_dump_finalize(sdump, NULL); | |
| return GF_OK; | |
| } | |
| #ifndef GPAC_DISABLE_SVG | |
| else if ((tag>=GF_NODE_RANGE_FIRST_SVG) && (tag<=GF_NODE_RANGE_LAST_SVG)) { | |
| sdump->dump_mode = GF_SM_DUMP_SVG; | |
| gf_dump_setup(sdump, NULL); | |
| gf_dump_svg_element(sdump, sdump->sg->RootNode, NULL, 1); | |
| return GF_OK; | |
| } | |
| else if (tag==TAG_DOMFullNode) { | |
| sdump->dump_mode = GF_SM_DUMP_XML; | |
| gf_dump_setup(sdump, NULL); | |
| SD_DumpDOMElement(sdump, (GF_DOMFullNode*)sdump->sg->RootNode); | |
| } | |
| #endif | |
| return GF_OK; | |
| } | |
| static void ReorderAUContext(GF_List *sample_list, GF_AUContext *au, Bool lsr_dump) | |
| { | |
| u64 autime, time; | |
| u32 i; | |
| Bool has_base; | |
| GF_AUContext *ptr; | |
| /* | |
| this happens when converting from bt to xmt | |
| NOTE: Comment is wrong? this happens when just loading BT | |
| */ | |
| if (!au->timing_sec) { | |
| au->timing_sec = (Double) (s64) au->timing; | |
| /* Hack to avoid timescale=0 which happens when loading a BT with no SLConfig*/ | |
| if (!au->owner->timeScale) au->owner->timeScale = 1000; | |
| au->timing_sec /= au->owner->timeScale; | |
| } | |
| /*this happens when converting from xmt to bt*/ | |
| if (!au->timing) { | |
| gf_assert(au->owner->timeScale); | |
| au->timing = (u64) (au->timing_sec * au->owner->timeScale); | |
| } | |
| autime = au->timing + au->owner->imp_exp_time; | |
| has_base = 0; | |
| i=0; | |
| while ((ptr = (GF_AUContext*)gf_list_enum(sample_list, &i))) { | |
| time = ptr->timing + ptr->owner->imp_exp_time; | |
| if ( | |
| /*time ordered*/ | |
| (time > autime) | |
| /*set bifs first for first AU*/ | |
| || (!has_base && (time == autime) && (ptr->owner->streamType < au->owner->streamType) ) | |
| /*set OD first for laser*/ | |
| || (lsr_dump && (au->owner->streamType==GF_STREAM_OD)) | |
| ) { | |
| gf_list_insert(sample_list, au, i-1); | |
| return; | |
| } | |
| has_base = 0; | |
| if ( (ptr->owner->streamType == au->owner->streamType) && (time == autime) ) has_base = 1; | |
| } | |
| gf_list_add(sample_list, au); | |
| } | |
| GF_EXPORT | |
| GF_Err gf_sm_dump(GF_SceneManager *ctx, char *rad_name, Bool is_final_name, GF_SceneDumpFormat dump_mode) | |
| { | |
| GF_Err e; | |
| GF_List *sample_list; | |
| Bool first_par; | |
| u32 i, j, indent, num_scene, num_od, first_bifs; | |
| Double time; | |
| GF_SceneDumper *dumper; | |
| GF_StreamContext *sc; | |
| GF_AUContext *au; | |
| Bool no_root_found = 1; | |
| num_scene = num_od = 0; | |
| indent = 0; | |
| dumper = gf_sm_dumper_new(ctx->scene_graph, rad_name, is_final_name, ' ', dump_mode); | |
| if (!dumper) { | |
| return GF_IO_ERR; | |
| } | |
| sample_list = gf_list_new(); | |
| e = GF_OK; | |
| /*configure all systems streams we're dumping*/ | |
| i=0; | |
| while ((sc = (GF_StreamContext*)gf_list_enum(ctx->streams, &i))) { | |
| switch (sc->streamType) { | |
| case GF_STREAM_SCENE: | |
| num_scene ++; | |
| break; | |
| case GF_STREAM_OD: | |
| num_od ++; | |
| break; | |
| default: | |
| continue; | |
| } | |
| j=0; | |
| while ((au = (GF_AUContext*)gf_list_enum(sc->AUs, &j))) { | |
| ReorderAUContext(sample_list, au, dumper->LSRDump); | |
| if (dumper->dump_mode==GF_SM_DUMP_SVG) break; | |
| } | |
| if (dumper->dump_mode==GF_SM_DUMP_SVG) break; | |
| } | |
| first_bifs = (num_scene==1) ? 1 : 0; | |
| num_scene = (num_scene>1) ? 1 : 0; | |
| num_od = (num_od>1) ? 1 : 0; | |
| gf_dump_setup(dumper, (GF_Descriptor *) ctx->root_od); | |
| #ifndef GPAC_DISABLE_SVG | |
| if (dumper->dump_mode==GF_SM_DUMP_SVG) { | |
| au = (GF_AUContext*)gf_list_get(sample_list, 0); | |
| GF_Command *com = NULL; | |
| if (au) com = (GF_Command*)gf_list_get(au->commands, 0); | |
| if (!au) { | |
| gf_dump_svg_element(dumper, dumper->sg->RootNode, NULL, 1); | |
| } else if (!com || (com->tag!=GF_SG_LSR_NEW_SCENE) || !com->node) { | |
| e = GF_NOT_SUPPORTED; | |
| } else { | |
| gf_dump_svg_element(dumper, com->node, NULL, 1); | |
| } | |
| gf_dump_finalize(dumper, (GF_Descriptor *) ctx->root_od); | |
| gf_sm_dumper_del(dumper); | |
| gf_list_del(sample_list); | |
| return e; | |
| } | |
| #endif | |
| time = dumper->LSRDump ? -1 : 0; | |
| first_par = 0; | |
| while (gf_list_count(sample_list)) { | |
| au = (GF_AUContext*)gf_list_get(sample_list, 0); | |
| gf_list_rem(sample_list, 0); | |
| if (!dumper->XMLDump) { | |
| if (!first_bifs || (au->owner->streamType != GF_STREAM_SCENE) ) { | |
| if (au->flags & GF_SM_AU_RAP) gf_fprintf(dumper->trace, "RAP "); | |
| gf_fprintf(dumper->trace, "AT "LLD" ", au->timing); | |
| if ( (au->owner->streamType==GF_STREAM_OD && num_od) || (au->owner->streamType==GF_STREAM_SCENE && num_scene)) { | |
| gf_fprintf(dumper->trace, "IN %d ", au->owner->ESID); | |
| } | |
| gf_fprintf(dumper->trace, "{\n"); | |
| indent++; | |
| } | |
| switch (au->owner->streamType) { | |
| case GF_STREAM_OD: | |
| if (dumper->LSRDump) { | |
| dump_od_to_saf(dumper, au, indent); | |
| } else { | |
| #ifndef GPAC_DISABLE_OD_DUMP | |
| e = gf_odf_dump_com_list(au->commands, dumper->trace, indent+1, 0); | |
| #endif | |
| } | |
| break; | |
| case GF_STREAM_SCENE: | |
| e = gf_sm_dump_command_list(dumper, au->commands, indent, first_bifs); | |
| break; | |
| } | |
| if (first_bifs) { | |
| first_bifs = 0; | |
| gf_fprintf(dumper->trace, "\n"); | |
| } else { | |
| indent--; | |
| gf_fprintf(dumper->trace, "}\n\n"); | |
| } | |
| } | |
| else { | |
| if (dumper->LSRDump) { | |
| /* if (time != au->timing_sec) { | |
| time = au->timing_sec; | |
| } | |
| */ | |
| } else if (!time && !num_scene && first_bifs) { | |
| } else if (num_scene || num_od) { | |
| if (!first_par) { | |
| first_par = 1; | |
| indent += 1; | |
| } else { | |
| gf_fprintf(dumper->trace, " </par>\n"); | |
| } | |
| gf_fprintf(dumper->trace, " <par begin=\"%g\" atES_ID=\"es%d\" isRAP=\"%s\">\n", au->timing_sec, au->owner->ESID, (au->flags & GF_SM_AU_RAP) ? "yes" : "no"); | |
| } else if (au->timing_sec>time) { | |
| if (!first_par) { | |
| first_par = 1; | |
| indent += 1; | |
| } else { | |
| gf_fprintf(dumper->trace, " </par>\n"); | |
| } | |
| gf_fprintf(dumper->trace, "<par begin=\"%g\">\n", au->timing_sec); | |
| } | |
| switch (au->owner->streamType) { | |
| case GF_STREAM_OD: | |
| if (dumper->LSRDump) { | |
| dump_od_to_saf(dumper, au, indent+1); | |
| } else { | |
| #ifndef GPAC_DISABLE_OD_DUMP | |
| e = gf_odf_dump_com_list(au->commands, dumper->trace, indent+1, 1); | |
| #endif | |
| } | |
| break; | |
| case GF_STREAM_SCENE: | |
| if (gf_list_count(au->commands)) { | |
| if (dumper->LSRDump) | |
| gf_sm_dump_saf_hdr(dumper, "sceneUnit", au->timing, au->flags & GF_SM_AU_RAP); | |
| e = gf_sm_dump_command_list(dumper, au->commands, indent+1, first_bifs); | |
| first_bifs = 0; | |
| no_root_found = 0; | |
| if (dumper->LSRDump) | |
| gf_fprintf(dumper->trace, "</saf:sceneUnit>\n"); | |
| } | |
| break; | |
| } | |
| time = au->timing_sec; | |
| } | |
| if (dumper->X3DDump || (dumper->dump_mode==GF_SM_DUMP_VRML)) break; | |
| } | |
| #ifndef GPAC_DISABLE_VRML | |
| if (no_root_found && ctx->scene_graph->RootNode) { | |
| GF_Route *r; | |
| DumpProtos(dumper, ctx->scene_graph->protos); | |
| gf_dump_vrml_node(dumper, ctx->scene_graph->RootNode, 0, NULL); | |
| i=0; | |
| gf_fprintf(dumper->trace, "\n"); | |
| while ((r = (GF_Route*)gf_list_enum(dumper->sg->Routes, &i))) { | |
| if (r->IS_route || (r->graph!=dumper->sg)) continue; | |
| e = gf_dump_vrml_route(dumper, r, 0); | |
| if (e) return e; | |
| } | |
| } | |
| #endif | |
| /*close command*/ | |
| if (!dumper->X3DDump && first_par) gf_fprintf(dumper->trace, " </par>\n"); | |
| if (gf_list_count(sample_list) && (dumper->X3DDump || (dumper->dump_mode==GF_SM_DUMP_VRML)) ) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[Scene Dump] MPEG-4 Commands found, not supported in %s - skipping\n", dumper->X3DDump ? "X3D" : "VRML")); | |
| } | |
| gf_dump_finalize(dumper, (GF_Descriptor *) ctx->root_od); | |
| gf_sm_dumper_del(dumper); | |
| gf_list_del(sample_list); | |
| return e; | |
| } | |
| #endif /*GPAC_DISABLE_SCENE_DUMP*/ |