| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  |  * as published by the Free Software Foundation; either version 2 | 
					
						
							|  |  |  |  * of the License, or (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  * along with this program; if not, write to the Free Software  Foundation, | 
					
						
							| 
									
										
										
										
											2010-02-12 13:34:04 +00:00
										 |  |  |  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * The Original Code is Copyright (C) 2007 by Nicholas Bishop | 
					
						
							|  |  |  |  * All rights reserved. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 08:08:12 +11:00
										 |  |  | /** \file
 | 
					
						
							|  |  |  |  * \ingroup bke | 
					
						
							| 
									
										
										
										
											2011-02-27 20:40:57 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | #include "MEM_guardedalloc.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-04 06:05:48 +00:00
										 |  |  | /* for reading old multires */ | 
					
						
							|  |  |  | #define DNA_DEPRECATED_ALLOW
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | #include "DNA_mesh_types.h"
 | 
					
						
							|  |  |  | #include "DNA_meshdata_types.h"
 | 
					
						
							|  |  |  | #include "DNA_object_types.h"
 | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | #include "DNA_scene_types.h"
 | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | #include "BLI_bitmap.h"
 | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | #include "BLI_blenlib.h"
 | 
					
						
							| 
									
										
										
										
											2010-03-22 11:59:36 +00:00
										 |  |  | #include "BLI_math.h"
 | 
					
						
							| 
									
										
										
										
											2018-01-11 17:56:18 +01:00
										 |  |  | #include "BLI_task.h"
 | 
					
						
							| 
									
										
										
										
											2020-03-19 09:33:03 +01:00
										 |  |  | #include "BLI_utildefines.h"
 | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-10 20:33:09 +00:00
										 |  |  | #include "BKE_ccg.h"
 | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | #include "BKE_cdderivedmesh.h"
 | 
					
						
							| 
									
										
										
										
											2020-03-19 09:33:03 +01:00
										 |  |  | #include "BKE_editmesh.h"
 | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | #include "BKE_mesh.h"
 | 
					
						
							| 
									
										
										
										
											2013-12-12 16:26:11 +11:00
										 |  |  | #include "BKE_mesh_mapping.h"
 | 
					
						
							| 
									
										
										
										
											2018-06-05 16:58:08 +02:00
										 |  |  | #include "BKE_mesh_runtime.h"
 | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | #include "BKE_modifier.h"
 | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | #include "BKE_multires.h"
 | 
					
						
							| 
									
										
										
										
											2010-03-22 11:59:36 +00:00
										 |  |  | #include "BKE_paint.h"
 | 
					
						
							| 
									
										
										
										
											2020-03-19 09:33:03 +01:00
										 |  |  | #include "BKE_pbvh.h"
 | 
					
						
							| 
									
										
										
										
											2010-01-25 11:39:56 +00:00
										 |  |  | #include "BKE_scene.h"
 | 
					
						
							| 
									
										
										
										
											2018-09-14 10:56:54 +02:00
										 |  |  | #include "BKE_subdiv_ccg.h"
 | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | #include "BKE_subsurf.h"
 | 
					
						
							| 
									
										
										
										
											2011-01-07 19:18:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-25 08:03:05 +00:00
										 |  |  | #include "BKE_object.h"
 | 
					
						
							| 
									
										
										
										
											2009-11-25 14:07:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "CCGSubSurf.h"
 | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 17:00:24 +02:00
										 |  |  | #include "DEG_depsgraph_query.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-03 12:35:51 +01:00
										 |  |  | #include "multires_reshape.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | #include <math.h>
 | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | #include <string.h>
 | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | /* MULTIRES MODIFIER */ | 
					
						
							|  |  |  | static const int multires_max_levels = 13; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static const int multires_grid_tot[] = { | 
					
						
							|  |  |  |     0, 4, 9, 25, 81, 289, 1089, 4225, 16641, 66049, 263169, 1050625, 4198401, 16785409}; | 
					
						
							|  |  |  | static const int multires_side_tot[] = { | 
					
						
							|  |  |  |     0, 2, 3, 5, 9, 17, 33, 65, 129, 257, 513, 1025, 2049, 4097}; | 
					
						
							| 
									
										
										
										
											2009-11-25 14:07:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-26 04:40:56 +00:00
										 |  |  | /* See multiresModifier_disp_run for description of each operation */ | 
					
						
							|  |  |  | typedef enum { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   APPLY_DISPLACEMENTS, | 
					
						
							|  |  |  |   CALC_DISPLACEMENTS, | 
					
						
							|  |  |  |   ADD_DISPLACEMENTS, | 
					
						
							| 
									
										
										
										
											2012-02-26 04:40:56 +00:00
										 |  |  | } DispOp; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-21 15:55:10 +00:00
										 |  |  | static void multires_mvert_to_ss(DerivedMesh *dm, MVert *mvert); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void multiresModifier_disp_run( | 
					
						
							|  |  |  |     DerivedMesh *dm, Mesh *me, DerivedMesh *dm2, DispOp op, CCGElem **oldGridData, int totlvl); | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-19 15:17:46 +11:00
										 |  |  | /** Customdata */ | 
					
						
							| 
									
										
										
										
											2012-03-19 05:13:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | void multires_customdata_delete(Mesh *me) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (me->edit_mesh) { | 
					
						
							|  |  |  |     BMEditMesh *em = me->edit_mesh; | 
					
						
							|  |  |  |     /* CustomData_external_remove is used here only to mark layer
 | 
					
						
							|  |  |  |      * as non-external for further free-ing, so zero element count | 
					
						
							|  |  |  |      * looks safer than em->totface */ | 
					
						
							|  |  |  |     CustomData_external_remove(&em->bm->ldata, &me->id, CD_MDISPS, 0); | 
					
						
							| 
									
										
											  
											
												Add mask support to CCGSubSurf and multires.
* Add new CCG function ccgSubSurf_setAllocMask(). Similar to to
  ccgSubSurf_setCalcVertexNormals(), it sets whether the CCG elements
  have a mask layer and what that layer's offset is. Unlike normals
  however, it doesn't change any behavior during CCG calculation; it's
  there only to give CCGKey information on the mask.
* Add a new flag to _getSubSurf(), CCG_ALLOC_MASK. If set, space for
  an extra layer is allocated, but the number of CCG layers is not set
  to include it. This is done because GridPaintMasks are absolute,
  rather than being relative to the subdivided output (as MDisp
  displacements are), so we skip subdividing paint masks here.
* Add a new flag to subsurf_make_derived_from_derived(),
  SUBSURF_ALLOC_PAINT_MASK. This controls whether CCG_ALLOC_MASK is
  set for _getSubSurf(). Related, masks are never loaded in during
  ss_sync_from_derivedmesh(). After subdivision is finished, if the
  alloc mask flag is set, the number of CCG layers is increase to 4
  with ccgSubSurf_setNumLayers().
* Add a new flag to multires_make_from_derived(),
  MULTIRES_ALLOC_PAINT_MASK. Not all multires functions need paint
  mask data (e.g. multiresModifier_base_apply.) This flag is always
  set in MOD_multires.c so that subdividing a mesh with a mask updates
  properly even when not in sculpt mode.
* Update multiresModifier_disp_run() to apply, calculate, and add mask
  elements. It's almost the same as the existing operations with xyz
  coordinates, but treats masks as absolute rather than displacements
  relative to subdivided values.
* Update multires_customdata_delete to free CD_GRID_PAINT_MASK in
  addition to CD_MDISPS.
* Update multires_del_higher() to call the new function
  multires_grid_paint_mask_downsample(), which allocates a
  lower-resolution paint mask grid and copies values over from the
  high-resolution grid.
											
										 
											2012-05-10 20:34:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-20 12:23:14 +01:00
										 |  |  |     if (CustomData_has_layer(&em->bm->ldata, CD_MDISPS)) { | 
					
						
							|  |  |  |       BM_data_layer_free(em->bm, &em->bm->ldata, CD_MDISPS); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (CustomData_has_layer(&em->bm->ldata, CD_GRID_PAINT_MASK)) { | 
					
						
							|  |  |  |       BM_data_layer_free(em->bm, &em->bm->ldata, CD_GRID_PAINT_MASK); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     CustomData_external_remove(&me->ldata, &me->id, CD_MDISPS, me->totloop); | 
					
						
							|  |  |  |     CustomData_free_layer_active(&me->ldata, CD_MDISPS, me->totloop); | 
					
						
							| 
									
										
											  
											
												Add mask support to CCGSubSurf and multires.
* Add new CCG function ccgSubSurf_setAllocMask(). Similar to to
  ccgSubSurf_setCalcVertexNormals(), it sets whether the CCG elements
  have a mask layer and what that layer's offset is. Unlike normals
  however, it doesn't change any behavior during CCG calculation; it's
  there only to give CCGKey information on the mask.
* Add a new flag to _getSubSurf(), CCG_ALLOC_MASK. If set, space for
  an extra layer is allocated, but the number of CCG layers is not set
  to include it. This is done because GridPaintMasks are absolute,
  rather than being relative to the subdivided output (as MDisp
  displacements are), so we skip subdividing paint masks here.
* Add a new flag to subsurf_make_derived_from_derived(),
  SUBSURF_ALLOC_PAINT_MASK. This controls whether CCG_ALLOC_MASK is
  set for _getSubSurf(). Related, masks are never loaded in during
  ss_sync_from_derivedmesh(). After subdivision is finished, if the
  alloc mask flag is set, the number of CCG layers is increase to 4
  with ccgSubSurf_setNumLayers().
* Add a new flag to multires_make_from_derived(),
  MULTIRES_ALLOC_PAINT_MASK. Not all multires functions need paint
  mask data (e.g. multiresModifier_base_apply.) This flag is always
  set in MOD_multires.c so that subdividing a mesh with a mask updates
  properly even when not in sculpt mode.
* Update multiresModifier_disp_run() to apply, calculate, and add mask
  elements. It's almost the same as the existing operations with xyz
  coordinates, but treats masks as absolute rather than displacements
  relative to subdivided values.
* Update multires_customdata_delete to free CD_GRID_PAINT_MASK in
  addition to CD_MDISPS.
* Update multires_del_higher() to call the new function
  multires_grid_paint_mask_downsample(), which allocates a
  lower-resolution paint mask grid and copies values over from the
  high-resolution grid.
											
										 
											2012-05-10 20:34:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     CustomData_free_layer_active(&me->ldata, CD_GRID_PAINT_MASK, me->totloop); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2012-03-19 05:13:41 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-19 15:17:46 +11:00
										 |  |  | /** Grid hiding */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static BLI_bitmap *multires_mdisps_upsample_hidden(BLI_bitmap *lo_hidden, | 
					
						
							|  |  |  |                                                    int lo_level, | 
					
						
							|  |  |  |                                                    int hi_level, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                                                    /* assumed to be at hi_level (or null) */ | 
					
						
							|  |  |  |                                                    const BLI_bitmap *prev_hidden) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   BLI_bitmap *subd; | 
					
						
							|  |  |  |   int hi_gridsize = BKE_ccg_gridsize(hi_level); | 
					
						
							|  |  |  |   int lo_gridsize = BKE_ccg_gridsize(lo_level); | 
					
						
							|  |  |  |   int yh, xh, xl, yl, xo, yo, hi_ndx; | 
					
						
							|  |  |  |   int offset, factor; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   BLI_assert(lo_level <= hi_level); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* fast case */ | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (lo_level == hi_level) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return MEM_dupallocN(lo_hidden); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-06 17:18:10 +01:00
										 |  |  |   subd = BLI_BITMAP_NEW(square_i(hi_gridsize), "MDisps.hidden upsample"); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   factor = BKE_ccg_factor(lo_level, hi_level); | 
					
						
							|  |  |  |   offset = 1 << (hi_level - lo_level - 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* low-res blocks */ | 
					
						
							|  |  |  |   for (yl = 0; yl < lo_gridsize; yl++) { | 
					
						
							|  |  |  |     for (xl = 0; xl < lo_gridsize; xl++) { | 
					
						
							|  |  |  |       int lo_val = BLI_BITMAP_TEST(lo_hidden, yl * lo_gridsize + xl); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* high-res blocks */ | 
					
						
							|  |  |  |       for (yo = -offset; yo <= offset; yo++) { | 
					
						
							|  |  |  |         yh = yl * factor + yo; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |         if (yh < 0 || yh >= hi_gridsize) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           continue; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         for (xo = -offset; xo <= offset; xo++) { | 
					
						
							|  |  |  |           xh = xl * factor + xo; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |           if (xh < 0 || xh >= hi_gridsize) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |             continue; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |           hi_ndx = yh * hi_gridsize + xh; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           if (prev_hidden) { | 
					
						
							|  |  |  |             /* If prev_hidden is available, copy it to
 | 
					
						
							|  |  |  |              * subd, except when the equivalent element in | 
					
						
							|  |  |  |              * lo_hidden is different */ | 
					
						
							|  |  |  |             if (lo_val != prev_hidden[hi_ndx]) { | 
					
						
							|  |  |  |               BLI_BITMAP_SET(subd, hi_ndx, lo_val); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else { | 
					
						
							|  |  |  |               BLI_BITMAP_SET(subd, hi_ndx, prev_hidden[hi_ndx]); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           else { | 
					
						
							|  |  |  |             BLI_BITMAP_SET(subd, hi_ndx, lo_val); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return subd; | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-22 23:20:48 +00:00
										 |  |  | static BLI_bitmap *multires_mdisps_downsample_hidden(BLI_bitmap *old_hidden, | 
					
						
							|  |  |  |                                                      int old_level, | 
					
						
							|  |  |  |                                                      int new_level) | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BLI_bitmap *new_hidden; | 
					
						
							|  |  |  |   int new_gridsize = BKE_ccg_gridsize(new_level); | 
					
						
							|  |  |  |   int old_gridsize = BKE_ccg_gridsize(old_level); | 
					
						
							|  |  |  |   int x, y, factor, old_value; | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BLI_assert(new_level <= old_level); | 
					
						
							|  |  |  |   factor = BKE_ccg_factor(new_level, old_level); | 
					
						
							| 
									
										
										
										
											2020-03-06 17:18:10 +01:00
										 |  |  |   new_hidden = BLI_BITMAP_NEW(square_i(new_gridsize), "downsample hidden"); | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   for (y = 0; y < new_gridsize; y++) { | 
					
						
							|  |  |  |     for (x = 0; x < new_gridsize; x++) { | 
					
						
							|  |  |  |       old_value = BLI_BITMAP_TEST(old_hidden, factor * y * old_gridsize + x * factor); | 
					
						
							| 
									
										
										
										
											2018-06-17 17:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       BLI_BITMAP_SET(new_hidden, y * new_gridsize + x, old_value); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return new_hidden; | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void multires_output_hidden_to_ccgdm(CCGDerivedMesh *ccgdm, Mesh *me, int level) | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   const MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); | 
					
						
							|  |  |  |   BLI_bitmap **grid_hidden = ccgdm->gridHidden; | 
					
						
							|  |  |  |   int *gridOffset; | 
					
						
							|  |  |  |   int i, j; | 
					
						
							| 
									
										
										
										
											2018-06-17 17:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   gridOffset = ccgdm->dm.getGridOffset(&ccgdm->dm); | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   for (i = 0; i < me->totpoly; i++) { | 
					
						
							|  |  |  |     for (j = 0; j < me->mpoly[i].totloop; j++) { | 
					
						
							|  |  |  |       int g = gridOffset[i] + j; | 
					
						
							|  |  |  |       const MDisps *md = &mdisps[g]; | 
					
						
							|  |  |  |       BLI_bitmap *gh = md->hidden; | 
					
						
							| 
									
										
										
										
											2018-06-17 17:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       if (gh) { | 
					
						
							|  |  |  |         grid_hidden[g] = multires_mdisps_downsample_hidden(gh, md->level, level); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* subdivide mdisps.hidden if needed (assumes that md.level reflects
 | 
					
						
							| 
									
										
										
										
											2012-04-22 11:54:53 +00:00
										 |  |  |  * the current level of md.hidden) */ | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | static void multires_mdisps_subdivide_hidden(MDisps *md, int new_level) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BLI_bitmap *subd; | 
					
						
							| 
									
										
										
										
											2018-06-17 17:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BLI_assert(md->hidden); | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* nothing to do if already subdivided enough */ | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (md->level >= new_level) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   subd = multires_mdisps_upsample_hidden(md->hidden, md->level, new_level, NULL); | 
					
						
							| 
									
										
										
										
											2018-06-17 17:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* swap in the subdivided data */ | 
					
						
							|  |  |  |   MEM_freeN(md->hidden); | 
					
						
							|  |  |  |   md->hidden = subd; | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static MDisps *multires_mdisps_initialize_hidden(Mesh *me, int level) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   MDisps *mdisps = CustomData_add_layer(&me->ldata, CD_MDISPS, CD_CALLOC, NULL, me->totloop); | 
					
						
							|  |  |  |   int gridsize = BKE_ccg_gridsize(level); | 
					
						
							| 
									
										
										
										
											2020-03-06 17:18:10 +01:00
										 |  |  |   int gridarea = square_i(gridsize); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   int i, j; | 
					
						
							| 
									
										
										
										
											2018-06-17 17:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   for (i = 0; i < me->totpoly; i++) { | 
					
						
							|  |  |  |     bool hide = false; | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     for (j = 0; j < me->mpoly[i].totloop; j++) { | 
					
						
							|  |  |  |       if (me->mvert[me->mloop[me->mpoly[i].loopstart + j].v].flag & ME_HIDE) { | 
					
						
							|  |  |  |         hide = true; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     if (!hide) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       continue; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     for (j = 0; j < me->mpoly[i].totloop; j++) { | 
					
						
							|  |  |  |       MDisps *md = &mdisps[me->mpoly[i].loopstart + j]; | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       BLI_assert(!md->hidden); | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       md->hidden = BLI_BITMAP_NEW(gridarea, "MDisps.hidden initialize"); | 
					
						
							|  |  |  |       BLI_bitmap_set_all(md->hidden, true, gridarea); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return mdisps; | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-17 14:20:14 +01:00
										 |  |  | Mesh *BKE_multires_create_mesh(struct Depsgraph *depsgraph, | 
					
						
							|  |  |  |                                Object *object, | 
					
						
							|  |  |  |                                MultiresModifierData *mmd) | 
					
						
							| 
									
										
										
										
											2018-08-16 13:00:24 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-17 14:20:14 +01:00
										 |  |  |   Object *object_eval = DEG_get_evaluated_object(depsgraph, object); | 
					
						
							| 
									
										
										
										
											2020-03-17 14:18:27 +01:00
										 |  |  |   Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); | 
					
						
							| 
									
										
										
										
											2020-03-17 14:20:14 +01:00
										 |  |  |   Mesh *deformed_mesh = mesh_get_eval_deform( | 
					
						
							|  |  |  |       depsgraph, scene_eval, object_eval, &CD_MASK_BAREMESH); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   ModifierEvalContext modifier_ctx = { | 
					
						
							|  |  |  |       .depsgraph = depsgraph, | 
					
						
							| 
									
										
										
										
											2020-03-17 14:20:14 +01:00
										 |  |  |       .object = object_eval, | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       .flag = MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY, | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2018-09-20 12:04:17 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-08 10:14:02 +02:00
										 |  |  |   const ModifierTypeInfo *mti = BKE_modifier_get_info(mmd->modifier.type); | 
					
						
							| 
									
										
										
										
											2020-04-21 13:09:41 +02:00
										 |  |  |   Mesh *result = mti->modifyMesh(&mmd->modifier, &modifier_ctx, deformed_mesh); | 
					
						
							| 
									
										
										
										
											2018-09-20 12:04:17 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (result == deformed_mesh) { | 
					
						
							|  |  |  |     result = BKE_mesh_copy_for_eval(deformed_mesh, true); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return result; | 
					
						
							| 
									
										
										
										
											2018-08-16 13:00:24 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-17 17:34:04 +01:00
										 |  |  | float (*BKE_multires_create_deformed_base_mesh_vert_coords(struct Depsgraph *depsgraph, | 
					
						
							|  |  |  |                                                            struct Object *object, | 
					
						
							|  |  |  |                                                            struct MultiresModifierData *mmd, | 
					
						
							|  |  |  |                                                            int *r_num_deformed_verts))[3] | 
					
						
							| 
									
										
										
										
											2020-03-17 15:55:59 +01:00
										 |  |  | { | 
					
						
							|  |  |  |   Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); | 
					
						
							|  |  |  |   Object *object_eval = DEG_get_evaluated_object(depsgraph, object); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Object object_for_eval = *object_eval; | 
					
						
							|  |  |  |   object_for_eval.data = object->data; | 
					
						
							| 
									
										
										
										
											2020-03-27 11:27:49 +01:00
										 |  |  |   object_for_eval.sculpt = NULL; | 
					
						
							| 
									
										
										
										
											2020-03-17 15:55:59 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-17 17:34:04 +01:00
										 |  |  |   const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); | 
					
						
							|  |  |  |   ModifierEvalContext mesh_eval_context = {depsgraph, &object_for_eval, 0}; | 
					
						
							|  |  |  |   if (use_render) { | 
					
						
							|  |  |  |     mesh_eval_context.flag |= MOD_APPLY_RENDER; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   VirtualModifierData virtual_modifier_data; | 
					
						
							| 
									
										
										
										
											2020-05-08 10:14:02 +02:00
										 |  |  |   ModifierData *first_md = BKE_modifiers_get_virtual_modifierlist(&object_for_eval, | 
					
						
							| 
									
										
										
										
											2020-05-08 19:02:03 +10:00
										 |  |  |                                                                   &virtual_modifier_data); | 
					
						
							| 
									
										
										
										
											2020-03-17 17:34:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Mesh *base_mesh = object->data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int num_deformed_verts; | 
					
						
							|  |  |  |   float(*deformed_verts)[3] = BKE_mesh_vert_coords_alloc(base_mesh, &num_deformed_verts); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (ModifierData *md = first_md; md != NULL; md = md->next) { | 
					
						
							| 
									
										
										
										
											2020-05-08 10:14:02 +02:00
										 |  |  |     const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); | 
					
						
							| 
									
										
										
										
											2020-03-17 17:34:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (md == &mmd->modifier) { | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-08 10:14:02 +02:00
										 |  |  |     if (!BKE_modifier_is_enabled(scene_eval, md, required_mode)) { | 
					
						
							| 
									
										
										
										
											2020-03-17 17:34:04 +01:00
										 |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (mti->type != eModifierTypeType_OnlyDeform) { | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-08 19:02:03 +10:00
										 |  |  |     BKE_modifier_deform_verts( | 
					
						
							|  |  |  |         md, &mesh_eval_context, base_mesh, deformed_verts, num_deformed_verts); | 
					
						
							| 
									
										
										
										
											2020-03-17 17:34:04 +01:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-03-17 15:55:59 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-17 17:34:04 +01:00
										 |  |  |   if (r_num_deformed_verts != NULL) { | 
					
						
							|  |  |  |     *r_num_deformed_verts = num_deformed_verts; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return deformed_verts; | 
					
						
							| 
									
										
										
										
											2020-03-17 15:55:59 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-05 12:20:49 +00:00
										 |  |  | MultiresModifierData *find_multires_modifier_before(Scene *scene, ModifierData *lastmd) | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   ModifierData *md; | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   for (md = lastmd; md; md = md->prev) { | 
					
						
							|  |  |  |     if (md->type == eModifierType_Multires) { | 
					
						
							| 
									
										
										
										
											2020-05-08 10:14:02 +02:00
										 |  |  |       if (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         return (MultiresModifierData *)md; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return NULL; | 
					
						
							| 
									
										
										
										
											2009-11-25 14:07:12 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2009-05-23 07:12:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-31 20:02:51 +00:00
										 |  |  | /* used for applying scale on mdisps layer and syncing subdivide levels when joining objects
 | 
					
						
							| 
									
										
										
										
											2012-03-09 18:28:30 +00:00
										 |  |  |  * use_first - return first multires modifier if all multires'es are disabled | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2013-03-19 23:17:44 +00:00
										 |  |  | MultiresModifierData *get_multires_modifier(Scene *scene, Object *ob, bool use_first) | 
					
						
							| 
									
										
										
										
											2010-10-25 08:03:05 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   ModifierData *md; | 
					
						
							|  |  |  |   MultiresModifierData *mmd = NULL, *firstmmd = NULL; | 
					
						
							| 
									
										
										
										
											2010-10-25 08:03:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* find first active multires modifier */ | 
					
						
							|  |  |  |   for (md = ob->modifiers.first; md; md = md->next) { | 
					
						
							|  |  |  |     if (md->type == eModifierType_Multires) { | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       if (!firstmmd) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         firstmmd = (MultiresModifierData *)md; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2010-10-25 08:03:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-08 10:14:02 +02:00
										 |  |  |       if (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         mmd = (MultiresModifierData *)md; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-10-25 08:03:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (!mmd && use_first) { | 
					
						
							|  |  |  |     /* active multires have not been found
 | 
					
						
							|  |  |  |      * try to use first one */ | 
					
						
							|  |  |  |     return firstmmd; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-10-25 08:03:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return mmd; | 
					
						
							| 
									
										
										
										
											2010-10-25 08:03:05 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | int multires_get_level(const Scene *scene, | 
					
						
							|  |  |  |                        const Object *ob, | 
					
						
							|  |  |  |                        const MultiresModifierData *mmd, | 
					
						
							|  |  |  |                        bool render, | 
					
						
							|  |  |  |                        bool ignore_simplify) | 
					
						
							| 
									
										
										
										
											2009-11-25 14:07:12 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (render) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return (scene != NULL) ? get_render_subsurf_level(&scene->r, mmd->renderlvl, true) : | 
					
						
							|  |  |  |                              mmd->renderlvl; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							|  |  |  |   else if (ob->mode == OB_MODE_SCULPT) { | 
					
						
							| 
									
										
										
										
											2020-04-30 15:41:45 +02:00
										 |  |  |     return mmd->sculptlvl; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							|  |  |  |   else if (ignore_simplify) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return mmd->lvl; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return (scene != NULL) ? get_render_subsurf_level(&scene->r, mmd->lvl, false) : mmd->lvl; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-05-23 07:12:55 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-05 18:20:27 +02:00
										 |  |  | void multires_set_tot_level(Object *ob, MultiresModifierData *mmd, int lvl) | 
					
						
							| 
									
										
										
										
											2009-05-23 07:12:55 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   mmd->totlvl = lvl; | 
					
						
							| 
									
										
										
										
											2009-11-25 14:07:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (ob->mode != OB_MODE_SCULPT) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     mmd->lvl = CLAMPIS(MAX2(mmd->lvl, lvl), 0, mmd->totlvl); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-11-25 14:07:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   mmd->sculptlvl = CLAMPIS(MAX2(mmd->sculptlvl, lvl), 0, mmd->totlvl); | 
					
						
							|  |  |  |   mmd->renderlvl = CLAMPIS(MAX2(mmd->renderlvl, lvl), 0, mmd->totlvl); | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | static void multires_dm_mark_as_modified(DerivedMesh *dm, MultiresModifiedFlags flags) | 
					
						
							| 
									
										
										
										
											2009-12-21 15:55:10 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; | 
					
						
							|  |  |  |   ccgdm->multires.modified_flags |= flags; | 
					
						
							| 
									
										
										
										
											2009-12-21 15:55:10 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void multires_ccg_mark_as_modified(SubdivCCG *subdiv_ccg, MultiresModifiedFlags flags) | 
					
						
							| 
									
										
										
										
											2018-09-14 10:56:54 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (flags & MULTIRES_COORDS_MODIFIED) { | 
					
						
							|  |  |  |     subdiv_ccg->dirty.coords = true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (flags & MULTIRES_HIDDEN_MODIFIED) { | 
					
						
							|  |  |  |     subdiv_ccg->dirty.hidden = true; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-09-14 10:56:54 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-09 12:12:18 +02:00
										 |  |  | void multires_mark_as_modified(Depsgraph *depsgraph, Object *object, MultiresModifiedFlags flags) | 
					
						
							| 
									
										
										
										
											2009-12-21 15:55:10 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-07-09 12:12:18 +02:00
										 |  |  |   if (object == NULL) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-07-09 12:12:18 +02:00
										 |  |  |   /* NOTE: CCG live inside of evaluated object.
 | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * While this is a bit weird to tag the only one, this is how other areas were built | 
					
						
							|  |  |  |    * historically: they are tagging multires for update and then rely on object re-evaluation to | 
					
						
							|  |  |  |    * do an actual update. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * In a longer term maybe special dependency graph tag can help sanitizing this a bit. */ | 
					
						
							|  |  |  |   Object *object_eval = DEG_get_evaluated_object(depsgraph, object); | 
					
						
							|  |  |  |   Mesh *mesh = object_eval->data; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   SubdivCCG *subdiv_ccg = mesh->runtime.subdiv_ccg; | 
					
						
							|  |  |  |   if (subdiv_ccg == NULL) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   multires_ccg_mark_as_modified(subdiv_ccg, flags); | 
					
						
							| 
									
										
										
										
											2009-12-21 15:55:10 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-28 12:05:48 +01:00
										 |  |  | void multires_flush_sculpt_updates(Object *object) | 
					
						
							| 
									
										
										
										
											2009-12-21 15:55:10 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-02-28 12:08:15 +01:00
										 |  |  |   if (object == NULL || object->sculpt == NULL || object->sculpt->pbvh == NULL) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   SculptSession *sculpt_session = object->sculpt; | 
					
						
							| 
									
										
										
										
											2020-04-02 10:10:13 +02:00
										 |  |  |   if (BKE_pbvh_type(sculpt_session->pbvh) != PBVH_GRIDS || !sculpt_session->multires.active || | 
					
						
							|  |  |  |       sculpt_session->multires.modifier == NULL) { | 
					
						
							| 
									
										
										
										
											2020-02-28 12:08:15 +01:00
										 |  |  |     return; | 
					
						
							| 
									
										
										
										
											2019-09-17 17:24:44 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-02-28 12:08:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-28 12:21:42 +01:00
										 |  |  |   SubdivCCG *subdiv_ccg = sculpt_session->subdiv_ccg; | 
					
						
							|  |  |  |   if (subdiv_ccg == NULL) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!subdiv_ccg->dirty.coords && !subdiv_ccg->dirty.hidden) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-28 12:08:15 +01:00
										 |  |  |   Mesh *mesh = object->data; | 
					
						
							|  |  |  |   multiresModifier_reshapeFromCCG( | 
					
						
							| 
									
										
										
										
											2020-04-02 10:10:13 +02:00
										 |  |  |       sculpt_session->multires.modifier->totlvl, mesh, sculpt_session->subdiv_ccg); | 
					
						
							| 
									
										
										
										
											2020-02-28 12:21:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |   subdiv_ccg->dirty.coords = false; | 
					
						
							|  |  |  |   subdiv_ccg->dirty.hidden = false; | 
					
						
							| 
									
										
										
										
											2019-09-17 17:24:44 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-28 12:05:48 +01:00
										 |  |  | void multires_force_sculpt_rebuild(Object *object) | 
					
						
							| 
									
										
										
										
											2019-09-17 17:24:44 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-02-28 12:05:48 +01:00
										 |  |  |   multires_flush_sculpt_updates(object); | 
					
						
							| 
									
										
										
										
											2019-09-17 17:24:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-28 12:08:15 +01:00
										 |  |  |   if (object == NULL || object->sculpt == NULL) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-09-17 22:15:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-28 12:08:15 +01:00
										 |  |  |   SculptSession *ss = object->sculpt; | 
					
						
							| 
									
										
										
										
											2019-09-17 22:15:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-28 12:08:15 +01:00
										 |  |  |   if (ss->pbvh != NULL) { | 
					
						
							|  |  |  |     BKE_pbvh_free(ss->pbvh); | 
					
						
							|  |  |  |     object->sculpt->pbvh = NULL; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (ss->pmap != NULL) { | 
					
						
							|  |  |  |     MEM_freeN(ss->pmap); | 
					
						
							|  |  |  |     ss->pmap = NULL; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (ss->pmap_mem != NULL) { | 
					
						
							|  |  |  |     MEM_freeN(ss->pmap_mem); | 
					
						
							|  |  |  |     ss->pmap_mem = NULL; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-28 12:05:48 +01:00
										 |  |  | void multires_force_external_reload(Object *object) | 
					
						
							| 
									
										
										
										
											2010-06-01 19:26:35 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-02-28 12:05:48 +01:00
										 |  |  |   Mesh *mesh = BKE_mesh_from_object(object); | 
					
						
							| 
									
										
										
										
											2010-06-01 19:26:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-28 12:05:48 +01:00
										 |  |  |   CustomData_external_reload(&mesh->ldata, &mesh->id, CD_MASK_MDISPS, mesh->totloop); | 
					
						
							|  |  |  |   multires_force_sculpt_rebuild(object); | 
					
						
							| 
									
										
										
										
											2010-02-07 10:16:42 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-09-09 00:14:51 +00:00
										 |  |  | /* reset the multires levels to match the number of mdisps */ | 
					
						
							| 
									
										
										
										
											2010-11-04 16:00:28 +00:00
										 |  |  | static int get_levels_from_disps(Object *ob) | 
					
						
							| 
									
										
										
										
											2010-09-09 00:14:51 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   Mesh *me = ob->data; | 
					
						
							|  |  |  |   MDisps *mdisp, *md; | 
					
						
							|  |  |  |   int i, j, totlvl = 0; | 
					
						
							| 
									
										
										
										
											2010-09-09 00:14:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   mdisp = CustomData_get_layer(&me->ldata, CD_MDISPS); | 
					
						
							| 
									
										
										
										
											2012-03-10 12:26:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (i = 0; i < me->totpoly; i++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     md = mdisp + me->mpoly[i].loopstart; | 
					
						
							| 
									
										
										
										
											2018-06-17 17:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     for (j = 0; j < me->mpoly[i].totloop; j++, md++) { | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       if (md->totdisp == 0) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         continue; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-06-17 17:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       while (1) { | 
					
						
							|  |  |  |         int side = (1 << (totlvl - 1)) + 1; | 
					
						
							|  |  |  |         int lvl_totdisp = side * side; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |         if (md->totdisp == lvl_totdisp) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           break; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |         } | 
					
						
							|  |  |  |         else if (md->totdisp < lvl_totdisp) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           totlvl--; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           totlvl++; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-06-17 17:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-09-09 00:14:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return totlvl; | 
					
						
							| 
									
										
										
										
											2010-11-04 16:00:28 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* reset the multires levels to match the number of mdisps */ | 
					
						
							|  |  |  | void multiresModifier_set_levels_from_disps(MultiresModifierData *mmd, Object *ob) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   Mesh *me = ob->data; | 
					
						
							|  |  |  |   MDisps *mdisp; | 
					
						
							| 
									
										
										
										
											2010-11-04 16:00:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (me->edit_mesh) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     mdisp = CustomData_get_layer(&me->edit_mesh->bm->ldata, CD_MDISPS); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     mdisp = CustomData_get_layer(&me->ldata, CD_MDISPS); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-11-04 16:00:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (mdisp) { | 
					
						
							|  |  |  |     mmd->totlvl = get_levels_from_disps(ob); | 
					
						
							|  |  |  |     mmd->lvl = MIN2(mmd->sculptlvl, mmd->totlvl); | 
					
						
							|  |  |  |     mmd->sculptlvl = MIN2(mmd->sculptlvl, mmd->totlvl); | 
					
						
							|  |  |  |     mmd->renderlvl = MIN2(mmd->renderlvl, mmd->totlvl); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-09-09 00:14:51 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-10 15:02:37 +00:00
										 |  |  | static void multires_set_tot_mdisps(Mesh *me, int lvl) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); | 
					
						
							|  |  |  |   int i; | 
					
						
							| 
									
										
										
										
											2010-05-10 15:02:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (mdisps) { | 
					
						
							|  |  |  |     for (i = 0; i < me->totloop; i++, mdisps++) { | 
					
						
							|  |  |  |       mdisps->totdisp = multires_grid_tot[lvl]; | 
					
						
							|  |  |  |       mdisps->level = lvl; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-05-10 15:02:37 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-29 05:48:18 +00:00
										 |  |  | static void multires_reallocate_mdisps(int totloop, MDisps *mdisps, int lvl) | 
					
						
							| 
									
										
										
										
											2010-05-10 15:02:37 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   int i; | 
					
						
							| 
									
										
										
										
											2010-05-10 15:02:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* reallocate displacements to be filled in */ | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (i = 0; i < totloop; i++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     int totdisp = multires_grid_tot[lvl]; | 
					
						
							|  |  |  |     float(*disps)[3] = MEM_calloc_arrayN(totdisp, 3 * sizeof(float), "multires disps"); | 
					
						
							| 
									
										
										
										
											2010-05-10 15:02:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     if (mdisps[i].disps) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       MEM_freeN(mdisps[i].disps); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-06-17 17:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     if (mdisps[i].level && mdisps[i].hidden) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       multires_mdisps_subdivide_hidden(&mdisps[i], lvl); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-05-10 15:02:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     mdisps[i].disps = disps; | 
					
						
							|  |  |  |     mdisps[i].totdisp = totdisp; | 
					
						
							|  |  |  |     mdisps[i].level = lvl; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-05-10 15:02:37 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-04-13 06:06:49 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-25 14:07:12 +00:00
										 |  |  | static void multires_copy_grid(float (*gridA)[3], float (*gridB)[3], int sizeA, int sizeB) | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   int x, y, j, skip; | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (sizeA > sizeB) { | 
					
						
							|  |  |  |     skip = (sizeA - 1) / (sizeB - 1); | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     for (j = 0, y = 0; y < sizeB; y++) { | 
					
						
							|  |  |  |       for (x = 0; x < sizeB; x++, j++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         copy_v3_v3(gridA[y * skip * sizeA + x * skip], gridB[j]); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     skip = (sizeB - 1) / (sizeA - 1); | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     for (j = 0, y = 0; y < sizeA; y++) { | 
					
						
							|  |  |  |       for (x = 0; x < sizeA; x++, j++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         copy_v3_v3(gridA[j], gridB[y * skip * sizeB + x * skip]); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-10 20:33:09 +00:00
										 |  |  | static void multires_copy_dm_grid(CCGElem *gridA, CCGElem *gridB, CCGKey *keyA, CCGKey *keyB) | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   int x, y, j, skip; | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (keyA->grid_size > keyB->grid_size) { | 
					
						
							|  |  |  |     skip = (keyA->grid_size - 1) / (keyB->grid_size - 1); | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     for (j = 0, y = 0; y < keyB->grid_size; y++) { | 
					
						
							|  |  |  |       for (x = 0; x < keyB->grid_size; x++, j++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         memcpy(CCG_elem_offset_co(keyA, gridA, y * skip * keyA->grid_size + x * skip), | 
					
						
							|  |  |  |                CCG_elem_offset_co(keyB, gridB, j), | 
					
						
							|  |  |  |                keyA->elem_size); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     skip = (keyB->grid_size - 1) / (keyA->grid_size - 1); | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     for (j = 0, y = 0; y < keyA->grid_size; y++) { | 
					
						
							|  |  |  |       for (x = 0; x < keyA->grid_size; x++, j++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         memcpy(CCG_elem_offset_co(keyA, gridA, j), | 
					
						
							|  |  |  |                CCG_elem_offset_co(keyB, gridB, y * skip * keyB->grid_size + x * skip), | 
					
						
							|  |  |  |                keyA->elem_size); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												Add mask support to CCGSubSurf and multires.
* Add new CCG function ccgSubSurf_setAllocMask(). Similar to to
  ccgSubSurf_setCalcVertexNormals(), it sets whether the CCG elements
  have a mask layer and what that layer's offset is. Unlike normals
  however, it doesn't change any behavior during CCG calculation; it's
  there only to give CCGKey information on the mask.
* Add a new flag to _getSubSurf(), CCG_ALLOC_MASK. If set, space for
  an extra layer is allocated, but the number of CCG layers is not set
  to include it. This is done because GridPaintMasks are absolute,
  rather than being relative to the subdivided output (as MDisp
  displacements are), so we skip subdividing paint masks here.
* Add a new flag to subsurf_make_derived_from_derived(),
  SUBSURF_ALLOC_PAINT_MASK. This controls whether CCG_ALLOC_MASK is
  set for _getSubSurf(). Related, masks are never loaded in during
  ss_sync_from_derivedmesh(). After subdivision is finished, if the
  alloc mask flag is set, the number of CCG layers is increase to 4
  with ccgSubSurf_setNumLayers().
* Add a new flag to multires_make_from_derived(),
  MULTIRES_ALLOC_PAINT_MASK. Not all multires functions need paint
  mask data (e.g. multiresModifier_base_apply.) This flag is always
  set in MOD_multires.c so that subdividing a mesh with a mask updates
  properly even when not in sculpt mode.
* Update multiresModifier_disp_run() to apply, calculate, and add mask
  elements. It's almost the same as the existing operations with xyz
  coordinates, but treats masks as absolute rather than displacements
  relative to subdivided values.
* Update multires_customdata_delete to free CD_GRID_PAINT_MASK in
  addition to CD_MDISPS.
* Update multires_del_higher() to call the new function
  multires_grid_paint_mask_downsample(), which allocates a
  lower-resolution paint mask grid and copies values over from the
  high-resolution grid.
											
										 
											2012-05-10 20:34:08 +00:00
										 |  |  | /* Reallocate gpm->data at a lower resolution and copy values over
 | 
					
						
							| 
									
										
										
										
											2012-05-16 23:37:23 +00:00
										 |  |  |  * from the original high-resolution data */ | 
					
						
							| 
									
										
											  
											
												Add mask support to CCGSubSurf and multires.
* Add new CCG function ccgSubSurf_setAllocMask(). Similar to to
  ccgSubSurf_setCalcVertexNormals(), it sets whether the CCG elements
  have a mask layer and what that layer's offset is. Unlike normals
  however, it doesn't change any behavior during CCG calculation; it's
  there only to give CCGKey information on the mask.
* Add a new flag to _getSubSurf(), CCG_ALLOC_MASK. If set, space for
  an extra layer is allocated, but the number of CCG layers is not set
  to include it. This is done because GridPaintMasks are absolute,
  rather than being relative to the subdivided output (as MDisp
  displacements are), so we skip subdividing paint masks here.
* Add a new flag to subsurf_make_derived_from_derived(),
  SUBSURF_ALLOC_PAINT_MASK. This controls whether CCG_ALLOC_MASK is
  set for _getSubSurf(). Related, masks are never loaded in during
  ss_sync_from_derivedmesh(). After subdivision is finished, if the
  alloc mask flag is set, the number of CCG layers is increase to 4
  with ccgSubSurf_setNumLayers().
* Add a new flag to multires_make_from_derived(),
  MULTIRES_ALLOC_PAINT_MASK. Not all multires functions need paint
  mask data (e.g. multiresModifier_base_apply.) This flag is always
  set in MOD_multires.c so that subdividing a mesh with a mask updates
  properly even when not in sculpt mode.
* Update multiresModifier_disp_run() to apply, calculate, and add mask
  elements. It's almost the same as the existing operations with xyz
  coordinates, but treats masks as absolute rather than displacements
  relative to subdivided values.
* Update multires_customdata_delete to free CD_GRID_PAINT_MASK in
  addition to CD_MDISPS.
* Update multires_del_higher() to call the new function
  multires_grid_paint_mask_downsample(), which allocates a
  lower-resolution paint mask grid and copies values over from the
  high-resolution grid.
											
										 
											2012-05-10 20:34:08 +00:00
										 |  |  | static void multires_grid_paint_mask_downsample(GridPaintMask *gpm, int level) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (level < gpm->level) { | 
					
						
							|  |  |  |     int gridsize = BKE_ccg_gridsize(level); | 
					
						
							|  |  |  |     float *data = MEM_calloc_arrayN( | 
					
						
							| 
									
										
										
										
											2020-03-06 17:18:10 +01:00
										 |  |  |         square_i(gridsize), sizeof(float), "multires_grid_paint_mask_downsample"); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     int x, y; | 
					
						
							| 
									
										
											  
											
												Add mask support to CCGSubSurf and multires.
* Add new CCG function ccgSubSurf_setAllocMask(). Similar to to
  ccgSubSurf_setCalcVertexNormals(), it sets whether the CCG elements
  have a mask layer and what that layer's offset is. Unlike normals
  however, it doesn't change any behavior during CCG calculation; it's
  there only to give CCGKey information on the mask.
* Add a new flag to _getSubSurf(), CCG_ALLOC_MASK. If set, space for
  an extra layer is allocated, but the number of CCG layers is not set
  to include it. This is done because GridPaintMasks are absolute,
  rather than being relative to the subdivided output (as MDisp
  displacements are), so we skip subdividing paint masks here.
* Add a new flag to subsurf_make_derived_from_derived(),
  SUBSURF_ALLOC_PAINT_MASK. This controls whether CCG_ALLOC_MASK is
  set for _getSubSurf(). Related, masks are never loaded in during
  ss_sync_from_derivedmesh(). After subdivision is finished, if the
  alloc mask flag is set, the number of CCG layers is increase to 4
  with ccgSubSurf_setNumLayers().
* Add a new flag to multires_make_from_derived(),
  MULTIRES_ALLOC_PAINT_MASK. Not all multires functions need paint
  mask data (e.g. multiresModifier_base_apply.) This flag is always
  set in MOD_multires.c so that subdividing a mesh with a mask updates
  properly even when not in sculpt mode.
* Update multiresModifier_disp_run() to apply, calculate, and add mask
  elements. It's almost the same as the existing operations with xyz
  coordinates, but treats masks as absolute rather than displacements
  relative to subdivided values.
* Update multires_customdata_delete to free CD_GRID_PAINT_MASK in
  addition to CD_MDISPS.
* Update multires_del_higher() to call the new function
  multires_grid_paint_mask_downsample(), which allocates a
  lower-resolution paint mask grid and copies values over from the
  high-resolution grid.
											
										 
											2012-05-10 20:34:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     for (y = 0; y < gridsize; y++) { | 
					
						
							|  |  |  |       for (x = 0; x < gridsize; x++) { | 
					
						
							|  |  |  |         data[y * gridsize + x] = paint_grid_paint_mask(gpm, level, x, y); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
											  
											
												Add mask support to CCGSubSurf and multires.
* Add new CCG function ccgSubSurf_setAllocMask(). Similar to to
  ccgSubSurf_setCalcVertexNormals(), it sets whether the CCG elements
  have a mask layer and what that layer's offset is. Unlike normals
  however, it doesn't change any behavior during CCG calculation; it's
  there only to give CCGKey information on the mask.
* Add a new flag to _getSubSurf(), CCG_ALLOC_MASK. If set, space for
  an extra layer is allocated, but the number of CCG layers is not set
  to include it. This is done because GridPaintMasks are absolute,
  rather than being relative to the subdivided output (as MDisp
  displacements are), so we skip subdividing paint masks here.
* Add a new flag to subsurf_make_derived_from_derived(),
  SUBSURF_ALLOC_PAINT_MASK. This controls whether CCG_ALLOC_MASK is
  set for _getSubSurf(). Related, masks are never loaded in during
  ss_sync_from_derivedmesh(). After subdivision is finished, if the
  alloc mask flag is set, the number of CCG layers is increase to 4
  with ccgSubSurf_setNumLayers().
* Add a new flag to multires_make_from_derived(),
  MULTIRES_ALLOC_PAINT_MASK. Not all multires functions need paint
  mask data (e.g. multiresModifier_base_apply.) This flag is always
  set in MOD_multires.c so that subdividing a mesh with a mask updates
  properly even when not in sculpt mode.
* Update multiresModifier_disp_run() to apply, calculate, and add mask
  elements. It's almost the same as the existing operations with xyz
  coordinates, but treats masks as absolute rather than displacements
  relative to subdivided values.
* Update multires_customdata_delete to free CD_GRID_PAINT_MASK in
  addition to CD_MDISPS.
* Update multires_del_higher() to call the new function
  multires_grid_paint_mask_downsample(), which allocates a
  lower-resolution paint mask grid and copies values over from the
  high-resolution grid.
											
										 
											2012-05-10 20:34:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     MEM_freeN(gpm->data); | 
					
						
							|  |  |  |     gpm->data = data; | 
					
						
							|  |  |  |     gpm->level = level; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
											  
											
												Add mask support to CCGSubSurf and multires.
* Add new CCG function ccgSubSurf_setAllocMask(). Similar to to
  ccgSubSurf_setCalcVertexNormals(), it sets whether the CCG elements
  have a mask layer and what that layer's offset is. Unlike normals
  however, it doesn't change any behavior during CCG calculation; it's
  there only to give CCGKey information on the mask.
* Add a new flag to _getSubSurf(), CCG_ALLOC_MASK. If set, space for
  an extra layer is allocated, but the number of CCG layers is not set
  to include it. This is done because GridPaintMasks are absolute,
  rather than being relative to the subdivided output (as MDisp
  displacements are), so we skip subdividing paint masks here.
* Add a new flag to subsurf_make_derived_from_derived(),
  SUBSURF_ALLOC_PAINT_MASK. This controls whether CCG_ALLOC_MASK is
  set for _getSubSurf(). Related, masks are never loaded in during
  ss_sync_from_derivedmesh(). After subdivision is finished, if the
  alloc mask flag is set, the number of CCG layers is increase to 4
  with ccgSubSurf_setNumLayers().
* Add a new flag to multires_make_from_derived(),
  MULTIRES_ALLOC_PAINT_MASK. Not all multires functions need paint
  mask data (e.g. multiresModifier_base_apply.) This flag is always
  set in MOD_multires.c so that subdividing a mesh with a mask updates
  properly even when not in sculpt mode.
* Update multiresModifier_disp_run() to apply, calculate, and add mask
  elements. It's almost the same as the existing operations with xyz
  coordinates, but treats masks as absolute rather than displacements
  relative to subdivided values.
* Update multires_customdata_delete to free CD_GRID_PAINT_MASK in
  addition to CD_MDISPS.
* Update multires_del_higher() to call the new function
  multires_grid_paint_mask_downsample(), which allocates a
  lower-resolution paint mask grid and copies values over from the
  high-resolution grid.
											
										 
											2012-05-10 20:34:08 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-05 18:20:27 +02:00
										 |  |  | static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl) | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   Mesh *me = (Mesh *)ob->data; | 
					
						
							|  |  |  |   int levels = mmd->totlvl - lvl; | 
					
						
							|  |  |  |   MDisps *mdisps; | 
					
						
							|  |  |  |   GridPaintMask *gpm; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   multires_set_tot_mdisps(me, mmd->totlvl); | 
					
						
							| 
									
										
										
										
											2020-03-13 16:13:32 +01:00
										 |  |  |   multiresModifier_ensure_external_read(me, mmd); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); | 
					
						
							|  |  |  |   gpm = CustomData_get_layer(&me->ldata, CD_GRID_PAINT_MASK); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-17 17:24:44 +02:00
										 |  |  |   multires_force_sculpt_rebuild(ob); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (mdisps && levels > 0) { | 
					
						
							|  |  |  |     if (lvl > 0) { | 
					
						
							|  |  |  |       /* MLoop *ml = me->mloop; */ /*UNUSED*/ | 
					
						
							|  |  |  |       int nsize = multires_side_tot[lvl]; | 
					
						
							|  |  |  |       int hsize = multires_side_tot[mmd->totlvl]; | 
					
						
							|  |  |  |       int i, j; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |       for (i = 0; i < me->totpoly; i++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         for (j = 0; j < me->mpoly[i].totloop; j++) { | 
					
						
							|  |  |  |           int g = me->mpoly[i].loopstart + j; | 
					
						
							|  |  |  |           MDisps *mdisp = &mdisps[g]; | 
					
						
							|  |  |  |           float(*disps)[3], (*ndisps)[3], (*hdisps)[3]; | 
					
						
							|  |  |  |           int totdisp = multires_grid_tot[lvl]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           disps = MEM_calloc_arrayN(totdisp, 3 * sizeof(float), "multires disps"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-17 15:10:28 +02:00
										 |  |  |           if (mdisp->disps != NULL) { | 
					
						
							|  |  |  |             ndisps = disps; | 
					
						
							|  |  |  |             hdisps = mdisp->disps; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             multires_copy_grid(ndisps, hdisps, nsize, hsize); | 
					
						
							|  |  |  |             if (mdisp->hidden) { | 
					
						
							|  |  |  |               BLI_bitmap *gh = multires_mdisps_downsample_hidden(mdisp->hidden, mdisp->level, lvl); | 
					
						
							|  |  |  |               MEM_freeN(mdisp->hidden); | 
					
						
							|  |  |  |               mdisp->hidden = gh; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-17 15:10:28 +02:00
										 |  |  |             MEM_freeN(mdisp->disps); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |           mdisp->disps = disps; | 
					
						
							|  |  |  |           mdisp->totdisp = totdisp; | 
					
						
							|  |  |  |           mdisp->level = lvl; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           if (gpm) { | 
					
						
							|  |  |  |             multires_grid_paint_mask_downsample(&gpm[g], lvl); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       multires_customdata_delete(me); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   multires_set_tot_level(ob, mmd, lvl); | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-27 19:40:36 +00:00
										 |  |  | /* (direction = 1) for delete higher, (direction = 0) for lower (not implemented yet) */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | void multiresModifier_del_levels(MultiresModifierData *mmd, | 
					
						
							|  |  |  |                                  Scene *scene, | 
					
						
							|  |  |  |                                  Object *ob, | 
					
						
							|  |  |  |                                  int direction) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   Mesh *me = BKE_mesh_from_object(ob); | 
					
						
							|  |  |  |   int lvl = multires_get_level(scene, ob, mmd, false, true); | 
					
						
							|  |  |  |   int levels = mmd->totlvl - lvl; | 
					
						
							|  |  |  |   MDisps *mdisps; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   multires_set_tot_mdisps(me, mmd->totlvl); | 
					
						
							| 
									
										
										
										
											2020-03-13 16:13:32 +01:00
										 |  |  |   multiresModifier_ensure_external_read(me, mmd); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-17 17:24:44 +02:00
										 |  |  |   multires_force_sculpt_rebuild(ob); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (mdisps && levels > 0 && direction == 1) { | 
					
						
							|  |  |  |     multires_del_higher(mmd, ob, lvl); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   multires_set_tot_level(ob, mmd, lvl); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static DerivedMesh *multires_dm_create_local(Scene *scene, | 
					
						
							|  |  |  |                                              Object *ob, | 
					
						
							|  |  |  |                                              DerivedMesh *dm, | 
					
						
							|  |  |  |                                              int lvl, | 
					
						
							|  |  |  |                                              int totlvl, | 
					
						
							|  |  |  |                                              int simple, | 
					
						
							|  |  |  |                                              bool alloc_paint_mask, | 
					
						
							|  |  |  |                                              int flags) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   MultiresModifierData mmd = {{NULL}}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   mmd.lvl = lvl; | 
					
						
							|  |  |  |   mmd.sculptlvl = lvl; | 
					
						
							|  |  |  |   mmd.renderlvl = lvl; | 
					
						
							|  |  |  |   mmd.totlvl = totlvl; | 
					
						
							|  |  |  |   mmd.simple = simple; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   flags |= MULTIRES_USE_LOCAL_MMD; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (alloc_paint_mask) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     flags |= MULTIRES_ALLOC_PAINT_MASK; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return multires_make_derived_from_derived(dm, &mmd, scene, ob, flags); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static DerivedMesh *subsurf_dm_create_local(Scene *scene, | 
					
						
							|  |  |  |                                             Object *ob, | 
					
						
							|  |  |  |                                             DerivedMesh *dm, | 
					
						
							|  |  |  |                                             int lvl, | 
					
						
							|  |  |  |                                             bool is_simple, | 
					
						
							|  |  |  |                                             bool is_optimal, | 
					
						
							|  |  |  |                                             bool is_plain_uv, | 
					
						
							|  |  |  |                                             bool alloc_paint_mask, | 
					
						
							|  |  |  |                                             bool for_render, | 
					
						
							|  |  |  |                                             SubsurfFlags flags) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   SubsurfModifierData smd = {{NULL}}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   smd.levels = smd.renderLevels = lvl; | 
					
						
							|  |  |  |   smd.quality = 3; | 
					
						
							|  |  |  |   if (!is_plain_uv) { | 
					
						
							|  |  |  |     smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     smd.uv_smooth = SUBSURF_UV_SMOOTH_NONE; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (is_simple) { | 
					
						
							|  |  |  |     smd.subdivType = ME_SIMPLE_SUBSURF; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (is_optimal) { | 
					
						
							|  |  |  |     smd.flags |= eSubsurfModifierFlag_ControlEdges; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (ob->mode & OB_MODE_EDIT) { | 
					
						
							|  |  |  |     flags |= SUBSURF_IN_EDIT_MODE; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (alloc_paint_mask) { | 
					
						
							|  |  |  |     flags |= SUBSURF_ALLOC_PAINT_MASK; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (for_render) { | 
					
						
							|  |  |  |     flags |= SUBSURF_USE_RENDER_PARAMS; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return subsurf_make_derived_from_derived(dm, &smd, scene, NULL, flags); | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-03 12:35:51 +01:00
										 |  |  | static void multires_subdivide_legacy( | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     MultiresModifierData *mmd, Scene *scene, Object *ob, int totlvl, int updateblock, int simple) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   Mesh *me = ob->data; | 
					
						
							|  |  |  |   MDisps *mdisps; | 
					
						
							|  |  |  |   const int lvl = mmd->totlvl; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if ((totlvl > multires_max_levels) || (me->totpoly == 0)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   BLI_assert(totlvl > lvl); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-17 17:24:44 +02:00
										 |  |  |   multires_force_sculpt_rebuild(ob); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (!mdisps) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     mdisps = multires_mdisps_initialize_hidden(me, totlvl); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (mdisps->disps && !updateblock && lvl != 0) { | 
					
						
							|  |  |  |     /* upsample */ | 
					
						
							|  |  |  |     DerivedMesh *lowdm, *cddm, *highdm; | 
					
						
							|  |  |  |     CCGElem **highGridData, **lowGridData, **subGridData; | 
					
						
							|  |  |  |     CCGKey highGridKey, lowGridKey; | 
					
						
							|  |  |  |     CCGSubSurf *ss; | 
					
						
							|  |  |  |     int i, numGrids, highGridSize; | 
					
						
							|  |  |  |     const bool has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* create subsurf DM from original mesh at high level */ | 
					
						
							|  |  |  |     cddm = CDDM_from_mesh(me); | 
					
						
							|  |  |  |     DM_set_only_copy(cddm, &CD_MASK_BAREMESH); | 
					
						
							|  |  |  |     highdm = subsurf_dm_create_local(NULL, | 
					
						
							|  |  |  |                                      ob, | 
					
						
							|  |  |  |                                      cddm, | 
					
						
							|  |  |  |                                      totlvl, | 
					
						
							|  |  |  |                                      simple, | 
					
						
							|  |  |  |                                      0, | 
					
						
							|  |  |  |                                      mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, | 
					
						
							|  |  |  |                                      has_mask, | 
					
						
							|  |  |  |                                      false, | 
					
						
							|  |  |  |                                      SUBSURF_IGNORE_SIMPLIFY); | 
					
						
							|  |  |  |     ss = ((CCGDerivedMesh *)highdm)->ss; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* create multires DM from original mesh at low level */ | 
					
						
							|  |  |  |     lowdm = multires_dm_create_local( | 
					
						
							|  |  |  |         scene, ob, cddm, lvl, lvl, simple, has_mask, MULTIRES_IGNORE_SIMPLIFY); | 
					
						
							|  |  |  |     BLI_assert(lowdm != cddm); | 
					
						
							|  |  |  |     cddm->release(cddm); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* copy subsurf grids and replace them with low displaced grids */ | 
					
						
							|  |  |  |     numGrids = highdm->getNumGrids(highdm); | 
					
						
							|  |  |  |     highGridSize = highdm->getGridSize(highdm); | 
					
						
							|  |  |  |     highGridData = highdm->getGridData(highdm); | 
					
						
							|  |  |  |     highdm->getGridKey(highdm, &highGridKey); | 
					
						
							|  |  |  |     lowGridData = lowdm->getGridData(lowdm); | 
					
						
							|  |  |  |     lowdm->getGridKey(lowdm, &lowGridKey); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     subGridData = MEM_calloc_arrayN(numGrids, sizeof(float *), "subGridData*"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |     for (i = 0; i < numGrids; i++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       /* backup subsurf grids */ | 
					
						
							|  |  |  |       subGridData[i] = MEM_calloc_arrayN( | 
					
						
							|  |  |  |           highGridKey.elem_size, highGridSize * highGridSize, "subGridData"); | 
					
						
							|  |  |  |       memcpy(subGridData[i], highGridData[i], highGridKey.elem_size * highGridSize * highGridSize); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* overwrite with current displaced grids */ | 
					
						
							|  |  |  |       multires_copy_dm_grid(highGridData[i], lowGridData[i], &highGridKey, &lowGridKey); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* low lower level dm no longer needed at this point */ | 
					
						
							|  |  |  |     lowdm->release(lowdm); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* subsurf higher levels again with displaced data */ | 
					
						
							|  |  |  |     ccgSubSurf_updateFromFaces(ss, lvl, NULL, 0); | 
					
						
							|  |  |  |     ccgSubSurf_updateLevels(ss, lvl, NULL, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* reallocate displacements */ | 
					
						
							|  |  |  |     multires_reallocate_mdisps(me->totloop, mdisps, totlvl); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* compute displacements */ | 
					
						
							|  |  |  |     multiresModifier_disp_run(highdm, me, NULL, CALC_DISPLACEMENTS, subGridData, totlvl); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* free */ | 
					
						
							|  |  |  |     highdm->release(highdm); | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |     for (i = 0; i < numGrids; i++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       MEM_freeN(subGridData[i]); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     MEM_freeN(subGridData); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     /* only reallocate, nothing to upsample */ | 
					
						
							|  |  |  |     multires_reallocate_mdisps(me->totloop, mdisps, totlvl); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   multires_set_tot_level(ob, mmd, totlvl); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-03 12:35:51 +01:00
										 |  |  | void multiresModifier_subdivide_legacy( | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     MultiresModifierData *mmd, Scene *scene, Object *ob, int updateblock, int simple) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-03 12:35:51 +01:00
										 |  |  |   multires_subdivide_legacy(mmd, scene, ob, mmd->totlvl + 1, updateblock, simple); | 
					
						
							| 
									
										
										
										
											2010-10-25 08:03:05 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-11 08:37:35 +00:00
										 |  |  | static void grid_tangent(const CCGKey *key, int x, int y, int axis, CCGElem *grid, float t[3]) | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (axis == 0) { | 
					
						
							|  |  |  |     if (x == key->grid_size - 1) { | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       if (y == key->grid_size - 1) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         sub_v3_v3v3( | 
					
						
							|  |  |  |             t, CCG_grid_elem_co(key, grid, x, y - 1), CCG_grid_elem_co(key, grid, x - 1, y - 1)); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							|  |  |  |       else { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x, y), CCG_grid_elem_co(key, grid, x - 1, y)); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     else { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x + 1, y), CCG_grid_elem_co(key, grid, x, y)); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   else if (axis == 1) { | 
					
						
							|  |  |  |     if (y == key->grid_size - 1) { | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       if (x == key->grid_size - 1) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         sub_v3_v3v3( | 
					
						
							|  |  |  |             t, CCG_grid_elem_co(key, grid, x - 1, y), CCG_grid_elem_co(key, grid, x - 1, (y - 1))); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							|  |  |  |       else { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x, y), CCG_grid_elem_co(key, grid, x, (y - 1))); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     else { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x, (y + 1)), CCG_grid_elem_co(key, grid, x, y)); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-11 08:37:35 +00:00
										 |  |  | /* Construct 3x3 tangent-space matrix in 'mat' */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void grid_tangent_matrix(float mat[3][3], const CCGKey *key, int x, int y, CCGElem *grid) | 
					
						
							| 
									
										
										
										
											2012-06-11 08:37:35 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   grid_tangent(key, x, y, 0, grid, mat[0]); | 
					
						
							|  |  |  |   normalize_v3(mat[0]); | 
					
						
							| 
									
										
										
										
											2012-06-11 08:37:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   grid_tangent(key, x, y, 1, grid, mat[1]); | 
					
						
							|  |  |  |   normalize_v3(mat[1]); | 
					
						
							| 
									
										
										
										
											2012-06-11 08:37:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   copy_v3_v3(mat[2], CCG_grid_elem_no(key, grid, x, y)); | 
					
						
							| 
									
										
										
										
											2012-06-11 08:37:35 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-11 20:14:16 +01:00
										 |  |  | typedef struct MultiresThreadedData { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   DispOp op; | 
					
						
							|  |  |  |   CCGElem **gridData, **subGridData; | 
					
						
							|  |  |  |   CCGKey *key; | 
					
						
							|  |  |  |   CCGKey *sub_key; | 
					
						
							|  |  |  |   MPoly *mpoly; | 
					
						
							|  |  |  |   MDisps *mdisps; | 
					
						
							|  |  |  |   GridPaintMask *grid_paint_mask; | 
					
						
							|  |  |  |   int *gridOffset; | 
					
						
							|  |  |  |   int gridSize, dGridSize, dSkip; | 
					
						
							|  |  |  |   float (*smat)[3]; | 
					
						
							| 
									
										
										
										
											2018-01-11 20:14:16 +01:00
										 |  |  | } MultiresThreadedData; | 
					
						
							| 
									
										
										
										
											2018-01-11 19:39:24 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void multires_disp_run_cb(void *__restrict userdata, | 
					
						
							|  |  |  |                                  const int pidx, | 
					
						
							| 
									
										
										
										
											2019-07-30 14:56:47 +02:00
										 |  |  |                                  const TaskParallelTLS *__restrict UNUSED(tls)) | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | { | 
					
						
							|  |  |  |   MultiresThreadedData *tdata = userdata; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   DispOp op = tdata->op; | 
					
						
							|  |  |  |   CCGElem **gridData = tdata->gridData; | 
					
						
							|  |  |  |   CCGElem **subGridData = tdata->subGridData; | 
					
						
							|  |  |  |   CCGKey *key = tdata->key; | 
					
						
							|  |  |  |   MPoly *mpoly = tdata->mpoly; | 
					
						
							|  |  |  |   MDisps *mdisps = tdata->mdisps; | 
					
						
							|  |  |  |   GridPaintMask *grid_paint_mask = tdata->grid_paint_mask; | 
					
						
							|  |  |  |   int *gridOffset = tdata->gridOffset; | 
					
						
							|  |  |  |   int gridSize = tdata->gridSize; | 
					
						
							|  |  |  |   int dGridSize = tdata->dGridSize; | 
					
						
							|  |  |  |   int dSkip = tdata->dSkip; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const int numVerts = mpoly[pidx].totloop; | 
					
						
							|  |  |  |   int S, x, y, gIndex = gridOffset[pidx]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (S = 0; S < numVerts; S++, gIndex++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     GridPaintMask *gpm = grid_paint_mask ? &grid_paint_mask[gIndex] : NULL; | 
					
						
							|  |  |  |     MDisps *mdisp = &mdisps[mpoly[pidx].loopstart + S]; | 
					
						
							|  |  |  |     CCGElem *grid = gridData[gIndex]; | 
					
						
							|  |  |  |     CCGElem *subgrid = subGridData[gIndex]; | 
					
						
							|  |  |  |     float(*dispgrid)[3] = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     dispgrid = mdisp->disps; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* if needed, reallocate multires paint mask */ | 
					
						
							|  |  |  |     if (gpm && gpm->level < key->level) { | 
					
						
							|  |  |  |       gpm->level = key->level; | 
					
						
							|  |  |  |       if (gpm->data) { | 
					
						
							|  |  |  |         MEM_freeN(gpm->data); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       gpm->data = MEM_calloc_arrayN(key->grid_area, sizeof(float), "gpm.data"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (y = 0; y < gridSize; y++) { | 
					
						
							|  |  |  |       for (x = 0; x < gridSize; x++) { | 
					
						
							|  |  |  |         float *co = CCG_grid_elem_co(key, grid, x, y); | 
					
						
							|  |  |  |         float *sco = CCG_grid_elem_co(key, subgrid, x, y); | 
					
						
							|  |  |  |         float *data = dispgrid[dGridSize * y * dSkip + x * dSkip]; | 
					
						
							|  |  |  |         float mat[3][3], disp[3], d[3], mask; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* construct tangent space matrix */ | 
					
						
							|  |  |  |         grid_tangent_matrix(mat, key, x, y, subgrid); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         switch (op) { | 
					
						
							|  |  |  |           case APPLY_DISPLACEMENTS: | 
					
						
							|  |  |  |             /* Convert displacement to object space
 | 
					
						
							|  |  |  |              * and add to grid points */ | 
					
						
							|  |  |  |             mul_v3_m3v3(disp, mat, data); | 
					
						
							|  |  |  |             add_v3_v3v3(co, sco, disp); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |           case CALC_DISPLACEMENTS: | 
					
						
							|  |  |  |             /* Calculate displacement between new and old
 | 
					
						
							|  |  |  |              * grid points and convert to tangent space */ | 
					
						
							|  |  |  |             sub_v3_v3v3(disp, co, sco); | 
					
						
							|  |  |  |             invert_m3(mat); | 
					
						
							|  |  |  |             mul_v3_m3v3(data, mat, disp); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |           case ADD_DISPLACEMENTS: | 
					
						
							|  |  |  |             /* Convert subdivided displacements to tangent
 | 
					
						
							|  |  |  |              * space and add to the original displacements */ | 
					
						
							|  |  |  |             invert_m3(mat); | 
					
						
							|  |  |  |             mul_v3_m3v3(d, mat, co); | 
					
						
							|  |  |  |             add_v3_v3(data, d); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (gpm) { | 
					
						
							|  |  |  |           switch (op) { | 
					
						
							|  |  |  |             case APPLY_DISPLACEMENTS: | 
					
						
							|  |  |  |               /* Copy mask from gpm to DM */ | 
					
						
							|  |  |  |               *CCG_grid_elem_mask(key, grid, x, y) = paint_grid_paint_mask(gpm, key->level, x, y); | 
					
						
							|  |  |  |               break; | 
					
						
							|  |  |  |             case CALC_DISPLACEMENTS: | 
					
						
							|  |  |  |               /* Copy mask from DM to gpm */ | 
					
						
							|  |  |  |               mask = *CCG_grid_elem_mask(key, grid, x, y); | 
					
						
							|  |  |  |               gpm->data[y * gridSize + x] = CLAMPIS(mask, 0, 1); | 
					
						
							|  |  |  |               break; | 
					
						
							|  |  |  |             case ADD_DISPLACEMENTS: | 
					
						
							|  |  |  |               /* Add mask displacement to gpm */ | 
					
						
							|  |  |  |               gpm->data[y * gridSize + x] += *CCG_grid_elem_mask(key, grid, x, y); | 
					
						
							|  |  |  |               break; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-01-11 19:39:24 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-13 20:50:32 +00:00
										 |  |  | /* XXX WARNING: subsurf elements from dm and oldGridData *must* be of the same format (size),
 | 
					
						
							|  |  |  |  *              because this code uses CCGKey's info from dm to access oldGridData's normals | 
					
						
							|  |  |  |  *              (through the call to grid_tangent_matrix())! */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void multiresModifier_disp_run( | 
					
						
							|  |  |  |     DerivedMesh *dm, Mesh *me, DerivedMesh *dm2, DispOp op, CCGElem **oldGridData, int totlvl) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; | 
					
						
							|  |  |  |   CCGElem **gridData, **subGridData; | 
					
						
							|  |  |  |   CCGKey key; | 
					
						
							|  |  |  |   MPoly *mpoly = me->mpoly; | 
					
						
							|  |  |  |   MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); | 
					
						
							|  |  |  |   GridPaintMask *grid_paint_mask = NULL; | 
					
						
							|  |  |  |   int *gridOffset; | 
					
						
							|  |  |  |   int i, gridSize, dGridSize, dSkip; | 
					
						
							|  |  |  |   int totloop, totpoly; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* this happens in the dm made by bmesh_mdisps_space_set */ | 
					
						
							|  |  |  |   if (dm2 && CustomData_has_layer(&dm2->loopData, CD_MDISPS)) { | 
					
						
							|  |  |  |     mpoly = CustomData_get_layer(&dm2->polyData, CD_MPOLY); | 
					
						
							|  |  |  |     mdisps = CustomData_get_layer(&dm2->loopData, CD_MDISPS); | 
					
						
							|  |  |  |     totloop = dm2->numLoopData; | 
					
						
							|  |  |  |     totpoly = dm2->numPolyData; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     totloop = me->totloop; | 
					
						
							|  |  |  |     totpoly = me->totpoly; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!mdisps) { | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     if (op == CALC_DISPLACEMENTS) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       mdisps = CustomData_add_layer(&me->ldata, CD_MDISPS, CD_DEFAULT, NULL, me->totloop); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       return; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /*numGrids = dm->getNumGrids(dm);*/ /*UNUSED*/ | 
					
						
							|  |  |  |   gridSize = dm->getGridSize(dm); | 
					
						
							|  |  |  |   gridData = dm->getGridData(dm); | 
					
						
							|  |  |  |   gridOffset = dm->getGridOffset(dm); | 
					
						
							|  |  |  |   dm->getGridKey(dm, &key); | 
					
						
							|  |  |  |   subGridData = (oldGridData) ? oldGridData : gridData; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   dGridSize = multires_side_tot[totlvl]; | 
					
						
							|  |  |  |   dSkip = (dGridSize - 1) / (gridSize - 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* multires paint masks */ | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (key.has_mask) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     grid_paint_mask = CustomData_get_layer(&me->ldata, CD_GRID_PAINT_MASK); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* when adding new faces in edit mode, need to allocate disps */ | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (i = 0; i < totloop; i++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     if (mdisps[i].disps == NULL) { | 
					
						
							|  |  |  |       multires_reallocate_mdisps(totloop, mdisps, totlvl); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-30 14:56:47 +02:00
										 |  |  |   TaskParallelSettings settings; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BLI_parallel_range_settings_defaults(&settings); | 
					
						
							|  |  |  |   settings.min_iter_per_thread = CCG_TASK_LIMIT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   MultiresThreadedData data = { | 
					
						
							|  |  |  |       .op = op, | 
					
						
							|  |  |  |       .gridData = gridData, | 
					
						
							|  |  |  |       .subGridData = subGridData, | 
					
						
							|  |  |  |       .key = &key, | 
					
						
							|  |  |  |       .mpoly = mpoly, | 
					
						
							|  |  |  |       .mdisps = mdisps, | 
					
						
							|  |  |  |       .grid_paint_mask = grid_paint_mask, | 
					
						
							|  |  |  |       .gridOffset = gridOffset, | 
					
						
							|  |  |  |       .gridSize = gridSize, | 
					
						
							|  |  |  |       .dGridSize = dGridSize, | 
					
						
							|  |  |  |       .dSkip = dSkip, | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   BLI_task_parallel_range(0, totpoly, &data, multires_disp_run_cb, &settings); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (op == APPLY_DISPLACEMENTS) { | 
					
						
							|  |  |  |     ccgSubSurf_stitchFaces(ccgdm->ss, 0, NULL, 0); | 
					
						
							|  |  |  |     ccgSubSurf_updateNormals(ccgdm->ss, NULL, 0); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-18 11:21:33 +02:00
										 |  |  | void multires_modifier_update_mdisps(struct DerivedMesh *dm, Scene *scene) | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; | 
					
						
							|  |  |  |   Object *ob; | 
					
						
							|  |  |  |   Mesh *me; | 
					
						
							|  |  |  |   MDisps *mdisps; | 
					
						
							|  |  |  |   MultiresModifierData *mmd; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ob = ccgdm->multires.ob; | 
					
						
							|  |  |  |   me = ccgdm->multires.ob->data; | 
					
						
							|  |  |  |   mmd = ccgdm->multires.mmd; | 
					
						
							|  |  |  |   multires_set_tot_mdisps(me, mmd->totlvl); | 
					
						
							| 
									
										
										
										
											2020-03-13 16:13:32 +01:00
										 |  |  |   multiresModifier_ensure_external_read(me, mmd); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (mdisps) { | 
					
						
							|  |  |  |     int lvl = ccgdm->multires.lvl; | 
					
						
							|  |  |  |     int totlvl = ccgdm->multires.totlvl; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (lvl < totlvl) { | 
					
						
							|  |  |  |       DerivedMesh *lowdm, *cddm, *highdm; | 
					
						
							|  |  |  |       CCGElem **highGridData, **lowGridData, **subGridData, **gridData, *diffGrid; | 
					
						
							|  |  |  |       CCGKey highGridKey, lowGridKey; | 
					
						
							|  |  |  |       CCGSubSurf *ss; | 
					
						
							|  |  |  |       int i, j, numGrids, highGridSize, lowGridSize; | 
					
						
							|  |  |  |       const bool has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-26 16:35:42 +01:00
										 |  |  |       /* Create subsurf DM from original mesh at high level. */ | 
					
						
							|  |  |  |       /* TODO: use mesh_deform_eval when sculpting on deformed mesh. */ | 
					
						
							|  |  |  |       cddm = CDDM_from_mesh(me); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       DM_set_only_copy(cddm, &CD_MASK_BAREMESH); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       highdm = subsurf_dm_create_local(scene, | 
					
						
							|  |  |  |                                        ob, | 
					
						
							|  |  |  |                                        cddm, | 
					
						
							|  |  |  |                                        totlvl, | 
					
						
							|  |  |  |                                        mmd->simple, | 
					
						
							|  |  |  |                                        0, | 
					
						
							|  |  |  |                                        mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, | 
					
						
							|  |  |  |                                        has_mask, | 
					
						
							|  |  |  |                                        false, | 
					
						
							|  |  |  |                                        SUBSURF_IGNORE_SIMPLIFY); | 
					
						
							|  |  |  |       ss = ((CCGDerivedMesh *)highdm)->ss; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* create multires DM from original mesh and displacements */ | 
					
						
							|  |  |  |       lowdm = multires_dm_create_local( | 
					
						
							|  |  |  |           scene, ob, cddm, lvl, totlvl, mmd->simple, has_mask, MULTIRES_IGNORE_SIMPLIFY); | 
					
						
							|  |  |  |       cddm->release(cddm); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* gather grid data */ | 
					
						
							|  |  |  |       numGrids = highdm->getNumGrids(highdm); | 
					
						
							|  |  |  |       highGridSize = highdm->getGridSize(highdm); | 
					
						
							|  |  |  |       highGridData = highdm->getGridData(highdm); | 
					
						
							|  |  |  |       highdm->getGridKey(highdm, &highGridKey); | 
					
						
							|  |  |  |       lowGridSize = lowdm->getGridSize(lowdm); | 
					
						
							|  |  |  |       lowGridData = lowdm->getGridData(lowdm); | 
					
						
							|  |  |  |       lowdm->getGridKey(lowdm, &lowGridKey); | 
					
						
							|  |  |  |       gridData = dm->getGridData(dm); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       BLI_assert(highGridKey.elem_size == lowGridKey.elem_size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       subGridData = MEM_calloc_arrayN(numGrids, sizeof(CCGElem *), "subGridData*"); | 
					
						
							|  |  |  |       diffGrid = MEM_calloc_arrayN(lowGridKey.elem_size, lowGridSize * lowGridSize, "diff"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |       for (i = 0; i < numGrids; i++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         /* backup subsurf grids */ | 
					
						
							|  |  |  |         subGridData[i] = MEM_calloc_arrayN( | 
					
						
							|  |  |  |             highGridKey.elem_size, highGridSize * highGridSize, "subGridData"); | 
					
						
							|  |  |  |         memcpy( | 
					
						
							|  |  |  |             subGridData[i], highGridData[i], highGridKey.elem_size * highGridSize * highGridSize); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* write difference of subsurf and displaced low level into high subsurf */ | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |         for (j = 0; j < lowGridSize * lowGridSize; j++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           sub_v4_v4v4(CCG_elem_offset_co(&lowGridKey, diffGrid, j), | 
					
						
							|  |  |  |                       CCG_elem_offset_co(&lowGridKey, gridData[i], j), | 
					
						
							|  |  |  |                       CCG_elem_offset_co(&lowGridKey, lowGridData[i], j)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         multires_copy_dm_grid(highGridData[i], diffGrid, &highGridKey, &lowGridKey); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* lower level dm no longer needed at this point */ | 
					
						
							|  |  |  |       MEM_freeN(diffGrid); | 
					
						
							|  |  |  |       lowdm->release(lowdm); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* subsurf higher levels again with difference of coordinates */ | 
					
						
							|  |  |  |       ccgSubSurf_updateFromFaces(ss, lvl, NULL, 0); | 
					
						
							|  |  |  |       ccgSubSurf_updateLevels(ss, lvl, NULL, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* add to displacements */ | 
					
						
							|  |  |  |       multiresModifier_disp_run(highdm, me, NULL, ADD_DISPLACEMENTS, subGridData, mmd->totlvl); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* free */ | 
					
						
							|  |  |  |       highdm->release(highdm); | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |       for (i = 0; i < numGrids; i++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         MEM_freeN(subGridData[i]); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       MEM_freeN(subGridData); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       DerivedMesh *cddm, *subdm; | 
					
						
							|  |  |  |       const bool has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-26 16:35:42 +01:00
										 |  |  |       /* TODO: use mesh_deform_eval when sculpting on deformed mesh. */ | 
					
						
							|  |  |  |       cddm = CDDM_from_mesh(me); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       DM_set_only_copy(cddm, &CD_MASK_BAREMESH); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       subdm = subsurf_dm_create_local(scene, | 
					
						
							|  |  |  |                                       ob, | 
					
						
							|  |  |  |                                       cddm, | 
					
						
							|  |  |  |                                       mmd->totlvl, | 
					
						
							|  |  |  |                                       mmd->simple, | 
					
						
							|  |  |  |                                       0, | 
					
						
							|  |  |  |                                       mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, | 
					
						
							|  |  |  |                                       has_mask, | 
					
						
							|  |  |  |                                       false, | 
					
						
							|  |  |  |                                       SUBSURF_IGNORE_SIMPLIFY); | 
					
						
							|  |  |  |       cddm->release(cddm); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       multiresModifier_disp_run( | 
					
						
							|  |  |  |           dm, me, NULL, CALC_DISPLACEMENTS, subdm->getGridData(subdm), mmd->totlvl); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       subdm->release(subdm); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | void multires_modifier_update_hidden(DerivedMesh *dm) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; | 
					
						
							|  |  |  |   BLI_bitmap **grid_hidden = ccgdm->gridHidden; | 
					
						
							|  |  |  |   Mesh *me = ccgdm->multires.ob->data; | 
					
						
							|  |  |  |   MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); | 
					
						
							|  |  |  |   int totlvl = ccgdm->multires.totlvl; | 
					
						
							|  |  |  |   int lvl = ccgdm->multires.lvl; | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (mdisps) { | 
					
						
							|  |  |  |     int i; | 
					
						
							| 
									
										
										
										
											2018-06-17 17:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     for (i = 0; i < me->totloop; i++) { | 
					
						
							|  |  |  |       MDisps *md = &mdisps[i]; | 
					
						
							|  |  |  |       BLI_bitmap *gh = grid_hidden[i]; | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       if (!gh && md->hidden) { | 
					
						
							|  |  |  |         MEM_freeN(md->hidden); | 
					
						
							|  |  |  |         md->hidden = NULL; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else if (gh) { | 
					
						
							|  |  |  |         gh = multires_mdisps_upsample_hidden(gh, lvl, totlvl, md->hidden); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |         if (md->hidden) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           MEM_freeN(md->hidden); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-06-17 17:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         md->hidden = gh; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2012-03-14 06:32:03 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2011-03-29 05:48:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-09 13:37:19 +00:00
										 |  |  | void multires_stitch_grids(Object *ob) | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (ob == NULL) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   SculptSession *sculpt_session = ob->sculpt; | 
					
						
							|  |  |  |   if (sculpt_session == NULL) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   PBVH *pbvh = sculpt_session->pbvh; | 
					
						
							|  |  |  |   SubdivCCG *subdiv_ccg = sculpt_session->subdiv_ccg; | 
					
						
							|  |  |  |   if (pbvh == NULL || subdiv_ccg == NULL) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   BLI_assert(BKE_pbvh_type(pbvh) == PBVH_GRIDS); | 
					
						
							|  |  |  |   /* NOTE: Currently CCG does not keep track of faces, making it impossible
 | 
					
						
							|  |  |  |    * to use BKE_pbvh_get_grid_updates(). | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   CCGFace **faces; | 
					
						
							|  |  |  |   int num_faces; | 
					
						
							|  |  |  |   BKE_pbvh_get_grid_updates(pbvh, false, (void ***)&faces, &num_faces); | 
					
						
							|  |  |  |   if (num_faces) { | 
					
						
							|  |  |  |     BKE_subdiv_ccg_average_stitch_faces(subdiv_ccg, faces, num_faces); | 
					
						
							|  |  |  |     MEM_freeN(faces); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | DerivedMesh *multires_make_derived_from_derived( | 
					
						
							|  |  |  |     DerivedMesh *dm, MultiresModifierData *mmd, Scene *scene, Object *ob, MultiresFlags flags) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   Mesh *me = ob->data; | 
					
						
							|  |  |  |   DerivedMesh *result; | 
					
						
							|  |  |  |   CCGDerivedMesh *ccgdm = NULL; | 
					
						
							|  |  |  |   CCGElem **gridData, **subGridData; | 
					
						
							|  |  |  |   CCGKey key; | 
					
						
							|  |  |  |   const bool render = (flags & MULTIRES_USE_RENDER_PARAMS) != 0; | 
					
						
							|  |  |  |   const bool ignore_simplify = (flags & MULTIRES_IGNORE_SIMPLIFY) != 0; | 
					
						
							|  |  |  |   int lvl = multires_get_level(scene, ob, mmd, render, ignore_simplify); | 
					
						
							|  |  |  |   int i, gridSize, numGrids; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (lvl == 0) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return dm; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const int subsurf_flags = ignore_simplify ? SUBSURF_IGNORE_SIMPLIFY : 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   result = subsurf_dm_create_local(scene, | 
					
						
							|  |  |  |                                    ob, | 
					
						
							|  |  |  |                                    dm, | 
					
						
							|  |  |  |                                    lvl, | 
					
						
							|  |  |  |                                    mmd->simple, | 
					
						
							|  |  |  |                                    mmd->flags & eMultiresModifierFlag_ControlEdges, | 
					
						
							|  |  |  |                                    mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, | 
					
						
							|  |  |  |                                    flags & MULTIRES_ALLOC_PAINT_MASK, | 
					
						
							|  |  |  |                                    render, | 
					
						
							|  |  |  |                                    subsurf_flags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!(flags & MULTIRES_USE_LOCAL_MMD)) { | 
					
						
							|  |  |  |     ccgdm = (CCGDerivedMesh *)result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ccgdm->multires.ob = ob; | 
					
						
							|  |  |  |     ccgdm->multires.mmd = mmd; | 
					
						
							|  |  |  |     ccgdm->multires.local_mmd = 0; | 
					
						
							|  |  |  |     ccgdm->multires.lvl = lvl; | 
					
						
							|  |  |  |     ccgdm->multires.totlvl = mmd->totlvl; | 
					
						
							|  |  |  |     ccgdm->multires.modified_flags = 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   numGrids = result->getNumGrids(result); | 
					
						
							|  |  |  |   gridSize = result->getGridSize(result); | 
					
						
							|  |  |  |   gridData = result->getGridData(result); | 
					
						
							|  |  |  |   result->getGridKey(result, &key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   subGridData = MEM_malloc_arrayN(numGrids, sizeof(CCGElem *), "subGridData*"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (i = 0; i < numGrids; i++) { | 
					
						
							|  |  |  |     subGridData[i] = MEM_malloc_arrayN(key.elem_size, gridSize * gridSize, "subGridData"); | 
					
						
							|  |  |  |     memcpy(subGridData[i], gridData[i], key.elem_size * gridSize * gridSize); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   multires_set_tot_mdisps(me, mmd->totlvl); | 
					
						
							| 
									
										
										
										
											2020-03-13 16:13:32 +01:00
										 |  |  |   multiresModifier_ensure_external_read(me, mmd); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /*run displacement*/ | 
					
						
							|  |  |  |   multiresModifier_disp_run(result, ob->data, dm, APPLY_DISPLACEMENTS, subGridData, mmd->totlvl); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* copy hidden elements for this level */ | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (ccgdm) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     multires_output_hidden_to_ccgdm(ccgdm, me, lvl); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   for (i = 0; i < numGrids; i++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     MEM_freeN(subGridData[i]); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   MEM_freeN(subGridData); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return result; | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /**** Old Multires code ****
 | 
					
						
							| 
									
										
										
										
											2012-05-16 23:37:23 +00:00
										 |  |  |  ***************************/ | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-10 17:37:04 +00:00
										 |  |  | /* Adapted from sculptmode.c */ | 
					
						
							| 
									
										
										
										
											2011-02-12 10:18:21 +00:00
										 |  |  | void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u, float v) | 
					
						
							| 
									
										
										
										
											2009-12-09 13:37:19 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   int x, y, x2, y2; | 
					
						
							|  |  |  |   const int st_max = st - 1; | 
					
						
							|  |  |  |   float urat, vrat, uopp; | 
					
						
							|  |  |  |   float d[4][3], d2[2][3]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (!disps || isnan(u) || isnan(v)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (u < 0) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     u = 0; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							|  |  |  |   else if (u >= st) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     u = st_max; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							|  |  |  |   if (v < 0) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     v = 0; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							|  |  |  |   else if (v >= st) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     v = st_max; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   x = floor(u); | 
					
						
							|  |  |  |   y = floor(v); | 
					
						
							|  |  |  |   x2 = x + 1; | 
					
						
							|  |  |  |   y2 = y + 1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (x2 >= st) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     x2 = st_max; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							|  |  |  |   if (y2 >= st) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     y2 = st_max; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   urat = u - x; | 
					
						
							|  |  |  |   vrat = v - y; | 
					
						
							|  |  |  |   uopp = 1 - urat; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   mul_v3_v3fl(d[0], disps[y * st + x], uopp); | 
					
						
							|  |  |  |   mul_v3_v3fl(d[1], disps[y * st + x2], urat); | 
					
						
							|  |  |  |   mul_v3_v3fl(d[2], disps[y2 * st + x], uopp); | 
					
						
							|  |  |  |   mul_v3_v3fl(d[3], disps[y2 * st + x2], urat); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   add_v3_v3v3(d2[0], d[0], d[1]); | 
					
						
							|  |  |  |   add_v3_v3v3(d2[1], d[2], d[3]); | 
					
						
							|  |  |  |   mul_v3_fl(d2[0], 1 - vrat); | 
					
						
							|  |  |  |   mul_v3_fl(d2[1], vrat); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   add_v3_v3v3(out, d2[0], d2[1]); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void old_mdisps_rotate( | 
					
						
							|  |  |  |     int S, int UNUSED(newside), int oldside, int x, int y, float *u, float *v) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   float offset = oldside * 0.5f - 0.5f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (S == 1) { | 
					
						
							|  |  |  |     *u = offset + x; | 
					
						
							|  |  |  |     *v = offset - y; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (S == 2) { | 
					
						
							|  |  |  |     *u = offset + y; | 
					
						
							|  |  |  |     *v = offset + x; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (S == 3) { | 
					
						
							|  |  |  |     *u = offset - x; | 
					
						
							|  |  |  |     *v = offset + y; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (S == 0) { | 
					
						
							|  |  |  |     *u = offset - y; | 
					
						
							|  |  |  |     *v = offset - x; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-12-10 17:37:04 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-10 17:37:04 +00:00
										 |  |  | static void old_mdisps_convert(MFace *mface, MDisps *mdisp) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   int newlvl = log(sqrt(mdisp->totdisp) - 1) / M_LN2; | 
					
						
							|  |  |  |   int oldlvl = newlvl + 1; | 
					
						
							|  |  |  |   int oldside = multires_side_tot[oldlvl]; | 
					
						
							|  |  |  |   int newside = multires_side_tot[newlvl]; | 
					
						
							|  |  |  |   int nvert = (mface->v4) ? 4 : 3; | 
					
						
							|  |  |  |   int newtotdisp = multires_grid_tot[newlvl] * nvert; | 
					
						
							|  |  |  |   int x, y, S; | 
					
						
							|  |  |  |   float(*disps)[3], (*out)[3], u = 0.0f, v = 0.0f; /* Quite gcc barking. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   disps = MEM_calloc_arrayN(newtotdisp, 3 * sizeof(float), "multires disps"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   out = disps; | 
					
						
							|  |  |  |   for (S = 0; S < nvert; S++) { | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |     for (y = 0; y < newside; y++) { | 
					
						
							|  |  |  |       for (x = 0; x < newside; x++, out++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         old_mdisps_rotate(S, newside, oldside, x, y, &u, &v); | 
					
						
							|  |  |  |         old_mdisps_bilinear(*out, mdisp->disps, oldside, u, v); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (S == 1) { | 
					
						
							|  |  |  |           (*out)[1] = -(*out)[1]; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (S == 2) { | 
					
						
							|  |  |  |           SWAP(float, (*out)[0], (*out)[1]); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (S == 3) { | 
					
						
							|  |  |  |           (*out)[0] = -(*out)[0]; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (S == 0) { | 
					
						
							|  |  |  |           SWAP(float, (*out)[0], (*out)[1]); | 
					
						
							|  |  |  |           (*out)[0] = -(*out)[0]; | 
					
						
							|  |  |  |           (*out)[1] = -(*out)[1]; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   MEM_freeN(mdisp->disps); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   mdisp->totdisp = newtotdisp; | 
					
						
							|  |  |  |   mdisp->level = newlvl; | 
					
						
							|  |  |  |   mdisp->disps = disps; | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-10 17:37:04 +00:00
										 |  |  | void multires_load_old_250(Mesh *me) | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   MDisps *mdisps, *mdisps2; | 
					
						
							|  |  |  |   MFace *mf; | 
					
						
							|  |  |  |   int i, j, k; | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS); | 
					
						
							| 
									
										
										
										
											2018-06-17 17:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (mdisps) { | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     for (i = 0; i < me->totface; i++) { | 
					
						
							|  |  |  |       if (mdisps[i].totdisp) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         old_mdisps_convert(&me->mface[i], &mdisps[i]); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-01-05 22:33:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     CustomData_add_layer(&me->ldata, CD_MDISPS, CD_CALLOC, NULL, me->totloop); | 
					
						
							|  |  |  |     mdisps2 = CustomData_get_layer(&me->ldata, CD_MDISPS); | 
					
						
							| 
									
										
										
										
											2018-06-17 17:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     k = 0; | 
					
						
							|  |  |  |     mf = me->mface; | 
					
						
							|  |  |  |     for (i = 0; i < me->totface; i++, mf++) { | 
					
						
							|  |  |  |       int nvert = mf->v4 ? 4 : 3; | 
					
						
							|  |  |  |       int totdisp = mdisps[i].totdisp / nvert; | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       for (j = 0; j < nvert; j++, k++) { | 
					
						
							|  |  |  |         mdisps2[k].disps = MEM_calloc_arrayN( | 
					
						
							|  |  |  |             totdisp, 3 * sizeof(float), "multires disp in conversion"); | 
					
						
							|  |  |  |         mdisps2[k].totdisp = totdisp; | 
					
						
							|  |  |  |         mdisps2[k].level = mdisps[i].level; | 
					
						
							|  |  |  |         memcpy(mdisps2[k].disps, mdisps[i].disps + totdisp * j, totdisp); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | /* Does not actually free lvl itself */ | 
					
						
							| 
									
										
										
										
											2009-09-16 17:43:09 +00:00
										 |  |  | static void multires_free_level(MultiresLevel *lvl) | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (lvl) { | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     if (lvl->faces) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       MEM_freeN(lvl->faces); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     } | 
					
						
							|  |  |  |     if (lvl->edges) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       MEM_freeN(lvl->edges); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     } | 
					
						
							|  |  |  |     if (lvl->colfaces) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       MEM_freeN(lvl->colfaces); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | void multires_free(Multires *mr) | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (mr) { | 
					
						
							|  |  |  |     MultiresLevel *lvl = mr->levels.first; | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     /* Free the first-level data */ | 
					
						
							|  |  |  |     if (lvl) { | 
					
						
							|  |  |  |       CustomData_free(&mr->vdata, lvl->totvert); | 
					
						
							|  |  |  |       CustomData_free(&mr->fdata, lvl->totface); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       if (mr->edge_flags) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         MEM_freeN(mr->edge_flags); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							|  |  |  |       if (mr->edge_creases) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         MEM_freeN(mr->edge_creases); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     while (lvl) { | 
					
						
							|  |  |  |       multires_free_level(lvl); | 
					
						
							|  |  |  |       lvl = lvl->next; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-27 12:07:07 +10:00
										 |  |  |     /* mr->verts may be NULL when loading old files,
 | 
					
						
							|  |  |  |      * see direct_link_mesh() in readfile.c, and T43560. */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     MEM_SAFE_FREE(mr->verts); | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     BLI_freelistN(&mr->levels); | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     MEM_freeN(mr); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-09 02:11:44 +00:00
										 |  |  | typedef struct IndexNode { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   struct IndexNode *next, *prev; | 
					
						
							|  |  |  |   int index; | 
					
						
							| 
									
										
										
										
											2013-09-09 02:11:44 +00:00
										 |  |  | } IndexNode; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void create_old_vert_face_map(ListBase **map, | 
					
						
							|  |  |  |                                      IndexNode **mem, | 
					
						
							|  |  |  |                                      const MultiresFace *mface, | 
					
						
							|  |  |  |                                      const int totvert, | 
					
						
							|  |  |  |                                      const int totface) | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   int i, j; | 
					
						
							|  |  |  |   IndexNode *node = NULL; | 
					
						
							| 
									
										
										
										
											2018-06-17 17:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   (*map) = MEM_calloc_arrayN(totvert, sizeof(ListBase), "vert face map"); | 
					
						
							|  |  |  |   (*mem) = MEM_calloc_arrayN(totface, 4 * sizeof(IndexNode), "vert face map mem"); | 
					
						
							|  |  |  |   node = *mem; | 
					
						
							| 
									
										
										
										
											2018-06-17 17:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* Find the users */ | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (i = 0; i < totface; i++) { | 
					
						
							|  |  |  |     for (j = 0; j < (mface[i].v[3] ? 4 : 3); j++, node++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       node->index = i; | 
					
						
							|  |  |  |       BLI_addtail(&(*map)[mface[i].v[j]], node); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static void create_old_vert_edge_map(ListBase **map, | 
					
						
							|  |  |  |                                      IndexNode **mem, | 
					
						
							|  |  |  |                                      const MultiresEdge *medge, | 
					
						
							|  |  |  |                                      const int totvert, | 
					
						
							|  |  |  |                                      const int totedge) | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   int i, j; | 
					
						
							|  |  |  |   IndexNode *node = NULL; | 
					
						
							| 
									
										
										
										
											2018-06-17 17:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   (*map) = MEM_calloc_arrayN(totvert, sizeof(ListBase), "vert edge map"); | 
					
						
							|  |  |  |   (*mem) = MEM_calloc_arrayN(totedge, 2 * sizeof(IndexNode), "vert edge map mem"); | 
					
						
							|  |  |  |   node = *mem; | 
					
						
							| 
									
										
										
										
											2018-06-17 17:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* Find the users */ | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (i = 0; i < totedge; i++) { | 
					
						
							|  |  |  |     for (j = 0; j < 2; j++, node++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       node->index = i; | 
					
						
							|  |  |  |       BLI_addtail(&(*map)[medge[i].v[j]], node); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | static MultiresFace *find_old_face( | 
					
						
							|  |  |  |     ListBase *map, MultiresFace *faces, int v1, int v2, int v3, int v4) | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   IndexNode *n1; | 
					
						
							|  |  |  |   int v[4], i, j; | 
					
						
							| 
									
										
										
										
											2010-11-05 13:37:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   v[0] = v1; | 
					
						
							|  |  |  |   v[1] = v2; | 
					
						
							|  |  |  |   v[2] = v3; | 
					
						
							|  |  |  |   v[3] = v4; | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   for (n1 = map[v1].first; n1; n1 = n1->next) { | 
					
						
							|  |  |  |     int fnd[4] = {0, 0, 0, 0}; | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |     for (i = 0; i < 4; i++) { | 
					
						
							|  |  |  |       for (j = 0; j < 4; j++) { | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |         if (v[i] == faces[n1->index].v[j]) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |           fnd[i] = 1; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     if (fnd[0] && fnd[1] && fnd[2] && fnd[3]) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       return &faces[n1->index]; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return NULL; | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static MultiresEdge *find_old_edge(ListBase *map, MultiresEdge *edges, int v1, int v2) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   IndexNode *n1, *n2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (n1 = map[v1].first; n1; n1 = n1->next) { | 
					
						
							|  |  |  |     for (n2 = map[v2].first; n2; n2 = n2->next) { | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       if (n1->index == n2->index) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         return &edges[n1->index]; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void multires_load_old_edges( | 
					
						
							|  |  |  |     ListBase **emap, MultiresLevel *lvl, int *vvmap, int dst, int v1, int v2, int mov) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   int emid = find_old_edge(emap[2], lvl->edges, v1, v2)->mid; | 
					
						
							|  |  |  |   vvmap[dst + mov] = emid; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (lvl->next->next) { | 
					
						
							|  |  |  |     multires_load_old_edges(emap + 1, lvl->next, vvmap, dst + mov, v1, emid, mov / 2); | 
					
						
							|  |  |  |     multires_load_old_edges(emap + 1, lvl->next, vvmap, dst + mov, v2, emid, -mov / 2); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void multires_load_old_faces(ListBase **fmap, | 
					
						
							|  |  |  |                                     ListBase **emap, | 
					
						
							|  |  |  |                                     MultiresLevel *lvl, | 
					
						
							|  |  |  |                                     int *vvmap, | 
					
						
							|  |  |  |                                     int dst, | 
					
						
							|  |  |  |                                     int v1, | 
					
						
							|  |  |  |                                     int v2, | 
					
						
							|  |  |  |                                     int v3, | 
					
						
							|  |  |  |                                     int v4, | 
					
						
							|  |  |  |                                     int st2, | 
					
						
							|  |  |  |                                     int st3) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   int fmid; | 
					
						
							|  |  |  |   int emid13, emid14, emid23, emid24; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (lvl && lvl->next) { | 
					
						
							|  |  |  |     fmid = find_old_face(fmap[1], lvl->faces, v1, v2, v3, v4)->mid; | 
					
						
							|  |  |  |     vvmap[dst] = fmid; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     emid13 = find_old_edge(emap[1], lvl->edges, v1, v3)->mid; | 
					
						
							|  |  |  |     emid14 = find_old_edge(emap[1], lvl->edges, v1, v4)->mid; | 
					
						
							|  |  |  |     emid23 = find_old_edge(emap[1], lvl->edges, v2, v3)->mid; | 
					
						
							|  |  |  |     emid24 = find_old_edge(emap[1], lvl->edges, v2, v4)->mid; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     multires_load_old_faces(fmap + 1, | 
					
						
							|  |  |  |                             emap + 1, | 
					
						
							|  |  |  |                             lvl->next, | 
					
						
							|  |  |  |                             vvmap, | 
					
						
							|  |  |  |                             dst + st2 * st3 + st3, | 
					
						
							|  |  |  |                             fmid, | 
					
						
							|  |  |  |                             v2, | 
					
						
							|  |  |  |                             emid23, | 
					
						
							|  |  |  |                             emid24, | 
					
						
							|  |  |  |                             st2, | 
					
						
							|  |  |  |                             st3 / 2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     multires_load_old_faces(fmap + 1, | 
					
						
							|  |  |  |                             emap + 1, | 
					
						
							|  |  |  |                             lvl->next, | 
					
						
							|  |  |  |                             vvmap, | 
					
						
							|  |  |  |                             dst - st2 * st3 + st3, | 
					
						
							|  |  |  |                             emid14, | 
					
						
							|  |  |  |                             emid24, | 
					
						
							|  |  |  |                             fmid, | 
					
						
							|  |  |  |                             v4, | 
					
						
							|  |  |  |                             st2, | 
					
						
							|  |  |  |                             st3 / 2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     multires_load_old_faces(fmap + 1, | 
					
						
							|  |  |  |                             emap + 1, | 
					
						
							|  |  |  |                             lvl->next, | 
					
						
							|  |  |  |                             vvmap, | 
					
						
							|  |  |  |                             dst + st2 * st3 - st3, | 
					
						
							|  |  |  |                             emid13, | 
					
						
							|  |  |  |                             emid23, | 
					
						
							|  |  |  |                             v3, | 
					
						
							|  |  |  |                             fmid, | 
					
						
							|  |  |  |                             st2, | 
					
						
							|  |  |  |                             st3 / 2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     multires_load_old_faces(fmap + 1, | 
					
						
							|  |  |  |                             emap + 1, | 
					
						
							|  |  |  |                             lvl->next, | 
					
						
							|  |  |  |                             vvmap, | 
					
						
							|  |  |  |                             dst - st2 * st3 - st3, | 
					
						
							|  |  |  |                             v1, | 
					
						
							|  |  |  |                             fmid, | 
					
						
							|  |  |  |                             emid13, | 
					
						
							|  |  |  |                             emid14, | 
					
						
							|  |  |  |                             st2, | 
					
						
							|  |  |  |                             st3 / 2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (lvl->next->next) { | 
					
						
							|  |  |  |       multires_load_old_edges(emap, lvl->next, vvmap, dst, emid24, fmid, st3); | 
					
						
							|  |  |  |       multires_load_old_edges(emap, lvl->next, vvmap, dst, emid13, fmid, -st3); | 
					
						
							|  |  |  |       multires_load_old_edges(emap, lvl->next, vvmap, dst, emid14, fmid, -st2 * st3); | 
					
						
							|  |  |  |       multires_load_old_edges(emap, lvl->next, vvmap, dst, emid23, fmid, st2 * st3); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-21 15:55:10 +00:00
										 |  |  | static void multires_mvert_to_ss(DerivedMesh *dm, MVert *mvert) | 
					
						
							| 
									
										
										
										
											2009-12-11 10:56:20 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; | 
					
						
							|  |  |  |   CCGSubSurf *ss = ccgdm->ss; | 
					
						
							|  |  |  |   CCGElem *vd; | 
					
						
							|  |  |  |   CCGKey key; | 
					
						
							|  |  |  |   int index; | 
					
						
							|  |  |  |   int totvert, totedge, totface; | 
					
						
							|  |  |  |   int gridSize = ccgSubSurf_getGridSize(ss); | 
					
						
							|  |  |  |   int edgeSize = ccgSubSurf_getEdgeSize(ss); | 
					
						
							|  |  |  |   int i = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   dm->getGridKey(dm, &key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   totface = ccgSubSurf_getNumFaces(ss); | 
					
						
							|  |  |  |   for (index = 0; index < totface; index++) { | 
					
						
							|  |  |  |     CCGFace *f = ccgdm->faceMap[index].face; | 
					
						
							|  |  |  |     int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vd = ccgSubSurf_getFaceCenterData(f); | 
					
						
							|  |  |  |     copy_v3_v3(CCG_elem_co(&key, vd), mvert[i].co); | 
					
						
							|  |  |  |     i++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (S = 0; S < numVerts; S++) { | 
					
						
							|  |  |  |       for (x = 1; x < gridSize - 1; x++, i++) { | 
					
						
							|  |  |  |         vd = ccgSubSurf_getFaceGridEdgeData(ss, f, S, x); | 
					
						
							|  |  |  |         copy_v3_v3(CCG_elem_co(&key, vd), mvert[i].co); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (S = 0; S < numVerts; S++) { | 
					
						
							|  |  |  |       for (y = 1; y < gridSize - 1; y++) { | 
					
						
							|  |  |  |         for (x = 1; x < gridSize - 1; x++, i++) { | 
					
						
							|  |  |  |           vd = ccgSubSurf_getFaceGridData(ss, f, S, x, y); | 
					
						
							|  |  |  |           copy_v3_v3(CCG_elem_co(&key, vd), mvert[i].co); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   totedge = ccgSubSurf_getNumEdges(ss); | 
					
						
							|  |  |  |   for (index = 0; index < totedge; index++) { | 
					
						
							|  |  |  |     CCGEdge *e = ccgdm->edgeMap[index].edge; | 
					
						
							|  |  |  |     int x; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (x = 1; x < edgeSize - 1; x++, i++) { | 
					
						
							|  |  |  |       vd = ccgSubSurf_getEdgeData(ss, e, x); | 
					
						
							|  |  |  |       copy_v3_v3(CCG_elem_co(&key, vd), mvert[i].co); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   totvert = ccgSubSurf_getNumVerts(ss); | 
					
						
							|  |  |  |   for (index = 0; index < totvert; index++) { | 
					
						
							|  |  |  |     CCGVert *v = ccgdm->vertMap[index].vert; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vd = ccgSubSurf_getVertData(ss, v); | 
					
						
							|  |  |  |     copy_v3_v3(CCG_elem_co(&key, vd), mvert[i].co); | 
					
						
							|  |  |  |     i++; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ccgSubSurf_updateToFaces(ss, 0, NULL, 0); | 
					
						
							| 
									
										
										
										
											2009-12-11 10:56:20 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | /* Loads a multires object stored in the old Multires struct into the new format */ | 
					
						
							| 
									
										
										
										
											2009-12-11 10:56:20 +00:00
										 |  |  | static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl) | 
					
						
							| 
									
										
										
										
											2009-01-06 18:59:03 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   MultiresLevel *lvl, *lvl1; | 
					
						
							|  |  |  |   Multires *mr = me->mr; | 
					
						
							|  |  |  |   MVert *vsrc, *vdst; | 
					
						
							|  |  |  |   unsigned int src, dst; | 
					
						
							|  |  |  |   int st_last = multires_side_tot[totlvl - 1] - 1; | 
					
						
							|  |  |  |   int extedgelen = multires_side_tot[totlvl] - 2; | 
					
						
							|  |  |  |   int *vvmap;  // inorder for dst, map to src
 | 
					
						
							|  |  |  |   int crossedgelen; | 
					
						
							|  |  |  |   int s, x, tottri, totquad; | 
					
						
							|  |  |  |   unsigned int i, j, totvert; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   src = 0; | 
					
						
							|  |  |  |   vsrc = mr->verts; | 
					
						
							|  |  |  |   vdst = dm->getVertArray(dm); | 
					
						
							|  |  |  |   totvert = (unsigned int)dm->getNumVerts(dm); | 
					
						
							|  |  |  |   vvmap = MEM_calloc_arrayN(totvert, sizeof(int), "multires vvmap"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!vvmap) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   lvl1 = mr->levels.first; | 
					
						
							|  |  |  |   /* Load base verts */ | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (i = 0; i < lvl1->totvert; i++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     vvmap[totvert - lvl1->totvert + i] = src; | 
					
						
							|  |  |  |     src++; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Original edges */ | 
					
						
							|  |  |  |   dst = totvert - lvl1->totvert - extedgelen * lvl1->totedge; | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (i = 0; i < lvl1->totedge; i++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     int ldst = dst + extedgelen * i; | 
					
						
							|  |  |  |     int lsrc = src; | 
					
						
							|  |  |  |     lvl = lvl1->next; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |     for (j = 2; j <= mr->level_count; j++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       int base = multires_side_tot[totlvl - j + 1] - 2; | 
					
						
							|  |  |  |       int skip = multires_side_tot[totlvl - j + 2] - 1; | 
					
						
							|  |  |  |       int st = multires_side_tot[j - 1] - 1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |       for (x = 0; x < st; x++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         vvmap[ldst + base + x * skip] = lsrc + st * i + x; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       lsrc += lvl->totvert - lvl->prev->totvert; | 
					
						
							|  |  |  |       lvl = lvl->next; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Center points */ | 
					
						
							|  |  |  |   dst = 0; | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (i = 0; i < lvl1->totface; i++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     int sides = lvl1->faces[i].v[3] ? 4 : 3; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vvmap[dst] = src + lvl1->totedge + i; | 
					
						
							|  |  |  |     dst += 1 + sides * (st_last - 1) * st_last; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* The rest is only for level 3 and up */ | 
					
						
							|  |  |  |   if (lvl1->next && lvl1->next->next) { | 
					
						
							|  |  |  |     ListBase **fmap, **emap; | 
					
						
							|  |  |  |     IndexNode **fmem, **emem; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Face edge cross */ | 
					
						
							|  |  |  |     tottri = totquad = 0; | 
					
						
							|  |  |  |     crossedgelen = multires_side_tot[totlvl - 1] - 2; | 
					
						
							|  |  |  |     dst = 0; | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |     for (i = 0; i < lvl1->totface; i++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       int sides = lvl1->faces[i].v[3] ? 4 : 3; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       lvl = lvl1->next->next; | 
					
						
							|  |  |  |       dst++; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |       for (j = 3; j <= mr->level_count; j++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         int base = multires_side_tot[totlvl - j + 1] - 2; | 
					
						
							|  |  |  |         int skip = multires_side_tot[totlvl - j + 2] - 1; | 
					
						
							|  |  |  |         int st = pow(2, j - 2); | 
					
						
							|  |  |  |         int st2 = pow(2, j - 3); | 
					
						
							|  |  |  |         int lsrc = lvl->prev->totvert; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Skip exterior edge verts */ | 
					
						
							|  |  |  |         lsrc += lvl1->totedge * st; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Skip earlier face edge crosses */ | 
					
						
							|  |  |  |         lsrc += st2 * (tottri * 3 + totquad * 4); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |         for (s = 0; s < sides; s++) { | 
					
						
							|  |  |  |           for (x = 0; x < st2; x++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |             vvmap[dst + crossedgelen * (s + 1) - base - x * skip - 1] = lsrc; | 
					
						
							|  |  |  |             lsrc++; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         lvl = lvl->next; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       dst += sides * (st_last - 1) * st_last; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       if (sides == 4) { | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |         totquad++; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							|  |  |  |       else { | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |         tottri++; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* calculate vert to edge/face maps for each level (except the last) */ | 
					
						
							|  |  |  |     fmap = MEM_calloc_arrayN((mr->level_count - 1), sizeof(ListBase *), "multires fmap"); | 
					
						
							|  |  |  |     emap = MEM_calloc_arrayN((mr->level_count - 1), sizeof(ListBase *), "multires emap"); | 
					
						
							|  |  |  |     fmem = MEM_calloc_arrayN((mr->level_count - 1), sizeof(IndexNode *), "multires fmem"); | 
					
						
							|  |  |  |     emem = MEM_calloc_arrayN((mr->level_count - 1), sizeof(IndexNode *), "multires emem"); | 
					
						
							|  |  |  |     lvl = lvl1; | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |     for (i = 0; i < (unsigned int)mr->level_count - 1; i++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       create_old_vert_face_map(fmap + i, fmem + i, lvl->faces, lvl->totvert, lvl->totface); | 
					
						
							|  |  |  |       create_old_vert_edge_map(emap + i, emem + i, lvl->edges, lvl->totvert, lvl->totedge); | 
					
						
							|  |  |  |       lvl = lvl->next; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Interior face verts */ | 
					
						
							|  |  |  |     /* lvl = lvl1->next->next; */ /* UNUSED */ | 
					
						
							|  |  |  |     dst = 0; | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |     for (j = 0; j < lvl1->totface; j++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       int sides = lvl1->faces[j].v[3] ? 4 : 3; | 
					
						
							|  |  |  |       int ldst = dst + 1 + sides * (st_last - 1); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |       for (s = 0; s < sides; s++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         int st2 = multires_side_tot[totlvl - 1] - 2; | 
					
						
							|  |  |  |         int st3 = multires_side_tot[totlvl - 2] - 2; | 
					
						
							|  |  |  |         int st4 = st3 == 0 ? 1 : (st3 + 1) / 2; | 
					
						
							|  |  |  |         int mid = ldst + st2 * st3 + st3; | 
					
						
							|  |  |  |         int cv = lvl1->faces[j].v[s]; | 
					
						
							|  |  |  |         int nv = lvl1->faces[j].v[s == sides - 1 ? 0 : s + 1]; | 
					
						
							|  |  |  |         int pv = lvl1->faces[j].v[s == 0 ? sides - 1 : s - 1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         multires_load_old_faces(fmap, | 
					
						
							|  |  |  |                                 emap, | 
					
						
							|  |  |  |                                 lvl1->next, | 
					
						
							|  |  |  |                                 vvmap, | 
					
						
							|  |  |  |                                 mid, | 
					
						
							|  |  |  |                                 vvmap[dst], | 
					
						
							|  |  |  |                                 cv, | 
					
						
							|  |  |  |                                 find_old_edge(emap[0], lvl1->edges, pv, cv)->mid, | 
					
						
							|  |  |  |                                 find_old_edge(emap[0], lvl1->edges, cv, nv)->mid, | 
					
						
							|  |  |  |                                 st2, | 
					
						
							|  |  |  |                                 st4); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ldst += (st_last - 1) * (st_last - 1); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       dst = ldst; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*lvl = lvl->next;*/ /*UNUSED*/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |     for (i = 0; i < (unsigned int)(mr->level_count - 1); i++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       MEM_freeN(fmap[i]); | 
					
						
							|  |  |  |       MEM_freeN(fmem[i]); | 
					
						
							|  |  |  |       MEM_freeN(emap[i]); | 
					
						
							|  |  |  |       MEM_freeN(emem[i]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     MEM_freeN(fmap); | 
					
						
							|  |  |  |     MEM_freeN(emap); | 
					
						
							|  |  |  |     MEM_freeN(fmem); | 
					
						
							|  |  |  |     MEM_freeN(emem); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Transfer verts */ | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (i = 0; i < totvert; i++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     copy_v3_v3(vdst[i].co, vsrc[vvmap[i]].co); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   MEM_freeN(vvmap); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   multires_mvert_to_ss(dm, vdst); | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2009-12-11 10:56:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-20 18:54:58 +00:00
										 |  |  | /* Copy the first-level vcol data to the mesh, if it exists */ | 
					
						
							|  |  |  | /* Warning: higher-level vcol data will be lost */ | 
					
						
							|  |  |  | static void multires_load_old_vcols(Mesh *me) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   MultiresLevel *lvl; | 
					
						
							|  |  |  |   MultiresColFace *colface; | 
					
						
							|  |  |  |   MCol *mcol; | 
					
						
							|  |  |  |   int i, j; | 
					
						
							| 
									
										
										
										
											2010-11-20 18:54:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (!(lvl = me->mr->levels.first)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-11-20 18:54:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (!(colface = lvl->colfaces)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-11-20 18:54:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* older multires format never supported multiple vcol layers,
 | 
					
						
							|  |  |  |    * so we can assume the active vcol layer is the correct one */ | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (!(mcol = CustomData_get_layer(&me->fdata, CD_MCOL))) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-06-17 17:05:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (i = 0; i < me->totface; i++) { | 
					
						
							|  |  |  |     for (j = 0; j < 4; j++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       mcol[i * 4 + j].a = colface[i].col[j].a; | 
					
						
							|  |  |  |       mcol[i * 4 + j].r = colface[i].col[j].r; | 
					
						
							|  |  |  |       mcol[i * 4 + j].g = colface[i].col[j].g; | 
					
						
							|  |  |  |       mcol[i * 4 + j].b = colface[i].col[j].b; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-11-20 18:54:58 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Copy the first-level face-flag data to the mesh */ | 
					
						
							|  |  |  | static void multires_load_old_face_flags(Mesh *me) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   MultiresLevel *lvl; | 
					
						
							|  |  |  |   MultiresFace *faces; | 
					
						
							|  |  |  |   int i; | 
					
						
							| 
									
										
										
										
											2010-11-20 18:54:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (!(lvl = me->mr->levels.first)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-11-20 18:54:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (!(faces = lvl->faces)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-11-20 18:54:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (i = 0; i < me->totface; i++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     me->mface[i].flag = faces[i].flag; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-11-20 18:54:58 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2009-12-10 17:37:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | void multires_load_old(Object *ob, Mesh *me) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   MultiresLevel *lvl; | 
					
						
							|  |  |  |   ModifierData *md; | 
					
						
							|  |  |  |   MultiresModifierData *mmd; | 
					
						
							|  |  |  |   DerivedMesh *dm, *orig; | 
					
						
							|  |  |  |   CustomDataLayer *l; | 
					
						
							|  |  |  |   int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Load original level into the mesh */ | 
					
						
							|  |  |  |   lvl = me->mr->levels.first; | 
					
						
							|  |  |  |   CustomData_free_layers(&me->vdata, CD_MVERT, lvl->totvert); | 
					
						
							|  |  |  |   CustomData_free_layers(&me->edata, CD_MEDGE, lvl->totedge); | 
					
						
							|  |  |  |   CustomData_free_layers(&me->fdata, CD_MFACE, lvl->totface); | 
					
						
							|  |  |  |   me->totvert = lvl->totvert; | 
					
						
							|  |  |  |   me->totedge = lvl->totedge; | 
					
						
							|  |  |  |   me->totface = lvl->totface; | 
					
						
							|  |  |  |   me->mvert = CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert); | 
					
						
							|  |  |  |   me->medge = CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, NULL, me->totedge); | 
					
						
							|  |  |  |   me->mface = CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, me->totface); | 
					
						
							|  |  |  |   memcpy(me->mvert, me->mr->verts, sizeof(MVert) * me->totvert); | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (i = 0; i < me->totedge; i++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     me->medge[i].v1 = lvl->edges[i].v[0]; | 
					
						
							|  |  |  |     me->medge[i].v2 = lvl->edges[i].v[1]; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (i = 0; i < me->totface; i++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     me->mface[i].v1 = lvl->faces[i].v[0]; | 
					
						
							|  |  |  |     me->mface[i].v2 = lvl->faces[i].v[1]; | 
					
						
							|  |  |  |     me->mface[i].v3 = lvl->faces[i].v[2]; | 
					
						
							|  |  |  |     me->mface[i].v4 = lvl->faces[i].v[3]; | 
					
						
							|  |  |  |     me->mface[i].mat_nr = lvl->faces[i].mat_nr; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Copy the first-level data to the mesh */ | 
					
						
							|  |  |  |   /* XXX We must do this before converting tessfaces to polys/lopps! */ | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (i = 0, l = me->mr->vdata.layers; i < me->mr->vdata.totlayer; i++, l++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     CustomData_add_layer(&me->vdata, l->type, CD_REFERENCE, l->data, me->totvert); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (i = 0, l = me->mr->fdata.layers; i < me->mr->fdata.totlayer; i++, l++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     CustomData_add_layer(&me->fdata, l->type, CD_REFERENCE, l->data, me->totface); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   CustomData_reset(&me->mr->vdata); | 
					
						
							|  |  |  |   CustomData_reset(&me->mr->fdata); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   multires_load_old_vcols(me); | 
					
						
							|  |  |  |   multires_load_old_face_flags(me); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-03 12:35:51 +01:00
										 |  |  |   /* multiresModifier_subdivide_legacy (actually, multires_subdivide_legacy) expects polys, not
 | 
					
						
							|  |  |  |    * tessfaces! */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BKE_mesh_convert_mfaces_to_mpolys(me); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Add a multires modifier to the object */ | 
					
						
							|  |  |  |   md = ob->modifiers.first; | 
					
						
							| 
									
										
										
										
											2020-05-08 10:14:02 +02:00
										 |  |  |   while (md && BKE_modifier_get_info(md->type)->type == eModifierTypeType_OnlyDeform) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     md = md->next; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-05-08 10:14:02 +02:00
										 |  |  |   mmd = (MultiresModifierData *)BKE_modifier_new(eModifierType_Multires); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   BLI_insertlinkbefore(&ob->modifiers, md, mmd); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (i = 0; i < me->mr->level_count - 1; i++) { | 
					
						
							| 
									
										
										
										
											2020-03-03 12:35:51 +01:00
										 |  |  |     multiresModifier_subdivide_legacy(mmd, NULL, ob, 1, 0); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   mmd->lvl = mmd->totlvl; | 
					
						
							|  |  |  |   orig = CDDM_from_mesh(me); | 
					
						
							|  |  |  |   /* XXX We *must* alloc paint mask here, else we have some kind of mismatch in
 | 
					
						
							|  |  |  |    *     multires_modifier_update_mdisps() (called by dm->release(dm)), which always creates the | 
					
						
							|  |  |  |    *     reference subsurfed dm with this option, before calling multiresModifier_disp_run(), | 
					
						
							|  |  |  |    *     which implicitly expects both subsurfs from its first dm and oldGridData parameters to | 
					
						
							|  |  |  |    *     be of the same "format"! */ | 
					
						
							|  |  |  |   dm = multires_make_derived_from_derived(orig, mmd, NULL, ob, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   multires_load_old_dm(dm, me, mmd->totlvl + 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   multires_dm_mark_as_modified(dm, MULTIRES_COORDS_MODIFIED); | 
					
						
							|  |  |  |   dm->release(dm); | 
					
						
							|  |  |  |   orig->release(orig); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Remove the old multires */ | 
					
						
							|  |  |  |   multires_free(me->mr); | 
					
						
							|  |  |  |   me->mr = NULL; | 
					
						
							| 
									
										
										
										
											2007-12-29 17:07:55 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2009-11-25 14:07:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-07 15:16:10 +02:00
										 |  |  | /* If 'ob_src' and 'ob_dst' both have multires modifiers, synchronize them
 | 
					
						
							|  |  |  |  * such that 'ob_dst' has the same total number of levels as 'ob_src'. */ | 
					
						
							| 
									
										
										
										
											2020-03-03 12:35:51 +01:00
										 |  |  | void multiresModifier_sync_levels_ex(Object *ob_dst, | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |                                      MultiresModifierData *mmd_src, | 
					
						
							|  |  |  |                                      MultiresModifierData *mmd_dst) | 
					
						
							| 
									
										
										
										
											2010-10-25 08:03:05 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (mmd_src->totlvl == mmd_dst->totlvl) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-05-07 15:16:10 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (mmd_src->totlvl > mmd_dst->totlvl) { | 
					
						
							| 
									
										
										
										
											2020-04-30 15:15:19 +02:00
										 |  |  |     if (mmd_dst->simple) { | 
					
						
							|  |  |  |       multiresModifier_subdivide_to_level( | 
					
						
							|  |  |  |           ob_dst, mmd_dst, mmd_src->totlvl, MULTIRES_SUBDIVIDE_SIMPLE); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       multiresModifier_subdivide_to_level( | 
					
						
							|  |  |  |           ob_dst, mmd_dst, mmd_src->totlvl, MULTIRES_SUBDIVIDE_CATMULL_CLARK); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     multires_del_higher(mmd_dst, ob_dst, mmd_src->totlvl); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-05-07 15:16:10 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-10-25 08:03:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-05 18:20:27 +02:00
										 |  |  | static void multires_sync_levels(Scene *scene, Object *ob_src, Object *ob_dst) | 
					
						
							| 
									
										
										
										
											2015-05-07 15:16:10 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   MultiresModifierData *mmd_src = get_multires_modifier(scene, ob_src, true); | 
					
						
							|  |  |  |   MultiresModifierData *mmd_dst = get_multires_modifier(scene, ob_dst, true); | 
					
						
							| 
									
										
										
										
											2015-05-07 15:16:10 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (!mmd_src) { | 
					
						
							|  |  |  |     /* object could have MDISP even when there is no multires modifier
 | 
					
						
							|  |  |  |      * this could lead to troubles due to i've got no idea how mdisp could be | 
					
						
							| 
									
										
										
										
											2019-06-12 09:04:10 +10:00
										 |  |  |      * up-sampled correct without modifier data. | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |      * just remove mdisps if no multires present (nazgul) */ | 
					
						
							| 
									
										
										
										
											2010-10-25 08:03:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     multires_customdata_delete(ob_src->data); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-10-25 08:03:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (mmd_src && mmd_dst) { | 
					
						
							| 
									
										
										
										
											2020-03-03 12:35:51 +01:00
										 |  |  |     multiresModifier_sync_levels_ex(ob_dst, mmd_src, mmd_dst); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-10-25 08:03:05 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-02 15:23:06 +01:00
										 |  |  | static void multires_apply_uniform_scale(Object *object, const float scale) | 
					
						
							| 
									
										
										
										
											2010-10-25 08:03:05 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   Mesh *mesh = (Mesh *)object->data; | 
					
						
							|  |  |  |   MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS); | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |   for (int i = 0; i < mesh->totloop; i++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     MDisps *grid = &mdisps[i]; | 
					
						
							| 
									
										
										
										
											2019-09-08 00:12:26 +10:00
										 |  |  |     for (int j = 0; j < grid->totdisp; j++) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       mul_v3_fl(grid->disps[j], scale); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void multires_apply_smat(struct Depsgraph *UNUSED(depsgraph), | 
					
						
							|  |  |  |                                 Scene *scene, | 
					
						
							|  |  |  |                                 Object *object, | 
					
						
							| 
									
										
										
										
											2019-09-14 08:10:50 +10:00
										 |  |  |                                 const float smat[3][3]) | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | { | 
					
						
							|  |  |  |   const MultiresModifierData *mmd = get_multires_modifier(scene, object, true); | 
					
						
							|  |  |  |   if (mmd == NULL || mmd->totlvl == 0) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   /* Make sure layer present. */ | 
					
						
							|  |  |  |   Mesh *mesh = (Mesh *)object->data; | 
					
						
							| 
									
										
										
										
											2020-03-13 16:13:32 +01:00
										 |  |  |   multiresModifier_ensure_external_read(mesh, mmd); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (!CustomData_get_layer(&mesh->ldata, CD_MDISPS)) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (is_uniform_scaled_m3(smat)) { | 
					
						
							|  |  |  |     const float scale = mat3_to_scale(smat); | 
					
						
							|  |  |  |     multires_apply_uniform_scale(object, scale); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     /* TODO(sergey): This branch of code actually requires more work to
 | 
					
						
							|  |  |  |      * preserve all the details. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     const float scale = mat3_to_scale(smat); | 
					
						
							|  |  |  |     multires_apply_uniform_scale(object, scale); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-10-25 08:03:05 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-04 16:00:28 +00:00
										 |  |  | int multires_mdisp_corners(MDisps *s) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   int lvl = 13; | 
					
						
							| 
									
										
										
										
											2010-11-04 16:00:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   while (lvl > 0) { | 
					
						
							|  |  |  |     int side = (1 << (lvl - 1)) + 1; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     if ((s->totdisp % (side * side)) == 0) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       return s->totdisp / (side * side); | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     lvl--; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-11-04 16:00:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return 0; | 
					
						
							| 
									
										
										
										
											2010-11-04 16:00:28 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-06 12:07:27 +02:00
										 |  |  | void multiresModifier_scale_disp(struct Depsgraph *depsgraph, Scene *scene, Object *ob) | 
					
						
							| 
									
										
										
										
											2010-10-25 08:03:05 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   float smat[3][3]; | 
					
						
							| 
									
										
										
										
											2010-10-25 08:03:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* object's scale matrix */ | 
					
						
							|  |  |  |   BKE_object_scale_to_mat3(ob, smat); | 
					
						
							| 
									
										
										
										
											2010-10-25 08:03:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   multires_apply_smat(depsgraph, scene, ob, smat); | 
					
						
							| 
									
										
										
										
											2010-10-25 08:03:05 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | void multiresModifier_prepare_join(struct Depsgraph *depsgraph, | 
					
						
							|  |  |  |                                    Scene *scene, | 
					
						
							|  |  |  |                                    Object *ob, | 
					
						
							|  |  |  |                                    Object *to_ob) | 
					
						
							| 
									
										
										
										
											2010-10-25 08:03:05 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   float smat[3][3], tmat[3][3], mat[3][3]; | 
					
						
							|  |  |  |   multires_sync_levels(scene, to_ob, ob); | 
					
						
							| 
									
										
										
										
											2010-10-25 08:03:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* construct scale matrix for displacement */ | 
					
						
							|  |  |  |   BKE_object_scale_to_mat3(to_ob, tmat); | 
					
						
							|  |  |  |   invert_m3(tmat); | 
					
						
							|  |  |  |   BKE_object_scale_to_mat3(ob, smat); | 
					
						
							|  |  |  |   mul_m3_m3m3(mat, smat, tmat); | 
					
						
							| 
									
										
										
										
											2010-10-25 08:03:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   multires_apply_smat(depsgraph, scene, ob, mat); | 
					
						
							| 
									
										
										
										
											2010-10-25 08:03:05 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-11-04 16:00:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* update multires data after topology changing */ | 
					
						
							| 
									
										
										
										
											2012-04-16 11:03:42 +00:00
										 |  |  | void multires_topology_changed(Mesh *me) | 
					
						
							| 
									
										
										
										
											2010-11-04 16:00:28 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   MDisps *mdisp = NULL, *cur = NULL; | 
					
						
							|  |  |  |   int i, grid = 0; | 
					
						
							| 
									
										
										
										
											2010-11-04 16:00:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); | 
					
						
							|  |  |  |   mdisp = CustomData_get_layer(&me->ldata, CD_MDISPS); | 
					
						
							| 
									
										
										
										
											2010-11-05 14:00:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   if (!mdisp) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-11-04 16:00:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   cur = mdisp; | 
					
						
							|  |  |  |   for (i = 0; i < me->totloop; i++, cur++) { | 
					
						
							|  |  |  |     if (cur->totdisp) { | 
					
						
							|  |  |  |       grid = mdisp->totdisp; | 
					
						
							| 
									
										
										
										
											2010-11-08 14:39:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-11-08 14:00:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   for (i = 0; i < me->totloop; i++, mdisp++) { | 
					
						
							|  |  |  |     /* allocate memory for mdisp, the whole disp layer would be erased otherwise */ | 
					
						
							|  |  |  |     if (!mdisp->totdisp || !mdisp->disps) { | 
					
						
							|  |  |  |       if (grid) { | 
					
						
							|  |  |  |         mdisp->totdisp = grid; | 
					
						
							|  |  |  |         mdisp->disps = MEM_calloc_arrayN(3 * sizeof(float), mdisp->totdisp, "mdisp topology"); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2010-11-08 14:00:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-11-04 16:00:28 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-12-13 21:22:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-13 16:13:32 +01:00
										 |  |  | /* Makes sure data from an external file is fully read.
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Since the multires data files only contain displacement vectors without knowledge about | 
					
						
							|  |  |  |  * subdivision level some extra work is needed. Namely make is to all displacement grids have | 
					
						
							|  |  |  |  * proper level and number of displacement vectors set.  */ | 
					
						
							|  |  |  | void multires_ensure_external_read(struct Mesh *mesh, int top_level) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (!CustomData_external_test(&mesh->ldata, CD_MDISPS)) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS); | 
					
						
							|  |  |  |   if (mdisps == NULL) { | 
					
						
							|  |  |  |     mdisps = CustomData_add_layer(&mesh->ldata, CD_MDISPS, CD_DEFAULT, NULL, mesh->totloop); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const int totloop = mesh->totloop; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (int i = 0; i < totloop; ++i) { | 
					
						
							|  |  |  |     if (mdisps[i].level != top_level) { | 
					
						
							|  |  |  |       MEM_SAFE_FREE(mdisps[i].disps); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* NOTE: CustomData_external_read will take care of allocation of displacement vectors if
 | 
					
						
							|  |  |  |      * they are missing. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const int totdisp = multires_grid_tot[top_level]; | 
					
						
							|  |  |  |     mdisps[i].totdisp = totdisp; | 
					
						
							|  |  |  |     mdisps[i].level = top_level; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   CustomData_external_read(&mesh->ldata, &mesh->id, CD_MASK_MDISPS, mesh->totloop); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | void multiresModifier_ensure_external_read(struct Mesh *mesh, const MultiresModifierData *mmd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   multires_ensure_external_read(mesh, mmd->totlvl); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-02 16:43:28 +00:00
										 |  |  | /***************** Multires interpolation stuff *****************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-05 20:54:04 +00:00
										 |  |  | /* Find per-corner coordinate with given per-face UV coord */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | int mdisp_rot_face_to_crn(struct MVert *UNUSED(mvert), | 
					
						
							|  |  |  |                           struct MPoly *mpoly, | 
					
						
							|  |  |  |                           struct MLoop *UNUSED(mloop), | 
					
						
							|  |  |  |                           const struct MLoopTri *UNUSED(lt), | 
					
						
							|  |  |  |                           const int face_side, | 
					
						
							|  |  |  |                           const float u, | 
					
						
							|  |  |  |                           const float v, | 
					
						
							|  |  |  |                           float *x, | 
					
						
							|  |  |  |                           float *y) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   const float offset = face_side * 0.5f - 0.5f; | 
					
						
							|  |  |  |   int S = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (mpoly->totloop == 4) { | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     if (u <= offset && v <= offset) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       S = 0; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     } | 
					
						
							|  |  |  |     else if (u > offset && v <= offset) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       S = 1; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     } | 
					
						
							|  |  |  |     else if (u > offset && v > offset) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       S = 2; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     } | 
					
						
							|  |  |  |     else if (u <= offset && v >= offset) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       S = 3; | 
					
						
							| 
									
										
										
										
											2019-04-22 09:39:35 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (S == 0) { | 
					
						
							|  |  |  |       *y = offset - u; | 
					
						
							|  |  |  |       *x = offset - v; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (S == 1) { | 
					
						
							|  |  |  |       *x = u - offset; | 
					
						
							|  |  |  |       *y = offset - v; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (S == 2) { | 
					
						
							|  |  |  |       *y = u - offset; | 
					
						
							|  |  |  |       *x = v - offset; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (S == 3) { | 
					
						
							|  |  |  |       *x = offset - u; | 
					
						
							|  |  |  |       *y = v - offset; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if (mpoly->totloop == 3) { | 
					
						
							|  |  |  |     int grid_size = offset; | 
					
						
							|  |  |  |     float w = (face_side - 1) - u - v; | 
					
						
							|  |  |  |     float W1, W2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (u >= v && u >= w) { | 
					
						
							|  |  |  |       S = 0; | 
					
						
							|  |  |  |       W1 = w; | 
					
						
							|  |  |  |       W2 = v; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (v >= u && v >= w) { | 
					
						
							|  |  |  |       S = 1; | 
					
						
							|  |  |  |       W1 = u; | 
					
						
							|  |  |  |       W2 = w; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       S = 2; | 
					
						
							|  |  |  |       W1 = v; | 
					
						
							|  |  |  |       W2 = u; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     W1 /= (face_side - 1); | 
					
						
							|  |  |  |     W2 /= (face_side - 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     *x = (1 - (2 * W1) / (1 - W2)) * grid_size; | 
					
						
							|  |  |  |     *y = (1 - (2 * W2) / (1 - W1)) * grid_size; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     /* the complicated ngon case: find the actual coordinate from
 | 
					
						
							|  |  |  |      * the barycentric coordinates and finally find the closest vertex | 
					
						
							|  |  |  |      * should work reliably for convex cases only but better than nothing */ | 
					
						
							| 
									
										
										
										
											2015-07-30 14:43:58 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-19 09:07:40 +11:00
										 |  |  | #if 0
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     int minS, i; | 
					
						
							|  |  |  |     float mindist = FLT_MAX; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (i = 0; i < mpoly->totloop; i++) { | 
					
						
							|  |  |  |       float len = len_v3v3(NULL, mvert[mloop[mpoly->loopstart + i].v].co); | 
					
						
							|  |  |  |       if (len < mindist) { | 
					
						
							|  |  |  |         mindist = len; | 
					
						
							|  |  |  |         minS = i; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     S = minS; | 
					
						
							| 
									
										
										
										
											2018-10-19 09:07:40 +11:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     /* temp not implemented yet and also not working properly in current master.
 | 
					
						
							|  |  |  |      * (was worked around by subdividing once) */ | 
					
						
							|  |  |  |     S = 0; | 
					
						
							|  |  |  |     *x = 0; | 
					
						
							|  |  |  |     *y = 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return S; | 
					
						
							| 
									
										
										
										
											2011-06-05 20:54:04 +00:00
										 |  |  | } |