void PlaneDistortMaskOperation::executePixelSampled(float output[4],
                                                    float x,
                                                    float y,
                                                    PixelSampler /*sampler*/)
{
  float point[2];
  int inside_counter = 0;
  if (this->m_motion_blur_samples == 1) {
    MotionSample *sample_data = &this->m_samples[0];
    for (int sample = 0; sample < this->m_osa; sample++) {
      point[0] = x + this->m_jitter[sample][0];
      point[1] = y + this->m_jitter[sample][1];
      if (isect_point_tri_v2(point,
                             sample_data->frameSpaceCorners[0],
                             sample_data->frameSpaceCorners[1],
                             sample_data->frameSpaceCorners[2]) ||
          isect_point_tri_v2(point,
                             sample_data->frameSpaceCorners[0],
                             sample_data->frameSpaceCorners[2],
                             sample_data->frameSpaceCorners[3])) {
        inside_counter++;
      }
    }
    output[0] = (float)inside_counter / this->m_osa;
  }
  else {
    for (int motion_sample = 0; motion_sample < this->m_motion_blur_samples; ++motion_sample) {
      MotionSample *sample_data = &this->m_samples[motion_sample];
      for (int osa_sample = 0; osa_sample < this->m_osa; ++osa_sample) {
        point[0] = x + this->m_jitter[osa_sample][0];
        point[1] = y + this->m_jitter[osa_sample][1];
        if (isect_point_tri_v2(point,
                               sample_data->frameSpaceCorners[0],
                               sample_data->frameSpaceCorners[1],
                               sample_data->frameSpaceCorners[2]) ||
            isect_point_tri_v2(point,
                               sample_data->frameSpaceCorners[0],
                               sample_data->frameSpaceCorners[2],
                               sample_data->frameSpaceCorners[3])) {
          inside_counter++;
        }
      }
    }
    output[0] = (float)inside_counter / (this->m_osa * this->m_motion_blur_samples);
  }
}
void PlaneTrackMaskOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
	float point[2];

	int inside_counter = 0;
	for (int sample = 0; sample < this->m_osa; sample++) {
		point[0] = x + this->m_jitter[sample][0];
		point[1] = y + this->m_jitter[sample][1];

		if (isect_point_tri_v2(point, this->m_frameSpaceCorners[0], this->m_frameSpaceCorners[1], this->m_frameSpaceCorners[2]) ||
		    isect_point_tri_v2(point, this->m_frameSpaceCorners[0], this->m_frameSpaceCorners[2], this->m_frameSpaceCorners[3]))
		{
			inside_counter++;
		}
	}

	output[0] = (float) inside_counter / this->m_osa;
}
static PyObject *M_Geometry_intersect_point_tri_2d(PyObject *UNUSED(self), PyObject* args)
{
	VectorObject *pt_vec, *tri_p1, *tri_p2, *tri_p3;
	
	if(!PyArg_ParseTuple(args, "O!O!O!O!:intersect_point_tri_2d",
		  &vector_Type, &pt_vec,
		  &vector_Type, &tri_p1,
		  &vector_Type, &tri_p2,
		  &vector_Type, &tri_p3)
	) {
		return NULL;
	}
	
	if(BaseMath_ReadCallback(pt_vec) == -1 || BaseMath_ReadCallback(tri_p1) == -1 || BaseMath_ReadCallback(tri_p2) == -1 || BaseMath_ReadCallback(tri_p3) == -1)
		return NULL;
	
	return PyLong_FromLong(isect_point_tri_v2(pt_vec->vec, tri_p1->vec, tri_p2->vec, tri_p3->vec));
}
/* 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(
        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 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;
}