LCOV - code coverage report
Current view: top level - compositor - mpeg4_composite.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 317 402 78.9 %
Date: 2021-04-29 23:48:07 Functions: 13 14 92.9 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2020
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / Scene Compositor sub-project
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : 
      27             : 
      28             : #include <gpac/internal/scenegraph_dev.h>
      29             : 
      30             : #include "nodes_stacks.h"
      31             : #include "visual_manager.h"
      32             : #include "texturing.h"
      33             : 
      34             : #ifndef GPAC_DISABLE_VRML
      35             : 
      36             : #ifdef GPAC_USE_TINYGL
      37             : #include <GL/oscontext.h>
      38             : #endif
      39             : 
      40             : typedef struct
      41             : {
      42             :         GF_TextureHandler txh;
      43             :         Fixed sx, sy;
      44             :         /*the visual object handling the texture*/
      45             :         GF_VisualManager *visual;
      46             :         Bool first, unsupported;
      47             :         GF_List *sensors, *previous_sensors, *temp_sensors, *temp_previous_sensors;
      48             :         GF_Node *prev_hit_appear;
      49             : 
      50             :         GF_TraverseState *tr_state;
      51             : 
      52             : #ifdef GPAC_USE_TINYGL
      53             :         ostgl_context *tgl_ctx;
      54             : #else
      55             :         Bool use_fbo;
      56             : #endif
      57             : } CompositeTextureStack;
      58             : 
      59             : 
      60           0 : static Bool composite2d_draw_bitmap(GF_VisualManager *visual, GF_TraverseState *tr_state, struct _drawable_context *ctx)
      61             : {
      62             :         u8 alpha = 0xFF;
      63             :         GF_VideoSurface offscreen_dst, video_src;
      64             :         GF_Window src_wnd, dst_wnd;
      65             :         Bool use_blit, has_scale;
      66             :         CompositeTextureStack *st;
      67             : 
      68           0 :         if (visual->compositor->disable_composite_blit) return 0;
      69             : 
      70           0 :         if (!ctx->aspect.fill_texture) return 1;
      71           0 :         if (ctx->transform.m[0]<0) return 0;
      72           0 :         if (ctx->transform.m[4]<0) {
      73           0 :                 if (!(ctx->flags & CTX_FLIPED_COORDS)) return 0;
      74             :         } else {
      75           0 :                 if (ctx->flags & CTX_FLIPED_COORDS) return 0;
      76             :         }
      77           0 :         if (ctx->transform.m[1] || ctx->transform.m[3]) return 0;
      78             : #ifndef GPAC_DISABLE_VRML
      79           0 :         if ((ctx->flags & CTX_HAS_APPEARANCE) && ctx->appear && ((M_Appearance*)ctx->appear)->textureTransform)
      80             :                 return 0;
      81             : #endif
      82             : 
      83           0 :         alpha = GF_COL_A(ctx->aspect.fill_color);
      84             :         /*THIS IS A HACK, will not work when setting filled=0, transparency and XLineProps*/
      85           0 :         if (!alpha) alpha = GF_COL_A(ctx->aspect.line_color);
      86           0 :         if (!alpha) return 1;
      87             : 
      88           0 :         st = (CompositeTextureStack *) gf_node_get_private(visual->offscreen);
      89             : 
      90           0 :         if (!compositor_texture_rectangles(visual, ctx->aspect.fill_texture, &ctx->bi->clip, &ctx->bi->unclip, &src_wnd, &dst_wnd, &use_blit, &has_scale)) return 1;
      91             : 
      92             :         memset(&video_src, 0, sizeof(GF_VideoSurface));
      93           0 :         video_src.height = ctx->aspect.fill_texture->height;
      94           0 :         video_src.width = ctx->aspect.fill_texture->width;
      95             :         video_src.pitch_x = 0;
      96           0 :         video_src.pitch_y = ctx->aspect.fill_texture->stride;
      97           0 :         video_src.pixel_format = ctx->aspect.fill_texture->pixelformat;
      98             : #ifdef GF_SR_USE_DEPTH
      99           0 :         if (ctx->aspect.fill_texture->pixelformat==GF_PIXEL_YUVD) video_src.pixel_format = GF_PIXEL_YUV;
     100             : #endif
     101           0 :         video_src.video_buffer = ctx->aspect.fill_texture->data;
     102             : 
     103             :         memset(&offscreen_dst, 0, sizeof(GF_VideoSurface));
     104           0 :         offscreen_dst.width = st->txh.width;
     105           0 :         offscreen_dst.height = st->txh.height;
     106           0 :         offscreen_dst.pitch_y = st->txh.stride;
     107           0 :         offscreen_dst.pixel_format = st->txh.pixelformat;
     108           0 :         offscreen_dst.video_buffer = st->txh.data;
     109             : 
     110           0 :         gf_stretch_bits(&offscreen_dst, &video_src, &dst_wnd, &src_wnd, alpha, 0, tr_state->col_key, ctx->col_mat);
     111           0 :         return 1;
     112             : }
     113             : 
     114        2404 : static void composite_traverse(GF_Node *node, void *rs, Bool is_destroy)
     115             : {
     116        2404 :         if (is_destroy) {
     117          32 :                 u32 i=0;
     118             :                 GF_VisualManager *a_visual;
     119          32 :                 CompositeTextureStack *st = (CompositeTextureStack *) gf_node_get_private(node);
     120             :                 /*unregister visual*/
     121          32 :                 gf_sc_visual_unregister(st->visual->compositor, st->visual);
     122             : 
     123             :                 /*We must make sure we don't keep pointers to this composite in the different visuals.
     124             :                   - we must track Appearance nodes at the compositor level to undo the textureTransform while picking
     125             :                   - but we clearly don't want to track destruction of all appearance nodes just to solve this texture delete
     126             :                                 => remove the entire compositeTexture appearance state - this may lead to small bugs in interaction logics, however they should
     127             :                                 not be too damageable
     128             :                 */
     129          32 :                 st->visual->compositor->hit_appear = NULL;
     130          32 :                 st->visual->compositor->prev_hit_appear = NULL;
     131             : 
     132         142 :                 while ( (a_visual = gf_list_enum(st->visual->compositor->visuals, &i))) {
     133          78 :                         if (a_visual->offscreen) {
     134          46 :                                 CompositeTextureStack *a_st = (CompositeTextureStack *) gf_node_get_private(a_visual->offscreen);
     135          46 :                                 a_st->prev_hit_appear = NULL;
     136             :                         }
     137             :                 }
     138             : 
     139          32 :                 visual_del(st->visual);
     140          32 :                 if (st->txh.data) gf_free(st->txh.data);
     141             :                 /*destroy texture*/
     142          32 :                 gf_sc_texture_destroy(&st->txh);
     143             : #ifdef GPAC_USE_TINYGL
     144             :                 if (st->tgl_ctx) ostgl_delete_context(st->tgl_ctx);
     145             : #endif
     146             : 
     147          32 :                 gf_list_del(st->sensors);
     148          32 :                 gf_list_del(st->previous_sensors);
     149             : 
     150          32 :                 gf_list_del(st->tr_state->vrml_sensors);
     151          32 :                 gf_free(st->tr_state);
     152             : 
     153          32 :                 gf_free(st);
     154             :         } else {
     155        2372 :                 gf_node_traverse_children(node, rs);
     156             :         }
     157        2404 : }
     158             : 
     159        2068 : static Bool composite_do_bindable(GF_Node *n, GF_TraverseState *tr_state, Bool force_check)
     160             : {
     161             :         GF_Node *btop;
     162             :         Bool ret = 0;
     163        2068 :         switch (gf_node_get_tag(n)) {
     164             : #ifndef GPAC_DISABLE_3D
     165         304 :         case TAG_MPEG4_CompositeTexture3D:
     166             :         {
     167             :                 M_CompositeTexture3D*c3d = (M_CompositeTexture3D*)n;
     168         304 :                 if (force_check || gf_node_dirty_get(c3d->background)) {
     169          68 :                         gf_node_traverse(c3d->background, tr_state);
     170             :                         ret = 1;
     171             :                 }
     172         304 :                 btop = (GF_Node*)gf_list_get(tr_state->backgrounds, 0);
     173         304 :                 if (btop != c3d->background) {
     174           2 :                         gf_node_unregister(c3d->background, n);
     175           2 :                         gf_node_register(btop, n);
     176           2 :                         c3d->background = btop;
     177           2 :                         gf_node_event_out(n, 5/*"background"*/);
     178             :                         ret = 1;
     179             :                 }
     180         304 :                 if (force_check || gf_node_dirty_get(c3d->viewpoint)) {
     181           2 :                         gf_node_traverse(c3d->viewpoint, tr_state);
     182             :                         ret = 1;
     183             :                 }
     184         304 :                 btop = (GF_Node*)gf_list_get(tr_state->viewpoints, 0);
     185         304 :                 if (btop != c3d->viewpoint) {
     186           0 :                         gf_node_unregister(c3d->viewpoint, n);
     187           0 :                         gf_node_register(btop, n);
     188           0 :                         c3d->viewpoint = btop;
     189           0 :                         gf_node_event_out(n, 8/*"viewpoint"*/);
     190             :                         ret = 1;
     191             :                 }
     192             : 
     193         304 :                 if (force_check || gf_node_dirty_get(c3d->fog)) {
     194           2 :                         gf_node_traverse(c3d->fog, tr_state);
     195             :                         ret = 1;
     196             :                 }
     197         304 :                 btop = (GF_Node*)gf_list_get(tr_state->fogs, 0);
     198         304 :                 if (btop != c3d->fog) {
     199           0 :                         gf_node_unregister(c3d->fog, n);
     200           0 :                         gf_node_register(btop, n);
     201           0 :                         c3d->fog = btop;
     202           0 :                         gf_node_event_out(n, 6/*"fog"*/);
     203             :                         ret = 1;
     204             :                 }
     205             : 
     206         304 :                 if (force_check || gf_node_dirty_get(c3d->navigationInfo)) {
     207           2 :                         gf_node_traverse(c3d->navigationInfo, tr_state);
     208             :                         ret = 1;
     209             :                 }
     210         304 :                 btop = (GF_Node*)gf_list_get(tr_state->navigations, 0);
     211         304 :                 if (btop != c3d->navigationInfo) {
     212           0 :                         gf_node_unregister(c3d->navigationInfo, n);
     213           0 :                         gf_node_register(btop, n);
     214           0 :                         c3d->navigationInfo = btop;
     215           0 :                         gf_node_event_out(n, 7/*"navigationInfo"*/);
     216             :                         ret = 1;
     217             :                 }
     218             :                 return ret;
     219             :         }
     220             : #endif
     221        1764 :         case TAG_MPEG4_CompositeTexture2D:
     222             :         {
     223             :                 M_CompositeTexture2D *c2d = (M_CompositeTexture2D*)n;
     224        1764 :                 if (force_check || gf_node_dirty_get(c2d->background)) {
     225          36 :                         gf_node_traverse(c2d->background, tr_state);
     226             :                         ret = 1;
     227             :                 }
     228        1764 :                 btop = (GF_Node*)gf_list_get(tr_state->backgrounds, 0);
     229        1764 :                 if (btop != c2d->background) {
     230           9 :                         gf_node_unregister(c2d->background, n);
     231           9 :                         gf_node_register(btop, n);
     232           9 :                         c2d->background = btop;
     233           9 :                         gf_node_event_out(n, 5/*"background"*/);
     234             :                         ret = 1;
     235             :                 }
     236             : 
     237        1764 :                 if (force_check || gf_node_dirty_get(c2d->viewport)) {
     238          30 :                         gf_node_traverse(c2d->viewport, tr_state);
     239             :                         ret = 1;
     240             :                 }
     241        1764 :                 btop = (GF_Node*)gf_list_get(tr_state->viewpoints, 0);
     242        1764 :                 if (btop != c2d->viewport) {
     243           0 :                         gf_node_unregister(c2d->viewport, n);
     244           0 :                         gf_node_register(btop, n);
     245           0 :                         c2d->viewport = btop;
     246           0 :                         gf_node_event_out(n, 6/*"viewport"*/);
     247             :                         ret = 1;
     248             :                 }
     249             : 
     250             :                 return ret;
     251             :         }
     252             :         }
     253             :         return 0;
     254             : }
     255             : 
     256        2627 : static void composite_update(GF_TextureHandler *txh)
     257             : {
     258             :         s32 w, h;
     259             :         GF_EVGStencil *stencil;
     260             : #ifndef GPAC_USE_GLES1X
     261             :         M_Background2D *back;
     262             : #endif
     263             :         GF_List *sensor_bck;
     264             :         Bool invalidate_all;
     265             :         u32 new_pixel_format;
     266        2627 :         GF_Compositor *compositor = (GF_Compositor *)txh->compositor;
     267        2627 :         CompositeTextureStack *st = (CompositeTextureStack *) gf_node_get_private(txh->owner);
     268             : 
     269        2627 :         if (st->unsupported) return;
     270             : 
     271             :         /*
     272             :                 if (compositor->recompute_ar) {
     273             :                         gf_node_dirty_set(txh->owner, 0, 0);
     274             :                         return;
     275             :                 }
     276             :         */
     277        2627 :         if (!compositor->rebuild_offscreen_textures && (!compositor->text_edit_changed || !st->visual->has_text_edit ) && !gf_node_dirty_get(txh->owner)) {
     278         559 :                 txh->needs_refresh = 0;
     279         559 :                 return;
     280             :         }
     281        2068 :         gf_node_dirty_clear(st->txh.owner, 0);
     282             : 
     283             :         /*in OpenGL_ES, only RGBA can be safelly used with glReadPixels*/
     284             : #if defined(GPAC_USE_GLES1X)
     285             :         new_pixel_format = GF_PIXEL_RGBA;
     286             : 
     287             : #else
     288             : 
     289        2068 :         back = gf_list_get(st->visual->back_stack, 0);
     290        2068 :         if (back && back->isBound) new_pixel_format = GF_PIXEL_RGB;
     291             :         else new_pixel_format = GF_PIXEL_RGBA;
     292             : 
     293             : #ifdef GPAC_USE_TINYGL
     294             :         /*TinyGL pixel format is fixed at compile time, we cannot override it !*/
     295             :         if (st->visual->type_3d) new_pixel_format = GF_PIXEL_RGBA;
     296             : 
     297             : #elif !defined(GPAC_DISABLE_3D)
     298             :         /*no alpha support in offscreen rendering*/
     299        2068 :         if (!compositor->visual->type_3d && !compositor->hybrid_opengl && !compositor->fbo_id && (st->visual->type_3d) && !(compositor->video_out->hw_caps & GF_VIDEO_HW_OPENGL_OFFSCREEN_ALPHA))
     300             :                 new_pixel_format = GF_PIXEL_RGB;
     301             : #endif
     302             : 
     303             : #endif //GPAC_USE_GLES1X
     304             : 
     305             :         /*FIXME - we assume RGB+Depth+bitshape, we should check with the video out module*/
     306             : #if defined(GF_SR_USE_DEPTH) && !defined(GPAC_DISABLE_3D)
     307        2068 :         if (st->visual->type_3d && (compositor->video_out->hw_caps & GF_VIDEO_HW_HAS_DEPTH) ) new_pixel_format = GF_PIXEL_RGBDS;
     308             : #endif
     309             : 
     310             : 
     311             : #ifndef GPAC_DISABLE_3D
     312        2068 :         if (st->visual->type_3d>1) {
     313         302 :                 w = ((M_CompositeTexture3D*)txh->owner)->pixelWidth;
     314         302 :                 h = ((M_CompositeTexture3D*)txh->owner)->pixelHeight;
     315             :         } else
     316             : #endif
     317             :         {
     318        1766 :                 w = ((M_CompositeTexture2D*)txh->owner)->pixelWidth;
     319        1766 :                 h = ((M_CompositeTexture2D*)txh->owner)->pixelHeight;
     320             :         }
     321             : 
     322             :         /*internal GPAC hacks for testing color spaces*/
     323        2068 :         if (w<-1) {
     324           0 :                 w = -w;
     325           0 :                 if (h<0) {
     326           0 :                         h = -h;
     327           0 :                         if (new_pixel_format==GF_PIXEL_RGBA) {
     328             :                                 new_pixel_format=GF_PIXEL_ARGB;
     329             :                         } else {
     330             :                                 new_pixel_format=GF_PIXEL_BGR;
     331             :                         }
     332             :                 } else {
     333           0 :                         if (new_pixel_format==GF_PIXEL_RGB) {
     334             :                                 new_pixel_format=GF_PIXEL_RGBX;
     335             :                         }
     336             :                 }
     337             :         }
     338        2068 :         else if (h<-1) {
     339           0 :                 h = -h;
     340           0 :                 if (new_pixel_format==GF_PIXEL_RGB) {
     341             :                         new_pixel_format=GF_PIXEL_RGBX;
     342             :                 }
     343             :         }
     344             : 
     345        2068 :         if (w<0) w = 0;
     346        2068 :         if (h<0) h = 0;
     347             : 
     348             : 
     349        2068 :         if (!w || !h) {
     350           0 :                 if (txh->tx_io) {
     351             : #ifdef GPAC_USE_TINYGL
     352             :                         if (st->tgl_ctx) ostgl_delete_context(st->tgl_ctx);
     353             : #endif
     354           0 :                         gf_sc_texture_release(txh);
     355           0 :                         if (txh->data) gf_free(txh->data);
     356           0 :                         txh->data = NULL;
     357           0 :                         txh->width = txh->height = txh->stride = 0;
     358             :                 }
     359             :                 return;
     360             :         }
     361        2068 :         invalidate_all = compositor->rebuild_offscreen_textures;
     362             : 
     363             :         /*rebuild stencil*/
     364        2068 :         if (!txh->tx_io
     365        2036 :                 || (w != (s32) txh->width) || ( h != (s32) txh->height)
     366        2031 :                 || (new_pixel_format != txh->pixelformat)
     367             :            ) {
     368             : 
     369             :                 Bool needs_stencil = 1;
     370          52 :                 if (txh->tx_io) {
     371             : #ifdef GPAC_USE_TINYGL
     372             :                         if (st->tgl_ctx) ostgl_delete_context(st->tgl_ctx);
     373             : #endif
     374          20 :                         gf_sc_texture_release(txh);
     375          20 :                         if (txh->data)
     376          13 :                                 gf_free(txh->data);
     377          20 :                         txh->data = NULL;
     378             :                 }
     379             : 
     380             :                 /*we don't use rect ext because of no support for texture transforms*/
     381             :                 if ((1)
     382             : #ifndef GPAC_DISABLE_3D
     383             :                         || compositor->gl_caps.npot_texture
     384             : #endif
     385             :                    ) {
     386          52 :                         st->txh.width = w;
     387          52 :                         st->txh.height = h;
     388          52 :                         st->sx = st->sy = FIX_ONE;
     389             :                 } else {
     390             :                         st->txh.width = 2;
     391             :                         while (st->txh.width<(u32)w) st->txh.width*=2;
     392             :                         st->txh.height = 2;
     393             :                         while (st->txh.height<(u32)h) st->txh.height*=2;
     394             : 
     395             :                         st->sx = INT2FIX(st->txh.width) / w;
     396             :                         st->sy = INT2FIX(st->txh.height) / h;
     397             :                 }
     398             : 
     399          52 :                 gf_sc_texture_allocate(txh);
     400          52 :                 txh->pixelformat = new_pixel_format;
     401          52 :                 switch (new_pixel_format) {
     402          41 :                 case GF_PIXEL_RGBA:
     403             :                 case GF_PIXEL_ARGB:
     404          41 :                         txh->stride = txh->width * 4;
     405          41 :                         txh->transparent = 1;
     406          41 :                         break;
     407           0 :                 case GF_PIXEL_RGB_565:
     408           0 :                         txh->stride = txh->width * 2;
     409           0 :                         txh->transparent = 0;
     410           0 :                         break;
     411           0 :                 case GF_PIXEL_RGBDS:
     412           0 :                         txh->stride = txh->width * 4;
     413           0 :                         txh->transparent = 1;
     414           0 :                         break;
     415          11 :                 case GF_PIXEL_RGB:
     416          11 :                         txh->stride = txh->width * 3;
     417          11 :                         txh->transparent = 0;
     418          11 :                         break;
     419             :                 }
     420             : 
     421          52 :                 st->visual->width = txh->width;
     422          52 :                 st->visual->height = txh->height;
     423          52 :                 st->use_fbo = GF_FALSE;
     424             : 
     425          52 :                 stencil = gf_evg_stencil_new(GF_STENCIL_TEXTURE);
     426             : 
     427             : #ifndef GPAC_DISABLE_3D
     428          52 :                 if (st->visual->type_3d) {
     429             :                         /*figure out what to do if main visual (eg video out) is not in OpenGL ...*/
     430           9 :                         if (!compositor->visual->type_3d && !compositor->hybrid_opengl) {
     431             :                                 /*create an offscreen window for OpenGL rendering*/
     432           0 :                                 if (!compositor->fbo_id
     433           0 :                                         && ((compositor->offscreen_width < st->txh.width) || (compositor->offscreen_height < st->txh.height))
     434             :                                 ) {
     435             : 
     436           0 :                                         GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[CompositeTexture] Offscreen OpenGL is not possible if no openGL context is created - use hybridGL mode for compositor\n"));
     437           0 :                                         st->unsupported = GF_TRUE;
     438             :                                 }
     439             :                         } else {
     440             :                                 needs_stencil = 0;
     441             :                         }
     442             :                 }
     443             : #endif
     444             : 
     445             :                 if (needs_stencil) {
     446          43 :                         txh->data = (char*)gf_malloc(sizeof(unsigned char) * txh->stride * txh->height);
     447          43 :                         memset(txh->data, 0, sizeof(unsigned char) * txh->stride * txh->height);
     448             : 
     449             :                         /*set stencil texture - we don't check error as an image could not be supported by the rasterizer
     450             :                         but still supported by the blitter (case of RGBD/RGBDS)*/
     451          43 :                         gf_evg_stencil_set_texture(stencil, txh->data, txh->width, txh->height, txh->stride, txh->pixelformat);
     452             : 
     453             : #ifdef GPAC_USE_TINYGL
     454             :                         if (st->visual->type_3d && !compositor->visual->type_3d) {
     455             :                                 st->tgl_ctx = ostgl_create_context(txh->width, txh->height, txh->transparent ? 32 : 24, &txh->data, 1);
     456             :                                 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[CompositeTexture] Creating TinyGL Offscreen context %p (%d %d - pf %s)\n", st->tgl_ctx, txh->width, txh->width, gf_4cc_to_str(txh->pixelformat)));
     457             :                         }
     458             : #endif
     459             :                 }
     460             : #if !defined(GPAC_USE_TINYGL) && !defined(GPAC_DISABLE_3D)
     461           9 :                 else if (compositor->gl_caps.fbo) {
     462           9 :                         if (gf_sc_texture_setup_fbo(&st->txh)==GF_OK)
     463           9 :                                 st->use_fbo = GF_TRUE;
     464             :                 }
     465             : #endif
     466             : 
     467             :                 invalidate_all = 1;
     468          52 :                 gf_sc_texture_set_stencil(txh, stencil);
     469             :         }
     470        2068 :         if (!txh->tx_io) return;
     471             : 
     472             : #ifndef GPAC_DISABLE_3D
     473        2068 :         if (st->visual->camera.is_3D) {
     474             : #ifdef GPAC_USE_TINYGL
     475             :                 st->visual->type_3d = 2;
     476             : #else
     477         304 :                 if (compositor->visual->type_3d) {
     478         152 :                         st->visual->type_3d = 2;
     479         152 :                 } else if (compositor->hybrid_opengl || compositor->fbo_id) {
     480         152 :                         st->visual->type_3d = 2;
     481           0 :                 } else if (! (compositor->video_out->hw_caps & GF_VIDEO_HW_OPENGL_OFFSCREEN)) {
     482           0 :                         st->visual->type_3d = 0;
     483             :                 } else {
     484           0 :                         st->visual->type_3d = 2;
     485             :                 }
     486             : #endif
     487             :         }
     488             : #endif
     489             : 
     490        2068 :         stencil = gf_sc_texture_get_stencil(txh);
     491        2068 :         if (!stencil) return;
     492             : 
     493             : #ifdef GPAC_USE_TINYGL
     494             :         if (st->tgl_ctx)
     495             :                 ostgl_make_current(st->tgl_ctx, 0);
     496             : #elif !defined(GPAC_DISABLE_3D)
     497        2068 :         if (st->use_fbo) {
     498         302 :                 gf_sc_texture_enable_fbo(&st->txh, GF_TRUE);
     499             :         }
     500             : #endif
     501             : 
     502        2068 :         sensor_bck = st->tr_state->vrml_sensors;
     503             :         memset(st->tr_state, 0, sizeof(GF_TraverseState));
     504        2068 :         st->tr_state->vrml_sensors = sensor_bck;
     505        2068 :         st->tr_state->visual = st->visual;
     506        2068 :         st->tr_state->invalidate_all = invalidate_all;
     507             : 
     508        2068 :         st->tr_state->immediate_draw = st->visual->compositor->traverse_state->immediate_draw;
     509             : 
     510        4136 :         gf_mx2d_init(st->tr_state->transform);
     511        2068 :         gf_cmx_init(&st->tr_state->color_mat);
     512             : 
     513        2068 :         st->tr_state->backgrounds = st->visual->back_stack;
     514        2068 :         st->tr_state->viewpoints = st->visual->view_stack;
     515        2068 :         st->tr_state->pixel_metrics = gf_sg_use_pixel_metrics(gf_node_get_graph(st->txh.owner));
     516        2068 :         st->tr_state->min_hsize = INT2FIX( MIN(txh->width, txh->height) ) / 2;
     517        2068 :         st->tr_state->vp_size.x = INT2FIX(txh->width);
     518        2068 :         st->tr_state->vp_size.y = INT2FIX(txh->height);
     519             : 
     520        2068 :         composite_do_bindable(st->txh.owner, st->tr_state, st->first);
     521        2068 :         st->first = 0;
     522             : 
     523        2068 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[CompositeTexture] Entering draw cycle\n"));
     524             : 
     525        2068 :         txh->needs_refresh = visual_draw_frame(st->visual, st->txh.owner, st->tr_state, 0);
     526        2068 :         txh->transparent = (st->visual->last_had_back==2) ? 0 : 1;
     527             : 
     528        2068 :         if (!compositor->edited_text && st->visual->has_text_edit)
     529           0 :                 st->visual->has_text_edit = 0;
     530             : 
     531             : 
     532             : #if 0
     533             :         /*set active viewport in image coordinates top-left=(0, 0), not in BIFS*/
     534             :         if (gf_list_count(st->visual->view_stack)) {
     535             :                 M_Viewport *vp = (M_Viewport *)gf_list_get(st->visual->view_stack, 0);
     536             : 
     537             :                 if (vp->isBound) {
     538             :                         SFVec2f size = vp->size;
     539             :                         if (size.x >=0 && size.y>=0) {
     540             :                                 /*FIXME - we need tracking of VP changes*/
     541             :                                 txh->needs_refresh = 1;
     542             :                         }
     543             :                 }
     544             :         }
     545             : #endif
     546             : 
     547        2068 :         if (txh->needs_refresh) {
     548             : #ifndef GPAC_DISABLE_3D
     549             : 
     550             : #ifndef GPAC_USE_TINYGL
     551        1296 :                 if (st->use_fbo) {
     552         302 :                         gf_sc_texture_enable_fbo(&st->txh, GF_FALSE);
     553             :                 } else
     554             : #endif
     555             :                 //no FBO, for composite 3D, store current buffer to texture
     556         994 :                 if (st->visual->camera.is_3D && (st->visual->compositor->visual->type_3d || st->visual->compositor->hybrid_opengl)) {
     557             : #ifndef GPAC_USE_TINYGL
     558           2 :                         gf_sc_copy_to_texture(&st->txh);
     559             : #endif
     560             :                 }
     561         992 :                 else if (st->visual->camera.is_3D) {
     562           0 :                         if (st->visual->compositor->visual->type_3d) {
     563             : #ifndef GPAC_USE_TINYGL
     564           0 :                                 gf_sc_copy_to_texture(&st->txh);
     565             : #else
     566             :                                 /*in TinyGL we only need to push associated bitmap to the texture*/
     567             :                                 gf_sc_texture_push_image(&st->txh, 0, 0);
     568             : #endif
     569             :                         } else {
     570             : #ifndef GPAC_USE_TINYGL
     571           0 :                                 gf_sc_copy_to_stencil(&st->txh);
     572             : #else
     573             :                                 if (txh->pixelformat==GF_PIXEL_RGBDS)
     574             :                                         gf_get_tinygl_depth(&st->txh);
     575             : #endif
     576             :                         }
     577             :                 } else
     578             : #endif
     579             :                 {
     580         992 :                         gf_sc_texture_set_stencil(txh, stencil);
     581             :                 }
     582        1296 :                 gf_sc_invalidate(st->txh.compositor, NULL);
     583             :         }
     584        2068 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[CompositeTexture] Leaving draw cycle\n"));
     585             : }
     586             : 
     587             : 
     588        1764 : GF_Err composite_get_video_access(GF_VisualManager *visual)
     589             : {
     590             :         GF_EVGStencil *stencil;
     591             :         GF_Err e;
     592        1764 :         CompositeTextureStack *st = (CompositeTextureStack *) gf_node_get_private(visual->offscreen);
     593             : 
     594        1764 :         if (!st->txh.tx_io || !visual->raster_surface) return GF_BAD_PARAM;
     595        1764 :         stencil = gf_sc_texture_get_stencil(&st->txh);
     596        1764 :         if (!stencil) return GF_BAD_PARAM;
     597        1764 :         e = gf_evg_surface_attach_to_texture(visual->raster_surface, stencil);
     598        1764 :         if (!e) visual->is_attached = 1;
     599             :         return e;
     600             : }
     601             : 
     602        1764 : void composite_release_video_access(GF_VisualManager *visual)
     603             : {
     604        1764 : }
     605             : 
     606        5899 : Bool composite_check_visual_attached(GF_VisualManager *visual)
     607             : {
     608        5899 :         return visual->is_attached;
     609             : }
     610             : 
     611          30 : void compositor_init_compositetexture2d(GF_Compositor *compositor, GF_Node *node)
     612             : {
     613             :         M_CompositeTexture2D *c2d = (M_CompositeTexture2D *)node;
     614             :         CompositeTextureStack *st;
     615          30 :         GF_SAFEALLOC(st, CompositeTextureStack);
     616             : 
     617          30 :         if (!st) {
     618           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate composite texture stack\n"));
     619             :                 return;
     620             :         }
     621             : 
     622          30 :         GF_SAFEALLOC(st->tr_state, GF_TraverseState);
     623          30 :         if (!st->tr_state) {
     624           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate composite texture state\n"));
     625             :                 return;
     626             :         }
     627          30 :         st->tr_state->vrml_sensors = gf_list_new();
     628             : 
     629          30 :         st->sensors = gf_list_new();
     630          30 :         st->previous_sensors = gf_list_new();
     631          30 :         gf_sc_texture_setup(&st->txh, compositor, node);
     632             :         /*remove texture from compositor and add it at the end, so that any sub-textures are handled before*/
     633          30 :         gf_list_del_item(compositor->textures, &st->txh);
     634          30 :         gf_list_add(compositor->textures, &st->txh);
     635             : 
     636          30 :         st->txh.update_texture_fcnt = composite_update;
     637             : 
     638          30 :         if ((c2d->repeatSandT==1) || (c2d->repeatSandT==3) ) st->txh.flags |= GF_SR_TEXTURE_REPEAT_S;
     639          30 :         if (c2d->repeatSandT>1) st->txh.flags |= GF_SR_TEXTURE_REPEAT_T;
     640             : 
     641             :         /*create composite visual*/
     642          30 :         st->visual = visual_new(compositor);
     643          30 :         st->visual->offscreen = node;
     644          30 :         st->visual->GetSurfaceAccess = composite_get_video_access;
     645          30 :         st->visual->ReleaseSurfaceAccess = composite_release_video_access;
     646          30 :         st->visual->DrawBitmap = composite2d_draw_bitmap;
     647          30 :         st->visual->CheckAttached = composite_check_visual_attached;
     648             : 
     649          30 :         st->visual->raster_surface = gf_evg_surface_new(1);
     650             : 
     651             : 
     652          30 :         st->first = 1;
     653          30 :         st->visual->compositor = compositor;
     654          30 :         gf_node_set_private(node, st);
     655          30 :         gf_node_set_callback_function(node, composite_traverse);
     656          30 :         gf_sc_visual_register(compositor, st->visual);
     657             : }
     658             : 
     659             : 
     660             : #ifndef GPAC_DISABLE_3D
     661           2 : void compositor_init_compositetexture3d(GF_Compositor *compositor, GF_Node *node)
     662             : {
     663             :         M_CompositeTexture3D *c3d = (M_CompositeTexture3D *)node;
     664             :         CompositeTextureStack *st;
     665             : 
     666           2 :         if (!gf_sc_check_gl_support(compositor)) {
     667           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[Compositor] Driver disabled, cannot render 3D composite textures\n"));
     668             :                 return;
     669             :         }
     670             : 
     671           2 :         GF_SAFEALLOC(st, CompositeTextureStack);
     672           2 :         if (!st) {
     673           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate composite texture stack\n"));
     674             :                 return;
     675             :         }
     676           2 :         GF_SAFEALLOC(st->tr_state, GF_TraverseState);
     677           2 :         if (!st->tr_state) {
     678           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate composite texture state\n"));
     679             :                 return;
     680             :         }
     681             : 
     682           2 :         st->tr_state->vrml_sensors = gf_list_new();
     683             : 
     684           2 :         st->sensors = gf_list_new();
     685           2 :         st->previous_sensors = gf_list_new();
     686           2 :         gf_sc_texture_setup(&st->txh, compositor, node);
     687             :         /*remove texture from compositor and add it at the end, so that any sub-textures are handled before*/
     688           2 :         gf_list_del_item(compositor->textures, &st->txh);
     689           2 :         gf_list_add(compositor->textures, &st->txh);
     690             : 
     691           2 :         st->txh.update_texture_fcnt = composite_update;
     692             : 
     693           2 :         if (c3d->repeatS) st->txh.flags |= GF_SR_TEXTURE_REPEAT_S;
     694           2 :         if (c3d->repeatT) st->txh.flags |= GF_SR_TEXTURE_REPEAT_T;
     695             : 
     696             :         /*create composite visual*/
     697           2 :         st->visual = visual_new(compositor);
     698           2 :         st->visual->offscreen = node;
     699           2 :         st->visual->GetSurfaceAccess = composite_get_video_access;
     700           2 :         st->visual->ReleaseSurfaceAccess = composite_release_video_access;
     701           2 :         st->visual->CheckAttached = composite_check_visual_attached;
     702             : 
     703           2 :         st->visual->camera.is_3D = 1;
     704           2 :         st->first = 1;
     705           2 :         st->visual->compositor = compositor;
     706           2 :         gf_node_set_private(node, st);
     707           2 :         gf_node_set_callback_function(node, composite_traverse);
     708           2 :         gf_sc_visual_register(compositor, st->visual);
     709             : 
     710           2 :         camera_invalidate(&st->visual->camera);
     711             : }
     712             : #endif
     713             : 
     714        3307 : GF_TextureHandler *compositor_get_composite_texture(GF_Node *node)
     715             : {
     716        3307 :         CompositeTextureStack *st = (CompositeTextureStack*) gf_node_get_private(node);
     717        3307 :         return &st->txh;
     718             : }
     719             : 
     720          70 : Bool compositor_compositetexture_handle_event(GF_Compositor *compositor, GF_Node *composite_appear, GF_Event *ev, Bool is_flush)
     721             : {
     722             :         GF_Ray ray;
     723             :         Fixed dist;
     724             :         Bool had_text_sel=0;
     725             :         GF_Matrix mx;
     726             :         GF_ChildNodeItem *children, *l;
     727             :         Bool res;
     728             :         SFVec3f txcoord, loc_pt, world_pt;
     729             :         GF_Matrix l2w_mx, w2l_mx;
     730             :         CompositeTextureStack *stack;
     731             :         GF_Node *appear, *prev_appear;
     732             :         GF_List *sensor_bck;
     733             :         M_Appearance *ap = (M_Appearance *)composite_appear;
     734             :         assert(ap && ap->texture);
     735             : 
     736          70 :         if (ev->type > GF_EVENT_MOUSEMOVE) return 0;
     737          70 :         stack = gf_node_get_private(ap->texture);
     738          70 :         if (!stack->txh.tx_io) return 0;
     739             : 
     740             :         children = NULL;
     741             : 
     742             : 
     743          70 :         if (!is_flush) {
     744          68 :                 txcoord.x = compositor->hit_texcoords.x;
     745          68 :                 txcoord.y = compositor->hit_texcoords.y;
     746          68 :                 txcoord.z = 0;
     747          68 :                 if (gf_sc_texture_get_transform(&stack->txh, ap->textureTransform, &mx, 1)) {
     748             :                         /*tx coords are inverted when mapping, thus applying directly the matrix will give us the
     749             :                         untransformed coords*/
     750          50 :                         gf_mx_apply_vec(&mx, &txcoord);
     751          50 :                         while (txcoord.x<0) txcoord.x += FIX_ONE;
     752         177 :                         while (txcoord.x>FIX_ONE) txcoord.x -= FIX_ONE;
     753           0 :                         while (txcoord.y<0) txcoord.y += FIX_ONE;
     754          64 :                         while (txcoord.y>FIX_ONE) txcoord.y -= FIX_ONE;
     755             :                 }
     756             : 
     757             :                 /*convert to tx space*/
     758          68 :                 ev->mouse.x = FIX2INT( (txcoord.x - FIX_ONE/2) * stack->visual->width + FIX_ONE/2);
     759          68 :                 ev->mouse.y = FIX2INT( (txcoord.y - FIX_ONE/2) * stack->visual->height + FIX_ONE/2);
     760             : 
     761          68 :                 sensor_bck = stack->tr_state->vrml_sensors;
     762             :                 memset(stack->tr_state, 0, sizeof(GF_TraverseState));
     763          68 :                 stack->tr_state->vrml_sensors = sensor_bck;
     764             : 
     765          68 :                 stack->tr_state->visual = stack->visual;
     766          68 :                 stack->tr_state->traversing_mode = TRAVERSE_PICK;
     767          68 :                 stack->tr_state->pixel_metrics = gf_sg_use_pixel_metrics(gf_node_get_graph(ap->texture));
     768          68 :                 stack->tr_state->vp_size.x = INT2FIX(stack->txh.width);
     769          68 :                 stack->tr_state->vp_size.y = INT2FIX(stack->txh.height);
     770          68 :                 stack->tr_state->color_mat.identity = 1;
     771             : 
     772         136 :                 gf_mx2d_init(stack->tr_state->transform);
     773             : #ifndef GPAC_DISABLE_3D
     774         136 :                 gf_mx_init(stack->tr_state->model_matrix);
     775             : #endif
     776             :                 /*collect sensors but not anchors*/
     777          68 :                 l = children = ((M_CompositeTexture2D*)ap->texture)->children;
     778         350 :                 while (l) {
     779         214 :                         GF_SensorHandler *hsens = compositor_mpeg4_get_sensor_handler_ex(l->node, GF_TRUE);
     780         214 :                         if (hsens) gf_list_add(stack->tr_state->vrml_sensors, hsens);
     781         214 :                         l = l->next;
     782             :                 }
     783             :         }
     784             : 
     785          70 :         stack->temp_sensors = compositor->sensors;
     786          70 :         stack->temp_previous_sensors = compositor->previous_sensors;
     787          70 :         compositor->sensors = stack->sensors;
     788          70 :         compositor->previous_sensors = stack->previous_sensors;
     789             : 
     790          70 :         ray = compositor->hit_world_ray;
     791          70 :         dist = compositor->hit_square_dist;
     792          70 :         prev_appear = compositor->prev_hit_appear;
     793             : 
     794             :         /*protect against destrucion in case of self-destroy*/
     795          70 :         if (prev_appear) {
     796          65 :                 gf_node_register(prev_appear, NULL);
     797             :         }
     798          70 :         compositor->prev_hit_appear = stack->prev_hit_appear;
     799          70 :         appear = compositor->hit_appear;
     800          70 :         compositor->hit_appear = NULL;
     801             : 
     802             :         /*also backup current hit state in case we hit a node in the texture but don't consume the event*/
     803          70 :         loc_pt = compositor->hit_local_point;
     804          70 :         world_pt = compositor->hit_world_point;
     805          70 :         gf_mx_copy(l2w_mx, compositor->hit_local_to_world);
     806          70 :         gf_mx_copy(w2l_mx, compositor->hit_world_to_local);
     807             : 
     808          70 :         if (compositor->text_selection) had_text_sel=1;
     809             : 
     810          70 :         if (is_flush) {
     811             :                 res = 0;
     812           2 :                 gf_list_reset(stack->sensors);
     813           2 :                 gf_sc_exec_event_vrml(compositor, ev);
     814             :         } else {
     815          68 :                 res = visual_execute_event(stack->visual, stack->tr_state, ev, children);
     816             :         }
     817             : 
     818          70 :         if (!had_text_sel && compositor->edited_text) {
     819           0 :                 stack->visual->has_text_edit = 1;
     820          70 :         } else if (!compositor->text_selection) {
     821          70 :                 stack->visual->has_text_edit = 0;
     822             :         }
     823             : 
     824          70 :         if (!res) {
     825          13 :                 compositor->hit_local_point = loc_pt;
     826             :                 gf_mx_copy(compositor->hit_local_to_world, l2w_mx);
     827             :                 gf_mx_copy(compositor->hit_world_to_local, w2l_mx);
     828             :         }
     829             : 
     830          70 :         compositor->hit_world_point = world_pt;
     831          70 :         compositor->hit_world_ray = ray;
     832          70 :         compositor->hit_square_dist = dist;
     833             : 
     834          70 :         stack->sensors = compositor->sensors;
     835          70 :         stack->previous_sensors = compositor->previous_sensors;
     836          70 :         compositor->sensors = stack->temp_sensors;
     837          70 :         stack->temp_sensors = NULL;
     838          70 :         compositor->previous_sensors = stack->temp_previous_sensors;
     839          70 :         stack->temp_previous_sensors = NULL;
     840             : 
     841             : 
     842          70 :         if (!is_flush) {
     843             : #ifndef GPAC_DISABLE_3D
     844          68 :                 if (stack->tr_state->layer3d) compositor->traverse_state->layer3d = stack->tr_state->layer3d;
     845             : #endif
     846             :         }
     847             : 
     848          70 :         stack->prev_hit_appear = compositor->prev_hit_appear;
     849             : 
     850             :         //finally unregister the node, this may destroy the stack !
     851          70 :         if (prev_appear) {
     852          65 :                 if (prev_appear->sgprivate->num_instances>1) {
     853          65 :                         compositor->prev_hit_appear = prev_appear;
     854          65 :                         compositor->hit_appear = appear;
     855             :                 } else {
     856           0 :                         compositor->prev_hit_appear = NULL;
     857           0 :                         compositor->hit_appear = NULL;
     858             :                 }
     859          65 :                 gf_node_unregister(prev_appear, NULL);
     860             :         } else {
     861           5 :                 compositor->prev_hit_appear = prev_appear;
     862           5 :                 compositor->hit_appear = appear;
     863             :         }
     864             : 
     865             :         return res;
     866             : }
     867             : 
     868         170 : void compositor_compositetexture_sensor_delete(GF_Node *composite_appear, GF_SensorHandler *hdl)
     869             : {
     870         170 :         CompositeTextureStack *stack = gf_node_get_private(composite_appear);
     871         170 :         gf_list_del_item(stack->previous_sensors, hdl);
     872         170 :         gf_list_del_item(stack->sensors, hdl);
     873         170 :         if (stack->temp_sensors)
     874           0 :                 gf_list_del_item(stack->temp_sensors, hdl);
     875         170 :         if (stack->temp_previous_sensors)
     876           0 :                 gf_list_del_item(stack->temp_previous_sensors, hdl);
     877         170 : }
     878             : 
     879             : 
     880         485 : void compositor_adjust_scale(GF_Node *node, Fixed *sx, Fixed *sy)
     881             : {
     882         485 :         switch (gf_node_get_tag(node)) {
     883           7 :         case TAG_MPEG4_CompositeTexture2D:
     884             :         case TAG_MPEG4_CompositeTexture3D:
     885             :         {
     886           7 :                 CompositeTextureStack *st = (CompositeTextureStack *) gf_node_get_private(node);
     887           7 :                 (*sx) = gf_divfix(*sx, st->sx);
     888           7 :                 (*sy) = gf_divfix(*sy, st->sy);
     889           7 :                 break;
     890             :         }
     891             :         default:
     892             :                 return;
     893             :         }
     894             : }
     895             : 
     896        2787 : Bool compositor_is_composite_texture(GF_Node *appear)
     897             : {
     898             :         M_Appearance *ap = NULL;
     899             :         u32 tag;
     900        2787 :         if (!appear) return 0;
     901             : 
     902        2785 :         tag = gf_node_get_tag(appear);
     903        2785 :         if (tag==TAG_MPEG4_Appearance) ap = (M_Appearance *)appear;
     904             : #ifndef GPAC_DISABLE_X3D
     905           6 :         else if (tag==TAG_X3D_Appearance) ap = (M_Appearance *)appear;
     906             : #endif
     907             :         if (!ap) return 0;
     908        2785 :         if (!ap->texture) return 0;
     909         897 :         switch (gf_node_get_tag(((M_Appearance *)appear)->texture)) {
     910             :         case TAG_MPEG4_CompositeTexture2D:
     911             :         case TAG_MPEG4_CompositeTexture3D:
     912             :                 return 1;
     913             :         }
     914         829 :         return 0;
     915             : }
     916             : 
     917             : #endif /*GPAC_DISABLE_VRML*/

Generated by: LCOV version 1.13