How to increase bitmap pixel size? [closed] - c++

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I'm struggling to find the way to increase pixel sizes in a win32 bitmap. Is there any way to do it?
I made a small win32 program below. When you run it, you should get a window with a very tiny red dot in the center. You can use up, down, left, and right arrow keys to control the dot.
/* compile: gcc test.c -o test -lgdi32 -Wl,-subsystem,windows */
// TODO fast way to update? resize pixel size? best coding practices?
#include <windows.h>
#define WND_WIDTH 500
#define WND_HEIGHT 500
#define ID_TIMER 1
void DrawBitmap(HDC hdc, RECT *rect, BITMAPINFO info, void *bmpMem)
{
int width = rect->right - rect->left;
int height = rect->bottom - rect->top;
StretchDIBits(hdc,
0,
0,
info.bmiHeader.biWidth,
info.bmiHeader.biHeight,
0,
0,
width,
height,
bmpMem,
&info,
DIB_RGB_COLORS,
SRCCOPY);
}
void UpdateBitmap(BITMAPINFO info, void *bmpMem, POINT pix)
{
int width = info.bmiHeader.biWidth;
int height = info.bmiHeader.biHeight;
BYTE *pixel = (BYTE *) bmpMem;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (x == pix.x && y == pix.y)
{
*pixel++ = 0; /* blue */
*pixel++ = 0; /* green */
*pixel++ = 255; /* red */
*pixel++ = 255; /* alpha */
}
else
{
*pixel++ = 0; /* blue */
*pixel++ = 0; /* green */
*pixel++ = 0; /* red */
*pixel++ = 255; /* alpha */
}
}
}
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static BITMAPINFO info;
static void *bmpMem;
static POINT pixel;
switch (msg)
{
case WM_CREATE:
{
RECT rcClient;
GetClientRect(hWnd, &rcClient);
int width = rcClient.right - rcClient.left;
int height = rcClient.bottom - rcClient.top;
info.bmiHeader.biSize = sizeof(info.bmiHeader);
info.bmiHeader.biWidth = width;
info.bmiHeader.biHeight = height;
info.bmiHeader.biPlanes = 1;
info.bmiHeader.biBitCount = 32;
info.bmiHeader.biCompression = BI_RGB;
info.bmiHeader.biSizeImage = 0;
info.bmiHeader.biXPelsPerMeter = 0;
info.bmiHeader.biYPelsPerMeter = 0;
info.bmiHeader.biClrUsed = 0;
info.bmiHeader.biClrImportant = 0;
bmpMem = VirtualAlloc(0, width * height * 4, MEM_COMMIT, PAGE_READWRITE);
pixel.x = width / 2;
pixel.y = height / 2;
if(!SetTimer(hWnd, ID_TIMER, 50, NULL))
{
MessageBox(hWnd, "Could not SetTimer()!", "Error", MB_OK | MB_ICONEXCLAMATION);
PostQuitMessage(1);
}
break;
}/*
case WM_PAINT:
{
RECT rcClient;
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rcClient);
DrawBitmap(hdc, &rcClient, info, bmpMem);
EndPaint(hWnd, &ps);
break;
}*/
case WM_TIMER:
{
RECT rcClient;
HDC hdc = GetDC(hWnd);
GetClientRect(hWnd, &rcClient);
UpdateBitmap(info, bmpMem, pixel);
DrawBitmap(hdc, &rcClient, info, bmpMem);
ReleaseDC(hWnd, hdc);
break;
}
case WM_KEYDOWN:
{
switch (wParam)
{
case VK_LEFT: pixel.x -= 1; break;
case VK_RIGHT: pixel.x += 1; break;
case VK_UP: pixel.y += 1; break;
case VK_DOWN: pixel.y -= 1; break;
}
break;
}
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
KillTimer(hWnd, ID_TIMER);
VirtualFree(bmpMem, 0, MEM_RELEASE);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
const TCHAR szClassName[] = TEXT("MyClass");
WNDCLASS wc;
HWND hWnd;
MSG msg;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = szClassName;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClass(&wc))
{
MessageBox(NULL, TEXT("Window Registration Failed!"), TEXT("Error!"),
MB_ICONEXCLAMATION | MB_OK);
return 1;
}
hWnd = CreateWindow(szClassName,
TEXT("Title"),
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, /* this window style prevents window resizing */
CW_USEDEFAULT,
CW_USEDEFAULT,
WND_WIDTH,
WND_HEIGHT,
NULL,
NULL,
hInstance,
NULL);
if (hWnd == NULL)
{
MessageBox(NULL, TEXT("Window Creation Failed!"), TEXT("Error!"),
MB_ICONEXCLAMATION | MB_OK);
return 1;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
I want to increase the size of the tiny red dot and all other pixels in the bitmap. I tried to decrease the width and height like this
switch (msg)
{
case WM_CREATE:
{
//RECT rcClient;
//GetClientRect(hWnd, &rcClient);
int width = 30;
int height = 30;
I expected to see a big red dot at the center but I got the white screen instead. How can I edit the code to display bigger pixels?

You are creating a single red pixel in your UpdateBitmap:
if (x == pix.x && y == pix.y)
{
*pixel++ = 0; /* blue */
*pixel++ = 0; /* green */
*pixel++ = 255; /* red */
*pixel++ = 255; /* alpha */
}
If you want a bigger "dot" - define a radius somewhere:
int r = 17;
and change your condition to
if ((x - pix.x)* (x - pix.x) + (y - pix.y)* (y - pix.y) <= r*r)
To scale the entire bitmap, modify DrawBitmap:
void DrawBitmap(HDC hdc, RECT* rect, BITMAPINFO info, void* bmpMem)
{
int width = rect->right - rect->left;
int height = rect->bottom - rect->top;
int scale = 7;
StretchDIBits(hdc,
-(info.bmiHeader.biWidth * scale - width) / 2,
-(info.bmiHeader.biHeight * scale - height) / 2,
info.bmiHeader.biWidth * scale,
info.bmiHeader.biHeight * scale,
0,
0,
width,
height,
bmpMem,
&info,
DIB_RGB_COLORS,
SRCCOPY);
}
StretchDIBits will stretch (or shrink) the area of the source (specified by 0, 0, width, height) into some are of the destination.
In this example, I magnified the size of the destination by the factor of scale - so the image will stretch. The negative offset is to "center" the image over destination; you can use 0,0 to keep the top-left anchor.

Related

winAPI Rotating an Image on Screen while Keeping It Centered and the Background Updated

I'm writing code where a user can pick an image from their computer and rotate it on screen. However, there are two problems that I'm having currently. First, I realized that if the image is rectangular, you can see the old picture before it was rotated behind the new rotated image. Second, when I rotated the image, it seemed to rotate around a certain point on the picture, making the picture go off-screen sometimes. So I wanted to know how I would both keep the old image from showing after I rotated the iamge and also how I would keep the image centered to the screen.
This is my rotate code:
int flip = 1;
void rotateImage(HWND hWnd)
{
HDC hdc = GetDC(hWnd);
Graphics graphic(hdc);
Image* image = Image::FromFile(filePath);
int x = (GetSystemMetrics(SM_CXSCREEN) - image->GetWidth()) / 2;
int y = (GetSystemMetrics(SM_CYSCREEN) - image->GetHeight()) / 2 - 50;
int xx = image->GetWidth();
int yy = image->GetHeight();
if (flip == 1)
image->RotateFlip(Rotate90FlipNone);
else if (flip == 2)
image->RotateFlip(Rotate180FlipNone);
else if (flip == 3)
image->RotateFlip(Rotate270FlipNone);
RECT rc;
HBRUSH hBr;
SetRect(&rc, x, y, x + xx, y + yy);
hBr = CreateSolidBrush(RGB(255, 255, 255));
FillRect(hdc, &rc, hBr);
Status status = graphic.DrawImage(image, x, y);
RECT updateRect = { 0 };
updateRect.left = x;
updateRect.top = y;
updateRect.right = updateRect.left + image->GetWidth();
updateRect.bottom = updateRect.top + image->GetHeight();
flip++;
if (flip > 4) flip = 1;
ReleaseDC(hWnd, hdc);
}
This part of the code
RECT rc;
HBRUSH hBr;
SetRect(&rc, x, y, x + xx, y + yy);
hBr = CreateSolidBrush(RGB(255, 255, 255));
FillRect(hdc, &rc, hBr);
was me trying to solve the issue of the old image appearing after a rotation, but it seems that it cuts out too much of the window and deletes the controls on the window as well.
Some tips:
Each call to GdiplusStartup should be paired with a call to GdiplusShutdown.
Compare window width and height with image's.
Do drawing work in WM_PAINT message
Use window client RECT instead of screen RECT to draw image.
Get image width and heigth after rotate the image.
winAPI Rotating an Image on Screen while Keeping It Centered and the
Background Updated
The following code piece shows mentioned modifications and can achieve this purpose for me. You can refer to.
BOOL fRotate = FALSE;
BOOL fFileOpened = FALSE;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HRESULT hr;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_CREATE:
AddMenus(hWnd);
AddControls(hWnd);
hr = BufferedPaintInit();
break;
case WM_COMMAND:
switch (wParam)
{
case FILE_MENU_EXIT:
// File Menu Exit
DestroyWindow(hWnd);
break;
case FILE_OPEN:
fFileOpened = FALSE;
OpenFileWindow(hWnd);
InvalidateRect(hWnd, NULL, FALSE);
break;
case PIC_EDIT:
if (fFileOpened)
{
displayDialogW(hWnd);
}
else
MessageBoxA(NULL, "Pick an Image File to Edit!", "Error!", MB_ICONINFORMATION | MB_OKCANCEL);
break;
case PIC_ROTATE:
if (fFileOpened)
{
fRotate = TRUE;
InvalidateRect(hWnd, NULL, TRUE);
}
else
MessageBoxA(NULL, "Pick an Image File to Rotate!", "Error!", MB_ICONINFORMATION | MB_OKCANCEL);
break;
}
break;
case WM_PAINT: {
PAINTSTRUCT ps;
HDC screen = BeginPaint(hWnd, &ps);
// 3. Do draw work in WM_PAINT message
if (fRotate)
{
rotateImage(hWnd);
fRotate = FALSE;
}
else if (fFileOpened)
{
HPAINTBUFFER hbuff = BeginBufferedPaint(ps.hdc, &ps.rcPaint, BPBF_COMPATIBLEBITMAP, NULL, &screen);
if (hbuff)
{
RECT rc;
GetClientRect(hWnd, &rc);
FillRect(screen, &rc, GetSysColorBrush(COLOR_WINDOW));
putImage(screen, hWnd);
hr = EndBufferedPaint(hbuff, TRUE);
}
}
EndPaint(hWnd, &ps); } break;
case WM_DESTROY:
BufferedPaintUnInit();
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
void OpenFileWindow(HWND hWnd)
{
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (SUCCEEDED(hr))
{
IFileOpenDialog* pFileOpen;
// Create the FileOpenDialog object.
hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL,
IID_IFileOpenDialog, reinterpret_cast<void**>(&pFileOpen));
if (SUCCEEDED(hr))
{
// Show the Open dialog box.
hr = pFileOpen->Show(NULL);
// Get the file name from the dialog box.
if (SUCCEEDED(hr))
{
IShellItem* pItem;
hr = pFileOpen->GetResult(&pItem);
if (SUCCEEDED(hr))
{
PWSTR pszFilePath;
hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
// Display the file name to the user.
if (SUCCEEDED(hr))
{
char szBuffer[255];
WideCharToMultiByte(CP_ACP, 0, pszFilePath, -1, szBuffer, sizeof(szBuffer), NULL, NULL);
// JPG/JPEG/PNG
filePath = pszFilePath;
fFileOpened = TRUE;
CoTaskMemFree(pszFilePath);
}
pItem->Release();
}
}
pFileOpen->Release();
}
CoUninitialize();
}
}
void putImage(HDC hdc, HWND hWnd)
{
Graphics graphic(hdc);
Image* image = Image::FromFile(filePath);
// 4. Use window client RECT instead of screen RECT to draw image.
RECT clientRect;
GetClientRect(hWnd, &clientRect);
LONG cx = clientRect.right - clientRect.left;
LONG cy = clientRect.bottom - clientRect.top;
// TODO: 2. compare window width and height with image's before subtract.
int x = (cx - image->GetWidth()) / 2;
int y = (cy - image->GetHeight()) / 2;
Status status = graphic.DrawImage(image, x, y);
#if 1 //For testing purpose and feel free to remove.
// Draw a line at window middle for checking is the image is centered
LONG xMid = cx / 2;
LONG yMid = cy / 2;
Pen pen(Color(255, 0, 0, 255));
graphic.DrawLine(&pen, xMid, 0, xMid, clientRect.bottom);
graphic.DrawLine(&pen, 0, yMid, clientRect.right, yMid);
#endif //
}
int flip = 1;
void rotateImage(HWND hWnd)
{
HDC hdc = GetDC(hWnd);
Graphics graphic(hdc);
Image* image = Image::FromFile(filePath);
// 4. Use window client RECT instead of screen RECT to draw image.
RECT clientRect;
GetClientRect(hWnd, &clientRect);
LONG cx = clientRect.right - clientRect.left;
LONG cy = clientRect.bottom - clientRect.top;
if (flip == 1)
image->RotateFlip(Rotate90FlipNone);
else if (flip == 2)
image->RotateFlip(Rotate180FlipNone);
else if (flip == 3)
image->RotateFlip(Rotate270FlipNone);
// 5. Get image width and heigth after rotate
int xx = image->GetWidth();
int yy = image->GetHeight();
// TODO: 2. compare window width and height with image's before subtract.
int x = (cx - xx) / 2;
int y = (cy - yy) / 2;
RECT rc;
HBRUSH hBr;
SetRect(&rc, x, y, x + xx, y + yy);
hBr = CreateSolidBrush(RGB(255, 255, 255));
FillRect(hdc, &rc, hBr);
Status status = graphic.DrawImage(image, x, y);
// Draw a line at window middle
LONG xMid = cx / 2;
LONG yMid = cy / 2;
Pen pen(Color(255, 0, 0, 255));
graphic.DrawLine(&pen, xMid, 0, xMid, clientRect.bottom);
graphic.DrawLine(&pen, 0, yMid, clientRect.right, yMid);
flip++;
if (flip > 4) flip = 1;
ReleaseDC(hWnd, hdc);
}
Update: Add result of an image not working for OP.

WM_POPUP on resize cutting of drawn border

I have a window that i'm trying to draw everything in my self, including title bar, borders.
My problem is that when i drag my window from the bottom right to resize it.
My right/bottom border get cut of when i'm making my window smaller, seems to work fine when dragging it bigger.
If i remove CS_HREDRAW | CS_VREDRAW it just messes up the borders and it all ends up black from where i drag. ( i seen somewhere that it is better to not use these styles to stop flicker)
I'm not sure if im using the correct styles in my window to be able to do what i want here. My end goal is to draw everything in my window including title bar, borders, buttons and all controls.
bool Window::Create(const wchar_t *title, Vector2D size)
{
HINSTANCE instanceHandle = GetModuleHandle(NULL);
if (this->RegisterWindowClass())
{
m_handle = (HWND)CreateWindowEx(0, VERSION, L"", WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, size.m_x, size.m_y, NULL, NULL, instanceHandle, this);
if (m_handle)
{
::ShowWindow(m_handle, SW_SHOW);
}
}
return m_handle != 0;
}
bool Window::RegisterWindowClass(const wchar_t *title)
{
static bool registered = false;
if (!registered)
{
HINSTANCE instanceHandle = GetModuleHandle(NULL);
WNDCLASSEX windowClass;
windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.lpfnWndProc = (WNDPROC)Window::WindowProc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = instanceHandle;
windowClass.hIcon = NULL;
windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
windowClass.hbrBackground = (HBRUSH)(CreateSolidBrush(RGB(60, 60, 60)));//set back color to window
windowClass.lpszMenuName = NULL;
windowClass.lpszClassName = title;
windowClass.hIconSm = NULL;
if (RegisterClassEx(&windowClass))
registered = true;
}
return registered;
}
void Draw_LeftRightBottom_Rectangles(HDC hdc, HBRUSH brush, RECT rect, int TaskbarHeight)
{
RECT leftrect, rightrect, bottomrect;
leftrect.left = 0;
leftrect.top = TaskbarHeight;
leftrect.right = 2;
leftrect.bottom = rect.bottom;
//fill left rect of window for border
FillRect(hdc, &leftrect, brush);
rightrect.left = rect.right - 2;
rightrect.top = TaskbarHeight;
rightrect.right = rect.right;
rightrect.bottom = rect.bottom;
//fill right rect of window
FillRect(hdc, &rightrect, brush);
bottomrect.left = 0;
bottomrect.top = rect.bottom - 2;
bottomrect.right = rect.right;
bottomrect.bottom = rect.bottom;
//fill bottom rect of window
FillRect(hdc, &bottomrect, brush);
}
LRESULT Window::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static int X, Y;
Window* pThis;
if (uMsg == WM_NCCREATE)
{
pThis = static_cast<Window*>(reinterpret_cast<CREATESTRUCT*>(lParam)->lpCreateParams);
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pThis));
}
else
pThis = reinterpret_cast<Window*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
if (pThis != 0)
{
switch (uMsg)
{
case WM_PAINT:
{
RECT clientArea;
GetClientRect(hwnd, &clientArea);
PAINTSTRUCT ps;
if (BeginPaint(hwnd, &ps))
{
//Creating double buffer
HDC hdcMem = CreateCompatibleDC(ps.hdc);
int ndcmem = SaveDC(hdcMem);
HBITMAP hbmMem = CreateCompatibleBitmap(ps.hdc, X, Y);
SelectObject(hdcMem, hbmMem);
//-------------------------------------------------------
// Copy background bitmap into double buffer
BitBlt(hdcMem, 0, 0, clientArea.right, clientArea.bottom, ps.hdc, 0, 0, SRCCOPY);
//---------------------------------------------------------
RECT rect;
rect.bottom = 25;
rect.right = clientArea.right;
HBRUSH brush = CreateSolidBrush(RGB(0, 0, 0));
// Draw Titlebar
FillRect(hdcMem, &rect, brush);
Draw_LeftRightBottom_Rectangles(hdcMem, brush, clientArea, 25);
DeleteObject(brush);
//-----------------------------------------------------------------------------
// Copy double buffer to screen
BitBlt(ps.hdc, 0, 0, X, Y, hdcMem, 0, 0, SRCCOPY);
//--------------------------------------------------
// Clean up
RestoreDC(hdcMem, ndcmem);
DeleteObject(hbmMem);
DeleteDC(hdcMem);
EndPaint(hwnd, &ps);
//--------------------
}
return 0;;
}
case WM_SIZE:
{
X = LOWORD(lParam);
Y = HIWORD(lParam);
break;
}
case WM_NCHITTEST:
{
POINT pt;
RECT rc;
GetClientRect(hwnd, &rc);
pt.x = LOWORD(lParam);
pt.y = HIWORD(lParam);
ScreenToClient(hwnd, &pt);
if (pt.y > (rc.bottom - BORDERWIDTH))
{
if (pt.x>(rc.right - BORDERWIDTH))
{
return HTBOTTOMRIGHT;
}
}
if (pt.y < 25)
{
return HTCAPTION;
}
break;
}
}
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

Painted image is always black

I'm trying draw an image within a popup windows. I get the bitmap infos from a stream. That part should be ok, because if I create a file and save the bitmap it looks fine.
The byte array is stored as follows:
static BYTE* _bitampContent;
Here is how I create the window:
static WCHAR name[] = L"Bitmap Display";
HINSTANCE _instance = ::GetModuleHandle(NULL);
HWND hWnd;
MSG msg;
WNDCLASS wndClass;
wndClass.style = 0;
wndClass.lpfnWndProc = class::_WindowProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hInstance = _instance;
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = name;
if (RegisterClass(&wndClass) == 0)
{
MessageBox(0, L"The Window is not registered", L"Message", MB_OK);
return 0;
}
RECT rc;
GetWindowRect(hwndOwner, &rc);
int xPos = (GetSystemMetrics(SM_CXSCREEN) - rc.right) / 2;
int yPos = (GetSystemMetrics(SM_CYSCREEN) - rc.bottom) / 2;
hWnd = CreateWindowEx(WS_EX_TOPMOST, name, name, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, NULL, NULL, _instance, NULL);
if (hWnd == 0)
{
MessageBox(0, L"hWnd = 0", L"Message", MB_OK);
return 0;
}
ShowWindow(hWnd, SW_SHOWNORMAL);
UpdateWindow(hWnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
msg.wParam;
And in the WndProc function a paint the bitmap.
LRESULT CALLBACK class::_WindowProc(HWND hWnd, UINT uMsgId, WPARAM wParam, LPARAM lParam)
{
HBITMAP hbitmap;
BITMAP bitmap;
HDC hdc, hmemdc;
switch (uMsgId)
{
case WM_PAINT:
BITMAPINFOHEADER bmpInfoHeader;
bmpInfoHeader = { 0 };
bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfoHeader.biBitCount = 24;
bmpInfoHeader.biClrImportant = 0;
bmpInfoHeader.biClrUsed = 0;
bmpInfoHeader.biCompression = BI_RGB;
bmpInfoHeader.biHeight = 200;
bmpInfoHeader.biWidth = 200;
bmpInfoHeader.biPlanes = 1;
unsigned long pixel_data_size;
pixel_data_size = 200 * ((200 * (24 / 8)));
bmpInfoHeader.biSizeImage = pixel_data_size;
BITMAPINFO dbmi;
ZeroMemory(&dbmi, sizeof(dbmi));
dbmi.bmiHeader = bmpInfoHeader;
dbmi.bmiColors->rgbBlue = 0;
dbmi.bmiColors->rgbGreen = 0;
dbmi.bmiColors->rgbRed = 0;
dbmi.bmiColors->rgbReserved = 0;
void* bits;
bits = NULL;
hbitmap = CreateDIBSection(NULL, &dbmi, DIB_RGB_COLORS, &bits, NULL, 0);
if (hbitmap == NULL) {
MessageBox(NULL, L"Bitmap not loaded", L"Error", MB_OK);
return 0;
}
GdiFlush();
// copy pixels into DIB.
memcpy(bits, _bitampContent, sizeof(_bitampContent));
GetObject(hbitmap, sizeof(BITMAP), &bitmap);
PAINTSTRUCT paintStruct;
hdc = BeginPaint(hWnd, &paintStruct);
hmemdc = CreateCompatibleDC(hdc);
SelectObject(hmemdc, hbitmap);
BitBlt(hdc, 0, 0, bitmap.bmWidth, bitmap.bmHeight, hmemdc, 0, 0, SRCCOPY);
DeleteObject(hbitmap);
EndPaint(hWnd, &paintStruct);
return 0;
My problem is now, that the painted image is always black. I assume that this behavior has something to do with the DC's but I don't know exactly what.
What do I need to change?

OpenGL Flashing?

I'm trying to draw some text in OpenGL while the program draw a cube or any Opengl native so, when I try to put the text on the screen it flashes very fast and I don't know why, I tried to change the Sleep value and nothing...
The code is below; here is a GIF showing the problem.
The green background is the cube, the camera is very close to the background, you can move back with the NUM_2.
#include <windows.h>
#include <iostream>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#include "default.h"
using namespace std;
LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM);
DWORD WINAPI WorkLoop(LPVOID PARAMS);
void keyScan (MSG msg, Camera cam);
HDC hDC;
HGLRC hRC;
HWND hwnd;
RECT WBounds;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wcex;
MSG msg;
BOOL bQuit = FALSE;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_OWNDC;
wcex.lpfnWndProc = WindowProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = "GLSample";
wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);;
Screen ();
if (!RegisterClassEx(&wcex))
return 0;
hwnd = CreateWindowEx(0,
"GLSample",
"OpenGL Testing",
WS_OVERLAPPEDWINDOW,
Scr.sx/2-630,
Scr.sy/2-450,
1260,
900,
NULL,
NULL,
hInstance,
NULL);
GetClientRect(hwnd, &WBounds);
ShowWindow(hwnd, nCmdShow);
EnableOpenGL(hwnd, &hDC, &hRC); ///ENABLE OPENGL
Camera cam = Camera (0, 0, -1);
CreateThread(0, 0x1000, &WorkLoop, 0, 0, 0);
while (!bQuit)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT) bQuit = TRUE;
else
{
keyScan (msg, cam);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else
{
renderSimulation (cam);
SwapBuffers (hDC);
}
Sleep(1);
}
DisableOpenGL(hwnd, hDC, hRC);
DestroyWindow(hwnd);
return msg.wParam;
}
DWORD WINAPI WorkLoop(LPVOID PARAMS)
{
while (true)
{
InvalidateRect(hwnd, &WBounds, true);
Sleep(33);
}
ExitThread(0);
}
float x = 0.0f, y = 0.0f, z = 0.0f;
float rx = 0.0f, ry = 0.0f, rz = 0.0f;
char* textas = "test";
void keyScan (MSG p, Camera cam)
{
if (p.message == WM_KEYDOWN)
{
if (p.wParam == ARROW_RIGHT) {x += 0.1; cam.SetCameraPosition (x, y, z);}
else if (p.wParam == ARROW_LEFT) {x -= 0.1; cam.SetCameraPosition (x, y, z);}
else if (p.wParam == ARROW_UP) {y += 0.1; cam.SetCameraPosition (x, y, z);}
else if (p.wParam == ARROW_DOWN) {y -= 0.1; cam.SetCameraPosition (x, y, z);}
else if (p.wParam == NUM_8) {z += 0.1; cam.SetCameraPosition (x, y, z);}
else if (p.wParam == NUM_2) {z -= 0.1; cam.SetCameraPosition (x, y, z);}
else if (p.wParam == L) SetFullScreen (p.hwnd, hDC, hRC);
else if (p.wParam == K) textas = "cambiado";
}
}
HFONT Font = CreateFont(40, 0, 0, 0,FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET,OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY, FF_MODERN, TEXT("Arial"));
HPEN BoxPen = CreatePen(PS_SOLID, 1, RGB(0, 255, 0));
HPEN OutlinePen = CreatePen(PS_SOLID, 3, RGB(0, 0, 0));
HPEN CHPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
HBRUSH CHBrush = CreateSolidBrush(RGB(0, 255, 0));
void drawtext(HDC hdc, int x, int y, const char * text)
{
SetBkMode (hdc, TRANSPARENT);
SetTextColor(hdc, RGB(0, 255, 0));
SetBkColor(hdc, RGB(255, 255, 255));
TextOutA(hdc, x, y, text, strlen(text));
}
/*void Draw(HDC hdc, int x, int y, float dist)
{
int width = 20000 / dist;
int height = 45000 / dist;
SelectObject(hdc, OutlinePen);
SelectObject(hdc, WHITE_BRUSH);
Rectangle(hdc, x - (width / 2), y - height, x + (width / 2), y);
SelectObject(hdc, BoxPen);
Rectangle(hdc, x - (width / 2), y - height, x + (width / 2), y);
SetTextAlign(hdc, TA_CENTER | TA_NOUPDATECP);
std::stringstream ss2;
ss2 << "Dist: " << dist << " m";
drawtext(hdc, x, y + 90, ss2.str().c_str());
}*/
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_PAINT:
{
int win_width = WBounds.right - WBounds.left;
int win_height = WBounds.bottom + WBounds.left;
PAINTSTRUCT ps;
HDC Memhdc;
HDC hdc;
HBITMAP Membitmap;
hdc = BeginPaint(hwnd, &ps);
Memhdc = CreateCompatibleDC (hdc);
Membitmap = CreateCompatibleBitmap (hdc, win_width, win_height);
SelectObject (Memhdc, Membitmap);
//FillRect (Memhdc, &WBounds, WHITE_BRUSH);
SelectObject (Memhdc, Font);
SetTextAlign (Memhdc, TA_LEFT | TA_NOUPDATECP);
drawtext(Memhdc, 100, 100, textas);
//Draw (Memhdc, 20, 50, 90.0);
/*SelectObject(Memhdc, CHPen);
SelectObject(Memhdc, CHBrush);*/
BitBlt (hdc, 0, 0, win_width, win_height, Memhdc, 0, 0, SRCCOPY);
DeleteObject(Membitmap);
DeleteDC(Memhdc);
DeleteDC(hdc);
EndPaint(hwnd, &ps);
ValidateRect(hwnd, &WBounds);
}
case WM_KEYDOWN:
{
switch (wParam)
{
case VK_ESCAPE:
PostQuitMessage(0);
}
}
case WM_ERASEBKGND:
return 1;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
Two problems with your program:
Setting a background brush for a OpenGL window will make the OS visibly clear the window with the brush before sending WM_PAINT (upon which you overdraw with OpenGL). By using InvalidateRect you're triggering this erase-with-background before WM_PAINT
Double buffered OpenGL pixelformats and drawing with the GDI don't go well together. If you want to draw text you'll have to do it differently. For example drawing to a DIBSECTION DC and then drawing that bitmap per using a textured quad. Or using a font rasterizer that addresses OpenGL (FTGL, Glyphy or the likes).

