Example #1
0
void GraphicAlgorithms::FillTriangle(color_t* data, uint32_t stride, uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2,
	uint32_t x3, uint32_t y3, float u1, float v1, float u2, float v2, float u3, float v3, const Brush& brush)
{
	//保证 y1 是最小的
	if (y1 > y2)
	{
		std::swap(x1, x2);
		std::swap(y1, y2);
		std::swap(u1, u2);
		std::swap(v1, v2);
	}
	if (y1 > y3)
	{
		std::swap(x1, x3);
		std::swap(y1, y3);
		std::swap(u1, u3);
		std::swap(v1, v3);
	}
	//保证 y3 是最大的
	if (y3 < y2)
	{
		std::swap(x2, x3);
		std::swap(y2, y3);
		std::swap(u2, u3);
		std::swap(v2, v3);
	}
	//y1 ~ y2, y1 ~ y3, y2 ~ y3;
	Line lines[] =
	{
		Line(Point(x1, y1, u1, v1), Point(x2, y2, u2, v2)),
		Line(Point(x1, y1, u1, v1), Point(x3, y3, u3, v3)),
		Line(Point(x2, y2, u2, v2), Point(x3, y3, u3, v3))
	};
	auto start = y1 * stride;
	for (uint32_t y = y1; y < y2; y++)
	{
		auto minX = lines[0].GetX(y);
		auto maxX = lines[1].GetX(y);
		auto minUV = lines[0].GetUV(y);
		auto maxUV = lines[1].GetUV(y);
		//
		if (minX > maxX)
		{
			std::swap(minX, maxX);
			std::swap(minUV, maxUV);
		}
		auto iminX = std::roundf(minX);
		auto imaxX = std::roundf(maxX);
		const auto gradU = (maxX - minX) ? (maxUV.first - minUV.first) / (maxX - minX) : 0.f;
		const auto gradV = (maxX - minX) ? (maxUV.second - minUV.second) / (maxX - minX) : 0.f;
		for (uint32_t x = iminX, i = 0; x < imaxX; x++, i++)
		{
			auto u = gradU * i + minUV.first;
			auto v = gradV * i + minUV.second;
			::MixColor(data[start + x], brush.TakeSample(u, v));
		}
		start += stride;
	}

	for (uint32_t y = y2; y < y3; y++)
	{
		auto minX = lines[2].GetX(y);
		auto maxX = lines[1].GetX(y);
		auto minUV = lines[2].GetUV(y);
		auto maxUV = lines[1].GetUV(y);
		//
		if (minX > maxX)
		{
			std::swap(minX, maxX);
			std::swap(minUV, maxUV);
		}
		auto iminX = std::roundf(minX);
		auto imaxX = std::roundf(maxX);
		const auto gradU = (maxX - minX) ? (maxUV.first - minUV.first) / (maxX - minX) : 0.f;
		const auto gradV = (maxX - minX) ? (maxUV.second - minUV.second) / (maxX - minX) : 0.f;
		for (uint32_t x = iminX, i = 0; x < imaxX; x++, i++)
		{
			auto u = gradU * i + minUV.first;
			auto v = gradV * i + minUV.second;
			::MixColor(data[start + x], brush.TakeSample(u, v));
		}
		start += stride;
	}
}
Example #2
0
bool GraphicAlgorithms::DrawSpecialLine(color_t* data, uint32_t stride, int x1, int y1,
	int x2, int y2, float u1, float v1, float u2, float v2, const Brush& brush)
{
	//纵向
	if (x1 == x2)
	{
		//保证 y1 < y2
		if (y1 > y2)
		{
			std::swap(y1, y2);
			std::swap(u1, u2);
			std::swap(v1, v2);
		}
		auto curPixel = y1 * stride + x1;
		auto const gradient = (y2 - y1) ? (v2 - v1) / (y2 - y1) : 0.f;
		for (uint32_t y = y1; y <= y2; y++)
		{
			data[curPixel] = brush.TakeSample(u1, v1);
			curPixel += stride;
			v1 += gradient;
		}
	}
	//横向
	else if (y1 == y2)
	{
		//保证 x1 < x2
		if (x1 > x2)
		{
			std::swap(x1, x2);
			std::swap(u1, u2);
			std::swap(v1, v2);
		}
		const auto start = y1 * stride;
		auto const gradient = (u2 - u1) / (x2 - x1);
		for (uint32_t x = x1; x <= x2; x++)
		{
			data[start + x] = brush.TakeSample(u1, v1);
			u1 += gradient;
		}
	}
	//45度
	else if (x1 - x2 == y1 - y2)
	{
		//保证 x1 < x2(y1 < y2)
		if (x1 > x2)
		{
			std::swap(x1, x2);
			std::swap(y1, y2);
			std::swap(u1, u2);
			std::swap(v1, v2);
		}
		auto curPixel = y1 * stride + x1;
		auto const gradientX = (u2 - u1) / (y2 - y1);
		auto const gradientY = (v2 - v1) / (y2 - y1);
		for (uint32_t y = y1; y <= y2; y++)
		{
			data[curPixel] = brush.TakeSample(u1, v1);
			curPixel += stride + 1;
			u1 += gradientX;
			v1 += gradientY;
		}
	}
	//135度
	else if (x1 - x2 == y2 - y1)
	{
		//保证 y1 < y2(x1 > x2)
		if (y1 > y2)
		{
			std::swap(x1, x2);
			std::swap(y1, y2);
			std::swap(u1, u2);
			std::swap(v1, v2);
		}
		auto curPixel = y1 * stride + x1;
		auto const gradientX = (u2 - u1) / (y2 - y1);
		auto const gradientY = (v2 - v1) / (y2 - y1);
		for (uint32_t y = y1; y <= y2; y++)
		{
			data[curPixel] = brush.TakeSample(u1, v1);
			curPixel += stride - 1;
			u1 += gradientX;
			v1 += gradientY;
		}
	}
	//其他情况
	else
	{
		return false;
	}
	return true;
}
Example #3
0
void GraphicAlgorithms::DrawLine_WuXiaolin(color_t* data, uint32_t stride, uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2,
	float u1, float v1, float u2, float v2, const Brush& brush)
{
	if (DrawSpecialLine(data, stride, x1, y1, x2, y2, u1, v1, u2, v2, brush)) return;

	double dx = (double)x2 - (double)x1;
	double dy = (double)y2 - (double)y1;
	const auto ax = std::fabs(dx);
	const auto ay = std::fabs(dy);
	std::function<void(uint32_t, uint32_t, float, float, double)> plot;

	if (ax < ay)
	{
		std::swap(x1, y1);
		std::swap(x2, y2);
		std::swap(dx, dy);
		std::swap(u1, v1);
		std::swap(u2, v2);

		plot = [=, &brush](uint32_t y, uint32_t x, float v, float u, double p)
		{
			argb_color col1, col;
			col1.col = data[y * stride + x];
			col.col = brush.TakeSample(u, v);

			data[y * stride + x] = MixColor(col, col1, p).col;
		};
	}
	else
	{
		plot = [=, &brush](uint32_t x, uint32_t y, float u, float v, double p)
		{
			argb_color col1, col;
			col1.col = data[y * stride + x];
			col.col = brush.TakeSample(u, v);

			data[y * stride + x] = MixColor(col, col1, p).col;
		};
	}

	if (x2 < x1)
	{
		std::swap(x1, x2);
		std::swap(y1, y2);
		std::swap(u1, u2);
		std::swap(v1, v2);
	}
	const auto gradient = dy / dx;
	const auto gradientU = (u2 - u1) / dx;
	const auto gradientV = (v2 - v1) / dx;
	auto xEnd = std::round(x1);
	auto yEnd = y1 + gradient * (xEnd - x1);
	auto xGap = rfpart(x1 + 0.5);

	const auto xpxl1 = (uint32_t)xEnd;
	const auto ypxl1 = (uint32_t)std::floor(yEnd);
	plot(xpxl1, ypxl1, u1, v1, rfpart(yEnd) * xGap);
	plot(xpxl1, ypxl1 + 1, u1, v1, fpart(yEnd) * xGap);

	auto yInter = yEnd + gradient;
	auto vInter = v1 + gradientV * (xEnd - x1) + gradientV;

	xEnd = std::round(x2);
	yEnd = y2 + gradient * (xEnd - x2);
	xGap = fpart(x2 + 0.5);
	const auto xpxl2 = (uint32_t)xEnd;
	const auto ypxl2 = (uint32_t)std::floor(yEnd);
	plot(xpxl2, ypxl2, u2, v2, rfpart(yEnd) * xGap);
	plot(xpxl2, ypxl2 + 1, u2, v2, fpart(yEnd) * xGap);

	auto upxl1 = u1;
	for (uint32_t x = xpxl1 + 1; x < xpxl2; x++)
	{
		plot(x, std::floor(yInter), upxl1, vInter, rfpart(yInter));
		plot(x, std::floor(yInter) + 1, upxl1, vInter, fpart(yInter));

		yInter += gradient;
		upxl1 += gradientU;
		vInter += gradientV;
	}
}