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).
Related
hellow for some reson when i move mouse in window made in
windows.h allocated memory increse, pls help,
and also when mouse is moving screen blink
................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
code:
#include <Windows.h>
#include <windowsx.h>
#include <iostream>
#include <WinUser.h>
void DrawTirangle(HWND hwnd, POINT vertices[], int r, int g, int b) {
HDC hdc = GetDC(hwnd);
HPEN hPen = CreatePen(PS_SOLID, 2, RGB(r, g, b));
HPEN hOldPen = SelectPen(hdc, hPen);
HBRUSH hBrush = CreateSolidBrush(RGB(r, g, b));
HBRUSH hOldBrush = SelectBrush(hdc, hBrush);
POINT verticesx[] = { {vertices[0].x, vertices[0].y}, {vertices[1].x, vertices[1].y}, {vertices[2].x, vertices[2].y} };
Polygon(hdc, verticesx, sizeof(verticesx) / sizeof(verticesx[0]));
SelectBrush(hdc, hOldBrush);
DeleteObject(hBrush);
SelectPen(hdc, hOldPen);
DeleteObject(hPen);
}
#include "sys.h"
LRESULT CALLBACK ScreenProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) {
switch (uMsg)
{
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
HDC hDC = GetDC(hWnd);
RECT rect;
GetWindowRect(hWnd, &rect);
PatBlt(hDC, 0, 0, rect.right, rect.bottom, BLACKNESS);
ReleaseDC(hWnd, hDC);
renderer(hWnd);
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
void ClearBuffer(HWND hwnd, RECT screenDef) {
HDC hdc = GetDC(hwnd);
HPEN hPen = CreatePen(PS_SOLID, 2, RGB(0, 0, 0));
HPEN hOldPen = SelectPen(hdc, hPen);
HBRUSH hBrush = CreateSolidBrush(RGB(0, 0, 0));
HBRUSH hOldBrush = SelectBrush(hdc, hBrush);
POINT vertices1[] = { {0, 0}, {0, screenDef.bottom}, {screenDef.right + 80, screenDef.bottom},{screenDef.right,0} };
Polygon(hdc, vertices1, sizeof(vertices1) / sizeof(vertices1[0]));
SelectBrush(hdc, hOldBrush);
DeleteObject(hBrush);
SelectPen(hdc, hOldPen);
DeleteObject(hPen);
}
class SCREEN {
public:
SCREEN()
: m_hInstance(GetModuleHandle(nullptr))
{
const wchar_t* CLASS_NAME = L"x64 PxOS";
WNDCLASS wndClass = {};
wndClass.lpszClassName = CLASS_NAME;
wndClass.hInstance = m_hInstance;
wndClass.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wndClass.hCursor = LoadCursor(NULL,IDC_ARROW);
wndClass.lpfnWndProc = ScreenProc;
RegisterClass(&wndClass);
DWORD style = WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
int w = 640;
int h = 480;
RECT rect;
rect.left = 250;
rect.top = 250;
rect.right = rect.left + w;
rect.bottom = rect.top + h;
screenDef.left = rect.left;
screenDef.top = rect.top;
screenDef.right = rect.right;
screenDef.bottom = rect.bottom;
AdjustWindowRect(&rect, style, false);
mainBuffer = CreateWindowEx(
0,
CLASS_NAME,
L"x64 PxOS",
style,
rect.left,
rect.top,
rect.right - rect.left,
rect.bottom - rect.top,
NULL,
NULL,
m_hInstance,
NULL
);
ShowWindow(mainBuffer, SW_SHOW);
OldBuffer = mainBuffer;
OldBuffer1 = mainBuffer;
ClearBufferI = mainBuffer;
ClearBuffer(ClearBufferI, screenDef);
screenDefI = screenDef;
}
SCREEN(const SCREEN&) = delete;
SCREEN& operator = (const SCREEN&) = delete;
~SCREEN() {
const wchar_t* CLASS_NAME = L"x64 PxOS";
UnregisterClass(CLASS_NAME,m_hInstance);
}
bool ProcessMessages() {
MSG msg = {};
while (PeekMessage(&msg,nullptr,0u,0u,PM_REMOVE))
{
if (msg.message == WM_QUIT) {
return false;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return true;
}
HINSTANCE m_hInstance;
void SwapBuffers() {
/*if (bs == 1) {
bs = 2;
mainBuffer = OldBuffer;
}
else if(bs == 2) {
bs = 1;
mainBuffer = OldBuffer1;
}*/
}
HWND mainBuffer;
HWND OldBuffer;
HWND OldBuffer1;
HWND ClearBufferI;
int bs = 1;
RECT screenDef;
RECT screenDefI;
};
You are missing ReleaseDC for every GetDC.
You should only paint your window in response to WM_PAINT by calling BeginPaint/EndPaint.
I have created a custom window frame using DWM. The frame extends successfully but whenever I try to draw onto the frame, the extended frame coveres whatever I am trying to draw. I have seen other people try to input a top left within negative bounds, but even when I try to do that, the title bar still overlaps the main window's painting. Here is my code (note: i don't have any code for hit testing):
#include <Windows.h>
#include <numeric>
#include <dwmapi.h>
#pragma comment(lib, "dwmapi.lib")
const auto s_brush = CreateSolidBrush(RGB(0, 0, 255));
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
LRESULT res;
if (DwmDefWindowProc(hwnd, msg, wparam, lparam, &res))
return res;
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_CREATE:
{
RECT r;
GetWindowRect(hwnd, &r);
SetWindowPos(hwnd, 0, 0, 0, r.right - r.left, r.bottom - r.top, SWP_FRAMECHANGED);
}
break;
case WM_ACTIVATE:
{
int metrics[4];
const auto window_dpi_ = GetDpiForWindow(hwnd);
metrics[0] = GetSystemMetricsForDpi(SM_CYCAPTION, window_dpi_);
metrics[1] = GetSystemMetricsForDpi(SM_CXFIXEDFRAME, window_dpi_);
metrics[2] = GetSystemMetricsForDpi(SM_CYSIZEFRAME, window_dpi_);
metrics[3] = GetSystemMetricsForDpi(SM_CYBORDER, window_dpi_);
const auto cy_titlebar_ = std::accumulate(metrics, metrics + sizeof metrics / sizeof(int), 0);
MARGINS margins{ 0, 0, cy_titlebar_, 0 };
DwmExtendFrameIntoClientArea(hwnd, &margins);
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
const auto hdc = BeginPaint(hwnd, &ps);
const auto old = SelectObject(hdc, s_brush);
Rectangle(hdc, 0, 0, 50, 75);
SelectObject(hdc, old);
EndPaint(hwnd, &ps);
}
break;
case WM_NCCALCSIZE:
if (wparam == TRUE)
{
RECT& client_rect = reinterpret_cast<LPNCCALCSIZE_PARAMS>(lparam)->rgrc[0];
const auto window_dpi_ = GetDpiForWindow(hwnd);
const auto frame_width{ GetSystemMetricsForDpi(SM_CXFRAME, window_dpi_) };
const auto border_width{ GetSystemMetricsForDpi(SM_CXPADDEDBORDER, window_dpi_) };
const auto frame_height{ GetSystemMetricsForDpi(SM_CYFRAME, window_dpi_) };
client_rect.bottom -= frame_height + border_width;
client_rect.left += frame_width + border_width;
client_rect.right -= frame_width + border_width;
break;
}
default:
return DefWindowProcW(hwnd, msg, wparam, lparam);
}
return 0;
}
int WINAPI wWinMain(HINSTANCE hinstance, HINSTANCE, LPWSTR lpcmdline, int cmd_show)
{
WNDCLASS wc{ CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hinstance,
0,0, reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)), 0, L"CustWnd" };
const auto hwnd = CreateWindow(MAKEINTATOM(RegisterClass(&wc)), L"Custom Window Frame", WS_OVERLAPPEDWINDOW,
0, 0, 500, 700, 0, 0, hinstance, 0);
ShowWindow(hwnd, cmd_show);
UpdateWindow(hwnd);
MSG msg;
while (GetMessageW(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return 0;
}
The window class doesn't have a default cursor, it's going to show the wrong cursors as you move the mouse. Change wc to
WNDCLASS wc{ CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hinstance, 0,
LoadCursor(NULL, IDC_ARROW),
reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)), 0, L"CustWnd" };
WM_NCHITTEST should also be handled, otherwise title-bar will not grip. It is better to calculate the border thickness based on Windows style, or keep it as static value because it will be needed throughout the procedure, as well as title bar height.
Note that this code will look very different in Windows 10 versus Window 7 which has the weird transparent title-bar, you'll need 32-bit bitmap with alpha channel to draw on title-bar. Or use buffered paint with BufferedPaintSetAlpha as shown below
#include <Windows.h>
#include <Windowsx.h> //for `GET_X_LPARAM` etc.
...
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static int cy_titlebar_ = 100;
static RECT border_thickness;
LRESULT result;
if(DwmDefWindowProc(hWnd, msg, wParam, lParam, &result))
return result;
switch(msg)
{
case WM_CREATE:
{
//find border thickness
border_thickness = { 0 };
if(GetWindowLongPtr(hWnd, GWL_STYLE) & WS_THICKFRAME)
{
AdjustWindowRectEx(&border_thickness,
GetWindowLongPtr(hWnd, GWL_STYLE) & ~WS_CAPTION, FALSE, NULL);
border_thickness.left *= -1;
border_thickness.top *= -1;
}
else if(GetWindowLongPtr(hWnd, GWL_STYLE) & WS_BORDER)
{
border_thickness = { 1,1,1,1 };
}
MARGINS margins = { 0, 0, cy_titlebar_, 0 };
DwmExtendFrameIntoClientArea(hWnd, &margins);
SetWindowPos(hWnd, NULL, 0, 0, 0, 0,
SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
return 0;
}
case WM_NCCALCSIZE:
{
if(wParam)
{
RECT& r = reinterpret_cast<LPNCCALCSIZE_PARAMS>(lParam)->rgrc[0];
r.left += border_thickness.left;
r.right -= border_thickness.right;
r.bottom -= border_thickness.bottom;
return 0;
}
break;
}
case WM_NCHITTEST:
{
result = DefWindowProc(hWnd, msg, wParam, lParam);
if(result == HTCLIENT)
{
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
ScreenToClient(hWnd, &pt);
if(pt.y < border_thickness.top) return HTTOP;
if(pt.y < cy_titlebar_) return HTCAPTION;
}
return result;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
auto hdc = BeginPaint(hWnd, &ps);
//paint opaque:
RECT rc{ 0, 0, 100, cy_titlebar_ };
BP_PAINTPARAMS params = { sizeof(params), BPPF_NOCLIP | BPPF_ERASE };
HDC memdc;
HPAINTBUFFER hbuffer = BeginBufferedPaint(
hdc, &rc, BPBF_TOPDOWNDIB, ¶ms, &memdc);
auto brush = CreateSolidBrush(RGB(255, 0, 0));
FillRect(memdc, &rc, brush);
DeleteObject(brush);
SetBkMode(memdc, TRANSPARENT);
DrawText(memdc, L"Opaque", -1, &rc, 0);
BufferedPaintSetAlpha(hbuffer, &rc, 255);
EndBufferedPaint(hbuffer, TRUE);
EndPaint(hWnd, &ps);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
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);
}
I want to draw on a transparent window using a pen.
When drawing a line black area surround the line.
This image shows the problem:
How to solve this problem?
LRESULT __stdcall WindowProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
HDC hdc, backDC;
PAINTSTRUCT ps;
static Point prevPt;
// Draw or Erase
static bool isDraw = false;
static bool isErase = false;
// Select Pen Color
static int selectColor = 1;
// Color Pen(R, G, B) and Current Pen
static HPEN redPen;
static HPEN greenPen;
static HPEN bluePen;
static HPEN* currentPen = &redPen;
switch (iMessage)
{
case WM_CREATE:
{
redPen = CreatePen(PS_SOLID, 4, RGB(255, 0, 0));
greenPen = CreatePen(PS_SOLID, 4, RGB(0, 255, 0));
bluePen = CreatePen(PS_SOLID, 4, RGB(0, 0, 255));
return 0L;
}
case WM_DESTROY:
cout << "\n" << "destroying window" << endl;
PostQuitMessage(0);
return 0L;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
return 0L;
case WM_LBUTTONDOWN:
prevPt.x = LOWORD(lParam);
prevPt.y = HIWORD(lParam);
isDraw = true;
return 0L;
case WM_LBUTTONUP:
isDraw = false;
return 0L;
case WM_MOUSEMOVE:
{
int x = LOWORD(lParam);
int y = HIWORD(lParam);
if (isDraw)
{
hdc = GetDC(g_hWnd);
HPEN OldPen = (HPEN)SelectObject(hdc, *currentPen);
MoveToEx(hdc, prevPt.x, prevPt.y, NULL);
LineTo(hdc, x, y);
prevPt.x = x;
prevPt.y = y;
DeleteObject(OldPen);
ReleaseDC(g_hWnd, hdc);
}
}
return 0L;
case WM_RBUTTONDOWN:
isErase = true;
return 0L;
case WM_RBUTTONUP:
isErase = false;
return 0L;
case WM_MOUSEWHEEL:
if (selectColor > 3)
selectColor = 1;
if (selectColor == 1) // Red
currentPen = &redPen;
else if (selectColor == 2)
currentPen = &greenPen;
else if (selectColor == 3)
currentPen = &bluePen;
selectColor++;
return 0L;
}
return DefWindowProc(hWnd, iMessage, wParam, lParam);
}
void main()
{
HWND window;
LPCWSTR myclass = L"DrawTest";
WNDCLASSEX wndclass = { sizeof(WNDCLASSEX), CS_VREDRAW | CS_HREDRAW, WindowProc,
0, 0, NULL, LoadIcon(0,IDI_APPLICATION), LoadCursor(0,IDC_ARROW), (HBRUSH)WHITE_BRUSH, 0, myclass, LoadIcon(0,IDI_APPLICATION) };
if (RegisterClassEx(&wndclass))
{
window = CreateWindowEx(WS_EX_TRANSPARENT, myclass, L"title", WS_POPUP, 0, 0, GetSystemMetrics(SM_CXFULLSCREEN), GetSystemMetrics(SM_CYFULLSCREEN), 0, 0, NULL, 0);
}
VideoCapture* pCapture = nullptr;
pCapture = new VideoCapture(0);
if (pCapture)
{
if (!pCapture->isOpened())
{
cout << "Can not open video file." << endl;
return;
}
int fps = (int)(pCapture->get(CAP_PROP_FPS));
int delay = 0;
if (fps == 0)
fps = 24;
delay = 1000 / fps;
Mat colorMat;
while (1)
{
*pCapture >> colorMat;
if (colorMat.empty())
break;
Mat copyColor;
colorMat.copyTo(copyColor);
imshow("colorMat", copyColor);
int ckey = waitKey(delay);
if (ckey == 27)
break;
if (window)
{
ShowWindow(window, SW_SHOW);
MSG msg;
if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
GetMessage(&msg, 0, 0, 0);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
cv::destroyAllWindows();
}
}
As I said in my comment, create a layered window:
window = CreateWindowEx(WS_EX_LAYERED, myclass, L"title", WS_POPUP, 0, 0,
GetSystemMetrics(SM_CXFULLSCREEN), GetSystemMetrics(SM_CYFULLSCREEN),
HWND_DESKTOP, NULL, NULL, NULL);
set color transparency the same as your background brush:
SetLayeredWindowAttributes(window, RGB(255, 255, 255), 0, LWA_COLORKEY);
In WM_PAINT
hdc = BeginPaint(hwnd, &ps);
HPEN OldPen = (HPEN)SelectObject(hdc, *currentPen);
//set random values
MoveToEx(hdc, 50, 50, NULL);
LineTo(hdc, 450, 450);
SelectObject(hdc, OldPen);
EndPaint(hwnd, &ps);
return 0;
This code works, BUT you cant get mouse messages cause the window is transparent. That is the main issue, not the drawing.
EDIT
The problem is how to get mouse messages. The solution is to create a second window on top of your main window with opacity nearly zero so it is not visible but get the mouse messages!
window = CreateWindowEx(WS_EX_LAYERED, myclass, L"title", WS_POPUP, 0, 0,
GetSystemMetrics(SM_CXFULLSCREEN), GetSystemMetrics(SM_CYFULLSCREEN),
HWND_DESKTOP, NULL, NULL, NULL);
windowClone = CreateWindowEx(WS_EX_LAYERED, myclass, L"title", WS_POPUP, 0, 0,
GetSystemMetrics(SM_CXFULLSCREEN), GetSystemMetrics(SM_CYFULLSCREEN),
window, NULL, NULL, NULL);
Make your main window complete transparent:
//background color MUST be the same with color Key!
SetLayeredWindowAttributes(window, RGB(255, 255, 255), 0, LWA_COLORKEY);
Make nearly transparent your clone window
//The transparency is set to 1
SetLayeredWindowAttributes(windowClone, 0, 1, LWA_ALPHA);
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
PAINTSTRUCT ps;
HDC hdc;
static int draw = FALSE, startX, startY, endX, endY, posX, posY;
switch(message){ //handle the messages
case WM_PAINT:
printf("WM_PAINT \n");
if( hwnd == window && draw == TRUE ){
HPEN OldPen, redPen;
redPen = CreatePen(PS_SOLID, 4, RGB(255, 0, 0));
hdc = BeginPaint(hwnd, &ps);
OldPen = (HPEN)SelectObject(hdc, redPen);
MoveToEx(hdc, startX, startY, NULL);
LineTo(hdc, endX, endY);
SelectObject(hdc, OldPen);
EndPaint(hwnd, &ps);
DeleteObject(redPen);
return 0;
}
break;
case WM_MOUSEMOVE:
//printf("WM_MOUSEMOVE \n");
if( hwnd == windowClone && draw == TRUE ){
startX = posX;
startY = posY;
endX = GET_X_LPARAM(lParam);
endY = GET_Y_LPARAM(lParam);
posX = endX;
posY = endY;
InvalidateRect(window, NULL, FALSE);
}
break;
case WM_LBUTTONDOWN:
printf("WM_LBUTTONDOWN \n");
if( hwnd == windowClone ){
posX = GET_X_LPARAM(lParam);
posY = GET_Y_LPARAM(lParam);
draw = TRUE;
}
break;
case WM_LBUTTONUP:
printf("WM_LBUTTONUP \n");
if( hwnd == windowClone && draw == TRUE ){
draw = FALSE;
}
break;
case WM_CAPTURECHANGED:
printf("WM_CAPTURECHANGED \n");
if( hwnd == windowClone && draw == TRUE ){
draw = FALSE;
}
break;
default: //for messages that we don't deal with
return DefWindowProc(hwnd, message, wParam, lParam);
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
I use gluPerspective to mainly increase the draw distance, but it doesn't seem to work.
This is how it shows in my code:
gluPerspective(0, 70/70, 0, 4333);
ratio: The window Width and Height is both 700 and they are constant, in case of wondering.
fovy: I put 0 because, "they" say that using 45 is very nice to draw, but it stops drawing on the screen.
This is the full code:
#include <Windows.h>
#include <gl\GL.h>
#include <gl/glut.h>
WNDCLASSEX wclass;
MSG msg;
HWND hwnd;
HDC hdc;
HDC p_hdc;
float t;
int red, green, blue, x, y, z;
void update()
{
RECT rec;
GetClientRect(hwnd, &rec);
InvalidateRect(hwnd, &rec, false);
UpdateWindow(hwnd);
t += 0.5f;
}
void game()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0, 0, 0, 0);
float norm = 1;
float z = 0;
red = 255;
green = 255;
glPushMatrix();
glRotatef(t, 0, 1, 1);
glBegin(GL_TRIANGLES);
glColor3f(255, 0, 0);
glVertex3f(-norm, norm, z);
glVertex3f(norm, norm, z);
glColor3f(0, 110, 10);
glVertex3f(-norm, -norm, z);
glEnd();
gluPerspective(45, 70/70, 0.01f, 4333);
glPopMatrix();
SwapBuffers(hdc);
}
HGLRC hrc;
LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void EnableOpenGL(HWND hwnd, HDC* hDC, HGLRC* hRC);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpstr, int nCmdShow)
{
wclass.cbSize = sizeof(WNDCLASSEX);
wclass.style = 0;
wclass.lpfnWndProc = WinProc;
wclass.cbClsExtra = 0;
wclass.cbWndExtra = 0;
wclass.hInstance = hInstance;
wclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wclass.hbrBackground = (HBRUSH) (COLOR_WINDOW);
wclass.lpszMenuName = NULL;
wclass.lpszClassName = "CLASS";
wclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wclass))
{
MessageBox(0, "Windows Class Registration Failure Detected!\nProgram Can't Be Initialized..", "Failure Detected", MB_ICONERROR | MB_OK);
return 0;
}
hwnd = CreateWindowEx(
0, "CLASS", "OPENGL WORLD", WS_OVERLAPPEDWINDOW,
0, 0, 700, 700,
HWND_DESKTOP, NULL, hInstance, NULL
);
EnableOpenGL(hwnd, &hdc, &hrc);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
if(hwnd == NULL)
{
MessageBox(0, "Windows Form Creation Failure..", "Failure", MB_ICONERROR | MB_OK);
}
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
SetTimer(hwnd, 1, 1, NULL);
break;
case WM_DESTROY:
PostQuitMessage (0);
break;
case WM_TIMER:
game();
update();
break;
case WM_PAINT:
PAINTSTRUCT ps;
HDC win;
win = BeginPaint(hwnd, &ps);
p_hdc = win;
game();
EndPaint(hwnd, &ps);
break;
default:
return DefWindowProc (hwnd, msg, wParam, lParam);
}
return 0;
}
void EnableOpenGL(HWND hwnd, HDC* hDC, HGLRC* hRC)
{
PIXELFORMATDESCRIPTOR pfd;
int iFormat;
*hDC = GetDC(hwnd);
ZeroMemory(&pfd, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW |
PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 16;
pfd.iLayerType = PFD_MAIN_PLANE;
iFormat = ChoosePixelFormat(*hDC, &pfd);
SetPixelFormat(*hDC, iFormat, &pfd);
*hRC = wglCreateContext(*hDC);
wglMakeCurrent(*hDC, *hRC);
}
What to do?
EDIT: THE NEW CODE
#include <Windows.h>
#include <gl\GL.h>
#include <gl/glut.h>
WNDCLASSEX wclass;
MSG msg;
HWND hwnd;
HDC hdc;
HDC p_hdc;
float t;
int red, green, blue, x, y, z;
float cx, cy, cz;
void handle_resize()
{
RECT rec;
GetClientRect(hwnd, &rec);
long width = rec.right - rec.left;
long height = rec.top - rec.bottom;
float aspect = (float)width/(float)height;
glViewport(0, 0, 700, 700);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45, aspect, 0.01f, 99999);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void update()
{
RECT rec;
GetClientRect(hwnd, &rec);
InvalidateRect(hwnd, &rec, false);
UpdateWindow(hwnd);
t += 0.5f;
cz = -3;
}
void game()
{
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
float norm = 1;
float z = 0;
red = 255;
green = 255;
glPushMatrix();
glRotatef(t, 0, 1, 1);
glBegin(GL_TRIANGLES);
glColor3f(255, 0, 0);
glVertex3f(-norm, norm, z);
glVertex3f(norm, norm, z);
glColor3f(0, 110, 10);
glVertex3f(-norm, -norm, z);
glEnd();
glPopMatrix();
SwapBuffers(hdc);
}
HGLRC hrc;
LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void EnableOpenGL(HWND hwnd, HDC* hDC, HGLRC* hRC);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpstr, int nCmdShow)
{
wclass.cbSize = sizeof(WNDCLASSEX);
wclass.style = 0;
wclass.lpfnWndProc = WinProc;
wclass.cbClsExtra = 0;
wclass.cbWndExtra = 0;
wclass.hInstance = hInstance;
wclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wclass.hbrBackground = (HBRUSH) (COLOR_WINDOW);
wclass.lpszMenuName = NULL;
wclass.lpszClassName = "CLASS";
wclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wclass))
{
MessageBox(0, "Windows Class Registration Failure Detected!\nProgram Can't Be Initialized..", "Failure Detected", MB_ICONERROR | MB_OK);
return 0;
}
hwnd = CreateWindowEx(
0, "CLASS", "OPENGL WORLD", WS_OVERLAPPEDWINDOW,
0, 0, 700, 700,
HWND_DESKTOP, NULL, hInstance, NULL
);
EnableOpenGL(hwnd, &hdc, &hrc);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
glMatrixMode(GL_PROJECTION);
glMatrixMode(GL_MODELVIEW);
if(hwnd == NULL)
{
MessageBox(0, "Windows Form Creation Failure..", "Failure", MB_ICONERROR | MB_OK);
}
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
SetTimer(hwnd, 1, 1, NULL);
break;
case WM_DESTROY:
PostQuitMessage (0);
break;
case WM_TIMER:
game();
update();
break;
case WM_PAINT:
PAINTSTRUCT ps;
HDC win;
win = BeginPaint(hwnd, &ps);
p_hdc = win;
game();
EndPaint(hwnd, &ps);
break;
case WM_SIZE:
handle_resize();
break;
default:
return DefWindowProc (hwnd, msg, wParam, lParam);
}
return 0;
}
void EnableOpenGL(HWND hwnd, HDC* hDC, HGLRC* hRC)
{
PIXELFORMATDESCRIPTOR pfd;
int iFormat;
*hDC = GetDC(hwnd);
ZeroMemory(&pfd, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW |
PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 16;
pfd.iLayerType = PFD_MAIN_PLANE;
iFormat = ChoosePixelFormat(*hDC, &pfd);
SetPixelFormat(*hDC, iFormat, &pfd);
*hRC = wglCreateContext(*hDC);
wglMakeCurrent(*hDC, *hRC);
}
gluPerspective(0, 70/70, 0, 4333);
^ nope ^ nope
fovy and zNear must both be positive and non-zero.
Try this:
gluPerspective( 45, 70/70, 0.1, 4333 );
EDIT: Push your camera back a bit too:
#include <GL/glut.h>
float t = 0;
void timer( int val )
{
t += 0.5f;
glutTimerFunc( 10, timer, 0 );
glutPostRedisplay();
}
void display()
{
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
double w = glutGet( GLUT_WINDOW_WIDTH );
double h = glutGet( GLUT_WINDOW_HEIGHT );
gluPerspective( 45, w / h, 0.1, 4333.0 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glTranslatef( 0, 0, -5 );
float norm = 1;
float z = 0;
glPushMatrix();
glRotatef(t, 0, 1, 1);
glBegin(GL_TRIANGLES);
glColor3f(255, 0, 0);
glVertex3f(-norm, norm, z);
glVertex3f(norm, norm, z);
glColor3f(0, 110, 10);
glVertex3f(-norm, -norm, z);
glEnd();
glPopMatrix();
glutSwapBuffers();
}
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
glutInitWindowSize( 640, 480 );
glutCreateWindow( "GLUT" );
glutDisplayFunc( display );
glutTimerFunc( 0, timer, 0 );
glutMainLoop();
return 0;
}
As-per our comments, I made a few changes to your code that are necessary to properly deal with the perspective projection matrix and window sizing. There are still a number of things about this code that I do not like, such as drawing using a timer but this should at least address the small things.
New code:
void handle_resize (void)
{
RECT rec;
GetClientRect(hwnd, &rec);
long width = rec.right - rec.left;
long height = rec.top - rec.bottom;
float aspect = (float)width/(float)height;
glViewport (0, 0, width, height);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective (45, aspect, 0.01f, 4333);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
}
void game()
{
glClearColor(0, 0, 0, 0); // Do this first
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
float norm = 1;
float z = 0;
red = 255;
green = 255;
glMatrixMode (GL_MODELVIEW);
glPushMatrix();
glRotatef(t, 0, 1, 1);
glBegin(GL_TRIANGLES);
glColor3ub(255, 0, 0);
glVertex3f(-norm, norm, z);
glVertex3f(norm, norm, z);
glColor3ub(0, 110, 10);
glVertex3f(-norm, -norm, z);
glEnd();
//gluPerspective(45, 70/70, 0.01f, 4333); // GET THIS OUT OF HERE!!!
glPopMatrix();
SwapBuffers(hdc);
}
Changes to your window message handler:
switch (msg)
{
case WM_CREATE:
SetTimer(hwnd, 1, 1, NULL);
break;
// NEW EVENT: Handle window size change
case WM_SIZE:
handle_resize ();
break;
Other things to note:
glColor3f clamps the floating-point value to the range [0.0,1.0], you were using values of 255 which is only appropriate if you use glColor3ub, which is essentially the same thing as glColor3f (1.0f, 1.0f, 1.0f).