【发布时间】:2019-05-26 06:58:36
【问题描述】:
我创建了一个使用SetPixel() 方法在Windows 控制台中渲染精灵的基本程序,它运行良好,但是开销很大。
我对此进行了一些优化,这有所帮助,但仍然太慢了。
目前我的程序使用COLORREF 的两个缓冲区将较新的缓冲区绘制到屏幕上,交换它们并重新开始。但是,如果所述像素已更改,它只会重绘一个像素。这极大地提高了性能,但仍然很慢。
缓冲区交换尚未使用指针完成,但真正的开销是 SetPixel() 所以,我正在寻找一种使用 GDI 创建像素级图形的替代方法,它比 SetPixel() 更快
(忽略 anim_frame 和 img_data 向量的第一维,如果我决定添加动画对象,它们就在那里)
void graphics_context::update_screen()
{
update_buffer();
for (int x = 0; x < this->width; x++)
{
for (int y = 0; y < this->height; y++)
{
if (this->buffer.at(x).at(y) != this->buffer_past.at(x).at(y))
{
for (int i = 0; i < this->scale_factor; i++)
{
for (int j = 0; j < this->scale_factor; j++)
{
int posX = i + (this->scale_factor * x) + this->width_offset;
int posY = j + (this->scale_factor * y) + this->height_offset;
SetPixel(this->target_dc, posX, posY, this->buffer.at(x).at(y));
}
}
}
}
}
buffer_past = buffer;
}
这就是update_buffer() 方法:
void graphics_context::update_buffer()
{
for (int x = 0; x < this->width; x++)
{
for (int y = 0; y < this->height; y++)
{
buffer.at(x).at(y) = RGB(0, 0, 0);
}
}
//this->layers.at(1)->sprite; <- pointer to member gfx_obj pointer
for (int i = 0; i < this->layers.size(); i++)
{
gfx_object tmp_gfx = *this->layers.at(i)->sprite;
for (int x = 0; x < tmp_gfx.img_data.at(0).size(); x++)
{
for (int y = 0; y < tmp_gfx.img_data.at(tmp_gfx.anim_frame).at(0).size(); y++)
{
if(tmp_gfx.img_data.at(tmp_gfx.anim_frame).at(x).at(y) != RGB(0,255,0))
buffer.at(x + this->layers.at(i)->locX).at(y + this->layers.at(i)->locY) = tmp_gfx.img_data.at(tmp_gfx.anim_frame).at(x).at(y);
}
}
}
}
【问题讨论】:
-
SetPixel是出了名的慢,部分原因是它必须在每次调用时发现要写入的图像的属性。使用LockBits并直接对位图字节进行操作要快得多,如this question,但这也更复杂,因为位图格式可能不同。 -
如果
target_dc是一个窗口设备上下文,那么你正在做很多GDI 调用,它会很慢。如果target_dc是内存设备上下文,那么SetPixel相当快。使用SetPixelV,它不会返回现有颜色并且速度会更快一些。无论哪种方式都是错误的。最后你想使用BitBlt来绘制图像。您也可以使用BitBlt来绘制精灵。 -
.at也不快,但这可能是次要的 -
@BarmakShemirani 所以我必须改用位图,才能获得相当有效的绘图?而
target_dc是一个窗口设备上下文 -
@MSalters 是
[]运算符更快吗?还是我应该用一些指针魔法直接访问内存?