| 
									
										
										
										
											2016-10-26 20:11:09 +11: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, | 
					
						
							|  |  |  |  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. | 
					
						
							|  |  |  |  * All rights reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The Original Code is: some of this file. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 08:08:12 +11:00
										 |  |  | /** \file
 | 
					
						
							|  |  |  |  * \ingroup bli | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Utility functions for primitive drawing operations. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-26 20:26:32 +11:00
										 |  |  | #include <limits.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | #include "MEM_guardedalloc.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BLI_bitmap_draw_2d.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-26 20:26:32 +11:00
										 |  |  | #include "BLI_math_base.h"
 | 
					
						
							|  |  |  | #include "BLI_sort.h"
 | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | #include "BLI_utildefines.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BLI_strict_flags.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-26 20:26:32 +11:00
										 |  |  | /* -------------------------------------------------------------------- */ | 
					
						
							| 
									
										
										
										
											2018-04-21 18:34:34 +02:00
										 |  |  | /** \name Draw Line
 | 
					
						
							|  |  |  |  * \{ */ | 
					
						
							| 
									
										
										
										
											2016-10-26 20:26:32 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Plot a line from \a p1 to \a p2 (inclusive). | 
					
						
							| 
									
										
										
										
											2016-12-04 15:05:50 +11:00
										 |  |  |  * | 
					
						
							|  |  |  |  * \note For clipped line drawing, see: http://stackoverflow.com/a/40902741/432509
 | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-10-26 20:14:48 +11:00
										 |  |  | void BLI_bitmap_draw_2d_line_v2v2i( | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  |         const int p1[2], const int p2[2], | 
					
						
							| 
									
										
										
										
											2018-04-21 20:22:12 +02:00
										 |  |  |         bool (*callback)(int, int, void *), void *user_data) | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | { | 
					
						
							|  |  |  | 	/* Bresenham's line algorithm. */ | 
					
						
							|  |  |  | 	int x1 = p1[0]; | 
					
						
							|  |  |  | 	int y1 = p1[1]; | 
					
						
							|  |  |  | 	int x2 = p2[0]; | 
					
						
							|  |  |  | 	int y2 = p2[1]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-21 20:22:12 +02:00
										 |  |  | 	if (callback(x1, y1, user_data) == 0) { | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-04 15:05:50 +11:00
										 |  |  | 	/* if x1 == x2 or y1 == y2, then it does not matter what we set here */ | 
					
						
							|  |  |  | 	const int sign_x = (x2 > x1) ? 1 : -1; | 
					
						
							|  |  |  | 	const int sign_y = (y2 > y1) ? 1 : -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const int delta_x = (sign_x == 1) ? (x2 - x1) : (x1 - x2); | 
					
						
							|  |  |  | 	const int delta_y = (sign_y == 1) ? (y2 - y1) : (y1 - y2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const int delta_x_step = delta_x * 2; | 
					
						
							|  |  |  | 	const int delta_y_step = delta_y * 2; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | 	if (delta_x >= delta_y) { | 
					
						
							|  |  |  | 		/* error may go below zero */ | 
					
						
							| 
									
										
										
										
											2016-12-04 15:05:50 +11:00
										 |  |  | 		int error = delta_y_step - delta_x; | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		while (x1 != x2) { | 
					
						
							|  |  |  | 			if (error >= 0) { | 
					
						
							| 
									
										
										
										
											2016-12-04 15:05:50 +11:00
										 |  |  | 				if (error || (sign_x == 1)) { | 
					
						
							|  |  |  | 					y1 += sign_y; | 
					
						
							|  |  |  | 					error -= delta_x_step; | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				/* else do nothing */ | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			/* else do nothing */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-04 15:05:50 +11:00
										 |  |  | 			x1 += sign_x; | 
					
						
							|  |  |  | 			error += delta_y_step; | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-21 20:22:12 +02:00
										 |  |  | 			if (callback(x1, y1, user_data) == 0) { | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							|  |  |  | 		/* error may go below zero */ | 
					
						
							| 
									
										
										
										
											2016-12-04 15:05:50 +11:00
										 |  |  | 		int error = delta_x_step - delta_y; | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		while (y1 != y2) { | 
					
						
							|  |  |  | 			if (error >= 0) { | 
					
						
							| 
									
										
										
										
											2016-12-04 15:05:50 +11:00
										 |  |  | 				if (error || (sign_y == 1)) { | 
					
						
							|  |  |  | 					x1 += sign_x; | 
					
						
							|  |  |  | 					error -= delta_y_step; | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				/* else do nothing */ | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			/* else do nothing */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-04 15:05:50 +11:00
										 |  |  | 			y1 += sign_y; | 
					
						
							|  |  |  | 			error += delta_x_step; | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-21 20:22:12 +02:00
										 |  |  | 			if (callback(x1, y1, user_data) == 0) { | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-21 18:34:34 +02:00
										 |  |  | /** \} */ | 
					
						
							| 
									
										
										
										
											2016-10-26 20:26:32 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* -------------------------------------------------------------------- */ | 
					
						
							| 
									
										
										
										
											2018-04-21 18:34:34 +02:00
										 |  |  | /** \name Draw Filled Triangle
 | 
					
						
							|  |  |  |  * \{ */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Fill a triangle | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Standard algorithm, | 
					
						
							|  |  |  |  * See: http://www.sunshine2k.de/coding/java/TriangleRasterization/TriangleRasterization.html
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Changes to the basic implementation: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * - Reuse slope calculation when drawing the second triangle. | 
					
						
							|  |  |  |  * - Don't calculate the 4th point at all for the triangle split. | 
					
						
							|  |  |  |  * - Order line drawing from left to right (minor detail). | 
					
						
							|  |  |  |  * - 1-pixel offsets are applied so adjacent triangles don't overlap. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This is not clipped, a clipped version can be added if needed. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Macros could be moved to a shared location. */ | 
					
						
							|  |  |  | #define ORDERED_SWAP(ty, a, b) \
 | 
					
						
							|  |  |  | 	if (a > b) { SWAP(ty, a, b); } ((void)0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define ORDERED_SWAP_BY(ty, a, b, by) \
 | 
					
						
							|  |  |  | 	if ((a by) > (b by)) { SWAP(ty, a, b); } ((void)0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define ORDER_VARS2(ty, a, b) \
 | 
					
						
							|  |  |  | 	{ ORDERED_SWAP(ty, a, b); } ((void)0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define ORDER_VARS3_BY(ty, a, b, c, by) \
 | 
					
						
							|  |  |  | 	{ \ | 
					
						
							|  |  |  | 		ORDERED_SWAP_BY(ty, b, c, by); \ | 
					
						
							|  |  |  | 		ORDERED_SWAP_BY(ty, a, c, by); \ | 
					
						
							|  |  |  | 		ORDERED_SWAP_BY(ty, a, b, by); \ | 
					
						
							|  |  |  | 	} ((void)0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static float inv_slope(const int a[2], const int b[2]) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return ((float)(a[0] - b[0]) / | 
					
						
							|  |  |  | 	        (float)(a[1] - b[1])); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * <pre> | 
					
						
							|  |  |  |  * *---* | 
					
						
							| 
									
										
										
										
											2019-02-18 08:08:12 +11:00
										 |  |  |  * \ / | 
					
						
							| 
									
										
										
										
											2018-04-21 18:34:34 +02:00
										 |  |  |  *   * | 
					
						
							|  |  |  |  * </pre> | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void draw_tri_flat_max( | 
					
						
							|  |  |  |         const int p[2], | 
					
						
							|  |  |  |         const int max_y, | 
					
						
							|  |  |  |         const float inv_slope1, | 
					
						
							|  |  |  |         const float inv_slope2, | 
					
						
							|  |  |  |         void (*callback)(int x, int x_end, int y, void *), | 
					
						
							|  |  |  |         void *user_data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	float cur_x1 = (float)p[0]; | 
					
						
							|  |  |  | 	float cur_x2 = cur_x1; | 
					
						
							|  |  |  | 	/* start-end inclusive */ | 
					
						
							|  |  |  | 	const int min_y = p[1]; | 
					
						
							|  |  |  | 	const int max_y_end = max_y + 1; | 
					
						
							|  |  |  | 	for (int scanline_y = min_y; scanline_y != max_y_end; scanline_y += 1) { | 
					
						
							|  |  |  | 		callback((int)cur_x1, 1 + (int)cur_x2, scanline_y, user_data); | 
					
						
							|  |  |  | 		cur_x1 += inv_slope1; | 
					
						
							|  |  |  | 		cur_x2 += inv_slope2; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * <pre> | 
					
						
							|  |  |  |  *   * | 
					
						
							|  |  |  |  *  / \ | 
					
						
							|  |  |  |  * *---* | 
					
						
							|  |  |  |  * </pre> | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void draw_tri_flat_min( | 
					
						
							|  |  |  |         const int p[2], | 
					
						
							|  |  |  |         const int min_y, | 
					
						
							|  |  |  |         const float inv_slope1, | 
					
						
							|  |  |  |         const float inv_slope2, | 
					
						
							|  |  |  |         void (*callback)(int x, int x_end, int y, void *), | 
					
						
							|  |  |  |         void *user_data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	float cur_x1 = (float)p[0]; | 
					
						
							|  |  |  | 	float cur_x2 = cur_x1; | 
					
						
							|  |  |  | 	/* start-end inclusive */ | 
					
						
							|  |  |  | 	const int max_y = p[1]; | 
					
						
							|  |  |  | 	const int min_y_end = min_y - 1; | 
					
						
							|  |  |  | 	for (int scanline_y = max_y; scanline_y != min_y_end; scanline_y -= 1) { | 
					
						
							|  |  |  | 		callback((int)cur_x1, 1 + (int)cur_x2, scanline_y, user_data); | 
					
						
							|  |  |  | 		cur_x1 -= inv_slope1; | 
					
						
							|  |  |  | 		cur_x2 -= inv_slope2; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * \note Unclipped (clipped version can be added if needed). | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void BLI_bitmap_draw_2d_tri_v2i( | 
					
						
							|  |  |  |         /* all 2d */ | 
					
						
							|  |  |  |         const int p1[2], | 
					
						
							|  |  |  |         const int p2[2], | 
					
						
							|  |  |  |         const int p3[2], | 
					
						
							|  |  |  |         void (*callback)(int x, int x_end, int y, void *), | 
					
						
							|  |  |  |         void *user_data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* At first sort the three vertices by y-coordinate ascending so p1 is the top-most vertice */ | 
					
						
							|  |  |  | 	ORDER_VARS3_BY(const int *, p1, p2, p3, [1]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	BLI_assert(p1[1] <= p2[1] && p2[1] <= p3[1]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Check for trivial case of bottom-flat triangle. */ | 
					
						
							|  |  |  | 	if (p2[1] == p3[1]) { | 
					
						
							|  |  |  | 		float inv_slope1 = inv_slope(p2, p1); | 
					
						
							|  |  |  | 		float inv_slope2 = inv_slope(p3, p1); | 
					
						
							|  |  |  | 		ORDER_VARS2(float, inv_slope1, inv_slope2); | 
					
						
							| 
									
										
										
										
											2018-04-23 21:07:27 +02:00
										 |  |  | 		BLI_assert(!(inv_slope1 > inv_slope2)); | 
					
						
							| 
									
										
										
										
											2018-04-21 18:34:34 +02:00
										 |  |  | 		draw_tri_flat_max( | 
					
						
							|  |  |  | 		        p1, p2[1], | 
					
						
							|  |  |  | 		        inv_slope1, inv_slope2, | 
					
						
							|  |  |  | 		        callback, user_data); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else if (p1[1] == p2[1]) { | 
					
						
							|  |  |  | 		/* Check for trivial case of top-flat triangle. */ | 
					
						
							|  |  |  | 		float inv_slope1 = inv_slope(p3, p1); | 
					
						
							|  |  |  | 		float inv_slope2 = inv_slope(p3, p2); | 
					
						
							|  |  |  | 		ORDER_VARS2(float, inv_slope2, inv_slope1); | 
					
						
							| 
									
										
										
										
											2018-04-23 21:07:27 +02:00
										 |  |  | 		BLI_assert(!(inv_slope1 < inv_slope2)); | 
					
						
							| 
									
										
										
										
											2018-04-21 18:34:34 +02:00
										 |  |  | 		draw_tri_flat_min( | 
					
						
							|  |  |  | 		        p3, p2[1] + 1, /* avoid overlap */ | 
					
						
							|  |  |  | 		        inv_slope1, inv_slope2, | 
					
						
							|  |  |  | 		        callback, user_data); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							|  |  |  | 		/* General case - split the triangle in a top-flat and bottom-flat one. */ | 
					
						
							|  |  |  | 		const float inv_slope_p21 = inv_slope(p2, p1); | 
					
						
							|  |  |  | 		const float inv_slope_p31 = inv_slope(p3, p1); | 
					
						
							|  |  |  | 		const float inv_slope_p32 = inv_slope(p3, p2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		float inv_slope1_max, inv_slope2_max; | 
					
						
							|  |  |  | 		float inv_slope2_min, inv_slope1_min; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (inv_slope_p21 < inv_slope_p31) { | 
					
						
							|  |  |  | 			inv_slope1_max = inv_slope_p21; | 
					
						
							|  |  |  | 			inv_slope2_max = inv_slope_p31; | 
					
						
							|  |  |  | 			inv_slope2_min = inv_slope_p31; | 
					
						
							|  |  |  | 			inv_slope1_min = inv_slope_p32; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		else { | 
					
						
							|  |  |  | 			inv_slope1_max = inv_slope_p31; | 
					
						
							|  |  |  | 			inv_slope2_max = inv_slope_p21; | 
					
						
							|  |  |  | 			inv_slope2_min = inv_slope_p32; | 
					
						
							|  |  |  | 			inv_slope1_min = inv_slope_p31; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		draw_tri_flat_max( | 
					
						
							|  |  |  | 		        p1, p2[1], | 
					
						
							|  |  |  | 		        inv_slope1_max, inv_slope2_max, | 
					
						
							|  |  |  | 		        callback, user_data); | 
					
						
							|  |  |  | 		draw_tri_flat_min( | 
					
						
							|  |  |  | 		        p3, p2[1] + 1, /* avoid overlap */ | 
					
						
							|  |  |  | 		        inv_slope1_min, inv_slope2_min, | 
					
						
							|  |  |  | 		        callback, user_data); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #undef ORDERED_SWAP
 | 
					
						
							|  |  |  | #undef ORDERED_SWAP_BY
 | 
					
						
							|  |  |  | #undef ORDER_VARS2
 | 
					
						
							|  |  |  | #undef ORDER_VARS3_BY
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** \} */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* -------------------------------------------------------------------- */ | 
					
						
							|  |  |  | /** \name Draw Filled Polygon
 | 
					
						
							|  |  |  |  * \{ */ | 
					
						
							| 
									
										
										
										
											2016-10-26 20:26:32 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* sort edge-segments on y, then x axis */ | 
					
						
							|  |  |  | static int draw_poly_v2i_n__span_y_sort(const void *a_p, const void *b_p, void *verts_p) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const int (*verts)[2] = verts_p; | 
					
						
							|  |  |  | 	const int *a = a_p; | 
					
						
							|  |  |  | 	const int *b = b_p; | 
					
						
							|  |  |  | 	const int *co_a = verts[a[0]]; | 
					
						
							|  |  |  | 	const int *co_b = verts[b[0]]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (co_a[1] < co_b[1]) { | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else if (co_a[1] > co_b[1]) { | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else if (co_a[0] < co_b[0]) { | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else if (co_a[0] > co_b[0]) { | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							|  |  |  | 		/* co_a & co_b are identical, use the line closest to the x-min */ | 
					
						
							|  |  |  | 		const int *co = co_a; | 
					
						
							|  |  |  | 		co_a = verts[a[1]]; | 
					
						
							|  |  |  | 		co_b = verts[b[1]]; | 
					
						
							|  |  |  | 		int ord = (((co_b[0] - co[0]) * (co_a[1] - co[1])) - | 
					
						
							|  |  |  | 		           ((co_a[0] - co[0]) * (co_b[1] - co[1]))); | 
					
						
							|  |  |  | 		if (ord > 0) { | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (ord < 0) { | 
					
						
							|  |  |  | 			return 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2018-01-19 15:34:54 +11:00
										 |  |  |  * Draws a filled polygon with support for self intersections. | 
					
						
							| 
									
										
										
										
											2016-10-26 20:26:32 +11:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  |  * \param callback: Takes the x, y coords and x-span (\a x_end is not inclusive), | 
					
						
							|  |  |  |  * note that \a x_end will always be greater than \a x, so we can use: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \code{.c} | 
					
						
							|  |  |  |  * do { | 
					
						
							|  |  |  |  *     func(x, y); | 
					
						
							|  |  |  |  * } while (++x != x_end); | 
					
						
							|  |  |  |  * \endcode | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-10-26 20:14:48 +11:00
										 |  |  | void BLI_bitmap_draw_2d_poly_v2i_n( | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  |         const int xmin, const int ymin, const int xmax, const int ymax, | 
					
						
							| 
									
										
										
										
											2018-04-21 20:22:12 +02:00
										 |  |  |         const int verts[][2], const int verts_len, | 
					
						
							|  |  |  |         void (*callback)(int x, int x_end, int y, void *), void *user_data) | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | { | 
					
						
							|  |  |  | 	/* Originally by Darel Rex Finley, 2007.
 | 
					
						
							| 
									
										
										
										
											2016-10-26 20:26:32 +11:00
										 |  |  | 	 * Optimized by Campbell Barton, 2016 to track sorted intersections. */ | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-21 20:22:12 +02:00
										 |  |  | 	int (*span_y)[2] = MEM_mallocN(sizeof(*span_y) * (size_t)verts_len, __func__); | 
					
						
							| 
									
										
										
										
											2016-10-26 20:26:32 +11:00
										 |  |  | 	int span_y_len = 0; | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-21 20:22:12 +02:00
										 |  |  | 	for (int i_curr = 0, i_prev = verts_len - 1; i_curr < verts_len; i_prev = i_curr++) { | 
					
						
							| 
									
										
										
										
											2016-10-26 20:26:32 +11:00
										 |  |  | 		const int *co_prev = verts[i_prev]; | 
					
						
							|  |  |  | 		const int *co_curr = verts[i_curr]; | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-26 20:26:32 +11:00
										 |  |  | 		if (co_prev[1] != co_curr[1]) { | 
					
						
							|  |  |  | 			/* Any segments entirely above or below the area of interest can be skipped. */ | 
					
						
							|  |  |  | 			if ((min_ii(co_prev[1], co_curr[1]) >= ymax) || | 
					
						
							|  |  |  | 			    (max_ii(co_prev[1], co_curr[1]) <  ymin)) | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2016-10-26 20:26:32 +11:00
										 |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-26 20:26:32 +11:00
										 |  |  | 			int *s = span_y[span_y_len++]; | 
					
						
							|  |  |  | 			if (co_prev[1] < co_curr[1]) { | 
					
						
							|  |  |  | 				s[0] = i_prev; | 
					
						
							|  |  |  | 				s[1] = i_curr; | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			else { | 
					
						
							| 
									
										
										
										
											2016-10-26 20:26:32 +11:00
										 |  |  | 				s[0] = i_curr; | 
					
						
							|  |  |  | 				s[1] = i_prev; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	BLI_qsort_r(span_y, (size_t)span_y_len, sizeof(*span_y), draw_poly_v2i_n__span_y_sort, (void *)verts); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	struct NodeX { | 
					
						
							|  |  |  | 		int span_y_index; | 
					
						
							|  |  |  | 		int x; | 
					
						
							| 
									
										
										
										
											2018-04-21 20:22:12 +02:00
										 |  |  | 	} *node_x = MEM_mallocN(sizeof(*node_x) * (size_t)(verts_len + 1), __func__); | 
					
						
							| 
									
										
										
										
											2016-10-26 20:26:32 +11:00
										 |  |  | 	int node_x_len = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int span_y_index = 0; | 
					
						
							|  |  |  | 	if (span_y_len != 0 && verts[span_y[0][0]][1] < ymin) { | 
					
						
							|  |  |  | 		while ((span_y_index < span_y_len) && | 
					
						
							|  |  |  | 		       (verts[span_y[span_y_index][0]][1] < ymin)) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			BLI_assert(verts[span_y[span_y_index][0]][1] < | 
					
						
							|  |  |  | 			           verts[span_y[span_y_index][1]][1]); | 
					
						
							|  |  |  | 			if (verts[span_y[span_y_index][1]][1] >= ymin) { | 
					
						
							|  |  |  | 				struct NodeX *n = &node_x[node_x_len++]; | 
					
						
							|  |  |  | 				n->span_y_index = span_y_index; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			span_y_index += 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Loop through the rows of the image. */ | 
					
						
							|  |  |  | 	for (int pixel_y = ymin; pixel_y < ymax; pixel_y++) { | 
					
						
							|  |  |  | 		bool is_sorted = true; | 
					
						
							|  |  |  | 		bool do_remove = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for (int i = 0, x_ix_prev = INT_MIN; i < node_x_len; i++) { | 
					
						
							|  |  |  | 			struct NodeX *n = &node_x[i]; | 
					
						
							|  |  |  | 			const int *s = span_y[n->span_y_index]; | 
					
						
							|  |  |  | 			const int *co_prev = verts[s[0]]; | 
					
						
							|  |  |  | 			const int *co_curr = verts[s[1]]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			BLI_assert(co_prev[1] < pixel_y && co_curr[1] >= pixel_y); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			const double x    = (co_prev[0] - co_curr[0]); | 
					
						
							|  |  |  | 			const double y    = (co_prev[1] - co_curr[1]); | 
					
						
							|  |  |  | 			const double y_px = (pixel_y    - co_curr[1]); | 
					
						
							|  |  |  | 			const int    x_ix = (int)((double)co_curr[0] + ((y_px / y) * x)); | 
					
						
							|  |  |  | 			n->x = x_ix; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (is_sorted && (x_ix_prev > x_ix)) { | 
					
						
							|  |  |  | 				is_sorted = false; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (do_remove == false && co_curr[1] == pixel_y) { | 
					
						
							|  |  |  | 				do_remove = true; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			x_ix_prev = x_ix; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Sort the nodes, via a simple "Bubble" sort. */ | 
					
						
							|  |  |  | 		if (is_sorted == false) { | 
					
						
							|  |  |  | 			int i = 0; | 
					
						
							|  |  |  | 			const int node_x_end = node_x_len - 1; | 
					
						
							|  |  |  | 			while (i < node_x_end) { | 
					
						
							|  |  |  | 				if (node_x[i].x > node_x[i + 1].x) { | 
					
						
							|  |  |  | 					SWAP(struct NodeX, node_x[i], node_x[i + 1]); | 
					
						
							|  |  |  | 					if (i != 0) { | 
					
						
							|  |  |  | 						i -= 1; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				else { | 
					
						
							|  |  |  | 					i += 1; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Fill the pixels between node pairs. */ | 
					
						
							| 
									
										
										
										
											2016-10-26 20:26:32 +11:00
										 |  |  | 		for (int i = 0; i < node_x_len; i += 2) { | 
					
						
							|  |  |  | 			int x_src = node_x[i].x; | 
					
						
							|  |  |  | 			int x_dst = node_x[i + 1].x; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (x_src >= xmax) { | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (x_dst > xmin) { | 
					
						
							|  |  |  | 				if (x_src < xmin) { | 
					
						
							|  |  |  | 					x_src = xmin; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if (x_dst > xmax) { | 
					
						
							|  |  |  | 					x_dst = xmax; | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				/* for single call per x-span */ | 
					
						
							| 
									
										
										
										
											2016-10-26 20:26:32 +11:00
										 |  |  | 				if (x_src < x_dst) { | 
					
						
							| 
									
										
										
										
											2018-04-21 20:22:12 +02:00
										 |  |  | 					callback(x_src - xmin, x_dst - xmin, pixel_y - ymin, user_data); | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-10-26 20:26:32 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* Clear finalized nodes in one pass, only when needed
 | 
					
						
							|  |  |  | 		 * (avoids excessive array-resizing). */ | 
					
						
							|  |  |  | 		if (do_remove == true) { | 
					
						
							|  |  |  | 			int i_dst = 0; | 
					
						
							|  |  |  | 			for (int i_src = 0; i_src < node_x_len; i_src += 1) { | 
					
						
							|  |  |  | 				const int *s = span_y[node_x[i_src].span_y_index]; | 
					
						
							|  |  |  | 				const int *co = verts[s[1]]; | 
					
						
							|  |  |  | 				if (co[1] != pixel_y) { | 
					
						
							|  |  |  | 					if (i_dst != i_src) { | 
					
						
							|  |  |  | 						/* x is initialized for the next pixel_y (no need to adjust here) */ | 
					
						
							|  |  |  | 						node_x[i_dst].span_y_index = node_x[i_src].span_y_index; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					i_dst += 1; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			node_x_len = i_dst; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Scan for new x-nodes */ | 
					
						
							|  |  |  | 		while ((span_y_index < span_y_len) && | 
					
						
							|  |  |  | 		       (verts[span_y[span_y_index][0]][1] == pixel_y)) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			/* note, node_x these are just added at the end,
 | 
					
						
							|  |  |  | 			 * not ideal but sorting once will resolve. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* x is initialized for the next pixel_y */ | 
					
						
							|  |  |  | 			struct NodeX *n = &node_x[node_x_len++]; | 
					
						
							|  |  |  | 			n->span_y_index = span_y_index; | 
					
						
							|  |  |  | 			span_y_index += 1; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-10-26 20:26:32 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	MEM_freeN(span_y); | 
					
						
							| 
									
										
										
										
											2016-10-26 20:11:09 +11:00
										 |  |  | 	MEM_freeN(node_x); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-04-21 18:34:34 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** \} */ |