EasyX 任意透明度,缓冲区画点,绘制半透明星星图案时,发生黑线以及绘图缓冲区益出决解。

0

使用半透明算法加载一个缓冲区画点,再组成其他的几何图形,以下代码里,矩形半透明没有任何问题,但是一个星星形状的图形,进行半透明运算反去过的效果有黑线,然后就是一个绘图缓冲区益出问题,不知是什么问题,如果有人解决可以有偿。微信:NYJ13620
下面是一个修复半透明红色和红色变黑的源代码:

#include<stdio.h>
#include<graphics.h>
DWORD* g_pBuf;
// 进行前景色和背景色半透明计算。
COLORREF  Alphargb(int r1, int g1, int b1, int r2, int g2, int b2, int alp)
{	COLORREF rgb1 =RGB((((r1 - alp) * r1) + (alp * r2)) * 0.01,(((g1 - alp) * g1) + (alp * g2)) * 0.01,(((b1 - alp) * b1) + (alp * b2)) * 0.01);
	return rgb1;
}
// 显示缓冲区指针
COLORREF fast_getpixel(int x, int y, int WIDTH){COLORREF c = g_pBuf[y * WIDTH + x];return BGR(c);}
// 快速画点函数
void fast_putpixel(int x, int y, int WIDTH, COLORREF c)
{
	COLORREF bj;
	bj = fast_getpixel(x, y, WIDTH);
	int r2 = GetRValue(c),g2 = GetGValue(c),b2 = GetBValue(c),r1 = GetRValue(bj),g1 = GetGValue(bj),b1 = GetBValue(bj);

	COLORREF bjys = getbkcolor();
	COLORREF bj1 = BGR(r1, g1, b1);

	if (bjys == bj){	g_pBuf[abs(y * WIDTH + x)] = BGR(c);}
	if (bjys != bj){g_pBuf[abs(y * WIDTH + x)] = BGR(Alphargb(r2, g2, b2, r1, g1, b1, 60));}
}

void rec(int x1, int y1, int x2, int y2, COLORREF c)
{	int  WIDTH = getwidth();
	for (int i = y1; i < y1 + (y2 - y1); i++){for (int j = x1; j < x1 + (x2 - x1); j++){	fast_putpixel(j, i, WIDTH, c);}}
}

int main()
{
	initgraph(800, 800);
	g_pBuf = GetImageBuffer();
	int rz = 100, gz = 0, bz = 0, a = 1;
	ExMessage m;		// 定义消息变量

	BeginBatchDraw();
	while (true)
	{	// 获取一条鼠标或按键消息
		m = getmessage(EX_MOUSE | EX_KEY);
		switch (m.message)
		{
		case WM_MOUSEMOVE:
			// 鼠标移动的时候画红色的小点	
			rec(100, 100, 200, 200, RED);
			rec(150, 150, 150 + 100, 150 + 100, GREEN);
			rec(200, 200, 200 + 100, 200 + 100, BLUE);
			rec(200 + 50, 200 + 50, 250 + 100, 250 + 100, WHITE);
			rec(300, 300, 300 + 100, 300 + 100, LIGHTMAGENTA);
			rec(250 + 100, 250 + 100, 350 + 100, 350 + 100, YELLOW);
			rec(m.x, m.y, m.x + 100, m.y + 100, RGB(rz, gz, bz));
			FlushBatchDraw();
			break;

		case WM_LBUTTONDOWN:
			a = rand() % 3 + 1;
			if (a == 1) { rz = 100; gz = 0; bz = 0; }if (a == 2) { rz = 0; gz = 100; bz = 0; }if (a == 3) { rz = 0; gz = 0; bz = 100; }
			break;
		}
		cleardevice();
	}
	EndBatchDraw();
	getmessage(EX_CHAR);
	closegraph();
	return 0;
}	

问题代码:

