LCOV - code coverage report
Current view: top level - compositor - mpeg4_gradients.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 264 354 74.6 %
Date: 2021-04-29 23:48:07 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2012
       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             : #include "nodes_stacks.h"
      27             : #include "texturing.h"
      28             : 
      29             : #ifndef GPAC_DISABLE_VRML
      30             : 
      31             : 
      32             : #define GRAD_TEXTURE_SIZE       128
      33             : #define GRAD_TEXTURE_HSIZE      64
      34             : 
      35             : enum
      36             : {
      37             :         GF_SR_TEXTURE_GRAD_REGISTERED = 1<<6,
      38             :         GF_SR_TEXTURE_GRAD_NO_RGB = 1<<7,
      39             : };
      40             : 
      41             : /*linear/radial gradient*/
      42             : typedef struct
      43             : {
      44             :         GF_TextureHandler txh;
      45             :         char *tx_data;
      46             : //      Bool no_rgb_support;
      47             : } GradientStack;
      48             : 
      49       11798 : void GradientGetMatrix(GF_Node *transform, GF_Matrix2D *mat)
      50             : {
      51       23596 :         gf_mx2d_init(*mat);
      52       11798 :         if (transform) {
      53           0 :                 switch (gf_node_get_tag(transform) ) {
      54           0 :                 case TAG_MPEG4_Transform2D:
      55             :                 {
      56             :                         M_Transform2D *tr = (M_Transform2D *)transform;
      57           0 :                         gf_mx2d_add_scale_at(mat, 0, 0, tr->scale.x, tr->scale.y, tr->scaleOrientation);
      58           0 :                         gf_mx2d_add_rotation(mat, tr->center.x, tr->center.y, tr->rotationAngle);
      59           0 :                         gf_mx2d_add_translation(mat, tr->translation.x, tr->translation.y);
      60             :                 }
      61           0 :                 break;
      62           0 :                 case TAG_MPEG4_TransformMatrix2D:
      63             :                 {
      64             :                         M_TransformMatrix2D *tm = (M_TransformMatrix2D*)transform;
      65           0 :                         gf_mx2d_init(*mat);
      66           0 :                         mat->m[0] = tm->mxx;
      67           0 :                         mat->m[1] = tm->mxy;
      68           0 :                         mat->m[2] = tm->tx;
      69           0 :                         mat->m[3] = tm->myx;
      70           0 :                         mat->m[4] = tm->myy;
      71           0 :                         mat->m[5] = tm->ty;
      72             :                 }
      73           0 :                 break;
      74             :                 default:
      75             :                         break;
      76             :                 }
      77       11798 :         }
      78       11798 : }
      79             : 
      80         508 : static void DestroyGradient(GF_Node *node, void *rs, Bool is_destroy)
      81             : {
      82         508 :         if (is_destroy) {
      83         508 :                 GradientStack *st = (GradientStack *) gf_node_get_private(node);
      84         508 :                 gf_sc_texture_destroy(&st->txh);
      85         508 :                 if (st->tx_data) gf_free(st->tx_data);
      86         508 :                 gf_free(st);
      87             :         }
      88         508 : }
      89             : 
      90        3226 : static void UpdateLinearGradient(GF_TextureHandler *txh)
      91             : {
      92             :         u32 i, *cols;
      93             :         Fixed a;
      94             :         Bool const_a;
      95             :         GF_EVGStencil *stencil;
      96        3226 :         M_LinearGradient *lg = (M_LinearGradient *) txh->owner;
      97        3226 :         GradientStack *st = (GradientStack *) gf_node_get_private(txh->owner);
      98             : 
      99        3226 :         if (!gf_node_dirty_get(txh->owner)) {
     100        2075 :                 txh->needs_refresh = 0;
     101        2075 :                 return;
     102             :         }
     103        1151 :         if (lg->key.count > lg->keyValue.count) return;
     104             : 
     105        1151 :         if (!txh->tx_io) {
     106          57 :                 gf_node_dirty_set(gf_node_get_parent(txh->owner, 0), 0, 1);
     107          57 :                 gf_node_dirty_set(txh->owner, 0, 1);
     108          57 :                 gf_sc_texture_allocate(txh);
     109             :         }
     110             : 
     111        1151 :         stencil = gf_sc_texture_get_stencil(txh);
     112        1151 :         if (!stencil) stencil = gf_evg_stencil_new(GF_STENCIL_LINEAR_GRADIENT);
     113             :         /*set stencil even if assigned, this invalidates the associated bitmap state in 3D*/
     114        1151 :         gf_sc_texture_set_stencil(txh, stencil);
     115             : 
     116        1151 :         gf_node_dirty_clear(txh->owner, 0);
     117        1151 :         txh->needs_refresh = 1;
     118             : 
     119        1151 :         st->txh.transparent = 0;
     120        1151 :         const_a = (lg->opacity.count == 1) ? 1 : 0;
     121        1151 :         cols = (u32*)gf_malloc(sizeof(u32) * lg->key.count);
     122        4714 :         for (i=0; i<lg->key.count; i++) {
     123        3563 :                 a = (const_a ? lg->opacity.vals[0] : lg->opacity.vals[i]);
     124        3563 :                 cols[i] = GF_COL_ARGB_FIXED(a, lg->keyValue.vals[i].red, lg->keyValue.vals[i].green, lg->keyValue.vals[i].blue);
     125        3563 :                 if (a != FIX_ONE) txh->transparent = 1;
     126             :         }
     127        1151 :         gf_evg_stencil_set_gradient_interpolation(stencil, lg->key.vals, cols, lg->key.count);
     128        1151 :         gf_free(cols);
     129        1151 :         gf_evg_stencil_set_gradient_mode(stencil, (GF_GradientMode) lg->spreadMethod);
     130             : }
     131             : 
     132             : 
     133        1459 : static void LG_ComputeMatrix(GF_TextureHandler *txh, GF_Rect *bounds, GF_Matrix2D *mat, Bool for_3d)
     134             : {
     135             :         GF_EVGStencil *stencil;
     136        1459 :         M_LinearGradient *lg = (M_LinearGradient *) txh->owner;
     137             : 
     138        1459 :         stencil = gf_sc_texture_get_stencil(txh);
     139        1459 :         if (!stencil) return;
     140             : 
     141        1459 :         if (lg->key.count<2) return;
     142        1459 :         if (lg->key.count != lg->keyValue.count) return;
     143             : 
     144             :         /*create gradient brush if needed*/
     145        1459 :         if (!txh->tx_io) return;
     146             : 
     147        1459 :         GradientGetMatrix((GF_Node *) lg->transform, mat);
     148             : 
     149             :         /*translate to the center of the bounds*/
     150        1459 :         gf_mx2d_add_translation(mat, gf_divfix(bounds->x, bounds->width), gf_divfix(bounds->y - bounds->height, bounds->height));
     151             :         /*scale back to object coordinates - the gradient is still specified in texture coordinates
     152             :         i order to avoid overflows in fixed point*/
     153        1459 :         gf_mx2d_add_scale(mat, bounds->width, bounds->height);
     154             : 
     155        1459 :         gf_evg_stencil_set_linear_gradient(stencil, lg->startPoint.x, lg->startPoint.y, lg->endPoint.x, lg->endPoint.y);
     156             : }
     157             : 
     158             : //TODO - replace this with shader-based code ...
     159             : 
     160         314 : static void BuildLinearGradientTexture(GF_TextureHandler *txh)
     161             : {
     162             :         u32 i;
     163             :         SFVec2f start, end;
     164             :         u32 *cols;
     165             :         Fixed a;
     166             :         Bool const_a;
     167             :         GF_Matrix2D mat;
     168             :         GF_EVGStencil * stenc;
     169             :         GF_EVGSurface *surface;
     170             :         GF_EVGStencil * texture2D;
     171             :         GF_Path *path;
     172             :         GF_Err e;
     173             :         Bool transparent;
     174             :         u32 pix_fmt = 0;
     175         314 :         M_LinearGradient *lg = (M_LinearGradient *) txh->owner;
     176         314 :         GradientStack *st = (GradientStack *) gf_node_get_private(txh->owner);
     177             : 
     178         314 :         if (!txh->tx_io) return;
     179             : 
     180         314 :         if (!(txh->flags & GF_SR_TEXTURE_GRAD_REGISTERED)) {
     181           8 :                 txh->flags |= GF_SR_TEXTURE_GRAD_REGISTERED;
     182           8 :                 if (gf_list_find(txh->compositor->textures, txh)<0)
     183           8 :                         gf_list_insert(txh->compositor->textures, txh, 0);
     184             :         }
     185             : 
     186         314 :         if (lg->key.count<2) return;
     187         314 :         if (lg->key.count != lg->keyValue.count) return;
     188             : 
     189         314 :         start = lg->startPoint;
     190         314 :         end = lg->endPoint;
     191             : 
     192         314 :         transparent = (lg->opacity.count==1) ? (lg->opacity.vals[0]!=FIX_ONE) : 1;
     193             : 
     194             :         /*init our 2D graphics stuff*/
     195         314 :         texture2D = gf_evg_stencil_new(GF_STENCIL_TEXTURE);
     196         314 :         if (!texture2D) return;
     197         314 :         surface = gf_evg_surface_new(1);
     198         314 :         if (!surface) {
     199           0 :                 gf_evg_stencil_delete(texture2D);
     200           0 :                 return;
     201             :         }
     202             : 
     203         314 :         if (st->txh.flags & GF_SR_TEXTURE_GRAD_NO_RGB) transparent = 1;
     204             : 
     205         314 :         if (st->tx_data && (st->txh.transparent != transparent)) {
     206           0 :                 gf_free(st->tx_data);
     207           0 :                 st->tx_data = NULL;
     208             :         }
     209             : 
     210         314 :         if (transparent) {
     211           0 :                 if (!st->tx_data) {
     212           0 :                         st->tx_data = (char *) gf_malloc(sizeof(char)*GRAD_TEXTURE_SIZE*GRAD_TEXTURE_SIZE*4);
     213             :                 }
     214           0 :                 memset(st->tx_data, 0, sizeof(char)*txh->stride*txh->height);
     215             : 
     216             :                 pix_fmt = GF_PIXEL_RGBA;
     217           0 :                 e = gf_evg_stencil_set_texture(texture2D, st->tx_data, GRAD_TEXTURE_SIZE, GRAD_TEXTURE_SIZE, 4*GRAD_TEXTURE_SIZE, pix_fmt);
     218           0 :                 if (e) {
     219             :                         pix_fmt = GF_PIXEL_ARGB;
     220           0 :                         e = gf_evg_stencil_set_texture(texture2D, st->tx_data, GRAD_TEXTURE_SIZE, GRAD_TEXTURE_SIZE, 4*GRAD_TEXTURE_SIZE, pix_fmt);
     221             :                 }
     222             :         } else {
     223         314 :                 if (!st->tx_data) {
     224           8 :                         st->tx_data = (char *) gf_malloc(sizeof(char)*GRAD_TEXTURE_SIZE*GRAD_TEXTURE_SIZE*3);
     225             :                 }
     226         314 :                 e = gf_evg_stencil_set_texture(texture2D, st->tx_data, GRAD_TEXTURE_SIZE, GRAD_TEXTURE_SIZE, 3*GRAD_TEXTURE_SIZE, GF_PIXEL_RGB);
     227             :                 /*try with ARGB (it actually is needed for GDIplus module since GDIplus cannot handle native RGB texture (it works in BGR)*/
     228         314 :                 if (e) {
     229             :                         /*remember for later use*/
     230           0 :                         st->txh.flags |= GF_SR_TEXTURE_GRAD_NO_RGB;
     231             :                         transparent = 1;
     232           0 :                         gf_free(st->tx_data);
     233           0 :                         st->tx_data = (char *) gf_malloc(sizeof(char)*GRAD_TEXTURE_SIZE*GRAD_TEXTURE_SIZE*4);
     234           0 :                         e = gf_evg_stencil_set_texture(texture2D, st->tx_data, GRAD_TEXTURE_SIZE, GRAD_TEXTURE_SIZE, 4*GRAD_TEXTURE_SIZE, GF_PIXEL_ARGB);
     235             :                 }
     236             :         }
     237         314 :         st->txh.transparent = transparent;
     238             : 
     239         314 :         if (e) {
     240           0 :                 gf_free(st->tx_data);
     241           0 :                 gf_evg_stencil_delete(texture2D);
     242           0 :                 gf_evg_surface_delete(surface);
     243           0 :                 return;
     244             :         }
     245         314 :         e = gf_evg_surface_attach_to_texture(surface, texture2D);
     246         314 :         if (e) {
     247           0 :                 gf_evg_stencil_delete(texture2D);
     248           0 :                 gf_evg_surface_delete(surface);
     249           0 :                 return;
     250             :         }
     251             : 
     252             :         /*create & setup gradient*/
     253         314 :         stenc = gf_evg_stencil_new(GF_STENCIL_LINEAR_GRADIENT);
     254         314 :         if (!stenc) {
     255           0 :                 gf_evg_stencil_delete(texture2D);
     256           0 :                 gf_evg_surface_delete(surface);
     257           0 :                 return;
     258             :         }
     259             :         /*move line to object space*/
     260         314 :         start.x *= GRAD_TEXTURE_SIZE;
     261         314 :         end.x *= GRAD_TEXTURE_SIZE;
     262         314 :         start.y *= GRAD_TEXTURE_SIZE;
     263         314 :         end.y *= GRAD_TEXTURE_SIZE;
     264         314 :         gf_evg_stencil_set_linear_gradient(stenc, start.x, start.y, end.x, end.y);
     265         314 :         const_a = (lg->opacity.count == 1) ? 1 : 0;
     266         314 :         cols = (u32*)gf_malloc(sizeof(u32) * lg->key.count);
     267        1280 :         for (i=0; i<lg->key.count; i++) {
     268         966 :                 a = (const_a ? lg->opacity.vals[0] : lg->opacity.vals[i]);
     269         966 :                 cols[i] = GF_COL_ARGB_FIXED(a, lg->keyValue.vals[i].red, lg->keyValue.vals[i].green, lg->keyValue.vals[i].blue);
     270             :         }
     271         314 :         gf_evg_stencil_set_gradient_interpolation(stenc, lg->key.vals, cols, lg->key.count);
     272         314 :         gf_free(cols);
     273         314 :         gf_evg_stencil_set_gradient_mode(stenc, (GF_GradientMode)lg->spreadMethod);
     274             : 
     275             :         /*fill surface*/
     276         314 :         path = gf_path_new();
     277         314 :         gf_path_add_move_to(path, -INT2FIX(GRAD_TEXTURE_HSIZE), -INT2FIX(GRAD_TEXTURE_HSIZE));
     278         314 :         gf_path_add_line_to(path, INT2FIX(GRAD_TEXTURE_HSIZE), -INT2FIX(GRAD_TEXTURE_HSIZE));
     279         314 :         gf_path_add_line_to(path, INT2FIX(GRAD_TEXTURE_HSIZE), INT2FIX(GRAD_TEXTURE_HSIZE));
     280         314 :         gf_path_add_line_to(path, -INT2FIX(GRAD_TEXTURE_HSIZE), INT2FIX(GRAD_TEXTURE_HSIZE));
     281         314 :         gf_path_close(path);
     282             : 
     283             :         /*add gradient transform*/
     284         314 :         GradientGetMatrix(lg->transform, &mat);
     285             : 
     286             :         /*move transform to object space*/
     287         314 :         mat.m[2] *= GRAD_TEXTURE_SIZE;
     288         314 :         mat.m[5] *= GRAD_TEXTURE_SIZE;
     289             :         /*translate to the center of the bounds*/
     290         314 :         gf_mx2d_add_translation(&mat, -INT2FIX(GRAD_TEXTURE_HSIZE), -INT2FIX(GRAD_TEXTURE_HSIZE));
     291             :         /*back to GL bottom->up order*/
     292         314 :         gf_mx2d_add_scale(&mat, FIX_ONE, -FIX_ONE);
     293         314 :         gf_evg_stencil_set_matrix(stenc, &mat);
     294             : 
     295         314 :         gf_evg_surface_set_raster_level(surface, GF_RASTER_HIGH_QUALITY);
     296         314 :         gf_evg_surface_set_path(surface, path);
     297         314 :         gf_evg_surface_fill(surface, stenc);
     298         314 :         gf_evg_stencil_delete(stenc);
     299         314 :         gf_evg_surface_delete(surface);
     300         314 :         gf_evg_stencil_delete(texture2D);
     301         314 :         gf_path_del(path);
     302             : 
     303         314 :         txh->data = st->tx_data;
     304         314 :         txh->width = GRAD_TEXTURE_SIZE;
     305         314 :         txh->height = GRAD_TEXTURE_SIZE;
     306         314 :         txh->transparent = transparent;
     307         314 :         if (transparent) {
     308             :                 u32 j;
     309           0 :                 txh->stride = GRAD_TEXTURE_SIZE*4;
     310           0 :                 txh->pixelformat = GF_PIXEL_RGBA;
     311             : 
     312             :                 /*back to RGBA texturing*/
     313           0 :                 if (pix_fmt != GF_PIXEL_RGBA) {
     314           0 :                         for (i=0; i<txh->height; i++) {
     315           0 :                                 char *data = txh->data + i*txh->stride;
     316           0 :                                 for (j=0; j<txh->width; j++) {
     317           0 :                                         u32 val = *(u32 *) &data[4*j];
     318           0 :                                         data[4*j] = (val>>16) & 0xFF;
     319           0 :                                         data[4*j+1] = (val>>8) & 0xFF;
     320           0 :                                         data[4*j+2] = (val) & 0xFF;
     321           0 :                                         data[4*j+3] = (val>>24) & 0xFF;
     322             :                                 }
     323             :                         }
     324             :                 }
     325             :         } else {
     326         314 :                 txh->stride = GRAD_TEXTURE_SIZE*3;
     327         314 :                 txh->pixelformat = GF_PIXEL_RGB;
     328             :         }
     329         314 :         txh->flags |= GF_SR_TEXTURE_NO_GL_FLIP;
     330         314 :         gf_sc_texture_set_data(txh);
     331             : }
     332             : 
     333          74 : void compositor_init_linear_gradient(GF_Compositor *compositor, GF_Node *node)
     334             : {
     335             :         GradientStack *st;
     336          74 :         GF_SAFEALLOC(st, GradientStack);
     337          74 :         if (!st) {
     338           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate gradient stack\n"));
     339             :                 return;
     340             :         }
     341             : 
     342             :         /*!!! Gradients are textures but are not registered as textures with the compositor in order to avoid updating
     343             :         too many textures each frame - gradients are only registered with the compositor when they are used in OpenGL, in order
     344             :         to release associated HW resource when no longer used*/
     345          74 :         st->txh.owner = node;
     346          74 :         st->txh.compositor = compositor;
     347          74 :         st->txh.update_texture_fcnt = UpdateLinearGradient;
     348          74 :         st->txh.compute_gradient_matrix = LG_ComputeMatrix;
     349             : 
     350          74 :         gf_node_set_private(node, st);
     351          74 :         gf_node_set_callback_function(node, DestroyGradient);
     352             : }
     353             : 
     354             : 
     355           2 : static void BuildRadialGradientTexture(GF_TextureHandler *txh)
     356             : {
     357             :         u32 i;
     358             :         SFVec2f center, focal;
     359             :         u32 *cols;
     360             :         Fixed a, radius;
     361             :         Bool const_a;
     362             :         GF_Matrix2D mat;
     363             :         GF_EVGStencil * stenc;
     364             :         GF_EVGSurface *surface;
     365             :         GF_EVGStencil * texture2D;
     366             :         GF_Path *path;
     367             :         GF_Err e;
     368             :         u32 pix_fmt = 0;
     369             :         Bool transparent;
     370           2 :         M_RadialGradient *rg = (M_RadialGradient*) txh->owner;
     371           2 :         GradientStack *st = (GradientStack *) gf_node_get_private(txh->owner);
     372             : 
     373           2 :         if (!txh->tx_io) return;
     374             : 
     375           2 :         if (!(txh->flags & GF_SR_TEXTURE_GRAD_REGISTERED)) {
     376           1 :                 txh->flags |= GF_SR_TEXTURE_GRAD_REGISTERED;
     377           1 :                 if (gf_list_find(txh->compositor->textures, txh)<0)
     378           1 :                         gf_list_insert(txh->compositor->textures, txh, 0);
     379             :         }
     380             : 
     381           2 :         if (rg->key.count<2) return;
     382           2 :         if (rg->key.count != rg->keyValue.count) return;
     383             : 
     384           2 :         transparent = (rg->opacity.count==1) ? ((rg->opacity.vals[0]!=FIX_ONE) ? 1 : 0) : 1;
     385             : 
     386             :         /*init our 2D graphics stuff*/
     387           2 :         texture2D = gf_evg_stencil_new(GF_STENCIL_TEXTURE);
     388           2 :         if (!texture2D) return;
     389           2 :         surface = gf_evg_surface_new(1);
     390           2 :         if (!surface) {
     391           0 :                 gf_evg_stencil_delete(texture2D);
     392           0 :                 return;
     393             :         }
     394             : 
     395           2 :         if (st->txh.flags & GF_SR_TEXTURE_GRAD_NO_RGB) transparent = 1;
     396             : 
     397           2 :         if (st->tx_data && (st->txh.transparent != transparent)) {
     398           0 :                 gf_free(st->tx_data);
     399           0 :                 st->tx_data = NULL;
     400             :         }
     401             : 
     402           2 :         if (transparent) {
     403           2 :                 if (!st->tx_data) {
     404           1 :                         st->tx_data = (char *) gf_malloc(sizeof(char)*GRAD_TEXTURE_SIZE*GRAD_TEXTURE_SIZE*4);
     405             :                 }
     406           2 :                 memset(st->tx_data, 0, sizeof(char)*txh->stride*txh->height);
     407             : 
     408             :                 pix_fmt = GF_PIXEL_RGBA;
     409             : 
     410           2 :                 e = gf_evg_stencil_set_texture(texture2D, st->tx_data, GRAD_TEXTURE_SIZE, GRAD_TEXTURE_SIZE, 4*GRAD_TEXTURE_SIZE, pix_fmt);
     411             : 
     412           2 :                 if (e) {
     413             :                         pix_fmt = GF_PIXEL_ARGB;
     414           0 :                         e = gf_evg_stencil_set_texture(texture2D, st->tx_data, GRAD_TEXTURE_SIZE, GRAD_TEXTURE_SIZE, 4*GRAD_TEXTURE_SIZE, pix_fmt);
     415             :                 }
     416             :         } else {
     417           0 :                 if (!st->tx_data) {
     418           0 :                         st->tx_data = (char *) gf_malloc(sizeof(char)*GRAD_TEXTURE_SIZE*GRAD_TEXTURE_SIZE*3);
     419             :                 }
     420           0 :                 e = gf_evg_stencil_set_texture(texture2D, st->tx_data, GRAD_TEXTURE_SIZE, GRAD_TEXTURE_SIZE, 3*GRAD_TEXTURE_SIZE, GF_PIXEL_RGB);
     421             :                 /*try with ARGB (it actually is needed for GDIplus module since GDIplus cannot handle native RGB texture (it works in BGR)*/
     422           0 :                 if (e) {
     423             :                         /*remember for later use*/
     424           0 :                         st->txh.flags |= GF_SR_TEXTURE_GRAD_NO_RGB;
     425             :                         transparent = 1;
     426           0 :                         gf_free(st->tx_data);
     427           0 :                         st->tx_data = (char *) gf_malloc(sizeof(char)*GRAD_TEXTURE_SIZE*GRAD_TEXTURE_SIZE*4);
     428           0 :                         e = gf_evg_stencil_set_texture(texture2D, st->tx_data, GRAD_TEXTURE_SIZE, GRAD_TEXTURE_SIZE, 4*GRAD_TEXTURE_SIZE, GF_PIXEL_ARGB);
     429             :                 }
     430             :         }
     431           2 :         st->txh.transparent = transparent;
     432             : 
     433           2 :         if (e) {
     434           0 :                 gf_free(st->tx_data);
     435           0 :                 gf_evg_stencil_delete(texture2D);
     436           0 :                 gf_evg_surface_delete(surface);
     437           0 :                 return;
     438             :         }
     439           2 :         e = gf_evg_surface_attach_to_texture(surface, texture2D);
     440           2 :         if (e) {
     441           0 :                 gf_evg_stencil_delete(texture2D);
     442           0 :                 gf_evg_surface_delete(surface);
     443           0 :                 return;
     444             :         }
     445             : 
     446             :         /*create & setup gradient*/
     447           2 :         stenc = gf_evg_stencil_new(GF_STENCIL_RADIAL_GRADIENT);
     448           2 :         if (!stenc) {
     449           0 :                 gf_evg_stencil_delete(texture2D);
     450           0 :                 gf_evg_surface_delete(surface);
     451             :         }
     452             : 
     453           2 :         center = rg->center;
     454           2 :         focal = rg->focalPoint;
     455           2 :         radius = rg->radius;
     456             : 
     457             :         /*move circle to object space*/
     458           2 :         center.x *= GRAD_TEXTURE_SIZE;
     459           2 :         center.y *= GRAD_TEXTURE_SIZE;
     460           2 :         focal.x *= GRAD_TEXTURE_SIZE;
     461           2 :         focal.y *= GRAD_TEXTURE_SIZE;
     462           2 :         radius *= GRAD_TEXTURE_SIZE;
     463             : 
     464           2 :         gf_evg_stencil_set_radial_gradient(stenc, center.x, center.y, focal.x, focal.y, radius, radius);
     465             : 
     466           2 :         const_a = (rg->opacity.count == 1) ? 1 : 0;
     467           2 :         cols = (u32*) gf_malloc(sizeof(u32) * rg->key.count);
     468           8 :         for (i=0; i<rg->key.count; i++) {
     469           6 :                 a = (const_a ? rg->opacity.vals[0] : rg->opacity.vals[i]);
     470           6 :                 cols[i] = GF_COL_ARGB_FIXED(a, rg->keyValue.vals[i].red, rg->keyValue.vals[i].green, rg->keyValue.vals[i].blue);
     471             :         }
     472           2 :         gf_evg_stencil_set_gradient_interpolation(stenc, rg->key.vals, cols, rg->key.count);
     473           2 :         gf_free(cols);
     474           2 :         gf_evg_stencil_set_gradient_mode(stenc, (GF_GradientMode)rg->spreadMethod);
     475             : 
     476             :         /*fill surface*/
     477           2 :         path = gf_path_new();
     478           2 :         gf_path_add_move_to(path, -INT2FIX(GRAD_TEXTURE_HSIZE), -INT2FIX(GRAD_TEXTURE_HSIZE));
     479           2 :         gf_path_add_line_to(path, INT2FIX(GRAD_TEXTURE_HSIZE), -INT2FIX(GRAD_TEXTURE_HSIZE));
     480           2 :         gf_path_add_line_to(path, INT2FIX(GRAD_TEXTURE_HSIZE), INT2FIX(GRAD_TEXTURE_HSIZE));
     481           2 :         gf_path_add_line_to(path, -INT2FIX(GRAD_TEXTURE_HSIZE), INT2FIX(GRAD_TEXTURE_HSIZE));
     482           2 :         gf_path_close(path);
     483             : 
     484             :         /*add gradient transform*/
     485           2 :         GradientGetMatrix(rg->transform, &mat);
     486             :         /*move transform to object space*/
     487           2 :         mat.m[2] *= GRAD_TEXTURE_SIZE;
     488           2 :         mat.m[5] *= GRAD_TEXTURE_SIZE;
     489             :         /*translate to the center of the bounds*/
     490           2 :         gf_mx2d_add_translation(&mat, -INT2FIX(GRAD_TEXTURE_HSIZE), -INT2FIX(GRAD_TEXTURE_HSIZE));
     491             :         /*back to GL bottom->up order*/
     492           2 :         gf_mx2d_add_scale(&mat, FIX_ONE, -FIX_ONE);
     493           2 :         gf_evg_stencil_set_matrix(stenc, &mat);
     494             : 
     495           2 :         gf_evg_surface_set_raster_level(surface, GF_RASTER_HIGH_QUALITY);
     496           2 :         gf_evg_surface_set_path(surface, path);
     497           2 :         gf_evg_surface_fill(surface, stenc);
     498           2 :         gf_evg_stencil_delete(stenc);
     499           2 :         gf_evg_surface_delete(surface);
     500           2 :         gf_evg_stencil_delete(texture2D);
     501           2 :         gf_path_del(path);
     502             : 
     503           2 :         txh->data = st->tx_data;
     504           2 :         txh->width = GRAD_TEXTURE_SIZE;
     505           2 :         txh->height = GRAD_TEXTURE_SIZE;
     506           2 :         txh->transparent = transparent;
     507           2 :         if (transparent) {
     508             :                 u32 j;
     509           2 :                 txh->stride = GRAD_TEXTURE_SIZE*4;
     510           2 :                 txh->pixelformat = GF_PIXEL_RGBA;
     511             : 
     512             :                 /*back to RGBA texturing*/
     513           2 :                 if (pix_fmt == GF_PIXEL_ARGB) {
     514           0 :                         for (i=0; i<txh->height; i++) {
     515           0 :                                 char *data = txh->data + i*txh->stride;
     516           0 :                                 for (j=0; j<txh->width; j++) {
     517             :                                         u8 pa, pr, pg, pb;
     518           0 :                                         pa = data[4*j];
     519           0 :                                         pr = data[4*j+1];
     520           0 :                                         pg = data[4*j+2];
     521           0 :                                         pb = data[4*j+3];
     522           0 :                                         data[4*j] = pr;
     523           0 :                                         data[4*j+1] = pg;
     524           0 :                                         data[4*j+2] = pb;
     525           0 :                                         data[4*j+3] = pa;
     526             :                                 }
     527             :                         }
     528             :                 }
     529             :         } else {
     530           0 :                 txh->stride = GRAD_TEXTURE_SIZE*3;
     531           0 :                 txh->pixelformat = GF_PIXEL_RGB;
     532             :         }
     533             : //      tx_set_blend_enable(txh, 1);
     534           2 :         txh->flags |= GF_SR_TEXTURE_NO_GL_FLIP;
     535           2 :         gf_sc_texture_set_data(txh);
     536           2 :         return;
     537             : }
     538             : 
     539       25093 : static void UpdateRadialGradient(GF_TextureHandler *txh)
     540             : {
     541             :         Bool const_a;
     542             :         GF_EVGStencil * stencil;
     543             :         u32 i, *cols;
     544             :         Fixed a;
     545       25093 :         M_RadialGradient *rg = (M_RadialGradient*) txh->owner;
     546       25093 :         GradientStack *st = (GradientStack *) gf_node_get_private(txh->owner);
     547             : 
     548       25093 :         if (!gf_node_dirty_get(txh->owner)) {
     549       24335 :                 txh->needs_refresh = 0;
     550       24335 :                 return;
     551             :         }
     552         758 :         if (rg->key.count > rg->keyValue.count) return;
     553             : 
     554         758 :         if (!txh->tx_io) gf_sc_texture_allocate(txh);
     555             : 
     556         758 :         stencil = gf_sc_texture_get_stencil(txh);
     557         758 :         if (!stencil) stencil = gf_evg_stencil_new(GF_STENCIL_RADIAL_GRADIENT);
     558             :         /*set stencil even if assigned, this invalidates the associated bitmap state in 3D*/
     559         758 :         gf_sc_texture_set_stencil(txh, stencil);
     560             : 
     561         758 :         gf_node_dirty_clear(txh->owner, 0);
     562         758 :         txh->needs_refresh = 1;
     563             : 
     564         758 :         st->txh.transparent = 0;
     565        1548 :         for (i=0; i<rg->opacity.count; i++) {
     566         824 :                 if (rg->opacity.vals[i] != FIX_ONE) {
     567          34 :                         st->txh.transparent = 1;
     568          34 :                         break;
     569             :                 }
     570             :         }
     571             : 
     572         758 :         const_a = (rg->opacity.count == 1) ? 1 : 0;
     573         758 :         cols = (u32*)gf_malloc(sizeof(u32) * rg->key.count);
     574        2641 :         for (i=0; i<rg->key.count; i++) {
     575        1883 :                 a = (const_a ? rg->opacity.vals[0] : rg->opacity.vals[i]);
     576        1883 :                 cols[i] = GF_COL_ARGB_FIXED(a, rg->keyValue.vals[i].red, rg->keyValue.vals[i].green, rg->keyValue.vals[i].blue);
     577             :         }
     578         758 :         gf_evg_stencil_set_gradient_interpolation(stencil, rg->key.vals, cols, rg->key.count);
     579         758 :         gf_free(cols);
     580             : 
     581         758 :         gf_evg_stencil_set_gradient_mode(stencil, (GF_GradientMode) rg->spreadMethod);
     582             : 
     583             : }
     584             : 
     585       10023 : static void RG_ComputeMatrix(GF_TextureHandler *txh, GF_Rect *bounds, GF_Matrix2D *mat, Bool for_3d)
     586             : {
     587             :         GF_EVGStencil * stencil;
     588       10023 :         M_RadialGradient *rg = (M_RadialGradient *) txh->owner;
     589             : 
     590       10023 :         if (rg->key.count<2) return;
     591       10023 :         if (rg->key.count != rg->keyValue.count) return;
     592             : 
     593       10023 :         if (!txh->tx_io) return;
     594             : 
     595       10023 :         stencil = gf_sc_texture_get_stencil(txh);
     596       10023 :         if (!stencil) return;
     597             : 
     598       10023 :         GradientGetMatrix((GF_Node *) rg->transform, mat);
     599             : 
     600       10023 :         gf_evg_stencil_set_radial_gradient(stencil, rg->center.x, rg->center.y, rg->focalPoint.x, rg->focalPoint.y, rg->radius, rg->radius);
     601             :         /*move to center of bounds*/
     602       10023 :         gf_mx2d_add_translation(mat, gf_divfix(bounds->x, bounds->width), gf_divfix(bounds->y - bounds->height, bounds->height));
     603             :         /*scale back to object coordinates - the gradient is still specified in texture coordinates
     604             :         i order to avoid overflows in fixed point*/
     605       10023 :         gf_mx2d_add_scale(mat, bounds->width, bounds->height);
     606             : }
     607             : 
     608             : 
     609         434 : void compositor_init_radial_gradient(GF_Compositor *compositor, GF_Node *node)
     610             : {
     611             :         GradientStack *st;
     612         434 :         GF_SAFEALLOC(st, GradientStack);
     613         434 :         if (!st) {
     614           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate gradient stack\n"));
     615             :                 return;
     616             :         }
     617             : 
     618             :         /*!!! Gradients are textures but are not registered as textures with the compositor in order to avoid updating
     619             :         too many textures each frame - gradients are only registered with the compositor when they are used in OpenGL, in order
     620             :         to release associated HW resource when no longer used*/
     621         434 :         st->txh.owner = node;
     622         434 :         st->txh.compositor = compositor;
     623         434 :         st->txh.update_texture_fcnt = UpdateRadialGradient;
     624         434 :         st->txh.compute_gradient_matrix = RG_ComputeMatrix;
     625             : 
     626         434 :         gf_node_set_private(node, st);
     627         434 :         gf_node_set_callback_function(node, DestroyGradient);
     628             : }
     629             : 
     630       27340 : GF_TextureHandler *compositor_mpeg4_get_gradient_texture(GF_Node *node)
     631             : {
     632       27340 :         GradientStack *st = (GradientStack*) gf_node_get_private(node);
     633       27340 :         st->txh.update_texture_fcnt(&st->txh);
     634       27340 :         return &st->txh;
     635             : }
     636             : 
     637             : #endif /*GPAC_DISABLE_VRML*/
     638             : 
     639         316 : void compositor_gradient_update(GF_TextureHandler *txh)
     640             : {
     641         316 :         switch (gf_node_get_tag(txh->owner) ) {
     642             : #ifndef GPAC_DISABLE_VRML
     643           2 :         case TAG_MPEG4_RadialGradient:
     644           2 :                 BuildRadialGradientTexture(txh);
     645           2 :                 break;
     646         314 :         case TAG_MPEG4_LinearGradient:
     647         314 :                 BuildLinearGradientTexture(txh);
     648         314 :                 break;
     649             : #endif
     650             : 
     651             : #ifndef GPAC_DISABLE_SVG
     652           0 :         case TAG_SVG_linearGradient:
     653             :         case TAG_SVG_radialGradient:
     654           0 :                 compositor_svg_build_gradient_texture(txh);
     655           0 :                 break;
     656             : #endif
     657             :         }
     658         316 : }
     659             : 

Generated by: LCOV version 1.13