void KeyingScreenOperation::executePixel(float output[4], int x, int y, void *data)
{
	output[0] = 0.0f;
	output[1] = 0.0f;
	output[2] = 0.0f;
	output[3] = 1.0f;

	if (this->m_movieClip && data) {
		TriangulationData *triangulation = this->m_cachedTriangulation;
		TileData *tile_data = (TileData *) data;
		int i;
		float co[2] = {(float) x, (float) y};

		for (i = 0; i < tile_data->triangles_total; i++) {
			int triangle_idx = tile_data->triangles[i];
			rctf *rect = &triangulation->triangles_AABB[triangle_idx];

			if (IN_RANGE_INCL(x, rect->xmin, rect->xmax) && IN_RANGE_INCL(y, rect->ymin, rect->ymax)) {
				int *triangle = triangulation->triangles[triangle_idx];
				VoronoiTriangulationPoint *a = &triangulation->triangulated_points[triangle[0]],
				                          *b = &triangulation->triangulated_points[triangle[1]],
				                          *c = &triangulation->triangulated_points[triangle[2]];
				float w[3];

				if (barycentric_coords_v2(a->co, b->co, c->co, co, w)) {
					if (barycentric_inside_triangle_v2(w)) {
						output[0] = a->color[0] * w[0] + b->color[0] * w[1] + c->color[0] * w[2];
						output[1] = a->color[1] * w[0] + b->color[1] * w[1] + c->color[1] * w[2];
						output[2] = a->color[2] * w[0] + b->color[2] * w[1] + c->color[2] * w[2];

						break;
					}
				}
			}
		}
	}
}
static void compute_gradient_screen(RenderData *rd, NodeKeyingScreenData *keyingscreen_data, MovieClip *clip, CompBuf *screenbuf)
{
	MovieClipUser user = {0};
	MovieTracking *tracking = &clip->tracking;
	MovieTrackingTrack *track;
	VoronoiTriangulationPoint *triangulated_points;
	VoronoiSite *sites;
	ImBuf *ibuf;
	ListBase *tracksbase;
	ListBase edges = {NULL, NULL};
	int sites_total, triangulated_points_total, triangles_total;
	int (*triangles)[3];
	int i, x, y;
	float *rect = screenbuf->rect;

	if (keyingscreen_data->tracking_object[0]) {
		MovieTrackingObject *object = BKE_tracking_object_get_named(tracking, keyingscreen_data->tracking_object);

		if (!object)
			return;

		tracksbase = BKE_tracking_object_get_tracks(tracking, object);
	}
	else
		tracksbase = BKE_tracking_get_active_tracks(tracking);

	sites_total = BLI_countlist(tracksbase);

	if (!sites_total)
		return;

	BKE_movieclip_user_set_frame(&user, rd->cfra);
	ibuf = BKE_movieclip_get_ibuf(clip, &user);

	sites = MEM_callocN(sizeof(VoronoiSite) * sites_total, "keyingscreen voronoi sites");
	track = tracksbase->first;
	i = 0;
	while (track) {
		VoronoiSite *site = &sites[i];
		MovieTrackingMarker *marker = BKE_tracking_marker_get(track, rd->cfra);
		ImBuf *pattern_ibuf = BKE_tracking_get_pattern_imbuf(ibuf, track, marker, TRUE, FALSE);
		int j;

		zero_v3(site->color);

		if (pattern_ibuf) {
			for (j = 0; j < pattern_ibuf->x * pattern_ibuf->y; j++) {
				if (pattern_ibuf->rect_float) {
					add_v3_v3(site->color, &pattern_ibuf->rect_float[4 * j]);
				}
				else {
					unsigned char *rrgb = (unsigned char *)pattern_ibuf->rect;

					site->color[0] += srgb_to_linearrgb((float)rrgb[4 * j + 0] / 255.0f);
					site->color[1] += srgb_to_linearrgb((float)rrgb[4 * j + 1] / 255.0f);
					site->color[2] += srgb_to_linearrgb((float)rrgb[4 * j + 2] / 255.0f);
				}
			}

			mul_v3_fl(site->color, 1.0f / (pattern_ibuf->x * pattern_ibuf->y));
			IMB_freeImBuf(pattern_ibuf);
		}

		site->co[0] = marker->pos[0] * screenbuf->x;
		site->co[1] = marker->pos[1] * screenbuf->y;

		track = track->next;
		i++;
	}

	IMB_freeImBuf(ibuf);

	BLI_voronoi_compute(sites, sites_total, screenbuf->x, screenbuf->y, &edges);

	BLI_voronoi_triangulate(sites, sites_total, &edges, screenbuf->x, screenbuf->y,
	                        &triangulated_points, &triangulated_points_total,
                            &triangles, &triangles_total);

	for (y = 0; y < screenbuf->y; y++) {
		for (x = 0; x < screenbuf->x; x++) {
			int index = 4 * (y * screenbuf->x + x);

			rect[index + 0] = rect[index + 1] = rect[index + 2] = 0.0f;
			rect[index + 3] = 1.0f;

			for (i = 0; i < triangles_total; i++) {
				int *triangle = triangles[i];
				VoronoiTriangulationPoint *a = &triangulated_points[triangle[0]],
				                          *b = &triangulated_points[triangle[1]],
				                          *c = &triangulated_points[triangle[2]];
				float co[2] = {x, y}, w[3];

				if (barycentric_coords_v2(a->co, b->co, c->co, co, w)) {
					if (barycentric_inside_triangle_v2(w)) {
						rect[index + 0] += a->color[0] * w[0] + b->color[0] * w[1] + c->color[0] * w[2];
						rect[index + 1] += a->color[1] * w[0] + b->color[1] * w[1] + c->color[1] * w[2];
						rect[index + 2] += a->color[2] * w[0] + b->color[2] * w[1] + c->color[2] * w[2];
					}
				}
			}
		}
	}

	MEM_freeN(triangulated_points);
	MEM_freeN(triangles);
	MEM_freeN(sites);
	BLI_freelistN(&edges);
}