// EasyX 简单缓冲区半透明画点,让你的绘图支持任意的透明度,达到让大家推波推润的效果。
// 2023 - 4 - 7 
// 作者:舞乐葉
// QQ:2250395955
#define WINVER 0x0A00
#define _WIN32_WINNT 0x0A00
#include <stdio.h>
#include <conio.h>
#include <graphics.h>
#include <math.h>
#include <ShellScalingApi.h>		// 引用头文件
#pragma comment(lib, "Shcore.lib")	// 链接库文件
// 打开缓冲区。
DWORD* g_pBuf;
// 进行前景色和背景色半透明计算。
COLORREF  Alphargb(int r1, int g1, int b1, int r2, int g2, int b2, int alp)
{	COLORREF rgb1 = RGB((((r1 - alp) * r1) + (alp * r2)) * 0.01, (((g1 - alp) * g1) + (alp * g2)) * 0.01, (((b1 - alp) * b1) + (alp * b2)) * 0.01);
	return rgb1;
}
// 显示缓冲区指针,并读取坐标上的颜色值。
COLORREF fast_getpixel(int x, int y, int WIDTH) { COLORREF c = g_pBuf[y * WIDTH + x]; return BGR(c); }

// 快速缓冲区半透明画点函数 2
void putpixel1(DWORD* g_pBuf, int x, int y, COLORREF c)
{	int xxx = getwidth(), ax = (y * xxx + x), WIDTH = getwidth(), puti = abs(y * WIDTH + x);
	
	if (puti <= 1){puti == 5;}
	if (puti <= (getwidth() * getheight())){puti - 5;}
	COLORREF bj, bjys = getbkcolor();
	// 读取背景上的颜色点。
	bj = fast_getpixel(x, y, xxx);
	//if (bj != WHITE) bj = fast_getpixel(x, y, xxx);
	// 声明定义背景颜色和绘图的颜色。
	int r2 = GetRValue(c), g2 = GetGValue(c), b2 = GetBValue(c), r1 = GetRValue(bj), g1 = GetGValue(bj), b1 = GetBValue(bj);
	// 获取背景颜色和绘图颜色,并进行透明混合计算和,排除不是透明的部分。
	COLORREF bj1 = BGR(r1, g1, b1);
	// 排除非透明区域的颜色,只混合有颜色的区域。
	if (bjys == bj) { g_pBuf[puti] = BGR(c); }
	if (bj != bjys) { g_pBuf[puti] = BGR(Alphargb(r2, g2, b2, r1, g1, b1, 60)); }
}
// 画支持透明的矩形。
void rec(int x1, int y1, int x2, int y2, COLORREF c)
{// 获取绘图区宽度。
	int  WIDTH = getwidth();	g_pBuf = GetImageBuffer();
	for (int i = y1; i < y1 + (y2 - y1); i++)for (int j = x1; j < x1 + (x2 - x1); j++)putpixel1(g_pBuf, j, i, c);
}
// 中点画圆法,转为星星形状
void Circle_Midpoint5(int x, int y, int r, int color, int temp)
{	DWORD* pu = GetImageBuffer();
	int tx = 0, ty = r, d = 1 - r, d1 = 0;
	while (tx <= ty)
	{	if (temp == 1)
		{	(x + tx, y + ty, color);
			putpixel1(pu, x + ty, y + tx, color);																	d1 = 0;
			for (int i = (x + tx); i <= (x + r); i++) { putpixel1(pu, (x + tx) + d1, y + ty, color);	d1++; }		d1 = 0;
			for (int i = (x + ty); i <= (x + r); i++) { putpixel1(pu, (x + ty) + d1, y + tx, color);	d1++; }
		}
		if (temp == 2)
		{	putpixel1(pu, x - ty, y + tx, color); putpixel1(pu, x - tx, y + ty, color);						d1 = 0;
			for (int i = (x - ty); i >= (x - r); i--) { putpixel1(pu, (x - ty) + d1, y + tx, color);	d1--; }		d1 = 0;
			for (int i = (x - tx); i >= (x - r); i--) { putpixel1(pu, (x - tx) + d1, y + ty, color);	d1--; }
		}
		if (temp == 3)
		{	putpixel1(pu, x - ty, y - tx, color); putpixel1(pu, x - tx, y - ty, color);						d1 = 0;
			for (int i = (x - ty); i >= (x - r); i--) { putpixel1(pu, (x - ty) + d1, y - tx, color);	d1--; }		d1 = 0;
			for (int i = (x - tx); i >= (x - r); i--) { putpixel1(pu, (x - tx) + d1, y - ty, color);	d1--; }
		}
		if (temp == 4)
		{	putpixel1(pu, x + tx, y - ty, color); putpixel1(pu, x + ty, y - tx, color);						d1 = 0;
			for (int i = (x + tx); i <= (x + r); i++) { putpixel1(pu, (x + tx) + d1, y - ty, color);	d1++; }		d1 = 0;
			for (int i = (x + ty); i <= (x + r); i++) { putpixel1(pu, (x + ty) + d1, y - tx, color);	d1++; }
		}
		if (d < 0)d += 2 * tx + 3; else d += 2 * (tx - ty) + 5, ty--;
		tx++;
	}
}
void star(int x, int y, int lie = NULL)
{	int x1 = x - lie, y1 = y - lie; int x2 = x + lie, y2 = y - lie; int x3 = x + lie, y3 = y + lie; int x4 = x - lie, y4 = y + lie;
	Circle_Midpoint5(x1, y1, lie, RED, 1); Circle_Midpoint5(x2, y2, lie, RED, 2);
	Circle_Midpoint5(x3, y3, lie, RED, 3); Circle_Midpoint5(x4, y4, lie, RED, 4);
}
// 主函数
int main()
{	SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
	// 创建绘图窗口
	initgraph(800, 800);
	g_pBuf = GetImageBuffer();
	BeginBatchDraw();		// 开启批量绘图
	ExMessage m;
	while (true)
	{	// 获取一条鼠标或按键消息
		peekmessage(&m, EX_MOUSE | EX_KEY, true);
		rec(100, 100, 200, 200, RED);
		rec(150, 150, 150 + 100, 150 + 100, GREEN);
		rec(200, 200, 200 + 100, 200 + 100, BLUE);
		rec(200 + 50, 200 + 50, 250 + 100, 250 + 100, WHITE);
		rec(300, 300, 300 + 100, 300 + 100, LIGHTMAGENTA);
		rec(250 + 100, 250 + 100, 350 + 100, 350 + 100, YELLOW);
		switch (m.message)
		{
		case WM_MOUSEMOVE:star(m.x, m.y, 100);rec(m.x + 100, m.y, m.x + 200, m.y + 100, RED);
		break;
		}
		FlushBatchDraw();
		cleardevice();
	}
	_getch();
	EndBatchDraw();
	closegraph();
	return 0;
}
ava
Margoo

2023-4-11

0

1. 你的矩形半透明也有问题。例如,红色矩形,叠加在红色区域上,会变成黑色。显然,这是不合理的。
2. 星星形状的黑线问题,可以看到,黑线仅发生在圆弧切线斜率 |k|<1 的时候。这时候,x 增加时,y 不一定增加。如果 y 没有增加,根据你的算法,就会发生同一条横线重复绘制的问题。根据前面说的,当重复绘制时,你的程序会导致图像显示为黑色。所以,就出现了黑线。

ava
慢羊羊

2023-4-15

对于矩形半透明的问题,我在以前的源代码版本上进行恢复,现在以经接近于真正半透明的原色了,红色和红色不会变成黑色,推测问题和星星开关函数有关,在 PS 半透明的颜色校准相当的接近或者相等了。示例正面代码。 -  Margoo  2023-4-16
技术讨论社区