I am writing an HSV colour picker in plain win32 c .
I have a Sat/Val box and a Hue slider exactly like the image on the left here:
Up until now I was just generating the background of the Sat-Val box whenever I needed it.
But now that I have a simple prototype and I am circling around to refactor and clean up I have realized that it actually takes a sizeable amount of time to generate the background bitmap for the sat-val box.
Since scrolling the hue slider should update the sat-val box with the appropriate hue, and it should be responsive and fast, I guess I cannot generate the background on the fly because it's too costly.
I have been using a very simple function like this:
HBITMAP ColorPicker::genSVBackground(uint32_t hue)
{
uint32_t width = 256;
uint32_t height = 256;
HDC hDC = GetDC(hwnd);
HDC memDC = CreateCompatibleDC(hDC);
HBITMAP bitmap = CreateCompatibleBitmap(hDC, width, height);
HGDIOBJ oldObj = SelectObject(memDC, bitmap);
for (uint32_t y = 0; y < height; y) {
for (uint32_t x = 0; x < width; x) {
RGBColor rgbCol = hsv_to_rgb(HSVColor(hue, x, 255 - y));
COLORREF col = (rgbCol.blue << 16) | (rgbCol.green << 8) | (rgbCol.red);
SetPixel(memDC, x, y, col);
}
}
SelectObject(memDC, oldObj);
DeleteDC(memDC);
return bitmap;
}
So the first question is:
Can I make this faster? Fast enough that I can still generate it on the fly? Should I?
And if I cannot make it faster, or if there's really no point and I might as well just use an external resource instead.
What is the best approach to go about storing this in an external resource?
Should I create one giant array that describes a 'cube' of hue x sat x val (my hue, sat and val system is 0-255 each) so I can just load the entire thing into memory and index certain positions to read out an entire background slice?
I know how to do the specifics of the resource storage/loading I'm just not sure if I'm approaching this problem the right way.
Should I store each slice as a separate resource? 256 of them?
Is there a standard way to solving this kind of thing?
CodePudding user response:
I think the source of your slowness is writing one pixel at a time to the memory DC.
Instead of calling SetPixel 256x256 times in a loop, blast an entire matrix of pixels to the DC at once. At the very least, that's 64K function invocations.
I used to do this kind of buffering with GDI all the time. I'd create a Bitmap object and then call the LockBits method on it. Do my rendering directly on the returned pointer, and then UnlockBits. It's been a while since I've done the pure Win32 variations of this, but I'm sure it's possible.