Gday, just been playing with fractals myself for a couple of weeks, 4d julia sets in my case - the problems you mention are one of the definite gotchas in the pursuit.
The way to do it is to allocate a buffer that will hold the rgba values of the pixels you wish to plot. You can access the pixels in virtually no time.
In order to further speed up your program, you should use worker threads. Each thread completes a portion of the picture before signalling that it's done. Each thread can use the same screen buffer, which you then blast to screen in a single fell swoop.
Here's the basic code:
void *screenBuffer;
long imageWidth, imageHeight;
void setupBuffer(int w, int h)
{
screenBuffer = (long*)malloc(w * h * 4); imageWidth = w;
imageHeight = h;
}
void myPixel(int x, int y, long rgbaVal)
{
((long*)(screenBuffer))[y*imageWidth+x] = rgbaVal; }
void videoput32(void *buf, int imgBufWidth, int imgBufHeight, HWND destHwnd)
{
char bibuf[ sizeof(BITMAPINFOHEADER)+12 ];
BITMAPINFO &bi = *(BITMAPINFO*)&bibuf;
BITMAPINFOHEADER &bih = bi.bmiHeader;
bih.biSize = sizeof(bih);
bih.biWidth = imgBufWidth;
bih.biHeight = -imgBufHeight;
bih.biPlanes = 1;
bih.biBitCount = 32;
bih.biCompression = BI_BITFIELDS;
bih.biSizeImage = 0;
bih.biXPelsPerMeter = 0;
bih.biYPelsPerMeter = 0;
bih.biClrUsed = 0;
bih.biClrImportant=0;
((unsigned long*)bi.bmiColors)[0]=0x00FF0000;
((unsigned long*)bi.bmiColors)[1]=0x0000FF00;
((unsigned long*)bi.bmiColors)[2]=0x000000FF;
RECT r;
HDC dc=GetDC(destHwnd);
GetClientRect(destHwnd, &r);
StretchDIBits(dc, 0, 0, r.right, r.bottom, 0, 0, imageWidth, imageWidth, buf, &bi, DIB_RGB_COLORS, SRCCOPY);
ReleaseDC(destHwnd,dc);
ValidateRect(destHwnd, &r);
}
And a small section from the DialogProc:
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case IDC_RENDER_BTN:
threadsRemaining = onRenderButtonClick();
SetDlgItemInt(hwndDlg, IDC_THREADS_REMAINING_TXT, threadsRemaining, true);
break;
}
}
return TRUE;
case WM_THREAD_COMPLETE:
threadsRemaining--;
SetDlgItemInt(hwndDlg, IDC_THREADS_REMAINING_TXT, threadsRemaining, true);
if (threadsRemaining == 0)
{
drawZbufferToImage();
SendMessage(outputWnd, WM_SET_DATA, 0, (LPARAM) &bufferSpec);
threadsRemaining = onRenderButtonClick();
}
break;
And another - a snippet of the thread function and it telling the main window that it's done.
#define WM_THREAD_COMPLETE WM_USER + 1
void threadFunction2(void *threadData)
{
myThreadData_t *tmp = (myThreadData_t*)threadData;
drawIntoZbuffer3( frameNum, (RECT){tmp->left,tmp->top,tmp->right,tmp->bottom} );
SendMessage(mainHwnd, WM_THREAD_COMPLETE, 0, 0);
}