static void compute_ideal_colors_and_weights_3_comp(
	const block_size_descriptor& bsd,
	const image_block& blk,
	const error_weight_block& ewb,
	const partition_info& pi,
	endpoints_and_weights& ei,
	unsigned int omitted_component
) {
	unsigned int partition_count = pi.partition_count;
	ei.ep.partition_count = partition_count;
	promise(partition_count > 0);

	unsigned int texel_count = bsd.texel_count;
	promise(texel_count > 0);

	partition_metrics pms[BLOCK_MAX_PARTITIONS];

	const float *error_weights;
	const float* data_vr = nullptr;
	const float* data_vg = nullptr;
	const float* data_vb = nullptr;
	if (omitted_component == 0)
	{
		error_weights = ewb.texel_weight_gba;
		data_vr = blk.data_g;
		data_vg = blk.data_b;
		data_vb = blk.data_a;
	}
	else if (omitted_component == 1)
	{
		error_weights = ewb.texel_weight_rba;
		data_vr = blk.data_r;
		data_vg = blk.data_b;
		data_vb = blk.data_a;
	}
	else if (omitted_component == 2)
	{
		error_weights = ewb.texel_weight_rga;
		data_vr = blk.data_r;
		data_vg = blk.data_g;
		data_vb = blk.data_a;
	}
	else
	{
		error_weights = ewb.texel_weight_rgb;
		data_vr = blk.data_r;
		data_vg = blk.data_g;
		data_vb = blk.data_b;
	}

	float lowparam[BLOCK_MAX_PARTITIONS] { 1e10f, 1e10f, 1e10f, 1e10f };
	float highparam[BLOCK_MAX_PARTITIONS] { -1e10f, -1e10f, -1e10f, -1e10f };

	line3 lines[BLOCK_MAX_PARTITIONS];
	float scale[BLOCK_MAX_PARTITIONS];
	float length_squared[BLOCK_MAX_PARTITIONS];

	compute_avgs_and_dirs_3_comp(pi, blk, ewb, omitted_component, pms);

	for (unsigned int i = 0; i < partition_count; i++)
	{
		vfloat4 dir = pms[i].dir;
		if (hadd_rgb_s(dir) < 0.0f)
		{
			dir = vfloat4::zero() - dir;
		}

		lines[i].a = pms[i].avg;
		lines[i].b = normalize_safe(dir, unit3());
	}

	for (unsigned int i = 0; i < texel_count; i++)
	{
		if (error_weights[i] > 1e-10f)
		{
			int partition = pi.partition_of_texel[i];
			vfloat4 point = vfloat3(data_vr[i], data_vg[i], data_vb[i]) * pms[partition].color_scale;
			line3 l = lines[partition];
			float param = dot3_s(point - l.a, l.b);
			ei.weights[i] = param;

			lowparam[partition] = astc::min(param, lowparam[partition]);
			highparam[partition] = astc::max(param, highparam[partition]);
		}
		else
		{
			ei.weights[i] = -1e38f;
		}
	}

	for (unsigned int i = 0; i < partition_count; i++)
	{
		float length = highparam[i] - lowparam[i];
		if (length < 0)			// Case for when none of the texels had any weight
		{
			lowparam[i] = 0.0f;
			highparam[i] = 1e-7f;
		}

		// It is possible for a uniform-color partition to produce length=0; this causes NaN issues
		// so set to a small value to avoid this problem.
		length = astc::max(length, 1e-7f);

		length_squared[i] = length * length;
		scale[i] = 1.0f / length;

		vfloat4 ep0 = lines[i].a + lines[i].b * lowparam[i];
		vfloat4 ep1 = lines[i].a + lines[i].b * highparam[i];

		ep0 = ep0 * pms[i].icolor_scale;
		ep1 = ep1 * pms[i].icolor_scale;

		vfloat4 bmin = blk.data_min;
		vfloat4 bmax = blk.data_max;

		assert(omitted_component < BLOCK_MAX_COMPONENTS);
		switch (omitted_component)
		{
			case 0:
				ei.ep.endpt0[i] = vfloat4(bmin.lane<0>(), ep0.lane<0>(), ep0.lane<1>(), ep0.lane<2>());
				ei.ep.endpt1[i] = vfloat4(bmax.lane<0>(), ep1.lane<0>(), ep1.lane<1>(), ep1.lane<2>());
				break;
			case 1:
				ei.ep.endpt0[i] = vfloat4(ep0.lane<0>(), bmin.lane<1>(), ep0.lane<1>(), ep0.lane<2>());
				ei.ep.endpt1[i] = vfloat4(ep1.lane<0>(), bmax.lane<1>(), ep1.lane<1>(), ep1.lane<2>());
				break;
			case 2:
				ei.ep.endpt0[i] = vfloat4(ep0.lane<0>(), ep0.lane<1>(), bmin.lane<2>(), ep0.lane<2>());
				ei.ep.endpt1[i] = vfloat4(ep1.lane<0>(), ep1.lane<1>(), bmax.lane<2>(), ep1.lane<2>());
				break;
			default:
				ei.ep.endpt0[i] = vfloat4(ep0.lane<0>(), ep0.lane<1>(), ep0.lane<2>(), bmin.lane<3>());
				ei.ep.endpt1[i] = vfloat4(ep1.lane<0>(), ep1.lane<1>(), ep1.lane<2>(), bmax.lane<3>());
				break;
		}
	}


	bool is_constant_wes = true;
	float constant_wes = length_squared[pi.partition_of_texel[0]] * error_weights[0];

	for (unsigned int i = 0; i < texel_count; i++)
	{
		int partition = pi.partition_of_texel[i];
		float idx = (ei.weights[i] - lowparam[partition]) * scale[partition];
		idx = astc::clamp1f(idx);

		ei.weights[i] = idx;
		ei.weight_error_scale[i] = length_squared[partition] * error_weights[i];
		assert(!astc::isnan(ei.weight_error_scale[i]));

		is_constant_wes = is_constant_wes && ei.weight_error_scale[i] == constant_wes;
	}

	// Zero initialize any SIMD over-fetch
	unsigned int texel_count_simd = round_up_to_simd_multiple_vla(texel_count);
	for (unsigned int i = texel_count; i < texel_count_simd; i++)
	{
		ei.weights[i] = 0.0f;
		ei.weight_error_scale[i] = 0.0f;
	}

	ei.is_constant_weight_error_scale = is_constant_wes;
}
static void compute_ideal_colors_and_weights_3_comp(
	const block_size_descriptor& bsd,
	const image_block& blk,
	const error_weight_block& ewb,
	const partition_info& pi,
	endpoints_and_weights& ei,
	unsigned int omitted_component
) {
	unsigned int partition_count = pi.partition_count;
	ei.ep.partition_count = partition_count;
	promise(partition_count > 0);

	unsigned int texel_count = bsd.texel_count;
	promise(texel_count > 0);

	partition_metrics pms[BLOCK_MAX_PARTITIONS];

	const float *error_weights;
	const float* data_vr = nullptr;
	const float* data_vg = nullptr;
	const float* data_vb = nullptr;
	if (omitted_component == 0)
	{
		error_weights = ewb.texel_weight_gba;
		data_vr = blk.data_g;
		data_vg = blk.data_b;
		data_vb = blk.data_a;
	}
	else if (omitted_component == 1)
	{
		error_weights = ewb.texel_weight_rba;
		data_vr = blk.data_r;
		data_vg = blk.data_b;
		data_vb = blk.data_a;
	}
	else if (omitted_component == 2)
	{
		error_weights = ewb.texel_weight_rga;
		data_vr = blk.data_r;
		data_vg = blk.data_g;
		data_vb = blk.data_a;
	}
	else
	{
		error_weights = ewb.texel_weight_rgb;
		data_vr = blk.data_r;
		data_vg = blk.data_g;
		data_vb = blk.data_b;
	}

	float lowparam[BLOCK_MAX_PARTITIONS] { 1e10f, 1e10f, 1e10f, 1e10f };
	float highparam[BLOCK_MAX_PARTITIONS] { -1e10f, -1e10f, -1e10f, -1e10f };

	line3 lines[BLOCK_MAX_PARTITIONS];
	float scale[BLOCK_MAX_PARTITIONS];
	float length_squared[BLOCK_MAX_PARTITIONS];

	compute_avgs_and_dirs_3_comp(pi, blk, ewb, omitted_component, pms);

	for (unsigned int i = 0; i < partition_count; i++)
	{
		vfloat4 dir = pms[i].dir;
		if (hadd_rgb_s(dir) < 0.0f)
		{
			dir = vfloat4::zero() - dir;
		}

		lines[i].a = pms[i].avg;
		lines[i].b = normalize_safe(dir, unit3());
	}

	for (unsigned int i = 0; i < texel_count; i++)
	{
		if (error_weights[i] > 1e-10f)
		{
			int partition = pi.partition_of_texel[i];
			vfloat4 point = vfloat3(data_vr[i], data_vg[i], data_vb[i]) * pms[partition].color_scale;
			line3 l = lines[partition];
			float param = dot3_s(point - l.a, l.b);
			ei.weights[i] = param;

			lowparam[partition] = astc::min(param, lowparam[partition]);
			highparam[partition] = astc::max(param, highparam[partition]);
		}
		else
		{
			ei.weights[i] = -1e38f;
		}
	}

	for (unsigned int i = 0; i < partition_count; i++)
	{
		float length = highparam[i] - lowparam[i];
		if (length < 0)			 
		{
			lowparam[i] = 0.0f;
			highparam[i] = 1e-7f;
		}

		 
		 
		length = astc::max(length, 1e-7f);

		length_squared[i] = length * length;
		scale[i] = 1.0f / length;

		vfloat4 ep0 = lines[i].a + lines[i].b * lowparam[i];
		vfloat4 ep1 = lines[i].a + lines[i].b * highparam[i];

		ep0 = ep0 * pms[i].icolor_scale;
		ep1 = ep1 * pms[i].icolor_scale;

		vfloat4 bmin = blk.data_min;
		vfloat4 bmax = blk.data_max;

		assert(omitted_component < BLOCK_MAX_COMPONENTS);
		switch (omitted_component)
		{
			case 0:
				ei.ep.endpt0[i] = vfloat4(bmin.lane<0>(), ep0.lane<0>(), ep0.lane<1>(), ep0.lane<2>());
				ei.ep.endpt1[i] = vfloat4(bmax.lane<0>(), ep1.lane<0>(), ep1.lane<1>(), ep1.lane<2>());
				break;
			case 1:
				ei.ep.endpt0[i] = vfloat4(ep0.lane<0>(), bmin.lane<1>(), ep0.lane<1>(), ep0.lane<2>());
				ei.ep.endpt1[i] = vfloat4(ep1.lane<0>(), bmax.lane<1>(), ep1.lane<1>(), ep1.lane<2>());
				break;
			case 2:
				ei.ep.endpt0[i] = vfloat4(ep0.lane<0>(), ep0.lane<1>(), bmin.lane<2>(), ep0.lane<2>());
				ei.ep.endpt1[i] = vfloat4(ep1.lane<0>(), ep1.lane<1>(), bmax.lane<2>(), ep1.lane<2>());
				break;
			default:
				ei.ep.endpt0[i] = vfloat4(ep0.lane<0>(), ep0.lane<1>(), ep0.lane<2>(), bmin.lane<3>());
				ei.ep.endpt1[i] = vfloat4(ep1.lane<0>(), ep1.lane<1>(), ep1.lane<2>(), bmax.lane<3>());
				break;
		}
	}


	bool is_constant_wes = true;
	float constant_wes = length_squared[pi.partition_of_texel[0]] * error_weights[0];

	for (unsigned int i = 0; i < texel_count; i++)
	{
		int partition = pi.partition_of_texel[i];
		float idx = (ei.weights[i] - lowparam[partition]) * scale[partition];
		idx = astc::clamp1f(idx);

		ei.weights[i] = idx;
		ei.weight_error_scale[i] = length_squared[partition] * error_weights[i];
		assert(!astc::isnan(ei.weight_error_scale[i]));

		is_constant_wes = is_constant_wes && ei.weight_error_scale[i] == constant_wes;
	}

	 
	unsigned int texel_count_simd = round_up_to_simd_multiple_vla(texel_count);
	for (unsigned int i = texel_count; i < texel_count_simd; i++)
	{
		ei.weights[i] = 0.0f;
		ei.weight_error_scale[i] = 0.0f;
	}

	ei.is_constant_weight_error_scale = is_constant_wes;
}