1472 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1472 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * ***** BEGIN GPL LICENSE BLOCK *****
 | 
						|
 *
 | 
						|
 * 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,
 | 
						|
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 | 
						|
 *
 | 
						|
 * The Original Code is Copyright (C) 2012 Blender Foundation.
 | 
						|
 * All rights reserved.
 | 
						|
 *
 | 
						|
 * Contributor(s): Blender Foundation,
 | 
						|
 *                 Campbell Barton
 | 
						|
 *
 | 
						|
 * ***** END GPL LICENSE BLOCK *****
 | 
						|
 */
 | 
						|
 | 
						|
/** \file blender/blenkernel/intern/mask_rasterize.c
 | 
						|
 *  \ingroup bke
 | 
						|
 *
 | 
						|
 * This module exposes a rasterizer that works as a black box - implementation details are confined to this file,
 | 
						|
 *
 | 
						|
 * The basic method to access is:
 | 
						|
 * - create & initialize a handle from a #Mask datablock.
 | 
						|
 * - execute pixel lookups.
 | 
						|
 * - free the handle.
 | 
						|
 *
 | 
						|
 * This file is admittedly a bit confusticated, in quite few areas speed was chosen over readability,
 | 
						|
 * though it is commented - so shouldn't be so hard to see whats going on.
 | 
						|
 *
 | 
						|
 *
 | 
						|
 * Implementation:
 | 
						|
 *
 | 
						|
 * To rasterize the mask its converted into geometry that use a ray-cast for each pixel lookup.
 | 
						|
 *
 | 
						|
 * Initially 'kdopbvh' was used but this ended up being too slow.
 | 
						|
 *
 | 
						|
 * To gain some extra speed we take advantage of a few shortcuts that can be made rasterizing masks specifically.
 | 
						|
 * - all triangles are known to be completely white - so no depth check is done on triangle intersection.
 | 
						|
 * - all quads are known to be feather outlines - the 1 and 0 depths are known by the vertex order in the quad,
 | 
						|
 * - there is no color - just a value for each mask pixel.
 | 
						|
 * - the mask spacial structure always maps to space 0-1 on X and Y axis.
 | 
						|
 * - bucketing is used to speed up lookups for geometry.
 | 
						|
 *
 | 
						|
 * Other Details:
 | 
						|
 * - used unsigned values all over for some extra speed on some arch's.
 | 
						|
 * - anti-aliasing is faked, just ensuring at least one pixel feather - avoids oversampling.
 | 
						|
 * - initializing the spacial structure doesn't need to be as optimized as pixel lookups are.
 | 
						|
 * - mask lookups need not be pixel aligned so any sub-pixel values from x/y (0 - 1), can be found.
 | 
						|
 *   (perhaps masks can be used as a vector texture in 3D later on)
 | 
						|
 *
 | 
						|
 *
 | 
						|
 * Currently, to build the spacial structure we have to calculate the total number of faces ahead of time.
 | 
						|
 *
 | 
						|
 * This is getting a bit complicated with the addition of unfilled splines and end capping -
 | 
						|
 * If large changes are needed here we would be better off using an iterable
 | 
						|
 * BLI_mempool for triangles and converting to a contiguous array afterwards.
 | 
						|
 *
 | 
						|
 * - Campbell
 | 
						|
 */
 | 
						|
 | 
						|
#include "MEM_guardedalloc.h"
 | 
						|
 | 
						|
#include "DNA_vec_types.h"
 | 
						|
#include "DNA_mask_types.h"
 | 
						|
#include "DNA_scene_types.h"
 | 
						|
 | 
						|
#include "BLI_utildefines.h"
 | 
						|
#include "BLI_scanfill.h"
 | 
						|
#include "BLI_memarena.h"
 | 
						|
 | 
						|
#include "BLI_math.h"
 | 
						|
#include "BLI_rect.h"
 | 
						|
#include "BLI_listbase.h"
 | 
						|
#include "BLI_linklist.h"
 | 
						|
 | 
						|
#include "BKE_mask.h"
 | 
						|
 | 
						|
#include "BLI_strict_flags.h"
 | 
						|
 | 
						|
/* this is rather and annoying hack, use define to isolate it.
 | 
						|
 * problem is caused by scanfill removing edges on us. */
 | 
						|
#define USE_SCANFILL_EDGE_WORKAROUND
 | 
						|
 | 
						|
#define SPLINE_RESOL_CAP_PER_PIXEL 2
 | 
						|
#define SPLINE_RESOL_CAP_MIN 8
 | 
						|
#define SPLINE_RESOL_CAP_MAX 64
 | 
						|
 | 
						|
/* found this gives best performance for high detail masks, values between 2 and 8 work best */
 | 
						|
#define BUCKET_PIXELS_PER_CELL 4
 | 
						|
 | 
						|
#define SF_EDGE_IS_BOUNDARY 0xff
 | 
						|
#define SF_KEYINDEX_TEMP_ID ((unsigned int) -1)
 | 
						|
 | 
						|
#define TRI_TERMINATOR_ID   ((unsigned int) -1)
 | 
						|
#define TRI_VERT            ((unsigned int) -1)
 | 
						|
 | 
						|
/* for debugging add... */
 | 
						|
#ifndef NDEBUG
 | 
						|
/* printf("%u %u %u %u\n", _t[0], _t[1], _t[2], _t[3]); \ */
 | 
						|
#  define FACE_ASSERT(face, vert_max)                    \
 | 
						|
{                                                        \
 | 
						|
	unsigned int *_t = face;                             \
 | 
						|
	BLI_assert(_t[0] < vert_max);                        \
 | 
						|
	BLI_assert(_t[1] < vert_max);                        \
 | 
						|
	BLI_assert(_t[2] < vert_max);                        \
 | 
						|
	BLI_assert(_t[3] < vert_max || _t[3] == TRI_VERT);   \
 | 
						|
} (void)0
 | 
						|
#else
 | 
						|
   /* do nothing */
 | 
						|
#  define FACE_ASSERT(face, vert_max)
 | 
						|
#endif
 | 
						|
 | 
						|
static void rotate_point_v2(float r_p[2], const float p[2], const float cent[2], const float angle, const float asp[2])
 | 
						|
{
 | 
						|
	const float s = sinf(angle);
 | 
						|
	const float c = cosf(angle);
 | 
						|
	float p_new[2];
 | 
						|
 | 
						|
	/* translate point back to origin */
 | 
						|
	r_p[0] = (p[0] - cent[0]) / asp[0];
 | 
						|
	r_p[1] = (p[1] - cent[1]) / asp[1];
 | 
						|
 | 
						|
	/* rotate point */
 | 
						|
	p_new[0] = ((r_p[0] * c) - (r_p[1] * s)) * asp[0];
 | 
						|
	p_new[1] = ((r_p[0] * s) + (r_p[1] * c)) * asp[1];
 | 
						|
 | 
						|
	/* translate point back */
 | 
						|
	r_p[0] = p_new[0] + cent[0];
 | 
						|
	r_p[1] = p_new[1] + cent[1];
 | 
						|
}
 | 
						|
 | 
						|
BLI_INLINE unsigned int clampis_uint(const unsigned int v, const unsigned int min, const unsigned int max)
 | 
						|
{
 | 
						|
	return v < min ? min : (v > max ? max : v);
 | 
						|
}
 | 
						|
 | 
						|
/* --------------------------------------------------------------------- */
 | 
						|
/* local structs for mask rasterizeing                                   */
 | 
						|
/* --------------------------------------------------------------------- */
 | 
						|
 | 
						|
/**
 | 
						|
 * A single #MaskRasterHandle contains multiple #MaskRasterLayer's,
 | 
						|
 * each #MaskRasterLayer does its own lookup which contributes to
 | 
						|
 * the final pixel with its own blending mode and the final pixel
 | 
						|
 * is blended between these.
 | 
						|
 */
 | 
						|
 | 
						|
/* internal use only */
 | 
						|
typedef struct MaskRasterLayer {
 | 
						|
	/* geometry */
 | 
						|
	unsigned int   face_tot;
 | 
						|
	unsigned int (*face_array)[4];  /* access coords tri/quad */
 | 
						|
	float        (*face_coords)[3]; /* xy, z 0-1 (1.0 == filled) */
 | 
						|
 | 
						|
 | 
						|
	/* 2d bounds (to quickly skip bucket lookup) */
 | 
						|
	rctf bounds;
 | 
						|
 | 
						|
 | 
						|
	/* buckets */
 | 
						|
	unsigned int **buckets_face;
 | 
						|
	/* cache divide and subtract */
 | 
						|
	float buckets_xy_scalar[2]; /* (1.0 / (buckets_width + FLT_EPSILON)) * buckets_x */
 | 
						|
	unsigned int buckets_x;
 | 
						|
	unsigned int buckets_y;
 | 
						|
 | 
						|
 | 
						|
	/* copied direct from #MaskLayer.--- */
 | 
						|
	/* blending options */
 | 
						|
	float  alpha;
 | 
						|
	char   blend;
 | 
						|
	char   blend_flag;
 | 
						|
	char   falloff;
 | 
						|
 | 
						|
} MaskRasterLayer;
 | 
						|
 | 
						|
typedef struct MaskRasterSplineInfo {
 | 
						|
	/* body of the spline */
 | 
						|
	unsigned int vertex_offset;
 | 
						|
	unsigned int vertex_total;
 | 
						|
 | 
						|
	/* capping for non-filled, non cyclic splines */
 | 
						|
	unsigned int vertex_total_cap_head;
 | 
						|
	unsigned int vertex_total_cap_tail;
 | 
						|
 | 
						|
	bool is_cyclic;
 | 
						|
} MaskRasterSplineInfo;
 | 
						|
 | 
						|
