Win32 confusing flicker - c++
I have a function in which a bunch of stuff is drawn into an offscreen buffer. At the end of the function, it calls InvalidateRect. For some reason, sometimes it redraws halfway through the function, causing a flicker. Here's the code for the function:
// Side Info
HBITMAP side = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_SIDEINFO));
hdcold = (HBITMAP)SelectObject(hbcmem, side);
BitBlt(hdcmem, 339, 26, 154, 300, hbcmem, 0, 0, SRCCOPY);
DrawLevelNumber(game.levelnumber);
if (color)
sprites = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_COLOR_SPRITES));
else sprites = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BLACKWHITE_SPRITES));
hdcold = (HBITMAP)SelectObject(hbcmem, sprites);
// Find x and y coordinate for the top left of the visible screen
int x = game.Player_x, y = game.Player_y, ypos = 0;
if (x < 4) x = 4;
if (x > 27) x = 27;
if (y < 4) y = 4;
if (y > 27) y = 27;
x -= 4;
y -= 4;
// Draw lower layer
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
if (game.Layer_Two[x + i][y + j] != 0)
{
int xpos = game.get_pos(game.Layer_Two[x + i][y + j], ypos, false);
BitBlt(hdcmem, (i * 32) + 32, (j * 32) + 32, 32, 32, hbcmem, xpos, ypos, SRCCOPY);
}
}
}
// Draw upper layer
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
if ((game.Layer_Two[x + i][y + j] != 0 && game.Layer_One[x + i][y + j] >= 64 && game.Layer_One[x + i][y + j] <= 111))
{
int xpos = game.get_pos(game.Layer_One[x + i][y + j], ypos, true);
BitBlt(hdcmem, (i * 32) + 32, (j * 32) + 32, 32, 32, hbcmem, xpos + 96, ypos, SRCPAINT);
BitBlt(hdcmem, (i * 32) + 32, (j * 32) + 32, 32, 32, hbcmem, xpos, ypos, SRCAND);
} else {
int xpos = game.get_pos(game.Layer_One[x + i][y + j], ypos, false);
BitBlt(hdcmem, (i * 32) + 32, (j * 32) + 32, 32, 32, hbcmem, xpos, ypos, SRCCOPY);
}
}
}
// If it isn't started, show title
if (!game.started)
{
HDC tmphdc = CreateCompatibleDC(hdcmem);
HDC tmp = CreateCompatibleDC(tmphdc);
RECT rc;
GetClientRect(hWnd, &rc);
string str = game.leveltitle.substr(0, game.leveltitle.length() - 1) + "\nPassword: " + game.password;
TCHAR* tch = new TCHAR[str.length()];
mbstowcs_s(NULL, tch, _tcslen(tch), str.c_str(), str.length());
HFONT font = CreateFont(25, 0, 0, 0, FW_BOLD, false, false, false, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE, NULL);
SelectObject(tmp, font);
DrawText(tmp, tch, str.length(), &rc, DT_CALCRECT);
rc.right += 16;
HBITMAP tmpbm = CreateCompatibleBitmap(hdcmem, rc.right, rc.bottom);
HBITMAP tmpold = (HBITMAP)SelectObject(tmphdc, tmpbm);
HBRUSH hbr = CreateSolidBrush(RGB(255, 255, 255));
HPEN pen = CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
SelectObject(hdcmem, pen);
SelectObject(hdcmem, hbr);
Rectangle(hdcmem, 176 - (rc.right / 2), 243, 177 + (rc.right / 2), 248);
hbr = CreateSolidBrush(RGB(128, 128, 128));
pen = CreatePen(PS_SOLID, 1, RGB(128, 128, 128));
SelectObject(hdcmem, pen);
SelectObject(hdcmem, hbr);
Rectangle(hdcmem, 176 - (rc.right / 2), 294, 177 + (rc.right / 2), 299);
HBITMAP left = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_LEFT));
hdcold = (HBITMAP)SelectObject(hbcmem, left);
BitBlt(hdcmem, 176 - (rc.right / 2) - 4, 243, 4, 56, hbcmem, 0, 0, SRCCOPY);
HBITMAP right = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_RIGHT));
hdcold = (HBITMAP)SelectObject(hbcmem, right);
BitBlt(hdcmem, 176 + (rc.right / 2) + 1, 243, 4, 56, hbcmem, 0, 0, SRCCOPY);
SelectObject(tmphdc, font);
SetTextColor(tmphdc, RGB(255, 255, 0));
SetBkColor(tmphdc, RGB(0, 0, 0));
DrawText(tmphdc, tch, str.length(), &rc, DT_CENTER);
BITMAP structBitmapHeader;
memset( &structBitmapHeader, 0, sizeof(BITMAP) );
HGDIOBJ hBitmap = GetCurrentObject(tmphdc, OBJ_BITMAP);
GetObject(hBitmap, sizeof(BITMAP), &structBitmapHeader);
BitBlt(hdcmem, 176 - (rc.right / 2), 247, structBitmapHeader.bmWidth, structBitmapHeader.bmHeight, tmphdc, 0, 0, SRCCOPY);
}
// If paused
if (game.paused)
{
RECT rc;
rc.top = 32;
rc.left = 32;
rc.bottom = 330;
rc.right = 330;
BitBlt(hdcmem, 32, 32, 288, 288, NULL, 0, 0, BLACKNESS);
HFONT font = CreateFont(50, 0, 0, 0, FW_NORMAL, false, false, false, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE, NULL);
SelectObject(hdcmem, font);
SetTextColor(hdcmem, RGB(255, 0, 0));
SetBkColor(hdcmem, RGB(0, 0, 0));
DrawText(hdcmem, L"PAUSED", 6, &rc, (DT_CENTER + DT_SINGLELINE + DT_VCENTER));
}
nums = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_NUMBERS));
hdcold = (HBITMAP)SelectObject(hbcmem, nums);
for (int i = 100; i > 0; i /= 10) // Coins left
{
int tmp;
if (i == 100)
tmp = game.coinsleft / 100;
if (i == 10)
tmp = ((game.coinsleft % 100) - (game.coinsleft % 10)) / 10;
if (i == 1)
tmp = game.coinsleft % 10;
if (game.coinsleft < i && i > 1)
tmp = 10;
int ypos = game.get_num_pos(tmp, (game.coinsleft == 0));
BitBlt(hdcmem, 369 + ((3 - log10((double)i)) * 17), 215, 17, 23, hbcmem, 0, ypos, SRCCOPY);
if (i == 100)
tmp = game.timeleft / 100;
if (i == 10)
tmp = ((game.timeleft % 100) - (game.timeleft % 10)) / 10;
if (i == 1)
tmp = game.timeleft % 10;
if (game.timeleft < i && i > 1)
tmp = 10;
if (game.timelimit == 0)
tmp = 11;
ypos = game.get_num_pos(tmp, (game.timeleft < 16 || game.timelimit == 0));
BitBlt(hdcmem, 369 + ((3 - log10((double)i)) * 17), 125, 17, 23, hbcmem, 0, ypos, SRCCOPY);
}
if (game.onhint)
{
HBITMAP sidebg = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_SIDEBG));
hdcold = (HBITMAP)SelectObject(hbcmem, sidebg);
BitBlt(hdcmem, 353, 165, 127, 146, hbcmem, 0, 0, SRCCOPY);
} else {
hdcold = (HBITMAP)SelectObject(hbcmem, sprites); // LOWER SIDE INFO
if (game.key1 > 0)
BitBlt(hdcmem, 352, 247, 32, 32, hbcmem, 192, 160, SRCCOPY);
else BitBlt(hdcmem, 352, 247, 32, 32, hbcmem, 0, 0, SRCCOPY);
if (game.key2 > 0)
BitBlt(hdcmem, 384, 247, 32, 32, hbcmem, 192, 128, SRCCOPY);
else BitBlt(hdcmem, 384, 247, 32, 32, hbcmem, 0, 0, SRCCOPY);
if (game.key3 > 0)
BitBlt(hdcmem, 416, 247, 32, 32, hbcmem, 192, 224, SRCCOPY);
else BitBlt(hdcmem, 416, 247, 32, 32, hbcmem, 0, 0, SRCCOPY);
if (game.key4)
BitBlt(hdcmem, 448, 247, 32, 32, hbcmem, 192, 192, SRCCOPY);
else BitBlt(hdcmem, 448, 247, 32, 32, hbcmem, 0, 0, SRCCOPY);
if (game.water)
BitBlt(hdcmem, 352, 279, 32, 32, hbcmem, 192, 256, SRCCOPY);
else BitBlt(hdcmem, 352, 279, 32, 32, hbcmem, 0, 0, SRCCOPY);
if (game.fire)
BitBlt(hdcmem, 384, 279, 32, 32, hbcmem, 192, 288, SRCCOPY);
else BitBlt(hdcmem, 384, 279, 32, 32, hbcmem, 0, 0, SRCCOPY);
if (game.ice)
BitBlt(hdcmem, 416, 279, 32, 32, hbcmem, 192, 320, SRCCOPY);
else BitBlt(hdcmem, 416, 279, 32, 32, hbcmem, 0, 0, SRCCOPY);
if (game.suction)
BitBlt(hdcmem, 448, 279, 32, 32, hbcmem, 192, 352, SRCCOPY);
else BitBlt(hdcmem, 448, 279, 32, 32, hbcmem, 0, 0, SRCCOPY);
}
RECT rc;
rc.left = 0;
rc.top = 0;
rc.right = 518;
rc.bottom = 401;
InvalidateRect(hWnd, &rc, false);
What is causing the flicker?
Ensure that you handle the WM_ERASEBKGND message and return TRUE, this will prevent the window base class from drawing the background.
Instead of calling InvalidateRect at the end of your drawing routine, place your drawing code inside a WM_PAINT message handler, this ensures your drawing code is called whenever the window is being repainted.
Related
How can I calculate the height and width of a given text? OpenGL
I draw the text using this two functions: https://pastebin.com/JVc5xFFT I draw the text - GlText(dc, "Test", ERGB{ 155, 179, 0 }, 5, 220); I build a font to uint with this function GLvoid BuildFont(HDC hDC, UINT* FontBase, int PointerWidth) { HFONT font; HFONT oldfont; *FontBase = glGenLists(96); font = CreateFontW(-MulDiv(PointerWidth, GetDeviceCaps(hDC, LOGPIXELSY), 72), 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, VARIABLE_PITCH | FF_SWISS, L"Trebuchet MS"); oldfont = (HFONT)SelectObject(hDC, font); wglUseFontBitmaps(hDC, 32, 96, *FontBase); SelectObject(hDC, oldfont); DeleteObject(font); } How can I find out the height and width of a given text?
Function for calculating(badly code. but working): SIZE CalculateTextSize(HDC dc, std::string text) { SIZE szi; SelectObject(dc, Font); SetTextCharacterExtra(dc, 1); GetTextExtentPoint32A(dc, text.c_str(), strlen(text.c_str()), &szi); szi.cx -= GetTextCharacterExtra(dc) * (strlen(text.c_str()) - 2); szi.cy -= ((FontSize % 2) % 2 == 0) ? FontSize / 2 : (FontSize / 2) - 1; return szi; }
SDL - how to render text from an alpha-only bitmap?
I'm trying to render text using SDL. Obviously SDL does not support rendering text by itself, so I went with this approach: load font file raster glyphs in the font to a bitmap pack all bitmaps in a large texture, forming a spritesheet of glyphs render text as a sequence of glyph-sprites: copy rectangles from the texture to the target First steps are handled using FreeType library. It can generate bitmaps for many kinds of fonts and provide a lot of extra info about the glyphs. FreeType-generated bitmaps are (by default) alpha channel only. For every glyph I basically get a 2D array of A values in range 0 - 255. For simplicity reasons the MCVE below needs only SDL, I already embedded FreeType-generated bitmap in the source code. Now, the question is: how should I manage the texture that consists of such bitmaps? What blending mode should I use? What modulation should I use? What should the texture be filled with? FreeType provides alpha channel only, SDL generally wants a texture of RGBA pixels. What values should I use for RGB? How do I draw text in specific color? I don't want to make a separate texture for each color. FreeType documentation says: For optimal rendering on a screen the bitmap should be used as an alpha channel in linear blending with gamma correction. SDL blending mode documentation doesn't list anything named linear blending so I used a custom one but I'm not sure if I got it right. I'm not sure if I got some of SDL calls right as some of them are poorly documented (I already know that locking with empty rectangles crashes on Direct3D), especially how to copy data using SDL_LockTexture. #include <string> #include <stdexcept> #include <SDL.h> constexpr unsigned char pixels[] = { 0, 0, 0, 0, 0, 0, 0, 30, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 169, 255, 155, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 255, 255, 229, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 189, 233, 255, 255, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 254, 83, 250, 255, 148, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 227, 2, 181, 255, 232, 3, 0, 0, 0, 0, 0, 0, 0, 2, 224, 138, 0, 94, 255, 255, 66, 0, 0, 0, 0, 0, 0, 0, 68, 255, 48, 0, 15, 248, 255, 153, 0, 0, 0, 0, 0, 0, 0, 166, 213, 0, 0, 0, 175, 255, 235, 4, 0, 0, 0, 0, 0, 16, 247, 122, 0, 0, 0, 88, 255, 255, 71, 0, 0, 0, 0, 0, 105, 255, 192, 171, 171, 171, 182, 255, 255, 159, 0, 0, 0, 0, 0, 203, 215, 123, 123, 123, 123, 123, 196, 255, 239, 6, 0, 0, 0, 44, 255, 108, 0, 0, 0, 0, 0, 75, 255, 255, 77, 0, 0, 0, 142, 252, 22, 0, 0, 0, 0, 0, 5, 238, 255, 164, 0, 0, 5, 234, 184, 0, 0, 0, 0, 0, 0, 0, 156, 255, 242, 8, 0, 81, 255, 95, 0, 0, 0, 0, 0, 0, 0, 68, 255, 255, 86, 0, 179, 249, 14, 0, 0, 0, 0, 0, 0, 0, 3, 245, 255, 195, 0 }; [[noreturn]] inline void throw_error(const char* desc, const char* sdl_err) { throw std::runtime_error(std::string(desc) + sdl_err); } void update_pixels( SDL_Texture& texture, const SDL_Rect& texture_rect, const unsigned char* src_alpha, int src_size_x, int src_size_y) { void* pixels; int pitch; if (SDL_LockTexture(&texture, &texture_rect, &pixels, &pitch)) throw_error("could not lock texture: ", SDL_GetError()); auto pixel_buffer = reinterpret_cast<unsigned char*>(pixels); for (int y = 0; y < src_size_y; ++y) { for (int x = 0; x < src_size_x; ++x) { // this assumes SDL_PIXELFORMAT_RGBA8888 unsigned char* const rgba = pixel_buffer + x * 4; unsigned char& r = rgba[0]; unsigned char& g = rgba[1]; unsigned char& b = rgba[2]; unsigned char& a = rgba[3]; r = 0xff; g = 0xff; b = 0xff; a = src_alpha[x]; } src_alpha += src_size_y; pixel_buffer += pitch; } SDL_UnlockTexture(&texture); } int main(int /* argc */, char* /* argv */[]) { if (SDL_Init(SDL_INIT_VIDEO) < 0) throw_error("could not init SDL: ", SDL_GetError()); SDL_Window* window = SDL_CreateWindow("Hello World", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1024, 768, SDL_WINDOW_RESIZABLE); if (!window) throw_error("could not create window: ", SDL_GetError()); SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0); if (!renderer) throw_error("could not create renderer: ", SDL_GetError()); SDL_Texture* texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, 512, 512); if (!texture) throw_error("could not create texture: ", SDL_GetError()); SDL_SetTextureColorMod(texture, 255, 0, 0); SDL_Rect src_rect; src_rect.x = 0; src_rect.y = 0; src_rect.w = 15; src_rect.h = 17; update_pixels(*texture, src_rect, pixels, src_rect.w, src_rect.h); /* * FreeType documentation: For optimal rendering on a screen the bitmap should be used as * an alpha channel in linear blending with gamma correction. * * The blending used is therefore: * dstRGB = (srcRGB * srcA) + (dstRGB * (1 - srcA)) * dstA = (srcA * 0) + (dstA * 1) = dstA */ SDL_BlendMode blend_mode = SDL_ComposeCustomBlendMode( SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_BLENDOPERATION_ADD, SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_ADD); if (SDL_SetTextureBlendMode(texture, blend_mode)) throw_error("could not set texture blending: ", SDL_GetError()); while (true) { SDL_SetRenderDrawColor(renderer, 255, 255, 0, 255); SDL_RenderClear(renderer); SDL_Rect dst_rect; dst_rect.x = 100; dst_rect.y = 100; dst_rect.w = src_rect.w; dst_rect.h = src_rect.h; SDL_RenderCopy(renderer, texture, &src_rect, &dst_rect); SDL_RenderPresent(renderer); SDL_Delay(16); SDL_Event event; while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_KEYUP: switch (event.key.keysym.sym) { case SDLK_ESCAPE: return 0; } break; case SDL_QUIT: return 0; } } } return 0; } Expected result: red letter "A" on yellow background. Actual result: malformed red lines inside black square on yellow background. I suspect that lines are broken because there is a bug within pointer arithmetics inside update_pixels but I have no idea what's causing the black square.
First of all, part of this stuff is already done in SDL_ttf library. You could use it to rasterise glyphs to surfaces or generate multichar text surface. Your src_alpha += src_size_y; is incorrect - you copy row by row, but skip by column length, not row length. It should be src_size_x. That results in incorrect offset on each row and only first row of your copied image is correct. Your colour packing when writing to texture is backwards. See https://wiki.libsdl.org/SDL_PixelFormatEnum#order - Packed component order (high bit -> low bit): SDL_PACKEDORDER_RGBA, meaning R is packed at highest bits while A is at lowest. So, when representing it with unsigned char*, First byte is A and fourth is R: unsigned char& r = rgba[3]; unsigned char& g = rgba[2]; unsigned char& b = rgba[1]; unsigned char& a = rgba[0]; You don't need custom blending, use SDL_BLENDMODE_BLEND, that is 'standard' "src-alpha, one-minus-src-alpha" formula everyone uses (note that it does not blend dst alpha channel itself, nor uses it to any extent; when blending, we only care about src alpha). Finally one more approach to this: you could put your glyph luminance value (alpha, whatever it is called, the point is it only have one channel) and put it into every channel. That way you could do additive blending without using alpha at all, don't even need RGBA texture. Glyph colour could still be multiplied with colour mod. SDL_ttf implements just that.
Re-Create Bitmap Color table from 8 bpp bitmap
I have a field device that uses the raster bytes from a bitmap to display an 8 Bit-per-pixel image. The device uses its own color table to display bitmaps which were created in MS Paint. Given that the field device does not store the original color table, is it possible to download the image bytes, and recreate the bitmap in Windows? The bpp, height and width are all known, just the color table itself is missing. MS Paint seems to use the same color indexes for 256 bitmaps, so it seems that this should be possible. I have a bitmap tools class, and I can create a 24-bit bitmap using the function shown below, and I am trying to modify this to also create 256 (8 bpp) bitmaps. What would it take to make this work? // This function needs to be fixed. // It only works for 24-BPP bitmaps. void BitmapTools::SetHbitmap (BYTE* pBitmapBits, LONG lWidth,LONG lHeight, WORD wBitsPerPixel) { if (wBitsPerPixel < 24) { MessageBox (GetFrame()->m_hWnd, "Error at BitmapTools::SetHbitmap(). This function only works with 24 BPP bitmaps.", "Error", MB_ICONERROR); return; } // Some basic bitmap parameters unsigned long headers_size = sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ); unsigned long pixel_data_size = lHeight * ( ( lWidth * ( wBitsPerPixel / 8 ) ) ); BITMAPINFOHEADER bmpInfoHeader = {0}; // Set the size bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER); // Bit count bmpInfoHeader.biBitCount = wBitsPerPixel; // Use all colors bmpInfoHeader.biClrImportant = 0; // Use as many colors according to bits per pixel if (wBitsPerPixel < 24) { bmpInfoHeader.biClrUsed = (1<<wBitsPerPixel); } else { bmpInfoHeader.biClrUsed = 0; } // Store as un Compressed bmpInfoHeader.biCompression = BI_RGB; // Set the height in pixels bmpInfoHeader.biHeight = lHeight; // Width of the Image in pixels bmpInfoHeader.biWidth = lWidth; // Default number of planes bmpInfoHeader.biPlanes = 1; // Calculate the image size in bytes bmpInfoHeader.biSizeImage = pixel_data_size; BITMAPFILEHEADER bfh = {0}; bfh.bfType = 0x4D42; // Offset to the RGBQUAD bfh.bfOffBits = headers_size; // Total size of image including size of headers bfh.bfSize = headers_size + pixel_data_size; HDC hdc = ::GetDC(NULL); UINT usage; // This does not work. Is there a way to add an arbitrary color // table containing all 256 colors? if (wBitsPerPixel < 24) { usage = DIB_PAL_COLORS; } else { usage = DIB_RGB_COLORS; } //usage = DIB_RGB_COLORS; this->H_Bitmap = CreateDIBitmap (hdc, &bmpInfoHeader, CBM_INIT, pBitmapBits,(BITMAPINFO*)&bmpInfoHeader, usage); } Edit: I made a new function based on someone else's post to create a 256 color bitmap, and I added the values from the color table used by MS Paint. It almost works, except the bottom-right of the image has a row of black pixels. Here is the code I am now using: Edit2: Thanks to everyone for your help, esp. Mark. I got it working now. I made the corrections in the code below. HBITMAP BitmapTools::Create8bppBitmap(HDC hdc, int width, int height, int paddedSize, LPVOID pBits) { BITMAPINFO *bmi = (BITMAPINFO *)malloc(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256); BITMAPINFOHEADER &bih(bmi->bmiHeader); bih.biSize = sizeof (BITMAPINFOHEADER); bih.biWidth = width; bih.biHeight = -height; bih.biPlanes = 1; bih.biBitCount = 8; bih.biCompression = BI_RGB; bih.biSizeImage = 0; //bih.biXPelsPerMeter = 14173; //bih.biYPelsPerMeter = 14173; bih.biClrUsed = 0; bih.biClrImportant = 0; BYTE red[256] = {0, 128, 0, 128, 0, 128, 0, 192, 192, 166, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 192, 224, 0, 32, 64, 96, 128, 160, 255, 160, 128, 255, 0, 255, 0, 255, 0, 255}; BYTE green[256] = {0, 0, 128, 128, 0, 0, 128, 192, 220, 202, 32, 32, 32, 32, 32, 32, 64, 64, 64, 64, 64, 64, 64, 64, 96, 96, 96, 96, 96, 96, 96, 96, 128, 128, 128, 128, 128, 128, 128, 128, 160, 160, 160, 160, 160, 160, 160, 160, 192, 192, 192, 192, 192, 192, 192, 192, 224, 224, 224, 224, 224, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 32, 32, 32, 32, 32, 32, 32, 32, 64, 64, 64, 64, 64, 64, 64, 64, 96, 96, 96, 96, 96, 96, 96, 96, 128, 128, 128, 128, 128, 128, 128, 128, 160, 160, 160, 160, 160, 160, 160, 160, 192, 192, 192, 192, 192, 192, 192, 192, 224, 224, 224, 224, 224, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 32, 32, 32, 32, 32, 32, 32, 32, 64, 64, 64, 64, 64, 64, 64, 64, 96, 96, 96, 96, 96, 96, 96, 96, 128, 128, 128, 128, 128, 128, 128, 128, 160, 160, 160, 160, 160, 160, 160, 160, 192, 192, 192, 192, 192, 192, 192, 192, 224, 224, 224, 224, 224, 224, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 32, 32, 32, 32, 32, 32, 32, 32, 64, 64, 64, 64, 64, 64, 64, 64, 96, 96, 96, 96, 96, 96, 96, 96, 128, 128, 128, 128, 128, 128, 128, 128, 160, 160, 160, 160, 160, 160, 160, 160, 192, 192, 192, 192, 192, 192, 251, 160, 128, 0, 255, 255, 0, 0, 255, 255}; BYTE blue[256] = {0, 0, 0, 0, 128, 128, 128, 192, 192, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 240, 164, 128, 0, 0, 0, 255, 255, 255, 255}; for (int i = 0; i <= 255; i++) { bmi->bmiColors[i].rgbBlue = blue[i]; bmi->bmiColors[i].rgbGreen = green[i]; bmi->bmiColors[i].rgbRed = red[i]; bmi->bmiColors[i].rgbReserved = 0; } void *Pixels = NULL; HBITMAP hbmp = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, &Pixels, NULL, 0); //HBITMAP hbmp = CreateDIBSection(hdc, bmi, DIB_PAL_COLORS, &Pixels, NULL, 0); if(pBits != NULL) { //fill the bitmap BYTE* pbBits = (BYTE*)pBits; BYTE *Pix = (BYTE *)Pixels; memcpy(Pix, pbBits, paddedSize); // --Correction made here-- } free(bmi); return hbmp; } I use this function to save the bitmap: BOOL BitmapTools::SaveHBitmap(const char* filename, HBITMAP hbitmap) { BITMAP bitmap; if (!GetObjectW(hbitmap, sizeof(BITMAP), (void*)&bitmap)) return FALSE; // Convert the color format to a count of bits. WORD clrbits = (WORD)(bitmap.bmPlanes * bitmap.bmBitsPixel); if (clrbits == 1) clrbits = 1; else if (clrbits <= 4) clrbits = 4; else if (clrbits <= 8) clrbits = 8; else if (clrbits <= 16) clrbits = 16; else if (clrbits <= 24) clrbits = 24; else clrbits = 32; //clrUsed is zero for 24 bit and higher int clrUsed = (clrbits <= 8) ? (1 << clrbits) : 0; //TRACE("clrUsed %d\n", clrUsed); int bitmapInfoSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * clrUsed; PBITMAPINFO bitmapInfo = (PBITMAPINFO)new char[bitmapInfoSize]; memset(bitmapInfo, 0, bitmapInfoSize); // Initialize the fields in the BITMAPINFO structure. bitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bitmapInfo->bmiHeader.biWidth = bitmap.bmWidth; bitmapInfo->bmiHeader.biHeight = bitmap.bmHeight; bitmapInfo->bmiHeader.biPlanes = bitmap.bmPlanes; bitmapInfo->bmiHeader.biBitCount = bitmap.bmBitsPixel; bitmapInfo->bmiHeader.biClrUsed = clrUsed; bitmapInfo->bmiHeader.biCompression = BI_RGB; // Compute the number of bytes in the array of color // indices and store the result in biSizeImage. // The width must be DWORD aligned unless the bitmap // is RLE compressed. int dibSize = ((bitmap.bmWidth * clrbits + 31) & ~31) / 8 * bitmap.bmHeight; char* dib = new char[dibSize]; bitmapInfo->bmiHeader.biSizeImage = dibSize; // Set biClrImportant to 0, indicating that all of // the device colors are important. bitmapInfo->bmiHeader.biClrImportant = 0; //bitmapInfo->bmiColors [0].rgbBlue PBITMAPINFOHEADER bmpInfoHeader = (PBITMAPINFOHEADER)bitmapInfo; HDC hdc = CreateCompatibleDC(0); if (!GetDIBits(hdc, hbitmap, 0, bmpInfoHeader->biHeight, dib, bitmapInfo, 0)) { delete bitmapInfo; delete[]dib; return FALSE; } DWORD dwTmp; BITMAPFILEHEADER bmpFileHeader; bmpFileHeader.bfType = 0x4d42; // 0x42 = "B" 0x4d = "M" bmpFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + clrUsed * sizeof(RGBQUAD); bmpFileHeader.bfSize = bmpFileHeader.bfOffBits + dibSize; HANDLE hfile = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hfile != INVALID_HANDLE_VALUE) { WriteFile(hfile,(LPVOID)&bmpFileHeader, sizeof(BITMAPFILEHEADER), (LPDWORD) &dwTmp, NULL); WriteFile(hfile, (void*)bmpInfoHeader, sizeof(BITMAPINFOHEADER) + clrUsed * sizeof(RGBQUAD), (LPDWORD) &dwTmp, NULL); WriteFile(hfile, (void*)dib, dibSize, (LPDWORD) &dwTmp, NULL); CloseHandle(hfile); } DeleteDC(hdc); delete bitmapInfo; delete[]dib; return TRUE; } Here is the image I get. Note the last row has a set of black pixels. I'm not 100% sure that the problem is with these functions (my next step will be to compare the bytes from the original bitmap to the ones from the field device). Edit: I checked the bytes from the field device, and they match the original bitmap raster bytes 100%, so I believe the problem is in one of these functions.
Win32 - why is nothing being drawn to the screen?
I'm trying to use an off-screen buffer so that I can keep track of changes to the screen before/after WM_PAINT and just copy them through one line in WM_PAINT. Here's some code I have to set up the graphics: hdc = GetDC(hWnd); hdcmem = CreateCompatibleDC(hdc); hbcmem = CreateCompatibleDC(hdcmem); // Load bitmaps bg = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BACKGROUND)); side = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_SIDEINFO)); mainCont = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_GAME_CONT)); if(bg == NULL || side == NULL || mainCont == NULL) ThrowError("A bitmap failed to load."); // Background hdcold = (HBITMAP)SelectObject(hbcmem, bg); BitBlt(hdcmem, 0, 0, 237, 196, hbcmem, 0, 0, SRCCOPY); BitBlt(hdcmem, 237, 0, 237, 196, hbcmem, 0, 0, SRCCOPY); BitBlt(hdcmem, 237 * 2, 0, 237, 196, hbcmem, 0, 0, SRCCOPY); BitBlt(hdcmem, 0, 196, 237, 196, hbcmem, 0, 0, SRCCOPY); BitBlt(hdcmem, 237, 196, 237, 196, hbcmem, 0, 0, SRCCOPY); BitBlt(hdcmem, 237 * 2, 196, 237, 196, hbcmem, 0, 0, SRCCOPY); // Side Info hdcold = (HBITMAP)SelectObject(hbcmem, side); BitBlt(hdcmem, 339, 26, 154, 300, hbcmem, 0, 0, SRCCOPY); // Main Game Container hdcold = (HBITMAP)SelectObject(hbcmem, mainCont); BitBlt(hdcmem, 26, 26, 300, 300, hbcmem, 0, 0, SRCCOPY); hdc, hdcmem, hbcmem, hdcold, bg, side, and mainCont are declared previously. Their scope includes everything in this file (including this code and the code in WM_PAINT). Here's the code in WM_PAINT: PAINTSTRUCT ps; BeginPaint(hWnd, &ps); BitBlt(hdc, 0, 0, 518, 401, hdcmem, 0, 0, SRCCOPY); EndPaint(hWnd, &ps); For some reason, nothing is being drawn to the screen. I'm racking my brain trying to figure it out. A pointer in the right direction would be much appreciated.
Create a compatible bitmap for your memory device context first, then select that bitmap to the memory dc and it should work ! hdc = GetDC(hWnd); // used only to create compatibles. hdcmem = CreateCompatibleDC(hdc); hbcmem = CreateCompatibleDC(hdc); // Create client-area-sized compatible bitmap. RECT rc; GetClientRect(hWnd, &rc); HBITMAP hbm_memdc = CreateComptibleBitmap(hdc, rc.right, rc.bottom); HBITMAP hbm_memdc_old = (HBITMAP)SelectObject(hdcmem, hbm_memdc) ReleaseDC(hdc); // this no longer needed // now start rendering into hdcmem... You'll want to keep the old bitmap handle selected out to put it back before destroying your custom one on shutdown. How you manage that is entirely up to you.
SDL program freezes
I'm writing a simple program for testing mouse. It compiles fine, but doesn't work. When I launch it, the window freezes. What am I doing wrong? #include <SDL/SDL.h> #undef main int main() { if (SDL_Init (SDL_INIT_EVERYTHING) != 0) return 1; SDL_Surface* Scr; if ((Scr = SDL_SetVideoMode (300, 200, 32, 0)) == 0) return 2; SDL_Rect Mouse1 = {50, 50, 50, 100}; SDL_Rect Mouse3 = {150, 50, 50, 100}; SDL_Rect Mouse2 = {250, 50, 50, 100}; SDL_Surface Colors; SDL_Rect Click = {0, 0, 50, 100}; SDL_Rect NoClick = {50, 0, 50, 100}; SDL_FillRect (Scr, 0, SDL_MapRGB (Scr->format, 255, 255, 255)); SDL_FillRect (&Colors, &Click, SDL_MapRGB (Colors.format, 255, 0, 0)); SDL_FillRect (&Colors, &NoClick, SDL_MapRGB (Colors.format, 0, 0, 255)); while (true) { if (SDL_GetMouseState (0, 0) & SDL_BUTTON(1)) SDL_BlitSurface (&Colors, &Click, Scr, &Mouse1); else SDL_BlitSurface (&Colors, &NoClick, Scr, &Mouse1); if (SDL_GetMouseState (0, 0) & SDL_BUTTON(2)) SDL_BlitSurface (&Colors, &Click, Scr, &Mouse2); else SDL_BlitSurface (&Colors, &NoClick, Scr, &Mouse2); if (SDL_GetMouseState (0, 0) & SDL_BUTTON(3)) SDL_BlitSurface (&Colors, &Click, Scr, &Mouse3); else SDL_BlitSurface (&Colors, &NoClick, Scr, &Mouse3); if (SDL_GetKeyState (0) [SDLK_ESCAPE]) return 0; SDL_Delay (17); } }
You are not processing any events. In your case, call SDL_PumpEvents to make SDL process them and update all its internal states: while (true) { SDL_PumpEvents(); // The rest is the same ... }