【问题标题】:How to display pixels on screen directly from a raw array of RGB values faster than SetPixel()?如何比 SetPixel() 更快地直接从 RGB 值的原始数组在屏幕上显示像素?
【发布时间】:2014-11-18 06:55:02
【问题描述】:

我喜欢在 C++ 中制作“动画”,例如 MandelBrot Set zoomer、Game of Life 模拟器等,方法是将像素直接逐帧设置到屏幕上。 SetPixel() 命令使这非常容易,尽管不幸的是它也非常缓慢。如果我想用数组 R 的内容绘制整个屏幕,这是我为每一帧使用的那种设置:

#include <windows.h>
using namespace std;
int main()
{
    int xres = 1366;
    int yres = 768;
    char *R = new char [xres*yres*3];

    /*
    R is a char array containing the RGB value of each pixel sequentially
    Arithmetic operations done to each element of R here
    */

    HWND window; HDC dc; window = GetActiveWindow(); dc = GetDC(window);

    for (int j=0 ; j<yres ; j++)
        for (int i=0 ; i<xres ; i++)
            SetPixel(dc,i,j,RGB(R[j*xres+3*i],R[j*xres+3*i+1],R[j*xres+3*i+2]));

    delete [] R;
    return 0;
}

在我的机器上,这需要将近 5 秒才能执行,原因很明显,SetPixel() 被调用超过一百万次。最佳情况下,我可以让它运行速度提高 100 倍并获得流畅的 20fps 动画。

我听说以某种方式将 R 转换为位图文件,然后使用 BitBlt 在一个干净的命令中显示框架是可行的方法,但我不知道如何为我的设置实现这一点,我将不胜感激帮助。

如果相关,我在 Windows 7 上运行并使用 Code::Blocks 作为我的 IDE。

【问题讨论】:

  • 您的预感是正确的:Windows 和设置单个像素之间的交互是瓶颈,首选方法是创建内存位图。找到这方面的教程应该不难。一旦你实施它,你可能会对速度的提高惊讶。 (另一种选择可能是切换到 SDL,它也可以以相同的方式加速,但最小化 Windows 特定部分。)
  • 使用CreateDIBitmap() 根据您提供的像素数据创建位图。生成的位图将与您要在其上绘制的窗口 HDC 兼容,因此您可以使用 CreateCompatibleDC()SelectObject() 准备要绘制的位图,然后使用 BitBlt() 将位图实际绘制到窗口上。
  • 另见 CreateDIBSection

标签: c++ windows animation bitmap pixel


【解决方案1】:

按照 Remy 的建议,我最终采用了这种显示像素数组的方式(对于需要一些代码作为示例的人):

COLORREF *arr = (COLORREF*) calloc(512*512, sizeof(COLORREF));
/* Filling array here */
/* ... */

// Creating temp bitmap
HBITMAP map = CreateBitmap(512 // width. 512 in my case
                           512, // height
                           1, // Color Planes, unfortanutelly don't know what is it actually. Let it be 1
                           8*4, // Size of memory for one pixel in bits (in win32 4 bytes = 4*8 bits)
                           (void*) arr); // pointer to array
// Temp HDC to copy picture
HDC src = CreateCompatibleDC(hdc); // hdc - Device context for window, I've got earlier with GetDC(hWnd) or GetDC(NULL);
SelectObject(src, map); // Inserting picture into our temp HDC
// Copy image from temp HDC to window
BitBlt(hdc, // Destination
       10,  // x and
       10,  // y - upper-left corner of place, where we'd like to copy
       512, // width of the region
       512, // height
       src, // source
       0,   // x and
       0,   // y of upper left corner  of part of the source, from where we'd like to copy
       SRCCOPY); // Defined DWORD to juct copy pixels. Watch more on msdn;

DeleteDC(src); // Deleting temp HDC

【讨论】:

  • 另外,不要忘记在最后调用DeleteObject(map) 之前调用DeleteDC(src)。见here
  • 在 MinGW 上,我必须在“-o”参数的名称后添加“-lgdi32”。
猜你喜欢
  • 1970-01-01
  • 2013-03-17
  • 2015-12-04
  • 1970-01-01
  • 2017-11-21
  • 1970-01-01
  • 2014-12-28
  • 1970-01-01
  • 2020-12-01
相关资源
最近更新 更多