| /* | |
| * GPAC - Multimedia Framework C SDK | |
| * | |
| * Authors: Jean Le Feuvre | |
| * Copyright (c) Telecom ParisTech 2000-2012 | |
| * 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/internal/scenegraph_dev.h> | |
| #ifndef GPAC_DISABLE_SCENE_STATS | |
| struct _statman | |
| { | |
| GF_SceneStatistics *stats; | |
| GF_List *def_nodes; | |
| }; | |
| static GF_SceneStatistics *NewSceneStats() | |
| { | |
| GF_SceneStatistics *tmp; | |
| GF_SAFEALLOC(tmp, GF_SceneStatistics); | |
| if (!tmp) return NULL; | |
| tmp->node_stats = gf_list_new(); | |
| tmp->proto_stats = gf_list_new(); | |
| tmp->max_2d.x = FIX_MIN; | |
| tmp->max_2d.y = FIX_MIN; | |
| tmp->max_3d.x = FIX_MIN; | |
| tmp->max_3d.y = FIX_MIN; | |
| tmp->max_3d.z = FIX_MIN; | |
| tmp->min_2d.x = FIX_MAX; | |
| tmp->min_2d.y = FIX_MAX; | |
| tmp->min_3d.x = FIX_MAX; | |
| tmp->min_3d.y = FIX_MAX; | |
| tmp->min_3d.z = FIX_MAX; | |
| return tmp; | |
| } | |
| static void ResetStatisitics(GF_SceneStatistics *stat) | |
| { | |
| while (gf_list_count(stat->node_stats)) { | |
| GF_NodeStats *ptr = (GF_NodeStats *)gf_list_get(stat->node_stats, 0); | |
| gf_list_rem(stat->node_stats, 0); | |
| gf_free(ptr); | |
| } | |
| while (gf_list_count(stat->proto_stats)) { | |
| GF_NodeStats *ptr = (GF_NodeStats *)gf_list_get(stat->proto_stats, 0); | |
| gf_list_rem(stat->proto_stats, 0); | |
| gf_free(ptr); | |
| } | |
| stat->max_2d.x = FIX_MIN; | |
| stat->max_2d.y = FIX_MIN; | |
| stat->max_3d.x = FIX_MIN; | |
| stat->max_3d.y = FIX_MIN; | |
| stat->max_3d.z = FIX_MIN; | |
| stat->min_2d.x = FIX_MAX; | |
| stat->min_2d.y = FIX_MAX; | |
| stat->min_3d.x = FIX_MAX; | |
| stat->min_3d.y = FIX_MAX; | |
| stat->min_3d.z = FIX_MAX; | |
| stat->count_2d = stat->rem_2d = stat->count_3d = stat->rem_3d = stat->count_float = 0; | |
| stat->rem_float = stat->count_color = stat->rem_color = stat->count_2f = stat->count_3f = 0; | |
| } | |
| static void DeleteStatisitics(GF_SceneStatistics *stat) | |
| { | |
| ResetStatisitics(stat); | |
| gf_list_del(stat->node_stats); | |
| gf_list_del(stat->proto_stats); | |
| gf_free(stat); | |
| } | |
| static void StatNode(GF_SceneStatistics *stat, GF_Node *n, Bool isUsed, Bool isDelete, GF_Node *prev) | |
| { | |
| u32 i; | |
| GF_NodeStats *ptr = NULL; | |
| if (!stat) return; | |
| if (n->sgprivate->tag == TAG_ProtoNode) { | |
| #ifndef GPAC_DISABLE_VRML | |
| GF_ProtoInstance *pr = (GF_ProtoInstance *)n; | |
| i=0; | |
| while ((ptr = (GF_NodeStats *)gf_list_enum(stat->proto_stats, &i))) { | |
| if (pr->proto_interface && (pr->proto_interface->ID == ptr->tag)) break; | |
| ptr = NULL; | |
| } | |
| if (!ptr) { | |
| GF_SAFEALLOC(ptr, GF_NodeStats); | |
| if (!ptr) return; | |
| if (pr->proto_interface) { | |
| ptr->tag = pr->proto_interface->ID; | |
| ptr->name = gf_sg_proto_get_class_name(pr->proto_interface); | |
| } | |
| gf_list_add(stat->proto_stats, ptr); | |
| } | |
| #endif | |
| } else { | |
| i=0; | |
| while ((ptr = (GF_NodeStats *)gf_list_enum(stat->node_stats, &i))) { | |
| if (n->sgprivate->tag == ptr->tag) break; | |
| ptr = NULL; | |
| } | |
| if (!ptr) { | |
| GF_SAFEALLOC(ptr, GF_NodeStats); | |
| if (!ptr) return; | |
| ptr->tag = n->sgprivate->tag; | |
| ptr->name = gf_node_get_class_name(n); | |
| gf_list_add(stat->node_stats, ptr); | |
| } | |
| } | |
| if (isDelete) ptr->nb_del += n->sgprivate->num_instances; | |
| else if (isUsed) ptr->nb_used += 1; | |
| /*this is because the node passes twice in the stat, once on DumpNode and once in replaceALL*/ | |
| else ptr->nb_created += prev ? (prev->sgprivate->num_instances - 1) : 1; | |
| } | |
| #ifndef GPAC_DISABLE_SVG | |
| static void StatFixed(GF_SceneStatistics *stat, Fixed v, Bool scale) | |
| { | |
| u32 int_res, frac_res; | |
| if (v > 32767.0) | |
| v = 32767.0; | |
| else if (v < -32768.0) | |
| v = -32768.0; | |
| u32 fixv = FIX2INT((v>0?v:-v) * (1<<16)); | |
| s32 intv = (fixv & 0xFFFF0000)>>16; | |
| u32 fracv = fixv & 0x0000FFFF; | |
| int_res = 0; | |
| while ( (intv >> int_res) ) int_res++; | |
| int_res++; /* signedness */ | |
| if (fracv) { | |
| frac_res = 1; | |
| while ((fracv << frac_res) & 0x0000FFFF) | |
| frac_res++; | |
| } else { | |
| frac_res = 0; | |
| } | |
| if (scale) { | |
| if (int_res > stat->scale_int_res_2d) stat->scale_int_res_2d = int_res; | |
| if (frac_res > stat->scale_frac_res_2d) stat->scale_frac_res_2d = frac_res; | |
| } else { | |
| if (int_res > stat->int_res_2d) stat->int_res_2d = int_res; | |
| if (frac_res > stat->frac_res_2d) stat->frac_res_2d = frac_res; | |
| } | |
| if (stat->max_fixed < v) stat->max_fixed = v; | |
| if (stat->min_fixed > v) stat->min_fixed = v; | |
| } | |
| static void StatSVGPoint(GF_SceneStatistics *stat, SFVec2f *val) | |
| { | |
| if (!stat || !val) return; | |
| if (stat->max_2d.x < val->x) stat->max_2d.x = val->x; | |
| if (stat->max_2d.y < val->y) stat->max_2d.y = val->y; | |
| if (stat->min_2d.x > val->x) stat->min_2d.x = val->x; | |
| if (stat->min_2d.y > val->y) stat->min_2d.y = val->y; | |
| StatFixed(stat, val->x, 0); | |
| StatFixed(stat, val->y, 0); | |
| } | |
| #endif | |
| static void StatSFVec2f(GF_SceneStatistics *stat, SFVec2f *val) | |
| { | |
| if (!stat || !val) return; | |
| if (stat->max_2d.x < val->x) stat->max_2d.x = val->x; | |
| if (stat->max_2d.y < val->y) stat->max_2d.y = val->y; | |
| if (stat->min_2d.x > val->x) stat->min_2d.x = val->x; | |
| if (stat->min_2d.y > val->y) stat->min_2d.y = val->y; | |
| } | |
| static void StatSFVec3f(GF_SceneStatistics *stat, SFVec3f *val) | |
| { | |
| if (!stat || !val) return; | |
| if (stat->max_3d.x < val->x) stat->max_3d.x = val->x; | |
| if (stat->max_3d.y < val->y) stat->max_3d.y = val->y; | |
| if (stat->max_3d.z < val->z) stat->max_3d.z = val->y; | |
| if (stat->min_3d.x > val->x) stat->min_3d.x = val->x; | |
| if (stat->min_3d.y > val->y) stat->min_3d.y = val->y; | |
| if (stat->min_3d.z > val->z) stat->min_3d.z = val->z; | |
| } | |
| static void StatField(GF_SceneStatistics *stat, GF_FieldInfo *field) | |
| { | |
| u32 i; | |
| switch (field->fieldType) { | |
| case GF_SG_VRML_SFFLOAT: | |
| stat->count_float++; | |
| if (stat->max_fixed < *(SFFloat*)field->far_ptr) | |
| stat->max_fixed = *(SFFloat*)field->far_ptr; | |
| if (stat->min_fixed > *(SFFloat*)field->far_ptr) | |
| stat->min_fixed = *(SFFloat*)field->far_ptr; | |
| break; | |
| case GF_SG_VRML_SFCOLOR: | |
| stat->count_color++; | |
| break; | |
| case GF_SG_VRML_SFVEC2F: | |
| stat->count_2f++; | |
| StatSFVec2f(stat, field->far_ptr); | |
| break; | |
| case GF_SG_VRML_SFVEC3F: | |
| stat->count_3f++; | |
| StatSFVec3f(stat, field->far_ptr); | |
| break; | |
| case GF_SG_VRML_MFFLOAT: | |
| stat->count_float+= ((MFFloat *)field->far_ptr)->count; | |
| break; | |
| case GF_SG_VRML_MFCOLOR: | |
| stat->count_color+= ((MFColor *)field->far_ptr)->count; | |
| break; | |
| case GF_SG_VRML_MFVEC2F: | |
| { | |
| MFVec2f *mf2d = (MFVec2f *)field->far_ptr; | |
| for (i=0; i<mf2d->count; i++) { | |
| StatSFVec2f(stat, &mf2d->vals[i]); | |
| stat->count_2d ++; | |
| } | |
| } | |
| break; | |
| case GF_SG_VRML_MFVEC3F: | |
| { | |
| MFVec3f *mf3d = (MFVec3f *)field->far_ptr; | |
| for (i=0; i<mf3d->count; i++) { | |
| StatSFVec3f(stat, &mf3d->vals[i]); | |
| stat->count_3d ++; | |
| } | |
| } | |
| break; | |
| } | |
| } | |
| static void StatSingleField(GF_SceneStatistics *stat, GF_FieldInfo *field) | |
| { | |
| switch (field->fieldType) { | |
| case GF_SG_VRML_SFVEC2F: | |
| StatSFVec2f(stat, (SFVec2f *)field->far_ptr); | |
| break; | |
| case GF_SG_VRML_MFVEC3F: | |
| StatSFVec3f(stat, (SFVec3f *)field->far_ptr); | |
| break; | |
| } | |
| } | |
| #ifndef GPAC_DISABLE_SVG | |
| static void StatSVGAttribute(GF_SceneStatistics *stat, GF_FieldInfo *field) | |
| { | |
| u32 i = 0; | |
| stat->nb_svg_attributes++; | |
| switch (field->fieldType) { | |
| case SVG_PathData_datatype: | |
| { | |
| #if USE_GF_PATH | |
| SVG_PathData *d = (SVG_PathData *)field->far_ptr; | |
| for (i=0; i<d->n_points; i++) { | |
| StatSVGPoint(stat, &(d->points[i])); | |
| stat->count_2d ++; | |
| } | |
| #else | |
| SVG_PathData *d = (SVG_PathData *)field->far_ptr; | |
| for (i=0; i<gf_list_count(d->points); i++) { | |
| SVG_Point *p = (SVG_Point *)gf_list_get(d->points, i); | |
| StatSVGPoint(stat, (SFVec2f *)p); | |
| stat->count_2d ++; | |
| } | |
| #endif | |
| } | |
| break; | |
| case SVG_ViewBox_datatype: | |
| { | |
| SVG_ViewBox *vB = (SVG_ViewBox *)field->far_ptr; | |
| StatFixed(stat, vB->x, 0); | |
| StatFixed(stat, vB->y, 0); | |
| StatFixed(stat, vB->width, 0); | |
| StatFixed(stat, vB->height, 0); | |
| } | |
| break; | |
| case SVG_Points_datatype: | |
| case SVG_Coordinates_datatype: | |
| { | |
| GF_List *points = *((GF_List **)field->far_ptr); | |
| for (i=0; i<gf_list_count(points); i++) { | |
| SVG_Point *p = (SVG_Point *)gf_list_get(points, i); | |
| StatSVGPoint(stat, (SFVec2f *)p); | |
| stat->count_2d ++; | |
| } | |
| } | |
| break; | |
| case SVG_Transform_datatype: | |
| { | |
| GF_Matrix2D *mx = &((SVG_Transform *)field->far_ptr)->mat; | |
| if (!gf_mx2d_is_identity(*mx) && !(!mx->m[0] && !mx->m[1] && !mx->m[3] && !mx->m[4])) { | |
| StatFixed(stat, mx->m[0], 1); | |
| StatFixed(stat, mx->m[1], 1); | |
| StatFixed(stat, mx->m[3], 1); | |
| StatFixed(stat, mx->m[4], 1); | |
| StatFixed(stat, mx->m[2], 0); | |
| StatFixed(stat, mx->m[5], 0); | |
| } | |
| } | |
| break; | |
| case SVG_Motion_datatype: | |
| { | |
| GF_Matrix2D *mx = (GF_Matrix2D *)field->far_ptr; | |
| if (!gf_mx2d_is_identity(*mx) && !(!mx->m[0] && !mx->m[1] && !mx->m[3] && !mx->m[4])) { | |
| StatFixed(stat, mx->m[0], 1); | |
| StatFixed(stat, mx->m[1], 1); | |
| StatFixed(stat, mx->m[3], 1); | |
| StatFixed(stat, mx->m[4], 1); | |
| StatFixed(stat, mx->m[2], 0); | |
| StatFixed(stat, mx->m[5], 0); | |
| } | |
| } | |
| break; | |
| case SVG_Length_datatype: | |
| case SVG_Coordinate_datatype: | |
| StatFixed(stat, ((SVG_Number *)field->far_ptr)->value, 0); | |
| break; | |
| } | |
| } | |
| #endif | |
| static void StatRemField(GF_SceneStatistics *stat, u32 fieldType, GF_FieldInfo *field) | |
| { | |
| u32 count = 1; | |
| if (field) count = ((GenMFField*)field->far_ptr)->count; | |
| switch (fieldType) { | |
| case GF_SG_VRML_MFFLOAT: | |
| stat->rem_float += count; | |
| break; | |
| case GF_SG_VRML_SFCOLOR: | |
| stat->rem_color += count; | |
| break; | |
| case GF_SG_VRML_MFVEC2F: | |
| stat->rem_2d += count; | |
| break; | |
| case GF_SG_VRML_MFVEC3F: | |
| stat->rem_3d += count; | |
| break; | |
| } | |
| } | |
| Bool StatIsUSE(GF_StatManager *st, GF_Node *n) | |
| { | |
| u32 i; | |
| GF_Node *ptr; | |
| if (!n || !gf_node_get_id(n) ) return 0; | |
| i=0; | |
| while ((ptr = (GF_Node*)gf_list_enum(st->def_nodes, &i))) { | |
| if (ptr == n) return 1; | |
| } | |
| gf_list_add(st->def_nodes, n); | |
| return 0; | |
| } | |
| static GF_Err StatNodeGraph(GF_StatManager *st, GF_Node *n) | |
| { | |
| GF_Node *clone; | |
| GF_FieldInfo field; | |
| Bool no_cycle; | |
| if (!n) return GF_OK; | |
| no_cycle = gf_node_set_cyclic_traverse_flag(n, GF_TRUE); | |
| StatNode(st->stats, n, StatIsUSE(st, n), 0, NULL); | |
| if (!no_cycle) return GF_OK; | |
| if (n->sgprivate->tag != TAG_ProtoNode) { | |
| clone = gf_node_new(n->sgprivate->scenegraph, n->sgprivate->tag); | |
| } else { | |
| #ifndef GPAC_DISABLE_VRML | |
| clone = gf_sg_proto_create_node(n->sgprivate->scenegraph, ((GF_ProtoInstance *)n)->proto_interface, NULL); | |
| #else | |
| clone = NULL; | |
| #endif | |
| } | |
| if (!clone) return GF_OK; | |
| gf_node_register(clone, NULL); | |
| #ifndef GPAC_DISABLE_SVG | |
| if ((n->sgprivate->tag>= GF_NODE_RANGE_FIRST_SVG) && (n->sgprivate->tag<= GF_NODE_RANGE_LAST_SVG)) { | |
| GF_ChildNodeItem *list = ((SVG_Element *)n)->children; | |
| GF_DOMAttribute *atts = ((GF_DOMNode*)n)->attributes; | |
| while (atts) { | |
| field.far_ptr = atts->data; | |
| field.fieldType = atts->data_type; | |
| field.fieldIndex = atts->tag; | |
| field.name = NULL; | |
| StatSVGAttribute(st->stats, &field); | |
| atts = atts->next; | |
| } | |
| while (list) { | |
| StatNodeGraph(st, list->node); | |
| list = list->next; | |
| } | |
| } else | |
| #endif | |
| if (n->sgprivate->tag == TAG_DOMText) { | |
| } else if (n->sgprivate->tag == TAG_DOMFullNode) { | |
| } | |
| #ifndef GPAC_DISABLE_VRML | |
| else if (n->sgprivate->tag<= GF_NODE_RANGE_LAST_X3D) { | |
| GF_Node *child; | |
| GF_ChildNodeItem *list; | |
| u32 i, count; | |
| GF_FieldInfo clone_field; | |
| count = gf_node_get_field_count(n); | |
| for (i=0; i<count; i++) { | |
| gf_node_get_field(n, i, &field); | |
| if (field.eventType==GF_SG_EVENT_IN) continue; | |
| if (field.eventType==GF_SG_EVENT_OUT) continue; | |
| switch (field.fieldType) { | |
| case GF_SG_VRML_SFNODE: | |
| child = *((GF_Node **)field.far_ptr); | |
| StatNodeGraph(st, child); | |
| break; | |
| case GF_SG_VRML_MFNODE: | |
| list = *((GF_ChildNodeItem **)field.far_ptr); | |
| while (list) { | |
| StatNodeGraph(st, list->node); | |
| list = list->next; | |
| } | |
| break; | |
| default: | |
| gf_node_get_field(clone, i, &clone_field); | |
| if (!gf_sg_vrml_field_equal(clone_field.far_ptr, field.far_ptr, field.fieldType)) { | |
| StatField(st->stats, &field); | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| #endif | |
| gf_node_unregister(clone, NULL); | |
| gf_node_set_cyclic_traverse_flag(n, GF_FALSE); | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_sm_stats_for_command(GF_StatManager *stat, GF_Command *com) | |
| { | |
| #ifdef GPAC_DISABLE_VRML | |
| return GF_NOT_SUPPORTED; | |
| #else | |
| GF_FieldInfo field; | |
| GF_Err e; | |
| GF_ChildNodeItem *list; | |
| u32 i; | |
| GF_CommandField *inf = NULL; | |
| if (gf_list_count(com->command_fields)) | |
| inf = (GF_CommandField*)gf_list_get(com->command_fields, 0); | |
| if (!com || !stat) return GF_BAD_PARAM; | |
| switch (com->tag) { | |
| case GF_SG_SCENE_REPLACE: | |
| if (com->node) StatNodeGraph(stat, com->node); | |
| break; | |
| case GF_SG_NODE_REPLACE: | |
| if (inf && inf->new_node) StatNodeGraph(stat, inf->new_node); | |
| break; | |
| case GF_SG_FIELD_REPLACE: | |
| if (!inf) return GF_OK; | |
| e = gf_node_get_field(com->node, inf->fieldIndex, &field); | |
| if (e) return e; | |
| switch (field.fieldType) { | |
| case GF_SG_VRML_SFNODE: | |
| if (inf->new_node) StatNodeGraph(stat, inf->new_node); | |
| break; | |
| case GF_SG_VRML_MFNODE: | |
| if (inf) { | |
| list = * ((GF_ChildNodeItem**) inf->field_ptr); | |
| while (list) { | |
| StatNodeGraph(stat, list->node); | |
| list = list->next; | |
| } | |
| } | |
| break; | |
| default: | |
| if (inf) { | |
| field.far_ptr = inf->field_ptr; | |
| StatField(stat->stats, &field); | |
| } | |
| break; | |
| } | |
| break; | |
| case GF_SG_INDEXED_REPLACE: | |
| if (!inf) return GF_OK; | |
| e = gf_node_get_field(com->node, inf->fieldIndex, &field); | |
| if (e) return e; | |
| if (field.fieldType == GF_SG_VRML_MFNODE) { | |
| StatNodeGraph(stat, inf->new_node); | |
| } else { | |
| field.fieldType = gf_sg_vrml_get_sf_type(field.fieldType); | |
| field.far_ptr = inf->field_ptr; | |
| StatSingleField(stat->stats, &field); | |
| } | |
| break; | |
| case GF_SG_NODE_DELETE: | |
| case GF_SG_NODE_DELETE_EX: | |
| case GF_SG_GLOBAL_QUANTIZER: | |
| if (com->node) StatNode(stat->stats, com->node, 0, 1, NULL); | |
| break; | |
| case GF_SG_INDEXED_DELETE: | |
| if (!inf) return GF_OK; | |
| e = gf_node_get_field(com->node, inf->fieldIndex, &field); | |
| if (e) return e; | |
| /*then we need special handling in case of a node*/ | |
| if (gf_sg_vrml_get_sf_type(field.fieldType) == GF_SG_VRML_SFNODE) { | |
| GF_Node *n = gf_node_list_get_child( * (GF_ChildNodeItem **) field.far_ptr, inf->pos); | |
| if (n) StatNode(stat->stats, n, 0, 1, NULL); | |
| } else { | |
| StatRemField(stat->stats, inf->fieldType, NULL); | |
| } | |
| break; | |
| case GF_SG_NODE_INSERT: | |
| if (inf && inf->new_node) StatNodeGraph(stat, inf->new_node); | |
| break; | |
| case GF_SG_INDEXED_INSERT: | |
| if (!inf) return GF_OK; | |
| e = gf_node_get_field(com->node, inf->fieldIndex, &field); | |
| if (e) return e; | |
| /*rescale the MFField and parse the SFField*/ | |
| if (field.fieldType != GF_SG_VRML_MFNODE) { | |
| field.fieldType = gf_sg_vrml_get_sf_type(field.fieldType); | |
| field.far_ptr = inf->field_ptr; | |
| StatSingleField(stat->stats, &field); | |
| } else { | |
| if (inf->new_node) StatNodeGraph(stat, inf->new_node); | |
| } | |
| break; | |
| case GF_SG_ROUTE_REPLACE: | |
| case GF_SG_ROUTE_DELETE: | |
| case GF_SG_ROUTE_INSERT: | |
| return GF_OK; | |
| case GF_SG_XREPLACE: | |
| if (!inf) return GF_OK; | |
| e = gf_node_get_field(com->node, inf->fieldIndex, &field); | |
| if (e) return e; | |
| /*rescale the MFField and parse the SFField*/ | |
| if (field.fieldType != GF_SG_VRML_MFNODE) { | |
| field.fieldType = gf_sg_vrml_get_sf_type(field.fieldType); | |
| field.far_ptr = inf->field_ptr; | |
| StatSingleField(stat->stats, &field); | |
| } else { | |
| if (inf->new_node) StatNodeGraph(stat, inf->new_node); | |
| } | |
| break; | |
| case GF_SG_MULTIPLE_REPLACE: | |
| case GF_SG_MULTIPLE_INDEXED_REPLACE: | |
| for (i=0; i<gf_list_count(com->command_fields); i++) { | |
| inf = (GF_CommandField*)gf_list_get(com->command_fields, i); | |
| e = gf_node_get_field(com->node, inf->fieldIndex, &field); | |
| if (e) return e; | |
| /*rescale the MFField and parse the SFField*/ | |
| if (field.fieldType != GF_SG_VRML_MFNODE) { | |
| field.fieldType = gf_sg_vrml_get_sf_type(field.fieldType); | |
| field.far_ptr = inf->field_ptr; | |
| StatSingleField(stat->stats, &field); | |
| } else { | |
| if (inf->new_node) StatNodeGraph(stat, inf->new_node); | |
| } | |
| } | |
| break; | |
| case GF_SG_PROTO_INSERT: | |
| case GF_SG_PROTO_DELETE: | |
| case GF_SG_PROTO_DELETE_ALL: | |
| return GF_OK; | |
| default: | |
| return GF_BAD_PARAM; | |
| } | |
| return GF_OK; | |
| #endif | |
| } | |
| static GF_Err gf_sm_stat_au(GF_List *commandList, GF_StatManager *st) | |
| { | |
| u32 i, count; | |
| count = gf_list_count(commandList); | |
| for (i=0; i<count; i++) { | |
| GF_Command *com = (GF_Command *)gf_list_get(commandList, i); | |
| gf_sm_stats_for_command(st, com); | |
| } | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_sm_stats_for_scene(GF_StatManager *stat, GF_SceneManager *sm) | |
| { | |
| u32 i, j; | |
| GF_StreamContext *sc; | |
| GF_Err e; | |
| if (gf_list_count(sm->streams)) { | |
| i=0; | |
| while ((sc = (GF_StreamContext*)gf_list_enum(sm->streams, &i))) { | |
| GF_AUContext *au; | |
| if (sc->streamType != GF_STREAM_SCENE) continue; | |
| if (!stat->stats->base_layer) | |
| stat->stats->base_layer = sc; | |
| j=0; | |
| while ((au = (GF_AUContext*)gf_list_enum(sc->AUs, &j))) { | |
| e = gf_sm_stat_au(au->commands, stat); | |
| if (e) return e; | |
| } | |
| } | |
| } else { /* No scene stream: e.g. SVG */ | |
| if (sm->scene_graph) gf_sm_stats_for_graph(stat, sm->scene_graph); | |
| } | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_sm_stats_for_graph(GF_StatManager *stat, GF_SceneGraph *sg) | |
| { | |
| if (!stat || !sg) return GF_BAD_PARAM; | |
| return StatNodeGraph(stat, sg->RootNode); | |
| } | |
| /*creates new stat handler*/ | |
| GF_EXPORT | |
| GF_StatManager *gf_sm_stats_new() | |
| { | |
| GF_StatManager *sm = (GF_StatManager *)gf_malloc(sizeof(GF_StatManager)); | |
| sm->def_nodes = gf_list_new(); | |
| sm->stats = NewSceneStats(); | |
| return sm; | |
| } | |
| /*deletes stat object returned by one of the above functions*/ | |
| GF_EXPORT | |
| void gf_sm_stats_del(GF_StatManager *stat) | |
| { | |
| gf_list_del(stat->def_nodes); | |
| DeleteStatisitics(stat->stats); | |
| gf_free(stat); | |
| } | |
| GF_EXPORT | |
| const GF_SceneStatistics *gf_sm_stats_get(GF_StatManager *stat) | |
| { | |
| return stat->stats; | |
| } | |
| GF_EXPORT | |
| void gf_sm_stats_reset(GF_StatManager *stat) | |
| { | |
| if (!stat) return; | |
| ResetStatisitics(stat->stats); | |
| } | |
| #endif /*GPAC_DISABLE_SCENE_STATS*/ |