blob: 938ad2c925d507680a120fb5c7b78533921181b2 [file] [edit]
/*
* GPAC - Multimedia Framework C SDK
*
* Authors: Jean Le Feuvre
* Copyright (c) Telecom ParisTech 2000-2023
* All rights reserved
*
* This file is part of GPAC / Scene Compositor 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 "visual_manager.h"
#include "nodes_stacks.h"
#if !defined(GPAC_DISABLE_COMPOSITOR)
#include <gpac/nodes_mpeg4.h>
#ifndef GPAC_DISABLE_SVG
#include <gpac/nodes_svg.h>
#endif
static Bool visual_draw_bitmap_stub(GF_VisualManager *visual, GF_TraverseState *tr_state, struct _drawable_context *ctx)
{
return 0;
}
GF_VisualManager *visual_new(GF_Compositor *compositor)
{
GF_VisualManager *tmp;
GF_SAFEALLOC(tmp, GF_VisualManager);
if (!tmp) {
GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate new visual\n"));
return NULL;
}
tmp->center_coords = 1;
tmp->compositor = compositor;
ra_init(&tmp->to_redraw);
#ifndef GPAC_DISABLE_VRML
tmp->back_stack = gf_list_new();
tmp->view_stack = gf_list_new();
#endif
tmp->raster_brush = gf_evg_stencil_new(GF_STENCIL_SOLID);
tmp->DrawBitmap = visual_draw_bitmap_stub;
tmp->ClearSurface = visual_2d_clear_surface;
#ifdef GPAC_ENABLE_COVERAGE
if (gf_sys_is_cov_mode()) {
visual_draw_bitmap_stub(tmp, NULL, NULL);
visual_reset_graphics(NULL);
}
#endif
#ifndef GPAC_DISABLE_3D
#ifndef GPAC_DISABLE_VRML
tmp->navigation_stack = gf_list_new();
tmp->fog_stack = gf_list_new();
#endif /*GPAC_DISABLE_VRML*/
tmp->alpha_nodes_to_draw = gf_list_new();
tmp->compiled_programs = gf_list_new();
#endif
return tmp;
}
void visual_del(GF_VisualManager *visual)
{
ra_del(&visual->to_redraw);
if (visual->raster_surface) gf_evg_surface_delete(visual->raster_surface);
visual->raster_surface = NULL;
if (visual->raster_brush) gf_evg_stencil_delete(visual->raster_brush);
visual->raster_brush = NULL;
while (visual->context) {
DrawableContext *ctx = visual->context;
visual->context = ctx->next;
DeleteDrawableContext(ctx);
}
while (visual->prev_nodes) {
struct _drawable_store *cur = visual->prev_nodes;
visual->prev_nodes = cur->next;
gf_free(cur);
}
#ifndef GPAC_DISABLE_VRML
if (visual->back_stack) BindableStackDelete(visual->back_stack);
if (visual->view_stack) BindableStackDelete(visual->view_stack);
#endif /*GPAC_DISABLE_VRML*/
#ifndef GPAC_DISABLE_3D
visual_3d_reset_graphics(visual);
ra_del(&visual->hybgl_drawn);
#ifndef GPAC_DISABLE_VRML
if (visual->navigation_stack) BindableStackDelete(visual->navigation_stack);
if (visual->fog_stack) BindableStackDelete(visual->fog_stack);
#endif /*GPAC_DISABLE_VRML*/
gf_list_del(visual->alpha_nodes_to_draw);
gf_list_del(visual->compiled_programs);
#endif
gf_free(visual);
}
Bool visual_get_size_info(GF_TraverseState *tr_state, Fixed *surf_width, Fixed *surf_height)
{
Fixed w, h;
// w = tr_state->visual->width;
// h = tr_state->visual->height;
w = tr_state->vp_size.x;
h = tr_state->vp_size.y;
/*no size info, use main compositor output size*/
if (!w || !h) {
w = INT2FIX(tr_state->visual->compositor->vp_width);
h = INT2FIX(tr_state->visual->compositor->vp_height);
}
if (tr_state->pixel_metrics) {
*surf_width = w;
*surf_height = h;
return 1;
}
if (tr_state->min_hsize) {
*surf_width = gf_divfix(w, tr_state->min_hsize);
*surf_height = gf_divfix(h, tr_state->min_hsize);
return 0;
}
if (h > w) {
*surf_width = 2*FIX_ONE;
*surf_height = gf_divfix(2*h, w);
} else {
*surf_width = gf_divfix(2*w, h);
*surf_height = 2*FIX_ONE;
}
return 0;
}
void visual_clean_contexts(GF_VisualManager *visual)
{
u32 i, count;
Bool is_root_visual = (visual->compositor->visual==visual) ? 1 : 0;
DrawableContext *ctx = visual->context;
while (ctx && ctx->drawable) {
/*remove visual registration flag*/
ctx->drawable->flags &= ~DRAWABLE_REGISTERED_WITH_VISUAL;
if (is_root_visual && (ctx->flags & CTX_HAS_APPEARANCE))
gf_node_dirty_reset(ctx->appear, 0);
#ifndef GPAC_DISABLE_3D
/*this may happen when switching a visual from 2D to 3D - discard context*/
if (visual->type_3d) ctx->drawable=NULL;
#endif
ctx = ctx->next;
}
/*composite visual, cannot reset flags until root is done*/
if (!is_root_visual) return;
/*reset all flags of all appearance nodes registered on all visuals but main one (done above)
this must be done once all visuals have been drawn, otherwise we won't detect the changes
for nodes drawn on several visuals*/
count = gf_list_count(visual->compositor->visuals);
for (i=1; i<count; i++) {
GF_VisualManager *a_vis = gf_list_get(visual->compositor->visuals, i);
ctx = a_vis->context;
while (ctx && ctx->drawable) {
if (ctx->flags & CTX_HAS_APPEARANCE)
gf_node_dirty_reset(ctx->appear, 0);
ctx->drawable = NULL;
ctx = ctx->next;
}
}
}
Bool visual_draw_frame(GF_VisualManager *visual, GF_Node *root, GF_TraverseState *tr_state, Bool is_root_visual)
{
#ifndef GPAC_DISABLE_3D
if (visual->type_3d) {
Bool res = visual_3d_draw_frame(visual, root, tr_state, is_root_visual);
visual_clean_contexts(visual);
return res;
}
if (visual->compositor->hybrid_opengl)
visual_3d_clean_state(visual);
#endif
return visual_2d_draw_frame(visual, root, tr_state, is_root_visual);
}
void gf_sc_get_nodes_bounds(GF_Node *self, GF_ChildNodeItem *children, GF_TraverseState *tr_state, s32 *child_idx)
{
u32 i;
SFVec2f size;
GF_Rect rc;
GF_Matrix2D cur_mx;
if (tr_state->abort_bounds_traverse) {
if (self == tr_state->for_node) {
gf_mx2d_pre_multiply(&tr_state->mx_at_node, &tr_state->transform);
}
tr_state->abort_bounds_traverse=0;
gf_sc_get_nodes_bounds(self, children, tr_state, child_idx);
tr_state->abort_bounds_traverse=1;
return;
}
if (!children) return;
size.x = size.y = -FIX_ONE;
#ifndef GPAC_DISABLE_VRML
switch (gf_node_get_tag(self)) {
case TAG_MPEG4_Layer2D:
size = ((M_Layer2D *)self)->size;
break;
case TAG_MPEG4_Layer3D:
size = ((M_Layer3D *)self)->size;
break;
case TAG_MPEG4_Form:
size = ((M_Form *)self)->size;
break;
}
#endif
if ((size.x>=0) && (size.y>=0)) {
tr_state->bounds = gf_rect_center(size.x, size.y);
return;
}
gf_mx2d_copy(cur_mx, tr_state->transform);
rc = gf_rect_center(0,0);
i = 0;
while (children) {
if (child_idx && (i != (u32) *child_idx)) {
children = children->next;
continue;
}
gf_mx2d_init(tr_state->transform);
tr_state->bounds = gf_rect_center(0,0);
/*we hit the target node*/
if (children->node == tr_state->for_node)
tr_state->abort_bounds_traverse = 1;
gf_node_traverse(children->node, tr_state);
if (tr_state->abort_bounds_traverse) {
gf_mx2d_add_matrix(&tr_state->mx_at_node, &cur_mx);
return;
}
gf_mx2d_apply_rect(&tr_state->transform, &tr_state->bounds);
gf_rect_union(&rc, &tr_state->bounds);
children = children->next;
if (child_idx)
break;
}
#ifndef GPAC_DISABLE_SVG
if (gf_node_get_tag(self)==TAG_SVG_use) {
GF_FieldInfo info;
if (gf_node_get_attribute_by_tag(self, TAG_XLINK_ATT_href, 0, 0, &info)==GF_OK) {
GF_Node *iri = ((XMLRI*)info.far_ptr)->target;
if (iri) {
gf_mx2d_init(tr_state->transform);
tr_state->bounds = gf_rect_center(0,0);
/*we hit the target node*/
if (iri == tr_state->for_node)
tr_state->abort_bounds_traverse = 1;
gf_node_traverse(iri, tr_state);
if (tr_state->abort_bounds_traverse) {
gf_mx2d_pre_multiply(&tr_state->mx_at_node, &cur_mx);
return;
}
gf_mx2d_apply_rect(&tr_state->transform, &tr_state->bounds);
gf_rect_union(&rc, &tr_state->bounds);
}
}
}
#endif
gf_mx2d_copy(tr_state->transform, cur_mx);
if (self != tr_state->for_node) {
gf_mx2d_apply_rect(&tr_state->transform, &rc);
}
tr_state->bounds = rc;
}
void visual_reset_graphics(GF_VisualManager *visual)
{
if (!visual) return;
#ifndef GPAC_DISABLE_3D
if (visual->type_3d) {
visual_3d_reset_graphics(visual);
}
compositor_2d_reset_gl_auto(visual->compositor);
#endif
}
#endif //!defined(GPAC_DISABLE_COMPOSITOR)