Resize window to fit content after WM_PAINT

is there a way to resize after all WM_PAINT calls are done? so that i can automatically resize my window to fit whatever i have painted, since initially my window size is defined at a certain size, there may be leftover spaces that are not painted, how can i remove these leftover spaces?
As you can see from the screenshot below the white spaces are the leftover spaces.
#include <windows.h>
#include "resource.h"
#include "loadFromTextFile.h"
const char g_szClassName[] = "myWindowClass";
const int recLength = 3;
const int wndHeight = 700;
const int wndWidth = 700;
PAINTSTRUCT ps;
HDC hdc;
HBRUSH blackBrush = CreateSolidBrush(RGB(0, 0, 0));
HBRUSH whiteBrush = CreateSolidBrush(RGB(255, 255, 255));
HBRUSH redBrush = CreateSolidBrush(RGB(255, 0, 0));
HPEN myPen = CreatePen(PS_NULL, 1, RGB(0, 0, 0));
//load from text
string FILE_PATH = ("10x10.txt");
loadFromTextFile loaded = loadFromTextFile(FILE_PATH);
int mazeWidth = loaded.getColumns() * recLength;
int mazeHeight = loaded.getRows() * recLength;
void paintMaze(HWND hwnd, vector<vector<string> > grid){
hdc = ::BeginPaint(hwnd, &ps);
SelectObject(hdc, myPen);
for (int r = 0; r < loaded.getRows(); r++){
for (int c = 0; c < loaded.getColumns(); c++){
RECT rect;
rect.left = c*recLength;//x upper left
rect.top = r*recLength;//y upper left
rect.right = (c + 1)*recLength;//x lower right corner
rect.bottom = (r + 1)*recLength;//y lower right corner
if (grid[r][c] == "1"){//1 path
FillRect(hdc, &rect, blackBrush);
}
else if (grid[r][c] == "0"){//wall
FillRect(hdc, &rect, whiteBrush);
}
if (r == 50 && c == 50){
FillRect(hdc, &rect, redBrush);
}
}
}
DeleteObject(blackBrush);
DeleteObject(whiteBrush);
DeleteObject(redBrush);
DeleteObject(myPen);
EndPaint(hwnd, &ps);
}
// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_FILE_EXIT:
PostMessage(hwnd, WM_CLOSE, 0, 0);
break;
case ID_ABOUT:
SetWindowPos(hwnd, 0, 0, 0, mazeWidth, mazeHeight, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
break;
}
break;
case WM_PAINT:
{
paintMaze(hwnd, loaded.getNodeGrid());
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
//Step 1: Registering the Window Class
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);;
wc.lpszClassName = g_szClassName;
wc.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1));
wc.hIconSm = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON, 32, 32, 0);
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// Step 2: Creating the Window
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
" Maze",
WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU,//prevent resize
CW_USEDEFAULT, CW_USEDEFAULT, wndWidth, wndHeight,
NULL, NULL, hInstance, NULL);
if (hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// Step 3: The Message Loop
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
Paint in an offscreen buffer.
This allows you to resize the window.
Paint the window by copying the buffer.