This source file includes following definitions.
- group_2d_traverse
- group_2d_traverse_with_order
- group_3d_setup
- group_3d_delete
- group_3d_new
- get_light_type
- group_3d_traverse
- parent_node_setup
- parent_node_predestroy
- parent_node_reset
- parent_node_start_group
- parent_node_end_group
- parent_node_end_text_group
- parent_node_traverse
- parent_node_child_traverse
- parent_node_child_traverse_matrix
#include "nodes_stacks.h"
#include "mpeg4_grouping.h"
#include "visual_manager.h"
#ifndef GPAC_DISABLE_VRML
void group_2d_traverse(GF_Node *node, GroupingNode2D *group, GF_TraverseState *tr_state)
{
u32 backup;
#ifdef GF_SR_USE_VIDEO_CACHE
Bool group_cached;
#endif
GF_List *sensor_backup;
GF_ChildNodeItem *child;
backup = gf_node_dirty_get(node);
if (backup & GF_SG_CHILD_DIRTY) {
GF_SensorHandler *hsens;
Bool check_anchor=0;
u32 ntag = gf_node_get_tag(node);
group->flags &= ~GROUP_HAS_SENSORS;
if (group->sensors) gf_list_reset(group->sensors);
drawable_reset_group_highlight(tr_state, node);
group->bounds.width = 0;
if (ntag==TAG_MPEG4_Anchor) check_anchor=1;
#ifndef GPAC_DISABLE_X3D
else if (ntag==TAG_X3D_Anchor) check_anchor=1;
#endif
if (check_anchor) {
GF_SensorHandler *gf_sc_anchor_get_handler(GF_Node *n);
hsens = gf_sc_anchor_get_handler(node);
if (hsens) {
if (!group->sensors) group->sensors = gf_list_new();
gf_list_add(group->sensors, hsens);
group->flags |= GROUP_HAS_SENSORS | GROUP_IS_ANCHOR;
}
} else {
child = ((GF_ParentNode *)node)->children;
while (child) {
hsens = compositor_mpeg4_get_sensor_handler_ex(child->node, GF_TRUE);
if (hsens) {
if (!group->sensors) group->sensors = gf_list_new();
gf_list_add(group->sensors, hsens);
group->flags |= GROUP_HAS_SENSORS;
}
child = child->next;
}
}
}
else if ((tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) && !tr_state->for_node && group->bounds.width) {
tr_state->bounds = group->bounds;
return;
}
#ifdef GF_SR_USE_VIDEO_CACHE
group_cached = group_2d_cache_traverse(node, group, tr_state);
#endif
gf_node_dirty_clear(node, GF_SG_CHILD_DIRTY);
#ifdef GF_SR_USE_VIDEO_CACHE
if (group_cached) return;
#endif
sensor_backup = NULL;
if ((tr_state->traversing_mode==TRAVERSE_PICK) && (group->flags & GROUP_HAS_SENSORS) ) {
sensor_backup = tr_state->vrml_sensors;
assert(group->sensors);
tr_state->vrml_sensors = group->sensors;
}
if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
child = ((GF_ParentNode *)node)->children;
backup = tr_state->text_split_mode;
if (tr_state->text_split_mode && (gf_node_list_get_count(child)>1) ) tr_state->text_split_mode = 0;
group->flags &= ~GROUP_SKIP_CULLING;
group->bounds.width = group->bounds.height = 0;
tr_state->bounds.width = tr_state->bounds.height = 0;
#ifndef GPAC_DISABLE_3D
tr_state->bbox.is_set = 0;
#endif
while (child) {
gf_node_traverse(child->node, tr_state);
if (tr_state->disable_cull) {
group->flags |= GROUP_SKIP_CULLING;
tr_state->disable_cull = 0;
}
#ifndef GPAC_DISABLE_3D
if (tr_state->bbox.is_set) {
gf_rect_from_bbox(&tr_state->bounds, &tr_state->bbox);
tr_state->bbox.is_set = 0;
}
#endif
gf_rect_union(&group->bounds, &tr_state->bounds);
tr_state->bounds.width = tr_state->bounds.height = 0;
child = child->next;
}
tr_state->bounds = group->bounds;
if (group->flags & GROUP_SKIP_CULLING)
tr_state->disable_cull = 1;
tr_state->text_split_mode = backup;
}
else if (tr_state->traversing_mode==TRAVERSE_SORT) {
Bool prev_inv = tr_state->invalidate_all;
#ifdef GF_SR_USE_VIDEO_CACHE
DrawableContext *first_ctx = tr_state->visual->cur_context;
Bool skip_first_ctx = (first_ctx && first_ctx->drawable) ? 1 : 0;
u32 cache_too_small = 0;
u32 traverse_time = gf_sys_clock();
u32 last_cache_idx = gf_list_count(tr_state->visual->compositor->cached_groups_queue);
tr_state->cache_too_small = 0;
#endif
if (backup & GF_SG_VRML_COLOR_DIRTY) {
tr_state->invalidate_all = 1;
gf_node_dirty_clear(node, GF_SG_VRML_COLOR_DIRTY);
}
child = ((GF_ParentNode *)node)->children;
while (child) {
gf_node_traverse(child->node, tr_state);
child = child->next;
#ifdef GF_SR_USE_VIDEO_CACHE
if (tr_state->cache_too_small)
cache_too_small++;
#endif
}
tr_state->invalidate_all = prev_inv;
#ifdef GF_SR_USE_VIDEO_CACHE
if (cache_too_small) {
tr_state->cache_too_small = 1;
} else {
traverse_time = gf_sys_clock() - traverse_time;
group->traverse_time += traverse_time;
group_2d_cache_evaluate(node, group, tr_state, first_ctx, skip_first_ctx, last_cache_idx);
}
#endif
drawable_check_focus_highlight(node, tr_state, NULL);
}
else {
child = ((GF_ParentNode *)node)->children;
while (child) {
gf_node_traverse(child->node, tr_state);
child = child->next;
}
}
if (sensor_backup) {
tr_state->vrml_sensors = sensor_backup;
}
}
void group_2d_traverse_with_order(GF_Node *node, GroupingNode2D *group, GF_TraverseState *tr_state, u32 *positions)
{
u32 i, count;
Bool backup;
GF_List *sensor_backup;
GF_Node *child;
GF_ChildNodeItem *list;
#ifdef GF_SR_USE_VIDEO_CACHE
Bool group_cached;
#endif
backup = gf_node_dirty_get(node);
if (backup & GF_SG_CHILD_DIRTY) {
GF_SensorHandler *hsens;
Bool check_anchor=0;
u32 ntag = gf_node_get_tag(node);
group->flags &= ~GROUP_HAS_SENSORS;
drawable_reset_group_highlight(tr_state, node);
if (ntag==TAG_MPEG4_Anchor) check_anchor=1;
#ifndef GPAC_DISABLE_X3D
else if (ntag==TAG_X3D_Anchor) check_anchor=1;
#endif
if (check_anchor) {
GF_SensorHandler *gf_sc_anchor_get_handler(GF_Node *n);
hsens = gf_sc_anchor_get_handler(node);
if (hsens) {
if (!group->sensors) group->sensors = gf_list_new();
gf_list_add(group->sensors, hsens);
group->flags |= GROUP_HAS_SENSORS | GROUP_IS_ANCHOR;
}
} else {
list = ((GF_ParentNode *)node)->children;
while (list) {
hsens = compositor_mpeg4_get_sensor_handler_ex(list->node, GF_TRUE);
if (hsens) {
if (!group->sensors) group->sensors = gf_list_new();
gf_list_add(group->sensors, hsens);
group->flags |= GROUP_HAS_SENSORS;
}
list = list->next;
}
}
}
else if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
tr_state->bounds = group->bounds;
return;
}
#ifdef GF_SR_USE_VIDEO_CACHE
group_cached = group_2d_cache_traverse(node, group, tr_state);
#endif
gf_node_dirty_clear(node, GF_SG_CHILD_DIRTY);
#ifdef GF_SR_USE_VIDEO_CACHE
if (group_cached) return;
#endif
sensor_backup = NULL;
if ((tr_state->traversing_mode==TRAVERSE_PICK) && (group->flags & GROUP_HAS_SENSORS) ) {
sensor_backup = tr_state->vrml_sensors;
tr_state->vrml_sensors = group->sensors;
}
if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
list = ((GF_ParentNode *)node)->children;
backup = tr_state->text_split_mode;
if (tr_state->text_split_mode && (gf_node_list_get_count(list)>1) ) tr_state->text_split_mode = 0;
group->flags &= ~GROUP_SKIP_CULLING;
group->bounds.width = group->bounds.height = 0;
tr_state->bounds.width = tr_state->bounds.height = 0;
#ifndef GPAC_DISABLE_3D
tr_state->bbox.is_set = 0;
#endif
count = gf_node_list_get_count(list);
for (i=0; i<count; i++) {
child = gf_node_list_get_child(list, positions[i]);
gf_node_traverse(child, tr_state);
if (tr_state->disable_cull) {
group->flags |= GROUP_SKIP_CULLING;
tr_state->disable_cull = 0;
}
#ifndef GPAC_DISABLE_3D
if (tr_state->bbox.is_set) {
gf_rect_from_bbox(&tr_state->bounds, &tr_state->bbox);
tr_state->bbox.is_set = 0;
}
#endif
gf_rect_union(&group->bounds, &tr_state->bounds);
tr_state->bounds.width = tr_state->bounds.height = 0;
}
tr_state->bounds = group->bounds;
if (group->flags & GROUP_SKIP_CULLING)
tr_state->disable_cull = 1;
tr_state->text_split_mode = backup;
} else if (tr_state->traversing_mode==TRAVERSE_SORT) {
Bool prev_inv = tr_state->invalidate_all;
#ifdef GF_SR_USE_VIDEO_CACHE
DrawableContext *first_ctx = tr_state->visual->cur_context;
u32 cache_too_small = 0;
Bool skip_first_ctx = (first_ctx && first_ctx->drawable) ? 1 : 0;
u32 traverse_time = gf_sys_clock();
u32 last_cache_idx = gf_list_count(tr_state->visual->compositor->cached_groups_queue);
tr_state->cache_too_small = 0;
#endif
if (backup & GF_SG_VRML_COLOR_DIRTY) {
tr_state->invalidate_all = 1;
gf_node_dirty_clear(node, GF_SG_VRML_COLOR_DIRTY);
}
list = ((GF_ParentNode *)node)->children;
count = gf_node_list_get_count(list);
for (i=0; i<count; i++) {
child = gf_node_list_get_child(list, positions[i]);
gf_node_traverse(child, tr_state);
#ifdef GF_SR_USE_VIDEO_CACHE
if (tr_state->cache_too_small)
cache_too_small++;
#endif
}
tr_state->invalidate_all = prev_inv;
#ifdef GF_SR_USE_VIDEO_CACHE
if (cache_too_small) {
tr_state->cache_too_small = 1;
} else {
traverse_time = gf_sys_clock() - traverse_time;
group->traverse_time += traverse_time;
group_2d_cache_evaluate(node, group, tr_state, first_ctx, skip_first_ctx, last_cache_idx);
}
#endif
drawable_check_focus_highlight(node, tr_state, NULL);
} else {
list = ((GF_ParentNode *)node)->children;
count = gf_node_list_get_count(list);
for (i=0; i<count; i++) {
child = gf_node_list_get_child(list, positions[i]);
gf_node_traverse(child, tr_state);
}
}
if (sensor_backup) {
tr_state->vrml_sensors = sensor_backup;
}
}
#ifndef GPAC_DISABLE_3D
void group_3d_setup(GroupingNode *group, GF_Node *node)
{
memset(group, 0, sizeof(GroupingNode));
}
void group_3d_delete(GF_Node *node)
{
GroupingNode *group = (GroupingNode *)gf_node_get_private(node);
gf_free(group);
}
GroupingNode *group_3d_new(GF_Node *node)
{
GroupingNode *st;
GF_SAFEALLOC(st, GroupingNode);
gf_node_set_private(node, st);
return st;
}
static u32 get_light_type(GF_Node *n)
{
switch (gf_node_get_tag(n)) {
case TAG_MPEG4_DirectionalLight:
#ifndef GPAC_DISABLE_X3D
case TAG_X3D_DirectionalLight:
#endif
return 2;
case TAG_MPEG4_PointLight:
case TAG_MPEG4_SpotLight:
return 1;
default:
return 0;
}
}
void group_3d_traverse(GF_Node *node, GroupingNode *group, GF_TraverseState *tr_state)
{
u32 mode_back;
Bool split_text_backup, do_lights;
DirectionalLightContext *dl;
GF_List *sensor_backup;
GF_SensorHandler *hsens;
GF_ChildNodeItem *l;
if (gf_node_dirty_get(node) & GF_SG_CHILD_DIRTY) {
if (!tr_state->visual->type_3d && tr_state->visual->compositor->hybrid_opengl) {
tr_state->visual->compositor->root_visual_setup=0;
tr_state->visual->compositor->force_type_3d=1;
}
if (tr_state->traversing_mode!=TRAVERSE_GET_BOUNDS) {
mode_back = tr_state->traversing_mode;
tr_state->traversing_mode=TRAVERSE_GET_BOUNDS;
group_3d_traverse(node, group, tr_state);
tr_state->traversing_mode = mode_back;
}
else {
u32 ntag = gf_node_get_tag(node);
group->flags &= ~(GROUP_HAS_SENSORS | GROUP_HAS_LIGHTS);
if ((ntag==TAG_MPEG4_Anchor)
#ifndef GPAC_DISABLE_X3D
|| (ntag==TAG_X3D_Anchor)
#endif
) group->flags |= GROUP_HAS_SENSORS;
l = ((GF_ParentNode*)node)->children;
while (l) {
hsens = compositor_mpeg4_get_sensor_handler_ex(l->node, GF_TRUE);
if (hsens) {
group->flags |= GROUP_HAS_SENSORS;
}
else if (get_light_type(l->node)) {
group->flags |= GROUP_HAS_LIGHTS;
}
l = l->next;
}
gf_node_dirty_clear(node, GF_SG_CHILD_DIRTY);
}
}
else if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
tr_state->bbox = group->bbox;
if (!tr_state->bbox.is_set) tr_state->bbox.radius=-FIX_ONE;
gf_node_dirty_clear(node, 0);
return;
}
gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
mode_back=tr_state->cull_flag;
if (!(group->flags & GROUP_SKIP_CULLING)
&& (tr_state->traversing_mode==TRAVERSE_SORT)
&& !visual_3d_node_cull(tr_state, &group->bbox, 0)) {
tr_state->cull_flag = mode_back;
return;
}
sensor_backup = NULL;
if ((tr_state->traversing_mode==TRAVERSE_PICK) && (group->flags & GROUP_HAS_SENSORS) ) {
sensor_backup = tr_state->vrml_sensors;
tr_state->vrml_sensors = gf_list_new();
l = ((GF_ParentNode*)node)->children;
while (l) {
hsens = compositor_mpeg4_get_sensor_handler_ex(l->node, GF_TRUE);
if (hsens && hsens->IsEnabled(l->node))
gf_list_add(tr_state->vrml_sensors, hsens);
l = l->next;
}
}
do_lights = 0;
if (group->flags & GROUP_HAS_LIGHTS) {
if (tr_state->traversing_mode==TRAVERSE_LIGHTING) {
l = ((GF_ParentNode*)node)->children;
while (l) {
if (get_light_type(l->node)==2) gf_node_traverse(l->node, tr_state);
l = l->next;
}
}
else if (tr_state->traversing_mode==TRAVERSE_SORT) {
do_lights = 1;
tr_state->traversing_mode = TRAVERSE_DRAW_3D;
tr_state->local_light_on = 1;
l = ((GF_ParentNode*)node)->children;
while (l) {
if (get_light_type(l->node)==1) {
dl = (DirectionalLightContext*)gf_malloc(sizeof(DirectionalLightContext));
dl->dlight = l->node;
memcpy(&dl->light_matrix, &tr_state->model_matrix, sizeof(GF_Matrix));
gf_list_add(tr_state->local_lights, dl);
gf_node_traverse(dl->dlight, tr_state);
}
l = l->next;
}
tr_state->traversing_mode = TRAVERSE_SORT;
}
}
if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
l = ((GF_ParentNode*)node)->children;
split_text_backup = tr_state->text_split_mode;
if (tr_state->text_split_mode && (gf_node_list_get_count(l)>1) ) tr_state->text_split_mode = 0;
group->bbox.is_set = tr_state->bbox.is_set = 0;
tr_state->bounds.width = 0;
group->flags &= ~GROUP_SKIP_CULLING;
while (l) {
gf_node_traverse(l->node, tr_state);
if (tr_state->disable_cull) {
group->flags |= GROUP_SKIP_CULLING;
tr_state->disable_cull = 0;
}
if (tr_state->bounds.width) {
gf_bbox_from_rect(&tr_state->bbox, &tr_state->bounds);
tr_state->bounds.width = 0;
}
if (tr_state->bbox.is_set) {
gf_bbox_union(&group->bbox, &tr_state->bbox);
}
tr_state->bbox.is_set = 0;
l = l->next;
}
tr_state->bbox = group->bbox;
if (group->flags & GROUP_SKIP_CULLING)
tr_state->disable_cull = 1;
tr_state->text_split_mode = split_text_backup;
} else {
l = ((GF_ParentNode*)node)->children;
while (l) {
gf_node_traverse(l->node, tr_state);
l = l->next;
}
if (tr_state->traversing_mode==TRAVERSE_SORT)
drawable3d_check_focus_highlight(node, tr_state, NULL);
}
tr_state->cull_flag = mode_back;
if (sensor_backup) {
gf_list_del(tr_state->vrml_sensors);
tr_state->vrml_sensors = sensor_backup;
}
if (do_lights) {
u32 lcount;
tr_state->traversing_mode = TRAVERSE_DRAW_3D;
tr_state->local_light_on = 0;
while ( (lcount = gf_list_count(tr_state->local_lights)) ) {
dl = (DirectionalLightContext*)gf_list_get(tr_state->local_lights, lcount-1);
gf_list_rem(tr_state->local_lights, lcount-1);
gf_node_traverse(dl->dlight, tr_state);
gf_free(dl);
}
tr_state->traversing_mode = TRAVERSE_SORT;
}
}
#endif
void parent_node_setup(ParentNode2D *group)
{
group->groups = gf_list_new();
}
void parent_node_predestroy(ParentNode2D *group)
{
parent_node_reset(group);
gf_list_del(group->groups);
}
void parent_node_reset(ParentNode2D *group)
{
while (gf_list_count(group->groups)) {
ChildGroup *cg = (ChildGroup *)gf_list_get(group->groups, 0);
gf_list_rem(group->groups, 0);
gf_free(cg);
}
}
void parent_node_start_group(ParentNode2D *group, GF_Node *n, Bool discardable)
{
ChildGroup *cg;
if (!n) {
cg = gf_list_last(group->groups);
if (!cg) return;
n = cg->child;
}
GF_SAFEALLOC(cg, ChildGroup);
if (!cg) {
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate child group\n"));
return;
}
cg->child = n;
cg->text_type = discardable;
gf_list_add(group->groups, cg);
}
void parent_node_end_group(ParentNode2D *group, GF_Rect *bounds)
{
ChildGroup *cg = (ChildGroup *)gf_list_last(group->groups);
if (!cg) return;
if (cg->ascent || cg->descent) return;
cg->original = *bounds;
cg->final = cg->original;
}
void parent_node_end_text_group(ParentNode2D *group, GF_Rect *bounds, Fixed ascent, Fixed descent, u32 text_split_idx)
{
ChildGroup *cg = (ChildGroup *)gf_list_last(group->groups);
if (!cg) return;
cg->text_split_idx = text_split_idx;
cg->ascent = ascent;
cg->descent = descent;
cg->final = cg->original = *bounds;
}
void parent_node_traverse(GF_Node *node, ParentNode2D *group, GF_TraverseState *tr_state)
{
Bool split_text_backup;
GF_List *sensor_backup;
GF_ChildNodeItem *l;
if (gf_node_dirty_get(node) & GF_SG_CHILD_DIRTY) {
Bool check_anchor=0;
u32 ntag = gf_node_get_tag(node);
group->flags &= ~GROUP_HAS_SENSORS;
if (ntag==TAG_MPEG4_Anchor) check_anchor=1;
#ifndef GPAC_DISABLE_X3D
else if (ntag==TAG_X3D_Anchor) check_anchor=1;
#endif
if (check_anchor) {
group->flags |= GROUP_HAS_SENSORS | GROUP_IS_ANCHOR;
} else {
l = ((GF_ParentNode *)node)->children;
while (l) {
GF_SensorHandler *hsens = compositor_mpeg4_get_sensor_handler_ex(l->node, GF_TRUE);
if (hsens) {
group->flags |= GROUP_HAS_SENSORS;
break;
}
l = l->next;
}
}
gf_node_dirty_clear(node, GF_SG_CHILD_DIRTY);
}
gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
sensor_backup = NULL;
if ((tr_state->traversing_mode==TRAVERSE_PICK) && (group->flags & GROUP_HAS_SENSORS) ) {
GF_SensorHandler *hsens;
sensor_backup = tr_state->vrml_sensors;
tr_state->vrml_sensors = gf_list_new();
l = ((GF_ParentNode *)node)->children;
while (l) {
hsens = compositor_mpeg4_get_sensor_handler_ex(l->node, GF_TRUE);
if (hsens) gf_list_add(tr_state->vrml_sensors, hsens);
l = l->next;
}
}
split_text_backup = tr_state->text_split_mode;
group->flags &= ~GROUP_SKIP_CULLING;
tr_state->bounds.width = tr_state->bounds.height = 0;
#ifndef GPAC_DISABLE_3D
tr_state->bbox.is_set = 0;
#endif
l = ((GF_ParentNode *)node)->children;
while (l) {
parent_node_start_group(group, l->node, 0);
tr_state->bounds.width = tr_state->bounds.height = 0;
gf_node_traverse(l->node, tr_state);
#ifndef GPAC_DISABLE_3D
if (tr_state->bbox.is_set) {
gf_rect_from_bbox(&tr_state->bounds, &tr_state->bbox);
tr_state->bbox.is_set = 0;
}
#endif
parent_node_end_group(group, &tr_state->bounds);
l = l->next;
}
tr_state->text_split_mode = split_text_backup;
if (sensor_backup) {
gf_list_del(tr_state->vrml_sensors);
tr_state->vrml_sensors = sensor_backup;
}
}
void parent_node_child_traverse(ChildGroup *cg, GF_TraverseState *tr_state)
{
Fixed dx, dy;
dx = cg->final.x - cg->original.x + cg->scroll_x;
dy = cg->final.y - cg->original.y + cg->scroll_y;
tr_state->text_split_idx = cg->text_split_idx;
#ifndef GPAC_DISABLE_3D
if (tr_state->visual->type_3d) {
GF_Matrix mx_bckup;
gf_mx_copy(mx_bckup, tr_state->model_matrix);
gf_mx_add_translation(&tr_state->model_matrix, dx, dy, 0);
gf_node_traverse(cg->child, tr_state);
gf_mx_copy(tr_state->model_matrix, mx_bckup);
} else
#endif
{
GF_Matrix2D mx2d;
gf_mx2d_copy(mx2d, tr_state->transform);
gf_mx2d_init(tr_state->transform);
gf_mx2d_add_translation(&tr_state->transform, dx, dy);
gf_mx2d_add_matrix(&tr_state->transform, &mx2d);
gf_node_traverse(cg->child, tr_state);
gf_mx2d_copy(tr_state->transform, mx2d);
}
tr_state->text_split_idx = 0;
}
void parent_node_child_traverse_matrix(ChildGroup *cg, GF_TraverseState *tr_state, GF_Matrix2D *mat2D)
{
if (!mat2D) return;
tr_state->text_split_idx = cg->text_split_idx;
#ifndef GPAC_DISABLE_3D
if (tr_state->visual->type_3d) {
GF_Matrix mx, mx_bckup;
gf_mx_from_mx2d(&mx, mat2D);
gf_mx_copy(mx_bckup, tr_state->model_matrix);
gf_mx_add_matrix(&tr_state->model_matrix, &mx);
gf_node_traverse(cg->child, tr_state);
gf_mx_copy(tr_state->model_matrix, mx_bckup);
} else
#endif
{
GF_Matrix2D mx2d;
gf_mx2d_copy(mx2d, tr_state->transform);
gf_mx2d_pre_multiply(&tr_state->transform, mat2D);
gf_node_traverse(cg->child, tr_state);
gf_mx2d_copy(tr_state->transform, mx2d);
}
tr_state->text_split_idx = 0;
}
#endif