/**
 | 
						|
 * opaque local struct for mask pixel lookup, each MaskLayer needs one of these
 | 
						|
 */
 | 
						|
struct MaskRasterHandle {
 | 
						|
	MaskRasterLayer *layers;
 | 
						|
	unsigned int     layers_tot;
 | 
						|
 | 
						|
	/* 2d bounds (to quickly skip bucket lookup) */
 | 
						|
	rctf bounds;
 | 
						|
};
 | 
						|
 | 
						|
/* --------------------------------------------------------------------- */
 | 
						|
/* alloc / free functions                                                */
 | 
						|
/* --------------------------------------------------------------------- */
 | 
						|
 | 
						|
MaskRasterHandle *BKE_maskrasterize_handle_new(void)
 | 
						|
{
 | 
						|
	MaskRasterHandle *mr_handle;
 | 
						|
 | 
						|
	mr_handle = MEM_callocN(sizeof(MaskRasterHandle), "MaskRasterHandle");
 | 
						|
 | 
						|
	return mr_handle;
 | 
						|
}
 | 
						|
 | 
						|
void BKE_maskrasterize_handle_free(MaskRasterHandle *mr_handle)
 | 
						|
{
 | 
						|
	const unsigned int layers_tot = mr_handle->layers_tot;
 | 
						|
	unsigned int i;
 | 
						|
	MaskRasterLayer *layer = mr_handle->layers;
 | 
						|
 | 
						|
	for (i = 0; i < layers_tot; i++, layer++) {
 | 
						|
 | 
						|
		if (layer->face_array) {
 | 
						|
			MEM_freeN(layer->face_array);
 | 
						|
		}
 | 
						|
 | 
						|
		if (layer->face_coords) {
 | 
						|
			MEM_freeN(layer->face_coords);
 | 
						|
		}
 | 
						|
 | 
						|
		if (layer->buckets_face) {
 | 
						|
			const unsigned int   bucket_tot = layer->buckets_x * layer->buckets_y;
 | 
						|
			unsigned int bucket_index;
 | 
						|
			for (bucket_index = 0; bucket_index < bucket_tot; bucket_index++) {
 | 
						|
				unsigned int *face_index = layer->buckets_face[bucket_index];
 | 
						|
				if (face_index) {
 | 
						|
					MEM_freeN(face_index);
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			MEM_freeN(layer->buckets_face);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	MEM_freeN(mr_handle->layers);
 | 
						|
	MEM_freeN(mr_handle);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void maskrasterize_spline_differentiate_point_outset(float (*diff_feather_points)[2], float (*diff_points)[2],
 | 
						|
                                                            const unsigned int tot_diff_point, const float ofs,
 | 
						|
                                                            const bool do_test)
 | 
						|
{
 | 
						|
	unsigned int k_prev = tot_diff_point - 2;
 | 
						|
	unsigned int k_curr = tot_diff_point - 1;
 | 
						|
	unsigned int k_next = 0;
 | 
						|
 | 
						|
	unsigned int k;
 | 
						|
 | 
						|
	float d_prev[2];
 | 
						|
	float d_next[2];
 | 
						|
	float d[2];
 | 
						|
 | 
						|
	const float *co_prev;
 | 
						|
	const float *co_curr;
 | 
						|
	const float *co_next;
 | 
						|
 | 
						|
	const float ofs_squared = ofs * ofs;
 | 
						|
 | 
						|
	co_prev = diff_points[k_prev];
 | 
						|
	co_curr = diff_points[k_curr];
 | 
						|
	co_next = diff_points[k_next];
 | 
						|
 | 
						|
	/* precalc */
 | 
						|
	sub_v2_v2v2(d_prev, co_prev, co_curr);
 | 
						|
	normalize_v2(d_prev);
 | 
						|
 | 
						|
	for (k = 0; k < tot_diff_point; k++) {
 | 
						|
 | 
						|
		/* co_prev = diff_points[k_prev]; */ /* precalc */
 | 
						|
		co_curr = diff_points[k_curr];
 | 
						|
		co_next = diff_points[k_next];
 | 
						|
 | 
						|
		/* sub_v2_v2v2(d_prev, co_prev, co_curr); */ /* precalc */
 | 
						|
		sub_v2_v2v2(d_next, co_curr, co_next);
 | 
						|
 | 
						|
		/* normalize_v2(d_prev); */ /* precalc */
 | 
						|
		normalize_v2(d_next);
 | 
						|
 | 
						|
		if ((do_test == false) ||
 | 
						|
		    (len_squared_v2v2(diff_feather_points[k], diff_points[k]) < ofs_squared))
 | 
						|
		{
 | 
						|
 | 
						|
			add_v2_v2v2(d, d_prev, d_next);
 | 
						|
 | 
						|
			normalize_v2(d);
 | 
						|
 | 
						|
			diff_feather_points[k][0] = diff_points[k][0] + ( d[1] * ofs);
 | 
						|
			diff_feather_points[k][1] = diff_points[k][1] + (-d[0] * ofs);
 | 
						|
		}
 | 
						|
 | 
						|
		/* use next iter */
 | 
						|
		copy_v2_v2(d_prev, d_next);
 | 
						|
 | 
						|
		/* k_prev = k_curr; */ /* precalc */
 | 
						|
		k_curr = k_next;
 | 
						|
		k_next++;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/* this function is not exact, sometimes it returns false positives,
 | 
						|
 * the main point of it is to clear out _almost_ all bucket/face non-intersections,
 | 
						|
 * returning true in corner cases is ok but missing an intersection is NOT.
 | 
						|
 *
 | 
						|
 * method used
 | 
						|
 * - check if the center of the buckets bounding box is intersecting the face
 | 
						|
 * - if not get the max radius to a corner of the bucket and see how close we
 | 
						|
 *   are to any of the triangle edges.
 | 
						|
 */
 | 
						|
static bool layer_bucket_isect_test(
 | 
						|
        const MaskRasterLayer *layer, unsigned int face_index,
 | 
						|
        const unsigned int bucket_x, const unsigned int bucket_y,
 | 
						|
        const float bucket_size_x, const float bucket_size_y,
 | 
						|
        const float bucket_max_rad_squared)
 | 
						|
{
 | 
						|
	unsigned int *face = layer->face_array[face_index];
 | 
						|
	float (*cos)[3] = layer->face_coords;
 | 
						|
 | 
						|
	const float xmin = layer->bounds.xmin + (bucket_size_x * (float)bucket_x);
 | 
						|
	const float ymin = layer->bounds.ymin + (bucket_size_y * (float)bucket_y);
 | 
						|
	const float xmax = xmin + bucket_size_x;
 | 
						|
	const float ymax = ymin + bucket_size_y;
 | 
						|
 | 
						|
	const float cent[2] = {(xmin + xmax) * 0.5f,
 | 
						|
	                       (ymin + ymax) * 0.5f};
 | 
						|
 | 
						|
	if (face[3] == TRI_VERT) {
 | 
						|
		const float *v1 = cos[face[0]];
 | 
						|
		const float *v2 = cos[face[1]];
 | 
						|
		const float *v3 = cos[face[2]];
 | 
						|
 | 
						|
		if (isect_point_tri_v2(cent, v1, v2, v3)) {
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			if ((dist_squared_to_line_segment_v2(cent, v1, v2) < bucket_max_rad_squared) ||
 | 
						|
			    (dist_squared_to_line_segment_v2(cent, v2, v3) < bucket_max_rad_squared) ||
 | 
						|
			    (dist_squared_to_line_segment_v2(cent, v3, v1) < bucket_max_rad_squared))
 | 
						|
			{
 | 
						|
				return true;
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				// printf("skip tri\n");
 | 
						|
				return false;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		const float *v1 = cos[face[0]];
 | 
						|
		const float *v2 = cos[face[1]];
 | 
						|
		const float *v3 = cos[face[2]];
 | 
						|
		const float *v4 = cos[face[3]];
 | 
						|
 | 
						|
		if (isect_point_tri_v2(cent, v1, v2, v3)) {
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
		else if (isect_point_tri_v2(cent, v1, v3, v4)) {
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			if ((dist_squared_to_line_segment_v2(cent, v1, v2) < bucket_max_rad_squared) ||
 | 
						|
			    (dist_squared_to_line_segment_v2(cent, v2, v3) < bucket_max_rad_squared) ||
 | 
						|
			    (dist_squared_to_line_segment_v2(cent, v3, v4) < bucket_max_rad_squared) ||
 | 
						|
			    (dist_squared_to_line_segment_v2(cent, v4, v1) < bucket_max_rad_squared))
 | 
						|
			{
 | 
						|
				return true;
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				// printf("skip quad\n");
 | 
						|
				return false;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void layer_bucket_init_dummy(MaskRasterLayer *layer)
 | 
						|
{
 | 
						|
	layer->face_tot = 0;
 | 
						|
	layer->face_coords = NULL;
 | 
						|
	layer->face_array  = NULL;
 | 
						|
 | 
						|
	layer->buckets_x = 0;
 | 
						|
	layer->buckets_y = 0;
 | 
						|
 | 
						|
	layer->buckets_xy_scalar[0] = 0.0f;
 | 
						|
	layer->buckets_xy_scalar[1] = 0.0f;
 | 
						|
 | 
						|
	layer->buckets_face = NULL;
 | 
						|
 | 
						|
	BLI_rctf_init(&layer->bounds, -1.0f, -1.0f, -1.0f, -1.0f);
 | 
						|
}
 | 
						|
 | 
						|
static void layer_bucket_init(MaskRasterLayer *layer, const float pixel_size)
 | 
						|
{
 | 
						|
	MemArena *arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), __func__);
 | 
						|
 | 
						|
	const float bucket_dim_x = BLI_rctf_size_x(&layer->bounds);
 | 
						|
	const float bucket_dim_y = BLI_rctf_size_y(&layer->bounds);
 | 
						|
 | 
						|
	layer->buckets_x = (unsigned int)((bucket_dim_x / pixel_size) / (float)BUCKET_PIXELS_PER_CELL);
 | 
						|
	layer->buckets_y = (unsigned int)((bucket_dim_y / pixel_size) / (float)BUCKET_PIXELS_PER_CELL);
 | 
						|
 | 
						|
//		printf("bucket size %ux%u\n", layer->buckets_x, layer->buckets_y);
 | 
						|
 | 
						|
	CLAMP(layer->buckets_x, 8, 512);
 | 
						|
	CLAMP(layer->buckets_y, 8, 512);
 | 
						|
 | 
						|
	layer->buckets_xy_scalar[0] = (1.0f / (bucket_dim_x + FLT_EPSILON)) * (float)layer->buckets_x;
 | 
						|
	layer->buckets_xy_scalar[1] = (1.0f / (bucket_dim_y + FLT_EPSILON)) * (float)layer->buckets_y;
 | 
						|
 | 
						|
	{
 | 
						|
		/* width and height of each bucket */
 | 
						|
		const float bucket_size_x = (bucket_dim_x + FLT_EPSILON) / (float)layer->buckets_x;
 | 
						|
		const float bucket_size_y = (bucket_dim_y + FLT_EPSILON) / (float)layer->buckets_y;
 | 
						|
		const float bucket_max_rad = (max_ff(bucket_size_x, bucket_size_y) * (float)M_SQRT2) + FLT_EPSILON;
 | 
						|
		const float bucket_max_rad_squared = bucket_max_rad * bucket_max_rad;
 | 
						|
 | 
						|
		unsigned int *face = &layer->face_array[0][0];
 | 
						|
		float (*cos)[3] = layer->face_coords;
 | 
						|
 | 
						|
		const unsigned int  bucket_tot = layer->buckets_x * layer->buckets_y;
 | 
						|
		LinkNode     **bucketstore     = MEM_callocN(bucket_tot * sizeof(LinkNode *),  __func__);
 | 
						|
		unsigned int  *bucketstore_tot = MEM_callocN(bucket_tot * sizeof(unsigned int), __func__);
 | 
						|
 | 
						|
		unsigned int face_index;
 | 
						|
 | 
						|
		for (face_index = 0; face_index < layer->face_tot; face_index++, face += 4) {
 | 
						|
			float xmin;
 | 
						|
			float xmax;
 | 
						|
			float ymin;
 | 
						|
			float ymax;
 | 
						|
 | 
						|
			if (face[3] == TRI_VERT) {
 | 
						|
				const float *v1 = cos[face[0]];
 | 
						|
				const float *v2 = cos[face[1]];
 | 
						|
				const float *v3 = cos[face[2]];
 | 
						|
 | 
						|
				xmin = min_ff(v1[0], min_ff(v2[0], v3[0]));
 | 
						|
				xmax = max_ff(v1[0], max_ff(v2[0], v3[0]));
 | 
						|
				ymin = min_ff(v1[1], min_ff(v2[1], v3[1]));
 | 
						|
				ymax = max_ff(v1[1], max_ff(v2[1], v3[1]));
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				const float *v1 = cos[face[0]];
 | 
						|
				const float *v2 = cos[face[1]];
 | 
						|
				const float *v3 = cos[face[2]];
 | 
						|
				const float *v4 = cos[face[3]];
 | 
						|
 | 
						|
				xmin = min_ff(v1[0], min_ff(v2[0], min_ff(v3[0], v4[0])));
 | 
						|
				xmax = max_ff(v1[0], max_ff(v2[0], max_ff(v3[0], v4[0])));
 | 
						|
				ymin = min_ff(v1[1], min_ff(v2[1], min_ff(v3[1], v4[1])));
 | 
						|
				ymax = max_ff(v1[1], max_ff(v2[1], max_ff(v3[1], v4[1])));
 | 
						|
			}
 | 
						|
 | 
						|
 | 
						|
			/* not essential but may as will skip any faces outside the view */
 | 
						|
			if (!((xmax < 0.0f) || (ymax < 0.0f) || (xmin > 1.0f) || (ymin > 1.0f))) {
 | 
						|
 | 
						|
				CLAMP(xmin, 0.0f,  1.0f);
 | 
						|
				CLAMP(ymin, 0.0f,  1.0f);
 | 
						|
				CLAMP(xmax, 0.0f,  1.0f);
 | 
						|
				CLAMP(ymax, 0.0f,  1.0f);
 | 
						|
 | 
						|
				{
 | 
						|
					unsigned int xi_min = (unsigned int) ((xmin - layer->bounds.xmin) * layer->buckets_xy_scalar[0]);
 | 
						|
					unsigned int xi_max = (unsigned int) ((xmax - layer->bounds.xmin) * layer->buckets_xy_scalar[0]);
 | 
						|
					unsigned int yi_min = (unsigned int) ((ymin - layer->bounds.ymin) * layer->buckets_xy_scalar[1]);
 | 
						|
					unsigned int yi_max = (unsigned int) ((ymax - layer->bounds.ymin) * layer->buckets_xy_scalar[1]);
 | 
						|
					void *face_index_void = SET_UINT_IN_POINTER(face_index);
 | 
						|
 | 
						|
					unsigned int xi, yi;
 | 
						|
 | 
						|
					/* this should _almost_ never happen but since it can in extreme cases,
 | 
						|
					 * we have to clamp the values or we overrun the buffer and crash */
 | 
						|
					if (xi_min >= layer->buckets_x) xi_min = layer->buckets_x - 1;
 | 
						|
					if (xi_max >= layer->buckets_x) xi_max = layer->buckets_x - 1;
 | 
						|
					if (yi_min >= layer->buckets_y) yi_min = layer->buckets_y - 1;
 | 
						|
					if (yi_max >= layer->buckets_y) yi_max = layer->buckets_y - 1;
 | 
						|
 | 
						|
					for (yi = yi_min; yi <= yi_max; yi++) {
 | 
						|
						unsigned int bucket_index = (layer->buckets_x * yi) + xi_min;
 | 
						|
						for (xi = xi_min; xi <= xi_max; xi++, bucket_index++) {
 | 
						|
							// unsigned int bucket_index = (layer->buckets_x * yi) + xi; /* correct but do in outer loop */
 | 
						|
 | 
						|
							BLI_assert(xi < layer->buckets_x);
 | 
						|
							BLI_assert(yi < layer->buckets_y);
 | 
						|
							BLI_assert(bucket_index < bucket_tot);
 | 
						|
 | 
						|
							/* check if the bucket intersects with the face */
 | 
						|
							/* note: there is a trade off here since checking box/tri intersections isn't
 | 
						|
							 * as optimal as it could be, but checking pixels against faces they will never intersect
 | 
						|
							 * with is likely the greater slowdown here - so check if the cell intersects the face */
 | 
						|
							if (layer_bucket_isect_test(layer, face_index,
 | 
						|
							                            xi, yi,
 | 
						|
							                            bucket_size_x, bucket_size_y,
 | 
						|
							                            bucket_max_rad_squared))
 | 
						|
							{
 | 
						|
								BLI_linklist_prepend_arena(&bucketstore[bucket_index], face_index_void, arena);
 | 
						|
								bucketstore_tot[bucket_index]++;
 | 
						|
							}
 | 
						|
						}
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (1) {
 | 
						|
			/* now convert linknodes into arrays for faster per pixel access */
 | 
						|
			unsigned int  **buckets_face = MEM_mallocN(bucket_tot * sizeof(*buckets_face), __func__);
 | 
						|
			unsigned int bucket_index;
 | 
						|
 | 
						|
			for (bucket_index = 0; bucket_index < bucket_tot; bucket_index++) {
 | 
						|
				if (bucketstore_tot[bucket_index]) {
 | 
						|
					unsigned int  *bucket = MEM_mallocN((bucketstore_tot[bucket_index] + 1) * sizeof(unsigned int),
 | 
						|
					                                    __func__);
 | 
						|
					LinkNode *bucket_node;
 | 
						|
 | 
						|
					buckets_face[bucket_index] = bucket;
 | 
						|
 | 
						|
					for (bucket_node = bucketstore[bucket_index]; bucket_node; bucket_node = bucket_node->next) {
 | 
						|
						*bucket = GET_UINT_FROM_POINTER(bucket_node->link);
 | 
						|
						bucket++;
 | 
						|
					}
 | 
						|
					*bucket = TRI_TERMINATOR_ID;
 | 
						|
				}
 | 
						|
				else {
 | 
						|
					buckets_face[bucket_index] = NULL;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			layer->buckets_face = buckets_face;
 | 
						|
		}
 | 
						|
 | 
						|
		MEM_freeN(bucketstore);
 | 
						|
		MEM_freeN(bucketstore_tot);
 | 
						|
	}
 | 
						|
 | 
						|
	BLI_memarena_free(arena);
 | 
						|
}
 | 
						|
 | 
						|
void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, struct Mask *mask,
 | 
						|
                                   const int width, const int height,
 | 
						|
                                   const bool do_aspect_correct, const bool do_mask_aa,
 | 
						|
                                   const bool do_feather)
 | 
						|
{
 | 
						|
	const rctf default_bounds = {0.0f, 1.0f, 0.0f, 1.0f};
 | 
						|
	const float pixel_size = 1.0f / (float)min_ii(width, height);
 | 
						|
	const float asp_xy[2] = {(do_aspect_correct && width > height) ? (float)height / (float)width  : 1.0f,
 | 
						|
	                         (do_aspect_correct && width < height) ? (float)width  / (float)height : 1.0f};
 | 
						|
 | 
						|
	const float zvec[3] = {0.0f, 0.0f, 1.0f};
 | 
						|
	MaskLayer *masklay;
 | 
						|
	unsigned int masklay_index;
 | 
						|
	MemArena *sf_arena;
 | 
						|
 | 
						|
	mr_handle->layers_tot = (unsigned int)BLI_listbase_count(&mask->masklayers);
 | 
						|
	mr_handle->layers = MEM_mallocN(sizeof(MaskRasterLayer) * mr_handle->layers_tot, "MaskRasterLayer");
 | 
						|
	BLI_rctf_init_minmax(&mr_handle->bounds);
 | 
						|
 | 
						|
	sf_arena = BLI_memarena_new(BLI_SCANFILL_ARENA_SIZE, __func__);
 | 
						|
 | 
						|
	for (masklay = mask->masklayers.first, masklay_index = 0; masklay; masklay = masklay->next, masklay_index++) {
 | 
						|
 | 
						|
		/* we need to store vertex ranges for open splines for filling */
 | 
						|
		unsigned int tot_splines;
 | 
						|
		MaskRasterSplineInfo *open_spline_ranges;
 | 
						|
		unsigned int   open_spline_index = 0;
 | 
						|
 | 
						|
		MaskSpline *spline;
 | 
						|
 | 
						|
		/* scanfill */
 | 
						|
		ScanFillContext sf_ctx;
 | 
						|
		ScanFillVert *sf_vert = NULL;
 | 
						|
		ScanFillVert *sf_vert_next = NULL;
 | 
						|
		ScanFillFace *sf_tri;
 | 
						|
 | 
						|
		unsigned int sf_vert_tot = 0;
 | 
						|
		unsigned int tot_feather_quads = 0;
 | 
						|
 | 
						|
#ifdef USE_SCANFILL_EDGE_WORKAROUND
 | 
						|
		unsigned int tot_boundary_used = 0;
 | 
						|
		unsigned int tot_boundary_found = 0;
 | 
						|
#endif
 | 
						|
 | 
						|
		if (masklay->restrictflag & MASK_RESTRICT_RENDER) {
 | 
						|
			/* skip the layer */
 | 
						|
			mr_handle->layers_tot--;
 | 
						|
			masklay_index--;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		tot_splines = (unsigned int)BLI_listbase_count(&masklay->splines);
 | 
						|
		open_spline_ranges = MEM_callocN(sizeof(*open_spline_ranges) * tot_splines, __func__);
 | 
						|
 | 
						|
		BLI_scanfill_begin_arena(&sf_ctx, sf_arena);
 | 
						|
 | 
						|
		for (spline = masklay->splines.first; spline; spline = spline->next) {
 | 
						|
			const bool is_cyclic = (spline->flag & MASK_SPLINE_CYCLIC) != 0;
 | 
						|
			const bool is_fill = (spline->flag & MASK_SPLINE_NOFILL) == 0;
 | 
						|
 | 
						|
			float (*diff_points)[2];
 | 
						|
			unsigned int tot_diff_point;
 | 
						|
 | 
						|
			float (*diff_feather_points)[2];
 | 
						|
			float (*diff_feather_points_flip)[2];
 | 
						|
			unsigned int tot_diff_feather_points;
 | 
						|
 | 
						|
			const unsigned int resol_a = BKE_mask_spline_resolution(spline, width, height) / 4;
 | 
						|
			const unsigned int resol_b = BKE_mask_spline_feather_resolution(spline, width, height) / 4;
 | 
						|
			const unsigned int resol = CLAMPIS(MAX2(resol_a, resol_b), 4, 512);
 | 
						|
 | 
						|
			diff_points = BKE_mask_spline_differentiate_with_resolution(
 | 
						|
			                  spline, &tot_diff_point, resol);
 | 
						|
 | 
						|
			if (do_feather) {
 | 
						|
				diff_feather_points = BKE_mask_spline_feather_differentiated_points_with_resolution(
 | 
						|
				                          spline, &tot_diff_feather_points, resol, false);
 | 
						|
				BLI_assert(diff_feather_points);
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				tot_diff_feather_points = 0;
 | 
						|
				diff_feather_points = NULL;
 | 
						|
			}
 | 
						|
 | 
						|
			if (tot_diff_point > 3) {
 | 
						|
				ScanFillVert *sf_vert_prev;
 | 
						|
				unsigned int j;
 | 
						|
 | 
						|
				float co[3];
 | 
						|
				co[2] = 0.0f;
 | 
						|
 | 
						|
				sf_ctx.poly_nr++;
 | 
						|
 | 
						|
				if (do_aspect_correct) {
 | 
						|
					if (width != height) {
 | 
						|
						float *fp;
 | 
						|
						float *ffp;
 | 
						|
						unsigned int i;
 | 
						|
						float asp;
 | 
						|
 | 
						|
						if (width < height) {
 | 
						|
							fp = &diff_points[0][0];
 | 
						|
							ffp = tot_diff_feather_points ? &diff_feather_points[0][0] : NULL;
 | 
						|
							asp = (float)width / (float)height;
 | 
						|
						}
 | 
						|
						else {
 | 
						|
							fp = &diff_points[0][1];
 | 
						|
							ffp = tot_diff_feather_points ? &diff_feather_points[0][1] : NULL;
 | 
						|
							asp = (float)height / (float)width;
 | 
						|
						}
 | 
						|
 | 
						|
						for (i = 0; i < tot_diff_point; i++, fp += 2) {
 | 
						|
							(*fp) = (((*fp) - 0.5f) / asp) + 0.5f;
 | 
						|
						}
 | 
						|
 | 
						|
						if (tot_diff_feather_points) {
 | 
						|
							for (i = 0; i < tot_diff_feather_points; i++, ffp += 2) {
 | 
						|
								(*ffp) = (((*ffp) - 0.5f) / asp) + 0.5f;
 | 
						|
							}
 | 
						|
						}
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				/* fake aa, using small feather */
 | 
						|
				if (do_mask_aa == true) {
 | 
						|
					if (do_feather == false) {
 | 
						|
						tot_diff_feather_points = tot_diff_point;
 | 
						|
						diff_feather_points = MEM_mallocN(sizeof(*diff_feather_points) *
 | 
						|
						                                  (size_t)tot_diff_feather_points,
 | 
						|
						                                  __func__);
 | 
						|
						/* add single pixel feather */
 | 
						|
						maskrasterize_spline_differentiate_point_outset(diff_feather_points, diff_points,
 | 
						|
						                                               tot_diff_point, pixel_size, false);
 | 
						|
					}
 | 
						|
					else {
 | 
						|
						/* ensure single pixel feather, on any zero feather areas */
 | 
						|
						maskrasterize_spline_differentiate_point_outset(diff_feather_points, diff_points,
 | 
						|
						                                               tot_diff_point, pixel_size, true);
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				if (is_fill) {
 | 
						|
					/* applt intersections depending on fill settings */
 | 
						|
					if (spline->flag & MASK_SPLINE_NOINTERSECT) {
 | 
						|
						BKE_mask_spline_feather_collapse_inner_loops(spline, diff_feather_points, tot_diff_feather_points);
 | 
						|
					}
 | 
						|
 | 
						|
					copy_v2_v2(co, diff_points[0]);
 | 
						|
					sf_vert_prev = BLI_scanfill_vert_add(&sf_ctx, co);
 | 
						|
					sf_vert_prev->tmp.u = sf_vert_tot;
 | 
						|
					sf_vert_prev->keyindex = sf_vert_tot + tot_diff_point; /* absolute index of feather vert */
 | 
						|
					sf_vert_tot++;
 | 
						|
 | 
						|
					/* TODO, an alternate functions so we can avoid double vector copy! */
 | 
						|
					for (j = 1; j < tot_diff_point; j++) {
 | 
						|
						copy_v2_v2(co, diff_points[j]);
 | 
						|
						sf_vert = BLI_scanfill_vert_add(&sf_ctx, co);
 | 
						|
						sf_vert->tmp.u = sf_vert_tot;
 | 
						|
						sf_vert->keyindex = sf_vert_tot + tot_diff_point; /* absolute index of feather vert */
 | 
						|
						sf_vert_tot++;
 | 
						|
					}
 | 
						|
 | 
						|
					sf_vert = sf_vert_prev;
 | 
						|
					sf_vert_prev = sf_ctx.fillvertbase.last;
 | 
						|
 | 
						|
					for (j = 0; j < tot_diff_point; j++) {
 | 
						|
						ScanFillEdge *sf_edge = BLI_scanfill_edge_add(&sf_ctx, sf_vert_prev, sf_vert);
 | 
						|
 | 
						|
#ifdef USE_SCANFILL_EDGE_WORKAROUND
 | 
						|
						if (diff_feather_points) {
 | 
						|
							sf_edge->tmp.c = SF_EDGE_IS_BOUNDARY;
 | 
						|
							tot_boundary_used++;
 | 
						|
						}
 | 
						|
#else
 | 
						|
						(void)sf_edge;
 | 
						|
#endif
 | 
						|
						sf_vert_prev = sf_vert;
 | 
						|
						sf_vert = sf_vert->next;
 | 
						|
					}
 | 
						|
 | 
						|
					if (diff_feather_points) {
 | 
						|
						float co_feather[3];
 | 
						|
						co_feather[2] = 1.0f;
 | 
						|
 | 
						|
						BLI_assert(tot_diff_feather_points == tot_diff_point);
 | 
						|
 | 
						|
						/* note: only added for convenience, we don't infact use these to scanfill,
 | 
						|
						 * only to create feather faces after scanfill */
 | 
						|
						for (j = 0; j < tot_diff_feather_points; j++) {
 | 
						|
							copy_v2_v2(co_feather, diff_feather_points[j]);
 | 
						|
							sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
 | 
						|
 | 
						|
							/* no need for these attrs */
 | 
						|
#if 0
 | 
						|
							sf_vert->tmp.u = sf_vert_tot;
 | 
						|
							sf_vert->keyindex = sf_vert_tot + tot_diff_point; /* absolute index of feather vert */
 | 
						|
#endif
 | 
						|
							sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
 | 
						|
							sf_vert_tot++;
 | 
						|
						}
 | 
						|
 | 
						|
						tot_feather_quads += tot_diff_point;
 | 
						|
					}
 | 
						|
				}
 | 
						|
				else {
 | 
						|
					/* unfilled spline */
 | 
						|
					if (diff_feather_points) {
 | 
						|
 | 
						|
						float co_diff[2];
 | 
						|
 | 
						|
						float co_feather[3];
 | 
						|
						co_feather[2] = 1.0f;
 | 
						|
 | 
						|
						if (spline->flag & MASK_SPLINE_NOINTERSECT) {
 | 
						|
							diff_feather_points_flip = MEM_mallocN(sizeof(float) * 2 * tot_diff_feather_points, "diff_feather_points_flip");
 | 
						|
 | 
						|
							for (j = 0; j < tot_diff_point; j++) {
 | 
						|
								sub_v2_v2v2(co_diff, diff_points[j], diff_feather_points[j]);
 | 
						|
								add_v2_v2v2(diff_feather_points_flip[j], diff_points[j], co_diff);
 | 
						|
							}
 | 
						|
 | 
						|
							BKE_mask_spline_feather_collapse_inner_loops(spline, diff_feather_points,      tot_diff_feather_points);
 | 
						|
							BKE_mask_spline_feather_collapse_inner_loops(spline, diff_feather_points_flip, tot_diff_feather_points);
 | 
						|
						}
 | 
						|
						else {
 | 
						|
							diff_feather_points_flip = NULL;
 | 
						|
						}
 | 
						|
 | 
						|
 | 
						|
						open_spline_ranges[open_spline_index].vertex_offset = sf_vert_tot;
 | 
						|
						open_spline_ranges[open_spline_index].vertex_total = tot_diff_point;
 | 
						|
 | 
						|
						/* TODO, an alternate functions so we can avoid double vector copy! */
 | 
						|
						for (j = 0; j < tot_diff_point; j++) {
 | 
						|
 | 
						|
							/* center vert */
 | 
						|
							copy_v2_v2(co, diff_points[j]);
 | 
						|
							sf_vert = BLI_scanfill_vert_add(&sf_ctx, co);
 | 
						|
							sf_vert->tmp.u = sf_vert_tot;
 | 
						|
							sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
 | 
						|
							sf_vert_tot++;
 | 
						|
 | 
						|
 | 
						|
							/* feather vert A */
 | 
						|
							copy_v2_v2(co_feather, diff_feather_points[j]);
 | 
						|
							sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
 | 
						|
							sf_vert->tmp.u = sf_vert_tot;
 | 
						|
							sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
 | 
						|
							sf_vert_tot++;
 | 
						|
 | 
						|
 | 
						|
							/* feather vert B */
 | 
						|
							if (diff_feather_points_flip) {
 | 
						|
								copy_v2_v2(co_feather, diff_feather_points_flip[j]);
 | 
						|
							}
 | 
						|
							else {
 | 
						|
								sub_v2_v2v2(co_diff, co, co_feather);
 | 
						|
								add_v2_v2v2(co_feather, co, co_diff);
 | 
						|
							}
 | 
						|
 | 
						|
							sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
 | 
						|
							sf_vert->tmp.u = sf_vert_tot;
 | 
						|
							sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
 | 
						|
							sf_vert_tot++;
 | 
						|
 | 
						|
							tot_feather_quads += 2;
 | 
						|
						}
 | 
						|
 | 
						|
						if (!is_cyclic) {
 | 
						|
							tot_feather_quads -= 2;
 | 
						|
						}
 | 
						|
 | 
						|
						if (diff_feather_points_flip) {
 | 
						|
							MEM_freeN(diff_feather_points_flip);
 | 
						|
							diff_feather_points_flip = NULL;
 | 
						|
						}
 | 
						|
 | 
						|
						/* cap ends */
 | 
						|
 | 
						|
						/* dummy init value */
 | 
						|
						open_spline_ranges[open_spline_index].vertex_total_cap_head = 0;
 | 
						|
						open_spline_ranges[open_spline_index].vertex_total_cap_tail = 0;
 | 
						|
 | 
						|
						if (!is_cyclic) {
 | 
						|
							const float *fp_cent;
 | 
						|
							const float *fp_turn;
 | 
						|
 | 
						|
							unsigned int k;
 | 
						|
 | 
						|
							fp_cent = diff_points[0];
 | 
						|
							fp_turn = diff_feather_points[0];
 | 
						|
 | 
						|
#define CALC_CAP_RESOL                                                                      \
 | 
						|
	clampis_uint((unsigned int )(len_v2v2(fp_cent, fp_turn) /                               \
 | 
						|
	                             (pixel_size * SPLINE_RESOL_CAP_PER_PIXEL)),                \
 | 
						|
	             SPLINE_RESOL_CAP_MIN, SPLINE_RESOL_CAP_MAX)
 | 
						|
 | 
						|
							{
 | 
						|
								const unsigned int vertex_total_cap = CALC_CAP_RESOL;
 | 
						|
 | 
						|
								for (k = 1; k < vertex_total_cap; k++) {
 | 
						|
									const float angle = (float)k * (1.0f / (float)vertex_total_cap) * (float)M_PI;
 | 
						|
									rotate_point_v2(co_feather, fp_turn, fp_cent, angle, asp_xy);
 | 
						|
 | 
						|
									sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
 | 
						|
									sf_vert->tmp.u = sf_vert_tot;
 | 
						|
									sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
 | 
						|
									sf_vert_tot++;
 | 
						|
								}
 | 
						|
								tot_feather_quads += vertex_total_cap;
 | 
						|
 | 
						|
								open_spline_ranges[open_spline_index].vertex_total_cap_head = vertex_total_cap;
 | 
						|
							}
 | 
						|
 | 
						|
							fp_cent = diff_points[tot_diff_point - 1];
 | 
						|
							fp_turn = diff_feather_points[tot_diff_point - 1];
 | 
						|
 | 
						|
							{
 | 
						|
								const unsigned int vertex_total_cap = CALC_CAP_RESOL;
 | 
						|
 | 
						|
								for (k = 1; k < vertex_total_cap; k++) {
 | 
						|
									const float angle = (float)k * (1.0f / (float)vertex_total_cap) * (float)M_PI;
 | 
						|
									rotate_point_v2(co_feather, fp_turn, fp_cent, -angle, asp_xy);
 | 
						|
 | 
						|
									sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
 | 
						|
									sf_vert->tmp.u = sf_vert_tot;
 | 
						|
									sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
 | 
						|
									sf_vert_tot++;
 | 
						|
								}
 | 
						|
								tot_feather_quads += vertex_total_cap;
 | 
						|
 | 
						|
								open_spline_ranges[open_spline_index].vertex_total_cap_tail = vertex_total_cap;
 | 
						|
							}
 | 
						|
						}
 | 
						|
 | 
						|
						open_spline_ranges[open_spline_index].is_cyclic = is_cyclic;
 | 
						|
						open_spline_index++;
 | 
						|
 | 
						|
#undef CALC_CAP_RESOL
 | 
						|
						/* end capping */
 | 
						|
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if (diff_points) {
 | 
						|
				MEM_freeN(diff_points);
 | 
						|
			}
 | 
						|
 | 
						|
			if (diff_feather_points) {
 | 
						|
				MEM_freeN(diff_feather_points);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		{
 | 
						|
			unsigned int (*face_array)[4], *face;  /* access coords */
 | 
						|
			float        (*face_coords)[3], *cos; /* xy, z 0-1 (1.0 == filled) */
 | 
						|
			unsigned int sf_tri_tot;
 | 
						|
			rctf bounds;
 | 
						|
			unsigned int face_index;
 | 
						|
			int scanfill_flag = 0;
 | 
						|
 | 
						|
			bool is_isect = false;
 | 
						|
			ListBase isect_remvertbase = {NULL, NULL};
 | 
						|
			ListBase isect_remedgebase = {NULL, NULL};
 | 
						|
 | 
						|
			/* now we have all the splines */
 | 
						|
			face_coords = MEM_mallocN((sizeof(float) * 3) * sf_vert_tot, "maskrast_face_coords");
 | 
						|
 | 
						|
			/* init bounds */
 | 
						|
			BLI_rctf_init_minmax(&bounds);
 | 
						|
 | 
						|
			/* coords */
 | 
						|
			cos = (float *)face_coords;
 | 
						|
			for (sf_vert = sf_ctx.fillvertbase.first; sf_vert; sf_vert = sf_vert_next) {
 | 
						|
				sf_vert_next = sf_vert->next;
 | 
						|
				copy_v3_v3(cos, sf_vert->co);
 | 
						|
 | 
						|
				/* remove so as not to interfere with fill (called after) */
 | 
						|
				if (sf_vert->keyindex == SF_KEYINDEX_TEMP_ID) {
 | 
						|
					BLI_remlink(&sf_ctx.fillvertbase, sf_vert);
 | 
						|
				}
 | 
						|
 | 
						|
				/* bounds */
 | 
						|
				BLI_rctf_do_minmax_v(&bounds, cos);
 | 
						|
 | 
						|
				cos += 3;
 | 
						|
			}
 | 
						|
 | 
						|
 | 
						|
			/* --- inefficient self-intersect case --- */
 | 
						|
			/* if self intersections are found, its too trickty to attempt to map vertices
 | 
						|
			 * so just realloc and add entirely new vertices - the result of the self-intersect check
 | 
						|
			 */
 | 
						|
			if ((masklay->flag & MASK_LAYERFLAG_FILL_OVERLAP) &&
 | 
						|
			    (is_isect = BLI_scanfill_calc_self_isect(&sf_ctx,
 | 
						|
			                                             &isect_remvertbase,
 | 
						|
			                                             &isect_remedgebase)))
 | 
						|
			{
 | 
						|
				unsigned int sf_vert_tot_isect = (unsigned int)BLI_listbase_count(&sf_ctx.fillvertbase);
 | 
						|
				unsigned int i = sf_vert_tot;
 | 
						|
 | 
						|
				face_coords = MEM_reallocN(face_coords, sizeof(float[3]) * (sf_vert_tot + sf_vert_tot_isect));
 | 
						|
 | 
						|
				cos = (float *)&face_coords[sf_vert_tot][0];
 | 
						|
 | 
						|
				for (sf_vert = sf_ctx.fillvertbase.first; sf_vert; sf_vert = sf_vert->next) {
 | 
						|
					copy_v3_v3(cos, sf_vert->co);
 | 
						|
					sf_vert->tmp.u = i++;
 | 
						|
					cos += 3;
 | 
						|
				}
 | 
						|
 | 
						|
				sf_vert_tot += sf_vert_tot_isect;
 | 
						|
 | 
						|
				/* we need to calc polys after self intersect */
 | 
						|
				scanfill_flag |= BLI_SCANFILL_CALC_POLYS;
 | 
						|
			}
 | 
						|
			/* --- end inefficient code --- */
 | 
						|
 | 
						|
 | 
						|
			/* main scan-fill */
 | 
						|
			if ((masklay->flag & MASK_LAYERFLAG_FILL_DISCRETE) == 0)
 | 
						|
				scanfill_flag |= BLI_SCANFILL_CALC_HOLES;
 | 
						|
 | 
						|
			sf_tri_tot = (unsigned int)BLI_scanfill_calc_ex(&sf_ctx, scanfill_flag, zvec);
 | 
						|
 | 
						|
			if (is_isect) {
 | 
						|
				/* add removed data back, we only need edges for feather,
 | 
						|
				 * but add verts back so they get freed along with others */
 | 
						|
				BLI_movelisttolist(&sf_ctx.fillvertbase, &isect_remvertbase);
 | 
						|
				BLI_movelisttolist(&sf_ctx.filledgebase, &isect_remedgebase);
 | 
						|
			}
 | 
						|
 | 
						|
			face_array = MEM_mallocN(sizeof(*face_array) * ((size_t)sf_tri_tot + (size_t)tot_feather_quads), "maskrast_face_index");
 | 
						|
			face_index = 0;
 | 
						|
 | 
						|
			/* faces */
 | 
						|
			face = (unsigned int *)face_array;
 | 
						|
			for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) {
 | 
						|
				*(face++) = sf_tri->v3->tmp.u;
 | 
						|
				*(face++) = sf_tri->v2->tmp.u;
 | 
						|
				*(face++) = sf_tri->v1->tmp.u;
 | 
						|
				*(face++) = TRI_VERT;
 | 
						|
				face_index++;
 | 
						|
				FACE_ASSERT(face - 4, sf_vert_tot);
 | 
						|
			}
 | 
						|
 | 
						|
			/* start of feather faces... if we have this set,
 | 
						|
			 * 'face_index' is kept from loop above */
 | 
						|
 | 
						|
			BLI_assert(face_index == sf_tri_tot);
 | 
						|
 | 
						|
			if (tot_feather_quads) {
 | 
						|
				ScanFillEdge *sf_edge;
 | 
						|
 | 
						|
				for (sf_edge = sf_ctx.filledgebase.first; sf_edge; sf_edge = sf_edge->next) {
 | 
						|
					if (sf_edge->tmp.c == SF_EDGE_IS_BOUNDARY) {
 | 
						|
						*(face++) = sf_edge->v1->tmp.u;
 | 
						|
						*(face++) = sf_edge->v2->tmp.u;
 | 
						|
						*(face++) = sf_edge->v2->keyindex;
 | 
						|
						*(face++) = sf_edge->v1->keyindex;
 | 
						|
						face_index++;
 | 
						|
						FACE_ASSERT(face - 4, sf_vert_tot);
 | 
						|
 | 
						|
#ifdef USE_SCANFILL_EDGE_WORKAROUND
 | 
						|
						tot_boundary_found++;
 | 
						|
#endif
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
#ifdef USE_SCANFILL_EDGE_WORKAROUND
 | 
						|
			if (tot_boundary_found != tot_boundary_used) {
 | 
						|
				BLI_assert(tot_boundary_found < tot_boundary_used);
 | 
						|
			}
 | 
						|
#endif
 | 
						|
 | 
						|
			/* feather only splines */
 | 
						|
			while (open_spline_index > 0) {
 | 
						|
				const unsigned int vertex_offset         = open_spline_ranges[--open_spline_index].vertex_offset;
 | 
						|
				unsigned int       vertex_total          = open_spline_ranges[  open_spline_index].vertex_total;
 | 
						|
				unsigned int       vertex_total_cap_head = open_spline_ranges[  open_spline_index].vertex_total_cap_head;
 | 
						|
				unsigned int       vertex_total_cap_tail = open_spline_ranges[  open_spline_index].vertex_total_cap_tail;
 | 
						|
				unsigned int k, j;
 | 
						|
 | 
						|
				j = vertex_offset;
 | 
						|
 | 
						|
				/* subtract one since we reference next vertex triple */
 | 
						|
				for (k = 0; k < vertex_total - 1; k++, j += 3) {
 | 
						|
 | 
						|
					BLI_assert(j == vertex_offset + (k * 3));
 | 
						|
 | 
						|
					*(face++) = j + 3; /* next span */ /* z 1 */
 | 
						|
					*(face++) = j + 0;                 /* z 1 */
 | 
						|
					*(face++) = j + 1;                 /* z 0 */
 | 
						|
					*(face++) = j + 4; /* next span */ /* z 0 */
 | 
						|
					face_index++;
 | 
						|
					FACE_ASSERT(face - 4, sf_vert_tot);
 | 
						|
 | 
						|
					*(face++) = j + 0;                 /* z 1 */
 | 
						|
					*(face++) = j + 3; /* next span */ /* z 1 */
 | 
						|
					*(face++) = j + 5; /* next span */ /* z 0 */
 | 
						|
					*(face++) = j + 2;                 /* z 0 */
 | 
						|
					face_index++;
 | 
						|
					FACE_ASSERT(face - 4, sf_vert_tot);
 | 
						|
				}
 | 
						|
 | 
						|
				if (open_spline_ranges[open_spline_index].is_cyclic) {
 | 
						|
					*(face++) = vertex_offset + 0; /* next span */ /* z 1 */
 | 
						|
					*(face++) = j             + 0;                 /* z 1 */
 | 
						|
					*(face++) = j             + 1;                 /* z 0 */
 | 
						|
					*(face++) = vertex_offset + 1; /* next span */ /* z 0 */
 | 
						|
					face_index++;
 | 
						|
					FACE_ASSERT(face - 4, sf_vert_tot);
 | 
						|
 | 
						|
					*(face++) = j          + 0;                    /* z 1 */
 | 
						|
					*(face++) = vertex_offset + 0; /* next span */ /* z 1 */
 | 
						|
					*(face++) = vertex_offset + 2; /* next span */ /* z 0 */
 | 
						|
					*(face++) = j          + 2;                    /* z 0 */
 | 
						|
					face_index++;
 | 
						|
					FACE_ASSERT(face - 4, sf_vert_tot);
 | 
						|
				}
 | 
						|
				else {
 | 
						|
					unsigned int midvidx = vertex_offset;
 | 
						|
 | 
						|
					/***************
 | 
						|
					 * cap end 'a' */
 | 
						|
					j = midvidx + (vertex_total * 3);
 | 
						|
 | 
						|
					for (k = 0; k < vertex_total_cap_head - 2; k++, j++) {
 | 
						|
						*(face++) = midvidx + 0;  /* z 1 */
 | 
						|
						*(face++) = midvidx + 0;  /* z 1 */
 | 
						|
						*(face++) = j + 0;        /* z 0 */
 | 
						|
						*(face++) = j + 1;        /* z 0 */
 | 
						|
						face_index++;
 | 
						|
						FACE_ASSERT(face - 4, sf_vert_tot);
 | 
						|
					}
 | 
						|
 | 
						|
					j = vertex_offset + (vertex_total * 3);
 | 
						|
 | 
						|
					/* 2 tris that join the original */
 | 
						|
					*(face++) = midvidx + 0;  /* z 1 */
 | 
						|
					*(face++) = midvidx + 0;  /* z 1 */
 | 
						|
					*(face++) = midvidx + 1;  /* z 0 */
 | 
						|
					*(face++) = j + 0;        /* z 0 */
 | 
						|
					face_index++;
 | 
						|
					FACE_ASSERT(face - 4, sf_vert_tot);
 | 
						|
 | 
						|
					*(face++) = midvidx + 0;                    /* z 1 */
 | 
						|
					*(face++) = midvidx + 0;                    /* z 1 */
 | 
						|
					*(face++) = j + vertex_total_cap_head - 2;  /* z 0 */
 | 
						|
					*(face++) = midvidx + 2;                    /* z 0 */
 | 
						|
					face_index++;
 | 
						|
					FACE_ASSERT(face - 4, sf_vert_tot);
 | 
						|
 | 
						|
 | 
						|
					/***************
 | 
						|
					 * cap end 'b' */
 | 
						|
					/* ... same as previous but v 2-3 flipped, and different initial offsets */
 | 
						|
 | 
						|
					j = vertex_offset + (vertex_total * 3) + (vertex_total_cap_head - 1);
 | 
						|
 | 
						|
					midvidx = vertex_offset + (vertex_total * 3) - 3;
 | 
						|
 | 
						|
					for (k = 0; k < vertex_total_cap_tail - 2; k++, j++) {
 | 
						|
						*(face++) = midvidx;  /* z 1 */
 | 
						|
						*(face++) = midvidx;  /* z 1 */
 | 
						|
						*(face++) = j + 1;    /* z 0 */
 | 
						|
						*(face++) = j + 0;    /* z 0 */
 | 
						|
						face_index++;
 | 
						|
						FACE_ASSERT(face - 4, sf_vert_tot);
 | 
						|
					}
 | 
						|
 | 
						|
					j = vertex_offset + (vertex_total * 3) + (vertex_total_cap_head - 1);
 | 
						|
 | 
						|
					/* 2 tris that join the original */
 | 
						|
					*(face++) = midvidx + 0;  /* z 1 */
 | 
						|
					*(face++) = midvidx + 0;  /* z 1 */
 | 
						|
					*(face++) = j + 0;        /* z 0 */
 | 
						|
					*(face++) = midvidx + 1;  /* z 0 */
 | 
						|
					face_index++;
 | 
						|
					FACE_ASSERT(face - 4, sf_vert_tot);
 | 
						|
 | 
						|
					*(face++) = midvidx + 0;                    /* z 1 */
 | 
						|
					*(face++) = midvidx + 0;                    /* z 1 */
 | 
						|
					*(face++) = midvidx + 2;                    /* z 0 */
 | 
						|
					*(face++) = j + vertex_total_cap_tail - 2;  /* z 0 */
 | 
						|
					face_index++;
 | 
						|
					FACE_ASSERT(face - 4, sf_vert_tot);
 | 
						|
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			MEM_freeN(open_spline_ranges);
 | 
						|
 | 
						|
//			fprintf(stderr, "%u %u (%u %u), %u\n", face_index, sf_tri_tot + tot_feather_quads, sf_tri_tot, tot_feather_quads, tot_boundary_used - tot_boundary_found);
 | 
						|
 | 
						|
#ifdef USE_SCANFILL_EDGE_WORKAROUND
 | 
						|
			BLI_assert(face_index + (tot_boundary_used - tot_boundary_found) == sf_tri_tot + tot_feather_quads);
 | 
						|
#else
 | 
						|
			BLI_assert(face_index == sf_tri_tot + tot_feather_quads);
 | 
						|
#endif
 | 
						|
			{
 | 
						|
				MaskRasterLayer *layer = &mr_handle->layers[masklay_index];
 | 
						|
 | 
						|
				if (BLI_rctf_isect(&default_bounds, &bounds, &bounds)) {
 | 
						|
#ifdef USE_SCANFILL_EDGE_WORKAROUND
 | 
						|
					layer->face_tot = (sf_tri_tot + tot_feather_quads) - (tot_boundary_used - tot_boundary_found);
 | 
						|
#else
 | 
						|
					layer->face_tot = (sf_tri_tot + tot_feather_quads);
 | 
						|
#endif
 | 
						|
					layer->face_coords = face_coords;
 | 
						|
					layer->face_array  = face_array;
 | 
						|
					layer->bounds = bounds;
 | 
						|
 | 
						|
					layer_bucket_init(layer, pixel_size);
 | 
						|
 | 
						|
					BLI_rctf_union(&mr_handle->bounds, &bounds);
 | 
						|
				}
 | 
						|
				else {
 | 
						|
					MEM_freeN(face_coords);
 | 
						|
					MEM_freeN(face_array);
 | 
						|
 | 
						|
					layer_bucket_init_dummy(layer);
 | 
						|
				}
 | 
						|
 | 
						|
				/* copy as-is */
 | 
						|
				layer->alpha = masklay->alpha;
 | 
						|
				layer->blend = masklay->blend;
 | 
						|
				layer->blend_flag = masklay->blend_flag;
 | 
						|
				layer->falloff = masklay->falloff;
 | 
						|
			}
 | 
						|
 | 
						|
			/* printf("tris %d, feather tris %d\n", sf_tri_tot, tot_feather_quads); */
 | 
						|
		}
 | 
						|
 | 
						|
		/* add trianges */
 | 
						|
		BLI_scanfill_end_arena(&sf_ctx, sf_arena);
 | 
						|
	}
 | 
						|
 | 
						|
	BLI_memarena_free(sf_arena);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* --------------------------------------------------------------------- */
 | 
						|
/* functions that run inside the sampling thread (keep fast!)            */
 | 
						|
/* --------------------------------------------------------------------- */
 | 
						|
 | 
						|
/* 2D ray test */
 | 
						|
#if 0
 | 
						|
static float maskrasterize_layer_z_depth_tri(const float pt[2],
 | 
						|
                                             const float v1[3], const float v2[3], const float v3[3])
 | 
						|
{
 | 
						|
	float w[3];
 | 
						|
	barycentric_weights_v2(v1, v2, v3, pt, w);
 | 
						|
	return (v1[2] * w[0]) + (v2[2] * w[1]) + (v3[2] * w[2]);
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#if 1
 | 
						|
static float maskrasterize_layer_z_depth_quad(const float pt[2],
 | 
						|
                                              const float v1[3], const float v2[3], const float v3[3], const float v4[3])
 | 
						|
{
 | 
						|
	float w[4];
 | 
						|
	barycentric_weights_v2_quad(v1, v2, v3, v4, pt, w);
 | 
						|
	//return (v1[2] * w[0]) + (v2[2] * w[1]) + (v3[2] * w[2]) + (v4[2] * w[3]);
 | 
						|
	return w[2] + w[3];  /* we can make this assumption for small speedup */
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
static float maskrasterize_layer_isect(unsigned int *face, float (*cos)[3], const float dist_orig, const float xy[2])
 | 
						|
{
 | 
						|
	/* we always cast from same place only need xy */
 | 
						|
	if (face[3] == TRI_VERT) {
 | 
						|
		/* --- tri --- */
 | 
						|
 | 
						|
#if 0
 | 
						|
		/* not essential but avoids unneeded extra lookups */
 | 
						|
		if ((cos[0][2] < dist_orig) ||
 | 
						|
		    (cos[1][2] < dist_orig) ||
 | 
						|
		    (cos[2][2] < dist_orig))
 | 
						|
		{
 | 
						|
			if (isect_point_tri_v2_cw(xy, cos[face[0]], cos[face[1]], cos[face[2]])) {
 | 
						|
				/* we know all tris are close for now */
 | 
						|
				return maskrasterize_layer_z_depth_tri(xy, cos[face[0]], cos[face[1]], cos[face[2]]);
 | 
						|
			}
 | 
						|
		}
 | 
						|
#else
 | 
						|
		/* we know all tris are close for now */
 | 
						|
		if (1) {
 | 
						|
			if (isect_point_tri_v2_cw(xy, cos[face[0]], cos[face[1]], cos[face[2]])) {
 | 
						|
				return 0.0f;
 | 
						|
			}
 | 
						|
		}
 | 
						|
#endif
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		/* --- quad --- */
 | 
						|
 | 
						|
		/* not essential but avoids unneeded extra lookups */
 | 
						|
		if ((cos[0][2] < dist_orig) ||
 | 
						|
		    (cos[1][2] < dist_orig) ||
 | 
						|
		    (cos[2][2] < dist_orig) ||
 | 
						|
		    (cos[3][2] < dist_orig))
 | 
						|
		{
 | 
						|
 | 
						|
			/* needs work */
 | 
						|
#if 1
 | 
						|
			/* quad check fails for bow-tie, so keep using 2 tri checks */
 | 
						|
			//if (isect_point_quad_v2(xy, cos[face[0]], cos[face[1]], cos[face[2]], cos[face[3]]))
 | 
						|
			if (isect_point_tri_v2(xy, cos[face[0]], cos[face[1]], cos[face[2]]) ||
 | 
						|
			    isect_point_tri_v2(xy, cos[face[0]], cos[face[2]], cos[face[3]]))
 | 
						|
			{
 | 
						|
				return maskrasterize_layer_z_depth_quad(xy, cos[face[0]], cos[face[1]], cos[face[2]], cos[face[3]]);
 | 
						|
			}
 | 
						|
#elif 1
 | 
						|
			/* don't use isect_point_tri_v2_cw because we could have bow-tie quads */
 | 
						|
 | 
						|
			if (isect_point_tri_v2(xy, cos[face[0]], cos[face[1]], cos[face[2]])) {
 | 
						|
				return maskrasterize_layer_z_depth_tri(xy, cos[face[0]], cos[face[1]], cos[face[2]]);
 | 
						|
			}
 | 
						|
			else if (isect_point_tri_v2(xy, cos[face[0]], cos[face[2]], cos[face[3]])) {
 | 
						|
				return maskrasterize_layer_z_depth_tri(xy, cos[face[0]], cos[face[2]], cos[face[3]]);
 | 
						|
			}
 | 
						|
#else
 | 
						|
			/* cheat - we know first 2 verts are z0.0f and second 2 are z 1.0f */
 | 
						|
			/* ... worth looking into */
 | 
						|
#endif
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return 1.0f;
 | 
						|
}
 | 
						|
 | 
						|
BLI_INLINE unsigned int layer_bucket_index_from_xy(MaskRasterLayer *layer, const float xy[2])
 | 
						|
{
 | 
						|
	BLI_assert(BLI_rctf_isect_pt_v(&layer->bounds, xy));
 | 
						|
 | 
						|
	return ( (unsigned int)((xy[0] - layer->bounds.xmin) * layer->buckets_xy_scalar[0])) +
 | 
						|
	       (((unsigned int)((xy[1] - layer->bounds.ymin) * layer->buckets_xy_scalar[1])) * layer->buckets_x);
 | 
						|
}
 | 
						|
 | 
						|
static float layer_bucket_depth_from_xy(MaskRasterLayer *layer, const float xy[2])
 | 
						|
{
 | 
						|
	unsigned int index = layer_bucket_index_from_xy(layer, xy);
 | 
						|
	unsigned int *face_index = layer->buckets_face[index];
 | 
						|
 | 
						|
	if (face_index) {
 | 
						|
		unsigned int (*face_array)[4] = layer->face_array;
 | 
						|
		float        (*cos)[3]        = layer->face_coords;
 | 
						|
		float best_dist = 1.0f;
 | 
						|
		while (*face_index != TRI_TERMINATOR_ID) {
 | 
						|
			const float test_dist = maskrasterize_layer_isect(face_array[*face_index], cos, best_dist, xy);
 | 
						|
			if (test_dist < best_dist) {
 | 
						|
				best_dist = test_dist;
 | 
						|
				/* comparing with 0.0f is OK here because triangles are always zero depth */
 | 
						|
				if (best_dist == 0.0f) {
 | 
						|
					/* bail early, we're as close as possible */
 | 
						|
					return 0.0f;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			face_index++;
 | 
						|
		}
 | 
						|
		return best_dist;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		return 1.0f;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
float BKE_maskrasterize_handle_sample(MaskRasterHandle *mr_handle, const float xy[2])
 | 
						|
{
 | 
						|
	/* can't do this because some layers may invert */
 | 
						|
	/* if (BLI_rctf_isect_pt_v(&mr_handle->bounds, xy)) */
 | 
						|
 | 
						|
	const unsigned int layers_tot = mr_handle->layers_tot;
 | 
						|
	unsigned int i;
 | 
						|
	MaskRasterLayer *layer = mr_handle->layers;
 | 
						|
 | 
						|
	/* return value */
 | 
						|
	float value = 0.0f;
 | 
						|
 | 
						|
	for (i = 0; i < layers_tot; i++, layer++) {
 | 
						|
		float value_layer;
 | 
						|
 | 
						|
		/* also used as signal for unused layer (when render is disabled) */
 | 
						|
		if (layer->alpha != 0.0f && BLI_rctf_isect_pt_v(&layer->bounds, xy)) {
 | 
						|
			value_layer = 1.0f - layer_bucket_depth_from_xy(layer, xy);
 | 
						|
 | 
						|
			switch (layer->falloff) {
 | 
						|
				case PROP_SMOOTH:
 | 
						|
					/* ease - gives less hard lines for dilate/erode feather */
 | 
						|
					value_layer = (3.0f * value_layer * value_layer - 2.0f * value_layer * value_layer * value_layer);
 | 
						|
					break;
 | 
						|
				case PROP_SPHERE:
 | 
						|
					value_layer = sqrtf(2.0f * value_layer - value_layer * value_layer);
 | 
						|
					break;
 | 
						|
				case PROP_ROOT:
 | 
						|
					value_layer = sqrtf(value_layer);
 | 
						|
					break;
 | 
						|
				case PROP_SHARP:
 | 
						|
					value_layer = value_layer * value_layer;
 | 
						|
					break;
 | 
						|
				case PROP_INVSQUARE:
 | 
						|
					value_layer = value_layer * (2.0f - value_layer);
 | 
						|
					break;
 | 
						|
				case PROP_LIN:
 | 
						|
				default:
 | 
						|
					/* nothing */
 | 
						|
					break;
 | 
						|
			}
 | 
						|
 | 
						|
			if (layer->blend != MASK_BLEND_REPLACE) {
 | 
						|
				value_layer *= layer->alpha;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			value_layer = 0.0f;
 | 
						|
		}
 | 
						|
 | 
						|
		if (layer->blend_flag & MASK_BLENDFLAG_INVERT) {
 | 
						|
			value_layer = 1.0f - value_layer;
 | 
						|
		}
 | 
						|
 | 
						|
		switch (layer->blend) {
 | 
						|
			case MASK_BLEND_MERGE_ADD:
 | 
						|
				value += value_layer * (1.0f - value);
 | 
						|
				break;
 | 
						|
			case MASK_BLEND_MERGE_SUBTRACT:
 | 
						|
				value -= value_layer * value;
 | 
						|
				break;
 | 
						|
			case MASK_BLEND_ADD:
 | 
						|
				value += value_layer;
 | 
						|
				break;
 | 
						|
			case MASK_BLEND_SUBTRACT:
 | 
						|
				value -= value_layer;
 | 
						|
				break;
 | 
						|
			case MASK_BLEND_LIGHTEN:
 | 
						|
				value = max_ff(value, value_layer);
 | 
						|
				break;
 | 
						|
			case MASK_BLEND_DARKEN:
 | 
						|
				value = min_ff(value, value_layer);
 | 
						|
				break;
 | 
						|
			case MASK_BLEND_MUL:
 | 
						|
				value *= value_layer;
 | 
						|
				break;
 | 
						|
			case MASK_BLEND_REPLACE:
 | 
						|
				value = (value * (1.0f - layer->alpha)) + (value_layer * layer->alpha);
 | 
						|
				break;
 | 
						|
			case MASK_BLEND_DIFFERENCE:
 | 
						|
				value = fabsf(value - value_layer);
 | 
						|
				break;
 | 
						|
			default: /* same as add */
 | 
						|
				BLI_assert(0);
 | 
						|
				value += value_layer;
 | 
						|
				break;
 | 
						|
		}
 | 
						|
 | 
						|
		/* clamp after applying each layer so we don't get
 | 
						|
		 * issues subtracting after accumulating over 1.0f */
 | 
						|
		CLAMP(value, 0.0f, 1.0f);
 | 
						|
	}
 | 
						|
 | 
						|
	return value;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * \brief Rasterize a buffer from a single mask
 | 
						|
 *
 | 
						|
 * We could get some speedup by inlining #BKE_maskrasterize_handle_sample
 | 
						|
 * and calculating each layer then blending buffers, but this function is only
 | 
						|
 * used by the sequencer - so better have the caller thread.
 | 
						|
 *
 | 
						|
 * Since #BKE_maskrasterize_handle_sample is used threaded elsewhere,
 | 
						|
 * we can simply use openmp here for some speedup.
 | 
						|
 */
 | 
						|
void BKE_maskrasterize_buffer(MaskRasterHandle *mr_handle,
 | 
						|
                              const unsigned int width, const unsigned int height,
 | 
						|
                              float *buffer)
 | 
						|
{
 | 
						|
	const float x_inv = 1.0f / (float)width;
 | 
						|
	const float y_inv = 1.0f / (float)height;
 | 
						|
	const float x_px_ofs = x_inv * 0.5f;
 | 
						|
	const float y_px_ofs = y_inv * 0.5f;
 | 
						|
#ifdef _MSC_VER
 | 
						|
	int y;  /* msvc requires signed for some reason */
 | 
						|
 | 
						|
	/* ignore sign mismatch */
 | 
						|
#  pragma warning(push)
 | 
						|
#  pragma warning(disable:4018)
 | 
						|
#else
 | 
						|
	unsigned int y;
 | 
						|
#endif
 | 
						|
 | 
						|
#pragma omp parallel for private(y)
 | 
						|
	for (y = 0; y < height; y++) {
 | 
						|
		unsigned int i = y * width;
 | 
						|
		unsigned int x;
 | 
						|
		float xy[2];
 | 
						|
		xy[1] = ((float)y * y_inv) + y_px_ofs;
 | 
						|
		for (x = 0; x < width; x++, i++) {
 | 
						|
			xy[0] = ((float)x * x_inv) + x_px_ofs;
 | 
						|
 | 
						|
			buffer[i] = BKE_maskrasterize_handle_sample(mr_handle, xy);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
#ifdef _MSC_VER
 | 
						|
#  pragma warning(pop)
 | 
						|
#endif
 | 
						|
 | 
						|
}
 |