LCOV - code coverage report
Current view: top level - compositor - mpeg4_geometry_3d.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 254 349 72.8 %
Date: 2021-04-29 23:48:07 Functions: 35 46 76.1 %

          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             : 
      27             : #include "visual_manager.h"
      28             : #include "nodes_stacks.h"
      29             : 
      30             : 
      31             : #ifndef GPAC_DISABLE_VRML
      32             : 
      33             : #ifndef GPAC_DISABLE_3D
      34             : 
      35             : #include <gpac/options.h>
      36             : #include <gpac/mediaobject.h>
      37             : 
      38       19454 : void drawable_3d_base_traverse(GF_Node *n, void *rs, Bool is_destroy, void (*build_shape)(GF_Node*,Drawable3D *,GF_TraverseState *) )
      39             : {
      40             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
      41       19454 :         Drawable3D *stack = (Drawable3D*)gf_node_get_private(n);
      42             : 
      43       19454 :         if (is_destroy) {
      44         184 :                 drawable_3d_del(n);
      45         184 :                 return;
      46             :         }
      47       19270 :         if (gf_node_dirty_get(n)) {
      48         320 :                 mesh_reset(stack->mesh);
      49         320 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Rebuilding mesh %s\n", gf_node_get_class_name(n)));
      50         320 :                 build_shape(n, stack, tr_state);
      51         320 :                 gf_node_dirty_clear(n, 0);
      52             :         }
      53       19270 :         switch (tr_state->traversing_mode) {
      54       15614 :         case TRAVERSE_DRAW_3D:
      55       15614 :                 visual_3d_draw(tr_state, stack->mesh);
      56       15614 :                 drawable3d_check_focus_highlight(n, tr_state, &stack->mesh->bounds);
      57       15614 :                 break;
      58        2592 :         case TRAVERSE_GET_BOUNDS:
      59        2592 :                 tr_state->bbox = stack->mesh->bounds;
      60        2592 :                 break;
      61         910 :         case TRAVERSE_PICK:
      62         910 :                 visual_3d_vrml_drawable_pick(n, tr_state, stack->mesh, NULL);
      63         910 :                 return;
      64         154 :         case TRAVERSE_SORT:
      65             :                 //we are drawing 3D object but configured for 2D, force 3D
      66         154 :                 if (!tr_state->visual->type_3d && tr_state->visual->compositor->hybrid_opengl) {
      67          54 :                         tr_state->visual->compositor->root_visual_setup=0;
      68          54 :                         tr_state->visual->compositor->force_type_3d=1;
      69             :                 }
      70             :         }
      71             : }
      72             : 
      73          54 : static void build_shape_box(GF_Node *n, Drawable3D *stack, GF_TraverseState *tr_state)
      74             : {
      75          54 :         mesh_new_box(stack->mesh, ((M_Box *)n)->size);
      76          54 : }
      77             : 
      78       11691 : static void TraverseBox(GF_Node *n, void *rs, Bool is_destroy)
      79             : {
      80       11691 :         drawable_3d_base_traverse(n, rs, is_destroy, build_shape_box);
      81       11691 : }
      82             : 
      83          55 : void compositor_init_box(GF_Compositor *compositor, GF_Node *node)
      84             : {
      85          55 :         drawable_3d_new(node);
      86          55 :         gf_node_set_callback_function(node, TraverseBox);
      87          55 : }
      88             : 
      89          12 : static void build_shape_cone(GF_Node *n, Drawable3D *stack, GF_TraverseState *tr_state)
      90             : {
      91             :         M_Cone *co = (M_Cone *)n;
      92          12 :         mesh_new_cone(stack->mesh, co->height, co->bottomRadius, co->bottom, co->side, tr_state->visual->compositor->fast);
      93          12 : }
      94             : 
      95         626 : static void TraverseCone(GF_Node *n, void *rs, Bool is_destroy)
      96             : {
      97         626 :         drawable_3d_base_traverse(n, rs, is_destroy, build_shape_cone);
      98         626 : }
      99             : 
     100          12 : void compositor_init_cone(GF_Compositor *compositor, GF_Node *node)
     101             : {
     102          12 :         drawable_3d_new(node);
     103          12 :         gf_node_set_callback_function(node, TraverseCone);
     104          12 : }
     105             : 
     106          21 : static void build_shape_cylinder(GF_Node *n, Drawable3D *stack, GF_TraverseState *tr_state)
     107             : {
     108             :         M_Cylinder *cy = (M_Cylinder *)n;
     109          21 :         mesh_new_cylinder(stack->mesh, cy->height, cy->radius, cy->bottom, cy->side, cy->top, tr_state->visual->compositor->fast);
     110          21 : }
     111             : 
     112        1717 : static void TraverseCylinder(GF_Node *n, void *rs, Bool is_destroy)
     113             : {
     114        1717 :         drawable_3d_base_traverse(n, rs, is_destroy, build_shape_cylinder);
     115        1717 : }
     116             : 
     117          21 : void compositor_init_cylinder(GF_Compositor *compositor, GF_Node *node)
     118             : {
     119          21 :         drawable_3d_new(node);
     120          21 :         gf_node_set_callback_function(node, TraverseCylinder);
     121          21 : }
     122             : 
     123          13 : static void build_shape_sphere(GF_Node *n, Drawable3D *stack, GF_TraverseState *tr_state)
     124             : {       
     125             :         M_Sphere *sp = (M_Sphere *)n;
     126          13 :         mesh_new_sphere(stack->mesh, sp->radius, tr_state->visual->compositor->fast, NULL);
     127          13 : }
     128             : 
     129         100 : static void get_tx_coords_from_angle(GF_TraverseState *tr_state, GF_TextureHandler *txh, Bool horizontal, u32 *min_coord, u32 *max_coord)
     130             : {
     131             :         GF_Vec target, ref;
     132             :         Fixed dot, det, hfov, theta_angle, angle_start, angle_end, min_tx, max_tx;
     133             :         u32 dim;
     134             :         
     135         100 :         ref.x = horizontal ? FIX_ONE : 0;
     136         100 :         ref.y = horizontal ? 0 : FIX_ONE;
     137             :         ref.z = 0;
     138             : 
     139         100 :         target = camera_get_target_dir(tr_state->camera);
     140         100 :         if (horizontal) target.y = 0;
     141          50 :         else target.x = 0;
     142             :         
     143         100 :         gf_vec_norm(&target);
     144         100 :         dot = gf_vec_dot(target, ref);
     145         100 :         if (horizontal) {
     146          50 :                 det = target.x*ref.z - target.z*ref.x;
     147             :         } else {
     148          50 :                 det = target.y*ref.z - target.z*ref.y;
     149             :         }
     150         100 :         theta_angle = gf_atan2(det, dot);
     151             :         //sphere starts horizontally at -PI/2
     152         100 :         if (horizontal) {
     153          50 :                 theta_angle -= GF_PI2;
     154          50 :                 hfov = tr_state->camera->fieldOfView*tr_state->camera->width/tr_state->camera->height/2;
     155             :         } else {
     156          50 :                 hfov = tr_state->camera->fieldOfView/2;
     157             :         }
     158             : 
     159         100 :         angle_start = theta_angle - hfov;
     160         100 :         angle_end = theta_angle + hfov;
     161             : 
     162             :         //move everything in [-PI,PI]
     163         100 :         if (angle_start < -GF_PI) angle_start += GF_2PI;
     164         100 :         if (angle_start > GF_PI) angle_start -= GF_2PI;
     165         100 :         if (angle_end < -GF_PI) angle_end += GF_2PI;
     166         100 :         if (angle_end > GF_PI) angle_end -= GF_2PI;
     167             :         
     168         100 :         if (horizontal) {
     169             :                 //start angle corresponds to max tx horiz coord, left to min
     170          50 :                 max_tx = FIX_ONE - (angle_start + GF_PI) / GF_2PI;
     171          50 :                 min_tx = FIX_ONE - (angle_end + GF_PI) / GF_2PI;
     172             :                 //we wrap horizontally, which means we may have min_tx > max_tx, in which case we need both [min_tx, WIDTH] and [0, max_tx] parts of the texture
     173          50 :                 dim = txh->width;
     174             :         } else {
     175             :                 //-angle is the same position as +angle
     176          50 :                 if (angle_start<0) angle_start = -angle_start;
     177          50 :                 if (angle_end<0) angle_end = -angle_end;
     178             :                 //SRD x=0 is the top of the sphere - we don't wrap vertically
     179          50 :                 if (angle_start<angle_end) {
     180          50 :                         min_tx = angle_start / GF_PI;
     181          50 :                         max_tx = angle_end / GF_PI;
     182             :                 } else {
     183           0 :                         max_tx = angle_start / GF_PI;
     184           0 :                         min_tx = angle_end / GF_PI;
     185             :                 }
     186          50 :                 dim = txh->height;
     187             :         }
     188         100 :         *min_coord= (u32) (min_tx*dim);
     189         100 :         *max_coord= (u32) (max_tx*dim);
     190         100 : }
     191             : 
     192        1590 : static void TraverseSphere(GF_Node *n, void *rs, Bool is_destroy)
     193             : {
     194             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
     195        1590 :         drawable_3d_base_traverse(n, rs, is_destroy, build_shape_sphere);
     196             : 
     197        1590 :         if (!is_destroy && tr_state->traversing_mode == TRAVERSE_DRAW_3D) {
     198             :                 GF_MediaObjectVRInfo vrinfo;
     199             :                 u32 min_x, max_x, min_y, max_y;
     200         919 :                 GF_TextureHandler *txh = gf_sc_texture_get_handler( ((M_Appearance *) tr_state->appear)->texture );
     201             :                 
     202        1788 :                 if (!txh || !txh->stream) return;
     203             :                 
     204         202 :                 if (!gf_mo_get_srd_info(txh->stream, &vrinfo) || !vrinfo.is_tiled_srd)
     205             :                         return;
     206             :                 
     207             :                 //we need to compute min/max tex coords visible for that sphere
     208             :                 
     209          50 :                 get_tx_coords_from_angle(tr_state, txh, GF_TRUE, &min_x, &max_x);
     210          50 :                 get_tx_coords_from_angle(tr_state, txh, GF_FALSE, &min_y, &max_y);
     211             :                 
     212          50 :                 gf_mo_hint_visible_rect(txh->stream, min_x, max_x, min_y, max_y);
     213          50 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor] Visible texture rectangle of sphere is %u,%u,%u,%u\n", min_x, max_x, min_y, max_y));
     214             :         }
     215             : }
     216             : 
     217          19 : void compositor_init_sphere(GF_Compositor *compositor, GF_Node *node)
     218             : {
     219          19 :         drawable_3d_new(node);
     220          19 :         gf_node_set_callback_function(node, TraverseSphere);
     221          19 : }
     222             : 
     223           7 : static void build_shape_point_set(GF_Node *n, Drawable3D *stack, GF_TraverseState *tr_state)
     224             : {
     225             :         M_PointSet *ps = (M_PointSet *)n;
     226           7 :         mesh_new_ps(stack->mesh, ps->coord, ps->color);
     227           7 : }
     228         153 : static void TraversePointSet(GF_Node *n, void *rs, Bool is_destroy)
     229             : {
     230         153 :         drawable_3d_base_traverse(n, rs, is_destroy, build_shape_point_set);
     231         153 : }
     232             : 
     233           7 : void compositor_init_point_set(GF_Compositor *compositor, GF_Node *node)
     234             : {
     235           7 :         drawable_3d_new(node);
     236           7 :         gf_node_set_callback_function(node, TraversePointSet);
     237           7 : }
     238             : 
     239          27 : static void build_shape_ifs(GF_Node *n, Drawable3D *stack, GF_TraverseState *tr_state)
     240             : {
     241          27 :         mesh_new_ifs(stack->mesh, n);
     242          27 : }
     243        2474 : static void TraverseIFS(GF_Node *n, void *rs, Bool is_destroy)
     244             : {
     245        2474 :         drawable_3d_base_traverse(n, rs, is_destroy, build_shape_ifs);
     246        2474 : }
     247             : 
     248           0 : static void IFS_SetColorIndex(GF_Node *node, GF_Route *route)
     249             : {
     250             :         M_IndexedFaceSet *ifs = (M_IndexedFaceSet *)node;
     251           0 :         if (node) {
     252           0 :                 gf_sg_vrml_field_copy(&ifs->colorIndex, &ifs->set_colorIndex, GF_SG_VRML_MFINT32);
     253           0 :                 gf_sg_vrml_mf_reset(&ifs->set_colorIndex, GF_SG_VRML_MFINT32);
     254             :         }
     255           0 : }
     256             : 
     257           0 : static void IFS_SetCoordIndex(GF_Node *node, GF_Route *route)
     258             : {
     259             :         M_IndexedFaceSet *ifs = (M_IndexedFaceSet *)node;
     260           0 :         if (node) {
     261           0 :                 gf_sg_vrml_field_copy(&ifs->coordIndex, &ifs->set_coordIndex, GF_SG_VRML_MFINT32);
     262           0 :                 gf_sg_vrml_mf_reset(&ifs->set_coordIndex, GF_SG_VRML_MFINT32);
     263             :         }
     264           0 : }
     265             : 
     266           0 : static void IFS_SetNormalIndex(GF_Node *node, GF_Route *route)
     267             : {
     268             :         M_IndexedFaceSet *ifs = (M_IndexedFaceSet *)node;
     269           0 :         if (node) {
     270           0 :                 gf_sg_vrml_field_copy(&ifs->normalIndex, &ifs->set_normalIndex, GF_SG_VRML_MFINT32);
     271           0 :                 gf_sg_vrml_mf_reset(&ifs->set_normalIndex, GF_SG_VRML_MFINT32);
     272             :         }
     273           0 : }
     274             : 
     275           0 : static void IFS_SetTexCoordIndex(GF_Node *node, GF_Route *route)
     276             : {
     277             :         M_IndexedFaceSet *ifs = (M_IndexedFaceSet *)node;
     278           0 :         if (node) {
     279           0 :                 gf_sg_vrml_field_copy(&ifs->texCoordIndex, &ifs->set_texCoordIndex, GF_SG_VRML_MFINT32);
     280           0 :                 gf_sg_vrml_mf_reset(&ifs->set_texCoordIndex, GF_SG_VRML_MFINT32);
     281             :         }
     282           0 : }
     283             : 
     284          33 : void compositor_init_ifs(GF_Compositor *compositor, GF_Node *node)
     285             : {
     286             :         M_IndexedFaceSet *ifs = (M_IndexedFaceSet *)node;
     287          33 :         drawable_3d_new(node);
     288          33 :         gf_node_set_callback_function(node, TraverseIFS);
     289          33 :         ifs->on_set_colorIndex = IFS_SetColorIndex;
     290          33 :         ifs->on_set_coordIndex = IFS_SetCoordIndex;
     291          33 :         ifs->on_set_normalIndex = IFS_SetNormalIndex;
     292          33 :         ifs->on_set_texCoordIndex = IFS_SetTexCoordIndex;
     293             : 
     294             : #ifdef GPAC_ENABLE_COVERAGE
     295          33 :         if (gf_sys_is_cov_mode()) {
     296             :                 IFS_SetCoordIndex(NULL, NULL);
     297             :                 IFS_SetColorIndex(NULL, NULL);
     298             :                 IFS_SetNormalIndex(NULL, NULL);
     299             :                 IFS_SetTexCoordIndex(NULL, NULL);
     300             :         }
     301             : #endif
     302             : 
     303          33 : }
     304             : 
     305           8 : static void build_shape_ils(GF_Node *n, Drawable3D *stack, GF_TraverseState *tr_state)
     306             : {
     307             :         M_IndexedLineSet *ils = (M_IndexedLineSet *)n;
     308           8 :         mesh_new_ils(stack->mesh, ils->coord, &ils->coordIndex, ils->color, &ils->colorIndex, ils->colorPerVertex, 0);
     309           8 : }
     310             : 
     311         156 : static void TraverseILS(GF_Node *n, void *rs, Bool is_destroy)
     312             : {
     313         156 :         drawable_3d_base_traverse(n, rs, is_destroy, build_shape_ils);
     314         156 : }
     315             : 
     316           0 : static void ILS_SetColorIndex(GF_Node *node, GF_Route *route)
     317             : {
     318             :         M_IndexedLineSet *ils = (M_IndexedLineSet *)node;
     319           0 :         if (node) {
     320           0 :                 gf_sg_vrml_field_copy(&ils->colorIndex, &ils->set_colorIndex, GF_SG_VRML_MFINT32);
     321           0 :                 gf_sg_vrml_mf_reset(&ils->set_colorIndex, GF_SG_VRML_MFINT32);
     322             :         }
     323           0 : }
     324             : 
     325           0 : static void ILS_SetCoordIndex(GF_Node *node, GF_Route *route)
     326             : {
     327             :         M_IndexedLineSet *ils = (M_IndexedLineSet *)node;
     328           0 :         if (node) {
     329           0 :                 gf_sg_vrml_field_copy(&ils->coordIndex, &ils->set_coordIndex, GF_SG_VRML_MFINT32);
     330           0 :                 gf_sg_vrml_mf_reset(&ils->set_coordIndex, GF_SG_VRML_MFINT32);
     331             :         }
     332           0 : }
     333             : 
     334           8 : void compositor_init_ils(GF_Compositor *compositor, GF_Node *node)
     335             : {
     336             :         M_IndexedLineSet *ils = (M_IndexedLineSet *)node;
     337           8 :         drawable_3d_new(node);
     338           8 :         gf_node_set_callback_function(node, TraverseILS);
     339           8 :         ils->on_set_colorIndex = ILS_SetColorIndex;
     340           8 :         ils->on_set_coordIndex = ILS_SetCoordIndex;
     341             : 
     342             : #ifdef GPAC_ENABLE_COVERAGE
     343           8 :         if (gf_sys_is_cov_mode()) {
     344             :                 ILS_SetCoordIndex(NULL, NULL);
     345             :                 ILS_SetColorIndex(NULL, NULL);
     346             :         }
     347             : #endif
     348             : 
     349           8 : }
     350             : 
     351             : 
     352           7 : static void build_shape_elevation_grid(GF_Node *n, Drawable3D *stack, GF_TraverseState *tr_state)
     353             : {
     354           7 :         mesh_new_elevation_grid(stack->mesh, n);
     355           7 : }
     356             : 
     357         228 : static void TraverseElevationGrid(GF_Node *n, void *rs, Bool is_destroy)
     358             : {
     359         228 :         drawable_3d_base_traverse(n, rs, is_destroy, build_shape_elevation_grid);
     360         228 : }
     361             : 
     362           0 : static void ElevationGrid_SetHeight(GF_Node *node, GF_Route *route)
     363             : {
     364             :         M_ElevationGrid *eg = (M_ElevationGrid *)node;
     365           0 :         if (node) {
     366           0 :                 gf_sg_vrml_field_copy(&eg->height, &eg->set_height, GF_SG_VRML_MFFLOAT);
     367           0 :                 gf_sg_vrml_mf_reset(&eg->set_height, GF_SG_VRML_MFFLOAT);
     368             :         }
     369           0 : }
     370             : 
     371           7 : void compositor_init_elevation_grid(GF_Compositor *compositor, GF_Node *node)
     372             : {
     373             :         M_ElevationGrid *eg = (M_ElevationGrid *)node;
     374           7 :         drawable_3d_new(node);
     375           7 :         gf_node_set_callback_function(node, TraverseElevationGrid);
     376           7 :         eg->on_set_height = ElevationGrid_SetHeight;
     377             : #ifdef GPAC_ENABLE_COVERAGE
     378           7 :         if (gf_sys_is_cov_mode()) {
     379             :                 ElevationGrid_SetHeight(NULL, NULL);
     380             :         }
     381             : #endif
     382           7 : }
     383             : 
     384           7 : static void build_shape_extrusion(GF_Node *n, Drawable3D *stack, GF_TraverseState *tr_state)
     385             : {
     386           7 :         mesh_new_extrusion(stack->mesh, n);
     387           7 : }
     388             : 
     389         328 : static void TraverseExtrusion(GF_Node *n, void *rs, Bool is_destroy)
     390             : {
     391         328 :         drawable_3d_base_traverse(n, rs, is_destroy, build_shape_extrusion);
     392         328 : }
     393             : 
     394           0 : static void Extrusion_SetCrossSection(GF_Node *node, GF_Route *route)
     395             : {
     396             :         M_Extrusion *eg = (M_Extrusion *)node;
     397           0 :         if (node) {
     398           0 :                 gf_sg_vrml_field_copy(&eg->crossSection, &eg->set_crossSection, GF_SG_VRML_MFVEC2F);
     399           0 :                 gf_sg_vrml_mf_reset(&eg->set_crossSection, GF_SG_VRML_MFVEC2F);
     400             :         }
     401           0 : }
     402           0 : static void Extrusion_SetOrientation(GF_Node *node, GF_Route *route)
     403             : {
     404             :         M_Extrusion *eg = (M_Extrusion *)node;
     405           0 :         if (node) {
     406           0 :                 gf_sg_vrml_field_copy(&eg->orientation, &eg->set_orientation, GF_SG_VRML_MFROTATION);
     407           0 :                 gf_sg_vrml_mf_reset(&eg->set_orientation, GF_SG_VRML_MFROTATION);
     408             :         }
     409           0 : }
     410           0 : static void Extrusion_SetScale(GF_Node *node, GF_Route *route)
     411             : {
     412             :         M_Extrusion *eg = (M_Extrusion *)node;
     413           0 :         if (node) {
     414           0 :                 gf_sg_vrml_field_copy(&eg->scale, &eg->set_scale, GF_SG_VRML_MFVEC2F);
     415           0 :                 gf_sg_vrml_mf_reset(&eg->set_scale, GF_SG_VRML_MFVEC2F);
     416             :         }
     417           0 : }
     418           0 : static void Extrusion_SetSpine(GF_Node *node, GF_Route *route)
     419             : {
     420             :         M_Extrusion *eg = (M_Extrusion *)node;
     421           0 :         if (node) {
     422           0 :                 gf_sg_vrml_field_copy(&eg->spine, &eg->set_spine, GF_SG_VRML_MFVEC3F);
     423           0 :                 gf_sg_vrml_mf_reset(&eg->set_spine, GF_SG_VRML_MFVEC3F);
     424             :         }
     425           0 : }
     426           7 : void compositor_init_extrusion(GF_Compositor *compositor, GF_Node *node)
     427             : {
     428             :         M_Extrusion *ext = (M_Extrusion *)node;
     429           7 :         drawable_3d_new(node);
     430           7 :         gf_node_set_callback_function(node, TraverseExtrusion);
     431           7 :         ext->on_set_crossSection = Extrusion_SetCrossSection;
     432           7 :         ext->on_set_orientation = Extrusion_SetOrientation;
     433           7 :         ext->on_set_scale = Extrusion_SetScale;
     434           7 :         ext->on_set_spine = Extrusion_SetSpine;
     435             : 
     436             : #ifdef GPAC_ENABLE_COVERAGE
     437           7 :         if (gf_sys_is_cov_mode()) {
     438             :                 Extrusion_SetCrossSection(NULL, NULL);
     439             :                 Extrusion_SetOrientation(NULL, NULL);
     440             :                 Extrusion_SetScale(NULL, NULL);
     441             :                 Extrusion_SetSpine(NULL, NULL);
     442             :         }
     443             : #endif
     444             : 
     445           7 : }
     446             : 
     447             : 
     448             : /*
     449             :                         NonLinearDeformer
     450             : 
     451             :         NOTE: AFX spec is just hmm, well, hmm. NonLinearDeformer.extend interpretation differ from type to
     452             :         type within the spec, and between the spec and the ref soft. This is GPAC interpretation
     453             :         * all params are specified with default transform axis (Z axis)
     454             :         * NLD.type = 0 (taper):
     455             :                 * taping radius = NLD.param
     456             :                 * extend = N * [diff, perc] with
     457             :                         - diff : relative position along taper axis (for default, diff=0: z min, diff=1: z max)
     458             :                         - perc: mult ratio for base taper radius
     459             :                 extend works like key/keyValue for a scalar interpolator
     460             :                 final radius: r(z) = LinearInterp(extend[min key], extend[min key + 1]) * param
     461             : 
     462             :         * NLD.type = 1 (twister):
     463             :                 * twisting angle = NLD.param
     464             :                 * extend = N * [diff, perc] with
     465             :                         - diff : relative position along twister axis (for default, diff=0: z min, diff=1: z max)
     466             :                         - perc: mult ratio for base twister angle
     467             :                 extend works like key/keyValue for a scalar interpolator
     468             :                 final angle: a(z) = LinearInterp(extend[min key], extend[min key + 1]) * param
     469             : 
     470             :         * NLD.type = 2 (bender):
     471             :                 * bending curvature = NLD.param
     472             :                 * extend = N * [diff, perc] with
     473             :                         - diff : relative position along bender axis (for default, diff=0: z min, diff=1: z max)
     474             :                         - perc: mult ratio for base bender curvature
     475             :                 extend works like key/keyValue for a scalar interpolator
     476             :                 final curvature: c(z) = LinearInterp(extend[min key], extend[min key + 1]) * param
     477             : 
     478             :   Another pb of NLD is that the spec says nothing about object/axis alignment: should we center
     479             :   the object at 0,0,0 (local coords) or not? the results are quite different. Here we don't
     480             :   recenter the object before transform
     481             : 
     482             : 
     483             :  TODO - think of a way to implement this through the vertex shader
     484             :  */
     485             : 
     486         156 : static Bool NLD_GetMatrix(M_NonLinearDeformer *nld, GF_Matrix *mx)
     487             : {
     488             :         SFVec3f v1, v2;
     489             :         SFRotation r;
     490             :         Fixed l1, l2, dot;
     491             : 
     492             :         /*compute rotation matrix from NLD axis to 0 0 1*/
     493         156 :         v1 = nld->axis;
     494         156 :         gf_vec_norm(&v1);
     495             :         v2.x = v2.y = 0;
     496             :         v2.z = FIX_ONE;
     497         156 :         if (gf_vec_equal(v1, v2)) return 0;
     498             : 
     499         156 :         l1 = gf_vec_len(v1);
     500         156 :         l2 = gf_vec_len(v2);
     501         156 :         dot = gf_divfix(gf_vec_dot(v1, v2), gf_mulfix(l1, l2));
     502             : 
     503         156 :         r.x = gf_mulfix(v1.y, v2.z) - gf_mulfix(v2.y, v1.z);
     504         156 :         r.y = gf_mulfix(v1.z, v2.x) - gf_mulfix(v2.z, v1.x);
     505         156 :         r.z = gf_mulfix(v1.x, v2.y) - gf_mulfix(v2.x, v1.y);
     506         156 :         r.q = gf_atan2(gf_sqrt(FIX_ONE - gf_mulfix(dot, dot)), dot);
     507         312 :         gf_mx_init(*mx);
     508         156 :         gf_mx_add_rotation(mx, r.q, r.x, r.y, r.z);
     509         156 :         return 1;
     510             : }
     511             : 
     512      563400 : static GFINLINE void NLD_GetKey(M_NonLinearDeformer *nld, Fixed frac, Fixed *f_min, Fixed *min, Fixed *f_max, Fixed *max)
     513             : {
     514             :         u32 i, count;
     515      563400 :         count = nld->extend.count;
     516      563400 :         if (count%2) count--;
     517             : 
     518      563400 :         *f_min = 0;
     519      563400 :         *min = 0;
     520      980400 :         for (i=0; i<count; i+=2) {
     521      980400 :                 if (frac>=nld->extend.vals[i]) {
     522      980400 :                         *f_min = nld->extend.vals[i];
     523      980400 :                         *min = nld->extend.vals[i+1];
     524             :                 }
     525      980400 :                 if ((i+2<count) && (frac<=nld->extend.vals[i+2])) {
     526      563400 :                         *f_max = nld->extend.vals[i+2];
     527      563400 :                         *max = nld->extend.vals[i+3];
     528             :                         return;
     529             :                 }
     530             :         }
     531           0 :         if (count) {
     532           0 :                 *f_max = nld->extend.vals[count-2];
     533           0 :                 *max = nld->extend.vals[count-1];
     534             :         } else {
     535           0 :                 *f_max = FIX_ONE;
     536           0 :                 *max = GF_PI;
     537             :         }
     538             : }
     539             : 
     540         156 : static void NLD_Apply(M_NonLinearDeformer *nld, GF_Mesh *mesh)
     541             : {
     542             :         u32 i;
     543             :         GF_Matrix mx;
     544             :         SFVec3f n;
     545             :         Fixed param, z_min, z_max, v_min, v_max, f_min, f_max, frac, val, a_cos, a_sin;
     546         156 :         Bool needs_transform = NLD_GetMatrix(nld, &mx);
     547             : 
     548         156 :         param = nld->param;
     549         156 :         if (!param) param = 1;
     550             : 
     551         162 :         if (mesh->bounds.min_edge.z == mesh->bounds.max_edge.z) return;
     552             : 
     553             :         z_min = FIX_MAX;
     554             :         z_max = -FIX_MAX;
     555         150 :         if (needs_transform) {
     556      563400 :                 for (i=0; i<mesh->v_count; i++) {
     557      563400 :                         gf_mx_apply_vec(&mx, &mesh->vertices[i].pos);
     558      563400 :                         MESH_GET_NORMAL(n, mesh->vertices[i]);
     559      563400 :                         gf_mx_rotate_vector(&mx, &n);
     560      563400 :                         MESH_SET_NORMAL(mesh->vertices[i], n);
     561             : 
     562      563400 :                         if (mesh->vertices[i].pos.z<z_min) z_min = mesh->vertices[i].pos.z;
     563      563400 :                         if (mesh->vertices[i].pos.z>z_max) z_max = mesh->vertices[i].pos.z;
     564             :                 }
     565             :         } else {
     566             :                 z_min = mesh->bounds.min_edge.z;
     567             :                 z_max = mesh->bounds.max_edge.z;
     568             :         }
     569             : 
     570      563550 :         for (i=0; i<mesh->v_count; i++) {
     571      563400 :                 SFVec3f old = mesh->vertices[i].pos;
     572      563400 :                 frac = gf_divfix(old.z - z_min, z_max - z_min);
     573      563400 :                 NLD_GetKey(nld, frac, &f_min, &v_min, &f_max, &v_max);
     574      563400 :                 if (f_max == f_min) {
     575           0 :                         val = v_min;
     576             :                 } else {
     577      563400 :                         frac = gf_divfix(frac-f_min, f_max - f_min);
     578      563400 :                         val = gf_mulfix(v_max - v_min, frac) + v_min;
     579             :                 }
     580      563400 :                 val = gf_mulfix(val, param);
     581             : 
     582      563400 :                 switch (nld->type) {
     583             :                 /*taper*/
     584      563400 :                 case 0:
     585      563400 :                         mesh->vertices[i].pos.x = gf_mulfix(mesh->vertices[i].pos.x, val);
     586      563400 :                         mesh->vertices[i].pos.y = gf_mulfix(mesh->vertices[i].pos.y, val);
     587      563400 :                         MESH_GET_NORMAL(old, mesh->vertices[i]);
     588      563400 :                         n=old;
     589      563400 :                         n.x = gf_mulfix(n.x, val);
     590      563400 :                         n.y = gf_mulfix(n.y, val);
     591      563400 :                         gf_vec_norm(&n);
     592      563400 :                         MESH_SET_NORMAL(mesh->vertices[i], n);
     593      563400 :                         break;
     594             :                 /*twist*/
     595           0 :                 case 1:
     596           0 :                         a_cos = gf_cos(val);
     597           0 :                         a_sin = gf_sin(val);
     598           0 :                         mesh->vertices[i].pos.x = gf_mulfix(a_cos, old.x) - gf_mulfix(a_sin, old.y);
     599           0 :                         mesh->vertices[i].pos.y = gf_mulfix(a_sin, old.x) + gf_mulfix(a_cos, old.y);
     600           0 :                         MESH_GET_NORMAL(old, mesh->vertices[i]);
     601           0 :                         n=old;
     602           0 :                         n.x = gf_mulfix(a_cos, old.x) -  gf_mulfix(a_sin, old.y);
     603           0 :                         n.y = gf_mulfix(a_sin, old.x) + gf_mulfix(a_cos, old.y);
     604           0 :                         gf_vec_norm(&n);
     605           0 :                         MESH_SET_NORMAL(mesh->vertices[i], n);
     606           0 :                         break;
     607             :                 /*bend*/
     608           0 :                 case 2:
     609           0 :                         a_cos = gf_cos(val);
     610           0 :                         a_sin = gf_sin(val);
     611           0 :                         mesh->vertices[i].pos.x = gf_mulfix(a_sin, old.z) + gf_mulfix(a_cos, old.x);
     612           0 :                         mesh->vertices[i].pos.z = gf_mulfix(a_cos, old.z) - gf_mulfix(a_sin, old.x);
     613           0 :                         MESH_GET_NORMAL(old, mesh->vertices[i]);
     614           0 :                         n=old;
     615           0 :                         n.x = gf_mulfix(a_sin, old.z) +  gf_mulfix(a_cos, old.x);
     616           0 :                         n.z = gf_mulfix(a_cos, old.z) - gf_mulfix(a_sin, old.x);
     617           0 :                         gf_vec_norm(&n);
     618           0 :                         MESH_SET_NORMAL(mesh->vertices[i], n);
     619           0 :                         break;
     620             :                 /*pinch, not standard  (taper on X dim only)*/
     621           0 :                 case 3:
     622           0 :                         mesh->vertices[i].pos.x = gf_mulfix(mesh->vertices[i].pos.x, val);
     623           0 :                         MESH_GET_NORMAL(old, mesh->vertices[i]);
     624           0 :                         n=old;
     625           0 :                         n.x = gf_mulfix(n.x, val);
     626           0 :                         gf_vec_norm(&n);
     627           0 :                         MESH_SET_NORMAL(mesh->vertices[i], n);
     628           0 :                         break;
     629             :                 }
     630             :         }
     631         150 :         if (needs_transform) {
     632         150 :                 gf_mx_inverse(&mx);
     633      563550 :                 for (i=0; i<mesh->v_count; i++) {
     634      563400 :                         gf_mx_apply_vec(&mx, &mesh->vertices[i].pos);
     635      563400 :                         MESH_GET_NORMAL(n, mesh->vertices[i]);
     636      563400 :                         gf_mx_rotate_vector(&mx, &n);
     637      563400 :                         MESH_SET_NORMAL(mesh->vertices[i], n);
     638             :                 }
     639             :         }
     640         150 :         mesh_update_bounds(mesh);
     641         150 :         gf_mesh_build_aabbtree(mesh);
     642             : }
     643             : 
     644         156 : static void build_shape_nld(GF_Node *n, Drawable3D *stack, GF_TraverseState *tr_state)
     645             : {
     646             :         M_NonLinearDeformer *nld = (M_NonLinearDeformer*)n;
     647         156 :         Drawable3D *geo_st = (Drawable3D *)gf_node_get_private(nld->geometry);
     648             : 
     649         156 :         if (!nld->geometry) return;
     650         156 :         if (!geo_st) return;
     651             : 
     652         156 :         mesh_clone(stack->mesh, geo_st->mesh);
     653             :         /*apply deforms*/
     654         156 :         NLD_Apply(nld, stack->mesh);
     655             : }
     656             : 
     657         454 : static void TraverseNonLinearDeformer(GF_Node *n, void *rs, Bool is_destroy)
     658             : {
     659             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
     660             : 
     661             :         /*traverse geometry for get_bounds to make sure geometry is up to date*/
     662         454 :         if (!is_destroy && (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS)) {
     663         150 :                 gf_node_traverse(((M_NonLinearDeformer*)n)->geometry, tr_state);
     664             :         }
     665             : 
     666         454 :         drawable_3d_base_traverse(n, rs, is_destroy, build_shape_nld);
     667         454 : }
     668             : 
     669           7 : void compositor_init_non_linear_deformer(GF_Compositor *compositor, GF_Node *node)
     670             : {
     671           7 :         drawable_3d_new(node);
     672           7 :         gf_node_set_callback_function(node, TraverseNonLinearDeformer);
     673           7 : }
     674             : 
     675             : #endif /*GPAC_DISABLE_3D*/
     676             : 
     677             : #endif /*GPAC_DISABLE_VRML*/

Generated by: LCOV version 1.13